ruby_wasm 2.6.1-x86_64-darwin → 2.7.0-x86_64-darwin

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 03b91bccc370d225e9bb781d00ae39f434e44f225cd2513cac8c9131c01654e0
4
- data.tar.gz: 2c9b9c9071994734a49b268aaa43b08b4ef16be7bd8f99640685f7fd817e10e2
3
+ metadata.gz: 0a009971fbdd7e7ba5fecf2fa83833b570fc15d0c471db7ae6e84248a0386857
4
+ data.tar.gz: d66968df89e5fb5062cd42ad9fa71a45c1397e64e768ba86dafe916ca13ed5f3
5
5
  SHA512:
6
- metadata.gz: 044e4506b6818553a9dc618c0831ae38fc717c10f5bf9c70e0899c178016d11e60f455a801a5442177bd5738555780d9a52e843db0336908387e675f78d69935
7
- data.tar.gz: 8c7dcebeeaa6d37721e0e8aba2539c5ba5d9827334bf792262442d6b434549d2f6e3be52d34ff21799d8393b4d8b5810616b55a85c5275d7e0dd59430f06a4f9
6
+ metadata.gz: 29c2274ba5b0e7eca9ebf3b0b7450aa31209dd407f118f4e61b96b19f8d7e22aa990da6f65d51828bf565de9a2a2c8ddccafd21689303deb09678232192efef5
7
+ data.tar.gz: 2df93b6d257a4fe72e83037d6b1ec7679c338f12abf215dd426be6e8925caffadabb5d4320d5deb2e9e1cb68d0fc012e87aa153a7868fdad296835042b424efd
data/CONTRIBUTING.md CHANGED
@@ -9,8 +9,6 @@ This document describes development setup and pointers for diving into this proj
9
9
  $ git clone https://github.com/ruby/ruby.wasm --recursive
10
10
  $ cd ruby.wasm
11
11
  $ ./bin/setup
12
- # Just for building vendor/jco (will be removed soon)
13
- $ rustup target add wasm32-wasi
14
12
  # Compile extension library
15
13
  $ bundle exec rake compile
16
14
  $ rake --tasks
@@ -26,9 +24,9 @@ $ rake build:download_prebuilt
26
24
  $ rake build:head-wasm32-unknown-wasip1-full
27
25
 
28
26
  # Build npm package
29
- $ rake npm:ruby-head-wasm-wasi
27
+ $ rake npm:ruby-head-wasm-wasip2:build
30
28
  # Test npm package
31
- $ rake npm:ruby-head-wasm-wasi:check
29
+ $ rake npm:ruby-head-wasm-wasip2:check
32
30
  ```
33
31
 
34
32
  If you need to re-build Ruby, please clean `./rubies` directory, and run `rake npm:ruby-head-wasm-wasi` again.
@@ -111,9 +109,13 @@ $ rake 'bump_version[0.6.0]'
111
109
  $ git commit -m"Bump version to 0.6.0"
112
110
  $ git tag 0.6.0
113
111
  $ git push origin 0.6.0
114
- $ for pkg in pkg/ruby_wasm-*; do gem push $pkg; done
112
+ # After GitHub Actions "Build gems" is done
113
+ # https://github.com/ruby/ruby.wasm/actions/workflows/build-gems.yml
114
+ $ gh run download <run-id>
115
+ $ for pkg in cross-gem/pkg/ruby_wasm-*; do gem push $pkg; done
115
116
  $ gem build && gem push ruby_wasm-*.gem && rm ruby_wasm-*.gem
116
117
  $ (cd packages/gems/js/ && gem build && gem push js-*.gem && rm js-*.gem)
118
+ $ rake bump_dev_version
117
119
  ```
118
120
 
119
121
  ## Release Channels
@@ -127,5 +129,5 @@ $ npm install --save @ruby/wasm-wasi@latest
127
129
  # or if you want the nightly snapshot
128
130
  $ npm install --save @ruby/wasm-wasi@next
129
131
  # or you can specify the exact snapshot version
