ruby_wasm 2.5.0 → 2.5.2
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 +9 -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 +59 -25
- 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/wit_bindgen.rb +2 -2
- 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 +199 -5
- data/lib/ruby_wasm/packager/file_system.rb +5 -3
- data/lib/ruby_wasm/packager.rb +22 -82
- 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 +5571 -7015
- data/package.json +3 -3
- data/rakelib/check.rake +23 -10
- data/rakelib/ci.rake +3 -3
- data/rakelib/packaging.rake +44 -15
- data/sig/ruby_wasm/build.rbs +38 -28
- 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 -10
- 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
@@ -5,11 +5,12 @@ module RubyWasm
|
|
5
5
|
class CrossRubyExtProduct < BuildProduct
|
6
6
|
attr_reader :name
|
7
7
|
|
8
|
-
def initialize(srcdir, toolchain, ext_relative_path: nil)
|
8
|
+
def initialize(srcdir, toolchain, features:, ext_relative_path: nil)
|
9
9
|
@srcdir, @toolchain = srcdir, toolchain
|
10
10
|
# ext_relative_path is relative path from build dir
|
11
11
|
# e.g. cgi-0.3.6/ext/cgi/escape
|
12
12
|
@ext_relative_path = ext_relative_path || File.basename(srcdir)
|
13
|
+
@features = features
|
13
14
|
@name = @ext_relative_path
|
14
15
|
end
|
15
16
|
|
@@ -37,7 +38,6 @@ module RubyWasm
|
|
37
38
|
make_args << "AR=#{@toolchain.ar}"
|
38
39
|
make_args << "RANLIB=#{@toolchain.ranlib}"
|
39
40
|
|
40
|
-
make_args << "DESTDIR=#{crossruby.dest_dir}"
|
41
41
|
make_args
|
42
42
|
end
|
43
43
|
|
@@ -45,12 +45,15 @@ module RubyWasm
|
|
45
45
|
objdir = product_build_dir crossruby
|
46
46
|
executor.mkdir_p objdir
|
47
47
|
do_extconf executor, crossruby
|
48
|
+
|
49
|
+
executor.system "make", "-C", objdir, *make_args(crossruby), "clean"
|
50
|
+
build_target = crossruby.target.pic? ? "install-so" : "static"
|
48
51
|
executor.system "make",
|
49
52
|
"-j#{executor.process_count}",
|
50
53
|
"-C",
|
51
54
|
"#{objdir}",
|
52
55
|
*make_args(crossruby),
|
53
|
-
|
56
|
+
build_target
|
54
57
|
# A ext can provide link args by link.filelist. It contains only built archive file by default.
|
55
58
|
unless File.exist?(linklist(crossruby))
|
56
59
|
executor.write(
|
@@ -61,9 +64,28 @@ module RubyWasm
|
|
61
64
|
end
|
62
65
|
|
63
66
|
def do_extconf(executor, crossruby)
|
67
|
+
unless crossruby.target.pic?
|
68
|
+
self.do_legacy_extconf(executor, crossruby)
|
69
|
+
return
|
70
|
+
end
|
71
|
+
objdir = product_build_dir crossruby
|
72
|
+
source = crossruby.source
|
73
|
+
rbconfig_rb = Dir.glob(File.join(crossruby.dest_dir, "usr/local/lib/ruby/*/wasm32-wasi/rbconfig.rb")).first
|
74
|
+
raise "rbconfig.rb not found" unless rbconfig_rb
|
75
|
+
extconf_args = [
|
76
|
+
"-C", objdir,
|
77
|
+
"#{@srcdir}/extconf.rb",
|
78
|
+
"--target-rbconfig=#{rbconfig_rb}",
|
79
|
+
]
|
80
|
+
extconf_args << "--enable-component-model" if @features.support_component_model?
|
81
|
+
executor.system Gem.ruby, *extconf_args
|
82
|
+
end
|
83
|
+
|
84
|
+
def do_legacy_extconf(executor, crossruby)
|
64
85
|
objdir = product_build_dir crossruby
|
65
86
|
source = crossruby.source
|
66
87
|
extconf_args = [
|
88
|
+
"-C", objdir,
|
67
89
|
"--disable=gems",
|
68
90
|
# HACK: top_srcdir is required to find ruby headers
|
69
91
|
"-e",
|
@@ -71,9 +93,6 @@ module RubyWasm
|
|
71
93
|
# HACK: extout is required to find config.h
|
72
94
|
"-e",
|
73
95
|
%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
96
|
# HACK: force static ext build by imitating extmk
|
78
97
|
"-e",
|
79
98
|
"$static = true; trace_var(:$static) {|v| $static = true }",
|
@@ -88,12 +107,13 @@ module RubyWasm
|
|
88
107
|
# like "cgi/escape" instead of "escape"
|
89
108
|
"-e",
|
90
109
|
%Q(require "json"; File.write("#{metadata_json(crossruby)}", JSON.dump({target: $target}))),
|
91
|
-
"-I#{crossruby.build_dir}"
|
110
|
+
"-I#{crossruby.build_dir}",
|
111
|
+
"--",
|
92
112
|
]
|
113
|
+
extconf_args << "--enable-component-model" if @features.support_component_model?
|
93
114
|
# Clear RUBYOPT to avoid loading unrelated bundle setup
|
94
115
|
executor.system crossruby.baseruby_path,
|
95
116
|
*extconf_args,
|
96
|
-
chdir: objdir,
|
97
117
|
env: {
|
98
118
|
"RUBYOPT" => ""
|
99
119
|
}
|
@@ -118,7 +138,7 @@ module RubyWasm
|
|
118
138
|
end
|
119
139
|
|
120
140
|
class CrossRubyProduct < AutoconfProduct
|
121
|
-
attr_reader :source, :toolchain
|
141
|
+
attr_reader :target, :source, :toolchain
|
122
142
|
attr_accessor :user_exts,
|
123
143
|
:wasmoptflags,
|
124
144
|
:cppflags,
|
@@ -155,6 +175,14 @@ module RubyWasm
|
|
155
175
|
executor.system "make", "rbconfig.rb", chdir: build_dir
|
156
176
|
end
|
157
177
|
|
178
|
+
def need_exts_build?
|
179
|
+
@user_exts.any?
|
180
|
+
end
|
181
|
+
|
182
|
+
def need_extinit_obj?
|
183
|
+
need_exts_build? && !@target.pic?
|
184
|
+
end
|
185
|
+
|
158
186
|
def build_exts(executor)
|
159
187
|
@user_exts.each do |prod|
|
160
188
|
executor.begin_section prod.class, prod.name, "Building"
|
@@ -168,6 +196,7 @@ module RubyWasm
|
|
168
196
|
executor.mkdir_p build_dir
|
169
197
|
@toolchain.install
|
170
198
|
[@source, @baseruby, @libyaml, @zlib, @openssl, @wasi_vfs].each do |prod|
|
199
|
+
next unless prod
|
171
200
|
executor.begin_section prod.class, prod.name, "Building"
|
172
201
|
prod.build(executor)
|
173
202
|
executor.end_section prod.class, prod.name
|
@@ -176,17 +205,20 @@ module RubyWasm
|
|
176
205
|
configure(executor, reconfigure: reconfigure)
|
177
206
|
executor.end_section self.class, name
|
178
207
|
|
179
|
-
build_exts(executor)
|
208
|
+
build_exts(executor) if need_exts_build?
|
180
209
|
|
181
210
|
executor.begin_section self.class, name, "Building"
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
211
|
+
|
212
|
+
if need_extinit_obj?
|
213
|
+
executor.mkdir_p File.dirname(extinit_obj)
|
214
|
+
executor.system "ruby",
|
215
|
+
extinit_c_erb,
|
216
|
+
*@user_exts.map { |ext| ext.feature_name(self) },
|
217
|
+
"--cc",
|
218
|
+
toolchain.cc,
|
219
|
+
"--output",
|
220
|
+
extinit_obj
|
221
|
+
end
|
190
222
|
install_dir = File.join(build_dir, "install")
|
191
223
|
if !File.exist?(install_dir) || remake || reconfigure
|
192
224
|
executor.system "make",
|
@@ -216,7 +248,7 @@ module RubyWasm
|
|
216
248
|
end
|
217
249
|
|
218
250
|
def cache_key(digest)
|
219
|
-
|
251
|
+
@params.target.cache_key(digest)
|
220
252
|
digest << @params.default_exts
|
221
253
|
@wasmoptflags.each { |f| digest << f }
|
222
254
|
@cppflags.each { |f| digest << f }
|
@@ -229,11 +261,11 @@ module RubyWasm
|
|
229
261
|
end
|
230
262
|
|
231
263
|
def build_dir
|
232
|
-
File.join(@build_dir, @params.target, name)
|
264
|
+
File.join(@build_dir, @params.target.to_s, name)
|
233
265
|
end
|
234
266
|
|
235
267
|
def ext_build_dir
|
236
|
-
File.join(@build_dir, @params.target, name + "-ext")
|
268
|
+
File.join(@build_dir, @params.target.to_s, name + "-ext")
|
237
269
|
end
|
238
270
|
|
239
271
|
def with_libyaml(libyaml)
|
@@ -274,14 +306,14 @@ module RubyWasm
|
|
274
306
|
end
|
275
307
|
|
276
308
|
def configure_args(build_triple, toolchain)
|
277
|
-
target = @params.target
|
309
|
+
target = @params.target.triple
|
278
310
|
default_exts = @params.default_exts
|
279
311
|
|
280
312
|
ldflags = @ldflags.dup
|
281
313
|
xldflags = @xldflags.dup
|
282
314
|
|
283
315
|
args = self.system_triplet_args + ["--build", build_triple]
|
284
|
-
args << "--with-static-linked-ext"
|
316
|
+
args << "--with-static-linked-ext" unless @params.target.pic?
|
285
317
|
args << %Q(--with-ext=#{default_exts})
|
286
318
|
args << %Q(--with-libyaml-dir=#{@libyaml.install_root})
|
287
319
|
args << %Q(--with-zlib-dir=#{@zlib.install_root})
|
@@ -289,7 +321,7 @@ module RubyWasm
|
|
289
321
|
args << %Q(--with-baseruby=#{baseruby_path})
|
290
322
|
|
291
323
|
case target
|
292
|
-
when
|
324
|
+
when /^wasm32-unknown-wasi/
|
293
325
|
xldflags << @wasi_vfs.lib_wasi_vfs_a if @wasi_vfs
|
294
326
|
# TODO: Find a way to force cast or update API
|
295
327
|
# @type var wasi_sdk_path: untyped
|
@@ -308,8 +340,9 @@ module RubyWasm
|
|
308
340
|
|
309
341
|
args.concat(self.tools_args)
|
310
342
|
(@user_exts || []).each { |lib| xldflags << "@#{lib.linklist(self)}" }
|
311
|
-
xldflags << extinit_obj
|
343
|
+
xldflags << extinit_obj if need_extinit_obj?
|
312
344
|
|
345
|
+
cflags = @cflags.dup
|
313
346
|
xcflags = @xcflags.dup
|
314
347
|
xcflags << "-DWASM_SETJMP_STACK_BUFFER_SIZE=24576"
|
315
348
|
xcflags << "-DWASM_FIBER_STACK_BUFFER_SIZE=24576"
|
@@ -317,6 +350,7 @@ module RubyWasm
|
|
317
350
|
|
318
351
|
args << %Q(LDFLAGS=#{ldflags.join(" ")})
|
319
352
|
args << %Q(XLDFLAGS=#{xldflags.join(" ")})
|
353
|
+
args << %Q(CFLAGS=#{cflags.join(" ")})
|
320
354
|
args << %Q(XCFLAGS=#{xcflags.join(" ")})
|
321
355
|
args << %Q(debugflags=#{@debugflags.join(" ")})
|
322
356
|
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
|
@@ -4,10 +4,10 @@ module RubyWasm
|
|
4
4
|
|
5
5
|
def initialize(
|
6
6
|
build_dir:,
|
7
|
-
revision: "
|
7
|
+
revision: "v0.24.0"
|
8
8
|
)
|
9
9
|
@build_dir = build_dir
|
10
|
-
@tool_dir = File.join(@build_dir, "toolchain", "wit-bindgen")
|
10
|
+
@tool_dir = File.join(@build_dir, "toolchain", "wit-bindgen-#{revision}")
|
11
11
|
@bin_path = File.join(@tool_dir, "bin", "wit-bindgen")
|
12
12
|
@revision = revision
|
13
13
|
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.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
|
-
|
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
|