@@ -12,7 +12,7 @@ def build(executor, options)
1212
1313 extend Forwardable
1414
15- def_delegators :build_strategy , :cache_key , :artifact , :build_and_link_exts
15+ def_delegators :build_strategy , :cache_key , :artifact , :build_gem_exts , :link_gem_exts
1616
1717 private
1818
@@ -37,7 +37,11 @@ def build(executor, options)
3737 raise NotImplementedError
3838 end
3939
40- def build_and_link_exts ( executor , module_bytes )
40+ def build_gem_exts ( executor , gem_home )
41+ raise NotImplementedError
42+ end
43+
44+ def link_gem_exts ( executor , ruby_root , gem_home , module_bytes )
4145 raise NotImplementedError
4246 end
4347
@@ -55,6 +59,14 @@ def specs_with_extensions
5559 end
5660 end
5761
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+
5870 def cache_key ( digest )
5971 raise NotImplementedError
6072 end
@@ -93,20 +105,24 @@ def build(executor, options)
93105 build . crossruby . artifact
94106 end
95107
96- def build_and_link_exts ( executor , module_bytes )
108+ def build_gem_exts ( executor , gem_home )
97109 build = derive_build
98- self . build_exts ( executor , build )
99- self . link_exts ( executor , build )
110+ self . _build_gem_exts ( executor , build , gem_home )
100111 end
101112
102- def link_exts ( executor , build )
103- ruby_root = build . crossruby . dest_dir
113+ def link_gem_exts ( executor , ruby_root , gem_home , module_bytes )
114+ build = derive_build
115+ self . _link_gem_exts ( executor , build , ruby_root , gem_home , module_bytes )
116+ end
104117
105- libraries = [ File . join ( ruby_root , "usr" , "local" , "bin" , "ruby" ) ]
118+ def _link_gem_exts ( executor , build , ruby_root , gem_home , module_bytes )
119+ libraries = [ ]
106120
107121 # TODO: Should be computed from dyinfo of ruby binary
108122 wasi_libc_shared_libs = [
109123 "libc.so" ,
124+ "libc++.so" ,
125+ "libc++abi.so" ,
110126 "libwasi-emulated-getpid.so" ,
111127 "libwasi-emulated-mman.so" ,
112128 "libwasi-emulated-process-clocks.so" ,
@@ -119,13 +135,18 @@ def link_exts(executor, build)
119135 wasi_sdk_path = toolchain . wasi_sdk_path
120136 libraries << File . join ( wasi_sdk_path , "share/wasi-sysroot/lib/wasm32-wasi" , lib )
121137 end
122- wasi_adapter = RubyWasm ::Packager ::ComponentAdapter . wasi_snapshot_preview1 ( "command" )
138+ wasi_adapter = RubyWasm ::Packager ::ComponentAdapter . wasi_snapshot_preview1 ( wasi_exec_model )
123139 adapters = [ wasi_adapter ]
124- dl_openable_libs = Dir . glob ( File . join ( ruby_root , "usr" , "local" , "lib" , "ruby" , "**" , "*.so" ) )
140+ dl_openable_libs = [ ]
141+ dl_openable_libs << [ File . dirname ( ruby_root ) , Dir . glob ( File . join ( ruby_root , "lib" , "ruby" , "**" , "*.so" ) ) ]
142+ dl_openable_libs << [ gem_home , Dir . glob ( File . join ( gem_home , "**" , "*.so" ) ) ]
143+
125144 linker = RubyWasmExt ::ComponentLink . new
126145 linker . use_built_in_libdl ( true )
127146 linker . stub_missing_functions ( false )
128- linker . validate ( true )
147+ linker . validate ( ENV [ "RUBYWASM_SKIP_LINKER_VALIDATION" ] != "1" )
148+
149+ linker . library ( "ruby" , module_bytes , false )
129150
130151 libraries . each do |lib |
131152 # Non-DL openable libraries should be referenced as base name
@@ -135,42 +156,51 @@ def link_exts(executor, build)
135156 linker . library ( lib_name , module_bytes , false )
136157 end
137158
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 )
159+ dl_openable_libs . each do |root , libs |
160+ libs . each do |lib |
161+ # DL openable lib_name should be a relative path from ruby_root
162+ lib_name = "/" + Pathname . new ( lib ) . relative_path_from ( Pathname . new ( File . dirname ( root ) ) ) . to_s
163+ module_bytes = File . binread ( lib )
164+ RubyWasm . logger . info "Linking #{ lib_name } (#{ module_bytes . size } bytes)"
165+ linker . library ( lib_name , module_bytes , true )
166+ end
144167 end
145168
146169 adapters . each do |adapter |
147170 adapter_name = File . basename ( adapter )
148171 # e.g. wasi_snapshot_preview1.command.wasm -> wasi_snapshot_preview1
149172 adapter_name = adapter_name . split ( "." ) [ 0 ]
150173 module_bytes = File . binread ( adapter )
174+ RubyWasm . logger . info "Linking adapter #{ adapter_name } =#{ adapter } (#{ module_bytes . size } bytes)"
151175 linker . adapter ( adapter_name , module_bytes )
152176 end
153177 return linker . encode ( )
154178 end
155179
156- def build_exts ( executor , build )
180+ def _build_gem_exts ( executor , build , gem_home )
157181 exts = specs_with_extensions . flat_map do |spec , exts |
158182 exts . map do |ext |
159183 ext_feature = File . dirname ( ext ) # e.g. "ext/cgi/escape"
160184 ext_srcdir = File . join ( spec . full_gem_path , ext_feature )
161185 ext_relative_path = File . join ( spec . full_name , ext_feature )
162- RubyWasm ::CrossRubyExtProduct . new (
186+ prod = RubyWasm ::CrossRubyExtProduct . new (
163187 ext_srcdir ,
164188 build . toolchain ,
165189 features : @packager . features ,
166190 ext_relative_path : ext_relative_path
167191 )
192+ [ prod , spec ]
168193 end
169194 end
170195
171- exts . each do |prod |
196+ exts . each do |prod , spec |
197+ libdir = File . join ( gem_home , "gems" , spec . full_name , spec . raw_require_paths . first )
198+ extra_mkargs = [
199+ "sitearchdir=#{ libdir } " ,
200+ "sitelibdir=#{ libdir } " ,
201+ ]
172202 executor . begin_section prod . class , prod . name , "Building"
173- prod . build ( executor , build . crossruby )
203+ prod . build ( executor , build . crossruby , extra_mkargs )
174204 executor . end_section prod . class , prod . name
175205 end
176206 end
@@ -301,15 +331,19 @@ def derive_build
301331 build
302332 end
303333
304- def build_and_link_exts ( executor , module_bytes )
334+ def build_gem_exts ( executor , gem_home )
335+ # No-op because we already built extensions as part of the Ruby build
336+ end
337+
338+ def link_gem_exts ( executor , ruby_root , gem_home , module_bytes )
305339 return module_bytes unless @packager . features . support_component_model?
306340
307341 linker = RubyWasmExt ::ComponentEncode . new
308- linker . validate ( true )
342+ linker . validate ( ENV [ "RUBYWASM_SKIP_LINKER_VALIDATION" ] != "1" )
309343 linker . module ( module_bytes )
310344 linker . adapter (
311345 "wasi_snapshot_preview1" ,
312- File . binread ( RubyWasm ::Packager ::ComponentAdapter . wasi_snapshot_preview1 ( "reactor" ) )
346+ File . binread ( RubyWasm ::Packager ::ComponentAdapter . wasi_snapshot_preview1 ( wasi_exec_model ) )
313347 )
314348
315349 linker . encode ( )
0 commit comments