ruby_wasm 2.5.0-x86_64-darwin → 2.5.1-x86_64-darwin

Sign up to get free protection for your applications and to get access to all the features.
Files changed (43) hide show
  1. checksums.yaml +4 -4
  2. data/CONTRIBUTING.md +9 -7
  3. data/Gemfile +1 -1
  4. data/README.md +10 -9
  5. data/Rakefile +8 -7
  6. data/docs/cheat_sheet.md +8 -8
  7. data/lib/ruby_wasm/3.1/ruby_wasm.bundle +0 -0
  8. data/lib/ruby_wasm/3.2/ruby_wasm.bundle +0 -0
  9. data/lib/ruby_wasm/{3.0 → 3.3}/ruby_wasm.bundle +0 -0
  10. data/lib/ruby_wasm/build/executor.rb +4 -0
  11. data/lib/ruby_wasm/build/product/crossruby.rb +53 -23
  12. data/lib/ruby_wasm/build/product/libyaml.rb +5 -3
  13. data/lib/ruby_wasm/build/product/openssl.rb +7 -2
  14. data/lib/ruby_wasm/build/product/product.rb +3 -3
  15. data/lib/ruby_wasm/build/product/ruby_source.rb +3 -3
  16. data/lib/ruby_wasm/build/product/wasi_vfs.rb +1 -1
  17. data/lib/ruby_wasm/build/product/zlib.rb +3 -1
  18. data/lib/ruby_wasm/build/target.rb +24 -0
  19. data/lib/ruby_wasm/build/toolchain.rb +1 -1
  20. data/lib/ruby_wasm/build.rb +7 -3
  21. data/lib/ruby_wasm/cli.rb +141 -11
  22. data/lib/ruby_wasm/packager/component_adapter/wasi_snapshot_preview1.command.wasm +0 -0
  23. data/lib/ruby_wasm/packager/component_adapter/wasi_snapshot_preview1.reactor.wasm +0 -0
  24. data/lib/ruby_wasm/packager/component_adapter.rb +14 -0
  25. data/lib/ruby_wasm/packager/core.rb +180 -3
  26. data/lib/ruby_wasm/packager/file_system.rb +5 -3
  27. data/lib/ruby_wasm/packager.rb +18 -81
  28. data/lib/ruby_wasm/rake_task.rb +1 -0
  29. data/lib/ruby_wasm/version.rb +1 -1
  30. data/lib/ruby_wasm.rb +1 -0
  31. data/package-lock.json +410 -133
  32. data/package.json +3 -3
  33. data/rakelib/ci.rake +3 -3
  34. data/rakelib/packaging.rake +26 -12
  35. data/sig/ruby_wasm/build.rbs +36 -27
  36. data/sig/ruby_wasm/cli.rbs +27 -3
  37. data/sig/ruby_wasm/ext.rbs +15 -2
  38. data/sig/ruby_wasm/packager.rbs +37 -6
  39. metadata +9 -9
  40. data/builders/wasm32-unknown-emscripten/Dockerfile +0 -43
  41. data/builders/wasm32-unknown-emscripten/entrypoint.sh +0 -7
  42. data/builders/wasm32-unknown-wasi/Dockerfile +0 -47
  43. data/builders/wasm32-unknown-wasi/entrypoint.sh +0 -7
data/lib/ruby_wasm/cli.rb CHANGED
@@ -42,7 +42,7 @@ module RubyWasm
42
42
  end
43
43
 
44
44
  def build(args)
45
- # @type var options: Hash[Symbol, untyped]
45
+ # @type var options: cli_options
46
46
  options = {
47
47
  save_temps: false,
48
48
  optimize: false,
@@ -50,14 +50,16 @@ module RubyWasm
50
50
  reconfigure: false,
51
51
  clean: false,
52
52
  ruby_version: "3.3",
53
- target_triplet: "wasm32-unknown-wasi",
53
+ target_triplet: "wasm32-unknown-wasip1",
54
54
  profile: "full",
55
55
  stdlib: true,
56
- disable_gems: false
56
+ disable_gems: false,
57
+ gemfile: nil,
58
+ patches: [],
57
59
  }
