Skip to content

Commit fd4dda5

Browse files
committed
Remove @builder_ipps and @empty_builders cross-file state from the Rice generator. Replace @builder_ipps with
cursor-based .ipp path computation via ipp_path_for_cursor, and always generate builder functions for class templates (even when empty), eliminating the need for @empty_builders.
1 parent 90e6b61 commit fd4dda5

7 files changed

Lines changed: 34 additions & 42 deletions

File tree

lib/ruby-bindgen/generators/rice/class_template_specialization.erb

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -6,20 +6,5 @@
66
template_specialization.gsub(/<.*>/, "").split("::").last.camelize + template_arguments.split(",").map(&:strip).map { |t| t.gsub(/[^a-zA-Z0-9]/, " ").split.map(&:capitalize).join }.join
77
end -%>
88
<%- ruby_class_name = @namer.apply_rename_types(raw_name) -%>
9-
<%- has_instantiate = !@empty_builders.include?(cursor_template.spelling) -%>
10-
<%- if has_instantiate -%>
11-
<%- # New pattern: call the instantiate function which handles everything -%>
129
<%- parent_module = under ? under.cruby_name : "Rice::Module(rb_cObject)" -%>
1310
Rice::Data_Type<<%= template_specialization %>> <%= var_name %> = <%= cursor_template.spelling %>_instantiate<<%= template_arguments %>>(<%= parent_module %>, "<%= ruby_class_name %>");
14-
<%- else -%>
15-
<%- # Empty template: no instantiate function, just define the class -%>
16-
<%- if under && base_spelling -%>
17-
Rice::Data_Type<<%= template_specialization %>> <%= var_name %> = define_class_under<<%= template_specialization %>, <%= base_spelling %>>(<%= under.cruby_name %>, "<%= ruby_class_name %>");
18-
<%- elsif under -%>
19-
Rice::Data_Type<<%= template_specialization %>> <%= var_name %> = define_class_under<<%= template_specialization %>>(<%= under.cruby_name %>, "<%= ruby_class_name %>");
20-
<%- elsif base_spelling -%>
21-
Rice::Data_Type<<%= template_specialization %>> <%= var_name %> = define_class<<%= template_specialization %>, <%= base_spelling %>>("<%= ruby_class_name %>");
22-
<%- else -%>
23-
Rice::Data_Type<<%= template_specialization %>> <%= var_name %> = define_class<<%= template_specialization %>>("<%= ruby_class_name %>");
24-
<%- end -%>
25-
<%- end -%>

lib/ruby-bindgen/generators/rice/rice.rb

Lines changed: 15 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -154,10 +154,6 @@ def initialize(inputter, outputter, config)
154154
@incomplete_iterators = Hash.new
155155
# Iterator names per class (for aliasing each_const -> each)
156156
@class_iterator_names = Hash.new { |h, k| h[k] = Set.new }
157-
# Template classes with no bindable content (all methods deprecated/skipped)
158-
@empty_builders = Set.new
159-
# Maps builder function name -> -rb.ipp basename (persists across files for cross-file deps)
160-
@builder_ipps = {}
161157
end
162158

163159
def generate
@@ -245,6 +241,13 @@ def rice_include_header
245241
@include_header || "#{@project || 'rice'}_include.hpp"
246242
end
247243

244+
# Compute the .ipp path for a template defined in a different file.
245+
def ipp_path_for_cursor(cursor)
246+
template_file = cursor.file_location.file
247+
relative = Pathname.new(template_file).relative_path_from(Pathname.new(@inputter.base_path)).to_s
248+
File.join(File.dirname(relative), "#{File.basename(relative, '.*')}-rb.ipp")
249+
end
250+
248251
# Generate default Rice include header if user didn't specify one
249252
def create_rice_include_header
250253
return if @include_header # User specified their own header
@@ -535,12 +538,6 @@ def visit_class_template_builder(cursor)
535538
only_kinds: [:cursor_cxx_method, :cursor_constructor, :cursor_field_decl, :cursor_variable,
536539
:cursor_enum_decl, :cursor_conversion_function])
537540

538-
# If no children (all methods deprecated/skipped), don't generate builder
539-
if children.empty?
540-
@empty_builders.add(cursor.spelling)
541-
return ""
542-
end
543-
544541
# TODO: Calling get_base_spelling crashes libclang on certain templates.
545542
# Fix the instantiate functions by hand for now.
546543
#base_spelling = get_base_spelling(cursor)
@@ -564,12 +561,6 @@ def visit_class_template_builder(cursor)
564561
param_names = template_parameters.map(&:spelling).join(", ")
565562
fully_qualified_type = "#{cursor.qualified_name}<#{param_names}>"
566563

567-
# Track builder for cross-file dependency detection.
568-
# Store the full relative path (e.g., "opencv2/core/cvstd_wrapper-rb.ipp")
569-
# so consumers in different directories can compute the correct include path.
570-
builder_name = "#{cursor.spelling}_instantiate"
571-
@builder_ipps[builder_name] = File.join(@relative_dir, "#{@basename}.ipp")
572-
573564
children_content = merge_children(children, :indentation => 4, :separator => ".\n",
574565
:terminator => ";", :strip => true)
575566

