mt-lang 0.2.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 (258) hide show
  1. checksums.yaml +7 -0
  2. data/.ruby-version +1 -0
  3. data/AUTHORS +3 -0
  4. data/Gemfile +19 -0
  5. data/Gemfile.lock +82 -0
  6. data/LICENSE +21 -0
  7. data/README.md +1208 -0
  8. data/Rakefile +332 -0
  9. data/bin/mtc +8 -0
  10. data/bin/profile-mtc-checks +133 -0
  11. data/bin/tracy-profiler +0 -0
  12. data/docs/build-guide.md +536 -0
  13. data/docs/index.html +2778 -0
  14. data/docs/language-design.md +1519 -0
  15. data/docs/language-manual.md +1534 -0
  16. data/lib/milk_tea/base.rb +49 -0
  17. data/lib/milk_tea/bindings/bindgen/ast_parser.rb +398 -0
  18. data/lib/milk_tea/bindings/bindgen/declaration.rb +319 -0
  19. data/lib/milk_tea/bindings/bindgen/emitter.rb +387 -0
  20. data/lib/milk_tea/bindings/bindgen/overrides.rb +134 -0
  21. data/lib/milk_tea/bindings/bindgen/type_mapper.rb +622 -0
  22. data/lib/milk_tea/bindings/bindgen.rb +207 -0
  23. data/lib/milk_tea/bindings/cli.rb +121 -0
  24. data/lib/milk_tea/bindings/imported_bindings/defaults.rb +210 -0
  25. data/lib/milk_tea/bindings/imported_bindings/generator.rb +1114 -0
  26. data/lib/milk_tea/bindings/imported_bindings/method_source.rb +190 -0
  27. data/lib/milk_tea/bindings/imported_bindings/naming.rb +286 -0
  28. data/lib/milk_tea/bindings/imported_bindings.rb +215 -0
  29. data/lib/milk_tea/bindings/opengl_registry.rb +547 -0
  30. data/lib/milk_tea/bindings/raw_bindings/defaults.rb +1338 -0
  31. data/lib/milk_tea/bindings/raw_bindings.rb +269 -0
  32. data/lib/milk_tea/bindings/steamworks.rb +629 -0
  33. data/lib/milk_tea/bindings/upstream_sources.rb +352 -0
  34. data/lib/milk_tea/bindings/vendored_box2d.rb +79 -0
  35. data/lib/milk_tea/bindings/vendored_c_library.rb +322 -0
  36. data/lib/milk_tea/bindings/vendored_cjson.rb +52 -0
  37. data/lib/milk_tea/bindings/vendored_flecs.rb +78 -0
  38. data/lib/milk_tea/bindings/vendored_glfw.rb +77 -0
  39. data/lib/milk_tea/bindings/vendored_libuv.rb +75 -0
  40. data/lib/milk_tea/bindings/vendored_pcre2.rb +84 -0
  41. data/lib/milk_tea/bindings/vendored_raylib.rb +131 -0
  42. data/lib/milk_tea/bindings/vendored_sdl3.rb +78 -0
  43. data/lib/milk_tea/bindings/vendored_steamworks.rb +71 -0
  44. data/lib/milk_tea/bindings/vendored_tool.rb +71 -0
  45. data/lib/milk_tea/bindings/vendored_tools.rb +23 -0
  46. data/lib/milk_tea/bindings/vendored_tracy.rb +37 -0
  47. data/lib/milk_tea/bindings.rb +23 -0
  48. data/lib/milk_tea/core/ast.rb +311 -0
  49. data/lib/milk_tea/core/async_runtime_installer.rb +28 -0
  50. data/lib/milk_tea/core/binding_types.rb +18 -0
  51. data/lib/milk_tea/core/bindings/attribute_binding.rb +58 -0
  52. data/lib/milk_tea/core/bindings/function_binding.rb +5 -0
  53. data/lib/milk_tea/core/bindings/module_binding.rb +58 -0
  54. data/lib/milk_tea/core/bindings/value_binding.rb +21 -0
  55. data/lib/milk_tea/core/c_backend/aggregate_utils.rb +103 -0
  56. data/lib/milk_tea/core/c_backend/control_flow_emission.rb +412 -0
  57. data/lib/milk_tea/core/c_backend/expressions.rb +468 -0
  58. data/lib/milk_tea/core/c_backend/feature_detection.rb +483 -0
  59. data/lib/milk_tea/core/c_backend/reachability.rb +398 -0
  60. data/lib/milk_tea/core/c_backend/reinterpret.rb +226 -0
  61. data/lib/milk_tea/core/c_backend/runtime_helpers.rb +1080 -0
  62. data/lib/milk_tea/core/c_backend/statements.rb +563 -0
  63. data/lib/milk_tea/core/c_backend/type_collectors.rb +1545 -0
  64. data/lib/milk_tea/core/c_backend/type_declaration.rb +223 -0
  65. data/lib/milk_tea/core/c_backend/type_system.rb +345 -0
  66. data/lib/milk_tea/core/c_backend.rb +287 -0
  67. data/lib/milk_tea/core/compatibility_helpers.rb +79 -0
  68. data/lib/milk_tea/core/compile_time/const_eval.rb +187 -0
  69. data/lib/milk_tea/core/compile_time.rb +329 -0
  70. data/lib/milk_tea/core/control_flow/builder.rb +582 -0
  71. data/lib/milk_tea/core/control_flow/constant_propagation.rb +143 -0
  72. data/lib/milk_tea/core/control_flow/dataflow.rb +74 -0
  73. data/lib/milk_tea/core/control_flow/definite_assignment.rb +79 -0
  74. data/lib/milk_tea/core/control_flow/graph.rb +90 -0
  75. data/lib/milk_tea/core/control_flow/liveness.rb +24 -0
  76. data/lib/milk_tea/core/control_flow/nullability_flow.rb +43 -0
  77. data/lib/milk_tea/core/control_flow/reachability.rb +22 -0
  78. data/lib/milk_tea/core/control_flow/termination.rb +31 -0
  79. data/lib/milk_tea/core/control_flow.rb +34 -0
  80. data/lib/milk_tea/core/cst.rb +48 -0
  81. data/lib/milk_tea/core/cst_builder.rb +19 -0
  82. data/lib/milk_tea/core/ir.rb +85 -0
  83. data/lib/milk_tea/core/keywords.rb +97 -0
  84. data/lib/milk_tea/core/lexer/character_classes.rb +60 -0
  85. data/lib/milk_tea/core/lexer/format_strings.rb +225 -0
  86. data/lib/milk_tea/core/lexer/heredocs.rb +199 -0
  87. data/lib/milk_tea/core/lexer/indentation.rb +62 -0
  88. data/lib/milk_tea/core/lexer/numbers.rb +96 -0
  89. data/lib/milk_tea/core/lexer/recovery.rb +32 -0
  90. data/lib/milk_tea/core/lexer/strings.rb +167 -0
  91. data/lib/milk_tea/core/lexer/symbols.rb +71 -0
  92. data/lib/milk_tea/core/lexer/trivia.rb +53 -0
  93. data/lib/milk_tea/core/lexer.rb +430 -0
  94. data/lib/milk_tea/core/lowering/artifacts.rb +26 -0
  95. data/lib/milk_tea/core/lowering/async/analysis.rb +245 -0
  96. data/lib/milk_tea/core/lowering/async/lowering.rb +1399 -0
  97. data/lib/milk_tea/core/lowering/async/normalization.rb +459 -0
  98. data/lib/milk_tea/core/lowering/async.rb +714 -0
  99. data/lib/milk_tea/core/lowering/block.rb +1052 -0
  100. data/lib/milk_tea/core/lowering/calls.rb +1565 -0
  101. data/lib/milk_tea/core/lowering/declarations.rb +214 -0
  102. data/lib/milk_tea/core/lowering/dyn.rb +206 -0
  103. data/lib/milk_tea/core/lowering/events.rb +1054 -0
  104. data/lib/milk_tea/core/lowering/expressions.rb +1645 -0
  105. data/lib/milk_tea/core/lowering/foreign_cstr.rb +206 -0
  106. data/lib/milk_tea/core/lowering/functions.rb +242 -0
  107. data/lib/milk_tea/core/lowering/loops.rb +1087 -0
  108. data/lib/milk_tea/core/lowering/lowering_context.rb +80 -0
  109. data/lib/milk_tea/core/lowering/proc.rb +419 -0
  110. data/lib/milk_tea/core/lowering/resolve.rb +2516 -0
  111. data/lib/milk_tea/core/lowering/scans.rb +220 -0
  112. data/lib/milk_tea/core/lowering/str_buffer.rb +125 -0
  113. data/lib/milk_tea/core/lowering/utils.rb +1453 -0
  114. data/lib/milk_tea/core/lowering.rb +378 -0
  115. data/lib/milk_tea/core/module_binder.rb +181 -0
  116. data/lib/milk_tea/core/module_loader/errors.rb +21 -0
  117. data/lib/milk_tea/core/module_loader.rb +479 -0
  118. data/lib/milk_tea/core/module_path_resolver.rb +153 -0
  119. data/lib/milk_tea/core/module_roots.rb +88 -0
  120. data/lib/milk_tea/core/parser/attributes.rb +71 -0
  121. data/lib/milk_tea/core/parser/blocks.rb +119 -0
  122. data/lib/milk_tea/core/parser/declarations.rb +749 -0
  123. data/lib/milk_tea/core/parser/expressions.rb +624 -0
  124. data/lib/milk_tea/core/parser/recovery.rb +131 -0
  125. data/lib/milk_tea/core/parser/statements.rb +756 -0
  126. data/lib/milk_tea/core/parser/types.rb +271 -0
  127. data/lib/milk_tea/core/parser.rb +400 -0
  128. data/lib/milk_tea/core/prelude_installer.rb +29 -0
  129. data/lib/milk_tea/core/pretty_printer/ast_formatter.rb +917 -0
  130. data/lib/milk_tea/core/pretty_printer/base_formatter.rb +87 -0
  131. data/lib/milk_tea/core/pretty_printer/ir_formatter.rb +300 -0
  132. data/lib/milk_tea/core/pretty_printer.rb +17 -0
  133. data/lib/milk_tea/core/semantic_analyzer/analysis_context.rb +314 -0
  134. data/lib/milk_tea/core/semantic_analyzer/attributes.rb +184 -0
  135. data/lib/milk_tea/core/semantic_analyzer/calls.rb +992 -0
  136. data/lib/milk_tea/core/semantic_analyzer/expressions.rb +1735 -0
  137. data/lib/milk_tea/core/semantic_analyzer/flow_refinement.rb +355 -0
  138. data/lib/milk_tea/core/semantic_analyzer/foreign_functions.rb +155 -0
  139. data/lib/milk_tea/core/semantic_analyzer/function_binding.rb +354 -0
  140. data/lib/milk_tea/core/semantic_analyzer/generics.rb +383 -0
  141. data/lib/milk_tea/core/semantic_analyzer/interface_conformance.rb +78 -0
  142. data/lib/milk_tea/core/semantic_analyzer/module_context.rb +35 -0
  143. data/lib/milk_tea/core/semantic_analyzer/name_resolution.rb +1438 -0
  144. data/lib/milk_tea/core/semantic_analyzer/nullability.rb +421 -0
  145. data/lib/milk_tea/core/semantic_analyzer/statements.rb +1308 -0
  146. data/lib/milk_tea/core/semantic_analyzer/top_level.rb +588 -0
  147. data/lib/milk_tea/core/semantic_analyzer/type_compatibility.rb +307 -0
  148. data/lib/milk_tea/core/semantic_analyzer/type_declaration.rb +851 -0
  149. data/lib/milk_tea/core/semantic_analyzer.rb +327 -0
  150. data/lib/milk_tea/core/token.rb +26 -0
  151. data/lib/milk_tea/core/token_stream.rb +30 -0
  152. data/lib/milk_tea/core/types/layout.rb +243 -0
  153. data/lib/milk_tea/core/types/predicates.rb +609 -0
  154. data/lib/milk_tea/core/types/registry.rb +83 -0
  155. data/lib/milk_tea/core/types/types.rb +1696 -0
  156. data/lib/milk_tea/core/types/visitor.rb +442 -0
  157. data/lib/milk_tea/core.rb +25 -0
  158. data/lib/milk_tea/dap/backends/lldb_dap.rb +158 -0
  159. data/lib/milk_tea/dap/protocol.rb +58 -0
  160. data/lib/milk_tea/dap/server/breakpoints.rb +66 -0
  161. data/lib/milk_tea/dap/server/debug_map.rb +291 -0
  162. data/lib/milk_tea/dap/server/handlers.rb +374 -0
  163. data/lib/milk_tea/dap/server/launch.rb +261 -0
  164. data/lib/milk_tea/dap/server/lldb_backend.rb +380 -0
  165. data/lib/milk_tea/dap/server/pause_diagnostics.rb +109 -0
  166. data/lib/milk_tea/dap/server/utilities.rb +160 -0
  167. data/lib/milk_tea/dap/server/wire.rb +55 -0
  168. data/lib/milk_tea/dap/server.rb +131 -0
  169. data/lib/milk_tea/dap/session.rb +152 -0
  170. data/lib/milk_tea/dap.rb +6 -0
  171. data/lib/milk_tea/lsp/dependency_resolution.rb +52 -0
  172. data/lib/milk_tea/lsp/diagnostics.rb +611 -0
  173. data/lib/milk_tea/lsp/protocol.rb +104 -0
  174. data/lib/milk_tea/lsp/server/call_hierarchy.rb +274 -0
  175. data/lib/milk_tea/lsp/server/code_actions.rb +446 -0
  176. data/lib/milk_tea/lsp/server/code_lens.rb +97 -0
  177. data/lib/milk_tea/lsp/server/completion.rb +1099 -0
  178. data/lib/milk_tea/lsp/server/configuration.rb +167 -0
  179. data/lib/milk_tea/lsp/server/debug_info.rb +45 -0
  180. data/lib/milk_tea/lsp/server/definition.rb +779 -0
  181. data/lib/milk_tea/lsp/server/diagnostics_scheduling.rb +239 -0
  182. data/lib/milk_tea/lsp/server/execute_command.rb +25 -0
  183. data/lib/milk_tea/lsp/server/folding_range.rb +153 -0
  184. data/lib/milk_tea/lsp/server/formatting.rb +575 -0
  185. data/lib/milk_tea/lsp/server/hover.rb +1465 -0
  186. data/lib/milk_tea/lsp/server/inlay_hints.rb +204 -0
  187. data/lib/milk_tea/lsp/server/lifecycle.rb +234 -0
  188. data/lib/milk_tea/lsp/server/linked_editing_range.rb +43 -0
  189. data/lib/milk_tea/lsp/server/on_type_formatting.rb +73 -0
  190. data/lib/milk_tea/lsp/server/progress.rb +47 -0
  191. data/lib/milk_tea/lsp/server/references.rb +433 -0
  192. data/lib/milk_tea/lsp/server/rename.rb +598 -0
  193. data/lib/milk_tea/lsp/server/selection_range.rb +130 -0
  194. data/lib/milk_tea/lsp/server/semantic_tokens.rb +1745 -0
  195. data/lib/milk_tea/lsp/server/signature_help.rb +200 -0
  196. data/lib/milk_tea/lsp/server/text_documents.rb +125 -0
  197. data/lib/milk_tea/lsp/server/type_hierarchy.rb +167 -0
  198. data/lib/milk_tea/lsp/server/utilities.rb +520 -0
  199. data/lib/milk_tea/lsp/server.rb +415 -0
  200. data/lib/milk_tea/lsp/workspace/analysis.rb +209 -0
  201. data/lib/milk_tea/lsp/workspace/caches.rb +260 -0
  202. data/lib/milk_tea/lsp/workspace/collection.rb +98 -0
  203. data/lib/milk_tea/lsp/workspace/definition_index.rb +184 -0
  204. data/lib/milk_tea/lsp/workspace/dependency_graph.rb +282 -0
  205. data/lib/milk_tea/lsp/workspace/store.rb +154 -0
  206. data/lib/milk_tea/lsp/workspace/utilities.rb +490 -0
  207. data/lib/milk_tea/lsp/workspace.rb +127 -0
  208. data/lib/milk_tea/lsp.rb +13 -0
  209. data/lib/milk_tea/packages/atomic_write.rb +63 -0
  210. data/lib/milk_tea/packages/dependency_solver.rb +194 -0
  211. data/lib/milk_tea/packages/graph.rb +139 -0
  212. data/lib/milk_tea/packages/lock.rb +421 -0
  213. data/lib/milk_tea/packages/manager_cli.rb +485 -0
  214. data/lib/milk_tea/packages/manifest.rb +356 -0
  215. data/lib/milk_tea/packages/manifest_editor.rb +134 -0
  216. data/lib/milk_tea/packages/registry_metadata_provider.rb +34 -0
  217. data/lib/milk_tea/packages/registry_store.rb +420 -0
  218. data/lib/milk_tea/packages/services.rb +41 -0
  219. data/lib/milk_tea/packages/source_cache.rb +71 -0
  220. data/lib/milk_tea/packages/source_fetcher.rb +124 -0
  221. data/lib/milk_tea/packages/source_resolver.rb +389 -0
  222. data/lib/milk_tea/packages/version.rb +164 -0
  223. data/lib/milk_tea/packages.rb +16 -0
  224. data/lib/milk_tea/tooling/asset_pack.rb +141 -0
  225. data/lib/milk_tea/tooling/build.rb +1124 -0
  226. data/lib/milk_tea/tooling/build_cache.rb +240 -0
  227. data/lib/milk_tea/tooling/cli.rb +2688 -0
  228. data/lib/milk_tea/tooling/cst_formatter.rb +13 -0
  229. data/lib/milk_tea/tooling/debug_info_formatter.rb +456 -0
  230. data/lib/milk_tea/tooling/debug_map.rb +248 -0
  231. data/lib/milk_tea/tooling/docs_app.rb +369 -0
  232. data/lib/milk_tea/tooling/error_formatter.rb +86 -0
  233. data/lib/milk_tea/tooling/formatter.rb +787 -0
  234. data/lib/milk_tea/tooling/linter/doc_tags.rb +212 -0
  235. data/lib/milk_tea/tooling/linter/fix_engine.rb +237 -0
  236. data/lib/milk_tea/tooling/linter/flow_rules.rb +380 -0
  237. data/lib/milk_tea/tooling/linter/imports_platform.rb +841 -0
  238. data/lib/milk_tea/tooling/linter/release_rules.rb +744 -0
  239. data/lib/milk_tea/tooling/linter/reserved_names.rb +199 -0
  240. data/lib/milk_tea/tooling/linter/rules.rb +593 -0
  241. data/lib/milk_tea/tooling/linter/source_helpers.rb +407 -0
  242. data/lib/milk_tea/tooling/linter/trailing_comma.rb +139 -0
  243. data/lib/milk_tea/tooling/linter/visitors.rb +1286 -0
  244. data/lib/milk_tea/tooling/linter.rb +798 -0
  245. data/lib/milk_tea/tooling/project_scaffold.rb +82 -0
  246. data/lib/milk_tea/tooling/public/css/docs.css +166 -0
  247. data/lib/milk_tea/tooling/public/js/docs.js +94 -0
  248. data/lib/milk_tea/tooling/run.rb +408 -0
  249. data/lib/milk_tea/tooling/templates/wasm_shell.html +48 -0
  250. data/lib/milk_tea/tooling/toolchain_cli.rb +157 -0
  251. data/lib/milk_tea/tooling/views/404.erb +7 -0
  252. data/lib/milk_tea/tooling/views/index.erb +87 -0
  253. data/lib/milk_tea/tooling/views/layout.erb +69 -0
  254. data/lib/milk_tea/tooling/views/module.erb +97 -0
  255. data/lib/milk_tea/tooling/views/stdlib.erb +21 -0
  256. data/lib/milk_tea/tooling.rb +20 -0
  257. data/lib/milk_tea.rb +8 -0
  258. metadata +426 -0