58
60
  OptionParser
59
61
  .new do |opts|
60
- opts.banner = "Usage: rbwasm componentize [options]"
62
+ opts.banner = "Usage: rbwasm build [options]"
61
63
  opts.on("-h", "--help", "Prints this help") do
62
64
  @stdout.puts opts
63
65
  exit
@@ -106,6 +108,10 @@ module RubyWasm
106
108
  options[:disable_gems] = true
107
109
  end
108
110
 
111
+ opts.on("-p", "--patch PATCH", "Apply a patch") do |patch|
112
+ options[:patches] << patch
113
+ end
114
+
109
115
  opts.on("--format FORMAT", "Output format") do |format|
110
116
  options[:format] = format
111
117
  end
@@ -116,8 +122,19 @@ module RubyWasm
116
122
  end
117
123
  .parse!(args)
118
124
 
125
+ __skip__ = if defined?(Bundler)
126
+ Bundler.settings.temporary(force_ruby_platform: true) do
127
+ do_build_with_force_ruby_platform(options)
128
+ end
129
+ else
130
+ do_build_with_force_ruby_platform(options)
131
+ end
132
+ end
133
+
134
+ def do_build_with_force_ruby_platform(options)
119
135
  verbose = RubyWasm.logger.level == :debug
120
136
  executor = RubyWasm::BuildExecutor.new(verbose: verbose)
137
+
121
138
  packager = self.derive_packager(options)
122
139
 
123
140
  if options[:print_ruby_cache_key]
@@ -152,10 +169,11 @@ module RubyWasm
152
169
  private
153
170
 
154
171
  def build_config(options)
155
- config = { target: options[:target_triplet], src: options[:ruby_version] }
172
+ # @type var config: Packager::build_config
173
+ config = { target: options[:target_triplet], src: compute_build_source(options) }
156
174
  case options[:profile]
157
175
  when "full"
158
- config[:default_exts] = RubyWasm::Packager::ALL_DEFAULT_EXTS
176
+ config[:default_exts] = config[:src][:all_default_exts]
159
177
  env_additional_exts = ENV["RUBY_WASM_ADDITIONAL_EXTS"] || ""
160
178
  unless env_additional_exts.empty?
161
179
  config[:default_exts] += "," + env_additional_exts
@@ -170,12 +188,124 @@ module RubyWasm
170
188
  config
171
189
  end
172
190
 
