ruby_wasm 2.5.0-x64-mingw-ucrt → 2.5.1-x64-mingw-ucrt
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 +9 -7
- data/Gemfile +1 -1
- data/README.md +10 -9
- data/Rakefile +8 -7
- data/docs/cheat_sheet.md +8 -8
- data/lib/ruby_wasm/3.1/ruby_wasm.so +0 -0
- data/lib/ruby_wasm/3.2/ruby_wasm.so +0 -0
- data/lib/ruby_wasm/3.3/ruby_wasm.so +0 -0
- 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 +141 -11
- 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 +180 -3
- data/lib/ruby_wasm/packager/file_system.rb +5 -3
- data/lib/ruby_wasm/packager.rb +18 -81
- data/lib/ruby_wasm/rake_task.rb +1 -0
- data/lib/ruby_wasm/version.rb +1 -1
- data/lib/ruby_wasm.rb +1 -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 +15 -2
- data/sig/ruby_wasm/packager.rbs +37 -6
- metadata +8 -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
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,11 @@ module RubyWasm
|
|
152
169
|
private
|
153
170
|
|
154
171
|
def build_config(options)
|
155
|
-
|
172
|
+
# @type var config: Packager::build_config
|
173
|
+
config = { target: options[:target_triplet], src: compute_build_source(options) }
|
156
174
|
case options[:profile]
|
157
175
|
when "full"
|
158
|
-
config[:default_exts] =
|
176
|
+
config[:default_exts] = config[:src][:all_default_exts]
|
159
177
|
env_additional_exts = ENV["RUBY_WASM_ADDITIONAL_EXTS"] || ""
|
160
178
|
unless env_additional_exts.empty?
|
161
179
|
config[:default_exts] += "," + env_additional_exts
|
@@ -170,12 +188,124 @@ module RubyWasm
|
|
170
188
|
config
|
171
189
|
end
|
172
190
|
|
173
|
-
def
|
191
|
+
def compute_build_source(options)
|
192
|
+
src_name = options[:ruby_version]
|
193
|
+
aliases = self.class.build_source_aliases(root)
|
194
|
+
source = aliases[src_name]
|
195
|
+
if source.nil?
|
196
|
+
if File.directory?(src_name)
|
197
|
+
# Treat as a local source if the given name is a source directory.
|
198
|
+
RubyWasm.logger.debug "Using local source: #{src_name}"
|
199
|
+
if options[:patches].any?
|
200
|
+
RubyWasm.logger.warn "Patches specified through --patch are ignored for local sources"
|
201
|
+
end
|
202
|
+
# @type var local_source: RubyWasm::Packager::build_source_local
|
203
|
+
local_source = { type: "local", path: src_name }
|
204
|
+
# @type var local_source: RubyWasm::Packager::build_source
|
205
|
+
local_source = local_source.merge(name: "local", patches: [])
|
206
|
+
return local_source
|
207
|
+
end
|
208
|
+
# Otherwise, it's an unknown source.
|
209
|
+
raise(
|
210
|
+
"Unknown Ruby source: #{src_name} (available: #{aliases.keys.join(", ")} or a local directory)"
|
211
|
+
)
|
212
|
+
end
|
213
|
+
# Apply user-specified patches in addition to bundled patches.
|
214
|
+
source[:patches].concat(options[:patches])
|
215
|
+
source
|
216
|
+
end
|
217
|
+
|
218
|
+
# Retrieves the alias definitions for the Ruby sources.
|
219
|
+
def self.build_source_aliases(root)
|
220
|
+
# @type var sources: Hash[string, RubyWasm::Packager::build_source]
|
221
|
+
sources = {
|
222
|
+
"head" => {
|
223
|
+
type: "github",
|
224
|
+
repo: "ruby/ruby",
|
225
|
+
rev: "master",
|
226
|
+
all_default_exts: RubyWasm::Packager::ALL_DEFAULT_EXTS,
|
227
|
+
},
|
228
|
+
"3.3" => {
|
229
|
+
type: "tarball",
|
230
|
+
url: "https://cache.ruby-lang.org/pub/ruby/3.3/ruby-3.3.0.tar.gz",
|
231
|
+
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",
|
232
|
+
},
|
233
|
+
"3.2" => {
|
234
|
+
type: "tarball",
|
235
|
+
url: "https://cache.ruby-lang.org/pub/ruby/3.2/ruby-3.2.3.tar.gz",
|
236
|
+
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",
|
237
|
+
}
|
238
|
+
}
|
239
|
+
|
240
|
+
# Apply bundled and user-specified `<root>/patches` directories.
|
241
|
+
sources.each do |name, source|
|
242
|
+
source[:name] = name
|
243
|
+
patches_dirs = [bundled_patches_path, File.join(root, "patches")]
|
244
|
+
source[:patches] = patches_dirs.flat_map do |patches_dir|
|
245
|
+
Dir[File.join(patches_dir, name, "*.patch")]
|
246
|
+
.map { |p| File.expand_path(p) }
|
247
|
+
end
|
248
|
+
end
|
249
|
+
|
250
|
+
build_manifest = File.join(root, "build_manifest.json")
|
251
|
+
if File.exist?(build_manifest)
|
252
|
+
begin
|
253
|
+
manifest = JSON.parse(File.read(build_manifest))
|
254
|
+
manifest["ruby_revisions"].each do |name, rev|
|
255
|
+
source = sources[name]
|
256
|
+
next unless source[:type] == "github"
|
257
|
+
# @type var source: RubyWasm::Packager::build_source_github
|
258
|
+
source[:rev] = rev
|
259
|
+
end
|
260
|
+
rescue StandardError => e
|
261
|
+
RubyWasm.logger.warn "Failed to load build_manifest.json: #{e}"
|
262
|
+
end
|
263
|
+
end
|
264
|
+
sources
|
265
|
+
end
|
266
|
+
|
267
|
+
# Retrieves the root directory of the Ruby project.
|
268
|
+
def root
|
174
269
|
__skip__ =
|
175
|
-
|
270
|
+
@root ||=
|
271
|
+
begin
|
272
|
+
if explicit = ENV["RUBY_WASM_ROOT"]
|
273
|
+
File.expand_path(explicit)
|
274
|
+
elsif defined?(Bundler)
|
275
|
+
Bundler.root
|
276
|
+
else
|
277
|
+
Dir.pwd
|
278
|
+
end
|
279
|
+
rescue Bundler::GemfileNotFound
|
280
|
+
Dir.pwd
|
281
|
+
end
|
282
|
+
end
|
283
|
+
|
284
|
+
# Path to the directory containing the bundled patches, which is shipped
|
285
|
+
# as part of ruby_wasm gem to backport fixes or try experimental features
|
286
|
+
# before landing them to the ruby/ruby repository.
|
287
|
+
def self.bundled_patches_path
|
288
|
+
dir = __dir__
|
289
|
+
raise "Unexpected directory structure, no __dir__!??" unless dir
|
290
|
+
lib_source_root = File.join(dir, "..", "..")
|
291
|
+
File.join(lib_source_root, "patches")
|
292
|
+
end
|
293
|
+
|
294
|
+
def derive_packager(options)
|
295
|
+
__skip__ = definition = nil
|
296
|
+
__skip__ = if defined?(Bundler) && !options[:disable_gems]
|
297
|
+
begin
|
298
|
+
# Silence Bundler UI if --print-ruby-cache-key is specified not to bother the JSON output.
|
299
|
+
level = options[:print_ruby_cache_key] ? :silent : Bundler.ui.level
|
300
|
+
old_level = Bundler.ui.level
|
301
|
+
Bundler.ui.level = level
|
176
302
|
definition = Bundler.definition
|
303
|
+
ensure
|
304
|
+
Bundler.ui.level = old_level
|
177
305
|
end
|
178
|
-
|
306
|
+
end
|
307
|
+
RubyWasm.logger.info "Using Gemfile: #{definition.gemfiles}" if definition
|
308
|
+
RubyWasm::Packager.new(root, build_config(options), definition)
|
179
309
|
end
|
180
310
|
|
181
311
|
def do_print_ruby_cache_key(packager)
|
@@ -197,9 +327,9 @@ module RubyWasm
|
|
197
327
|
RubyWasm.logger.info "Size: #{SizeFormatter.format(wasm_bytes.size)}"
|
198
328
|
case options[:output]
|
199
329
|
when "-"
|
200
|
-
@stdout.write wasm_bytes
|
330
|
+
@stdout.write wasm_bytes
|
201
331
|
else
|
202
|
-
File.binwrite(options[:output], wasm_bytes
|
332
|
+
File.binwrite(options[:output], wasm_bytes)
|
203
333
|
RubyWasm.logger.debug "Wrote #{options[:output]}"
|
204
334
|
end
|
205
335
|
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
|
@@ -12,7 +12,7 @@ class RubyWasm::Packager::Core
|
|
12
12
|
|
13
13
|
extend Forwardable
|
14
14
|
|
15
|
-
def_delegators :build_strategy, :cache_key, :artifact
|
15
|
+
def_delegators :build_strategy, :cache_key, :artifact, :build_and_link_exts
|
16
16
|
|
17
17
|
private
|
18
18
|
|
@@ -37,6 +37,10 @@ class RubyWasm::Packager::Core
|
|
37
37
|
raise NotImplementedError
|
38
38
|
end
|
39
39
|
|
40
|
+
def build_and_link_exts(executor)
|
41
|
+
raise NotImplementedError
|
42
|
+
end
|
43
|
+
|
40
44
|
# Array of paths to extconf.rb files.
|
41
45
|
def specs_with_extensions
|
42
46
|
@packager.specs.filter_map do |spec|
|
@@ -61,6 +65,167 @@ class RubyWasm::Packager::Core
|
|
61
65
|
end
|
62
66
|
|
63
67
|
class DynamicLinking < BuildStrategy
|
68
|
+
def build(executor, options)
|
69
|
+
build = derive_build
|
70
|
+
force_rebuild =
|
71
|
+
options[:remake] || options[:clean] || options[:reconfigure]
|
72
|
+
if File.exist?(build.crossruby.artifact) && !force_rebuild
|
73
|
+
# Always build extensions because they are usually not expensive to build
|
74
|
+
return build.crossruby.artifact
|
75
|
+
end
|
76
|
+
build.crossruby.clean(executor) if options[:clean]
|
77
|
+
|
78
|
+
do_build =
|
79
|
+
proc do
|
80
|
+
build.crossruby.build(
|
81
|
+
executor,
|
82
|
+
remake: options[:remake],
|
83
|
+
reconfigure: options[:reconfigure]
|
84
|
+
)
|
85
|
+
end
|
86
|
+
|
87
|
+
__skip__ =
|
88
|
+
if defined?(Bundler)
|
89
|
+
Bundler.with_unbundled_env(&do_build)
|
90
|
+
else
|
91
|
+
do_build.call
|
92
|
+
end
|
93
|
+
build.crossruby.artifact
|
94
|
+
end
|
95
|
+
|
96
|
+
def build_and_link_exts(executor)
|
97
|
+
build = derive_build
|
98
|
+
self.build_exts(executor, build)
|
99
|
+
self.link_exts(executor, build)
|
100
|
+
end
|
101
|
+
|
102
|
+
def link_exts(executor, build)
|
103
|
+
ruby_root = build.crossruby.dest_dir
|
104
|
+
|
105
|
+
libraries = [File.join(ruby_root, "usr", "local", "bin", "ruby")]
|
106
|
+
|
107
|
+
# TODO: Should be computed from dyinfo of ruby binary
|
108
|
+
wasi_libc_shared_libs = [
|
109
|
+
"libc.so",
|
110
|
+
"libwasi-emulated-getpid.so",
|
111
|
+
"libwasi-emulated-mman.so",
|
112
|
+
"libwasi-emulated-process-clocks.so",
|
113
|
+
"libwasi-emulated-signal.so",
|
114
|
+
]
|
115
|
+
|
116
|
+
wasi_libc_shared_libs.each do |lib|
|
117
|
+
# @type var toolchain: RubyWasm::WASISDK
|
118
|
+
toolchain = build.toolchain
|
119
|
+
wasi_sdk_path = toolchain.wasi_sdk_path
|
120
|
+
libraries << File.join(wasi_sdk_path, "share/wasi-sysroot/lib/wasm32-wasi", lib)
|
121
|
+
end
|
122
|
+
wasi_adapter = RubyWasm::Packager::ComponentAdapter.wasi_snapshot_preview1("command")
|
123
|
+
adapters = [wasi_adapter]
|
124
|
+
dl_openable_libs = Dir.glob(File.join(ruby_root, "usr", "local", "lib", "ruby", "**", "*.so"))
|
125
|
+
linker = RubyWasmExt::ComponentLink.new
|
126
|
+
linker.use_built_in_libdl(true)
|
127
|
+
linker.stub_missing_functions(false)
|
128
|
+
linker.validate(true)
|
129
|
+
|
130
|
+
libraries.each do |lib|
|
131
|
+
# Non-DL openable libraries should be referenced as base name
|
132
|
+
lib_name = File.basename(lib)
|
133
|
+
module_bytes = File.binread(lib)
|
134
|
+
RubyWasm.logger.info "Linking #{lib_name} (#{module_bytes.size} bytes)"
|
135
|
+
linker.library(lib_name, module_bytes, false)
|
136
|
+
end
|
137
|
+
|
138
|
+
dl_openable_libs.each do |lib|
|
139
|
+
# DL openable lib_name should be a relative path from ruby_root
|
140
|
+
lib_name = "/" + Pathname.new(lib).relative_path_from(Pathname.new(ruby_root)).to_s
|
141
|
+
module_bytes = File.binread(lib)
|
142
|
+
RubyWasm.logger.info "Linking #{lib_name} (#{module_bytes.size} bytes)"
|
143
|
+
linker.library(lib_name, module_bytes, true)
|
144
|
+
end
|
145
|
+
|
146
|
+
adapters.each do |adapter|
|
147
|
+
adapter_name = File.basename(adapter)
|
148
|
+
# e.g. wasi_snapshot_preview1.command.wasm -> wasi_snapshot_preview1
|
149
|
+
adapter_name = adapter_name.split(".")[0]
|
150
|
+
module_bytes = File.binread(adapter)
|
151
|
+
linker.adapter(adapter_name, module_bytes)
|
152
|
+
end
|
153
|
+
return linker.encode()
|
154
|
+
end
|
155
|
+
|
156
|
+
def build_exts(executor, build)
|
157
|
+
exts = specs_with_extensions.flat_map do |spec, exts|
|
158
|
+
exts.map do |ext|
|
159
|
+
ext_feature = File.dirname(ext) # e.g. "ext/cgi/escape"
|
160
|
+
ext_srcdir = File.join(spec.full_gem_path, ext_feature)
|
161
|
+
ext_relative_path = File.join(spec.full_name, ext_feature)
|
162
|
+
RubyWasm::CrossRubyExtProduct.new(
|
163
|
+
ext_srcdir,
|
164
|
+
build.toolchain,
|
165
|
+
ext_relative_path: ext_relative_path
|
166
|
+
)
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
exts.each do |prod|
|
171
|
+
executor.begin_section prod.class, prod.name, "Building"
|
172
|
+
prod.build(executor, build.crossruby)
|
173
|
+
executor.end_section prod.class, prod.name
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
def cache_key(digest)
|
178
|
+
derive_build.cache_key(digest)
|
179
|
+
end
|
180
|
+
|
181
|
+
def artifact
|
182
|
+
derive_build.crossruby.artifact
|
183
|
+
end
|
184
|
+
|
185
|
+
def target
|
186
|
+
RubyWasm::Target.new(@packager.full_build_options[:target], pic: true)
|
187
|
+
end
|
188
|
+
|
189
|
+
def derive_build
|
190
|
+
return @build if @build
|
191
|
+
__skip__ =
|
192
|
+
build ||= RubyWasm::Build.new(
|
193
|
+
name, **@packager.full_build_options,
|
194
|
+
target: target,
|
195
|
+
# NOTE: We don't need linking libwasi_vfs because we use wasi-virt instead.
|
196
|
+
wasi_vfs: nil
|
197
|
+
)
|
198
|
+
build.crossruby.cflags = %w[-fPIC -fvisibility=default]
|
199
|
+
if @packager.full_build_options[:target] != "wasm32-unknown-emscripten"
|
200
|
+
build.crossruby.debugflags = %w[-g]
|
201
|
+
build.crossruby.wasmoptflags = %w[-O3 -g --pass-arg=asyncify-relocatable]
|
202
|
+
build.crossruby.ldflags = %w[
|
203
|
+
-Xlinker
|
204
|
+
--stack-first
|
205
|
+
-Xlinker
|
206
|
+
-z
|
207
|
+
-Xlinker
|
208
|
+
stack-size=16777216
|
209
|
+
]
|
210
|
+
build.crossruby.xldflags = %w[
|
211
|
+
-Xlinker -shared
|
212
|
+
-Xlinker --export-dynamic
|
213
|
+
-Xlinker --export-all
|
214
|
+
-Xlinker --experimental-pic
|
215
|
+
-Xlinker -export-if-defined=__main_argc_argv
|
216
|
+
]
|
217
|
+
end
|
218
|
+
@build = build
|
219
|
+
build
|
220
|
+
end
|
221
|
+
|
222
|
+
def name
|
223
|
+
require "digest"
|
224
|
+
options = @packager.full_build_options
|
225
|
+
src_channel = options[:src][:name]
|
226
|
+
target_triplet = options[:target]
|
227
|
+
"ruby-#{src_channel}-#{target_triplet}-pic#{options[:suffix]}"
|
228
|
+
end
|
64
229
|
end
|
65
230
|
|
66
231
|
class StaticLinking < BuildStrategy
|
@@ -99,10 +264,14 @@ class RubyWasm::Packager::Core
|
|
99
264
|
derive_build.crossruby.artifact
|
100
265
|
end
|
101
266
|
|
267
|
+
def target
|
268
|
+
RubyWasm::Target.new(@packager.full_build_options[:target])
|
269
|
+
end
|
270
|
+
|
102
271
|
def derive_build
|
103
272
|
return @build if @build
|
104
273
|
__skip__ =
|
105
|
-
build ||= RubyWasm::Build.new(name, **@packager.full_build_options)
|
274
|
+
build ||= RubyWasm::Build.new(name, **@packager.full_build_options, target: target)
|
106
275
|
build.crossruby.user_exts = user_exts(build)
|
107
276
|
# Emscripten uses --global-base=1024 by default, but it conflicts with
|
108
277
|
# --stack-first and -z stack-size since global-base 1024 is smaller than
|
@@ -111,7 +280,9 @@ class RubyWasm::Packager::Core
|
|
111
280
|
# script of Ruby.
|
112
281
|
if @packager.full_build_options[:target] != "wasm32-unknown-emscripten"
|
113
282
|
build.crossruby.debugflags = %w[-g]
|
114
|
-
|
283
|
+
# We assume that imported functions provided through WASI will not change
|
284
|
+
# asyncify state, so we ignore them.
|
285
|
+
build.crossruby.wasmoptflags = %w[-O3 -g --pass-arg=asyncify-ignore-imports]
|
115
286
|
build.crossruby.ldflags = %w[
|
116
287
|
-Xlinker
|
117
288
|
--stack-first
|
@@ -125,6 +296,12 @@ class RubyWasm::Packager::Core
|
|
125
296
|
build
|
126
297
|
end
|
127
298
|
|
299
|
+
def build_and_link_exts(executor)
|
300
|
+
build = derive_build
|
301
|
+
ruby_root = build.crossruby.dest_dir
|
302
|
+
File.binread(File.join(ruby_root, "usr", "local", "bin", "ruby"))
|
303
|
+
end
|
304
|
+
|
128
305
|
def user_exts(build)
|
129
306
|
@user_exts ||=
|
130
307
|
specs_with_extensions.flat_map do |spec, exts|
|
@@ -65,12 +65,14 @@ class RubyWasm::Packager::FileSystem
|
|
65
65
|
end
|
66
66
|
|
67
67
|
def remove_non_runtime_files(executor)
|
68
|
-
%w[
|
69
|
-
**/*.so
|
68
|
+
patterns = %w[
|
70
69
|
usr/local/lib/libruby-static.a
|
71
70
|
usr/local/bin/ruby
|
72
71
|
usr/local/include
|
73
|
-
]
|
72
|
+
]
|
73
|
+
|
74
|
+
patterns << "**/*.so" unless @packager.support_dynamic_linking?
|
75
|
+
patterns.each do |pattern|
|
74
76
|
Dir
|
75
77
|
.glob(File.join(@dest_dir, pattern))
|
76
78
|
.each do |entry|
|
data/lib/ruby_wasm/packager.rb
CHANGED
@@ -2,9 +2,15 @@
|
|
2
2
|
class RubyWasm::Packager
|
3
3
|
# Initializes a new instance of the RubyWasm::Packager class.
|
4
4
|
#
|
5
|
+
# @param root [String] The root directory of the Ruby project.
|
6
|
+
# The root directory (will) contain the following files:
|
7
|
+
# * build_manifest.json
|
8
|
+
# * rubies
|
9
|
+
# * build
|
5
10
|
# @param config [Hash] The build config used for building Ruby.
|
6
11
|
# @param definition [Bundler::Definition] The Bundler definition.
|
7
|
-
def initialize(config = nil, definition = nil)
|
12
|
+
def initialize(root, config = nil, definition = nil)
|
13
|
+
@root = root
|
8
14
|
@definition = definition
|
9
15
|
@config = config
|
10
16
|
end
|
@@ -21,15 +27,13 @@ class RubyWasm::Packager
|
|
21
27
|
|
22
28
|
fs = RubyWasm::Packager::FileSystem.new(dest_dir, self)
|
23
29
|
fs.package_ruby_root(tarball, executor)
|
24
|
-
|
25
|
-
ruby_wasm_bin = File.expand_path("bin/ruby", fs.ruby_root)
|
26
|
-
wasm_bytes = File.binread(ruby_wasm_bin).bytes
|
30
|
+
wasm_bytes = ruby_core.build_and_link_exts(executor)
|
27
31
|
|
28
32
|
fs.package_gems
|
29
33
|
fs.remove_non_runtime_files(executor)
|
30
34
|
fs.remove_stdlib(executor) unless options[:stdlib]
|
31
35
|
|
32
|
-
if full_build_options[:target] == "wasm32-unknown-
|
36
|
+
if full_build_options[:target] == "wasm32-unknown-wasip1" && !support_dynamic_linking?
|
33
37
|
# wasi-vfs supports only WASI target
|
34
38
|
wasi_vfs = RubyWasmExt::WasiVfs.new
|
35
39
|
wasi_vfs.map_dir("/bundle", fs.bundle_dir)
|
@@ -52,79 +56,23 @@ class RubyWasm::Packager
|
|
52
56
|
# Retrieves the specs from the Bundler definition, excluding the excluded gems.
|
53
57
|
def specs
|
54
58
|
return [] unless @definition
|
55
|
-
@
|
59
|
+
@specs ||= @definition.resolve.materialize(@definition.requested_dependencies)
|
60
|
+
.reject { |spec| EXCLUDED_GEMS.include?(spec.name) }
|
61
|
+
@specs
|
56
62
|
end
|
57
63
|
|
58
64
|
# Checks if dynamic linking is supported.
|
59
65
|
def support_dynamic_linking?
|
60
|
-
|
61
|
-
end
|
62
|
-
|
63
|
-
# Retrieves the root directory of the Ruby project.
|
64
|
-
# The root directory contains the following stuff:
|
65
|
-
# * patches/*.patch
|
66
|
-
# * build_manifest.json
|
67
|
-
# * rubies
|
68
|
-
# * build
|
69
|
-
def root
|
70
|
-
__skip__ =
|
71
|
-
@root ||=
|
72
|
-
begin
|
73
|
-
if explicit = ENV["RUBY_WASM_ROOT"]
|
74
|
-
File.expand_path(explicit)
|
75
|
-
elsif defined?(Bundler)
|
76
|
-
Bundler.root
|
77
|
-
else
|
78
|
-
Dir.pwd
|
79
|
-
end
|
80
|
-
rescue Bundler::GemfileNotFound
|
81
|
-
Dir.pwd
|
82
|
-
end
|
83
|
-
end
|
84
|
-
|
85
|
-
# Retrieves the alias definitions for the Ruby sources.
|
86
|
-
def self.build_source_aliases(root)
|
87
|
-
patches = Dir[File.join(root, "patches", "*.patch")]
|
88
|
-
sources = {
|
89
|
-
"head" => {
|
90
|
-
type: "github",
|
91
|
-
repo: "ruby/ruby",
|
92
|
-
rev: "master",
|
93
|
-
patches: patches.map { |p| File.expand_path(p) }
|
94
|
-
},
|
95
|
-
"3.3" => {
|
96
|
-
type: "tarball",
|
97
|
-
url: "https://cache.ruby-lang.org/pub/ruby/3.3/ruby-3.3.0.tar.gz"
|
98
|
-
},
|
99
|
-
"3.2" => {
|
100
|
-
type: "tarball",
|
101
|
-
url: "https://cache.ruby-lang.org/pub/ruby/3.2/ruby-3.2.3.tar.gz"
|
102
|
-
}
|
103
|
-
}
|
104
|
-
sources.each { |name, source| source[:name] = name }
|
105
|
-
|
106
|
-
build_manifest = File.join(root, "build_manifest.json")
|
107
|
-
if File.exist?(build_manifest)
|
108
|
-
begin
|
109
|
-
manifest = JSON.parse(File.read(build_manifest))
|
110
|
-
manifest["ruby_revisions"].each do |name, rev|
|
111
|
-
sources[name][:rev] = rev
|
112
|
-
end
|
113
|
-
rescue StandardError => e
|
114
|
-
RubyWasm.logger.warn "Failed to load build_manifest.json: #{e}"
|
115
|
-
end
|
116
|
-
end
|
117
|
-
sources
|
66
|
+
ENV["RUBY_WASM_EXPERIMENTAL_DYNAMIC_LINKING"] == "1"
|
118
67
|
end
|
119
68
|
|
120
69
|
ALL_DEFAULT_EXTS =
|
121
|
-
"
|
70
|
+
"cgi/escape,continuation,coverage,date,digest/bubblebabble,digest,digest/md5,digest/rmd160,digest/sha1,digest/sha2,etc,fcntl,json,json/generator,json/parser,objspace,pathname,psych,rbconfig/sizeof,ripper,stringio,strscan,monitor,zlib,openssl"
|
122
71
|
|
123
72
|
# Retrieves the build options used for building Ruby itself.
|
124
73
|
def build_options
|
125
74
|
default = {
|
126
|
-
target: "wasm32-unknown-
|
127
|
-
src: "3.3",
|
75
|
+
target: RubyWasm::Target.new("wasm32-unknown-wasip1"),
|
128
76
|
default_exts: ALL_DEFAULT_EXTS
|
129
77
|
}
|
130
78
|
override = @config || {}
|
@@ -135,25 +83,14 @@ class RubyWasm::Packager
|
|
135
83
|
# Retrieves the resolved build options
|
136
84
|
def full_build_options
|
137
85
|
options = build_options
|
138
|
-
build_dir = File.join(root, "build")
|
139
|
-
rubies_dir = File.join(root, "rubies")
|
86
|
+
build_dir = File.join(@root, "build")
|
87
|
+
rubies_dir = File.join(@root, "rubies")
|
140
88
|
toolchain = RubyWasm::Toolchain.get(options[:target], build_dir)
|
141
|
-
src =
|
142
|
-
if options[:src].is_a?(Hash)
|
143
|
-
options[:src]
|
144
|
-
else
|
145
|
-
src_name = options[:src]
|
146
|
-
aliases = self.class.build_source_aliases(root)
|
147
|
-
aliases[src_name] ||
|
148
|
-
raise(
|
149
|
-
"Unknown Ruby source: #{src_name} (available: #{aliases.keys.join(", ")})"
|
150
|
-
)
|
151
|
-
end
|
152
89
|
options.merge(
|
153
90
|
toolchain: toolchain,
|
154
91
|
build_dir: build_dir,
|
155
92
|
rubies_dir: rubies_dir,
|
156
|
-
src: src
|
93
|
+
src: options[:src]
|
157
94
|
)
|
158
95
|
end
|
159
96
|
end
|
data/lib/ruby_wasm/rake_task.rb
CHANGED
data/lib/ruby_wasm/version.rb
CHANGED
data/lib/ruby_wasm.rb
CHANGED
@@ -4,6 +4,7 @@ require_relative "ruby_wasm/version"
|
|
4
4
|
require_relative "ruby_wasm/util"
|
5
5
|
require_relative "ruby_wasm/build"
|
6
6
|
require_relative "ruby_wasm/packager"
|
7
|
+
require_relative "ruby_wasm/packager/component_adapter"
|
7
8
|
require_relative "ruby_wasm/packager/file_system"
|
8
9
|
require_relative "ruby_wasm/packager/core"
|
9
10
|
|