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,114 @@
|
|
|
1
|
+
# Templates
|
|
2
|
+
|
|
3
|
+
`ruby-bindgen` generates bindings for C++ class templates, handling specializations, base class chains, and file organization automatically. For details on how Rice wraps class templates, see the Rice [Class Templates](https://ruby-rice.github.io/4.x/bindings/class_templates/) documentation.
|
|
4
|
+
|
|
5
|
+
## Template Classes and Specializations
|
|
6
|
+
|
|
7
|
+
`ruby-bindgen` generates bindings for template class instantiations created via `typedef` or `using` statements:
|
|
8
|
+
|
|
9
|
+
```cpp
|
|
10
|
+
template<typename T>
|
|
11
|
+
class Point
|
|
12
|
+
{
|
|
13
|
+
T x, y;
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
typedef Point<int> Point2i;
|
|
17
|
+
using Point2f = Point<float>;
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
Generated bindings correctly handle:
|
|
21
|
+
|
|
22
|
+
- Fully qualified template arguments (`cv::Point<int>` not `Point<int>`)
|
|
23
|
+
- Base class inheritance chains for templates
|
|
24
|
+
- Auto-generation of base class bindings when no typedef exists
|
|
25
|
+
|
|
26
|
+
## Template Argument Qualification
|
|
27
|
+
|
|
28
|
+
Unqualified type names in template arguments are automatically qualified:
|
|
29
|
+
|
|
30
|
+
```cpp
|
|
31
|
+
// Input: std::map<String, DictValue>::iterator
|
|
32
|
+
// Output: std::map<cv::String, cv::dnn::DictValue>::iterator
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## Template Base Classes
|
|
36
|
+
|
|
37
|
+
When a class inherits from a template instantiation, the base class binding is auto-generated if no typedef exists:
|
|
38
|
+
|
|
39
|
+
```cpp
|
|
40
|
+
class PlaneWarper : public WarperBase<PlaneProjector>
|
|
41
|
+
{
|
|
42
|
+
};
|
|
43
|
+
// Auto-generates WarperBasePlaneProjector binding
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## Inheritance Chain Resolution
|
|
47
|
+
|
|
48
|
+
For template typedefs with base classes, the entire inheritance chain is resolved and generated in the correct order.
|
|
49
|
+
|
|
50
|
+
### Cross-File Duplicate Instantiations
|
|
51
|
+
|
|
52
|
+
When a template typedef in one header inherits from a template defined in another header, `ruby-bindgen` will re-instantiate the ancestor chain in the derived file even if those ancestors were already instantiated in the base file. For example, if `types.hpp` has `typedef Scalar_<double> Scalar` and `Scalar_` inherits from `Vec<double, 4>` which inherits from `Matx<double, 4, 1>`, the generated `types-rb.cpp` will include instantiation calls for all three — even though `Vec4d` and `Matx41d` were already emitted in `matx-rb.cpp`.
|
|
53
|
+
|
|
54
|
+
Rice handles this gracefully at runtime (re-registering an already-registered type is a no-op), so the duplicate instantiations are harmless but redundant. If this causes issues, you can remove the duplicate lines from the generated file by hand or use a [refinement file](customizing.md) to control instantiation order.
|
|
55
|
+
|
|
56
|
+
## Template Instantiate Files (.ipp)
|
|
57
|
+
|
|
58
|
+
When a header contains class templates with specializations (via `typedef` or `using`), `ruby-bindgen` generates reusable `_instantiate` template functions. These are placed in a separate `.ipp` file to enable reuse without duplicate symbol errors.
|
|
59
|
+
|
|
60
|
+
**Example**: For `templates.hpp` containing:
|
|
61
|
+
|
|
62
|
+
```cpp
|
|
63
|
+
template<typename T>
|
|
64
|
+
class Matrix
|
|
65
|
+
{
|
|
66
|
+
...
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
typedef Matrix<float> Matrixf;
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
`ruby-bindgen` generates:
|
|
73
|
+
|
|
74
|
+
**templates-rb.ipp** (template instantiate functions):
|
|
75
|
+
```cpp
|
|
76
|
+
#include <templates.hpp>
|
|
77
|
+
#include "templates-rb.hpp"
|
|
78
|
+
|
|
79
|
+
using namespace Rice;
|
|
80
|
+
|
|
81
|
+
template<typename T>
|
|
82
|
+
inline Rice::Data_Type<Matrix<T>> Matrix_instantiate(Rice::Module parent, const char* name)
|
|
83
|
+
{
|
|
84
|
+
return Rice::define_class_under<Matrix<T>>(parent, name).
|
|
85
|
+
define_constructor(Constructor<Matrix<T>>()).
|
|
86
|
+
define_attr("data", &Matrix<T>::data);
|
|
87
|
+
}
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
**templates-rb.cpp** (Init function only):
|
|
91
|
+
```cpp
|
|
92
|
+
#include "templates-rb.ipp"
|
|
93
|
+
|
|
94
|
+
void Init_Templates()
|
|
95
|
+
{
|
|
96
|
+
Rice::Data_Type<Matrix<float>> rb_cMatrixf =
|
|
97
|
+
Matrix_instantiate<float>(Rice::Module(rb_cObject), "Matrixf");
|
|
98
|
+
}
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
### Reusing Instantiate Functions
|
|
102
|
+
|
|
103
|
+
The `.ipp` separation enables [refinement files](customizing.md) to reuse `_instantiate` functions without causing duplicate `Init_` symbol errors:
|
|
104
|
+
|
|
105
|
+
```cpp
|
|
106
|
+
// mat_refinements.cpp - Custom extensions
|
|
107
|
+
#include "mat-rb.ipp" // Gets _instantiate functions, NOT Init_Core_Mat
|
|
108
|
+
|
|
109
|
+
void Init_Mat_Refinements()
|
|
110
|
+
{
|
|
111
|
+
Rice::Data_Type<cv::Mat_<double>> rb_cMat1d =
|
|
112
|
+
Mat__instantiate<double>(rb_mCv, "Mat1d");
|
|
113
|
+
}
|
|
114
|
+
```
|
data/docs/examples.md
ADDED
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
# Examples
|
|
2
|
+
|
|
3
|
+
## Reference projects
|
|
4
|
+
|
|
5
|
+
Three published gems use `ruby-bindgen` and are good places to read working
|
|
6
|
+
configuration, layout, and CI when starting your own bindings project.
|
|
7
|
+
|
|
8
|
+
| Project | Format | Size | When to use as a reference |
|
|
9
|
+
|-------------------------------------------------------------------------|------------|------------|-------------------------------------------------------------------------------------------------------------------------------------|
|
|
10
|
+
| [BitmapPlusPlus-ruby](https://ruby-rice.github.io/BitmapPlusPlus-ruby/) | Rice (C++) | ~1 file | Wrapping a small, header-only C++ library. The cleanest end-to-end gem layout (ext/, lib/, sig/, test/, docs/, CMakePresets.json). |
|
|
11
|
+
| [proj4rb](https://cfis.github.io/proj4rb/) | FFI (C) | medium | Wrapping a C library via FFI rather than a compiled extension. Shows library loading, version pinning, and Ruby-side wrappers. |
|
|
12
|
+
| [opencv-ruby](https://github.com/cfis/opencv-ruby) | Rice (C++) | very large | Wrapping a large, complex C++ library that needs heavy customization, CUDA guards, and post-regeneration manual edits. |
|
|
13
|
+
|
|
14
|
+
For learning, start with **BitmapPlusPlus-ruby** for C++ or **proj4rb** for C.
|
|
15
|
+
Read **opencv-ruby** later, as a study of how to scale the same approach to
|
|
16
|
+
1,000+ classes and 10,000+ method bindings.
|
|
17
|
+
|
|
18
|
+
## Minimal config snippets
|
|
19
|
+
|
|
20
|
+
Minimal end-to-end examples for each output format.
|
|
21
|
+
|
|
22
|
+
## Rice (C++)
|
|
23
|
+
|
|
24
|
+
`rice-bindings.yaml`:
|
|
25
|
+
|
|
26
|
+
```yaml
|
|
27
|
+
project: sample_ext
|
|
28
|
+
input: ./include
|
|
29
|
+
output: ./ext/generated
|
|
30
|
+
format: Rice
|
|
31
|
+
|
|
32
|
+
match:
|
|
33
|
+
- "**/*.hpp"
|
|
34
|
+
|
|
35
|
+
clang:
|
|
36
|
+
args:
|
|
37
|
+
- -I./include
|
|
38
|
+
- -std=c++17
|
|
39
|
+
- -xc++
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
Run:
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
ruby-bindgen rice-bindings.yaml
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
Output:
|
|
49
|
+
- One `*-rb.cpp` and `*-rb.hpp` per header
|
|
50
|
+
- Optional `*-rb.ipp` files when template `_instantiate` functions are generated
|
|
51
|
+
- Project files when `project` is set (`sample_ext-rb.cpp`, `sample_ext-rb.hpp`)
|
|
52
|
+
|
|
53
|
+
## FFI (C)
|
|
54
|
+
|
|
55
|
+
`ffi-bindings.yaml`:
|
|
56
|
+
|
|
57
|
+
```yaml
|
|
58
|
+
project: mylib
|
|
59
|
+
input: ./include
|
|
60
|
+
output: ./lib/generated
|
|
61
|
+
format: FFI
|
|
62
|
+
|
|
63
|
+
match:
|
|
64
|
+
- "**/*.h"
|
|
65
|
+
|
|
66
|
+
library_names:
|
|
67
|
+
- mylib
|
|
68
|
+
library_versions:
|
|
69
|
+
- "2"
|
|
70
|
+
- "1"
|
|
71
|
+
|
|
72
|
+
clang:
|
|
73
|
+
args:
|
|
74
|
+
- -I./include
|
|
75
|
+
- -xc
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
Run:
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
ruby-bindgen ffi-bindings.yaml
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
Output:
|
|
85
|
+
- A project loader file (`mylib_ffi.rb`) with `require 'ffi'`, `ffi_lib`, and `require_relative` calls
|
|
86
|
+
- One Ruby content file per header with enums, structs, callbacks, and `attach_function` calls
|
|
87
|
+
|
|
88
|
+
## CMake (for Rice output)
|
|
89
|
+
|
|
90
|
+
**Important:** CMake generation must run after Rice generation because it scans the output directory for `*-rb.cpp` files.
|
|
91
|
+
|
|
92
|
+
`rice-bindings.yaml`:
|
|
93
|
+
|
|
94
|
+
```yaml
|
|
95
|
+
project: sample_ext
|
|
96
|
+
input: ./include
|
|
97
|
+
output: ./ext/generated
|
|
98
|
+
format: Rice
|
|
99
|
+
match:
|
|
100
|
+
- "**/*.hpp"
|
|
101
|
+
clang:
|
|
102
|
+
args:
|
|
103
|
+
- -I./include
|
|
104
|
+
- -std=c++17
|
|
105
|
+
- -xc++
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
`cmake-bindings.yaml`:
|
|
109
|
+
|
|
110
|
+
```yaml
|
|
111
|
+
project: sample_ext
|
|
112
|
+
output: ./ext/generated
|
|
113
|
+
format: CMake
|
|
114
|
+
# input defaults to output for CMake and scans ./ext/generated for *-rb.cpp
|
|
115
|
+
|
|
116
|
+
include_dirs:
|
|
117
|
+
- "${CMAKE_CURRENT_SOURCE_DIR}/../include"
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
Run:
|
|
121
|
+
|
|
122
|
+
```bash
|
|
123
|
+
ruby-bindgen rice-bindings.yaml
|
|
124
|
+
ruby-bindgen cmake-bindings.yaml
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
Then build:
|
|
128
|
+
|
|
129
|
+
```bash
|
|
130
|
+
cd ./ext/generated
|
|
131
|
+
cmake --preset linux-debug
|
|
132
|
+
cmake --build build/linux-debug
|
|
133
|
+
```
|
data/docs/index.md
ADDED
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
# ruby-bindgen
|
|
2
|
+
|
|
3
|
+
Wrapping C and C++ libraries by hand is a long, arduous task. For large, complex libraries it can take months. As a result, many C/C++ libraries are either never exposed to Ruby or their bindings quickly become outdated, especially in scientific and technical domains.
|
|
4
|
+
|
|
5
|
+
`ruby-bindgen` and its ecosystem solve this problem by automating binding generation. For simpler libraries, it can generate ready-to-use bindings. For more complex libraries, it can also generate bindings but some [customizations](#customization) may be needed.
|
|
6
|
+
|
|
7
|
+
As an example, there are older, hand-crafted Ruby [bindings](https://github.com/ruby-opencv/ruby-opencv) for [OpenCV](https://opencv.org/). However, they are based on the C API which was subsequently removed by the OpenCV project. `ruby-bindgen` was used to create new OpenCV [bindings](https://github.com/cfis/opencv-ruby) based on the new C++ API. The bindings wrap over [1,000](https://cfis.github.io/opencv-ruby/) C++ classes and almost [10,000](https://cfis.github.io/opencv-ruby/) method calls. Imagine having to do that by hand!
|
|
8
|
+
|
|
9
|
+
## Ecosystem
|
|
10
|
+
`ruby-bindgen` is part of the C/C++ to Ruby toolchain.
|
|
11
|
+
|
|
12
|
+
```mermaid
|
|
13
|
+
flowchart TD
|
|
14
|
+
H["C/C++ headers"] --> CL["ffi-clang"]
|
|
15
|
+
CL --> RB["ruby-bindgen"]
|
|
16
|
+
RB --> F["C (ffi)"]
|
|
17
|
+
RB --> R["C++ (Rice)"]
|
|
18
|
+
RB --> C["Build (CMake)"]
|
|
19
|
+
|
|
20
|
+
click CL "https://github.com/ioquatix/ffi-clang" "ffi-clang"
|
|
21
|
+
click RB "https://github.com/ruby-rice/ruby-bindgen" "ruby-bindgen"
|
|
22
|
+
click R "https://github.com/ruby-rice/rice" "Rice"
|
|
23
|
+
click F "https://github.com/ffi/ffi" "FFI"
|
|
24
|
+
click C "https://cmake.org/" "CMake"
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
The components of the toolchain include:
|
|
28
|
+
|
|
29
|
+
- [ffi-clang](https://github.com/ioquatix/ffi-clang) - exposes [libclang](https://clang.llvm.org/) parsing APIs to Ruby.
|
|
30
|
+
- [ruby-bindgen](https://github.com/ruby-rice/ruby-bindgen) - generates bindings.
|
|
31
|
+
- [FFI](https://github.com/ffi/ffi) - enables direct C library calls from Ruby without compiling a C extension.
|
|
32
|
+
- [Rice](https://github.com/ruby-rice/rice) - handles C++/Ruby type conversion and native extension integration.
|
|
33
|
+
- [CMake](https://cmake.org/) - builds generated Rice wrappers into loadable extension binaries.
|
|
34
|
+
|
|
35
|
+
## Prerequisites
|
|
36
|
+
|
|
37
|
+
- Ruby 3.2 or later
|
|
38
|
+
- libclang (provided by LLVM/Clang)
|
|
39
|
+
|
|
40
|
+
## Installation
|
|
41
|
+
|
|
42
|
+
To install `ruby-bindgen` run the following command:
|
|
43
|
+
|
|
44
|
+
```console
|
|
45
|
+
gem install ruby-bindgen
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## Getting Started
|
|
49
|
+
|
|
50
|
+
`ruby-bindgen` is driven by a [configuration](configuration.md) file. To get started, first decide what type of library you are wrapping:
|
|
51
|
+
|
|
52
|
+
```mermaid
|
|
53
|
+
flowchart TD
|
|
54
|
+
A{"C or C++?"}
|
|
55
|
+
A -->|C| B["FFI"]
|
|
56
|
+
A -->|C++| C["Rice"]
|
|
57
|
+
C --> D{"CMake or<br/>extconf.rb?"}
|
|
58
|
+
D -->|CMake| E["CMake"]
|
|
59
|
+
D -->|extconf.rb| F["Done"]
|
|
60
|
+
B --> F
|
|
61
|
+
E --> F
|
|
62
|
+
|
|
63
|
+
click B "c/c_bindings.md" "C Bindings"
|
|
64
|
+
click C "cpp/cpp_bindings.md" "C++ Bindings"
|
|
65
|
+
click E "cmake/cmake_bindings.md" "CMake Bindings"
|
|
66
|
+
click D "https://ruby-rice.github.io/4.x/packaging/extconf/" "Rice extconf.rb packaging"
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
If a library provides both C and C++ APIs, use the C API! It is usually simpler to wrap and maintain and does not require users to compile extensions.
|
|
70
|
+
|
|
71
|
+
Once you have decided the format, create a simple [configuration](configuration.md) file and set its `format` field to `FFI`, `Rice` or `CMake`.
|
|
72
|
+
|
|
73
|
+
- `output` is always required
|
|
74
|
+
- `input` is required for `FFI` and `Rice`; for `CMake` it defaults to `output`
|
|
75
|
+
- `project` is required for `FFI` and optional for `Rice` and `CMake`
|
|
76
|
+
|
|
77
|
+
For example, a minimal Rice configuration looks like:
|
|
78
|
+
|
|
79
|
+
```yaml
|
|
80
|
+
project: my_extension
|
|
81
|
+
input: /path/to/headers
|
|
82
|
+
output: /path/to/output
|
|
83
|
+
format: Rice
|
|
84
|
+
|
|
85
|
+
match:
|
|
86
|
+
- "**/*.hpp" # use "**/*.h" for C headers in FFI configs
|
|
87
|
+
|
|
88
|
+
clang:
|
|
89
|
+
args:
|
|
90
|
+
- -I/path/to/includes
|
|
91
|
+
- -xc++ # omit for C libraries
|
|
92
|
+
```
|
|
93
|
+
See [Configuration](configuration.md) for all options.
|
|
94
|
+
|
|
95
|
+
For much more details, jump to the documentation page for each format:
|
|
96
|
+
|
|
97
|
+
| Format | Next Step |
|
|
98
|
+
|-----------|-------------------------------------|
|
|
99
|
+
| **FFI** | [C Bindings](c/c_bindings.md) |
|
|
100
|
+
| **Rice** | [C++ Bindings](cpp/cpp_bindings.md) |
|
|
101
|
+
| **CMake** | [CMake Bindings](cmake/cmake_bindings.md) |
|
|
102
|
+
|
|
103
|
+
Finally generate bindings by running the command:
|
|
104
|
+
|
|
105
|
+
```bash
|
|
106
|
+
ruby-bindgen /path/to/bindings.yaml
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
## Naming Conventions
|
|
110
|
+
|
|
111
|
+
`ruby-bindgen` follows Ruby naming conventions for both C and C++ bindings:
|
|
112
|
+
|
|
113
|
+
- Class/Module names: `UpperCamelCase`
|
|
114
|
+
- Constants: `UPPER_CASE`
|
|
115
|
+
- Methods/Functions: `snake_case`
|
|
116
|
+
- Enum values: `snake_case` symbols (FFI) or scoped constants (Rice)
|
|
117
|
+
|
|
118
|
+
In addition, methods that return boolean values have `?` appended to their names and `is_` removed if present. For example, `is_open` becomes `open?`.
|
|
119
|
+
|
|
120
|
+
## Customization
|
|
121
|
+
|
|
122
|
+
Out of the box, `ruby-bindgen` applies sensible defaults and heuristics. For most libraries you will need to fine-tune the output. The [configuration](configuration.md) file provides several knobs:
|
|
123
|
+
|
|
124
|
+
- **[Symbol filtering](configuration.md#symbols)** — skip functions, classes, enums, typedefs, unions, or variables by name or regex pattern. Useful for internal APIs, linker-error symbols, or platform-specific code.
|
|
125
|
+
- **[Symbol overrides](configuration.md#overrides-ffi-only)** (FFI) — replace a generated function signature when the heuristics pick the wrong type (e.g., `int` → `:bool`, `ulong` → `:size_t`).
|
|
126
|
+
- **[Version guards](configuration.md#versions)** — wrap symbols in `#if VERSION >= N` preprocessor guards so bindings compile against multiple library versions.
|
|
127
|
+
- **[Name mappings](configuration.md#name-mappings)** — override generated Ruby class and method names with exact strings or regex patterns with capture-group substitution.
|
|
128
|
+
- **[Export macros](configuration.md#export-macros)** — only include functions marked with specific visibility macros (e.g., `CV_EXPORTS`), preventing linker errors from internal symbols.
|
|
129
|
+
- **[Module naming](configuration.md#c-ffi-options)** (FFI) — set the Ruby module name, including nested modules like `Proj::Api`.
|
|
130
|
+
|
|
131
|
+
## Packaging
|
|
132
|
+
|
|
133
|
+
For Rice (C++) bindings, see the Rice [Packaging](https://ruby-rice.github.io/4.x/packaging/packaging/) documentation for how to package your extension as a gem.
|
data/docs/prior_art.md
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# Prior Art
|
|
2
|
+
|
|
3
|
+
This page lists related projects and adjacent tools that influenced, overlap with, or can complement `ruby-bindgen`.
|
|
4
|
+
|
|
5
|
+
## C/C++
|
|
6
|
+
|
|
7
|
+
### SWIG
|
|
8
|
+
|
|
9
|
+
- Project: [SWIG](https://www.swig.org/)
|
|
10
|
+
- Scope: Multi-language binding generator for C and C++
|
|
11
|
+
- Notes: Generates bindings for many languages including Ruby, Python, Java, and Go. Uses its own interface definition files rather than parsing headers directly. The most established tool in this space — active since 1996.
|
|
12
|
+
|
|
13
|
+
### ffi_gen
|
|
14
|
+
|
|
15
|
+
- Project: [ffi_gen](https://github.com/ffi/ffi_gen)
|
|
16
|
+
- Scope: Generate Ruby FFI wrappers for C APIs
|
|
17
|
+
- Notes: Has not been updated in over a decade and includes custom libclang bindings versus using [ffi-clang](https://github.com/ioquatix/ffi-clang).
|
|
18
|
+
|
|
19
|
+
### rbind
|
|
20
|
+
|
|
21
|
+
- Project: [rbind](https://github.com/D-Alex/rbind)
|
|
22
|
+
- Scope: C++ binding generator with a custom parser approach
|
|
23
|
+
- Notes: Has not been updated in four years and is coupled to OpenCV
|
|
24
|
+
|
|
25
|
+
## Rust
|
|
26
|
+
|
|
27
|
+
### Magnus
|
|
28
|
+
|
|
29
|
+
- Project: [magnus](https://github.com/matsadler/magnus)
|
|
30
|
+
- Scope: Rust crate for Ruby bindings
|
|
31
|
+
- Notes: Not a direct Ruby generator alternative for C/C++, but useful as a design reference for Ruby-native APIs from another language.
|
|
32
|
+
|
|
33
|
+
### rb-sys
|
|
34
|
+
|
|
35
|
+
- Project: [rb-sys](https://github.com/oxidize-rb/rb-sys)
|
|
36
|
+
- Scope: Rust bindings for the Ruby C API
|
|
37
|
+
- Notes: Provides low-level Rust bindings to Ruby, auto-generated from `ruby.h` using rust-bindgen.
|
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
# Troubleshooting
|
|
2
|
+
|
|
3
|
+
Common failures and how to fix them. Section headings match the exact
|
|
4
|
+
error string `ruby-bindgen` prints, so you can search for the message
|
|
5
|
+
verbatim.
|
|
6
|
+
|
|
7
|
+
## Pipeline and Failure Points
|
|
8
|
+
|
|
9
|
+
```mermaid
|
|
10
|
+
flowchart LR
|
|
11
|
+
A["config.yaml"] --> B["ruby-bindgen"]
|
|
12
|
+
B --> C["libclang parse"]
|
|
13
|
+
C --> D["generated bindings"]
|
|
14
|
+
D --> E["compile/link (Rice/CMake)"]
|
|
15
|
+
D --> F["runtime load (FFI)"]
|
|
16
|
+
|
|
17
|
+
X1["Fail: bad path / missing dirs"] -.-> A
|
|
18
|
+
X2["Fail: libclang not found"] -.-> C
|
|
19
|
+
X3["Fail: missing include args"] -.-> C
|
|
20
|
+
X4["Fail: empty output due to filters"] -.-> D
|
|
21
|
+
X5["Fail: linker missing symbols"] -.-> E
|
|
22
|
+
X6["Fail: shared library not found"] -.-> F
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
For the full backtrace on any of these errors, set `BINDGEN_DEBUG=1`.
|
|
26
|
+
|
|
27
|
+
## `Error: Config file not found: <path>`
|
|
28
|
+
|
|
29
|
+
Cause:
|
|
30
|
+
- Wrong path passed to `ruby-bindgen`
|
|
31
|
+
|
|
32
|
+
Fix:
|
|
33
|
+
```bash
|
|
34
|
+
ruby-bindgen /absolute/path/to/config.yaml
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## `Error: Config must specify 'output'`
|
|
38
|
+
|
|
39
|
+
Cause:
|
|
40
|
+
- The YAML file is missing the required top-level `output:` key.
|
|
41
|
+
|
|
42
|
+
Fix:
|
|
43
|
+
- Add `output: /path/to/output/dir` (the directory generated bindings are written to).
|
|
44
|
+
|
|
45
|
+
## `Error: Config must specify 'format'`
|
|
46
|
+
|
|
47
|
+
Cause:
|
|
48
|
+
- The YAML file is missing the required top-level `format:` key.
|
|
49
|
+
|
|
50
|
+
Fix:
|
|
51
|
+
- Add `format: Rice` (C++ via Rice), `format: FFI` (C via FFI), or `format: CMake` (CMake build files).
|
|
52
|
+
|
|
53
|
+
## `Error: Format must be 'FFI', 'Rice', or 'CMake', got: <value>`
|
|
54
|
+
|
|
55
|
+
Cause:
|
|
56
|
+
- `format:` is set to something other than the three accepted values. Match is case-sensitive.
|
|
57
|
+
|
|
58
|
+
Fix:
|
|
59
|
+
- Use exactly `Rice`, `FFI`, or `CMake`.
|
|
60
|
+
|
|
61
|
+
## `Error: Input path must be a directory: <path>`
|
|
62
|
+
|
|
63
|
+
Cause:
|
|
64
|
+
- `input:` points to a missing path or file (not a directory).
|
|
65
|
+
|
|
66
|
+
Fix:
|
|
67
|
+
- Set `input:` to an existing directory containing headers. For `format: CMake`, `input:` defaults to `output:` (the directory containing the generated `*-rb.cpp` files).
|
|
68
|
+
|
|
69
|
+
## `Error: Output path must be a directory: <path>`
|
|
70
|
+
|
|
71
|
+
Cause:
|
|
72
|
+
- `output:` directory does not exist.
|
|
73
|
+
|
|
74
|
+
Fix:
|
|
75
|
+
```bash
|
|
76
|
+
mkdir -p /path/to/output
|
|
77
|
+
ruby-bindgen config.yaml
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
## `Error: Project name must be a valid C/C++ identifier (hyphens allowed): <name>`
|
|
81
|
+
|
|
82
|
+
Cause:
|
|
83
|
+
- `project:` contains characters other than letters, digits, underscore, or hyphen, or starts with a digit.
|
|
84
|
+
|
|
85
|
+
Fix:
|
|
86
|
+
- Use a name like `my_extension` or `my-extension`. Hyphens are normalized to underscores in generated C++ identifiers.
|
|
87
|
+
|
|
88
|
+
## `Error: Rice include header not found: <path>`
|
|
89
|
+
|
|
90
|
+
Cause:
|
|
91
|
+
- `include:` (under a Rice config) names a header that does not exist under `output:`.
|
|
92
|
+
|
|
93
|
+
Fix:
|
|
94
|
+
- Confirm the file path is relative to `output:` and that the header is present before running. Without it, every generated `*-rb.hpp` would `#include` a missing file and the C++ build would fail far from the cause.
|
|
95
|
+
|
|
96
|
+
## `Error: libclang library not found: <path>`
|
|
97
|
+
|
|
98
|
+
Cause:
|
|
99
|
+
- `clang.libclang:` (or `clang-cl.libclang:`) explicitly points to a missing shared library.
|
|
100
|
+
|
|
101
|
+
Fix:
|
|
102
|
+
- Either correct the path or remove the `libclang:` key and rely on `ffi-clang`'s default discovery.
|
|
103
|
+
|
|
104
|
+
## `Error: clang args must be a YAML list, got: String`
|
|
105
|
+
|
|
106
|
+
Cause:
|
|
107
|
+
- `clang.args:` (or `clang-cl.args:`) is written as a single string instead of a YAML sequence.
|
|
108
|
+
|
|
109
|
+
Fix:
|
|
110
|
+
```yaml
|
|
111
|
+
clang:
|
|
112
|
+
args:
|
|
113
|
+
- -I/usr/include
|
|
114
|
+
- -std=c++17
|
|
115
|
+
- -xc++
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
## `libclang` runtime load failures
|
|
119
|
+
|
|
120
|
+
Symptoms:
|
|
121
|
+
- FFI load error for libclang
|
|
122
|
+
- Parser startup fails before processing files
|
|
123
|
+
|
|
124
|
+
Fix:
|
|
125
|
+
- Set the toolchain `libclang` path in config (`clang:` or `clang-cl:`)
|
|
126
|
+
- Verify the shared library exists and matches your architecture
|
|
127
|
+
|
|
128
|
+
Example:
|
|
129
|
+
|
|
130
|
+
```yaml
|
|
131
|
+
clang:
|
|
132
|
+
libclang: /usr/lib/llvm-17/lib/libclang.so
|
|
133
|
+
args:
|
|
134
|
+
- -I/usr/lib/clang/17/include
|
|
135
|
+
- -xc++
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
## Parse errors for standard/library types
|
|
139
|
+
|
|
140
|
+
Symptoms:
|
|
141
|
+
- Many unknown-type diagnostics
|
|
142
|
+
- Generated files missing expected classes/functions
|
|
143
|
+
|
|
144
|
+
Cause:
|
|
145
|
+
- Missing include paths or language flags in `clang.args`
|
|
146
|
+
|
|
147
|
+
Fix:
|
|
148
|
+
- Add system and project include paths
|
|
149
|
+
- Add `-xc++` for C++ headers (or `-xc` for C)
|
|
150
|
+
- Add `-std=c++17` (or your required standard)
|
|
151
|
+
|
|
152
|
+
## Empty or incomplete generated output
|
|
153
|
+
|
|
154
|
+
Cause:
|
|
155
|
+
- `match` glob too narrow
|
|
156
|
+
- `skip` glob too broad
|
|
157
|
+
- `export_macros` filters out everything
|
|
158
|
+
|
|
159
|
+
Fix:
|
|
160
|
+
- Validate `match`/`skip` patterns
|
|
161
|
+
- Temporarily remove `export_macros` and re-run to confirm filtering
|
|
162
|
+
|
|
163
|
+
## C++ compile failures after generation
|
|
164
|
+
|
|
165
|
+
Common causes:
|
|
166
|
+
- Missing includes in generated files
|
|
167
|
+
- Default argument edge cases
|
|
168
|
+
- Symbols declared in headers but not exported by the library
|
|
169
|
+
|
|
170
|
+
Fix:
|
|
171
|
+
- Use `symbols.skip` for problematic APIs, including overload-specific signatures when needed
|
|
172
|
+
- Add refinement files for custom behavior
|
|
173
|
+
- See [Updating Bindings](updating_bindings.md) for durable maintenance workflows
|
|
174
|
+
|
|
175
|
+
## CMake generation produced empty `target_sources`
|
|
176
|
+
|
|
177
|
+
Cause:
|
|
178
|
+
- No `*-rb.cpp` files in `output` yet
|
|
179
|
+
|
|
180
|
+
Fix:
|
|
181
|
+
- Run `format: Rice` generation first
|
|
182
|
+
- Then run `format: CMake`
|
|
183
|
+
|
|
184
|
+
## FFI runtime cannot load shared library
|
|
185
|
+
|
|
186
|
+
Cause:
|
|
187
|
+
- `library_names` / `library_versions` do not match installed artifacts
|
|
188
|
+
|
|
189
|
+
Fix:
|
|
190
|
+
- Set `library_names` to base names
|
|
191
|
+
- Add likely version suffixes to `library_versions`
|
|
192
|
+
- If the library is outside the standard loader path, use `library_search_path` and set the corresponding environment variable at runtime
|
|
193
|
+
- Confirm installation path is on loader search path
|
|
194
|
+
|
|
195
|
+
## Windows-specific
|
|
196
|
+
|
|
197
|
+
ruby-bindgen runs on Windows under both MSVC (mswin Ruby builds) and MinGW.
|
|
198
|
+
The toolchain is auto-detected via `RUBY_PLATFORM` — `mswin` uses the
|
|
199
|
+
`clang-cl:` config block, everything else uses `clang:`.
|
|
200
|
+
|
|
201
|
+
### Choosing MSVC vs MinGW
|
|
202
|
+
|
|
203
|
+
- **MSVC (`mswin`)** — recommended if you need to link against vcpkg or
|
|
204
|
+
other MSVC-built dependencies. Uses `clang-cl` (Clang's MSVC-compatible
|
|
205
|
+
driver) for header parsing.
|
|
206
|
+
- **MinGW** — uses regular `clang` and works with Unix-style include paths.
|
|
207
|
+
Easier setup if the library is already buildable with MinGW.
|
|
208
|
+
|
|
209
|
+
### libclang load failure on Windows
|
|
210
|
+
|
|
211
|
+
Symptoms:
|
|
212
|
+
- `Error: libclang library not found: ...`
|
|
213
|
+
- FFI load error at startup
|
|
214
|
+
|
|
215
|
+
Fix:
|
|
216
|
+
- Visual Studio bundles libclang at
|
|
217
|
+
`C:\Program Files\Microsoft Visual Studio\<edition>\<year>\VC\Tools\Llvm\x64\bin\libclang.dll`.
|
|
218
|
+
Either install the "Clang/LLVM tools" component in the VS installer or
|
|
219
|
+
install LLVM standalone and set `clang-cl.libclang:` to its `libclang.dll`.
|
|
220
|
+
- For MinGW Ruby, install LLVM via `pacman -S mingw-w64-clang-x86_64-clang`
|
|
221
|
+
(or the appropriate variant) and set `clang.libclang:` to the resulting
|
|
222
|
+
`libclang.dll`.
|
|
223
|
+
|
|
224
|
+
### Path separators
|
|
225
|
+
|
|
226
|
+
Use forward slashes (`/`) in YAML config paths even on Windows. The
|
|
227
|
+
inputter normalizes backslashes internally, but forward slashes avoid
|
|
228
|
+
YAML escape issues.
|
|
229
|
+
|
|
230
|
+
### vcpkg integration (MSVC)
|
|
231
|
+
|
|
232
|
+
If your library is installed via vcpkg, point `clang-cl.args:` at the
|
|
233
|
+
vcpkg include directory and `library_search_path:` at the bin directory:
|
|
234
|
+
|
|
235
|
+
```yaml
|
|
236
|
+
clang-cl:
|
|
237
|
+
libclang: C:/Program Files/Microsoft Visual Studio/2022/Community/VC/Tools/Llvm/x64/bin/libclang.dll
|
|
238
|
+
args:
|
|
239
|
+
- -IC:/vcpkg/installed/x64-windows/include
|
|
240
|
+
- -std:c++17
|
|
241
|
+
|
|
242
|
+
library_search_path: PATH
|
|
243
|
+
```
|