173
- def derive_packager(options)
191
+ def compute_build_source(options)
192
+ src_name = options[:ruby_version]
193
+ aliases = self.class.build_source_aliases(root)
194
+ source = aliases[src_name]
195
+ if source.nil?
196
+ if File.directory?(src_name)
197
+ # Treat as a local source if the given name is a source directory.
198
+ RubyWasm.logger.debug "Using local source: #{src_name}"
199
+ if options[:patches].any?
200
+ RubyWasm.logger.warn "Patches specified through --patch are ignored for local sources"
201
+ end
202
+ # @type var local_source: RubyWasm::Packager::build_source_local
203
+ local_source = { type: "local", path: src_name }
204
+ # @type var local_source: RubyWasm::Packager::build_source
205
+ local_source = local_source.merge(name: "local", patches: [])
206
+ return local_source
207
+ end
208
+ # Otherwise, it's an unknown source.
209
+ raise(
210
+ "Unknown Ruby source: #{src_name} (available: #{aliases.keys.join(", ")} or a local directory)"
211
+ )
212
+ end
213
+ # Apply user-specified patches in addition to bundled patches.
214
+ source[:patches].concat(options[:patches])
215
+ source
216
+ end
217
+
218
+ # Retrieves the alias definitions for the Ruby sources.
219
+ def self.build_source_aliases(root)
220
+ # @type var sources: Hash[string, RubyWasm::Packager::build_source]
221
+ sources = {
222
+ "head" => {
223
+ type: "github",
224
+ repo: "ruby/ruby",
225
+ rev: "master",
226
+ all_default_exts: RubyWasm::Packager::ALL_DEFAULT_EXTS,
227
+ },
228
+ "3.3" => {
229
+ type: "tarball",
230
+ url: "https://cache.ruby-lang.org/pub/ruby/3.3/ruby-3.3.0.tar.gz",
231
+ all_default_exts: "bigdecimal,cgi/escape,continuation,coverage,date,dbm,digest/bubblebabble,digest,digest/md5,digest/rmd160,digest/sha1,digest/sha2,etc,fcntl,fiber,gdbm,json,json/generator,json/parser,nkf,objspace,pathname,psych,racc/cparse,rbconfig/sizeof,ripper,stringio,strscan,monitor,zlib,openssl",
232
+ },
233
+ "3.2" => {
234
+ type: "tarball",
235
+ url: "https://cache.ruby-lang.org/pub/ruby/3.2/ruby-3.2.3.tar.gz",
236
+ all_default_exts: "bigdecimal,cgi/escape,continuation,coverage,date,dbm,digest/bubblebabble,digest,digest/md5,digest/rmd160,digest/sha1,digest/sha2,etc,fcntl,fiber,gdbm,json,json/generator,json/parser,nkf,objspace,pathname,psych,racc/cparse,rbconfig/sizeof,ripper,stringio,strscan,monitor,zlib,openssl",
237
+ }
238
+ }
239
+
240
+ # Apply bundled and user-specified `<root>/patches` directories.
241
+ sources.each do |name, source|
242
+ source[:name] = name
243
+ patches_dirs = [bundled_patches_path, File.join(root, "patches")]
244
+ source[:patches] = patches_dirs.flat_map do |patches_dir|
245
+ Dir[File.join(patches_dir, name, "*.patch")]
246
+ .map { |p| File.expand_path(p) }
247
+ end
248
+ end
249
+
250
+ build_manifest = File.join(root, "build_manifest.json")
251
+ if File.exist?(build_manifest)
252
+ begin
253
+ manifest = JSON.parse(File.read(build_manifest))
254
+ manifest["ruby_revisions"].each do |name, rev|
255
+ source = sources[name]
256
+ next unless source[:type] == "github"
257
+ # @type var source: RubyWasm::Packager::build_source_github
258
+ source[:rev] = rev
259
+ end
260
+ rescue StandardError => e
261
+ RubyWasm.logger.warn "Failed to load build_manifest.json: #{e}"
262
+ end
263
+ end
264
+ sources
265
+ end
266
+
267
+ # Retrieves the root directory of the Ruby project.
268
+ def root
174
269
  __skip__ =
175
- if defined?(Bundler) && !options[:disable_gems]
270
+ @root ||=
271
+ begin
272
+ if explicit = ENV["RUBY_WASM_ROOT"]
273
+ File.expand_path(explicit)
274
+ elsif defined?(Bundler)
275
+ Bundler.root
276
+ else
277
+ Dir.pwd
278
+ end
279
+ rescue Bundler::GemfileNotFound
280
+ Dir.pwd
281
+ end
282
+ end
283
+
284
+ # Path to the directory containing the bundled patches, which is shipped
285
+ # as part of ruby_wasm gem to backport fixes or try experimental features
286
+ # before landing them to the ruby/ruby repository.
287
+ def self.bundled_patches_path
288
+ dir = __dir__
289
+ raise "Unexpected directory structure, no __dir__!??" unless dir
290
+ lib_source_root = File.join(dir, "..", "..")
291
+ File.join(lib_source_root, "patches")
292
+ end
293
+
294
+ def derive_packager(options)
295
+ __skip__ = definition = nil
296
+ __skip__ = if defined?(Bundler) && !options[:disable_gems]
297
+ begin
298
+ # Silence Bundler UI if --print-ruby-cache-key is specified not to bother the JSON output.
299
+ level = options[:print_ruby_cache_key] ? :silent : Bundler.ui.level
300
+ old_level = Bundler.ui.level
301
+ Bundler.ui.level = level
176
302
  definition = Bundler.definition
