rubydex 0.1.0.beta11 → 0.1.0.beta13

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 (108) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE.txt +23 -23
  3. data/README.md +125 -125
  4. data/THIRD_PARTY_LICENSES.html +2018 -945
  5. data/exe/rdx +47 -47
  6. data/ext/rubydex/declaration.c +453 -388
  7. data/ext/rubydex/declaration.h +23 -23
  8. data/ext/rubydex/definition.c +284 -197
  9. data/ext/rubydex/definition.h +28 -28
  10. data/ext/rubydex/diagnostic.c +6 -6
  11. data/ext/rubydex/diagnostic.h +11 -11
  12. data/ext/rubydex/document.c +97 -98
  13. data/ext/rubydex/document.h +10 -10
  14. data/ext/rubydex/extconf.rb +146 -127
  15. data/ext/rubydex/graph.c +701 -512
  16. data/ext/rubydex/graph.h +10 -10
  17. data/ext/rubydex/handle.h +44 -44
  18. data/ext/rubydex/location.c +22 -22
  19. data/ext/rubydex/location.h +15 -15
  20. data/ext/rubydex/reference.c +123 -104
  21. data/ext/rubydex/reference.h +15 -16
  22. data/ext/rubydex/rubydex.c +22 -22
  23. data/ext/rubydex/utils.c +108 -86
  24. data/ext/rubydex/utils.h +34 -28
  25. data/lib/rubydex/comment.rb +17 -17
  26. data/lib/rubydex/declaration.rb +11 -0
  27. data/lib/rubydex/diagnostic.rb +21 -21
  28. data/lib/rubydex/failures.rb +15 -15
  29. data/lib/rubydex/graph.rb +98 -92
  30. data/lib/rubydex/keyword.rb +17 -0
  31. data/lib/rubydex/keyword_parameter.rb +13 -0
  32. data/lib/rubydex/location.rb +90 -90
  33. data/lib/rubydex/mixin.rb +22 -0
  34. data/lib/rubydex/version.rb +5 -5
  35. data/lib/rubydex.rb +24 -20
  36. data/rbi/rubydex.rbi +425 -310
  37. data/rust/Cargo.lock +1851 -1851
  38. data/rust/Cargo.toml +29 -29
  39. data/rust/about.toml +10 -10
  40. data/rust/{about.hbs → about_templates/about.hbs} +81 -78
  41. data/rust/about_templates/mingw_licenses.hbs +1071 -0
  42. data/rust/rubydex/Cargo.toml +42 -42
  43. data/rust/rubydex/src/compile_assertions.rs +13 -13
  44. data/rust/rubydex/src/diagnostic.rs +110 -109
  45. data/rust/rubydex/src/errors.rs +28 -28
  46. data/rust/rubydex/src/indexing/local_graph.rs +224 -224
  47. data/rust/rubydex/src/indexing/rbs_indexer.rs +1551 -1554
  48. data/rust/rubydex/src/indexing/ruby_indexer.rs +2329 -6753
  49. data/rust/rubydex/src/indexing/ruby_indexer_tests.rs +4962 -0
  50. data/rust/rubydex/src/indexing.rs +210 -210
  51. data/rust/rubydex/src/integrity.rs +279 -278
  52. data/rust/rubydex/src/job_queue.rs +199 -205
  53. data/rust/rubydex/src/lib.rs +17 -17
  54. data/rust/rubydex/src/listing.rs +371 -272
  55. data/rust/rubydex/src/main.rs +160 -160
  56. data/rust/rubydex/src/model/built_in.rs +83 -0
  57. data/rust/rubydex/src/model/comment.rs +24 -24
  58. data/rust/rubydex/src/model/declaration.rs +679 -588
  59. data/rust/rubydex/src/model/definitions.rs +1682 -1602
  60. data/rust/rubydex/src/model/document.rs +222 -252
  61. data/rust/rubydex/src/model/encoding.rs +22 -22
  62. data/rust/rubydex/src/model/graph.rs +3782 -3556
  63. data/rust/rubydex/src/model/id.rs +110 -110
  64. data/rust/rubydex/src/model/identity_maps.rs +58 -58
  65. data/rust/rubydex/src/model/ids.rs +60 -38
  66. data/rust/rubydex/src/model/keywords.rs +256 -256
  67. data/rust/rubydex/src/model/name.rs +298 -298
  68. data/rust/rubydex/src/model/references.rs +111 -111
  69. data/rust/rubydex/src/model/string_ref.rs +50 -50
  70. data/rust/rubydex/src/model/visibility.rs +41 -41
  71. data/rust/rubydex/src/model.rs +15 -14
  72. data/rust/rubydex/src/offset.rs +147 -147
  73. data/rust/rubydex/src/position.rs +6 -6
  74. data/rust/rubydex/src/query.rs +1841 -1700
  75. data/rust/rubydex/src/resolution.rs +1852 -5895
  76. data/rust/rubydex/src/resolution_tests.rs +4701 -0
  77. data/rust/rubydex/src/stats/memory.rs +71 -71
  78. data/rust/rubydex/src/stats/orphan_report.rs +264 -263
  79. data/rust/rubydex/src/stats/timer.rs +127 -127
  80. data/rust/rubydex/src/stats.rs +11 -11
  81. data/rust/rubydex/src/test_utils/context.rs +226 -226
  82. data/rust/rubydex/src/test_utils/graph_test.rs +730 -679
  83. data/rust/rubydex/src/test_utils/local_graph_test.rs +602 -602
  84. data/rust/rubydex/src/test_utils.rs +52 -52
  85. data/rust/rubydex/src/visualization/dot.rs +192 -176
  86. data/rust/rubydex/src/visualization.rs +6 -6
  87. data/rust/rubydex/tests/cli.rs +185 -167
  88. data/rust/rubydex-mcp/Cargo.toml +28 -28
  89. data/rust/rubydex-mcp/src/main.rs +48 -48
  90. data/rust/rubydex-mcp/src/server.rs +1145 -1145
  91. data/rust/rubydex-mcp/src/tools.rs +49 -49
  92. data/rust/rubydex-mcp/tests/mcp.rs +302 -302
  93. data/rust/rubydex-sys/Cargo.toml +20 -20
  94. data/rust/rubydex-sys/build.rs +14 -14
  95. data/rust/rubydex-sys/cbindgen.toml +12 -12
  96. data/rust/rubydex-sys/src/declaration_api.rs +485 -469
  97. data/rust/rubydex-sys/src/definition_api.rs +443 -352
  98. data/rust/rubydex-sys/src/diagnostic_api.rs +99 -99
  99. data/rust/rubydex-sys/src/document_api.rs +85 -54
  100. data/rust/rubydex-sys/src/graph_api.rs +1017 -700
  101. data/rust/rubydex-sys/src/lib.rs +79 -9
  102. data/rust/rubydex-sys/src/location_api.rs +79 -79
  103. data/rust/rubydex-sys/src/name_api.rs +187 -135
  104. data/rust/rubydex-sys/src/reference_api.rs +267 -195
  105. data/rust/rubydex-sys/src/utils.rs +70 -70
  106. data/rust/rustfmt.toml +2 -2
  107. metadata +16 -9
  108. data/lib/rubydex/librubydex_sys.so +0 -0