130
- $ npm install --save @ruby/wasm-wasi@2.6.1-2024-05-22-a
132
+ $ npm install --save @ruby/wasm-wasi@2.7.0-2024-11-11-a
131
133
  ```
data/Gemfile CHANGED
@@ -11,7 +11,8 @@ group :development do
11
11
  end
12
12
 
13
13
  group :check do
14
- gem "webrick"
14
+ # Use the latest version of webrick for URI change in Ruby 3.4
15
+ gem "webrick", "~> 1.8.2"
15
16
  gem "syntax_tree", "~> 3.5"
16
17
  gem "steep"
17
18
  end
data/NOTICE CHANGED
@@ -1264,8 +1264,7 @@ Licensed under the Apache License 2.0 https://www.openssl.org/source/license.htm
1264
1264
  https://github.com/kateinoigakukun/wasi-vfs
1265
1265
 
1266
1266
  ```
1267
- Copyright (c) 2022 Yuta Saito. All rights reserved.
1268
- Licensed under the MIT License
1267
+ Licensed under the Apache License v2.0 with LLVM Exceptions
1269
1268
  ```
1270
1269
 
1271
1270
  ---
data/README.md CHANGED
@@ -23,7 +23,7 @@ Create and save `index.html` page with the following contents:
23
23
 
24
24
  ```html
25
25
  <html>
26
- <script src="https://cdn.jsdelivr.net/npm/@ruby/3.3-wasm-wasi@2.6.1/dist/browser.script.iife.js"></script>
26
+ <script src="https://cdn.jsdelivr.net/npm/@ruby/3.3-wasm-wasi@2.7.0/dist/browser.script.iife.js"></script>
27
27
  <script type="text/ruby">
28
28
  require "js"
29
29
 
