ruby_wasm 2.5.0-x86_64-linux-musl → 2.5.2-x86_64-linux-musl

Sign up to get free protection for your applications and to get access to all the features.
Files changed (47) hide show
  1. checksums.yaml +4 -4
  2. data/CONTRIBUTING.md +9 -7
  3. data/Gemfile +1 -1
  4. data/README.md +12 -11
  5. data/Rakefile +9 -7
  6. data/docs/cheat_sheet.md +8 -8
  7. data/lib/ruby_wasm/3.1/ruby_wasm.so +0 -0
  8. data/lib/ruby_wasm/3.2/ruby_wasm.so +0 -0
  9. data/lib/ruby_wasm/{3.0 → 3.3}/ruby_wasm.so +0 -0
  10. data/lib/ruby_wasm/build/executor.rb +4 -0
  11. data/lib/ruby_wasm/build/product/crossruby.rb +59 -25
  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/wit_bindgen.rb +2 -2
  20. data/lib/ruby_wasm/build/toolchain.rb +1 -1
  21. data/lib/ruby_wasm/build.rb +7 -3
  22. data/lib/ruby_wasm/cli.rb +147 -11
  23. data/lib/ruby_wasm/feature_set.rb +30 -0
  24. data/lib/ruby_wasm/packager/component_adapter/wasi_snapshot_preview1.command.wasm +0 -0
  25. data/lib/ruby_wasm/packager/component_adapter/wasi_snapshot_preview1.reactor.wasm +0 -0
  26. data/lib/ruby_wasm/packager/component_adapter.rb +14 -0
  27. data/lib/ruby_wasm/packager/core.rb +199 -5
  28. data/lib/ruby_wasm/packager/file_system.rb +5 -3
  29. data/lib/ruby_wasm/packager.rb +22 -82
  30. data/lib/ruby_wasm/rake_task.rb +1 -0
  31. data/lib/ruby_wasm/version.rb +1 -1
  32. data/lib/ruby_wasm.rb +2 -0
  33. data/package-lock.json +5571 -7015
  34. data/package.json +3 -3
  35. data/rakelib/check.rake +23 -10
  36. data/rakelib/ci.rake +3 -3
  37. data/rakelib/packaging.rake +44 -15
  38. data/sig/ruby_wasm/build.rbs +38 -28
  39. data/sig/ruby_wasm/cli.rbs +27 -3
  40. data/sig/ruby_wasm/ext.rbs +25 -2
  41. data/sig/ruby_wasm/feature_set.rbs +12 -0
  42. data/sig/ruby_wasm/packager.rbs +44 -7
  43. metadata +12 -10
  44. data/builders/wasm32-unknown-emscripten/Dockerfile +0 -43
  45. data/builders/wasm32-unknown-emscripten/entrypoint.sh +0 -7
  46. data/builders/wasm32-unknown-wasi/Dockerfile +0 -47
  47. data/builders/wasm32-unknown-wasi/entrypoint.sh +0 -7
@@ -2,6 +2,7 @@ require_relative "build/build_params"
2
2
  require_relative "build/product"
3
3
  require_relative "build/toolchain"
4
4
  require_relative "build/executor"
5
+ require_relative "build/target"
5
6
 
6
7
  class RubyWasm::Build
7
8
  # Source to build from.
@@ -36,6 +37,7 @@ class RubyWasm::Build
36
37
  toolchain:,
37
38
  build_dir:,
38
39
  rubies_dir:,
40
+ wasi_vfs: :default,
39
41
  **options
40
42
  )
41
43
  @target = target
@@ -45,7 +47,7 @@ class RubyWasm::Build
45
47
 
46
48
  @libyaml = RubyWasm::LibYAMLProduct.new(@build_dir, @target, @toolchain)
47
49
  @zlib = RubyWasm::ZlibProduct.new(@build_dir, @target, @toolchain)