@@ -1,98 +1,97 @@
1
- #include "document.h"
2
- #include "definition.h"
3
- #include "graph.h"
4
- #include "handle.h"
5
- #include "rustbindings.h"
6
-
7
- VALUE cDocument;
8
-
9
- // Document#uri -> String
10
- static VALUE rdxr_document_uri(VALUE self) {
11
- HandleData *data;
12
- TypedData_Get_Struct(self, HandleData, &handle_type, data);
13
-
14
- void *graph;
15
- TypedData_Get_Struct(data->graph_obj, void *, &graph_type, graph);
16
- const char *uri = rdx_document_uri(graph, data->id);
17
-
18
- if (uri == NULL) {
19
- return Qnil;
20
- }
21
-
22
- VALUE str = rb_utf8_str_new_cstr(uri);
23
- free_c_string(uri);
24
-
25
- return str;
26
- }
27
-
28
- // Body function for rb_ensure in Document#definitions
29
- static VALUE document_definitions_yield(VALUE args) {
30
- VALUE self = rb_ary_entry(args, 0);
31
- void *iter = (void *)(uintptr_t)NUM2ULL(rb_ary_entry(args, 1));
32
-
33
- HandleData *data;
34
- TypedData_Get_Struct(self, HandleData, &handle_type, data);
35
-
36
- uint64_t id = 0;
37
- DefinitionKind kind;
38
- while (rdx_definitions_iter_next(iter, &id, &kind)) {
39
- VALUE argv[] = {data->graph_obj, ULL2NUM(id)};
40
- VALUE defn_class = rdxi_definition_class_for_kind(kind);
41
- VALUE handle = rb_class_new_instance(2, argv, defn_class);
42
- rb_yield(handle);
43
- }
44
-
45
- return Qnil;
46
- }
47
-
48
- // Ensure function for rb_ensure in Document#definitions to always free the iterator
49
- static VALUE document_definitions_ensure(VALUE args) {
50
- void *iter = (void *)(uintptr_t)NUM2ULL(rb_ary_entry(args, 1));
51
- rdx_definitions_iter_free(iter);
52
-
53
- return Qnil;
54
- }
55
-
56
- // Size function for the Document#definitions enumerator
57
- static VALUE document_definitions_size(VALUE self, VALUE _args, VALUE _eobj) {
58
- HandleData *data;
59
- TypedData_Get_Struct(self, HandleData, &handle_type, data);
60
-
61
- void *graph;
62
- TypedData_Get_Struct(data->graph_obj, void *, &graph_type, graph);
63
- struct DefinitionsIter *iter = rdx_document_definitions_iter_new(graph, data->id);
64
- size_t len = rdx_definitions_iter_len(iter);
65
- rdx_definitions_iter_free(iter);
66
-
67
- return SIZET2NUM(len);
68
- }
69
-
70
- // Document#definitions: () -> Enumerator[Definition]
71
- // Returns an enumerator that yields all definitions for this document lazily
72
- static VALUE rdxr_document_definitions(VALUE self) {
73
- if (!rb_block_given_p()) {
74
- return rb_enumeratorize_with_size(self, rb_str_new2("definitions"), 0, NULL, document_definitions_size);
75
- }
76
-
77
- HandleData *data;
78
- TypedData_Get_Struct(self, HandleData, &handle_type, data);
79
-
80
- void *graph;
81
- TypedData_Get_Struct(data->graph_obj, void *, &graph_type, graph);
82
- void *iter = rdx_document_definitions_iter_new(graph, data->id);
83
- VALUE args = rb_ary_new_from_args(2, self, ULL2NUM((uintptr_t)iter));
84
- rb_ensure(document_definitions_yield, args, document_definitions_ensure, args);
85
-
86
- return self;
87
- }
88
-
89
- void rdxi_initialize_document(VALUE mRubydex) {
90
- cDocument = rb_define_class_under(mRubydex, "Document", rb_cObject);
91
-
92
- rb_define_alloc_func(cDocument, rdxr_handle_alloc);
93
- rb_define_method(cDocument, "initialize", rdxr_handle_initialize, 2);
94
- rb_define_method(cDocument, "uri", rdxr_document_uri, 0);
95
- rb_define_method(cDocument, "definitions", rdxr_document_definitions, 0);
96
-
97
- rb_funcall(rb_singleton_class(cDocument), rb_intern("private"), 1, ID2SYM(rb_intern("new")));
98
- }
1
+ #include "document.h"
2
+ #include "definition.h"
3
+ #include "graph.h"
4
+ #include "handle.h"
5
+ #include "rustbindings.h"
6
+
7
+ VALUE cDocument;
8
+
9
+ // Document#uri -> String
10
+ static VALUE rdxr_document_uri(VALUE self) {
11
+ HandleData *data;
12
+ TypedData_Get_Struct(self, HandleData, &handle_type, data);
13
+
14
+ void *graph;
15
+ TypedData_Get_Struct(data->graph_obj, void *, &graph_type, graph);
16
+ const char *uri = rdx_document_uri(graph, data->id);
17
+
18
+ if (uri == NULL) {
19
+ return Qnil;
20
+ }
21
+
22
+ VALUE str = rb_utf8_str_new_cstr(uri);
23
+ free_c_string(uri);
24
+
25
+ return str;
26
+ }
27
+
28
+ // Body function for rb_ensure in Document#definitions
29
+ static VALUE document_definitions_yield(VALUE args) {
30
+ VALUE self = rb_ary_entry(args, 0);
31
+ void *iter = (void *)(uintptr_t)NUM2ULL(rb_ary_entry(args, 1));
32
+
33
+ HandleData *data;
34
+ TypedData_Get_Struct(self, HandleData, &handle_type, data);
35
+
36
+ CDefinition defn;
37
+ while (rdx_definitions_iter_next(iter, &defn)) {
38
+ VALUE argv[] = {data->graph_obj, ULL2NUM(defn.id)};
39
+ VALUE defn_class = rdxi_definition_class_for_kind(defn.kind);
40
+ VALUE handle = rb_class_new_instance(2, argv, defn_class);
41
+ rb_yield(handle);
42
+ }
43
+
44
+ return Qnil;
45
+ }
46
+
47
+ // Ensure function for rb_ensure in Document#definitions to always free the iterator
48
+ static VALUE document_definitions_ensure(VALUE args) {
49
+ void *iter = (void *)(uintptr_t)NUM2ULL(rb_ary_entry(args, 1));
50
+ rdx_definitions_iter_free(iter);
51
+
52
+ return Qnil;
53
+ }
54
+
55
+ // Size function for the Document#definitions enumerator
56
+ static VALUE document_definitions_size(VALUE self, VALUE _args, VALUE _eobj) {
57
+ HandleData *data;
58
+ TypedData_Get_Struct(self, HandleData, &handle_type, data);
59
+
60
+ void *graph;
61
+ TypedData_Get_Struct(data->graph_obj, void *, &graph_type, graph);
62
+ struct DefinitionsIter *iter = rdx_document_definitions_iter_new(graph, data->id);
63
+ size_t len = rdx_definitions_iter_len(iter);
64
+ rdx_definitions_iter_free(iter);
65
+
66
+ return SIZET2NUM(len);
67
+ }
68
+
69
+ // Document#definitions: () -> Enumerator[Definition]
70
+ // Returns an enumerator that yields all definitions for this document lazily
71
+ static VALUE rdxr_document_definitions(VALUE self) {
72
+ if (!rb_block_given_p()) {
73
+ return rb_enumeratorize_with_size(self, rb_str_new2("definitions"), 0, NULL, document_definitions_size);
74
+ }
75
+
76
+ HandleData *data;
77
+ TypedData_Get_Struct(self, HandleData, &handle_type, data);
78
+
79
+ void *graph;
80
+ TypedData_Get_Struct(data->graph_obj, void *, &graph_type, graph);
81
+ void *iter = rdx_document_definitions_iter_new(graph, data->id);
82
+ VALUE args = rb_ary_new_from_args(2, self, ULL2NUM((uintptr_t)iter));
83
+ rb_ensure(document_definitions_yield, args, document_definitions_ensure, args);
84
+
85
+ return self;
86
+ }
87
+
88
+ void rdxi_initialize_document(VALUE mRubydex) {
89
+ cDocument = rb_define_class_under(mRubydex, "Document", rb_cObject);
90
+
91
+ rb_define_alloc_func(cDocument, rdxr_handle_alloc);
92
+ rb_define_method(cDocument, "initialize", rdxr_handle_initialize, 2);
93
+ rb_define_method(cDocument, "uri", rdxr_document_uri, 0);
94
+ rb_define_method(cDocument, "definitions", rdxr_document_definitions, 0);
95
+
96
+ rb_funcall(rb_singleton_class(cDocument), rb_intern("private"), 1, ID2SYM(rb_intern("new")));
97
+ }
@@ -1,10 +1,10 @@
1
- #ifndef RUBYDEX_DOCUMENT_H
2
- #define RUBYDEX_DOCUMENT_H
3
-
4
- #include "ruby.h"
5
-
6
- extern VALUE cDocument;
7
-
8
- void rdxi_initialize_document(VALUE mRubydex);
9
-
10
- #endif // RUBYDEX_DOCUMENT_H
1
+ #ifndef RUBYDEX_DOCUMENT_H
2
+ #define RUBYDEX_DOCUMENT_H
3
+
4
+ #include "ruby.h"
5
+
6
+ extern VALUE cDocument;
7
+
8
+ void rdxi_initialize_document(VALUE mRubydex);
9
+
10
+ #endif // RUBYDEX_DOCUMENT_H
@@ -1,127 +1,146 @@
1
- # frozen_string_literal: true
2
-
3
- require "mkmf"
4
- require "pathname"
5
-
6
- unless system("cargo", "--version", out: File::NULL, err: File::NULL)
7
- abort "Installing Rubydex requires Cargo, the Rust package manager for platforms that we do not precompile binaries."
8
- end
9
-
10
- gem_dir = Pathname.new("../..").expand_path(__dir__)
11
- release = ENV["RELEASE"] || !gem_dir.join(".git").exist?
12
- root_dir = gem_dir.join("rust")
13
- target_dir = root_dir.join("target")
14
- target_dir = target_dir.join("x86_64-pc-windows-gnu") if Gem.win_platform?
15
- target_dir = target_dir.join(release ? "release" : "debug")
16
-
17
- bindings_path = root_dir.join("rubydex-sys").join("rustbindings.h")
18
-
19
- cargo_args = ["--manifest-path #{root_dir.join("Cargo.toml")}"]
20
- cargo_args << "--release" if release
21
-
22
- if Gem.win_platform?
23
- cargo_args << "--target x86_64-pc-windows-gnu"
24
- ENV["RUSTFLAGS"] = "-C target-feature=+crt-static"
25
- end
26
-
27
- append_cflags("-Werror=unused-but-set-variable")
28
- append_cflags("-Werror=implicit-function-declaration")
29
-
30
- if Gem.win_platform?
31
- $LDFLAGS << " #{target_dir.join("librubydex_sys.a")}"
32
-
33
- # On Windows, statically link system libraries to avoid having to distribute and load DLLs
34
- #
35
- # These libraries are the ones informed by `cargo rustc -- --print native-static-libs`, which displays the
36
- # libraries necessary for statically linking the Rust code on the current platform
37
- ["kernel32", "ntdll", "userenv", "ws2_32", "dbghelp", "msvcrt"].each do |lib|
38
- $LDFLAGS << " -l#{lib}"
39
- end
40
- else
41
- if RUBY_PLATFORM.include?("darwin")
42
- # On the precompiled version of the gem, the `dylib` is one folder above the `.bundle/.so` file. For on machine
43
- # compilation, they are at the same level
44
- append_ldflags("-Wl,-rpath,@loader_path")
45
- append_ldflags("-Wl,-rpath,@loader_path/..")
46
- else
47
- $LDFLAGS << " -Wl,-rpath,\\$$ORIGIN"
48
- $LDFLAGS << " -Wl,-rpath,\\$$ORIGIN/.."
49
- end
50
-
51
- # We cannot use append_ldflags here because the Rust code is only compiled later. If it's not compiled yet, this will
52
- # fail and the flag will not be added
53
- $LDFLAGS << " -L#{target_dir} -lrubydex_sys"
54
- end
55
-
56
- create_makefile("rubydex/rubydex")
57
-
58
- cargo_command = if ENV["SANITIZER"]
59
- ENV["RUSTFLAGS"] = "-Zsanitizer=#{ENV["SANITIZER"]}"
60
- "cargo +nightly build -Zbuild-std #{cargo_args.join(" ")}".strip
61
- else
62
- "cargo build #{cargo_args.join(" ")}".strip
63
- end
64
-
65
- lib_dir = gem_dir.join("lib").join("rubydex")
66
-
67
- copy_dylib_commands = if Gem.win_platform?
68
- ""
69
- elsif RUBY_PLATFORM.include?("darwin")
70
- src_dylib = target_dir.join("librubydex_sys.dylib")
71
- "\t$(COPY) #{src_dylib} #{lib_dir}"
72
- else
73
- # Linux
74
- src_dylib = target_dir.join("librubydex_sys.so")
75
- "\t$(COPY) #{src_dylib} #{lib_dir}"
76
- end
77
-
78
- rust_srcs = Dir.glob("#{root_dir}/**/*.rs").reject { |path| path.include?("rust/target") }
79
- makefile = File.read("Makefile")
80
-
81
- new_makefile = makefile.gsub("$(OBJS): $(HDRS) $(ruby_headers)", <<~MAKEFILE.chomp)
82
- .PHONY: compile_rust
83
- RUST_SRCS = #{File.expand_path("Cargo.toml", root_dir)} #{File.expand_path("Cargo.lock", root_dir)} #{rust_srcs.join(" ")}
84
-
85
- .rust_built: $(RUST_SRCS)
86
- \t#{cargo_command} || (echo "Compiling Rust failed" && exit 1)
87
- \t$(COPY) #{bindings_path} #{__dir__}
88
- \ttouch $@
89
-
90
- compile_rust: .rust_built
91
-
92
- $(OBJS): $(HDRS) $(ruby_headers) .rust_built
93
- MAKEFILE
94
-
95
- new_makefile.gsub!(/(\$\(Q\) \$\(LDSHARED\) .*)/, <<~MAKEFILE.chomp)
96
- \\1
97
- #{copy_dylib_commands}
98
- \t$(Q)$(RM) .rust_built
99
- MAKEFILE
100
-
101
- # Bundle all dependency licenses when building a release version of the gem. This only has to happen on CI where we
102
- # precompile binaries. Oherwise, we're not redistributing the Rust dependencies as they are getting downloaded, compiled
103
- # and linked on the user's machine
104
- if release && system("cargo", "about", "--version", out: File::NULL, err: File::NULL)
105
- licenses_file = root_dir.join("THIRD_PARTY_LICENSES.html")
106
- about_config = root_dir.join("about.toml")
107
- about_template = root_dir.join("about.hbs")
108
-
109
- new_makefile.gsub!(".rust_built: $(RUST_SRCS)", <<~MAKEFILE.chomp)
110
- #{licenses_file}: #{about_config} #{about_template}
111
- \t$(Q)$(RM) #{licenses_file}
112
- \tcargo about generate #{about_template} --manifest-path #{root_dir.join("Cargo.toml")} --workspace > #{licenses_file}
113
- \t$(COPY) #{licenses_file} #{gem_dir}
114
-
115
- .rust_built: $(RUST_SRCS) #{licenses_file}
116
- MAKEFILE
117
- end
118
-
119
- File.write("Makefile", new_makefile)
120
-
121
- begin
122
- require "extconf_compile_commands_json"
123
-
124
- ExtconfCompileCommandsJson.generate!
125
- ExtconfCompileCommandsJson.symlink!
126
- rescue LoadError # rubocop:disable Lint/SuppressedException
127
- end
1
+ # frozen_string_literal: true
2
+
3
+ require "mkmf"
4
+ require "pathname"
5
+
6
+ unless system("cargo", "--version", out: File::NULL, err: File::NULL)
7
+ abort "Installing Rubydex requires Cargo, the Rust package manager for platforms that we do not precompile binaries."
8
+ end
9
+
10
+ gem_dir = Pathname.new("../..").expand_path(__dir__)
11
+
12
+ # Use release mode for the compilation if:
13
+ # - The RELEASE environment variable is set
14
+ # - We're not working on Rubydex (BUNDLE_GEMFILE doesn't point to Rubydex's own Gemfile)
15
+ #
16
+ # We only need debug builds when working on Rubydex itself and on CI. This approach also lets people install Rubydex
17
+ # from the git source and get a release mode build
18
+
19
+ bundle_gemfile = ENV["BUNDLE_GEMFILE"]
20
+ developing_rubydex = bundle_gemfile && Pathname.new(bundle_gemfile).expand_path.dirname == gem_dir
21
+ release = ENV["RELEASE"] || !developing_rubydex
22
+
23
+ root_dir = gem_dir.join("rust")
24
+ target_dir = root_dir.join("target")
25
+ target_dir = target_dir.join("x86_64-pc-windows-gnu") if Gem.win_platform?
26
+ target_dir = target_dir.join(release ? "release" : "debug")
27
+
28
+ bindings_path = root_dir.join("rubydex-sys").join("rustbindings.h")
29
+
30
+ cargo_args = ["--manifest-path #{root_dir.join("Cargo.toml")}"]
31
+ cargo_args << "--release" if release
32
+
33
+ if Gem.win_platform?
34
+ cargo_args << "--target x86_64-pc-windows-gnu"
35
+ ENV["RUSTFLAGS"] = "-C target-feature=+crt-static"
36
+ end
37
+
38
+ append_cflags("-Werror=unused-but-set-variable")
39
+ append_cflags("-Werror=implicit-function-declaration")
40
+
41
+ # There's an error on Windows with function pointer types not matching. This has been fixed and backported in Ruby, but
42
+ # it seems that RubyInstaller sometimes picks an older patch version on CI and it breaks compilation. This isn't
43
+ # actually a problem, so we're ignoring it temporarily only on Windows
44
+ if Gem.win_platform? && RUBY_VERSION < "4.0"
45
+ append_cflags("-Wno-incompatible-pointer-types")
46
+ end
47
+
48
+ if Gem.win_platform?
49
+ $LDFLAGS << " #{target_dir.join("librubydex_sys.a")}"
50
+
51
+ # On Windows, statically link system libraries to avoid having to distribute and load DLLs
52
+ #
53
+ # These libraries are the ones informed by `cargo rustc -- --print native-static-libs`, which displays the
54
+ # libraries necessary for statically linking the Rust code on the current platform
55
+ ["kernel32", "ntdll", "userenv", "ws2_32", "dbghelp", "msvcrt"].each do |lib|
56
+ $LDFLAGS << " -l#{lib}"
57
+ end
58
+ else
59
+ if RUBY_PLATFORM.include?("darwin")
60
+ # On the precompiled version of the gem, the `dylib` is one folder above the `.bundle/.so` file. For on machine
61
+ # compilation, they are at the same level
62
+ append_ldflags("-Wl,-rpath,@loader_path")
63
+ append_ldflags("-Wl,-rpath,@loader_path/..")
64
+ else
65
+ $LDFLAGS << " -Wl,-rpath,\\$$ORIGIN"
66
+ $LDFLAGS << " -Wl,-rpath,\\$$ORIGIN/.."
67
+ end
68
+
69
+ # We cannot use append_ldflags here because the Rust code is only compiled later. If it's not compiled yet, this will
70
+ # fail and the flag will not be added
71
+ $LDFLAGS << " -L#{target_dir} -lrubydex_sys"
72
+ end
73
+
74
+ create_makefile("rubydex/rubydex")
75
+
76
+ cargo_command = if ENV["SANITIZER"]
77
+ ENV["RUSTFLAGS"] = "-Zsanitizer=#{ENV["SANITIZER"]}"
78
+ "cargo +nightly build -Zbuild-std #{cargo_args.join(" ")}".strip
79
+ else
80
+ "cargo build #{cargo_args.join(" ")}".strip
81
+ end
82
+
83
+ lib_dir = gem_dir.join("lib").join("rubydex")
84
+
85
+ copy_dylib_commands = if Gem.win_platform?
86
+ ""
87
+ elsif RUBY_PLATFORM.include?("darwin")
88
+ src_dylib = target_dir.join("librubydex_sys.dylib")
89
+ "\t$(COPY) #{src_dylib} #{lib_dir}"
90
+ else
91
+ # Linux
92
+ src_dylib = target_dir.join("librubydex_sys.so")
93
+ "\t$(COPY) #{src_dylib} #{lib_dir}"
94
+ end
95
+
96
+ rust_srcs = Dir.glob("#{root_dir}/**/*.rs").reject { |path| path.include?("rust/target") }
97
+ makefile = File.read("Makefile")
98
+
99
+ new_makefile = makefile.gsub("$(OBJS): $(HDRS) $(ruby_headers)", <<~MAKEFILE.chomp)
100
+ .PHONY: compile_rust
101
+ RUST_SRCS = #{File.expand_path("Cargo.toml", root_dir)} #{File.expand_path("Cargo.lock", root_dir)} #{rust_srcs.join(" ")}
102
+
103
+ .rust_built: $(RUST_SRCS)
104
+ \t#{cargo_command} || (echo "Compiling Rust failed" && exit 1)
105
+ \t$(COPY) #{bindings_path} #{__dir__}
106
+ \ttouch $@
107
+
108
+ compile_rust: .rust_built
109
+
110
+ $(OBJS): $(HDRS) $(ruby_headers) .rust_built
111
+ MAKEFILE
112
+
113
+ new_makefile.gsub!(/(\$\(Q\) \$\(LDSHARED\) .*)/, <<~MAKEFILE.chomp)
114
+ \\1
115
+ #{copy_dylib_commands}
116
+ \t$(Q)$(RM) .rust_built
117
+ MAKEFILE
118
+
119
+ # Bundle all dependency licenses when building a release version of the gem. This only has to happen on CI where we
120
+ # precompile binaries. Oherwise, we're not redistributing the Rust dependencies as they are getting downloaded, compiled
121
+ # and linked on the user's machine
122
+ if release && system("cargo", "about", "--version", out: File::NULL, err: File::NULL)
123
+ licenses_file = root_dir.join("THIRD_PARTY_LICENSES.html")
124
+ about_config = root_dir.join("about.toml")
125
+ about_templates_dir = root_dir.join("about_templates")
126
+ template_deps = Dir.glob("#{about_templates_dir}/*.hbs").join(" ")
127
+
128
+ new_makefile.gsub!(".rust_built: $(RUST_SRCS)", <<~MAKEFILE.chomp)
129
+ #{licenses_file}: #{about_config} #{template_deps}
130
+ \t$(Q)$(RM) #{licenses_file}
131
+ \tcargo about generate #{about_templates_dir} --name about --manifest-path #{root_dir.join("Cargo.toml")} --workspace > #{licenses_file}
132
+ \t$(COPY) #{licenses_file} #{gem_dir}
133
+
134
+ .rust_built: $(RUST_SRCS) #{licenses_file}
135
+ MAKEFILE
136
+ end
137
+
138
+ File.write("Makefile", new_makefile)
139
+
140
+ begin
141
+ require "extconf_compile_commands_json"
142
+
143
+ ExtconfCompileCommandsJson.generate!
144
+ ExtconfCompileCommandsJson.symlink!
145
+ rescue LoadError # rubocop:disable Lint/SuppressedException
146
+ end