ruby-bindgen 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/CHANGELOG.md +7 -0
- data/LICENSE +25 -0
- data/README.md +68 -0
- data/Rakefile +8 -0
- data/bin/ruby-bindgen +133 -0
- data/docs/architecture.md +238 -0
- data/docs/c/c_bindings.md +65 -0
- data/docs/c/constants.md +21 -0
- data/docs/c/customizing.md +19 -0
- data/docs/c/filtering.md +24 -0
- data/docs/c/getting_started.md +56 -0
- data/docs/c/library_loading.md +53 -0
- data/docs/c/output.md +96 -0
- data/docs/c/types.md +61 -0
- data/docs/c/version_guards.md +105 -0
- data/docs/cmake/cmake_bindings.md +19 -0
- data/docs/cmake/filtering.md +26 -0
- data/docs/cmake/getting_started.md +52 -0
- data/docs/cmake/output.md +110 -0
- data/docs/configuration.md +351 -0
- data/docs/contributing.md +68 -0
- data/docs/cpp/buffers.md +24 -0
- data/docs/cpp/classes.md +139 -0
- data/docs/cpp/cpp_bindings.md +29 -0
- data/docs/cpp/customizing.md +124 -0
- data/docs/cpp/enums.md +42 -0
- data/docs/cpp/filtering.md +35 -0
- data/docs/cpp/getting_started.md +80 -0
- data/docs/cpp/iterators.md +94 -0
- data/docs/cpp/operators.md +170 -0
- data/docs/cpp/output.md +125 -0
- data/docs/cpp/templates.md +114 -0
- data/docs/examples.md +133 -0
- data/docs/index.md +133 -0
- data/docs/prior_art.md +37 -0
- data/docs/troubleshooting.md +243 -0
- data/docs/type_spelling.md +200 -0
- data/docs/updating_bindings.md +55 -0
- data/docs/version_guards.md +69 -0
- data/lib/ruby-bindgen/config.rb +63 -0
- data/lib/ruby-bindgen/generators/cmake/cmake.rb +171 -0
- data/lib/ruby-bindgen/generators/cmake/directory.erb +29 -0
- data/lib/ruby-bindgen/generators/cmake/guard.rb +55 -0
- data/lib/ruby-bindgen/generators/cmake/presets.erb +232 -0
- data/lib/ruby-bindgen/generators/cmake/project.erb +89 -0
- data/lib/ruby-bindgen/generators/ffi/callback.erb +1 -0
- data/lib/ruby-bindgen/generators/ffi/constant.erb +1 -0
- data/lib/ruby-bindgen/generators/ffi/enum_constant_decl.erb +1 -0
- data/lib/ruby-bindgen/generators/ffi/enum_decl.erb +4 -0
- data/lib/ruby-bindgen/generators/ffi/enum_decl_anonymous.erb +4 -0
- data/lib/ruby-bindgen/generators/ffi/ffi.rb +687 -0
- data/lib/ruby-bindgen/generators/ffi/field_decl.erb +1 -0
- data/lib/ruby-bindgen/generators/ffi/function.erb +5 -0
- data/lib/ruby-bindgen/generators/ffi/library.erb +39 -0
- data/lib/ruby-bindgen/generators/ffi/project.erb +18 -0
- data/lib/ruby-bindgen/generators/ffi/struct.erb +6 -0
- data/lib/ruby-bindgen/generators/ffi/translation_unit.erb +9 -0
- data/lib/ruby-bindgen/generators/ffi/typedef_decl.erb +1 -0
- data/lib/ruby-bindgen/generators/ffi/union.erb +6 -0
- data/lib/ruby-bindgen/generators/ffi/variable.erb +1 -0
- data/lib/ruby-bindgen/generators/ffi/version.erb +9 -0
- data/lib/ruby-bindgen/generators/ffi/version_method.erb +5 -0
- data/lib/ruby-bindgen/generators/generator.rb +52 -0
- data/lib/ruby-bindgen/generators/rice/auto_generated_base_class.erb +5 -0
- data/lib/ruby-bindgen/generators/rice/class.erb +31 -0
- data/lib/ruby-bindgen/generators/rice/class_template.erb +9 -0
- data/lib/ruby-bindgen/generators/rice/class_template_specialization.erb +10 -0
- data/lib/ruby-bindgen/generators/rice/constant.erb +9 -0
- data/lib/ruby-bindgen/generators/rice/constructor.erb +1 -0
- data/lib/ruby-bindgen/generators/rice/conversion_function.erb +4 -0
- data/lib/ruby-bindgen/generators/rice/cxx_iterator_method.erb +1 -0
- data/lib/ruby-bindgen/generators/rice/cxx_method.erb +6 -0
- data/lib/ruby-bindgen/generators/rice/enum_constant_decl.erb +7 -0
- data/lib/ruby-bindgen/generators/rice/enum_decl.erb +6 -0
- data/lib/ruby-bindgen/generators/rice/field_decl.erb +8 -0
- data/lib/ruby-bindgen/generators/rice/function.erb +6 -0
- data/lib/ruby-bindgen/generators/rice/function_pointer.rb +68 -0
- data/lib/ruby-bindgen/generators/rice/incomplete_class.erb +3 -0
- data/lib/ruby-bindgen/generators/rice/iterator_alias.erb +1 -0
- data/lib/ruby-bindgen/generators/rice/iterator_collector.rb +159 -0
- data/lib/ruby-bindgen/generators/rice/namespace.erb +5 -0
- data/lib/ruby-bindgen/generators/rice/non_member_operator_binary.erb +4 -0
- data/lib/ruby-bindgen/generators/rice/non_member_operator_inspect.erb +6 -0
- data/lib/ruby-bindgen/generators/rice/non_member_operator_unary.erb +4 -0
- data/lib/ruby-bindgen/generators/rice/operator[].erb +4 -0
- data/lib/ruby-bindgen/generators/rice/project.cpp.erb +18 -0
- data/lib/ruby-bindgen/generators/rice/project.hpp.erb +13 -0
- data/lib/ruby-bindgen/generators/rice/reference_qualifier.rb +495 -0
- data/lib/ruby-bindgen/generators/rice/rice.rb +1724 -0
- data/lib/ruby-bindgen/generators/rice/rice_include.hpp.erb +7 -0
- data/lib/ruby-bindgen/generators/rice/signature_builder.rb +230 -0
- data/lib/ruby-bindgen/generators/rice/template_resolver.rb +585 -0
- data/lib/ruby-bindgen/generators/rice/translation_unit.cpp.erb +40 -0
- data/lib/ruby-bindgen/generators/rice/translation_unit.hpp.erb +7 -0
- data/lib/ruby-bindgen/generators/rice/translation_unit.ipp.erb +3 -0
- data/lib/ruby-bindgen/generators/rice/type_index.rb +117 -0
- data/lib/ruby-bindgen/generators/rice/type_speller.rb +509 -0
- data/lib/ruby-bindgen/generators/rice/union.erb +5 -0
- data/lib/ruby-bindgen/generators/rice/variable.erb +5 -0
- data/lib/ruby-bindgen/inputter.rb +54 -0
- data/lib/ruby-bindgen/name_mapper.rb +65 -0
- data/lib/ruby-bindgen/namer.rb +138 -0
- data/lib/ruby-bindgen/outputter.rb +40 -0
- data/lib/ruby-bindgen/parser.rb +82 -0
- data/lib/ruby-bindgen/refinements/cursor.rb +57 -0
- data/lib/ruby-bindgen/refinements/string.rb +41 -0
- data/lib/ruby-bindgen/symbol_candidates.rb +282 -0
- data/lib/ruby-bindgen/symbol_entry.rb +21 -0
- data/lib/ruby-bindgen/symbols.rb +107 -0
- data/lib/ruby-bindgen/type_pointer_formatter.rb +35 -0
- data/lib/ruby-bindgen/version.rb +3 -0
- data/lib/ruby-bindgen.rb +19 -0
- data/ruby-bindgen.gemspec +52 -0
- metadata +260 -0
|
@@ -0,0 +1,351 @@
|
|
|
1
|
+
# Configuration
|
|
2
|
+
|
|
3
|
+
`ruby-bindgen` uses a YAML configuration file to specify how bindings should be generated. This approach keeps your build configuration versioned and reproducible.
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
ruby-bindgen rice-bindings.yaml
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
For end-to-end examples, see [C Bindings](c/c_bindings.md), [C++ Bindings](cpp/cpp_bindings.md), and [CMake Bindings](cmake/cmake_bindings.md).
|
|
10
|
+
|
|
11
|
+
## Required Options
|
|
12
|
+
|
|
13
|
+
| Option | Description |
|
|
14
|
+
|----------|-------------------------------------------------------------------------------------------------------------------|
|
|
15
|
+
| `input` | Directory containing the header files to parse. Required for `FFI` and `Rice`. For `CMake`, if omitted it defaults to `output` so the generator scans previously generated `*-rb.cpp` files. Can be absolute or relative to the config file location. |
|
|
16
|
+
| `output` | Directory where generated binding files will be written. Can be absolute or relative to the config file location. |
|
|
17
|
+
| `format` | Type of bindings to generate: `Rice` for C++, `FFI` for C, or `CMake` for CMakeLists.txt. |
|
|
18
|
+
|
|
19
|
+
Relative paths for `input` and `output` are resolved from the config file's directory, not the current working directory. This makes configs portable across different machines.
|
|
20
|
+
|
|
21
|
+
## Common Options
|
|
22
|
+
|
|
23
|
+
These options apply to all formats.
|
|
24
|
+
|
|
25
|
+
| Option | Default | Description |
|
|
26
|
+
|-----------------|--------------------|-------------------------------------------------------------------------------------------|
|
|
27
|
+
| `match` | `["**/*.{h,hpp}"]` for `FFI`/`Rice`, `["**/*-rb.cpp"]` for `CMake` | Array of glob patterns specifying which files to process. **Note:** removing a header from `match` does not delete its previously generated `*-rb.cpp` file. You must manually delete stale output files when removing headers. Auto-cleanup is not performed because `match` is often temporarily narrowed to regenerate a single file. |
|
|
28
|
+
| `skip` | `[]` | Array of glob patterns specifying which files to skip. For Rice/FFI, these match header file paths. For CMake, these match generated `*-rb.cpp` file paths. In most cases, it's better to add skips to the Rice/FFI config so the files are never generated, rather than skipping them in CMake after the fact. |
|
|
29
|
+
| `symbols` | `{}` | Symbol actions and name mappings grouped by type. See [Symbols](#symbols). |
|
|
30
|
+
| `export_macros` | `[]` | List of macros that indicate a function is exported. See [Export Macros](#export-macros). |
|
|
31
|
+
| `version_check` | none | Identifier used for version guards. Required when `symbols.versions` is non-empty. For **Rice**, this is a C preprocessor macro — symbols are wrapped in `#if version_check >= version` / `#endif`. For **FFI**, this is a Ruby method name — symbols are wrapped in `if version_check >= version` / `end`. See [Versions](#versions). |
|
|
32
|
+
|
|
33
|
+
## C (FFI) Options
|
|
34
|
+
|
|
35
|
+
| Option | Default | Description |
|
|
36
|
+
|--------------------|----------|-------------|
|
|
37
|
+
| `project` | **required** | Project name. Used for the loader file name (`{project}_ffi.rb`) which contains the library preamble and `require_relative`s for each content file. |
|
|
38
|
+
| `library_names` | `[]` | Base names of shared libraries to load (e.g., `["proj"]` for `libproj`). |
|
|
39
|
+
| `library_versions` | `[]` | Library version suffixes to search for (e.g., `["25", "9"]`). Combined with `library_names` to build platform-specific search names like `libproj.so.25`. |
|
|
40
|
+
| `module` | filename | Ruby module name for the generated bindings. Defaults to the header filename camelized (e.g., `proj.h` → `Proj`). For the project loader, defaults to `project` camelized. Supports nested modules with `::` (e.g., `Proj::Api`). |
|
|
41
|
+
| `library_search_path` | none | Name of an environment variable containing a directory path. When the env var is set at runtime, library names are searched in that directory first before falling back to standard search. For example, `library_search_path: PROJ_LIB_PATH` generates code that checks `ENV['PROJ_LIB_PATH']` and prepends that path to each library name. |
|
|
42
|
+
|
|
43
|
+
## C++ (Rice) Options
|
|
44
|
+
|
|
45
|
+
| Option | Default | Description |
|
|
46
|
+
|-----------------|----------------|-------------|
|
|
47
|
+
| `project` | none | Project name for the Ruby extension. Used for the `Init_` function name and project wrapper file names. Must be a valid C/C++ identifier. When provided, generates project wrapper files (`{project}-rb.cpp`, `{project}-rb.hpp`). When omitted, only per-file bindings are generated. |
|
|
48
|
+
| `include` | auto-generated | Path to a custom Rice include header. See [Include Header](cpp/output.md#include-header). |
|
|
49
|
+
|
|
50
|
+
## CMake Options
|
|
51
|
+
|
|
52
|
+
| Option | Default | Description |
|
|
53
|
+
|----------------|---------|-------------|
|
|
54
|
+
| `project` | none | Project name used in the CMake `project()` command and build target name. When provided, generates the root `CMakeLists.txt` (with project setup, Rice fetch, Ruby detection) and `CMakePresets.json`. When omitted, only subdirectory `CMakeLists.txt` files are generated — useful when you manage the root project files yourself. |
|
|
55
|
+
| `include_dirs` | `[]` | List of include directory expressions added via `target_include_directories`. These are CMake expressions written directly into `CMakeLists.txt` (e.g., `${CMAKE_CURRENT_SOURCE_DIR}/../headers`). |
|
|
56
|
+
| `guards` | `{}` | Map of raw CMake condition expressions to arrays of generated path patterns. Matching directories are emitted inside guarded `add_subdirectory(...)` blocks; matching `*-rb.cpp` files are emitted inside guarded `target_sources(...)` blocks. Exact paths and globs are both supported. |
|
|
57
|
+
|
|
58
|
+
## Compiler Toolchain
|
|
59
|
+
|
|
60
|
+
`ruby-bindgen` uses top-level toolchain keys to configure compiler settings for different platforms:
|
|
61
|
+
|
|
62
|
+
- **`clang-cl:`** - Used when `RUBY_PLATFORM` contains `mswin` (MSVC toolchain)
|
|
63
|
+
- **`clang:`** - Used on Linux, macOS, and MinGW
|
|
64
|
+
|
|
65
|
+
| Option | Default | Description |
|
|
66
|
+
|------------|-------------|-------------|
|
|
67
|
+
| `libclang` | auto-detect | Path to the libclang shared library. Nested under `clang-cl:` or `clang:`. When specified, sets the `LIBCLANG` environment variable before loading ffi-clang. |
|
|
68
|
+
| `args` | `[]` | Arguments passed to libclang for parsing (include paths, language standard, defines, etc.). Nested under `clang-cl:` or `clang:`. |
|
|
69
|
+
|
|
70
|
+
You only need to include the toolchain sections for platforms you target.
|
|
71
|
+
|
|
72
|
+
### Resolution Flow
|
|
73
|
+
|
|
74
|
+
```mermaid
|
|
75
|
+
flowchart TD
|
|
76
|
+
A["config.yaml location"] --> B["Resolve relative input/output paths"]
|
|
77
|
+
B --> C{"RUBY_PLATFORM contains mswin?"}
|
|
78
|
+
C -->|Yes| D["Use clang-cl section"]
|
|
79
|
+
C -->|No| E["Use clang section (Linux, macOS, MinGW)"]
|
|
80
|
+
D --> F["Set LIBCLANG from toolchain libclang (if provided)"]
|
|
81
|
+
E --> F
|
|
82
|
+
F --> G["Pass toolchain args to libclang parser"]
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
### Clang Arguments
|
|
86
|
+
|
|
87
|
+
The `args` section under each toolchain is crucial for successful parsing. You typically need:
|
|
88
|
+
|
|
89
|
+
1. **System include paths** - Standard library headers
|
|
90
|
+
2. **Library include paths** - The library's own headers
|
|
91
|
+
3. **Language specification** - `-xc++` for C++ headers, `-xc` for C headers
|
|
92
|
+
4. **Language standard** - `-std=c++17` or similar
|
|
93
|
+
|
|
94
|
+
#### Finding System Include Paths
|
|
95
|
+
|
|
96
|
+
On Linux/macOS:
|
|
97
|
+
```bash
|
|
98
|
+
clang++ -E -x c++ - -v < /dev/null 2>&1 | grep "^ /"
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
On Windows with MSVC:
|
|
102
|
+
- Visual Studio include paths (e.g., `C:\Program Files\Microsoft Visual Studio\...\include`)
|
|
103
|
+
- Windows SDK include paths (e.g., `C:\Program Files (x86)\Windows Kits\10\Include\...`)
|
|
104
|
+
- LLVM/Clang include paths if using clang
|
|
105
|
+
|
|
106
|
+
### Finding Libclang
|
|
107
|
+
|
|
108
|
+
On Linux:
|
|
109
|
+
```bash
|
|
110
|
+
# Common locations
|
|
111
|
+
/usr/lib64/libclang.so # Fedora, RHEL
|
|
112
|
+
/usr/lib/x86_64-linux-gnu/libclang-*.so # Debian, Ubuntu
|
|
113
|
+
/usr/lib/llvm-*/lib/libclang.so # Multiple LLVM versions
|
|
114
|
+
|
|
115
|
+
# Find all libclang installations
|
|
116
|
+
find /usr -name "libclang*.so" 2>/dev/null
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
On macOS:
|
|
120
|
+
```bash
|
|
121
|
+
# Homebrew LLVM
|
|
122
|
+
/opt/homebrew/opt/llvm/lib/libclang.dylib # Apple Silicon
|
|
123
|
+
/usr/local/opt/llvm/lib/libclang.dylib # Intel
|
|
124
|
+
|
|
125
|
+
# Xcode Command Line Tools
|
|
126
|
+
/Library/Developer/CommandLineTools/usr/lib/libclang.dylib
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
On Windows:
|
|
130
|
+
```
|
|
131
|
+
# Visual Studio bundled LLVM
|
|
132
|
+
C:\Program Files\Microsoft Visual Studio\2022\...\VC\Tools\Llvm\x64\bin\libclang.dll
|
|
133
|
+
|
|
134
|
+
# Standalone LLVM installation
|
|
135
|
+
C:\Program Files\LLVM\bin\libclang.dll
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
## Symbols
|
|
139
|
+
|
|
140
|
+
The `symbols` option groups per-symbol actions and name mappings by type. The action groups are `skip`, `versions`, and `overrides`. Name mappings use `rename_types` and `rename_methods`.
|
|
141
|
+
|
|
142
|
+
### Skip
|
|
143
|
+
|
|
144
|
+
The `skip` key lists symbols to exclude from bindings. This works for functions, classes, enums, typedefs, unions, and variables. This is useful when:
|
|
145
|
+
|
|
146
|
+
- Symbols have export macros but still aren't available (build configuration issues)
|
|
147
|
+
- Symbols are internal/private APIs not meant for external use
|
|
148
|
+
- Symbols cause linker errors due to missing definitions
|
|
149
|
+
|
|
150
|
+
Symbol names support:
|
|
151
|
+
|
|
152
|
+
- Simple names: `versionMajor` - skips all symbols with this name
|
|
153
|
+
- Fully qualified names: `cv::ocl::PlatformInfo::versionMajor` - skips only that specific symbol
|
|
154
|
+
- Signatures: `cv::Mat_::zeros(int, const int *)` - skips only the overload with matching parameter types
|
|
155
|
+
- Regex patterns: `/pattern/` - skips symbols matching the regex
|
|
156
|
+
|
|
157
|
+
#### How Matching Works
|
|
158
|
+
|
|
159
|
+
For exact symbol matching, `ruby-bindgen` does not rely on just one spelling. It tries a small set of candidate names so that configuration can match what users usually write in headers.
|
|
160
|
+
|
|
161
|
+
For a member function such as `cv::dnn::Layer::init`, the candidate set typically includes:
|
|
162
|
+
|
|
163
|
+
- The simple spelling: `init`
|
|
164
|
+
- The semantic qualified name from libclang: `cv::dnn::dnn4_v20241223::Layer::init`
|
|
165
|
+
- A parent-type form that collapses inline namespaces: `cv::dnn::Layer::init`
|
|
166
|
+
|
|
167
|
+
For overloads, the same shapes are also tried with parameter lists appended:
|
|
168
|
+
|
|
169
|
+
- `init(const cv::Mat &)`
|
|
170
|
+
- `cv::dnn::dnn4_v20241223::Layer::init(const cv::Mat &)`
|
|
171
|
+
- `cv::dnn::Layer::init(const cv::Mat &)`
|
|
172
|
+
|
|
173
|
+
This matters for libraries such as OpenCV, where public APIs are often declared inside versioned inline namespaces but users usually write the enclosing API name in configuration.
|
|
174
|
+
|
|
175
|
+
Two additional normalizations are worth knowing:
|
|
176
|
+
|
|
177
|
+
- Anonymous scopes are stripped from user-facing matches. For example, an enum constant reported by clang as `Outer::(unnamed enum at ... )::Value` can be matched as `Outer::Value`.
|
|
178
|
+
- Macros only match by their simple name, because libclang does not provide a usable qualified name for macro definitions.
|
|
179
|
+
|
|
180
|
+
```yaml
|
|
181
|
+
symbols:
|
|
182
|
+
skip:
|
|
183
|
+
- versionMajor # Skips all symbols named "versionMajor"
|
|
184
|
+
- cv::ocl::PlatformInfo::versionMinor # Skips only this specific method
|
|
185
|
+
- "cv::Mat_::zeros(int, const int *)" # Skips only this overload (others remain)
|
|
186
|
+
- /cv::dnn::.*Layer::init.*/ # Regex: skips all init* methods on any Layer class
|
|
187
|
+
- DeprecatedEnum # Skips an enum
|
|
188
|
+
- InternalUnion # Skips a union
|
|
189
|
+
- debugVariable # Skips a variable
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
### Versions
|
|
193
|
+
|
|
194
|
+
The `versions` key wraps symbols in version guards. Each sub-key is the minimum version value, with a list of symbol names underneath.
|
|
195
|
+
|
|
196
|
+
For **Rice** (C++), this requires the `version_check` option to be set. The generator wraps version-specific symbols in `#if version_check >= version` / `#endif` preprocessor directives.
|
|
197
|
+
|
|
198
|
+
```yaml
|
|
199
|
+
format: Rice
|
|
200
|
+
version_check: CV_VERSION
|
|
201
|
+
symbols:
|
|
202
|
+
versions:
|
|
203
|
+
40100:
|
|
204
|
+
- cv::Foo::baz
|
|
205
|
+
40500:
|
|
206
|
+
- /cv::cuda::.*/
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
This generates:
|
|
210
|
+
```cpp
|
|
211
|
+
#if CV_VERSION >= 40100
|
|
212
|
+
.define_method("baz", &cv::Foo::baz)
|
|
213
|
+
#endif
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
For **FFI** (C), this requires the `version_check` option to be set to a Ruby method name. The generator wraps version-specific symbols in `if version_check >= version` Ruby conditionals and generates a `{project}_version.rb` skeleton file. The user implements the version detection method — typically by calling the library's own version API. See [Version Detection](c/version_guards.md) for a full example.
|
|
217
|
+
|
|
218
|
+
```yaml
|
|
219
|
+
format: FFI
|
|
220
|
+
project: proj
|
|
221
|
+
version_check: proj_version
|
|
222
|
+
symbols:
|
|
223
|
+
skip:
|
|
224
|
+
- PJ_INFO # manually defined in version file
|
|
225
|
+
- proj_info # manually defined in version file
|
|
226
|
+
versions:
|
|
227
|
+
60100:
|
|
228
|
+
- proj_normalize_for_visualization
|
|
229
|
+
60200:
|
|
230
|
+
- proj_cleanup
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
This generates:
|
|
234
|
+
```ruby
|
|
235
|
+
if proj_version >= 60100
|
|
236
|
+
attach_function :proj_normalize_for_visualization, ...
|
|
237
|
+
end
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
See [Version Guards](version_guards.md) for the Rice guide and [Version Detection](c/version_guards.md) for a full FFI example.
|
|
241
|
+
|
|
242
|
+
### Overrides (FFI only)
|
|
243
|
+
|
|
244
|
+
The `overrides` key replaces the generated `attach_function` signature for specific functions. This is useful when ruby-bindgen's type heuristics produce the wrong FFI type — for example, C functions that return `int` 0/1 for boolean, or use `size_t` parameters that resolve to `:ulong`.
|
|
245
|
+
|
|
246
|
+
Each entry maps a C function name to a signature string that replaces everything after `attach_function :ruby_name, :c_name, `:
|
|
247
|
+
|
|
248
|
+
```yaml
|
|
249
|
+
symbols:
|
|
250
|
+
overrides:
|
|
251
|
+
# C returns int 0/1, but Ruby 0 is truthy so must use :bool
|
|
252
|
+
proj_is_crs: "[:pointer], :bool"
|
|
253
|
+
# size_t vs ulong: on 64-bit Windows size_t is 8 bytes but ulong is 4 bytes
|
|
254
|
+
proj_trans_generic: "[:pointer, PjDirection, :pointer, :size_t, :size_t, ...], :size_t"
|
|
255
|
+
# Output buffer: char *s is caller-allocated, return is same pointer
|
|
256
|
+
proj_rtodms2: "[:pointer, :ulong, :double, :int, :int], :pointer"
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
### Overload-Specific Skipping
|
|
260
|
+
|
|
261
|
+
When a function has multiple overloads but only some cause problems (e.g., linker errors), you can target a specific overload by appending its parameter types in parentheses:
|
|
262
|
+
|
|
263
|
+
```yaml
|
|
264
|
+
symbols:
|
|
265
|
+
skip:
|
|
266
|
+
- cv::Mat_::zeros # Skips ALL overloads of zeros
|
|
267
|
+
- "cv::Mat_::zeros(int, const int *)" # Skips only zeros(int ndims, const int* sz)
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
The parameter types must match the canonical clang type spelling exactly (e.g., `const int *` not `const int*` or `int const *`).
|
|
271
|
+
|
|
272
|
+
### Regex Patterns
|
|
273
|
+
|
|
274
|
+
Regex patterns are enclosed in forward slashes (`/pattern/`) and are matched against the same candidate set as exact names: simple names, semantic qualified names, and inline-namespace-collapsed member names when available. This is particularly useful for:
|
|
275
|
+
|
|
276
|
+
- Matching across versioned inline namespaces (e.g., `cv::dnn::dnn4_v20241223::Layer`)
|
|
277
|
+
- Skipping families of related methods
|
|
278
|
+
- Handling template specializations
|
|
279
|
+
|
|
280
|
+
`ruby-bindgen` automatically skips:
|
|
281
|
+
|
|
282
|
+
- Deprecated functions (marked with `__attribute__((deprecated))`)
|
|
283
|
+
- Methods returning pointers to incomplete types (pimpl pattern)
|
|
284
|
+
|
|
285
|
+
## Export Macros
|
|
286
|
+
|
|
287
|
+
The `export_macros` option filters functions based on the presence of specific macros in the source code. This is useful for libraries that use macros to control symbol visibility.
|
|
288
|
+
|
|
289
|
+
When specified, only functions whose source text contains at least one of the listed macros will be included in the bindings. This prevents linker errors from trying to wrap internal functions that aren't exported from the shared library.
|
|
290
|
+
|
|
291
|
+
```yaml
|
|
292
|
+
export_macros:
|
|
293
|
+
- CV_EXPORTS
|
|
294
|
+
- CV_EXPORTS_W
|
|
295
|
+
```
|
|
296
|
+
|
|
297
|
+
### Common Library Macros
|
|
298
|
+
|
|
299
|
+
| Library | Export Macros |
|
|
300
|
+
|---------|--------------|
|
|
301
|
+
| OpenCV | `CV_EXPORTS`, `CV_EXPORTS_W`, `CV_EXPORTS_W_SIMPLE` |
|
|
302
|
+
| Qt | `Q_DECL_EXPORT`, `Q_CORE_EXPORT` |
|
|
303
|
+
| Boost | `BOOST_*_DECL` |
|
|
304
|
+
|
|
305
|
+
### Name Mappings
|
|
306
|
+
|
|
307
|
+
ruby-bindgen applies heuristics to convert C++ names to Ruby names — for example, `isEnabled()` becomes `enabled?` and `operator()` becomes `call`. These heuristics sometimes guess wrong. The `rename_methods` and `rename_types` keys under `symbols` let you override the generated names without manual post-generation edits.
|
|
308
|
+
|
|
309
|
+
Both options use the same pattern syntax as `symbols` names: plain strings for exact match, `/pattern/` for regex.
|
|
310
|
+
|
|
311
|
+
#### Type Mappings
|
|
312
|
+
|
|
313
|
+
Override generated Ruby class names for template instantiations. Supports `\1`, `\2`, etc. capture group substitution in regex replacements.
|
|
314
|
+
|
|
315
|
+
```yaml
|
|
316
|
+
symbols:
|
|
317
|
+
rename_types:
|
|
318
|
+
# OpenCV Matx naming convention: MatxUnsignedChar21 → Matx21b
|
|
319
|
+
- from: /^MatxUnsignedChar(\d+)$/
|
|
320
|
+
to: Matx\1b
|
|
321
|
+
- from: /^MatxUnsignedShort(\d+)$/
|
|
322
|
+
to: Matx\1w
|
|
323
|
+
- from: /^MatxShort(\d+)$/
|
|
324
|
+
to: Matx\1s
|
|
325
|
+
- from: /^MatxInt(\d+)$/
|
|
326
|
+
to: Matx\1i
|
|
327
|
+
```
|
|
328
|
+
|
|
329
|
+
Without these overrides, `Matx<unsigned char, 2, 1>` would generate the Ruby class name `MatxUnsignedChar21`. With the mapping, it becomes `Matx21b`, matching OpenCV's naming convention.
|
|
330
|
+
|
|
331
|
+
#### Method Mappings
|
|
332
|
+
|
|
333
|
+
Override generated Ruby method names. The `from` field is a C++ name (simple or fully qualified), the `to` field is the desired Ruby name.
|
|
334
|
+
|
|
335
|
+
```yaml
|
|
336
|
+
symbols:
|
|
337
|
+
rename_methods:
|
|
338
|
+
# Exact match by qualified name — grab is not a predicate, it grabs a frame
|
|
339
|
+
- from: cv::VideoCapture::grab
|
|
340
|
+
to: grab
|
|
341
|
+
# Override operator() → [] for element/ROI access
|
|
342
|
+
- from: cv::Mat::operator()
|
|
343
|
+
to: "[]"
|
|
344
|
+
- from: cv::UMat::operator()
|
|
345
|
+
to: "[]"
|
|
346
|
+
# Override operator() → to_size for MatSize (returns a Size, not element access)
|
|
347
|
+
- from: cv::MatSize::operator()
|
|
348
|
+
to: to_size
|
|
349
|
+
```
|
|
350
|
+
|
|
351
|
+
Without these overrides, ruby-bindgen would generate `grab?` (bool return, no params triggers predicate heuristic) and `call` (default `operator()` mapping).
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
# Contributing
|
|
2
|
+
|
|
3
|
+
Guidelines for changing `ruby-bindgen` and its generated-output tests.
|
|
4
|
+
|
|
5
|
+
## Key Files
|
|
6
|
+
|
|
7
|
+
- `lib/ruby-bindgen/generators/generator.rb` - base class shared by all generators
|
|
8
|
+
- `lib/ruby-bindgen/generators/rice/rice.rb` - main AST walker for Rice code generation
|
|
9
|
+
- `lib/ruby-bindgen/generators/rice/*.erb` - Rice templates
|
|
10
|
+
- `lib/ruby-bindgen/generators/ffi/ffi.rb` - main AST walker for FFI code generation
|
|
11
|
+
- `lib/ruby-bindgen/generators/cmake/cmake.rb` - CMake file generator
|
|
12
|
+
- `test/headers/cpp/*.hpp` - C++ input headers for tests
|
|
13
|
+
- `test/bindings/cpp/*-rb.cpp` - expected generated output (golden files)
|
|
14
|
+
|
|
15
|
+
## Run Tests
|
|
16
|
+
|
|
17
|
+
Run all tests before updating expected files:
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
bundle exec ruby -Ilib -Itest test/ffi_test.rb
|
|
21
|
+
bundle exec ruby -Ilib -Itest test/rice_test.rb
|
|
22
|
+
bundle exec ruby -Ilib -Itest test/cmake_test.rb
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
Run one test:
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
bundle exec ruby -Ilib -Itest test/rice_test.rb --name test_classes
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
Important:
|
|
32
|
+
- Run `cmake_test` after `rice_test` because it scans generated `*-rb.cpp` files.
|
|
33
|
+
|
|
34
|
+
## Updating Expected Files
|
|
35
|
+
|
|
36
|
+
Only update expected outputs after all tests pass on current expectations.
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
UPDATE_EXPECTED=1 bundle exec ruby -Ilib -Itest test/rice_test.rb
|
|
40
|
+
UPDATE_EXPECTED=1 bundle exec ruby -Ilib -Itest test/cmake_test.rb
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## Test Coverage Requirement
|
|
44
|
+
|
|
45
|
+
Every bug fix should include test coverage:
|
|
46
|
+
|
|
47
|
+
- Add or adjust headers in `test/headers/cpp/`
|
|
48
|
+
- Update expected generated outputs in `test/bindings/cpp/`
|
|
49
|
+
|
|
50
|
+
For cross-file typedef issues, use:
|
|
51
|
+
- `test/headers/cpp/cross_file_base.hpp`
|
|
52
|
+
- `test/headers/cpp/cross_file_derived.hpp`
|
|
53
|
+
|
|
54
|
+
## Regenerating opencv-ruby Bindings
|
|
55
|
+
|
|
56
|
+
Use the project configs in:
|
|
57
|
+
- `<opencv-ruby>/ext/rice-bindings.yaml`
|
|
58
|
+
- `<opencv-ruby>/ext/cmake-bindings.yaml`
|
|
59
|
+
|
|
60
|
+
Generate with:
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
cd <ruby-bindgen>
|
|
64
|
+
# 1. Generate Rice source files
|
|
65
|
+
bundle exec ruby -Ilib bin/ruby-bindgen <opencv-ruby>/ext/rice-bindings.yaml
|
|
66
|
+
# 2. Generate CMake files
|
|
67
|
+
bundle exec ruby -Ilib bin/ruby-bindgen <opencv-ruby>/ext/cmake-bindings.yaml
|
|
68
|
+
```
|
data/docs/cpp/buffers.md
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# Buffers and Pointers
|
|
2
|
+
|
|
3
|
+
`ruby-bindgen` automatically wraps some pointer parameters and return types. For details on using buffers and pointers from Ruby, see the Rice documentation on [Buffers](https://ruby-rice.github.io/4.x/bindings/buffers/) and [Pointers](https://ruby-rice.github.io/4.x/bindings/pointers/).
|
|
4
|
+
|
|
5
|
+
Pointers to most fundamental types (`int*`, `double*`, `unsigned char*`, `void*`, etc.) and double pointers (`T**`) are automatically wrapped using Rice's `ArgBuffer` and `ReturnBuffer` classes:
|
|
6
|
+
|
|
7
|
+
```cpp
|
|
8
|
+
void processData(int* data, int size); // ArgBuffer("data")
|
|
9
|
+
void getMinMax(double* min, double* max); // Out parameters via ArgBuffer
|
|
10
|
+
int* createBuffer(int size); // ReturnBuffer
|
|
11
|
+
void processArrays(float** matrices, int count); // Double pointer via ArgBuffer
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
`char*` and `wchar_t*` are treated as strings rather than raw buffers, so they do **not** use `ArgBuffer` or `ReturnBuffer`:
|
|
15
|
+
|
|
16
|
+
```cpp
|
|
17
|
+
void processCharBuffer(char* buffer, int length); // Arg("buffer")
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
This distinction matters for APIs that mix byte buffers and strings:
|
|
21
|
+
|
|
22
|
+
- `unsigned char*` is treated as a byte buffer
|
|
23
|
+
- `char*` / `wchar_t*` are treated as string pointers
|
|
24
|
+
- Any `T**` is treated as a buffer-style pointer, even when `T` is a class type
|
data/docs/cpp/classes.md
ADDED
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
# Classes & Structs
|
|
2
|
+
|
|
3
|
+
`ruby-bindgen` generates Rice bindings for C++ classes and structs, including constructors, methods, member variables, and single inheritance. For details on how Rice wraps classes, see the Rice documentation on [Classes](https://ruby-rice.github.io/4.x/bindings/classes/), [Constructors](https://ruby-rice.github.io/4.x/bindings/constructors/), [Methods](https://ruby-rice.github.io/4.x/bindings/methods/), [Overloaded Methods](https://ruby-rice.github.io/4.x/bindings/overloaded_methods/), [Attributes](https://ruby-rice.github.io/4.x/bindings/attributes/), and [Constants](https://ruby-rice.github.io/4.x/bindings/constants/).
|
|
4
|
+
|
|
5
|
+
## Constructors
|
|
6
|
+
|
|
7
|
+
### Multiple Constructors
|
|
8
|
+
|
|
9
|
+
All public, non-deleted, non-deprecated constructors are wrapped:
|
|
10
|
+
|
|
11
|
+
```cpp
|
|
12
|
+
class MyClass {
|
|
13
|
+
MyClass();
|
|
14
|
+
MyClass(int x);
|
|
15
|
+
MyClass(int x, int y);
|
|
16
|
+
};
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
### Implicit Default Constructor
|
|
20
|
+
|
|
21
|
+
If a class has no explicit constructors, the implicit default constructor is wrapped.
|
|
22
|
+
|
|
23
|
+
### Skipped Constructors
|
|
24
|
+
|
|
25
|
+
- Move constructors
|
|
26
|
+
- Deleted constructors
|
|
27
|
+
- Deprecated constructors
|
|
28
|
+
- Constructors of abstract classes
|
|
29
|
+
|
|
30
|
+
## Attributes
|
|
31
|
+
|
|
32
|
+
### Public Member Variables
|
|
33
|
+
|
|
34
|
+
Public member variables generate getter/setter methods via `define_attr`:
|
|
35
|
+
|
|
36
|
+
```cpp
|
|
37
|
+
class Point {
|
|
38
|
+
public:
|
|
39
|
+
int x, y; // Generates x, x=, y, y=
|
|
40
|
+
};
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
### Static Member Variables
|
|
44
|
+
|
|
45
|
+
Static members on classes use `define_singleton_attr`.
|
|
46
|
+
|
|
47
|
+
### Constants
|
|
48
|
+
|
|
49
|
+
`const` qualified variables and namespace-level variables generate Ruby constants.
|
|
50
|
+
|
|
51
|
+
## Single Inheritance
|
|
52
|
+
|
|
53
|
+
```cpp
|
|
54
|
+
class Derived : public Base {};
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
Generates:
|
|
58
|
+
```cpp
|
|
59
|
+
define_class<Derived, Base>("Derived")
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
For template base class inheritance, see [Templates](templates.md#template-base-classes).
|
|
63
|
+
|
|
64
|
+
## Methods
|
|
65
|
+
|
|
66
|
+
### Overloaded Methods
|
|
67
|
+
|
|
68
|
+
Overloaded methods are automatically detected and generate explicit type signatures:
|
|
69
|
+
|
|
70
|
+
```cpp
|
|
71
|
+
void process(int x);
|
|
72
|
+
void process(double x);
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
Generates:
|
|
76
|
+
```cpp
|
|
77
|
+
define_method<void(MyClass::*)(int)>("process", &MyClass::process, Arg("x")).
|
|
78
|
+
define_method<void(MyClass::*)(double)>("process", &MyClass::process, Arg("x"));
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
### Conversion Operators
|
|
82
|
+
|
|
83
|
+
Type conversion operators generate appropriately named Ruby methods:
|
|
84
|
+
|
|
85
|
+
```cpp
|
|
86
|
+
operator bool() const; // to_bool
|
|
87
|
+
operator std::string() const; // to_s
|
|
88
|
+
operator int*(); // to_ptr (non-const)
|
|
89
|
+
operator const int*() const; // to_const_ptr
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
Template parameter conversions in class templates use generic names (`to_ptr`, `to_const_ptr`) to avoid invalid method names.
|
|
93
|
+
|
|
94
|
+
For a complete table of conversion type mappings, see the [Operators](operators.md#conversion-operators) page.
|
|
95
|
+
|
|
96
|
+
### Callbacks
|
|
97
|
+
|
|
98
|
+
`ruby-bindgen` understands C-style callbacks and generates the appropriate Rice [callback code](https://ruby-rice.github.io/4.x/bindings/callbacks/).
|
|
99
|
+
|
|
100
|
+
### Safe Bool Idiom
|
|
101
|
+
|
|
102
|
+
Pre-C++11 "safe bool idiom" using typedef to member function pointer is automatically skipped:
|
|
103
|
+
|
|
104
|
+
```cpp
|
|
105
|
+
typedef void (MyClass::*bool_type)() const;
|
|
106
|
+
operator bool_type() const; // Skipped
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
### Default Values
|
|
110
|
+
|
|
111
|
+
`ruby-bindgen` preserves C++ default parameter values, handling namespace qualification and type constraints.
|
|
112
|
+
|
|
113
|
+
Default values are automatically qualified with full namespace paths:
|
|
114
|
+
|
|
115
|
+
```cpp
|
|
116
|
+
void func(int flags = NORM_L2); // -> cv::NORM_L2
|
|
117
|
+
void func(Mat m = noArray()); // -> cv::noArray()
|
|
118
|
+
void func(Scalar s = Scalar::all(0)); // -> cv::Scalar::all(0)
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
Default values referencing class template members preserve template parameters:
|
|
122
|
+
|
|
123
|
+
```cpp
|
|
124
|
+
template<typename T>
|
|
125
|
+
class Quat {
|
|
126
|
+
static constexpr T EPS = 1e-6;
|
|
127
|
+
Quat(T eps = EPS); // -> cv::Quat<T>::EPS
|
|
128
|
+
};
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
Default parameter values are only generated for copyable types. `ruby-bindgen` detects non-copyable types via private copy constructors, deleted copy constructors (`= delete`), or inherited inaccessible copy constructors:
|
|
132
|
+
|
|
133
|
+
```cpp
|
|
134
|
+
class NonCopyable {
|
|
135
|
+
NonCopyable(const NonCopyable&) = delete;
|
|
136
|
+
};
|
|
137
|
+
|
|
138
|
+
void func(NonCopyable nc = NonCopyable()); // Default value NOT generated
|
|
139
|
+
```
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# C++ Bindings
|
|
2
|
+
|
|
3
|
+
`ruby-bindgen` creates Ruby bindings for C++ libraries using [Rice](https://github.com/ruby-rice/rice). Creating C++ bindings takes more work than creating C bindings, so if a library provides both a C and C++ API you should use the C API.
|
|
4
|
+
|
|
5
|
+
`ruby-bindgen` does its best to generate compilable Rice code. It has been battle tested against [OpenCV](https://github.com/opencv/opencv), which is a large, complex C++ API with over a thousand classes and ten thousand methods.
|
|
6
|
+
|
|
7
|
+
For many libraries, the generated bindings will compile and work with no additional changes. For example, [BitmapPlusPlus-ruby](https://ruby-rice.github.io/BitmapPlusPlus-ruby/) is a fully automated set of bindings generated by `ruby-bindgen` for the BitmapPlusPlus library.
|
|
8
|
+
|
|
9
|
+
For more complex libraries, like [OpenCV](https://github.com/opencv/opencv), some [customization](customizing.md) will likely be required.
|
|
10
|
+
|
|
11
|
+
## Getting Started
|
|
12
|
+
|
|
13
|
+
See [Getting Started](getting_started.md) for a step-by-step guide to creating your first Rice bindings.
|
|
14
|
+
|
|
15
|
+
## Output
|
|
16
|
+
|
|
17
|
+
See [Rice Output](output.md) for details on the generated files, including header files, project files, the include header, and the init function call graph.
|
|
18
|
+
|
|
19
|
+
## Build System
|
|
20
|
+
|
|
21
|
+
After generating Rice bindings, you will need to setup a build system for your extension. `ruby-bindgen` can generate [CMake build files](../cmake/cmake_bindings.md) to compile and link the generated bindings.
|
|
22
|
+
|
|
23
|
+
## Packaging
|
|
24
|
+
|
|
25
|
+
For packaging your extension as a gem, see the Rice [Packaging](https://ruby-rice.github.io/4.x/packaging/packaging/) documentation.
|
|
26
|
+
|
|
27
|
+
## Example
|
|
28
|
+
|
|
29
|
+
For a complete, fully automated example see [BitmapPlusPlus-ruby](https://ruby-rice.github.io/BitmapPlusPlus-ruby/).
|