ruby_wasm 2.5.0.pre.1 → 2.5.1

Sign up to get free protection for your applications and to get access to all the features.
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