48
- @wasi_vfs = RubyWasm::WasiVfsProduct.new(@build_dir)
50
+ @wasi_vfs = wasi_vfs == :default ? RubyWasm::WasiVfsProduct.new(@build_dir) : wasi_vfs
49
51
  @source = RubyWasm::BuildSource.new(src, @build_dir)
50
52
  @baseruby = RubyWasm::BaseRubyProduct.new(@build_dir, @source)
51
53
  @openssl = RubyWasm::OpenSSLProduct.new(@build_dir, @target, @toolchain)
@@ -78,11 +80,13 @@ class RubyWasm::Build
78
80
  @crossruby.cache_key(digest)
79
81
  digest << @build_dir
80
82
  digest << @rubies_dir
81
- digest << @target
83
+ @target.cache_key(digest)
82
84
  digest << @toolchain.name
83
85
  digest << @libyaml.name
84
86
  digest << @zlib.name
85
87
  digest << @openssl.name
86
- digest << @wasi_vfs.name
88
+ if wasi_vfs = @wasi_vfs
89
+ digest << wasi_vfs.name
90
+ end
87
91
  end
88
92
  end
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,12 @@ module RubyWasm
152
169
  private
153
170
 
154
171
  def build_config(options)
155
- config = { target: options[:target_triplet], src: options[:ruby_version] }
172
+ build_source, all_default_exts = compute_build_source(options)
173
+ # @type var config: Packager::build_config
174
+ config = { target: options[:target_triplet], src: build_source }
156
175
  case options[:profile]
157
176
  when "full"
158
- config[:default_exts] = RubyWasm::Packager::ALL_DEFAULT_EXTS
177
+ config[:default_exts] = all_default_exts || ""
159
178
  env_additional_exts = ENV["RUBY_WASM_ADDITIONAL_EXTS"] || ""
160
179
  unless env_additional_exts.empty?
161
180
  config[:default_exts] += "," + env_additional_exts
@@ -170,12 +189,129 @@ module RubyWasm
170
189
  config
171
190
  end
172
191
 
173
- def derive_packager(options)
192
+ def compute_build_source(options)
193
+ src_name = options[:ruby_version]
194
+ aliases = self.class.build_source_aliases(root)
195
+ source = aliases[src_name]
196
+ if source.nil?
197
+ if File.directory?(src_name)
198
+ # Treat as a local source if the given name is a source directory.
199
+ RubyWasm.logger.debug "Using local source: #{src_name}"
200
+ if options[:patches].any?
201
+ RubyWasm.logger.warn "Patches specified through --patch are ignored for local sources"
202
+ end
203
+ # @type var local_source: RubyWasm::Packager::build_source_local
204
+ local_source = { type: "local", path: src_name }
205
+ # @type var local_source: RubyWasm::Packager::build_source
206
+ local_source = local_source.merge(name: "local", patches: [])
207
+ return [local_source, nil]
208
+ end
209
+ # Otherwise, it's an unknown source.
210
+ raise(
211
+ "Unknown Ruby source: #{src_name} (available: #{aliases.keys.join(", ")} or a local directory)"
212
+ )
213
+ end
214
+ # Apply user-specified patches in addition to bundled patches.
215
+ source[:patches].concat(options[:patches])
216
+ # @type var all_default_exts: String
217
+ __skip__ = all_default_exts = source[:all_default_exts]
218
+ [source, all_default_exts]
219
+ end
220
+
221
+ # Retrieves the alias definitions for the Ruby sources.
222
+ def self.build_source_aliases(root)
223
+ # @type var sources: Hash[string, RubyWasm::Packager::build_source]
224
+ sources = {
225
+ "head" => {
226
+ type: "github",
227
+ repo: "ruby/ruby",
228
+ rev: "master",
229
+ all_default_exts: RubyWasm::Packager::ALL_DEFAULT_EXTS,
230
+ },
231
+ "3.3" => {
232
+ type: "tarball",
233
+ url: "https://cache.ruby-lang.org/pub/ruby/3.3/ruby-3.3.1.tar.gz",
234
+ 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",
235
+ },
236
+ "3.2" => {
237
+ type: "tarball",
238
+ url: "https://cache.ruby-lang.org/pub/ruby/3.2/ruby-3.2.4.tar.gz",
239
+ 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",
240
+ }
241
+ }
242
+
243
+ # Apply bundled and user-specified `<root>/patches` directories.
244
+ sources.each do |name, source|
245
+ source[:name] = name
246
+ patches_dirs = [bundled_patches_path, File.join(root, "patches")]
247
+ source[:patches] = patches_dirs.flat_map do |patches_dir|
248
+ Dir[File.join(patches_dir, name, "*.patch")]
249
+ .map { |p| File.expand_path(p) }
250
+ end
251
+ end
252
+
253
+ build_manifest = File.join(root, "build_manifest.json")
254
+ if File.exist?(build_manifest)
255
+ begin
256
+ manifest = JSON.parse(File.read(build_manifest))
257
+ manifest["ruby_revisions"].each do |name, rev|
258
+ source = sources[name]
259
+ next unless source[:type] == "github"
260
+ # @type var source: RubyWasm::Packager::build_source_github
261
+ source[:rev] = rev
262
+ end
263
+ rescue StandardError => e
264
+ RubyWasm.logger.warn "Failed to load build_manifest.json: #{e}"
265
+ end
266
+ end
267
+ sources
268
+ end
269
+
270
+ # Retrieves the root directory of the Ruby project.
271
+ def root
174
272
  __skip__ =