data/Rakefile CHANGED
@@ -28,20 +28,26 @@ NPM_PACKAGES = [
28
28
  {
29
29
  name: "ruby-head-wasm-wasi",
30
30
  ruby_version: "head",
31
- gemfile: "packages/npm-packages/ruby-wasm-wasi/Gemfile",
31
+ gemfile: "packages/npm-packages/ruby-head-wasm-wasi/Gemfile",
32
32
  target: "wasm32-unknown-wasip1",
33
+ },
34
+ {
35
+ name: "ruby-head-wasm-wasip2",
36
+ ruby_version: "head",
37
+ gemfile: "packages/npm-packages/ruby-head-wasm-wasip2/Gemfile",
38
+ target: "wasm32-unknown-wasip2",
33
39
  enable_component_model: true,
34
40
  },
35
41
  {
36
42
  name: "ruby-3.3-wasm-wasi",
37
43
  ruby_version: "3.3",
38
- gemfile: "packages/npm-packages/ruby-wasm-wasi/Gemfile",
44
+ gemfile: "packages/npm-packages/ruby-3.3-wasm-wasi/Gemfile",
39
45
  target: "wasm32-unknown-wasip1"
40
46
  },
41
47
  {
42
48
  name: "ruby-3.2-wasm-wasi",
43
49
  ruby_version: "3.2",
44
- gemfile: "packages/npm-packages/ruby-wasm-wasi/Gemfile",
50
+ gemfile: "packages/npm-packages/ruby-3.2-wasm-wasi/Gemfile",
45
51
  target: "wasm32-unknown-wasip1"
46
52
  },
47
53
  { name: "ruby-wasm-wasi", target: "wasm32-unknown-wasip1" }
@@ -68,10 +74,11 @@ class BuildTask < Struct.new(:name, :target, :build_command)
68
74
  def ruby_cache_key
69
75
  return @key if @key
70
76
  require "open3"
77
+ env = { "RUBY_WASM_ROOT" => LIB_ROOT }
71
78
  cmd = build_command + ["--print-ruby-cache-key"]
72
- stdout, status = Open3.capture2(*cmd)
79
+ stdout, status = Open3.capture2(env, *cmd)
73
80
  unless status.success?
74
- raise "Command failed with status (#{status.exitstatus}): #{cmd.join ""}"
81
+ raise "Command failed with status (#{status.exitstatus}): #{cmd.join " "}"
75
82
  end
76
83
  require "json"
77
84
  @key = JSON.parse(stdout)
data/docs/api.md CHANGED
@@ -1,2 +1,2 @@
1
1
  - [Ruby API](https://ruby.github.io/ruby.wasm/JS.html)
2
- - [JavaScript API](https://github.com/ruby/ruby.wasm/blob/main/packages/npm-packages/ruby-wasm-wasi/README.md#API)
2
+ - [JavaScript API](https://ruby.github.io/ruby.wasm/npm/@ruby/wasm-wasi/)
data/docs/cheat_sheet.md CHANGED
@@ -38,7 +38,7 @@ The easiest way to run Ruby on browser is to use `browser.script.iife.js` script
38
38
 
39
39
  ```html
40
40
  <html>
41
- <script src="https://cdn.jsdelivr.net/npm/@ruby/3.3-wasm-wasi@2.6.1/dist/browser.script.iife.js"></script>
41
+ <script src="https://cdn.jsdelivr.net/npm/@ruby/3.3-wasm-wasi@2.7.0/dist/browser.script.iife.js"></script>
42
42
  <script type="text/ruby">
43
43
  require "js"
44
44
  JS.global[:document].write "Hello, world!"
@@ -51,8 +51,8 @@ If you want to control Ruby VM from JavaScript, you can use `@ruby/wasm-wasi` pa
51
51
  ```html
52
52
  <html>
53
53
  <script type="module">
54
- import { DefaultRubyVM } from "https://cdn.jsdelivr.net/npm/@ruby/wasm-wasi@2.6.1/dist/browser/+esm";
55
- const response = await fetch("https://cdn.jsdelivr.net/npm/@ruby/3.3-wasm-wasi@2.6.1/dist/ruby+stdlib.wasm");
54
+ import { DefaultRubyVM } from "https://cdn.jsdelivr.net/npm/@ruby/wasm-wasi@2.7.0/dist/browser/+esm";
55
+ const response = await fetch("https://cdn.jsdelivr.net/npm/@ruby/3.3-wasm-wasi@2.7.0/dist/ruby+stdlib.wasm");
56
56
  const module = await WebAssembly.compileStreaming(response);
57
57
  const { vm } = await DefaultRubyVM(module);
58
58
 
@@ -69,11 +69,11 @@ If you want to control Ruby VM from JavaScript, you can use `@ruby/wasm-wasi` pa
69
69
 
70
70
  ```html
71
71
  <html>
72
- <script src="https://cdn.jsdelivr.net/npm/@ruby/wasm-wasi@2.6.1/dist/browser.umd.js"></script>
72
+ <script src="https://cdn.jsdelivr.net/npm/@ruby/wasm-wasi@2.7.0/dist/browser.umd.js"></script>
73
73
  <script>
74
74
  const main = async () => {
75
75
  const { DefaultRubyVM } = window["ruby-wasm-wasi"];
76
- const response = await fetch("https://cdn.jsdelivr.net/npm/@ruby/3.3-wasm-wasi@2.6.1/dist/ruby+stdlib.wasm");
76
+ const response = await fetch("https://cdn.jsdelivr.net/npm/@ruby/3.3-wasm-wasi@2.7.0/dist/ruby+stdlib.wasm");
77
77
  const module = await WebAssembly.compileStreaming(response);
78
78
  const { vm } = await DefaultRubyVM(module);
79
79
 
@@ -128,7 +128,7 @@ end
128
128
 
129
129
  ```html
130
130
  <html>
131
- <script src="https://cdn.jsdelivr.net/npm/@ruby/3.3-wasm-wasi@2.6.1/dist/browser.script.iife.js"></script>
131
+ <script src="https://cdn.jsdelivr.net/npm/@ruby/3.3-wasm-wasi@2.7.0/dist/browser.script.iife.js"></script>
132
132
  <script type="text/ruby" data-eval="async">
133
133
  require "js"
134
134
 
@@ -143,8 +143,8 @@ Or using `@ruby/wasm-wasi` package API `RubyVM#evalAsync`:
143
143
  ```html
144
144
  <html>
145
145
  <script type="module">
146
- import { DefaultRubyVM } from "https://cdn.jsdelivr.net/npm/@ruby/wasm-wasi@2.6.1/dist/browser/+esm";
147
- const response = await fetch("https://cdn.jsdelivr.net/npm/@ruby/3.3-wasm-wasi@2.6.1/dist/ruby+stdlib.wasm");
146
+ import { DefaultRubyVM } from "https://cdn.jsdelivr.net/npm/@ruby/wasm-wasi@2.7.0/dist/browser/+esm";
147
+ const response = await fetch("https://cdn.jsdelivr.net/npm/@ruby/3.3-wasm-wasi@2.7.0/dist/ruby+stdlib.wasm");
148
148
  const module = await WebAssembly.compileStreaming(response);
149
149
  const { vm } = await DefaultRubyVM(module);
150
150
 
Binary file
Binary file
Binary file
@@ -71,16 +71,15 @@ module RubyWasm
71
71
  return
72
72
  end
73
73
  objdir = product_build_dir crossruby
74
- source = crossruby.source
75
- rbconfig_rb = Dir.glob(File.join(crossruby.dest_dir, "usr/local/lib/ruby/*/wasm32-wasi/rbconfig.rb")).first
74
+ rbconfig_rb = crossruby.rbconfig_rb
76
75
  raise "rbconfig.rb not found" unless rbconfig_rb
77
76
  extconf_args = [
78
77
  "-C", objdir,
79
78
  "#{@srcdir}/extconf.rb",
80
79
  "--target-rbconfig=#{rbconfig_rb}",
81
80
  ]
82
- extconf_args << "--enable-component-model" if @features.support_component_model?
83
- executor.system Gem.ruby, *extconf_args
81
+ extconf_args << "--disable-component-model" unless @features.support_component_model?
82
+ executor.system crossruby.baseruby_path, *extconf_args
84
83
  end
85
84
 
86
85
  def do_legacy_extconf(executor, crossruby)
@@ -112,7 +111,7 @@ module RubyWasm
112
111
  "-I#{crossruby.build_dir}",
113
112
  "--",
114
113
  ]
115
- extconf_args << "--enable-component-model" if @features.support_component_model?
114
+ extconf_args << "--disable-component-model" unless @features.support_component_model?
116
115
  # Clear RUBYOPT to avoid loading unrelated bundle setup
117
116
  executor.system crossruby.baseruby_path,
118
117
  *extconf_args,
@@ -223,6 +222,10 @@ module RubyWasm
223
222
  end
224
223
  install_dir = File.join(build_dir, "install")
225
224
  if !File.exist?(install_dir) || remake || reconfigure
225
+ unless target.pic?
226
+ # HACK: force static linking for non-pic target
227
+ executor.rm_f File.join(build_dir, "ruby")
228
+ end
226
229
  executor.system "make",
227
230
  "-j#{executor.process_count}",
228
231
  "install",
@@ -302,6 +305,10 @@ module RubyWasm
302
305
  File.expand_path("../crossruby/extinit.c.erb", __FILE__)
303
306
  end
304
307
 
308
+ def rbconfig_rb
309
+ Dir.glob(File.join(dest_dir, "usr/local/lib/ruby/*/wasm32-wasi/rbconfig.rb")).first
310
+ end
311
+
305
312
  def baseruby_path
306
313
  File.join(@baseruby.install_dir, "bin/ruby")
307
314
  end
@@ -359,6 +366,10 @@ module RubyWasm
359
366
  args << %Q(wasmoptflags=#{@wasmoptflags.join(" ")})
360
367
  end
361
368
  args << "--disable-install-doc"
369
+ unless @params.target.pic?
370
+ # TODO: Remove this hack after dropping Ruby 3.2 support
371
+ args << "ac_cv_func_dlopen=no"
372
+ end
362
373
  args
363
374
  end
364
375
  end
@@ -56,7 +56,7 @@ module RubyWasm
56
56
  def initialize(
57
57
  wasi_sdk_path = ENV["WASI_SDK_PATH"],
58
58
  build_dir: nil,
59
- version_major: 20,
59
+ version_major: 21,
60
60
  version_minor: 0,
61
61
  binaryen_version: 108
62
62
  )
data/lib/ruby_wasm/cli.rb CHANGED
@@ -216,7 +216,9 @@ module RubyWasm
216
216
  local_source = { type: "local", path: src_name }
217
217
  # @type var local_source: RubyWasm::Packager::build_source
218
218
  local_source = local_source.merge(name: "local", patches: [])
219
- return [local_source, nil]
219
+ # FIXME: We should have a way to specify extensions to be included by users.
220
+ # For now, assume all default extensions available in the head revision are available.
221
+ return [local_source, RubyWasm::Packager::ALL_DEFAULT_EXTS]
220
222
  end
221
223
  # Otherwise, it's an unknown source.
222
224
  raise(
@@ -242,7 +244,7 @@ module RubyWasm
242
244
  },
243
245
  "3.3" => {
244
246
  type: "tarball",
245
- url: "https://cache.ruby-lang.org/pub/ruby/3.3/ruby-3.3.1.tar.gz",
247
+ url: "https://cache.ruby-lang.org/pub/ruby/3.3/ruby-3.3.3.tar.gz",
246
248
  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",
247
249
  },
248
250
  "3.2" => {
@@ -308,7 +310,10 @@ module RubyWasm
308
310
 
309
311
  def derive_packager(options)
310
312
  __skip__ = definition = nil
311
- __skip__ = if defined?(Bundler) && !options[:disable_gems]
313
+ features = RubyWasm::FeatureSet.derive_from_env
314
+ # The head ruby & dynamic linking uses "bundle" command to build gems instead of in-process integration.
315
+ use_in_process_gem_building = !(options[:ruby_version] == "head" && features.support_dynamic_linking?)
316
+ __skip__ = if defined?(Bundler) && !options[:disable_gems] && use_in_process_gem_building
312
317
  begin
313
318
  # Silence Bundler UI if --print-ruby-cache-key is specified not to bother the JSON output.
314
319
  level = options[:print_ruby_cache_key] ? :silent : Bundler.ui.level
@@ -319,10 +324,10 @@ module RubyWasm
319
324
  Bundler.ui.level = old_level
320
325
  end
321
326
  end
322
- RubyWasm.logger.info "Using Gemfile: #{definition.gemfiles}" if definition
327
+ RubyWasm.logger.info "Using Gemfile: #{definition.gemfiles.map(&:to_s).join(", ")}" if definition
323
328
  RubyWasm::Packager.new(
324
329
  root, build_config(options), definition,
325
- features: RubyWasm::FeatureSet.derive_from_env
330
+ features: features,
326
331
  )
327
332
  end
328
333
 
@@ -330,6 +335,9 @@ module RubyWasm
330
335
  ruby_core_build = packager.ruby_core_build
331
336
  require "digest"
332
337
  digest = Digest::SHA256.new
338
+ # The build system key is used to invalidate the cache when the build system is updated.
339
+ build_system_key = 1
340
+ digest.update(build_system_key.to_s)
333
341
  ruby_core_build.cache_key(digest)
334
342
  hexdigest = digest.hexdigest
335
343
  require "json"
@@ -1,4 +1,5 @@
1
1
  require "forwardable"
2
+ require "pathname"
2
3
 
3
4
  class RubyWasm::Packager::Core
4
5
  def initialize(packager)
@@ -19,7 +20,6 @@ class RubyWasm::Packager::Core
19
20
  def build_strategy
20
21
  @build_strategy ||=
21
22
  begin
22
- has_exts = @packager.specs.any? { |spec| spec.extensions.any? }
23
23
  if @packager.features.support_dynamic_linking?
24
24
  DynamicLinking.new(@packager)
25
25
  else
@@ -59,12 +59,12 @@ class RubyWasm::Packager::Core
59
59
  end
60
60
  end
61
61
 
62
- def wasi_exec_model
63
- # TODO: Detect WASI exec-model from binary exports (_start or _initialize)
64
- use_js_gem = @packager.specs.any? do |spec|
65
- spec.name == "js"
62
+ def with_unbundled_env(&block)
63
+ __skip__ = if defined?(Bundler)
64
+ Bundler.with_unbundled_env(&block)
65
+ else
66
+ block.call
66
67
  end
67
- use_js_gem ? "reactor" : "command"
68
68
  end
69
69
 
70
70
  def cache_key(digest)
@@ -87,27 +87,22 @@ class RubyWasm::Packager::Core
87
87
  end
88
88
  build.crossruby.clean(executor) if options[:clean]
89
89
 
90
- do_build =
91
- proc do
92
- build.crossruby.build(
93
- executor,
94
- remake: options[:remake],
95
- reconfigure: options[:reconfigure]
96
- )
97
- end
90
+ self.with_unbundled_env do
91
+ build.crossruby.build(
92
+ executor,
93
+ remake: options[:remake],
94
+ reconfigure: options[:reconfigure]
95
+ )
96
+ end
98
97
 
99
- __skip__ =
100
- if defined?(Bundler)
101
- Bundler.with_unbundled_env(&do_build)
102
- else
103
- do_build.call
104
- end
105
98
  build.crossruby.artifact
106
99
  end
107
100
 
108
101
  def build_gem_exts(executor, gem_home)
109
102
  build = derive_build
110
- self._build_gem_exts(executor, build, gem_home)
103
+ self.with_unbundled_env do
104
+ self._build_gem_exts(executor, build, gem_home)
105
+ end
111
106
  end
112
107
 
113
108
  def link_gem_exts(executor, ruby_root, gem_home, module_bytes)
@@ -135,12 +130,16 @@ class RubyWasm::Packager::Core
135
130
  wasi_sdk_path = toolchain.wasi_sdk_path
136
131
  libraries << File.join(wasi_sdk_path, "share/wasi-sysroot/lib/wasm32-wasi", lib)
137
132
  end
138
- wasi_adapter = RubyWasm::Packager::ComponentAdapter.wasi_snapshot_preview1(wasi_exec_model)
139
- adapters = [wasi_adapter]
140
133
  dl_openable_libs = []
141
134
  dl_openable_libs << [File.dirname(ruby_root), Dir.glob(File.join(ruby_root, "lib", "ruby", "**", "*.so"))]
142
135
  dl_openable_libs << [gem_home, Dir.glob(File.join(gem_home, "**", "*.so"))]
143
136
 
137
+ has_js_so = dl_openable_libs.any? do |root, libs|
138
+ libs.any? { |lib| lib.end_with?("/js.so") }
139
+ end
140
+ wasi_adapter = RubyWasm::Packager::ComponentAdapter.wasi_snapshot_preview1(has_js_so ? "reactor" : "command")
141
+ adapters = [wasi_adapter]
142
+
144
143
  linker = RubyWasmExt::ComponentLink.new
145
144
  linker.use_built_in_libdl(true)
146
145
  linker.stub_missing_functions(false)
@@ -148,11 +147,13 @@ class RubyWasm::Packager::Core
148
147
 
149
148
  linker.library("ruby", module_bytes, false)
150
149
 
150
+ RubyWasm.logger.info "Linking Ruby with extensions"
151
+
151
152
  libraries.each do |lib|
152
153
  # Non-DL openable libraries should be referenced as base name
153
154
  lib_name = File.basename(lib)
154
155
  module_bytes = File.binread(lib)
155
- RubyWasm.logger.info "Linking #{lib_name} (#{module_bytes.size} bytes)"
156
+ RubyWasm.logger.debug "Linking #{lib_name} (#{module_bytes.size} bytes)"
156
157
  linker.library(lib_name, module_bytes, false)
157
158
  end
158
159
 
@@ -161,7 +162,7 @@ class RubyWasm::Packager::Core
161
162
  # DL openable lib_name should be a relative path from ruby_root
162
163
  lib_name = "/" + Pathname.new(lib).relative_path_from(Pathname.new(File.dirname(root))).to_s
163
164
  module_bytes = File.binread(lib)
164
- RubyWasm.logger.info "Linking #{lib_name} (#{module_bytes.size} bytes)"
165
+ RubyWasm.logger.debug "Linking #{lib_name} (#{module_bytes.size} bytes)"
165
166
  linker.library(lib_name, module_bytes, true)
166
167
  end
167
168
  end
@@ -171,38 +172,56 @@ class RubyWasm::Packager::Core
171
172
  # e.g. wasi_snapshot_preview1.command.wasm -> wasi_snapshot_preview1
172
173
  adapter_name = adapter_name.split(".")[0]
173
174
  module_bytes = File.binread(adapter)
174
- RubyWasm.logger.info "Linking adapter #{adapter_name}=#{adapter} (#{module_bytes.size} bytes)"
175
+ RubyWasm.logger.debug "Linking adapter #{adapter_name}=#{adapter} (#{module_bytes.size} bytes)"
175
176
  linker.adapter(adapter_name, module_bytes)
176
177
  end
177
178
  return linker.encode()
178
179
  end
179
180
 
180
181
  def _build_gem_exts(executor, build, gem_home)
181
- exts = specs_with_extensions.flat_map do |spec, exts|
182
- exts.map do |ext|
183
- ext_feature = File.dirname(ext) # e.g. "ext/cgi/escape"
184
- ext_srcdir = File.join(spec.full_gem_path, ext_feature)
185
- ext_relative_path = File.join(spec.full_name, ext_feature)
186
- prod = RubyWasm::CrossRubyExtProduct.new(
187
- ext_srcdir,
188
- build.toolchain,
189
- features: @packager.features,
190
- ext_relative_path: ext_relative_path
191
- )
192
- [prod, spec]
193
- end
182
+ build.toolchain.install
183
+ baseruby = build.baseruby
184
+ unless Dir.exist?(baseruby.install_dir)
185
+ baseruby.build(executor)
194
186
  end
195
187
 
196
- exts.each do |prod, spec|
197
- libdir = File.join(gem_home, "gems", spec.full_name, spec.raw_require_paths.first)
198
- extra_mkargs = [
199
- "sitearchdir=#{libdir}",
200
- "sitelibdir=#{libdir}",
201
- ]
202
- executor.begin_section prod.class, prod.name, "Building"
203
- prod.build(executor, build.crossruby, extra_mkargs)
204
- executor.end_section prod.class, prod.name
205
- end
188
+ crossruby = build.crossruby
189
+ rbconfig_rb = crossruby.rbconfig_rb
190
+
191
+ options = @packager.full_build_options
192
+ target_triplet = options[:target]
193
+
194
+ local_path = File.join("bundle", target_triplet)
195
+ env = {
196
+ "BUNDLE_APP_CONFIG" => File.join(".bundle", target_triplet),
197
+ "BUNDLE_PATH" => local_path,
198
+ "BUNDLE_WITHOUT" => "build",
199
+ # Do not auto-switch bundler version by Gemfile.lock
200
+ "BUNDLE_VERSION" => "system",
201
+ # FIXME: BUNDLE_PATH is set as a installation destination here, but
202
+ # it is also used as a source of gems to be loaded by RubyGems itself.
203
+ # RubyGems loads "psych" gem and if Gemfile includes "psych" gem,
204
+ # RubyGems tries to load "psych" gem from BUNDLE_PATH at the second
205
+ # time of "bundle install" command. But the extension of "psych" gem
206
+ # under BUNDLE_PATH is built for Wasm target, not for host platform,
207
+ # so it fails to load the extension.
208
+ #
209
+ # Thus we preload psych from the default LOAD_PATH here to avoid
210
+ # loading Wasm version of psych.so via `Kernel#require` patched by
211
+ # RubyGems.
212
+ "RUBYOPT" => "-rpsych",
213
+ }
214
+
215
+ args = [
216
+ File.join(baseruby.install_dir, "bin", "bundle"),
217
+ "install",
218
+ "--standalone",
219
+ "--target-rbconfig",
220
+ rbconfig_rb,
221
+ ]
222
+
223
+ executor.system(*args, env: env)
224
+ executor.cp_r(local_path, gem_home)
206
225
  end
207
226
 
208
227
  def cache_key(digest)
@@ -269,21 +288,14 @@ class RubyWasm::Packager::Core
269
288
  end
270
289
  build.crossruby.clean(executor) if options[:clean]
271
290
 
272
- do_build =
273
- proc do
274
- build.crossruby.build(
275
- executor,
276
- remake: options[:remake],
277
- reconfigure: options[:reconfigure]
278
- )
279
- end
291
+ self.with_unbundled_env do
292
+ build.crossruby.build(
293
+ executor,
294
+ remake: options[:remake],
295
+ reconfigure: options[:reconfigure]
296
+ )
297
+ end
280
298
 
281
- __skip__ =
282
- if defined?(Bundler)
283
- Bundler.with_unbundled_env(&do_build)
284
- else
285
- do_build.call
286
- end
287
299
  build.crossruby.artifact
288
300
  end
289
301
 
@@ -335,6 +347,14 @@ class RubyWasm::Packager::Core
335
347
  # No-op because we already built extensions as part of the Ruby build
336
348
  end
337
349
 
350
+ def wasi_exec_model
351
+ # TODO: Detect WASI exec-model from binary exports (_start or _initialize)
352
+ use_js_gem = @packager.specs.any? do |spec|
353
+ spec.name == "js"
354
+ end
355
+ use_js_gem ? "reactor" : "command"
356
+ end
357
+
338
358
  def link_gem_exts(executor, ruby_root, gem_home, module_bytes)
339
359
  return module_bytes unless @packager.features.support_component_model?
340
360
 
@@ -44,7 +44,6 @@ class RubyWasm::Packager::FileSystem
44
44
  when "enc"
45
45
  # Remove all encodings except for encdb.so and transdb.so
46
46
  enc_dir = File.join(@ruby_root, "lib", "ruby", ruby_version, "wasm32-wasi", "enc")
47
- puts File.join(enc_dir, "**/*.so")
48
47
  Dir.glob(File.join(enc_dir, "**/*.so")).each do |entry|
49
48
  next if entry.end_with?("encdb.so", "transdb.so")
50
49
  RubyWasm.logger.debug "Removing stdlib encoding: #{entry}"
@@ -34,7 +34,7 @@ class RubyWasm::Packager
34
34
 
35
35
  ruby_core.build_gem_exts(executor, fs.bundle_dir)
36
36
 
37
- fs.package_gems
37
+ fs.package_gems unless features.support_component_model?
38
38
  fs.remove_non_runtime_files(executor)
39
39
  if options[:stdlib]
40
40
  options[:without_stdlib_components].each do |component|
@@ -44,7 +44,7 @@ class RubyWasm::Packager
44
44
  fs.remove_stdlib(executor)
45
45
  end
46
46
 
47
- if full_build_options[:target] == "wasm32-unknown-wasip1" && !features.support_dynamic_linking?
47
+ if full_build_options[:target] == "wasm32-unknown-wasip1" && !features.support_component_model?
48
48
  # wasi-vfs supports only WASI target
49
49
  wasi_vfs = RubyWasmExt::WasiVfs.new
50
50
  wasi_vfs.map_dir("/bundle", fs.bundle_dir)
@@ -54,6 +54,20 @@ class RubyWasm::Packager
54
54
  end
55
55
  wasm_bytes = ruby_core.link_gem_exts(executor, fs.ruby_root, fs.bundle_dir, wasm_bytes)
56
56
 
57
+ if features.support_component_model?
58
+ wasi_virt = RubyWasmExt::WasiVirt.new
59
+ wasi_virt.allow_all
60
+ [
61
+ { guest: "/bundle", host: fs.bundle_dir },
62
+ { guest: "/usr", host: File.dirname(fs.ruby_root) }
63
+ ].each do |map|
64
+ map => { guest:, host: }
65
+ RubyWasm.logger.debug "Adding files into VFS: #{host} => #{guest}"
66
+ wasi_virt.map_dir(guest, host)
67
+ end
68
+ wasm_bytes = wasi_virt.compose(wasm_bytes)
69
+ end
70
+
57
71
  wasm_bytes = RubyWasmExt.preinitialize(wasm_bytes) if options[:optimize]
58
72
  wasm_bytes
59
73
  end
@@ -68,8 +82,9 @@ class RubyWasm::Packager
68
82
  # Retrieves the specs from the Bundler definition, excluding the excluded gems.
69
83
  def specs
70
84
  return [] unless @definition
71
- @specs ||= @definition.resolve.materialize(@definition.requested_dependencies)
85
+ __skip__ = @specs ||= @definition.resolve.materialize(@definition.requested_dependencies)
72
86
  .reject { |spec| EXCLUDED_GEMS.include?(spec.name) }
87
+ .reject { |spec| spec.is_a?(Bundler::LazySpecification) }
73
88
  @specs
74
89
  end
75
90
 
@@ -1,3 +1,3 @@
1
1
  module RubyWasm
2
- VERSION = "2.6.1"
2
+ VERSION = "2.7.0"
3
3
  end