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,53 @@
1
+ # Library Loading
2
+
3
+ FFI loads the target shared library at runtime. The `library_names`, `library_versions`, and `library_search_path` configuration options specify where to find the library.
4
+
5
+ ## Library Names
6
+
7
+ `library_names` specifies the base names of the shared library. The loader turns each base name into one or more search names and passes them to `ffi_lib`:
8
+
9
+ | Platform | `library_names: ["proj"]` searches for |
10
+ |----------|-----------------------------------------------------|
11
+ | Linux | `libproj`, `libproj.so.{version}` |
12
+ | macOS | `libproj`, `libproj.{version}` |
13
+ | MinGW | `libproj`, `libproj-{version}` |
14
+ | MSVC | `libproj`, `proj_{version}` |
15
+
16
+ The unversioned `libproj` entry is always included as a fallback.
17
+
18
+ The platform's loader appends the conventional shared-library suffix at
19
+ load time (`.so` on Linux, `.dylib` on macOS, `.dll` on Windows), so a
20
+ macOS entry like `libproj.25` resolves to `libproj.25.dylib`.
21
+
22
+ ## Library Versions
23
+
24
+ C shared libraries use version suffixes that vary by platform and change across releases. `library_versions` lets you list known version suffixes so FFI can find whichever version is installed.
25
+
26
+ For example, the [PROJ](https://proj.org/) coordinate transformation library has used these version suffixes across releases:
27
+
28
+ ```yaml
29
+ library_names:
30
+ - proj
31
+ library_versions:
32
+ - "25" # PROJ 9.2
33
+ - "22" # PROJ 8.x
34
+ - "19" # PROJ 7.x
35
+ - "17" # PROJ 6.1, 6.2
36
+ - "15" # PROJ 6.0
37
+ ```
38
+
39
+ This generates search names like `libproj.so.25`, `libproj.so.22`, etc. on Linux, `libproj.25` on macOS, `libproj-25` on MinGW, and `proj_25` on MSVC. The loader sorts the version suffixes in descending order before emitting them, so newer versions are tried first.
40
+
41
+ If `library_versions` is omitted, only the unversioned name is searched. This works on most systems where the package manager creates an unversioned symlink (e.g., `libproj.so` → `libproj.so.25`).
42
+
43
+ ## Library Search Path
44
+
45
+ If the library is installed outside standard operating system search paths, use `library_search_path`:
46
+
47
+ ```yaml
48
+ library_names:
49
+ - proj
50
+ library_search_path: PROJ_LIB_PATH
51
+ ```
52
+
53
+ This generates loader code that checks `ENV["PROJ_LIB_PATH"]` at runtime and prepends that directory to every generated search name before falling back to the default search list.
data/docs/c/output.md ADDED
@@ -0,0 +1,96 @@
1
+ # FFI Output
2
+
3
+ `ruby-bindgen` generates a project file, an optional version file and one FFI binding file per header. The project file first loads the target library and then binding files.
4
+
5
+ ``` mermaid
6
+ flowchart LR
7
+ subgraph Input
8
+ H1["mylib.h"]
9
+ H2["mylib_extra.h"]
10
+ CF["ffi-bindings.yaml"]
11
+ end
12
+
13
+ H1 & H2 & CF --> RB["ruby-bindgen"]
14
+
15
+ subgraph "FFI Output"
16
+ P["mylib_ffi.rb"]
17
+ V["mylib_version.rb"]
18
+ C1["mylib.rb"]
19
+ C2["mylib_extra.rb"]
20
+ end
21
+
22
+ RB --> P & V & C1 & C2
23
+ ```
24
+
25
+ Given a project named `mylib` that matches `mylib.h` and `mylib_extra.h`:
26
+
27
+ ```
28
+ output/
29
+ mylib_ffi.rb # project file: require 'ffi', library preamble, require_relatives
30
+ mylib_version.rb # version file: stub for runtime version detection (only with version_check)
31
+ mylib.rb # content from mylib.h
32
+ mylib_extra.rb # content from mylib_extra.h (reopens module)
33
+ ```
34
+
35
+ ## Project file (`mylib_ffi.rb`)
36
+
37
+ ```ruby
38
+ # This file was generated by ruby-bindgen. Please do not edit by hand.
39
+ require 'ffi'
40
+
41
+ module Mylib
42
+ extend FFI::Library
43
+
44
+ def self.library_names
45
+ ["mylib"]
46
+ end
47
+
48
+ def self.search_names
49
+ # Cross-platform library name generation
50
+ # Handles .so, .dylib, .dll variants
51
+ end
52
+
53
+ ffi_lib self.search_names
54
+ end
55
+
56
+ require_relative './mylib'
57
+ require_relative './mylib_extra'
58
+ ```
59
+
60
+ ## Version file (`mylib_version.rb`)
61
+
62
+ When [`version_check`](../configuration.md#versions) is configured, a version file is generated with a stub method that you must implement to return the runtime library version. This file is preserved on subsequent runs so your implementation is not overwritten. See [Version Guards](version_guards.md) for details.
63
+
64
+ ```ruby
65
+ module Mylib
66
+ def self.mylib_version
67
+ # Return the runtime library version as an integer.
68
+ # Example: 90602 for version 9.6.2
69
+ raise NotImplementedError, "Implement mylib_version to return the runtime library version number"
70
+ end
71
+ end
72
+ ```
73
+
74
+ ## Content file (`mylib.rb`)
75
+
76
+ ```ruby
77
+ module Mylib
78
+ # Structs
79
+ class MyStruct < FFI::Struct
80
+ layout :field1, :int,
81
+ :field2, :double
82
+ end
83
+
84
+ # Enums
85
+ MY_ENUM = enum(
86
+ :value_one, 0,
87
+ :value_two, 1
88
+ )
89
+
90
+ # Callbacks
91
+ callback :my_callback, [:int, :pointer], :void
92
+
93
+ # Functions
94
+ attach_function :my_function, :my_function, [:int, :string], :int
95
+ end
96
+ ```
data/docs/c/types.md ADDED
@@ -0,0 +1,61 @@
1
+ # Type Mapping
2
+
3
+ ## String and Pointer Types
4
+
5
+ C uses `char *` for both strings and raw memory buffers. `ruby-bindgen` uses const-qualification and context to pick an FFI type as shown in the following table:
6
+
7
+ | Context | `const char *` | `char *` |
8
+ |---------|---------------|----------|
9
+ | Function parameters | `:string` | `:pointer` |
10
+ | Function returns | `:string` | `:pointer` |
11
+ | Callback returns | `:pointer` | `:pointer` |
12
+ | Struct/union fields | `:string` | `:pointer` |
13
+
14
+ Since `const char *` is a read-only string, FFI can safely auto-convert it to a Ruby `String`. On the other hand, `char *` often indicates a caller-allocated buffer (e.g., `char *buf, size_t buf_size`), so it is safer to map it to `:pointer`. This allows callers to create the buffer with `FFI::MemoryPointer.new`. Callback returns always use `:pointer` regardless of const because FFI cannot manage the lifetime of callback-returned strings.
15
+
16
+ If a specific function needs a different type mapping, use [`symbols: overrides:`](../configuration.md#overrides-ffi-only) to replace the generated signature.
17
+
18
+ ## Struct Pointer Types
19
+
20
+ When a function parameter is a pointer to a struct, `ruby-bindgen` generates `StructName.by_ref`. This is correct for the common case of passing a single struct by pointer:
21
+
22
+ ```c
23
+ int proj_get_area_of_use(PJ *obj, double *west, ...);
24
+ // → attach_function :proj_get_area_of_use, ..., [:pointer, :pointer, ...], :int
25
+ ```
26
+
27
+ However, `.by_ref` is **wrong** when the pointer is actually an array of structs. `ruby-bindgen` cannot distinguish these cases from the C signatures — both are `SomeStruct *`.
28
+
29
+ Below are two common patterns to help decide.
30
+
31
+ ### Array parameters
32
+ Look for a count parameter that either precedes or follows the struct pointer:
33
+
34
+ ```c
35
+ PJ *proj_create_conversion(PJ_CONTEXT *ctx, ..., int param_count,
36
+ const PJ_PARAM_DESCRIPTION *params);
37
+ ```
38
+
39
+ Here `params` points to an array of `param_count` structs. The caller allocates the array with `FFI::MemoryPointer` and writes structs into it.
40
+
41
+ ### Array returns
42
+ A function returns a pointer to a statically-allocated or heap-allocated array of structs:
43
+
44
+ ```c
45
+ const PJ_OPERATIONS *proj_list_operations(void);
46
+ ```
47
+
48
+ This returns a NULL-terminated array of `PJ_OPERATIONS` structs, not a single struct. The caller iterates the array by advancing the pointer.
49
+
50
+ Use [`symbols: overrides:`](../configuration.md#overrides-ffi-only) to fix these:
51
+
52
+ ```yaml
53
+ symbols:
54
+ overrides:
55
+ proj_create_conversion: "[:pointer, :string, :string, :string, :string, :string, :string, :int, :pointer], :pointer"
56
+ proj_list_operations: "[], :pointer"
57
+ ```
58
+
59
+ ## Union Pointer Types
60
+
61
+ The same considerations apply to unions. When a function takes a pointer to a union, `ruby-bindgen` generates `UnionName.by_ref`. As with structs, this is wrong when the pointer is actually an array of unions — use [`symbols: overrides:`](../configuration.md#overrides-ffi-only) to fix these cases.
@@ -0,0 +1,105 @@
1
+ # Version Detection
2
+
3
+ When [`symbols.versions`](../configuration.md#versions) has entries, `ruby-bindgen` generates version-guarded Ruby conditionals and a `{project}_version.rb` skeleton file. You must implement the version detection method in that file — typically by calling the library's own version API.
4
+
5
+ ## Configuration
6
+
7
+ This example is from [proj4rb](https://github.com/cfis/proj4rb), Ruby bindings for the [PROJ](https://proj.org/) coordinate transformation library. PROJ's API has grown significantly across versions — `proj_normalize_for_visualization` was added in 6.1.0, `proj_cleanup` in 6.2.0, and so forth.
8
+
9
+ ```yaml
10
+ format: FFI
11
+ project: proj
12
+ module: Proj::Api
13
+ version_check: proj_version
14
+
15
+ library_names:
16
+ - proj
17
+
18
+ symbols:
19
+ skip:
20
+ - PJ_INFO # manually defined in version file
21
+ - proj_info # manually defined in version file
22
+
23
+ versions:
24
+ # 6.1.0
25
+ 60100:
26
+ - proj_normalize_for_visualization
27
+
28
+ # 6.2.0
29
+ 60200:
30
+ - proj_cleanup
31
+ - proj_as_projjson
32
+ - proj_create_crs_to_crs_from_pj
33
+
34
+ # 8.0.0
35
+ 80000:
36
+ - proj_context_errno_string
37
+ ```
38
+
39
+ The version file calls `proj_info()` and uses `PJ_INFO` to compute the runtime version number. Since those symbols are manually defined in the version file, add them to `skip` so they aren't also generated in the content files.
40
+
41
+ ## Generated Output
42
+
43
+ The generator produces three things:
44
+
45
+ **1. Version guards in content files** — version-specific symbols are wrapped in conditionals:
46
+
47
+ ```ruby
48
+ if proj_version >= 60100
49
+ attach_function :proj_normalize_for_visualization, ...
50
+ end
51
+ if proj_version >= 60200
52
+ attach_function :proj_cleanup, :proj_cleanup, [], :void
53
+ end
54
+ ```
55
+
56
+ **2. Version require in the project file** (`proj_ffi.rb`):
57
+
58
+ ```ruby
59
+ require_relative 'proj_version'
60
+ require_relative './proj'
61
+ ```
62
+
63
+ **3. Version skeleton file** (`proj_version.rb`) — generated once, then user-maintained:
64
+
65
+ ```ruby
66
+ module Proj
67
+ module Api
68
+ def self.proj_version
69
+ # Return the runtime library version as an integer.
70
+ # Example: 90602 for version 9.6.2
71
+ raise NotImplementedError, "Implement proj_version to return the runtime library version number"
72
+ end
73
+ end
74
+ end
75
+ ```
76
+
77
+ ## Implementing Version Detection
78
+
79
+ Replace the skeleton with your library's version API. PROJ provides `proj_info()` which returns a `PJ_INFO` struct with `major`, `minor`, and `patch` fields. Since the version file is loaded before the generated content files, define the struct and function here:
80
+
81
+ ```ruby
82
+ module Proj
83
+ module Api
84
+ class PjInfo < FFI::Struct
85
+ layout :major, :int,
86
+ :minor, :int,
87
+ :patch, :int,
88
+ :release, :string,
89
+ :version, :string,
90
+ :searchpath, :string,
91
+ :paths, :pointer,
92
+ :path_count, :ulong
93
+ end
94
+
95
+ attach_function :proj_info, :proj_info, [], PjInfo.by_value
96
+
97
+ def self.proj_version
98
+ info = proj_info
99
+ info[:major] * 10000 + info[:minor] * 100 + info[:patch]
100
+ end
101
+ end
102
+ end
103
+ ```
104
+
105
+ The version file is loaded before the content files, so `proj_version` is available when the guards execute. The skeleton is only generated if the file doesn't already exist — your implementation is preserved across re-runs.
@@ -0,0 +1,19 @@
1
+ # CMake Bindings
2
+
3
+ The `CMake` format generates `CMakeLists.txt` and `CMakePresets.json` files for building Rice C++ bindings.
4
+
5
+ Rice supports building extensions with either [extconf.rb](https://ruby-rice.github.io/4.x/packaging/extconf.rb/) or [CMake](https://ruby-rice.github.io/4.x/packaging/cmake/). While `extconf.rb` works for simple bindings, CMake is vastly superior for anything more complex — it provides better cross-platform support, dependency management, and build configuration.
6
+
7
+ **Important:** CMake generation must run after Rice generation because it scans the output directory for `*-rb.cpp` files. If no Rice output exists, the generated CMake source lists will be empty.
8
+
9
+ ## Getting Started
10
+
11
+ See [Getting Started](getting_started.md) for a step-by-step guide.
12
+
13
+ ## Output
14
+
15
+ See [Output](output.md) for details on the generated files.
16
+
17
+ ## Filtering
18
+
19
+ See [Filtering](filtering.md) for how to exclude files from the generated CMake build and how to conditionally include generated sources and directories with `guards`.
@@ -0,0 +1,26 @@
1
+ # Filtering
2
+
3
+ ## Skipping Files
4
+
5
+ The CMake config supports a `skip` option to exclude specific `*-rb.cpp` files from the generated `CMakeLists.txt`. However, in most cases it's better to add skip patterns to your Rice config instead — that way the problematic files are never generated, and CMake won't find them to include. The CMake `skip` is useful as a quick fix when you have stale generated files on disk that you don't want to recompile.
6
+
7
+ ## Guarding Files And Directories
8
+
9
+ Use `guards` when generated paths should remain on disk but only be compiled when a CMake condition is true.
10
+
11
+ ```yaml
12
+ guards:
13
+ OpenCV_HAS_CUDA:
14
+ - opencv2/cuda*-rb.cpp
15
+ TARGET OpenCV::dnn:
16
+ - opencv2/dnn
17
+ ```
18
+
19
+ Guard keys are emitted as raw `if(...)` conditions. Guard values may be exact paths or globs and may match generated directories and `*-rb.cpp` files.
20
+
21
+ - Matching directories are emitted inside guarded `add_subdirectory(...)` blocks.
22
+ - Matching `*-rb.cpp` files are emitted inside guarded `target_sources(...)` blocks.
23
+ - A guard pattern that matches nothing emits a warning.
24
+ - If the same path matches multiple guards, generation fails with an error.
25
+
26
+ Use `skip` for permanent exclusion. Use `guards` for conditional inclusion.
@@ -0,0 +1,52 @@
1
+ # Getting Started with CMake Bindings
2
+
3
+ This guide walks you through generating CMake build files for Rice C++ bindings.
4
+
5
+ ## Prerequisites
6
+
7
+ You must first generate Rice C++ bindings. See [Getting Started with Rice](../cpp/getting_started.md).
8
+
9
+ ## 1. Create a configuration file
10
+
11
+ Create a file named `cmake-bindings.yaml`:
12
+
13
+ ```yaml
14
+ project: my_extension
15
+ output: ./ext/generated
16
+ format: CMake
17
+
18
+ guards:
19
+ TARGET MyLib::gpu:
20
+ - gpu
21
+ - gpu/**/*-rb.cpp
22
+
23
+ include_dirs:
24
+ - "${CMAKE_CURRENT_SOURCE_DIR}/../include"
25
+ ```
26
+
27
+ Key options:
28
+
29
+ - `project` — name used in the CMake `project()` command and build target. When omitted, only subdirectory `CMakeLists.txt` files are generated — useful when you manage the root project files yourself.
30
+ - `output` — directory containing the Rice `*-rb.cpp` files. `input` defaults to `output` for CMake.
31
+ - `guards` — raw CMake conditions mapped to generated path patterns. Use this when a generated subdirectory or `*-rb.cpp` file should only be compiled when a module or feature is available.
32
+ - `include_dirs` — include directories added via `target_include_directories`. These are CMake expressions written directly into the generated `CMakeLists.txt`.
33
+
34
+ See [Configuration](../configuration.md) for all options.
35
+
36
+ ## 2. Generate CMake files
37
+
38
+ Run this **after** generating Rice bindings:
39
+
40
+ ```bash
41
+ ruby-bindgen cmake-bindings.yaml
42
+ ```
43
+
44
+ ## 3. Build
45
+
46
+ ```bash
47
+ cd ./ext/generated
48
+ cmake --preset linux-debug # or macos-debug, msvc-debug, mingw-debug, etc.
49
+ cmake --build build/linux-debug
50
+ ```
51
+
52
+ See [Output](output.md) for details on the available presets and generated files.
@@ -0,0 +1,110 @@
1
+ # CMake Output
2
+
3
+ The CMake format scans the output directory for `*-rb.cpp` files and generates:
4
+
5
+ ``` mermaid
6
+ flowchart LR
7
+ subgraph Input
8
+ CF["cmake-bindings.yaml"]
9
+ S1["*-rb.cpp"]
10
+ end
11
+
12
+ CF & S1 --> RB["ruby-bindgen"]
13
+
14
+ subgraph "CMake Output"
15
+ C1["CMakeLists.txt"]
16
+ C2["CMakePresets.json"]
17
+ end
18
+
19
+ RB --> C1 & C2
20
+ ```
21
+
22
+ ## Project Files
23
+
24
+ When the `project` option is set, `ruby-bindgen` generates the root `CMakeLists.txt` and `CMakePresets.json`. When `project` is omitted, these files are **not** generated — only subdirectory `CMakeLists.txt` files are produced. This is useful when you want to create and manage the root project files yourself and only regenerate subdirectory files on subsequent runs.
25
+
26
+ ## Top-level CMakeLists.txt
27
+
28
+ The top-level `CMakeLists.txt` is a complete project file that configures the entire build:
29
+
30
+ - C++17 standard requirement
31
+ - Rice fetched from GitHub via `FetchContent`
32
+ - Ruby detection via `find_package(Ruby)`
33
+ - Library target (SHARED on MSVC, MODULE elsewhere)
34
+ - Extension output configuration (correct suffix, visibility settings)
35
+ - Subdirectory includes and `*-rb.cpp` source file listing
36
+
37
+ For a well-documented example, see the [BitmapPlusPlus-ruby CMakeLists.txt](https://github.com/ruby-rice/BitmapPlusPlus-ruby/blob/main/ext/CMakeLists.txt). For details on how Rice uses CMake, see the Rice [CMake](https://ruby-rice.github.io/4.x/packaging/cmake/) documentation.
38
+
39
+ ## CMakePresets.json
40
+
41
+ The top-level directory also gets a `CMakePresets.json` with build presets for all major platforms. For an example, see the [BitmapPlusPlus-ruby CMakePresets.json](https://github.com/ruby-rice/BitmapPlusPlus-ruby/blob/main/ext/CMakePresets.json). For details, see the Rice [CMakePresets.json](https://ruby-rice.github.io/4.x/packaging/cmake/#cmakepresetsjson) documentation.
42
+
43
+ | Preset | Platform | Compiler |
44
+ |--------|----------|----------|
45
+ | `linux-debug` / `linux-release` | Linux | GCC/Clang |
46
+ | `macos-debug` / `macos-release` | macOS | Clang |
47
+ | `msvc-debug` / `msvc-release` | Windows | MSVC |
48
+ | `mingw-debug` / `mingw-release` | Windows | MinGW GCC |
49
+ | `clang-windows-debug` / `clang-windows-release` | Windows | clang-cl |
50
+
51
+ All presets use [Ninja](https://ninja-build.org/) as the build generator and include appropriate compiler flags for each platform (visibility settings, debug info, optimization levels).
52
+
53
+ ## Subdirectories
54
+
55
+ Each subdirectory containing `*-rb.cpp` files gets a minimal `CMakeLists.txt` that lists its source files and any nested subdirectories:
56
+
57
+ ```
58
+ ext/generated/
59
+ CMakeLists.txt # root project (requires project option)
60
+ CMakePresets.json # build presets
61
+ core/
62
+ CMakeLists.txt # add_subdirectory("hal") + target_sources(...)
63
+ matrix-rb.cpp
64
+ image-rb.cpp
65
+ hal/
66
+ CMakeLists.txt # target_sources(...)
67
+ interface-rb.cpp
68
+ ```
69
+
70
+ ```cmake
71
+ # Subdirectories
72
+ add_subdirectory("hal")
73
+
74
+ # Sources
75
+ target_sources(${CMAKE_PROJECT_NAME} PUBLIC
76
+ "matrix-rb.cpp"
77
+ "image-rb.cpp"
78
+ )
79
+ ```
80
+
81
+ When `guards` are configured, the generator groups matching directories and files under raw CMake `if(...)` blocks in the generated `CMakeLists.txt`:
82
+
83
+ ```yaml
84
+ guards:
85
+ TARGET OpenCV::dnn:
86
+ - opencv2/dnn
87
+ OpenCV_HAS_CUDA:
88
+ - opencv2/cuda*-rb.cpp
89
+ ```
90
+
91
+ ```cmake
92
+ # Subdirectories
93
+ add_subdirectory("core")
94
+
95
+ # Sources
96
+ target_sources(${CMAKE_PROJECT_NAME} PRIVATE
97
+ "core-rb.cpp"
98
+ )
99
+
100
+ if(TARGET OpenCV::dnn)
101
+ add_subdirectory("dnn")
102
+ endif()
103
+
104
+ if(OpenCV_HAS_CUDA)
105
+ target_sources(${CMAKE_PROJECT_NAME} PRIVATE
106
+ "cudaarithm-rb.cpp"
107
+ "cudaimgproc-rb.cpp"
108
+ )
109
+ endif()
110
+ ```