1
1
require "forwardable"
2
+ require "pathname"
2
3
3
4
class RubyWasm ::Packager ::Core
4
5
def initialize ( packager )
@@ -19,7 +20,6 @@ def build(executor, options)
19
20
def build_strategy
20
21
@build_strategy ||=
21
22
begin
22
- has_exts = @packager . specs . any? { |spec | spec . extensions . any? }
23
23
if @packager . features . support_dynamic_linking?
24
24
DynamicLinking . new ( @packager )
25
25
else
@@ -59,14 +59,6 @@ def specs_with_extensions
59
59
end
60
60
end
61
61
62
- def wasi_exec_model
63
- # TODO: Detect WASI exec-model from binary exports (_start or _initialize)
64
- use_js_gem = @packager . specs . any? do |spec |
65
- spec . name == "js"
66
- end
67
- use_js_gem ? "reactor" : "command"
68
- end
69
-
70
62
def with_unbundled_env ( &block )
71
63
__skip__ = if defined? ( Bundler )
72
64
Bundler . with_unbundled_env ( &block )
@@ -138,12 +130,16 @@ def _link_gem_exts(executor, build, ruby_root, gem_home, module_bytes)
138
130
wasi_sdk_path = toolchain . wasi_sdk_path
139
131
libraries << File . join ( wasi_sdk_path , "share/wasi-sysroot/lib/wasm32-wasi" , lib )
140
132
end
141
- wasi_adapter = RubyWasm ::Packager ::ComponentAdapter . wasi_snapshot_preview1 ( wasi_exec_model )
142
- adapters = [ wasi_adapter ]
143
133
dl_openable_libs = [ ]
144
134
dl_openable_libs << [ File . dirname ( ruby_root ) , Dir . glob ( File . join ( ruby_root , "lib" , "ruby" , "**" , "*.so" ) ) ]
145
135
dl_openable_libs << [ gem_home , Dir . glob ( File . join ( gem_home , "**" , "*.so" ) ) ]
146
136
137
+ has_js_so = dl_openable_libs . any? do |root , libs |
138
+ libs . any? { |lib | lib . end_with? ( "/js.so" ) }
139
+ end
140
+ wasi_adapter = RubyWasm ::Packager ::ComponentAdapter . wasi_snapshot_preview1 ( has_js_so ? "reactor" : "command" )
141
+ adapters = [ wasi_adapter ]
142
+
147
143
linker = RubyWasmExt ::ComponentLink . new
148
144
linker . use_built_in_libdl ( true )
149
145
linker . stub_missing_functions ( false )
@@ -187,31 +183,43 @@ def _build_gem_exts(executor, build, gem_home)
187
183
baseruby . build ( executor )
188
184
end
189
185
190
- exts = specs_with_extensions . flat_map do |spec , exts |
191
- exts . map do |ext |
192
- ext_feature = File . dirname ( ext ) # e.g. "ext/cgi/escape"
193
- ext_srcdir = File . join ( spec . full_gem_path , ext_feature )
194
- ext_relative_path = File . join ( spec . full_name , ext_feature )
195
- prod = RubyWasm ::CrossRubyExtProduct . new (
196
- ext_srcdir ,
197
- build . toolchain ,
198
- features : @packager . features ,
199
- ext_relative_path : ext_relative_path
200
- )
201
- [ prod , spec ]
202
- end
203
- end
186
+ crossruby = build . crossruby
187
+ rbconfig_rb = crossruby . rbconfig_rb
204
188
205
- exts . each do |prod , spec |
206
- libdir = File . join ( gem_home , "gems" , spec . full_name , spec . raw_require_paths . first )
207
- extra_mkargs = [
208
- "sitearchdir=#{ libdir } " ,
209
- "sitelibdir=#{ libdir } " ,
210
- ]
211
- executor . begin_section prod . class , prod . name , "Building"
212
- prod . build ( executor , build . crossruby , extra_mkargs )
213
- executor . end_section prod . class , prod . name
214
- end
189
+ options = @packager . full_build_options
190
+ target_triplet = options [ :target ]
191
+
192
+ local_path = File . join ( "bundle" , target_triplet )
193
+ env = {
194
+ "BUNDLE_APP_CONFIG" => File . join ( ".bundle" , target_triplet ) ,
195
+ "BUNDLE_PATH" => local_path ,
196
+ "BUNDLE_WITHOUT" => "build" ,
197
+ # Do not auto-switch bundler version by Gemfile.lock
198
+ "BUNDLE_VERSION" => "system" ,
199
+ # FIXME: BUNDLE_PATH is set as a installation destination here, but
200
+ # it is also used as a source of gems to be loaded by RubyGems itself.
201
+ # RubyGems loads "psych" gem and if Gemfile includes "psych" gem,
202
+ # RubyGems tries to load "psych" gem from BUNDLE_PATH at the second
203
+ # time of "bundle install" command. But the extension of "psych" gem
204
+ # under BUNDLE_PATH is built for Wasm target, not for host platform,
205
+ # so it fails to load the extension.
206
+ #
207
+ # Thus we preload psych from the default LOAD_PATH here to avoid
208
+ # loading Wasm version of psych.so via `Kernel#require` patched by
209
+ # RubyGems.
210
+ "RUBYOPT" => "-rpsych" ,
211
+ }
212
+
213
+ args = [
214
+ File . join ( baseruby . install_dir , "bin" , "bundle" ) ,
215
+ "install" ,
216
+ "--standalone" ,
217
+ "--target-rbconfig" ,
218
+ rbconfig_rb ,
219
+ ]
220
+
221
+ executor . system ( *args , env : env )
222
+ executor . cp_r ( local_path , gem_home )
215
223
end
216
224
217
225
def cache_key ( digest )
@@ -337,6 +345,14 @@ def build_gem_exts(executor, gem_home)
337
345
# No-op because we already built extensions as part of the Ruby build
338
346
end
339
347
348
+ def wasi_exec_model
349
+ # TODO: Detect WASI exec-model from binary exports (_start or _initialize)
350
+ use_js_gem = @packager . specs . any? do |spec |
351
+ spec . name == "js"
352
+ end
353
+ use_js_gem ? "reactor" : "command"
354
+ end
355
+
340
356
def link_gem_exts ( executor , ruby_root , gem_home , module_bytes )
341
357
return module_bytes unless @packager . features . support_component_model?
342
358
0 commit comments