@@ -0,0 +1,322 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "fileutils"
4
+ require "open3"
5
+ require "pathname"
6
+ require "shellwords"
7
+
8
+ module MilkTea
9
+ module VendoredCLibrary
10
+ class Error < RawBindings::Error; end
11
+
12
+ class Base
13
+ attr_reader :name, :source_root, :include_roots
14
+
15
+ def initialize(name:, source_root:, include_roots: [], cc_env_var: nil)
16
+ @name = name.to_s
17
+ @source_root = Pathname.new(File.expand_path(source_root.to_s))
18
+ @include_roots = include_roots.map { |path| Pathname.new(File.expand_path(path.to_s)) }.freeze
19
+ @cc_env_var = cc_env_var
20
+ end
21
+
22
+ def include_flags
23
+ include_roots.map { |path| "-I#{path}" }
24
+ end
25
+
26
+ def build_flags(platform: nil)
27
+ include_flags
28
+ end
29
+
30
+ def prepare!(env: ENV, cc: ENV.fetch("CC", "cc"), platform: nil)
31
+ raise NotImplementedError, "#{self.class} must implement #prepare!"
32
+ end
33
+
34
+ def link_flags(platform: nil)
35
+ raise NotImplementedError, "#{self.class} must implement #link_flags"
36
+ end
37
+
38
+ private
39
+
40
+ def resolved_cc(env, default_cc)
41
+ return default_cc unless @cc_env_var
42
+
43
+ env.fetch(@cc_env_var, default_cc)
44
+ end
45
+
46
+ def signature_path(root)
47
+ root.join(".milk-tea-signature")
48
+ end
49
+
50
+ def read_signature(root)
51
+ path = signature_path(root)
52
+ return unless File.exist?(path)
53
+
54
+ File.read(path)
55
+ end
56
+
57
+ def write_signature(root, value)
58
+ File.write(signature_path(root), value)
59
+ end
60
+
61
+ def newest_tree_file_mtime(root)
62
+ Dir.glob(File.join(root.to_s, "**", "*"))
63
+ .select { |path| File.file?(path) }
64
+ .map { |path| File.mtime(path) }
65
+ .max
66
+ end
67
+
68
+ def command_error(label, stdout, stderr)
69
+ details = [stdout, stderr].reject(&:empty?).join
70
+ details.empty? ? label : "#{label}:\n#{details}"
71
+ end
72
+
73
+ def tool_not_found(error)
74
+ Error.new("tool not found while building vendored #{name}: #{error.message}")
75
+ end
76
+ end
77
+
78
+ class Archive < Base
79
+ attr_reader :build_root, :archive_path, :sources, :defines
80
+
81
+ def initialize(name:, source_root:, build_root:, archive_name:, sources:, include_roots: [], defines: [], system_link_flags: [], cc_env_var: nil, c_flags: [], cxx_env_var: nil, cxx_flags: [], ar_env_var: nil, default_ar: "ar")
82
+ resolved_include_roots = include_roots.empty? ? [source_root] : include_roots
83
+ super(name:, source_root:, include_roots: resolved_include_roots, cc_env_var:)
84
+ @build_root = Pathname.new(File.expand_path(build_root.to_s))
85
+ @archive_path = @build_root.join(archive_name)
86
+ @sources = sources.dup.freeze
87
+ @defines = defines.dup.freeze
88
+ @system_link_flags = system_link_flags.dup.freeze
89
+ @c_flags = c_flags.dup.freeze
90
+ @cxx_env_var = cxx_env_var
91
+ @cxx_flags = cxx_flags.dup.freeze
92
+ @ar_env_var = ar_env_var
93
+ @default_ar = default_ar
94
+ end
95
+
96
+ def link_flags(platform: nil)
97
+ ["-L#{build_root}", *@system_link_flags]
98
+ end
99
+
100
+ def build_flags(platform: nil)
101
+ [*include_flags, *defines.map { |define| "-D#{define}" }].uniq
102
+ end
103
+
104
+ def prepare!(env: ENV, cc: ENV.fetch("CC", "cc"), cxx: ENV.fetch("CXX", "c++"), platform: nil)
105
+ resolved_cc = resolved_cc(env, cc)
106
+ resolved_cxx = resolved_cxx(env, cxx)
107
+ resolved_ar = env.fetch(@ar_env_var || "AR", @default_ar)
108
+ signature = configuration_signature(cc: resolved_cc, cxx: resolved_cxx, ar: resolved_ar)
109
+ signature_changed = signature != read_signature(build_root)
110
+
111
+ FileUtils.mkdir_p(build_root)
112
+ object_paths = sources.map do |source|
113
+ build_object(source, cc: resolved_cc, cxx: resolved_cxx, force_rebuild: signature_changed)
114
+ end
115
+ if !signature_changed && archive_up_to_date?(object_paths)
116
+ ensure_archive_index(ar: resolved_ar)
117
+ return archive_path.to_s
118
+ end
119
+
120
+ stdout, stderr, status = Open3.capture3(resolved_ar, "rcs", archive_path.to_s, *object_paths)
121
+ unless status.success?
122
+ raise Error, command_error("failed to archive vendored #{name}", stdout, stderr)
123
+ end
124
+ ensure_archive_index(ar: resolved_ar)
125
+
126
+ write_signature(build_root, signature)
127
+ archive_path.to_s
128
+ rescue Errno::ENOENT => e
129
+ raise tool_not_found(e)
130
+ end
131
+
132
+ private
133
+
134
+ def configuration_signature(cc:, cxx:, ar:)
135
+ [cc, cxx, ar, *include_flags, *defines, *@c_flags, *@cxx_flags].join("\0")
136
+ end
137
+
138
+ def resolved_cxx(env, default_cxx)
139
+ return default_cxx unless @cxx_env_var
140
+
141
+ env.fetch(@cxx_env_var, default_cxx)
142
+ end
143
+
144
+ def build_object(source, cc:, cxx:, force_rebuild:)
145
+ source_path = source_root.join(source)
146
+ object_path = build_root.join(source.sub(/\.(?:c|cc|cpp|cxx)\z/, ".o"))
147
+ if !force_rebuild && File.exist?(object_path) && File.size?(object_path) && File.mtime(object_path) >= File.mtime(source_path)
148
+ return object_path.to_s
149
+ end
150
+
151
+ FileUtils.mkdir_p(object_path.dirname)
152
+
153
+ compiler, language_flags = compiler_for_source(source, cc:, cxx:)
154
+
155
+ command = [
156
+ compiler,
157
+ "-c",
158
+ source_path.to_s,
159
+ *language_flags,
160
+ *include_flags,
161
+ *defines.map { |define| "-D#{define}" },
162
+ "-o",
163
+ object_path.to_s,
164
+ ]
165
+ stdout, stderr, status = Open3.capture3(*command)
166
+ unless status.success?
167
+ FileUtils.rm_f(object_path)
168
+ raise Error, command_error("failed to compile vendored #{name} source #{source}", stdout, stderr)
169
+ end
170
+
171
+ object_path.to_s
172
+ end
173
+
174
+ def compiler_for_source(source, cc:, cxx:)
175
+ case File.extname(source)
176
+ when ".cc", ".cpp", ".cxx"
177
+ [cxx, @cxx_flags]
178
+ else
179
+ [cc, @c_flags]
180
+ end
181
+ end
182
+
183
+ def ensure_archive_index(ar:)
184
+ stdout, stderr, status = Open3.capture3(ar, "s", archive_path.to_s)
185
+ unless status.success?
186
+ raise Error, command_error("failed to index vendored #{name} archive", stdout, stderr)
187
+ end
188
+ end
189
+
190
+ def archive_up_to_date?(object_paths)
191
+ return false unless File.exist?(archive_path)
192
+
193
+ archive_mtime = File.mtime(archive_path)
194
+ object_paths.all? { |path| File.mtime(path) <= archive_mtime }
195
+ end
196
+ end
197
+
198
+ class CMake < Base
199
+ attr_reader :build_root, :install_root, :archive_path
200
+
201
+ def initialize(name:, source_root:, build_root:, install_root:, archive_path:, include_roots: [], configure_args: [], build_target: "install", system_link_flags: [], pkg_config_name: nil, cc_env_var: nil, cmake_env_var: nil)
202
+ super(name:, source_root:, include_roots:, cc_env_var:)
203
+ @build_root = Pathname.new(File.expand_path(build_root.to_s))
204
+ @install_root = Pathname.new(File.expand_path(install_root.to_s))
205
+ @archive_path = Pathname.new(File.expand_path(archive_path.to_s))
206
+ @configure_args = configure_args.dup.freeze
207
+ @build_target = build_target
208
+ @system_link_flags = system_link_flags.dup.freeze
209
+ @pkg_config_name = pkg_config_name
210
+ @cmake_env_var = cmake_env_var
211
+ end
212
+
213
+ def link_flags(platform: nil)
214
+ ["-L#{archive_path.dirname}", *pkg_config_link_flags, *@system_link_flags].uniq
215
+ end
216
+
217
+ def build_flags(platform: nil)
218
+ include_flags
219
+ end
220
+
221
+ def prepare!(env: ENV, cc: ENV.fetch("CC", "cc"), platform: nil)
222
+ resolved_cc = resolved_cc(env, cc)
223
+ resolved_cmake = env.fetch(@cmake_env_var || "CMAKE", "cmake")
224
+ signature = configuration_signature(cc: resolved_cc, cmake: resolved_cmake)
225
+ needs_configure = signature != read_signature(build_root) || !File.exist?(build_root.join("CMakeCache.txt"))
226
+ needs_build = !archive_up_to_date?
227
+ return archive_path.to_s unless needs_configure || needs_build
228
+
229
+ FileUtils.mkdir_p(build_root)
230
+ FileUtils.mkdir_p(install_root)
231
+ configure(cmake: resolved_cmake, cc: resolved_cc)
232
+ build(cmake: resolved_cmake)
233
+ unless File.exist?(archive_path)
234
+ raise Error, "failed to build vendored #{name}: missing #{archive_path}"
235
+ end
236
+
237
+ write_signature(build_root, signature)
238
+ archive_path.to_s
239
+ rescue Errno::ENOENT => e
240
+ raise tool_not_found(e)
241
+ end
242
+
243
+ private
244
+
245
+ def configuration_signature(cc:, cmake:)
246
+ [cmake, cc, install_root.to_s, *include_flags, *@configure_args, @build_target].join("\0")
247
+ end
248
+
249
+ def archive_up_to_date?
250
+ return false unless File.exist?(archive_path)
251
+
252
+ newest_source_mtime = newest_tree_file_mtime(source_root)
253
+ return true unless newest_source_mtime
254
+
255
+ newest_source_mtime <= File.mtime(archive_path)
256
+ end
257
+
258
+ def configure(cmake:, cc:)
259
+ command = [
260
+ cmake,
261
+ "-S",
262
+ source_root.to_s,
263
+ "-B",
264
+ build_root.to_s,
265
+ "-G",
266
+ "Ninja",
267
+ "-DCMAKE_INSTALL_PREFIX=#{install_root}",
268
+ *@configure_args,
269
+ ]
270
+ stdout, stderr, status = Open3.capture3({ "CC" => cc }, *command)
271
+ unless status.success?
272
+ raise Error, command_error("failed to configure vendored #{name}", stdout, stderr)
273
+ end
274
+ end
275
+
276
+ def build(cmake:)
277
+ command = [cmake, "--build", build_root.to_s, "--target", @build_target]
278
+ stdout, stderr, status = Open3.capture3(*command)
279
+ unless status.success?
280
+ raise Error, command_error("failed to build vendored #{name}", stdout, stderr)
281
+ end
282
+ end
283
+
284
+ def pkg_config_link_flags
285
+ return [] unless @pkg_config_name
286
+
287
+ path = install_root.join("lib/pkgconfig/#{@pkg_config_name}.pc")
288
+ return [] unless File.exist?(path)
289
+
290
+ lines = File.readlines(path, chomp: true)
291
+ variables = pkg_config_variables(lines)
292
+ lines.filter_map do |line|
293
+ line.split(":", 2).last&.strip if line.start_with?("Libs:", "Libs.private:")
294
+ end.flat_map do |value|
295
+ Shellwords.split(expand_pkg_config_value(value, variables))
296
+ end
297
+ end
298
+
299
+ def pkg_config_variables(lines)
300
+ variables = {
301
+ "prefix" => install_root.to_s,
302
+ "exec_prefix" => install_root.to_s,
303
+ "libdir" => archive_path.dirname.to_s,
304
+ "includedir" => install_root.join("include").to_s,
305
+ }
306
+
307
+ lines.each do |line|
308
+ next if line.empty? || line.start_with?("#") || line.include?(":") || !line.include?("=")
309
+
310
+ key, value = line.split("=", 2)
311
+ variables[key] = expand_pkg_config_value(value, variables)
312
+ end
313
+
314
+ variables
315
+ end
316
+
317
+ def expand_pkg_config_value(value, variables)
318
+ value.gsub(/\$\{([^}]+)\}/) { variables.fetch(Regexp.last_match(1), "") }
319
+ end
320
+ end
321
+ end
322
+ end
@@ -0,0 +1,52 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MilkTea
4
+ module VendoredCJSON
5
+ Error = VendoredCLibrary::Error
6
+
7
+ SOURCES = %w[
8
+ cJSON.c
9
+ ].freeze
10
+
11
+ SYSTEM_LINK_FLAGS = %w[
12
+ -lm
13
+ ].freeze
14
+
15
+ module_function
16
+
17
+ def library(root: MilkTea.root)
18
+ resolved_root = Pathname.new(File.expand_path(root.to_s))
19
+ @libraries ||= {}
20
+ @libraries[resolved_root.to_s] ||= VendoredCLibrary::Archive.new(
21
+ name: "cjson",
22
+ source_root: source_root(root: resolved_root),
23
+ build_root: build_root(root: resolved_root),
24
+ archive_name: "libcjson.a",
25
+ sources: SOURCES,
26
+ include_roots: [source_root(root: resolved_root)],
27
+ system_link_flags: SYSTEM_LINK_FLAGS,
28
+ cc_env_var: "CJSON_CC",
29
+ )
30
+ end
31
+
32
+ def source_root(root: MilkTea.root)
33
+ MilkTea.writable_root_for(root).join("third_party/cjson-upstream")
34
+ end
35
+
36
+ def build_root(root: MilkTea.root)
37
+ MilkTea.writable_root_for(root).join("tmp/vendored-cjson")
38
+ end
39
+
40
+ def archive_path(root: MilkTea.root)
41
+ build_root(root:).join("libcjson.a")
42
+ end
43
+
44
+ def link_flags(root: MilkTea.root)
45
+ library(root:).link_flags
46
+ end
47
+
48
+ def prepare!(root: MilkTea.root, **kwargs)
49
+ library(root:).prepare!(**kwargs)
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,78 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MilkTea
4
+ module VendoredFlecs
5
+ Error = VendoredCLibrary::Error
6
+ SOURCE_NAME = "flecs"
7
+
8
+ SOURCES = %w[
9
+ distr/flecs.c
10
+ ].freeze
11
+
12
+ SYSTEM_LINK_FLAGS = %w[
13
+ -lrt
14
+ -lpthread
15
+ -lm
16
+ ].freeze
17
+
18
+ C_FLAGS = %w[
19
+ -std=gnu99
20
+ ].freeze
21
+
22
+ module_function
23
+
24
+ def source(root: MilkTea.root)
25
+ UpstreamSources.default_sources(root:).find { |entry| entry.name == SOURCE_NAME } ||
26
+ raise(Error, "missing upstream source definition for #{SOURCE_NAME}")
27
+ end
28
+
29
+ def library(root: MilkTea.root)
30
+ resolved_root = Pathname.new(File.expand_path(root.to_s))
31
+ @libraries ||= {}
32
+ @libraries[resolved_root.to_s] ||= VendoredCLibrary::Archive.new(
33
+ name: "flecs",
34
+ source_root: source_root(root: resolved_root),
35
+ build_root: build_root(root: resolved_root),
36
+ archive_name: "libflecs.a",
37
+ sources: SOURCES,
38
+ include_roots: [include_root(root: resolved_root)],
39
+ system_link_flags: SYSTEM_LINK_FLAGS,
40
+ cc_env_var: "FLECS_CC",
41
+ c_flags: C_FLAGS,
42
+ )
43
+ end
44
+
45
+ def source_root(root: MilkTea.root)
46
+ source(root:).checkout_root
47
+ end
48
+
49
+ def include_root(root: MilkTea.root)
50
+ source_root(root:).join("distr")
51
+ end
52
+
53
+ def header_path(root: MilkTea.root)
54
+ include_root(root:).join("flecs.h")
55
+ end
56
+
57
+ def build_root(root: MilkTea.root)
58
+ MilkTea.writable_root_for(root).join("tmp/vendored-flecs")
59
+ end
60
+
61
+ def archive_path(root: MilkTea.root)
62
+ build_root(root:).join("libflecs.a")
63
+ end
64
+
65
+ def include_flags(root: MilkTea.root)
66
+ library(root:).include_flags
67
+ end
68
+
69
+ def link_flags(root: MilkTea.root)
70
+ library(root:).link_flags
71
+ end
72
+
73
+ def prepare!(root: MilkTea.root, **kwargs)
74
+ source(root:).bootstrap!
75
+ library(root:).prepare!(**kwargs)
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,77 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MilkTea
4
+ module VendoredGLFW
5
+ Error = VendoredCLibrary::Error
6
+ SOURCE_NAME = "glfw"
7
+
8
+ CONFIGURE_ARGS = %w[
9
+ -DCMAKE_BUILD_TYPE=Release
10
+ -DCMAKE_POSITION_INDEPENDENT_CODE=ON
11
+ -DBUILD_SHARED_LIBS=OFF
12
+ -DGLFW_BUILD_EXAMPLES=OFF
13
+ -DGLFW_BUILD_TESTS=OFF
14
+ -DGLFW_BUILD_DOCS=OFF
15
+ ].freeze
16
+
17
+ module_function
18
+
19
+ def source(root: MilkTea.root)
20
+ UpstreamSources.default_sources(root:).find { |entry| entry.name == SOURCE_NAME } ||
21
+ raise(Error, "missing upstream source definition for #{SOURCE_NAME}")
22
+ end
23
+
24
+ def library(root: MilkTea.root)
25
+ resolved_root = Pathname.new(File.expand_path(root.to_s))
26
+ @libraries ||= {}
27
+ @libraries[resolved_root.to_s] ||= VendoredCLibrary::CMake.new(
28
+ name: "glfw",
29
+ source_root: source_root(root: resolved_root),
30
+ build_root: build_root(root: resolved_root),
31
+ install_root: install_root(root: resolved_root),
32
+ archive_path: archive_path(root: resolved_root),
33
+ include_roots: [include_root(root: resolved_root)],
34
+ configure_args: CONFIGURE_ARGS,
35
+ pkg_config_name: "glfw3",
36
+ cc_env_var: "GLFW_CC",
37
+ )
38
+ end
39
+
40
+ def source_root(root: MilkTea.root)
41
+ source(root:).checkout_root
42
+ end
43
+
44
+ def include_root(root: MilkTea.root)
45
+ source_root(root:).join("include")
46
+ end
47
+
48
+ def header_root(root: MilkTea.root)
49
+ include_root(root:).join("GLFW")
50
+ end
51
+
52
+ def build_root(root: MilkTea.root)
53
+ MilkTea.writable_root_for(root).join("tmp/vendored-glfw")
54
+ end
55
+
56
+ def install_root(root: MilkTea.root)
57
+ MilkTea.writable_root_for(root).join("tmp/vendored-glfw-prefix")
58
+ end
59
+
60
+ def archive_path(root: MilkTea.root)
61
+ install_root(root:).join("lib/libglfw3.a")
62
+ end
63
+
64
+ def include_flags(root: MilkTea.root)
65
+ library(root:).include_flags
66
+ end
67
+
68
+ def link_flags(root: MilkTea.root)
69
+ library(root:).link_flags
70
+ end
71
+
72
+ def prepare!(root: MilkTea.root, **kwargs)
73
+ source(root:).bootstrap!
74
+ library(root:).prepare!(**kwargs)
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,75 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MilkTea
4
+ module VendoredLibUV
5
+ Error = VendoredCLibrary::Error
6
+ SOURCE_NAME = "libuv"
7
+
8
+ CONFIGURE_ARGS = %w[
9
+ -DCMAKE_BUILD_TYPE=Release
10
+ -DCMAKE_POSITION_INDEPENDENT_CODE=ON
11
+ -DBUILD_SHARED_LIBS=OFF
12
+ -DBUILD_TESTING=OFF
13
+ ].freeze
14
+
15
+ module_function
16
+
17
+ def source(root: MilkTea.root)
18
+ UpstreamSources.default_sources(root:).find { |entry| entry.name == SOURCE_NAME } ||
19
+ raise(Error, "missing upstream source definition for #{SOURCE_NAME}")
20
+ end
21
+
22
+ def library(root: MilkTea.root)
23
+ resolved_root = Pathname.new(File.expand_path(root.to_s))
24
+ @libraries ||= {}
25
+ @libraries[resolved_root.to_s] ||= VendoredCLibrary::CMake.new(
26
+ name: "libuv",
27
+ source_root: source_root(root: resolved_root),
28
+ build_root: build_root(root: resolved_root),
29
+ install_root: install_root(root: resolved_root),
30
+ archive_path: archive_path(root: resolved_root),
31
+ include_roots: [include_root(root: resolved_root)],
32
+ configure_args: CONFIGURE_ARGS,
33
+ pkg_config_name: "libuv-static",
34
+ cc_env_var: "LIBUV_CC",
35
+ )
36
+ end
37
+
38
+ def source_root(root: MilkTea.root)
39
+ source(root:).checkout_root
40
+ end
41
+
42
+ def include_root(root: MilkTea.root)
43
+ source_root(root:).join("include")
44
+ end
45
+
46
+ def header_path(root: MilkTea.root)
47
+ include_root(root:).join("uv.h")
48
+ end
49
+
50
+ def build_root(root: MilkTea.root)
51
+ MilkTea.writable_root_for(root).join("tmp/vendored-libuv")
52
+ end
53
+
54
+ def install_root(root: MilkTea.root)
55
+ MilkTea.writable_root_for(root).join("tmp/vendored-libuv-prefix")
56
+ end
57
+
58
+ def archive_path(root: MilkTea.root)
59
+ install_root(root:).join("lib/libuv.a")
60
+ end
61
+
62
+ def include_flags(root: MilkTea.root)
63
+ library(root:).include_flags
64
+ end
65
+
66
+ def link_flags(root: MilkTea.root)
67
+ library(root:).link_flags
68
+ end
69
+
70
+ def prepare!(root: MilkTea.root, **kwargs)
71
+ source(root:).bootstrap!
72
+ library(root:).prepare!(**kwargs)
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,84 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MilkTea
4
+ module VendoredPCRE2
5
+ Error = VendoredCLibrary::Error
6
+ SOURCE_NAME = "pcre2"
7
+
8
+ CONFIGURE_ARGS = %w[
9
+ -DCMAKE_BUILD_TYPE=Release
10
+ -DCMAKE_POSITION_INDEPENDENT_CODE=ON
11
+ -DBUILD_SHARED_LIBS=OFF
12
+ -DPCRE2_BUILD_PCRE2_8=ON
13
+ -DPCRE2_BUILD_PCRE2_16=OFF
14
+ -DPCRE2_BUILD_PCRE2_32=OFF
15
+ -DPCRE2_BUILD_PCRE2GREP=OFF
16
+ -DPCRE2_BUILD_PCRE2TEST=OFF
17
+ -DPCRE2_BUILD_TESTS=OFF
18
+ ].freeze
19
+
20
+ SYSTEM_LINK_FLAGS = %w[
21
+ -lm
22
+ ].freeze
23
+
24
+ module_function
25
+
26
+ def source(root: MilkTea.root)
27
+ UpstreamSources.default_sources(root:).find { |entry| entry.name == SOURCE_NAME } ||
28
+ raise(Error, "missing upstream source definition for #{SOURCE_NAME}")
29
+ end
30
+
31
+ def library(root: MilkTea.root)
32
+ resolved_root = Pathname.new(File.expand_path(root.to_s))
33
+ @libraries ||= {}
34
+ @libraries[resolved_root.to_s] ||= VendoredCLibrary::CMake.new(
35
+ name: "pcre2",
36
+ source_root: source_root(root: resolved_root),
37
+ build_root: build_root(root: resolved_root),
38
+ install_root: install_root(root: resolved_root),
39
+ archive_path: archive_path(root: resolved_root),
40
+ include_roots: [include_root(root: resolved_root)],
41
+ configure_args: CONFIGURE_ARGS,
42
+ system_link_flags: SYSTEM_LINK_FLAGS,
43
+ cc_env_var: "PCRE2_CC",
44
+ )
45
+ end
46
+
47
+ def source_root(root: MilkTea.root)
48
+ source(root:).checkout_root
49
+ end
50
+
51
+ def include_root(root: MilkTea.root)
52
+ install_root(root:).join("include")
53
+ end
54
+
55
+ def header_path(root: MilkTea.root)
56
+ include_root(root:).join("pcre2.h")
57
+ end
58
+
59
+ def build_root(root: MilkTea.root)
60
+ MilkTea.writable_root_for(root).join("tmp/vendored-pcre2")
61
+ end
62
+
63
+ def install_root(root: MilkTea.root)
64
+ MilkTea.writable_root_for(root).join("tmp/vendored-pcre2-prefix")
65
+ end
66
+
67
+ def archive_path(root: MilkTea.root)
68
+ install_root(root:).join("lib/libpcre2-8.a")
69
+ end
70
+
71
+ def include_flags(root: MilkTea.root)
72
+ library(root:).include_flags
73
+ end
74
+
75
+ def link_flags(root: MilkTea.root)
76
+ library(root:).link_flags
77
+ end
78
+
79
+ def prepare!(root: MilkTea.root, **kwargs)
80
+ source(root:).bootstrap!
81
+ library(root:).prepare!(**kwargs)
82
+ end
83
+ end
84
+ end