ruby_wasm 2.5.0 → 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.
- checksums.yaml +4 -4
- data/CONTRIBUTING.md +7 -7
- data/Cargo.lock +91 -6
- data/Gemfile +1 -1
- data/README.md +9 -9
- data/Rakefile +8 -7
- data/docs/cheat_sheet.md +8 -8
- data/ext/ruby_wasm/Cargo.toml +3 -1
- data/ext/ruby_wasm/src/lib.rs +198 -8
- data/lib/ruby_wasm/build/executor.rb +4 -0
- data/lib/ruby_wasm/build/product/crossruby.rb +53 -23
- data/lib/ruby_wasm/build/product/libyaml.rb +5 -3
- data/lib/ruby_wasm/build/product/openssl.rb +7 -2
- data/lib/ruby_wasm/build/product/product.rb +3 -3
- data/lib/ruby_wasm/build/product/ruby_source.rb +3 -3
- data/lib/ruby_wasm/build/product/wasi_vfs.rb +1 -1
- data/lib/ruby_wasm/build/product/zlib.rb +3 -1
- data/lib/ruby_wasm/build/target.rb +24 -0
- data/lib/ruby_wasm/build/toolchain.rb +1 -1
- data/lib/ruby_wasm/build.rb +7 -3
- data/lib/ruby_wasm/cli.rb +147 -11
- data/lib/ruby_wasm/feature_set.rb +30 -0
- data/lib/ruby_wasm/packager/component_adapter/wasi_snapshot_preview1.command.wasm +0 -0
- data/lib/ruby_wasm/packager/component_adapter/wasi_snapshot_preview1.reactor.wasm +0 -0
- data/lib/ruby_wasm/packager/component_adapter.rb +14 -0
- data/lib/ruby_wasm/packager/core.rb +192 -4
- data/lib/ruby_wasm/packager/file_system.rb +5 -3
- data/lib/ruby_wasm/packager.rb +21 -83
- data/lib/ruby_wasm/rake_task.rb +1 -0
- data/lib/ruby_wasm/version.rb +1 -1
- data/lib/ruby_wasm.rb +2 -0
- data/package-lock.json +410 -133
- data/package.json +3 -3
- data/rakelib/ci.rake +3 -3
- data/rakelib/packaging.rake +26 -12
- data/sig/ruby_wasm/build.rbs +36 -27
- data/sig/ruby_wasm/cli.rbs +27 -3
- data/sig/ruby_wasm/ext.rbs +25 -2
- data/sig/ruby_wasm/feature_set.rbs +12 -0
- data/sig/ruby_wasm/packager.rbs +44 -7
- metadata +9 -7
- data/builders/wasm32-unknown-emscripten/Dockerfile +0 -43
- data/builders/wasm32-unknown-emscripten/entrypoint.sh +0 -7
- data/builders/wasm32-unknown-wasi/Dockerfile +0 -47
- data/builders/wasm32-unknown-wasi/entrypoint.sh +0 -7
@@ -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
|
-
|
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
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
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
|
-
|
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
|
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
|
@@ -308,8 +336,9 @@ module RubyWasm
|
|
308
336
|
|
309
337
|
args.concat(self.tools_args)
|
310
338
|
(@user_exts || []).each { |lib| xldflags << "@#{lib.linklist(self)}" }
|
311
|
-
xldflags << extinit_obj
|
339
|
+
xldflags << extinit_obj if need_extinit_obj?
|
312
340
|
|
341
|
+
cflags = @cflags.dup
|
313
342
|
xcflags = @xcflags.dup
|
314
343
|
xcflags << "-DWASM_SETJMP_STACK_BUFFER_SIZE=24576"
|
315
344
|
xcflags << "-DWASM_FIBER_STACK_BUFFER_SIZE=24576"
|
@@ -317,6 +346,7 @@ module RubyWasm
|
|
317
346
|
|
318
347
|
args << %Q(LDFLAGS=#{ldflags.join(" ")})
|
319
348
|
args << %Q(XLDFLAGS=#{xldflags.join(" ")})
|
349
|
+
args << %Q(CFLAGS=#{cflags.join(" ")})
|
320
350
|
args << %Q(XCFLAGS=#{xcflags.join(" ")})
|
321
351
|
args << %Q(debugflags=#{@debugflags.join(" ")})
|
322
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://
|
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://
|
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
|
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
|
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[:
|
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.
|
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
|
|
@@ -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
|
@@ -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
|
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
|
data/lib/ruby_wasm/build.rb
CHANGED
@@ -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
|
-
|
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
|
-
|
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:
|
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-
|
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
|
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
|
-
|
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] =
|
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
|
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.0.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.3.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
|
-
|
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
|
-
|
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
|
336
|
+
@stdout.write wasm_bytes
|
201
337
|
else
|
202
|
-
File.binwrite(options[:output], wasm_bytes
|
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
|