175
- if defined?(Bundler) && !options[:disable_gems]
273
+ @root ||=
274
+ begin
275
+ if explicit = ENV["RUBY_WASM_ROOT"]
276
+ File.expand_path(explicit)
277
+ elsif defined?(Bundler)
278
+ Bundler.root
279
+ else
280
+ Dir.pwd
281
+ end
282
+ rescue Bundler::GemfileNotFound
283
+ Dir.pwd
284
+ end
285
+ end
286
+
287
+ # Path to the directory containing the bundled patches, which is shipped
288
+ # as part of ruby_wasm gem to backport fixes or try experimental features
289
+ # before landing them to the ruby/ruby repository.
290
+ def self.bundled_patches_path
291
+ dir = __dir__
292
+ raise "Unexpected directory structure, no __dir__!??" unless dir
293
+ lib_source_root = File.join(dir, "..", "..")
294
+ File.join(lib_source_root, "patches")
295
+ end
296
+
297
+ def derive_packager(options)
298
+ __skip__ = definition = nil
299
+ __skip__ = if defined?(Bundler) && !options[:disable_gems]
300
+ begin
301
+ # Silence Bundler UI if --print-ruby-cache-key is specified not to bother the JSON output.
302
+ level = options[:print_ruby_cache_key] ? :silent : Bundler.ui.level
303
+ old_level = Bundler.ui.level
304
+ Bundler.ui.level = level
176
305
  definition = Bundler.definition
306
+ ensure
307
+ Bundler.ui.level = old_level
177
308
  end
178
- RubyWasm::Packager.new(build_config(options), definition)
309
+ end
310
+ RubyWasm.logger.info "Using Gemfile: #{definition.gemfiles}" if definition
311
+ RubyWasm::Packager.new(
312
+ root, build_config(options), definition,
313
+ features: RubyWasm::FeatureSet.derive_from_env
314
+ )
179
315
  end
180
316
 
181
317
  def do_print_ruby_cache_key(packager)
@@ -197,9 +333,9 @@ module RubyWasm
197
333
  RubyWasm.logger.info "Size: #{SizeFormatter.format(wasm_bytes.size)}"
198
334
  case options[:output]
199
335
  when "-"
200
- @stdout.write wasm_bytes.pack("C*")
336
+ @stdout.write wasm_bytes
201
337
  else
202
- File.binwrite(options[:output], wasm_bytes.pack("C*"))
338
+ File.binwrite(options[:output], wasm_bytes)
203
339
  RubyWasm.logger.debug "Wrote #{options[:output]}"
