ruby_wasm 2.5.0.pre.1 → 2.5.1

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 (52) hide show
  1. checksums.yaml +4 -4
  2. data/CONTRIBUTING.md +13 -9
  3. data/Cargo.lock +705 -451
  4. data/Gemfile +1 -1
  5. data/README.md +12 -19
  6. data/Rakefile +9 -9
  7. data/benchmarks/vm_deep_call.rb +2 -2
  8. data/docs/cheat_sheet.md +8 -8
  9. data/ext/ruby_wasm/Cargo.toml +6 -5
  10. data/ext/ruby_wasm/src/lib.rs +208 -7
  11. data/lib/ruby_wasm/build/executor.rb +4 -0
  12. data/lib/ruby_wasm/build/product/crossruby.rb +57 -23
  13. data/lib/ruby_wasm/build/product/libyaml.rb +5 -3
  14. data/lib/ruby_wasm/build/product/openssl.rb +7 -2
  15. data/lib/ruby_wasm/build/product/product.rb +3 -3
  16. data/lib/ruby_wasm/build/product/ruby_source.rb +3 -3
  17. data/lib/ruby_wasm/build/product/wasi_vfs.rb +1 -39
  18. data/lib/ruby_wasm/build/product/zlib.rb +5 -3
  19. data/lib/ruby_wasm/build/target.rb +24 -0
  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 +171 -13
  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 +192 -4
  28. data/lib/ruby_wasm/packager/file_system.rb +20 -17
  29. data/lib/ruby_wasm/packager.rb +21 -83
  30. data/lib/ruby_wasm/rake_task.rb +2 -0
  31. data/lib/ruby_wasm/version.rb +1 -1
  32. data/lib/ruby_wasm.rb +2 -0
  33. data/package-lock.json +410 -133
  34. data/package.json +3 -3
  35. data/{tasks → rakelib}/ci.rake +3 -3
  36. data/{tasks → rakelib}/doc.rake +6 -1
  37. data/{tasks → rakelib}/format.rake +3 -2
  38. data/{tasks → rakelib}/gem.rake +4 -1
  39. data/{tasks → rakelib}/packaging.rake +34 -17
  40. data/{tasks → rakelib}/version.rake +2 -0
  41. data/sig/ruby_wasm/build.rbs +36 -31
  42. data/sig/ruby_wasm/cli.rbs +30 -3
  43. data/sig/ruby_wasm/ext.rbs +28 -3
  44. data/sig/ruby_wasm/feature_set.rbs +12 -0
  45. data/sig/ruby_wasm/packager.rbs +44 -7
  46. metadata +16 -15
  47. data/builders/wasm32-unknown-emscripten/Dockerfile +0 -43
  48. data/builders/wasm32-unknown-emscripten/entrypoint.sh +0 -7
  49. data/builders/wasm32-unknown-wasi/Dockerfile +0 -47
  50. data/builders/wasm32-unknown-wasi/entrypoint.sh +0 -7
  51. data/ruby_wasm.gemspec +0 -32
  52. /data/{tasks → rakelib}/check.rake +0 -0
@@ -37,7 +37,6 @@ module RubyWasm
37
37
  make_args << "AR=#{@toolchain.ar}"
38
38
  make_args << "RANLIB=#{@toolchain.ranlib}"
39
39
 
40
- make_args << "DESTDIR=#{crossruby.dest_dir}"
41
40
  make_args
42
41
  end
43
42
 
@@ -45,12 +44,15 @@ module RubyWasm
45
44
  objdir = product_build_dir crossruby
46
45
  executor.mkdir_p objdir
47
46
  do_extconf executor, crossruby
47
+
48
+ executor.system "make", "-C", objdir, *make_args(crossruby), "clean"
49
+ build_target = crossruby.target.pic? ? "install-so" : "static"
48
50
  executor.system "make",
49
51
  "-j#{executor.process_count}",
50
52
  "-C",
51
53
  "#{objdir}",
52
54
  *make_args(crossruby),
53
- "static"
55
+ build_target
54
56
  # A ext can provide link args by link.filelist. It contains only built archive file by default.
55
57
  unless File.exist?(linklist(crossruby))