303
+ ensure
304
+ Bundler.ui.level = old_level
177
305
  end
178
- RubyWasm::Packager.new(build_config(options), definition)
306
+ end
307
+ RubyWasm.logger.info "Using Gemfile: #{definition.gemfiles}" if definition
308
+ RubyWasm::Packager.new(root, build_config(options), definition)
179
309
  end
180
310
 
181
311
  def do_print_ruby_cache_key(packager)
@@ -197,9 +327,9 @@ module RubyWasm
197
327
  RubyWasm.logger.info "Size: #{SizeFormatter.format(wasm_bytes.size)}"
198
328
  case options[:output]
199
329
  when "-"
200
- @stdout.write wasm_bytes.pack("C*")
330
+ @stdout.write wasm_bytes
201
331
  else
202
- File.binwrite(options[:output], wasm_bytes.pack("C*"))
332
+ File.binwrite(options[:output], wasm_bytes)
203
333
  RubyWasm.logger.debug "Wrote #{options[:output]}"
204
334
  end
205
335
  end
@@ -0,0 +1,14 @@
1
+ module RubyWasm::Packager::ComponentAdapter
2
+ module_function
3
+
4
+ # The path to the component adapter for the given WASI execution model.
5
+ #
6
+ # @param exec_model [String] "command" or "reactor"
7
+ def wasi_snapshot_preview1(exec_model)
8
+ File.join(
9
+ File.dirname(__FILE__),
10
+ "component_adapter",
11
+ "wasi_snapshot_preview1.#{exec_model}.wasm"
12
+ )
13
+ end
14
+ end
@@ -12,7 +12,7 @@ class RubyWasm::Packager::Core
12
12
 
13
13
  extend Forwardable
14
14
 
15
- def_delegators :build_strategy, :cache_key, :artifact
15
+ def_delegators :build_strategy, :cache_key, :artifact, :build_and_link_exts
16
16
 
17
17
  private
18
18
 
@@ -37,6 +37,10 @@ class RubyWasm::Packager::Core
37
37
  raise NotImplementedError
38
38
  end
39
39
 
40
+ def build_and_link_exts(executor)
41
+ raise NotImplementedError
42
+ end
43
+
40
44
  # Array of paths to extconf.rb files.
41
45
  def specs_with_extensions
42
46
  @packager.specs.filter_map do |spec|
@@ -61,6 +65,167 @@ class RubyWasm::Packager::Core
61
65
  end
62
66
 
63
67
  class DynamicLinking < BuildStrategy