204
340
  end
205
341
  end
@@ -0,0 +1,30 @@
1
+ ##
2
+ # A set of feature flags that can be used to enable or disable experimental features.
3
+ class RubyWasm::FeatureSet
4
+ def initialize(features)
5
+ @features = features
6
+ end
7
+
8
+ # Maps the feature to the environment variable.
9
+ FEATURES = {
10
+ dynamic_linking: "RUBY_WASM_EXPERIMENTAL_DYNAMIC_LINKING",
11
+ component_model: "RUBY_WASM_EXPERIMENTAL_COMPONENT_MODEL",
12
+ }.freeze
13
+ private_constant :FEATURES
14
+
15
+ # Derives the feature set from the environment variables. A feature
16
+ # is enabled if the corresponding environment variable is set to "1",
17
+ # otherwise it is disabled.
18
+ def self.derive_from_env
19
+ values = FEATURES.transform_values { |key| ENV[key] == "1" }
20
+ new(values)
21
+ end
22
+
23
+ def support_dynamic_linking?
24
+ @features[:dynamic_linking]
25
+ end
26
+
27
+ def support_component_model?
28
+ @features[:component_model] || @features[:dynamic_linking]
29
+ end
30
+ 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
 
@@ -20,7 +20,7 @@ class RubyWasm::Packager::Core
20
20
  @build_strategy ||=
21
21
  begin
22
22
  has_exts = @packager.specs.any? { |spec| spec.extensions.any? }
23
- if @packager.support_dynamic_linking?
23
+ if @packager.features.support_dynamic_linking?
24
24
  DynamicLinking.new(@packager)
25
25
  else
26
26
  StaticLinking.new(@packager)
@@ -37,6 +37,10 @@ class RubyWasm::Packager::Core
37
37
  raise NotImplementedError
38
38
  end
39
39
 
40
+ def build_and_link_exts(executor, module_bytes)
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,168 @@ 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, module_bytes)
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
+ features: @packager.features,
166
+ ext_relative_path: ext_relative_path
167
+ )
168
+ end
169
+ end
170
+
171
+ exts.each do |prod|
172
+ executor.begin_section prod.class, prod.name, "Building"
173
+ prod.build(executor, build.crossruby)
174
+ executor.end_section prod.class, prod.name
175
+ end
176
+ end
177
+
178
+ def cache_key(digest)
179
+ derive_build.cache_key(digest)
180
+ end
181
+
182
+ def artifact
183
+ derive_build.crossruby.artifact
184
+ end
185
+
186
+ def target
187
+ RubyWasm::Target.new(@packager.full_build_options[:target], pic: true)
188
+ end
189
+
190
+ def derive_build
191
+ return @build if @build
192
+ __skip__ =
193
+ build ||= RubyWasm::Build.new(
194
+ name, **@packager.full_build_options,
195
+ target: target,
196
+ # NOTE: We don't need linking libwasi_vfs because we use wasi-virt instead.
197
+ wasi_vfs: nil
198
+ )
199
+ build.crossruby.cflags = %w[-fPIC -fvisibility=default]
200
+ if @packager.full_build_options[:target] != "wasm32-unknown-emscripten"
201
+ build.crossruby.debugflags = %w[-g]
202
+ build.crossruby.wasmoptflags = %w[-O3 -g --pass-arg=asyncify-relocatable]
203
+ build.crossruby.ldflags = %w[
204
+ -Xlinker
205
+ --stack-first
206
+ -Xlinker
207
+ -z
208
+ -Xlinker
209
+ stack-size=16777216
210
+ ]
211
+ build.crossruby.xldflags = %w[
212
+ -Xlinker -shared
213
+ -Xlinker --export-dynamic
214
+ -Xlinker --export-all
215
+ -Xlinker --experimental-pic
216
+ -Xlinker -export-if-defined=__main_argc_argv
217
+ ]
218
+ end
219
+ @build = build
220
+ build
221
+ end
222
+
223
+ def name
224
+ require "digest"
225
+ options = @packager.full_build_options
226
+ src_channel = options[:src][:name]
227
+ target_triplet = options[:target]
228
+ "ruby-#{src_channel}-#{target_triplet}-pic#{options[:suffix]}"
229
+ end
64
230
  end
