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.
Files changed (115) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +7 -0
  3. data/LICENSE +25 -0
  4. data/README.md +68 -0
  5. data/Rakefile +8 -0
  6. data/bin/ruby-bindgen +133 -0
  7. data/docs/architecture.md +238 -0
  8. data/docs/c/c_bindings.md +65 -0
  9. data/docs/c/constants.md +21 -0
  10. data/docs/c/customizing.md +19 -0
  11. data/docs/c/filtering.md +24 -0
  12. data/docs/c/getting_started.md +56 -0
  13. data/docs/c/library_loading.md +53 -0
  14. data/docs/c/output.md +96 -0
  15. data/docs/c/types.md +61 -0
  16. data/docs/c/version_guards.md +105 -0
  17. data/docs/cmake/cmake_bindings.md +19 -0
  18. data/docs/cmake/filtering.md +26 -0
  19. data/docs/cmake/getting_started.md +52 -0
  20. data/docs/cmake/output.md +110 -0
  21. data/docs/configuration.md +351 -0
  22. data/docs/contributing.md +68 -0
  23. data/docs/cpp/buffers.md +24 -0
  24. data/docs/cpp/classes.md +139 -0
  25. data/docs/cpp/cpp_bindings.md +29 -0
  26. data/docs/cpp/customizing.md +124 -0
  27. data/docs/cpp/enums.md +42 -0
  28. data/docs/cpp/filtering.md +35 -0
  29. data/docs/cpp/getting_started.md +80 -0
  30. data/docs/cpp/iterators.md +94 -0
  31. data/docs/cpp/operators.md +170 -0
  32. data/docs/cpp/output.md +125 -0
  33. data/docs/cpp/templates.md +114 -0
  34. data/docs/examples.md +133 -0
  35. data/docs/index.md +133 -0
  36. data/docs/prior_art.md +37 -0
  37. data/docs/troubleshooting.md +243 -0
  38. data/docs/type_spelling.md +200 -0
  39. data/docs/updating_bindings.md +55 -0
  40. data/docs/version_guards.md +69 -0
  41. data/lib/ruby-bindgen/config.rb +63 -0
  42. data/lib/ruby-bindgen/generators/cmake/cmake.rb +171 -0
  43. data/lib/ruby-bindgen/generators/cmake/directory.erb +29 -0
  44. data/lib/ruby-bindgen/generators/cmake/guard.rb +55 -0
  45. data/lib/ruby-bindgen/generators/cmake/presets.erb +232 -0
  46. data/lib/ruby-bindgen/generators/cmake/project.erb +89 -0
  47. data/lib/ruby-bindgen/generators/ffi/callback.erb +1 -0
  48. data/lib/ruby-bindgen/generators/ffi/constant.erb +1 -0
  49. data/lib/ruby-bindgen/generators/ffi/enum_constant_decl.erb +1 -0
  50. data/lib/ruby-bindgen/generators/ffi/enum_decl.erb +4 -0
  51. data/lib/ruby-bindgen/generators/ffi/enum_decl_anonymous.erb +4 -0
  52. data/lib/ruby-bindgen/generators/ffi/ffi.rb +687 -0
  53. data/lib/ruby-bindgen/generators/ffi/field_decl.erb +1 -0
  54. data/lib/ruby-bindgen/generators/ffi/function.erb +5 -0
  55. data/lib/ruby-bindgen/generators/ffi/library.erb +39 -0
  56. data/lib/ruby-bindgen/generators/ffi/project.erb +18 -0
  57. data/lib/ruby-bindgen/generators/ffi/struct.erb +6 -0
  58. data/lib/ruby-bindgen/generators/ffi/translation_unit.erb +9 -0
  59. data/lib/ruby-bindgen/generators/ffi/typedef_decl.erb +1 -0
  60. data/lib/ruby-bindgen/generators/ffi/union.erb +6 -0
  61. data/lib/ruby-bindgen/generators/ffi/variable.erb +1 -0
  62. data/lib/ruby-bindgen/generators/ffi/version.erb +9 -0
  63. data/lib/ruby-bindgen/generators/ffi/version_method.erb +5 -0
  64. data/lib/ruby-bindgen/generators/generator.rb +52 -0
  65. data/lib/ruby-bindgen/generators/rice/auto_generated_base_class.erb +5 -0
  66. data/lib/ruby-bindgen/generators/rice/class.erb +31 -0
  67. data/lib/ruby-bindgen/generators/rice/class_template.erb +9 -0
  68. data/lib/ruby-bindgen/generators/rice/class_template_specialization.erb +10 -0
  69. data/lib/ruby-bindgen/generators/rice/constant.erb +9 -0
  70. data/lib/ruby-bindgen/generators/rice/constructor.erb +1 -0
  71. data/lib/ruby-bindgen/generators/rice/conversion_function.erb +4 -0
  72. data/lib/ruby-bindgen/generators/rice/cxx_iterator_method.erb +1 -0
  73. data/lib/ruby-bindgen/generators/rice/cxx_method.erb +6 -0
  74. data/lib/ruby-bindgen/generators/rice/enum_constant_decl.erb +7 -0
  75. data/lib/ruby-bindgen/generators/rice/enum_decl.erb +6 -0
  76. data/lib/ruby-bindgen/generators/rice/field_decl.erb +8 -0
  77. data/lib/ruby-bindgen/generators/rice/function.erb +6 -0
  78. data/lib/ruby-bindgen/generators/rice/function_pointer.rb +68 -0
  79. data/lib/ruby-bindgen/generators/rice/incomplete_class.erb +3 -0
  80. data/lib/ruby-bindgen/generators/rice/iterator_alias.erb +1 -0
  81. data/lib/ruby-bindgen/generators/rice/iterator_collector.rb +159 -0
  82. data/lib/ruby-bindgen/generators/rice/namespace.erb +5 -0
  83. data/lib/ruby-bindgen/generators/rice/non_member_operator_binary.erb +4 -0
  84. data/lib/ruby-bindgen/generators/rice/non_member_operator_inspect.erb +6 -0
  85. data/lib/ruby-bindgen/generators/rice/non_member_operator_unary.erb +4 -0
  86. data/lib/ruby-bindgen/generators/rice/operator[].erb +4 -0
  87. data/lib/ruby-bindgen/generators/rice/project.cpp.erb +18 -0
  88. data/lib/ruby-bindgen/generators/rice/project.hpp.erb +13 -0
  89. data/lib/ruby-bindgen/generators/rice/reference_qualifier.rb +495 -0
  90. data/lib/ruby-bindgen/generators/rice/rice.rb +1724 -0
  91. data/lib/ruby-bindgen/generators/rice/rice_include.hpp.erb +7 -0
  92. data/lib/ruby-bindgen/generators/rice/signature_builder.rb +230 -0
  93. data/lib/ruby-bindgen/generators/rice/template_resolver.rb +585 -0
  94. data/lib/ruby-bindgen/generators/rice/translation_unit.cpp.erb +40 -0
  95. data/lib/ruby-bindgen/generators/rice/translation_unit.hpp.erb +7 -0
  96. data/lib/ruby-bindgen/generators/rice/translation_unit.ipp.erb +3 -0
  97. data/lib/ruby-bindgen/generators/rice/type_index.rb +117 -0
  98. data/lib/ruby-bindgen/generators/rice/type_speller.rb +509 -0
  99. data/lib/ruby-bindgen/generators/rice/union.erb +5 -0
  100. data/lib/ruby-bindgen/generators/rice/variable.erb +5 -0
  101. data/lib/ruby-bindgen/inputter.rb +54 -0
  102. data/lib/ruby-bindgen/name_mapper.rb +65 -0
  103. data/lib/ruby-bindgen/namer.rb +138 -0
  104. data/lib/ruby-bindgen/outputter.rb +40 -0
  105. data/lib/ruby-bindgen/parser.rb +82 -0
  106. data/lib/ruby-bindgen/refinements/cursor.rb +57 -0
  107. data/lib/ruby-bindgen/refinements/string.rb +41 -0
  108. data/lib/ruby-bindgen/symbol_candidates.rb +282 -0
  109. data/lib/ruby-bindgen/symbol_entry.rb +21 -0
  110. data/lib/ruby-bindgen/symbols.rb +107 -0
  111. data/lib/ruby-bindgen/type_pointer_formatter.rb +35 -0
  112. data/lib/ruby-bindgen/version.rb +3 -0
  113. data/lib/ruby-bindgen.rb +19 -0
  114. data/ruby-bindgen.gemspec +52 -0
  115. 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
+ ```