68
+ def build(executor, options)
69
+ build = derive_build
70
+ force_rebuild =
71
+ options[:remake] || options[:clean] || options[:reconfigure]
72
+ if File.exist?(build.crossruby.artifact) && !force_rebuild
73
+ # Always build extensions because they are usually not expensive to build
74
+ return build.crossruby.artifact
75
+ end
76
+ build.crossruby.clean(executor) if options[:clean]
77
+
78
+ do_build =
79
+ proc do
80
+ build.crossruby.build(
81
+ executor,
82
+ remake: options[:remake],
83
+ reconfigure: options[:reconfigure]
84
+ )
85
+ end
86
+
87
+ __skip__ =
88
+ if defined?(Bundler)
89
+ Bundler.with_unbundled_env(&do_build)
90
+ else
91
+ do_build.call
92
+ end
93
+ build.crossruby.artifact
94
+ end
95
+
96
+ def build_and_link_exts(executor)
97
+ build = derive_build
98
+ self.build_exts(executor, build)
99
+ self.link_exts(executor, build)
100
+ end
101
+
102
+ def link_exts(executor, build)
103
+ ruby_root = build.crossruby.dest_dir
104
+
105
+ libraries = [File.join(ruby_root, "usr", "local", "bin", "ruby")]
106
+
107
+ # TODO: Should be computed from dyinfo of ruby binary
108
+ wasi_libc_shared_libs = [
109
+ "libc.so",
110
+ "libwasi-emulated-getpid.so",
111
+ "libwasi-emulated-mman.so",
112
+ "libwasi-emulated-process-clocks.so",
113
+ "libwasi-emulated-signal.so",
114
+ ]
115
+
116
+ wasi_libc_shared_libs.each do |lib|
117
+ # @type var toolchain: RubyWasm::WASISDK
118
+ toolchain = build.toolchain
119
+ wasi_sdk_path = toolchain.wasi_sdk_path
120
+ libraries << File.join(wasi_sdk_path, "share/wasi-sysroot/lib/wasm32-wasi", lib)
121
+ end
122
+ wasi_adapter = RubyWasm::Packager::ComponentAdapter.wasi_snapshot_preview1("command")
123
+ adapters = [wasi_adapter]
124
+ dl_openable_libs = Dir.glob(File.join(ruby_root, "usr", "local", "lib", "ruby", "**", "*.so"))
125
+ linker = RubyWasmExt::ComponentLink.new
126
+ linker.use_built_in_libdl(true)
127
+ linker.stub_missing_functions(false)
128
+ linker.validate(true)
129
+
130
+ libraries.each do |lib|
131
+ # Non-DL openable libraries should be referenced as base name
132
+ lib_name = File.basename(lib)
133
+ module_bytes = File.binread(lib)
134
+ RubyWasm.logger.info "Linking #{lib_name} (#{module_bytes.size} bytes)"
135
+ linker.library(lib_name, module_bytes, false)
136
+ end
137
+
138
+ dl_openable_libs.each do |lib|
139
+ # DL openable lib_name should be a relative path from ruby_root
140
+ lib_name = "/" + Pathname.new(lib).relative_path_from(Pathname.new(ruby_root)).to_s
141
+ module_bytes = File.binread(lib)
142
+ RubyWasm.logger.info "Linking #{lib_name} (#{module_bytes.size} bytes)"
143
+ linker.library(lib_name, module_bytes, true)
144
+ end
145
+
146
+ adapters.each do |adapter|
147
+ adapter_name = File.basename(adapter)
148
+ # e.g. wasi_snapshot_preview1.command.wasm -> wasi_snapshot_preview1
149
+ adapter_name = adapter_name.split(".")[0]
150
+ module_bytes = File.binread(adapter)
151
+ linker.adapter(adapter_name, module_bytes)
152
+ end
153
+ return linker.encode()
154
+ end
155
+
156
+ def build_exts(executor, build)
157
+ exts = specs_with_extensions.flat_map do |spec, exts|
158
+ exts.map do |ext|
159
+ ext_feature = File.dirname(ext) # e.g. "ext/cgi/escape"
160
+ ext_srcdir = File.join(spec.full_gem_path, ext_feature)
161
+ ext_relative_path = File.join(spec.full_name, ext_feature)
162
+ RubyWasm::CrossRubyExtProduct.new(
163
+ ext_srcdir,
164
+ build.toolchain,
165
+ ext_relative_path: ext_relative_path
166
+ )
167
+ end
168
+ end
169
+
170
+ exts.each do |prod|
171
+ executor.begin_section prod.class, prod.name, "Building"
172
+ prod.build(executor, build.crossruby)
173
+ executor.end_section prod.class, prod.name
174
+ end
175
+ end
176
+
177
+ def cache_key(digest)
178
+ derive_build.cache_key(digest)
179
+ end
180
+
181
+ def artifact
182
+ derive_build.crossruby.artifact
183
+ end
184
+
185
+ def target
186
+ RubyWasm::Target.new(@packager.full_build_options[:target], pic: true)
187
+ end
188
+
189
+ def derive_build
190
+ return @build if @build
191
+ __skip__ =
192
+ build ||= RubyWasm::Build.new(
193
+ name, **@packager.full_build_options,
194
+ target: target,
195
+ # NOTE: We don't need linking libwasi_vfs because we use wasi-virt instead.
196
+ wasi_vfs: nil
197
+ )
198
+ build.crossruby.cflags = %w[-fPIC -fvisibility=default]
199
+ if @packager.full_build_options[:target] != "wasm32-unknown-emscripten"
200
+ build.crossruby.debugflags = %w[-g]
201
+ build.crossruby.wasmoptflags = %w[-O3 -g --pass-arg=asyncify-relocatable]
202
+ build.crossruby.ldflags = %w[
203
+ -Xlinker
204
+ --stack-first
205
+ -Xlinker
206
+ -z
207
+ -Xlinker
208
+ stack-size=16777216
209
+ ]
210
+ build.crossruby.xldflags = %w[
211
+ -Xlinker -shared
212
+ -Xlinker --export-dynamic
213
+ -Xlinker --export-all
214
+ -Xlinker --experimental-pic
215
+ -Xlinker -export-if-defined=__main_argc_argv
216
+ ]
217
+ end
218
+ @build = build
219
+ build
220
+ end
221
+
222
+ def name
223
+ require "digest"
224
+ options = @packager.full_build_options
225
+ src_channel = options[:src][:name]
226
+ target_triplet = options[:target]
227
+ "ruby-#{src_channel}-#{target_triplet}-pic#{options[:suffix]}"
228
+ end
64
229
  end