@@ -1898,14 +1889,14 @@ def visit_template_specialization(cursor, cursor_template, underlying_type)
18981889

18991890
template_specialization = type_spelling(underlying_type)
19001891

1901-
# Check if the template's _instantiate builder was generated in a different file
1902-
builder_name = "#{cursor_template.spelling}_instantiate"
1903-
builder_ipp = @builder_ipps[builder_name]
1904-
current_ipp = File.join(@relative_dir, "#{@basename}.ipp")
1905-
if builder_ipp && builder_ipp != current_ipp
1906-
# Compute relative path from current file's directory to the ipp file
1907-
ipp_relative = Pathname.new(builder_ipp).relative_path_from(Pathname.new(@relative_dir)).to_s
1908-
@includes << "#include \"#{ipp_relative}\""
1892+
# If template is defined in a different file, include its .ipp for the _instantiate builder
1893+
unless cursor_template.file_location.file == cursor_template.translation_unit.file.name
1894+
builder_ipp = ipp_path_for_cursor(cursor_template)
1895+
current_ipp = File.join(@relative_dir, "#{@basename}.ipp")
1896+
if builder_ipp != current_ipp
1897+
ipp_relative = Pathname.new(builder_ipp).relative_path_from(Pathname.new(@relative_dir)).to_s
1898+
@includes << "#include \"#{ipp_relative}\""
1899+
end
19091900
end
19101901

19111902
@classes[cursor.cruby_name] = template_specialization

test/bindings/cpp/cross_file_derived-rb.ipp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,9 @@ inline Rice::Data_Type<CrossFile::DerivedVector<T, N>> DerivedVector_instantiate
77
Arg("other"));
88
}
99

10+
template<typename T>
11+
inline Rice::Data_Type<CrossFile::DataType<T>> DataType_instantiate(Rice::Module parent, const char* name)
12+
{
13+
return Rice::define_class_under<CrossFile::DataType<T>>(parent, name);
14+
}
1015

test/bindings/cpp/filtering-rb.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ void Init_Filtering()
3232
define_method<void(Outer::Wrapper<int>::*)(int*)>("wrap", &Outer::Wrapper<int>::wrap,
3333
ArgBuffer("obj"));
3434

35-
Rice::Data_Type<Outer::DeprecatedTemplate<int>> rb_cDeprecatedTemplateInt = define_class_under<Outer::DeprecatedTemplate<int>>(rb_mOuter, "DeprecatedTemplateInt");
35+
Rice::Data_Type<Outer::DeprecatedTemplate<int>> rb_cDeprecatedTemplateInt = DeprecatedTemplate_instantiate<int>(rb_mOuter, "DeprecatedTemplateInt");
3636

3737
Rice::Data_Type<Outer::OtherClass> rb_cOuterOtherClass = define_class_under<Outer::OtherClass>(rb_mOuter, "OtherClass").
3838
define_constructor(Constructor<Outer::OtherClass>());

test/bindings/cpp/filtering-rb.ipp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,4 +15,9 @@ inline Rice::Data_Type<Outer::Wrapper<T>> Wrapper_instantiate(Rice::Module paren
1515
std::conditional_t<std::is_fundamental_v<T>, ArgBuffer, Arg>("obj"));
1616
}
1717

18+
template<typename T>
19+
inline Rice::Data_Type<Outer::DeprecatedTemplate<T>> DeprecatedTemplate_instantiate(Rice::Module parent, const char* name)
20+
{
21+
return Rice::define_class_under<Outer::DeprecatedTemplate<T>>(parent, name);
22+
}
1823

test/bindings/cpp/functions-rb.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
using namespace Rice;
55

6-
6+
#include "functions-rb.ipp"
77

88
void Init_Functions()
99
{
@@ -79,7 +79,7 @@ void Init_Functions()
7979

8080
Module rb_mNontypeArgs = define_module("NontypeArgs");
8181

82-
Rice::Data_Type<nontype_args::Container<double, nontype_args::Config::Size>> rb_cNontype_argsContainerDoubleNontype_argsConfigSize = define_class_under<nontype_args::Container<double, nontype_args::Config::Size>>(rb_mNontypeArgs, "ContainerDoubleNontypeArgsConfigSize");
82+
Rice::Data_Type<nontype_args::Container<double, nontype_args::Config::Size>> rb_cNontype_argsContainerDoubleNontype_argsConfigSize = Container_instantiate<double, nontype_args::Config::Size>(rb_mNontypeArgs, "ContainerDoubleNontypeArgsConfigSize");
8383

8484
Rice::Data_Type<nontype_args::Config> rb_cNontypeArgsConfig = define_class_under<nontype_args::Config>(rb_mNontypeArgs, "Config").
8585
define_constructor(Constructor<nontype_args::Config>()).

test/bindings/cpp/functions-rb.ipp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
template<typename T, int N>
2+
inline Rice::Data_Type<nontype_args::Container<T, N>> Container_instantiate(Rice::Module parent, const char* name)
3+
{
4+
return Rice::define_class_under<nontype_args::Container<T, N>>(parent, name);
5+
}
6+

0 commit comments

Comments
 (0)