56
58
  executor.write(
@@ -61,9 +63,27 @@ module RubyWasm
61
63
  end
62
64
 
63
65
  def do_extconf(executor, crossruby)
66
+ unless crossruby.target.pic?
67
+ self.do_legacy_extconf(executor, crossruby)
68
+ return
69
+ end
70
+ objdir = product_build_dir crossruby
71
+ source = crossruby.source
72
+ rbconfig_rb = Dir.glob(File.join(crossruby.dest_dir, "usr/local/lib/ruby/*/wasm32-wasi/rbconfig.rb")).first
73
+ raise "rbconfig.rb not found" unless rbconfig_rb
74
+ extconf_args = [
75
+ "-C", objdir,
76
+ "#{@srcdir}/extconf.rb",
77
+ "--target-rbconfig=#{rbconfig_rb}",
78
+ ]
79
+ executor.system Gem.ruby, *extconf_args
80
+ end
81
+
82
+ def do_legacy_extconf(executor, crossruby)
64
83
  objdir = product_build_dir crossruby
65
84
  source = crossruby.source
66
85
  extconf_args = [
86
+ "-C", objdir,
67
87
  "--disable=gems",
68
88
  # HACK: top_srcdir is required to find ruby headers
69
89
  "-e",
@@ -71,9 +91,6 @@ module RubyWasm
71
91
  # HACK: extout is required to find config.h
72
92
  "-e",
73
93
  %Q($extout="#{crossruby.build_dir}/.ext"),
74
- # HACK: skip have_devel check since ruby is not installed yet
75
- "-e",
76
- "$have_devel = true",
77
94
  # HACK: force static ext build by imitating extmk
78
95
  "-e",
79
96
  "$static = true; trace_var(:$static) {|v| $static = true }",
@@ -93,7 +110,6 @@ module RubyWasm
93
110
  # Clear RUBYOPT to avoid loading unrelated bundle setup
94
111
  executor.system crossruby.baseruby_path,
95
112
  *extconf_args,
96
- chdir: objdir,
97
113
  env: {
98
114
  "RUBYOPT" => ""
99
115
  }
@@ -118,7 +134,7 @@ module RubyWasm
118
134
  end
119
135
 
120
136
  class CrossRubyProduct < AutoconfProduct
121
- attr_reader :source, :toolchain
137
+ attr_reader :target, :source, :toolchain
122
138
  attr_accessor :user_exts,
123
139
  :wasmoptflags,
124
140
  :cppflags,
@@ -155,6 +171,14 @@ module RubyWasm
155
171
  executor.system "make", "rbconfig.rb", chdir: build_dir
156
172
  end
157
173
 
174
+ def need_exts_build?
175
+ @user_exts.any?
176
+ end
177
+
178
+ def need_extinit_obj?
179
+ need_exts_build? && !@target.pic?
180
+ end
181
+
158
182
  def build_exts(executor)
159
183
  @user_exts.each do |prod|
160
184
  executor.begin_section prod.class, prod.name, "Building"
@@ -168,6 +192,7 @@ module RubyWasm
168
192
  executor.mkdir_p build_dir
169
193
  @toolchain.install
170
194
  [@source, @baseruby, @libyaml, @zlib, @openssl, @wasi_vfs].each do |prod|
195
+ next unless prod
171
196
  executor.begin_section prod.class, prod.name, "Building"
172
197
  prod.build(executor)
173
198
  executor.end_section prod.class, prod.name
@@ -176,17 +201,20 @@ module RubyWasm
176
201
  configure(executor, reconfigure: reconfigure)
177
202
  executor.end_section self.class, name
178
203
 
179
- build_exts(executor)
204
+ build_exts(executor) if need_exts_build?
180
205
 
181
206
  executor.begin_section self.class, name, "Building"
182
- executor.mkdir_p File.dirname(extinit_obj)
183
- executor.system "ruby",
184
- extinit_c_erb,
185
- *@user_exts.map { |ext| ext.feature_name(self) },
186
- "--cc",
187
- toolchain.cc,
188
- "--output",
189
- extinit_obj
207
+
208
+ if need_extinit_obj?
209
+ executor.mkdir_p File.dirname(extinit_obj)
210
+ executor.system "ruby",
211
+ extinit_c_erb,
212
+ *@user_exts.map { |ext| ext.feature_name(self) },
213
+ "--cc",
214
+ toolchain.cc,
215
+ "--output",
216
+ extinit_obj
217
+ end
190
218
  install_dir = File.join(build_dir, "install")
191
219
  if !File.exist?(install_dir) || remake || reconfigure
192
220
  executor.system "make",
@@ -216,7 +244,7 @@ module RubyWasm
216
244
  end
217
245
 
218
246
  def cache_key(digest)
219
- digest << @params.target
247
+ @params.target.cache_key(digest)
220
248
  digest << @params.default_exts
221
249
  @wasmoptflags.each { |f| digest << f }
222
250
  @cppflags.each { |f| digest << f }
@@ -229,11 +257,11 @@ module RubyWasm
229
257
  end
230
258
 
231
259
  def build_dir
232
- File.join(@build_dir, @params.target, name)
260
+ File.join(@build_dir, @params.target.to_s, name)
233
261
  end
234
262
 
235
263
  def ext_build_dir
236
- File.join(@build_dir, @params.target, name + "-ext")
264
+ File.join(@build_dir, @params.target.to_s, name + "-ext")
237
265
  end
238
266
 
239
267
  def with_libyaml(libyaml)
@@ -274,14 +302,14 @@ module RubyWasm
274
302
  end
275
303
 
276
304
  def configure_args(build_triple, toolchain)
277
- target = @params.target
305
+ target = @params.target.triple
278
306
  default_exts = @params.default_exts
279
307
 
280
308
  ldflags = @ldflags.dup
281
309
  xldflags = @xldflags.dup
282
310
 
283
311
  args = self.system_triplet_args + ["--build", build_triple]
284
- args << "--with-static-linked-ext"
312
+ args << "--with-static-linked-ext" unless @params.target.pic?
285
313
  args << %Q(--with-ext=#{default_exts})
286
314
  args << %Q(--with-libyaml-dir=#{@libyaml.install_root})
287
315
  args << %Q(--with-zlib-dir=#{@zlib.install_root})
@@ -289,7 +317,7 @@ module RubyWasm
289
317
  args << %Q(--with-baseruby=#{baseruby_path})
290
318
 
291
319
  case target
292
- when "wasm32-unknown-wasi"
320
+ when /^wasm32-unknown-wasi/
293
321
  xldflags << @wasi_vfs.lib_wasi_vfs_a if @wasi_vfs
294
322
  # TODO: Find a way to force cast or update API
295
323
  # @type var wasi_sdk_path: untyped
@@ -298,14 +326,19 @@ module RubyWasm
298
326
  args << %Q(WASI_SDK_PATH=#{wasi_sdk_path.wasi_sdk_path})
299
327
  when "wasm32-unknown-emscripten"
300
328
  ldflags.concat(%w[-s MODULARIZE=1])
329
+ env_emcc_ldflags = ENV["RUBY_WASM_EMCC_LDFLAGS"] || ""
330
+ unless env_emcc_ldflags.empty?
331
+ ldflags << env_emcc_ldflags
332
+ end
301
333
  else
302
334
  raise "unknown target: #{target}"
303
335
  end
304
336
 
305
337
  args.concat(self.tools_args)
306
338
  (@user_exts || []).each { |lib| xldflags << "@#{lib.linklist(self)}" }
307
- xldflags << extinit_obj
339
+ xldflags << extinit_obj if need_extinit_obj?
308
340
 
341
+ cflags = @cflags.dup
309
342
  xcflags = @xcflags.dup
310
343
  xcflags << "-DWASM_SETJMP_STACK_BUFFER_SIZE=24576"
311
344
  xcflags << "-DWASM_FIBER_STACK_BUFFER_SIZE=24576"
@@ -313,6 +346,7 @@ module RubyWasm
313
346
 
314
347
  args << %Q(LDFLAGS=#{ldflags.join(" ")})
315
348
  args << %Q(XLDFLAGS=#{xldflags.join(" ")})
349
+ args << %Q(CFLAGS=#{cflags.join(" ")})
316
350
  args << %Q(XCFLAGS=#{xcflags.join(" ")})
317
351
  args << %Q(debugflags=#{@debugflags.join(" ")})
318
352
  args << %Q(cppflags=#{@cppflags.join(" ")})
@@ -13,7 +13,7 @@ module RubyWasm
13
13
  end
14
14
 
15
15
  def product_build_dir
16
- File.join(@build_dir, target, "yaml-#{LIBYAML_VERSION}")
16
+ File.join(@build_dir, target.to_s, "yaml-#{LIBYAML_VERSION}")
17
17
  end
18
18
 
19
19
  def destdir
@@ -52,12 +52,14 @@ module RubyWasm
52
52
  executor.system "curl",
53
53
  "-o",
54
54
  "#{product_build_dir}/config/config.guess",
55
- "https://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD"
55
+ "https://cdn.jsdelivr.net/gh/gcc-mirror/gcc@master/config.guess"
56
56
  executor.system "curl",
57
57
  "-o",
58
58
  "#{product_build_dir}/config/config.sub",
59
- "https://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD"
59
+ "https://cdn.jsdelivr.net/gh/gcc-mirror/gcc@master/config.sub"
60
60
 
61
+ configure_args = self.configure_args.dup
62
+ configure_args << "CFLAGS=-fPIC" if target.pic?
61
63
  executor.system "./configure", *configure_args, chdir: product_build_dir
62
64
  executor.system "make",
63
65
  "install",
@@ -13,7 +13,7 @@ module RubyWasm
13
13
  end
14
14
 
15
15
  def product_build_dir
16
- File.join(@build_dir, target, "openssl-#{OPENSSL_VERSION}")
16
+ File.join(@build_dir, target.to_s, "openssl-#{OPENSSL_VERSION}")
17
17
  end
18
18
 
19
19
  def destdir
@@ -42,7 +42,7 @@ module RubyWasm
42
42
  --libdir=lib
43
43
  -Wl,--allow-undefined
44
44
  ]
45
- if @target == "wasm32-unknown-wasi"
45
+ if @target.triple.start_with?("wasm32-unknown-wasi")
46
46
  args.concat %w[
47
47
  -D_WASI_EMULATED_SIGNAL
48
48
  -D_WASI_EMULATED_PROCESS_CLOCKS
@@ -52,6 +52,11 @@ module RubyWasm
52
52
  -DHAVE_FORK=0
53
53
  ]
54
54
  end
55
+
56
+ if @target.pic?
57
+ args << "-fPIC"
58
+ end
59
+
55
60
  args + tools_args
56
61
  end
57
62
 
@@ -12,13 +12,13 @@ module RubyWasm
12
12
  end
13
13
  def system_triplet_args
14
14
  args = []
15
- case @target
16
- when "wasm32-unknown-wasi"
15
+ case @target.triple
16
+ when /^wasm32-unknown-wasi/
17
17
  args.concat(%W[--host wasm32-wasi])
18
18
  when "wasm32-unknown-emscripten"
19
19
  args.concat(%W[--host wasm32-emscripten])
20
20
  else
21
- raise "unknown target: #{@target}"
21
+ raise "unknown target: #{@target.triple}"
22
22
  end
23
23
  args
24
24
  end
@@ -19,7 +19,7 @@ module RubyWasm
19
19
  when "tarball"
20
20
  digest << @params[:url]
21
21
  when "local"
22
- digest << File.mtime(@params[:src]).to_i.to_s
22
+ digest << File.mtime(@params[:path]).to_i.to_s
23
23
  else
24
24
  raise "unknown source type: #{@params[:type]}"
25
25
  end
@@ -75,12 +75,12 @@ module RubyWasm
75
75
  )
76
76
  when "local"
77
77
  executor.mkdir_p File.dirname(src_dir)
78
- executor.cp_r @params[:src], src_dir
78
+ executor.ln_s File.expand_path(@params[:path]), src_dir
79
79
  else
80
80
  raise "unknown source type: #{@params[:type]}"
81
81
  end
82
82
  (@params[:patches] || []).each do |patch_path|
83
- executor.system "patch", "-p1", patch_path, chdir: src_dir
83
+ executor.system "patch", "-p1", "-i", patch_path, chdir: src_dir
84
84
  end
85
85
  end
86
86
 
@@ -7,17 +7,12 @@ module RubyWasm
7
7
  def initialize(build_dir)
8
8
  @build_dir = build_dir
9
9
  @need_fetch_lib = ENV["LIB_WASI_VFS_A"].nil?
10
- installed_cli_path =
11
- ENV["WASI_VFS_CLI"] || Toolchain.find_path("wasi-vfs")
12
- @need_fetch_cli = installed_cli_path.nil?
13
- @cli_path =
14
- installed_cli_path || File.join(cli_product_build_dir, "wasi-vfs")
15
10
  end
16
11
 
17
12
  def lib_product_build_dir
18
13
  File.join(
19
14
  @build_dir,
20
- "wasm32-unknown-wasi",
15
+ "wasm32-unknown-wasip1",
21
16
  "wasi-vfs-#{WASI_VFS_VERSION}"
22
17
  )
23
18
  end
@@ -26,18 +21,6 @@ module RubyWasm
26
21
  ENV["LIB_WASI_VFS_A"] || File.join(lib_product_build_dir, "libwasi_vfs.a")
27
22
  end
28
23
 
29
- def cli_product_build_dir
30
- File.join(
31
- @build_dir,
32
- RbConfig::CONFIG["host"],
33
- "wasi-vfs-#{WASI_VFS_VERSION}"
34
- )
35
- end
36
-
37
- def cli_bin_path
38
- @cli_path
39
- end
40
-
41
24
  def name
42
25
  "wasi-vfs-#{WASI_VFS_VERSION}-#{RbConfig::CONFIG["host"]}"
43
26
  end
@@ -58,26 +41,5 @@ module RubyWasm
58
41
  executor.mv File.join(tmpdir, "libwasi_vfs.a"), lib_wasi_vfs_a
59
42
  end
60
43
  end
61
-
62
- def install_cli
63
- return if !@need_fetch_cli || File.exist?(cli_bin_path)
64
- FileUtils.mkdir_p cli_product_build_dir
65
- zipfile = File.join(cli_product_build_dir, "wasi-vfs-cli.zip")
66
- system "curl", "-L", "-o", zipfile, self.cli_download_url
67
- system "unzip", zipfile, "-d", cli_product_build_dir
68
- end
69
-
70
- def cli_download_url
71
- assets = [
72
- [/x86_64-linux/, "wasi-vfs-cli-x86_64-unknown-linux-gnu.zip"],
73
- [/x86_64-darwin/, "wasi-vfs-cli-x86_64-apple-darwin.zip"],
74
- [/arm64e?-darwin/, "wasi-vfs-cli-aarch64-apple-darwin.zip"]
75
- ]
76
- asset = assets.find { |os, _| os =~ RUBY_PLATFORM }&.at(1)
77
- if asset.nil?
78
- raise "unsupported platform for fetching wasi-vfs CLI: #{RUBY_PLATFORM}"
79
- end
80
- "https://github.com/kateinoigakukun/wasi-vfs/releases/download/v#{WASI_VFS_VERSION}/#{asset}"
81
- end
82
44
  end
83
45
  end
@@ -4,7 +4,7 @@ module RubyWasm
4
4
  class ZlibProduct < AutoconfProduct
5
5
  attr_reader :target
6
6
 
7
- ZLIB_VERSION = "1.3"
7
+ ZLIB_VERSION = "1.3.1"
8
8
 
9
9
  def initialize(build_dir, target, toolchain)
10
10
  @build_dir = build_dir
@@ -13,7 +13,7 @@ module RubyWasm
13
13
  end
14
14
 
15
15
  def product_build_dir
16
- File.join(@build_dir, target, "zlib-#{ZLIB_VERSION}")
16
+ File.join(@build_dir, target.to_s, "zlib-#{ZLIB_VERSION}")
17
17
  end
18
18
 
19
19
  def destdir
@@ -46,7 +46,7 @@ module RubyWasm
46
46
  "-o",
47
47
  tarball_path,
48
48
  "-L",
49
- "https://zlib.net/zlib-#{ZLIB_VERSION}.tar.gz"
49
+ "https://github.com/madler/zlib/releases/download/v#{ZLIB_VERSION}/zlib-#{ZLIB_VERSION}.tar.gz"
50
50
  executor.system "tar",
51
51
  "xzf",
52
52
  tarball_path,
@@ -54,6 +54,8 @@ module RubyWasm
54
54
  product_build_dir,
55
55
  "--strip-components=1"
56
56
 
57
+ configure_args = self.configure_args.dup
58
+ configure_args << "CFLAGS=-fPIC" if target.pic?
57
59
  executor.system "env",
58
60
  *configure_args,
59
61
  "./configure",
@@ -0,0 +1,24 @@
1
+ module RubyWasm
2
+ # A build target representation
3
+ class Target
4
+ attr_reader :triple
5
+
6
+ def initialize(triple, pic: false)
7
+ @triple = triple
8
+ @pic = pic
9
+ end
10
+
11
+ def pic?
12
+ @pic
13
+ end
14
+
15
+ def to_s
16
+ "#{@triple}#{@pic ? "-pic" : ""}"
17
+ end
18
+
19
+ def cache_key(digest)
20
+ digest << @triple
21
+ digest << "pic" if @pic
22
+ end
23
+ end
24
+ end
@@ -18,7 +18,7 @@ module RubyWasm
18
18
 
19
19
  def self.get(target, build_dir = nil)
20
20
  case target
21
- when "wasm32-unknown-wasi"
21
+ when /^wasm32-unknown-wasi/
22
22
  return RubyWasm::WASISDK.new(build_dir: build_dir)
23
23
  when "wasm32-unknown-emscripten"
24
24
  return RubyWasm::Emscripten.new
@@ -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