65
230
 
66
231
  class StaticLinking < BuildStrategy
@@ -99,10 +264,14 @@ class RubyWasm::Packager::Core
99
264
  derive_build.crossruby.artifact
100
265
  end
101
266
 
267
+ def target
268
+ RubyWasm::Target.new(@packager.full_build_options[:target])
269
+ end
270
+
102
271
  def derive_build
103
272
  return @build if @build
104
273
  __skip__ =
105
- build ||= RubyWasm::Build.new(name, **@packager.full_build_options)
274
+ build ||= RubyWasm::Build.new(name, **@packager.full_build_options, target: target)
106
275
  build.crossruby.user_exts = user_exts(build)
107
276
  # Emscripten uses --global-base=1024 by default, but it conflicts with
108
277
  # --stack-first and -z stack-size since global-base 1024 is smaller than
@@ -111,7 +280,9 @@ class RubyWasm::Packager::Core
111
280
  # script of Ruby.
112
281
  if @packager.full_build_options[:target] != "wasm32-unknown-emscripten"
113
282
  build.crossruby.debugflags = %w[-g]
114
- build.crossruby.wasmoptflags = %w[-O3 -g]
283
+ # We assume that imported functions provided through WASI will not change
284
+ # asyncify state, so we ignore them.
285
+ build.crossruby.wasmoptflags = %w[-O3 -g --pass-arg=asyncify-ignore-imports]
115
286
  build.crossruby.ldflags = %w[
116
287
  -Xlinker
117
288
  --stack-first
@@ -125,6 +296,12 @@ class RubyWasm::Packager::Core
125
296
  build
126
297
  end
127
298
 
299
+ def build_and_link_exts(executor)
300
+ build = derive_build
301
+ ruby_root = build.crossruby.dest_dir
302
+ File.binread(File.join(ruby_root, "usr", "local", "bin", "ruby"))
303
+ end
304
+
128
305
  def user_exts(build)
129
306
  @user_exts ||=
130
307
  specs_with_extensions.flat_map do |spec, exts|
@@ -65,12 +65,14 @@ class RubyWasm::Packager::FileSystem
65
65
  end
66
66
 
67
67
  def remove_non_runtime_files(executor)
68
- %w[
69
- **/*.so
68
+ patterns = %w[
70
69
  usr/local/lib/libruby-static.a
71
70
  usr/local/bin/ruby
72
71
  usr/local/include
73
- ].each do |pattern|
72
+ ]
73
+
74
+ patterns << "**/*.so" unless @packager.support_dynamic_linking?
75
+ patterns.each do |pattern|
74
76
  Dir
75
77
  .glob(File.join(@dest_dir, pattern))
76
78
  .each do |entry|
@@ -2,9 +2,15 @@
2
2
  class RubyWasm::Packager
3
3
  # Initializes a new instance of the RubyWasm::Packager class.
4
4
  #
5
+ # @param root [String] The root directory of the Ruby project.
6
+ # The root directory (will) contain the following files:
7
+ # * build_manifest.json
8
+ # * rubies
9
+ # * build
5
10
  # @param config [Hash] The build config used for building Ruby.
6
11
  # @param definition [Bundler::Definition] The Bundler definition.
7
- def initialize(config = nil, definition = nil)
12
+ def initialize(root, config = nil, definition = nil)
13
+ @root = root
8
14
  @definition = definition
9
15
  @config = config
10
16
  end
@@ -21,15 +27,13 @@ class RubyWasm::Packager
21
27
 
22
28
  fs = RubyWasm::Packager::FileSystem.new(dest_dir, self)
23
29
  fs.package_ruby_root(tarball, executor)
24
-
25
- ruby_wasm_bin = File.expand_path("bin/ruby", fs.ruby_root)
26
- wasm_bytes = File.binread(ruby_wasm_bin).bytes
30
+ wasm_bytes = ruby_core.build_and_link_exts(executor)
27
31
 
28
32
  fs.package_gems
29
33
  fs.remove_non_runtime_files(executor)
30
34
  fs.remove_stdlib(executor) unless options[:stdlib]
31
35
 
32
- if full_build_options[:target] == "wasm32-unknown-wasi"
36
+ if full_build_options[:target] == "wasm32-unknown-wasip1" && !support_dynamic_linking?
33
37
  # wasi-vfs supports only WASI target
34
38
  wasi_vfs = RubyWasmExt::WasiVfs.new
35
39
  wasi_vfs.map_dir("/bundle", fs.bundle_dir)
@@ -52,79 +56,23 @@ class RubyWasm::Packager
52
56
  # Retrieves the specs from the Bundler definition, excluding the excluded gems.
53
57
  def specs
54
58
  return [] unless @definition
55
- @definition.specs.reject { |spec| EXCLUDED_GEMS.include?(spec.name) }
59
+ @specs ||= @definition.resolve.materialize(@definition.requested_dependencies)
60
+ .reject { |spec| EXCLUDED_GEMS.include?(spec.name) }
61
+ @specs
56
62
  end
57
63
 
58
64
  # Checks if dynamic linking is supported.
59
65
  def support_dynamic_linking?
60
- @ruby_channel == "head"
61
- end
62
-
63
- # Retrieves the root directory of the Ruby project.
64
- # The root directory contains the following stuff:
65
- # * patches/*.patch
66
- # * build_manifest.json
67
- # * rubies
68
- # * build
69
- def root
70
- __skip__ =
71
- @root ||=
72
- begin
73
- if explicit = ENV["RUBY_WASM_ROOT"]
74
- File.expand_path(explicit)
75
- elsif defined?(Bundler)
76
- Bundler.root
77
- else
78
- Dir.pwd
79
- end
80
- rescue Bundler::GemfileNotFound
81
- Dir.pwd
82
- end
83
- end
84
-
85
- # Retrieves the alias definitions for the Ruby sources.
86
- def self.build_source_aliases(root)
87
- patches = Dir[File.join(root, "patches", "*.patch")]
88
- sources = {
89
- "head" => {
90
- type: "github",
91
- repo: "ruby/ruby",
92
- rev: "master",
93
- patches: patches.map { |p| File.expand_path(p) }
94
- },
95
- "3.3" => {
96
- type: "tarball",
97
- url: "https://cache.ruby-lang.org/pub/ruby/3.3/ruby-3.3.0.tar.gz"
98
- },
99
- "3.2" => {
100
- type: "tarball",
101
- url: "https://cache.ruby-lang.org/pub/ruby/3.2/ruby-3.2.3.tar.gz"
102
- }
103
- }
104
- sources.each { |name, source| source[:name] = name }
105
-
106
- build_manifest = File.join(root, "build_manifest.json")
107
- if File.exist?(build_manifest)
108
- begin
109
- manifest = JSON.parse(File.read(build_manifest))
110
- manifest["ruby_revisions"].each do |name, rev|
111
- sources[name][:rev] = rev
112
- end
113
- rescue StandardError => e
114
- RubyWasm.logger.warn "Failed to load build_manifest.json: #{e}"
115
- end
116
- end
117
- sources
66
+ ENV["RUBY_WASM_EXPERIMENTAL_DYNAMIC_LINKING"] == "1"
118
67
  end
119
68
 
120
69
  ALL_DEFAULT_EXTS =
121
- "bigdecimal,cgi/escape,continuation,coverage,date,dbm,digest/bubblebabble,digest,digest/md5,digest/rmd160,digest/sha1,digest/sha2,etc,fcntl,fiber,gdbm,json,json/generator,json/parser,nkf,objspace,pathname,psych,racc/cparse,rbconfig/sizeof,ripper,stringio,strscan,monitor,zlib,openssl"
70
+ "cgi/escape,continuation,coverage,date,digest/bubblebabble,digest,digest/md5,digest/rmd160,digest/sha1,digest/sha2,etc,fcntl,json,json/generator,json/parser,objspace,pathname,psych,rbconfig/sizeof,ripper,stringio,strscan,monitor,zlib,openssl"
122
71
 
123
72
  # Retrieves the build options used for building Ruby itself.
124
73
  def build_options
125
74
  default = {
126
- target: "wasm32-unknown-wasi",
127
- src: "3.3",
75
+ target: RubyWasm::Target.new("wasm32-unknown-wasip1"),
128
76
  default_exts: ALL_DEFAULT_EXTS
129
77
  }
130
78
  override = @config || {}
@@ -135,25 +83,14 @@ class RubyWasm::Packager
135
83
  # Retrieves the resolved build options
136
84
  def full_build_options
137
85
  options = build_options
138
- build_dir = File.join(root, "build")
139
- rubies_dir = File.join(root, "rubies")
86
+ build_dir = File.join(@root, "build")
87
+ rubies_dir = File.join(@root, "rubies")
140
88
  toolchain = RubyWasm::Toolchain.get(options[:target], build_dir)
141
- src =
142
- if options[:src].is_a?(Hash)
143
- options[:src]
144
- else
145
- src_name = options[:src]
146
- aliases = self.class.build_source_aliases(root)
147
- aliases[src_name] ||
148
- raise(
149
- "Unknown Ruby source: #{src_name} (available: #{aliases.keys.join(", ")})"
150
- )
151
- end
152
89
  options.merge(
153
90
  toolchain: toolchain,
154
91
  build_dir: build_dir,
155
92
  rubies_dir: rubies_dir,
156
- src: src
93
+ src: options[:src]
157
94
  )
158
95
  end
159
96
  end
@@ -16,6 +16,7 @@ class RubyWasm::BuildTask < ::Rake::TaskLib
16
16
  **options,
17
17
  &block
18
18
  )
19
+ target = Target.new(target)
19
20
  @build =
20
21
  RubyWasm::Build.new(
21
22
  name,
@@ -1,3 +1,3 @@
1
1
  module RubyWasm
2
- VERSION = "2.5.0"
2
+ VERSION = "2.5.1"
3
3
  end
data/lib/ruby_wasm.rb CHANGED
@@ -4,6 +4,7 @@ require_relative "ruby_wasm/version"
4
4
  require_relative "ruby_wasm/util"
5
5
  require_relative "ruby_wasm/build"
6
6
  require_relative "ruby_wasm/packager"
7
+ require_relative "ruby_wasm/packager/component_adapter"
7
8
  require_relative "ruby_wasm/packager/file_system"
8
9
  require_relative "ruby_wasm/packager/core"
9
10