65
231
 
66
232
  class StaticLinking < BuildStrategy
@@ -93,16 +259,24 @@ class RubyWasm::Packager::Core
93
259
 
94
260
  def cache_key(digest)
95
261
  derive_build.cache_key(digest)
262
+ if enabled = @packager.features.support_component_model?
263
+ digest << enabled.to_s
264
+ end
96
265
  end
97
266
 
98
267
  def artifact
99
268
  derive_build.crossruby.artifact
100
269
  end
101
270
 
271
+ def target
272
+ RubyWasm::Target.new(@packager.full_build_options[:target])
273
+ end
274
+
102
275
  def derive_build
103
276
  return @build if @build
104
- __skip__ =
105
- build ||= RubyWasm::Build.new(name, **@packager.full_build_options)
277
+ __skip__ = build ||= RubyWasm::Build.new(
278
+ name, **@packager.full_build_options, target: target,
279
+ )
106
280
  build.crossruby.user_exts = user_exts(build)
107
281
  # Emscripten uses --global-base=1024 by default, but it conflicts with
108
282
  # --stack-first and -z stack-size since global-base 1024 is smaller than
@@ -111,7 +285,9 @@ class RubyWasm::Packager::Core
111
285
  # script of Ruby.
112
286
  if @packager.full_build_options[:target] != "wasm32-unknown-emscripten"
113
287
  build.crossruby.debugflags = %w[-g]
114
- build.crossruby.wasmoptflags = %w[-O3 -g]
288
+ # We assume that imported functions provided through WASI will not change
289
+ # asyncify state, so we ignore them.
290
+ build.crossruby.wasmoptflags = %w[-O3 -g --pass-arg=asyncify-ignore-imports]
115
291
  build.crossruby.ldflags = %w[
116
292
  -Xlinker
117
293
  --stack-first
@@ -125,6 +301,20 @@ class RubyWasm::Packager::Core
125
301
  build
126
302
  end
127
303
 
304
+ def build_and_link_exts(executor, module_bytes)
305
+ return module_bytes unless @packager.features.support_component_model?
306
+
307
+ linker = RubyWasmExt::ComponentEncode.new
308
+ linker.validate(true)
309
+ linker.module(module_bytes)
310
+ linker.adapter(
311
+ "wasi_snapshot_preview1",
312
+ File.binread(RubyWasm::Packager::ComponentAdapter.wasi_snapshot_preview1("reactor"))
313
+ )
314
+
315
+ linker.encode()
316
+ end
317
+
128
318
  def user_exts(build)
129
319
  @user_exts ||=
130
320
  specs_with_extensions.flat_map do |spec, exts|
@@ -135,6 +325,7 @@ class RubyWasm::Packager::Core
135
325
  RubyWasm::CrossRubyExtProduct.new(
136
326
  ext_srcdir,
137
327
  build.toolchain,
328
+ features: @packager.features,
138
329
  ext_relative_path: ext_relative_path
139
330
  )
140
331
  end
@@ -150,6 +341,9 @@ class RubyWasm::Packager::Core
150
341
  exts = specs_with_extensions.sort
151
342
  hash = ::Digest::MD5.new
152
343
  specs_with_extensions.each { |spec, _| hash << spec.full_name }
344
+ if enabled = @packager.features.support_component_model?
345
+ hash << enabled.to_s
346
+ end
153
347
  exts.empty? ? base : "#{base}-#{hash.hexdigest}"
154
348
  end
155
349
  end
@@ -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.features.support_dynamic_linking?
75
+ patterns.each do |pattern|
74
76
  Dir
75
77
  .glob(File.join(@dest_dir, pattern))
76
78
  .each do |entry|