diff --git a/.github/workflows/build-gems.yml b/.github/workflows/build-gems.yml index 8a5c710cb2..14d8daef5f 100644 --- a/.github/workflows/build-gems.yml +++ b/.github/workflows/build-gems.yml @@ -18,7 +18,7 @@ jobs: id: fetch with: supported-ruby-platforms: | - exclude: [arm-linux] + exclude: [arm-linux, x64-mingw32] stable-ruby-versions: | exclude: [head] diff --git a/Cargo.lock b/Cargo.lock index 6c487adfbe..b26d351956 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1012,6 +1012,7 @@ version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4778544796676e8428e9c622460ebf284bea52d8b10db3aeb449d8b5e61b3a13" dependencies = [ + "bytes", "magnus-macros", "rb-sys", "rb-sys-env", @@ -1268,18 +1269,18 @@ dependencies = [ [[package]] name = "rb-sys" -version = "0.9.86" +version = "0.9.97" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7285f2a7b92f58ab198e3fd59a71d2861478f9c4642f41e83582385818941697" +checksum = "47d30bcad206b51f2f66121190ca678dce1fdf3a2eae0ac5d838d1818b19bdf5" dependencies = [ "rb-sys-build", ] [[package]] name = "rb-sys-build" -version = "0.9.86" +version = "0.9.97" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71583945f94dabb6c0dfa63f1b71e929c1901e1e288ef3739ab8bed3b7069550" +checksum = "3cbd92f281615f3c2dcb9dcb0f0576624752afbf9a7f99173b37c4b55b62dd8a" dependencies = [ "bindgen", "lazy_static", @@ -1362,9 +1363,11 @@ checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" name = "ruby_wasm" version = "0.0.0" dependencies = [ + "bytes", "magnus", "structopt", "wasi-vfs-cli", + "wit-component", "wizer", ] @@ -1498,6 +1501,15 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "spdx" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29ef1a0fa1e39ac22972c8db23ff89aea700ab96aa87114e1fb55937a631a0c9" +dependencies = [ + "smallvec", +] + [[package]] name = "sptr" version = "0.3.2" @@ -1892,6 +1904,31 @@ dependencies = [ "leb128", ] +[[package]] +name = "wasm-encoder" +version = "0.203.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87e3b46a0d9d9143d57aa926c42e2af284b5cb8f0c7b71079afc7a6fca42db50" +dependencies = [ + "leb128", +] + +[[package]] +name = "wasm-metadata" +version = "0.203.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19fbd9b7017bdb3ceb63503a18d1aa7b0d026e18ce659d40b93bd9a15391424f" +dependencies = [ + "anyhow", + "indexmap 2.1.0", + "serde", + "serde_derive", + "serde_json", + "spdx", + "wasm-encoder 0.203.0", + "wasmparser 0.203.0", +] + [[package]] name = "wasmparser" version = "0.106.0" @@ -1912,6 +1949,17 @@ dependencies = [ "semver", ] +[[package]] +name = "wasmparser" +version = "0.203.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b473b35fff082e8c8377f4e2c8d48075e562aa051e48a02229bdcafbf349d37" +dependencies = [ + "bitflags 2.4.1", + "indexmap 2.1.0", + "semver", +] + [[package]] name = "wasmprinter" version = "0.2.75" @@ -2002,7 +2050,7 @@ dependencies = [ "syn 2.0.48", "wasmtime-component-util", "wasmtime-wit-bindgen", - "wit-parser", + "wit-parser 0.13.0", ] [[package]] @@ -2255,7 +2303,7 @@ dependencies = [ "anyhow", "heck 0.4.1", "indexmap 2.1.0", - "wit-parser", + "wit-parser 0.13.0", ] [[package]] @@ -2525,6 +2573,25 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "wit-component" +version = "0.203.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "379c4e193d37b3e2c808e99515c2a91dc19e7b3b160adfbb374463875375d6ff" +dependencies = [ + "anyhow", + "bitflags 2.4.1", + "indexmap 2.1.0", + "log", + "serde", + "serde_derive", + "serde_json", + "wasm-encoder 0.203.0", + "wasm-metadata", + "wasmparser 0.203.0", + "wit-parser 0.203.0", +] + [[package]] name = "wit-parser" version = "0.13.0" @@ -2542,6 +2609,24 @@ dependencies = [ "unicode-xid", ] +[[package]] +name = "wit-parser" +version = "0.203.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f547f9154c0fbd020c81c348d703b549bafd16ea68b15927acb5c890467e734" +dependencies = [ + "anyhow", + "id-arena", + "indexmap 2.1.0", + "log", + "semver", + "serde", + "serde_derive", + "serde_json", + "unicode-xid", + "wasmparser 0.203.0", +] + [[package]] name = "witx" version = "0.9.1" diff --git a/Gemfile b/Gemfile index c503a8ce32..9280078ddf 100644 --- a/Gemfile +++ b/Gemfile @@ -7,7 +7,7 @@ gemspec group :development do gem "rake" gem "rake-compiler" - gem "rb_sys", "0.9.85" + gem "rb_sys", "0.9.97" end group :check do diff --git a/ext/ruby_wasm/Cargo.toml b/ext/ruby_wasm/Cargo.toml index 8aa032fa3f..7d759919a4 100644 --- a/ext/ruby_wasm/Cargo.toml +++ b/ext/ruby_wasm/Cargo.toml @@ -10,7 +10,9 @@ publish = false crate-type = ["cdylib"] [dependencies] -magnus = "0.6.2" +magnus = { version = "0.6.2", features = ["bytes"] } +bytes = "1" wizer = "4.0.0" wasi-vfs-cli = { git = "https://github.com/kateinoigakukun/wasi-vfs/", tag = "0.5.2" } structopt = "0.3.26" +wit-component = "0.203.0" diff --git a/ext/ruby_wasm/src/lib.rs b/ext/ruby_wasm/src/lib.rs index b6c39a708c..909a24d20b 100644 --- a/ext/ruby_wasm/src/lib.rs +++ b/ext/ruby_wasm/src/lib.rs @@ -6,13 +6,13 @@ use magnus::{ value::{self, InnerValue}, wrap, Error, ExceptionClass, RModule, Ruby, }; -use wizer::Wizer; use structopt::StructOpt; +use wizer::Wizer; static RUBY_WASM: value::Lazy = value::Lazy::new(|ruby| ruby.define_module("RubyWasmExt").unwrap()); -fn preinit(core_module: Vec) -> Result, Error> { +fn preinit(core_module: bytes::Bytes) -> Result { let rbwasm_error = eval("RubyWasmExt::Error")?; let rbwasm_error = ExceptionClass::from_value(rbwasm_error).unwrap(); let mut wizer = Wizer::new(); @@ -26,6 +26,7 @@ fn preinit(core_module: Vec) -> Result, Error> { wizer .run(&core_module) .map_err(|e| Error::new(rbwasm_error, format!("failed to run wizer: {}", e))) + .map(|output| output.into()) } struct WasiVfsInner { @@ -53,14 +54,91 @@ impl WasiVfs { self.0.borrow_mut().map_dirs.push((guest_dir.into(), host_dir.into())); } - fn pack(&self, wasm_bytes: Vec) -> Result, Error> { + fn pack(&self, wasm_bytes: bytes::Bytes) -> Result { let output_bytes = wasi_vfs_cli::pack(&wasm_bytes, self.0.borrow().map_dirs.clone()).map_err(|e| { Error::new( exception::standard_error(), format!("failed to pack wasi vfs: {}", e), ) })?; - Ok(output_bytes) + Ok(output_bytes.into()) + } +} + +#[wrap(class = "RubyWasmExt::ComponentLink")] +struct ComponentLink(std::cell::RefCell>); + +impl ComponentLink { + fn new() -> Self { + Self(std::cell::RefCell::new(Some(wit_component::Linker::default()))) + } + fn linker(&self, body: impl FnOnce(wit_component::Linker) -> Result) -> Result<(), Error> { + let mut linker = self.0.take().ok_or_else(|| { + Error::new( + exception::standard_error(), + "linker is already consumed".to_string(), + ) + })?; + linker = body(linker)?; + self.0.replace(Some(linker)); + Ok(()) + } + + fn library(&self, name: String, module: bytes::Bytes, dl_openable: bool) -> Result<(), Error> { + self.linker(|linker| { + linker.library(&name, &module, dl_openable).map_err(|e| { + Error::new( + exception::standard_error(), + format!("failed to link library: {}", e), + ) + }) + }) + } + fn adapter(&self, name: String, module: bytes::Bytes) -> Result<(), Error> { + self.linker(|linker| { + linker.adapter(&name, &module).map_err(|e| { + Error::new( + exception::standard_error(), + format!("failed to link adapter: {}", e), + ) + }) + }) + } + fn validate(&self, validate: bool) -> Result<(), Error> { + self.linker(|linker| { + Ok(linker.validate(validate)) + }) + } + fn stack_size(&self, size: u32) -> Result<(), Error> { + self.linker(|linker| { + Ok(linker.stack_size(size)) + }) + } + fn stub_missing_functions(&self, stub: bool) -> Result<(), Error> { + self.linker(|linker| { + Ok(linker.stub_missing_functions(stub)) + }) + } + fn use_built_in_libdl(&self, use_libdl: bool) -> Result<(), Error> { + self.linker(|linker| { + Ok(linker.use_built_in_libdl(use_libdl)) + }) + } + fn encode(&self) -> Result { + // Take the linker out of the cell and consume it + let linker = self.0.borrow_mut().take().ok_or_else(|| { + Error::new( + exception::standard_error(), + "linker is already consumed".to_string(), + ) + })?; + let encoded = linker.encode().map_err(|e| { + Error::new( + exception::standard_error(), + format!("failed to encode linker: {}", e), + ) + })?; + Ok(encoded.into()) } } @@ -76,5 +154,16 @@ fn init(ruby: &Ruby) -> Result<(), Error> { wasi_vfs.define_singleton_method("run_cli", function!(WasiVfs::run_cli, 1))?; wasi_vfs.define_method("map_dir", method!(WasiVfs::map_dir, 2))?; wasi_vfs.define_method("pack", method!(WasiVfs::pack, 1))?; + + let component_link = module.define_class("ComponentLink", ruby.class_object())?; + component_link.define_singleton_method("new", function!(ComponentLink::new, 0))?; + component_link.define_method("library", method!(ComponentLink::library, 3))?; + component_link.define_method("adapter", method!(ComponentLink::adapter, 2))?; + component_link.define_method("validate", method!(ComponentLink::validate, 1))?; + component_link.define_method("stack_size", method!(ComponentLink::stack_size, 1))?; + component_link.define_method("stub_missing_functions", method!(ComponentLink::stub_missing_functions, 1))?; + component_link.define_method("use_built_in_libdl", method!(ComponentLink::use_built_in_libdl, 1))?; + component_link.define_method("encode", method!(ComponentLink::encode, 0))?; + Ok(()) } diff --git a/lib/ruby_wasm.rb b/lib/ruby_wasm.rb index fb94e0478a..a586a5b670 100644 --- a/lib/ruby_wasm.rb +++ b/lib/ruby_wasm.rb @@ -4,6 +4,7 @@ require_relative "ruby_wasm/util" require_relative "ruby_wasm/build" require_relative "ruby_wasm/packager" +require_relative "ruby_wasm/packager/component_adapter" require_relative "ruby_wasm/packager/file_system" require_relative "ruby_wasm/packager/core" diff --git a/lib/ruby_wasm/build/product/crossruby.rb b/lib/ruby_wasm/build/product/crossruby.rb index f28c3da94d..cb789bdc7c 100644 --- a/lib/ruby_wasm/build/product/crossruby.rb +++ b/lib/ruby_wasm/build/product/crossruby.rb @@ -44,12 +44,15 @@ def build(executor, crossruby) objdir = product_build_dir crossruby executor.mkdir_p objdir do_extconf executor, crossruby + + executor.system "make", "-C", objdir, *make_args(crossruby), "clean" + build_target = crossruby.target.pic? ? "install-so" : "static" executor.system "make", "-j#{executor.process_count}", "-C", "#{objdir}", *make_args(crossruby), - "static" + build_target # A ext can provide link args by link.filelist. It contains only built archive file by default. unless File.exist?(linklist(crossruby)) executor.write( @@ -60,6 +63,23 @@ def build(executor, crossruby) end def do_extconf(executor, crossruby) + unless crossruby.target.pic? + self.do_legacy_extconf(executor, crossruby) + return + end + objdir = product_build_dir crossruby + source = crossruby.source + rbconfig_rb = Dir.glob(File.join(crossruby.dest_dir, "usr/local/lib/ruby/*/wasm32-wasi/rbconfig.rb")).first + raise "rbconfig.rb not found" unless rbconfig_rb + extconf_args = [ + "-C", objdir, + "#{@srcdir}/extconf.rb", + "--target-rbconfig=#{rbconfig_rb}", + ] + executor.system Gem.ruby, *extconf_args + end + + def do_legacy_extconf(executor, crossruby) objdir = product_build_dir crossruby source = crossruby.source extconf_args = [ @@ -114,7 +134,7 @@ def cache_key(digest) end class CrossRubyProduct < AutoconfProduct - attr_reader :source, :toolchain + attr_reader :target, :source, :toolchain attr_accessor :user_exts, :wasmoptflags, :cppflags, @@ -155,6 +175,10 @@ def need_exts_build? @user_exts.any? end + def need_extinit_obj? + need_exts_build? && !@target.pic? + end + def build_exts(executor) @user_exts.each do |prod| executor.begin_section prod.class, prod.name, "Building" @@ -181,7 +205,7 @@ def build(executor, remake: false, reconfigure: false) executor.begin_section self.class, name, "Building" - if need_exts_build? + if need_extinit_obj? executor.mkdir_p File.dirname(extinit_obj) executor.system "ruby", extinit_c_erb, @@ -312,7 +336,7 @@ def configure_args(build_triple, toolchain) args.concat(self.tools_args) (@user_exts || []).each { |lib| xldflags << "@#{lib.linklist(self)}" } - xldflags << extinit_obj if need_exts_build? + xldflags << extinit_obj if need_extinit_obj? cflags = @cflags.dup xcflags = @xcflags.dup diff --git a/lib/ruby_wasm/cli.rb b/lib/ruby_wasm/cli.rb index f0f1001e17..89ba1d3912 100644 --- a/lib/ruby_wasm/cli.rb +++ b/lib/ruby_wasm/cli.rb @@ -122,8 +122,19 @@ def build(args) end .parse!(args) + __skip__ = if defined?(Bundler) + Bundler.settings.temporary(force_ruby_platform: true) do + do_build_with_force_ruby_platform(options) + end + else + do_build_with_force_ruby_platform(options) + end + end + + def do_build_with_force_ruby_platform(options) verbose = RubyWasm.logger.level == :debug executor = RubyWasm::BuildExecutor.new(verbose: verbose) + packager = self.derive_packager(options) if options[:print_ruby_cache_key] @@ -281,7 +292,7 @@ def self.bundled_patches_path end def derive_packager(options) - definition = nil + __skip__ = definition = nil __skip__ = if defined?(Bundler) && !options[:disable_gems] begin # Silence Bundler UI if --print-ruby-cache-key is specified not to bother the JSON output. @@ -293,6 +304,7 @@ def derive_packager(options) Bundler.ui.level = old_level end end + RubyWasm.logger.info "Using Gemfile: #{definition.gemfiles}" if definition RubyWasm::Packager.new(root, build_config(options), definition) end @@ -315,9 +327,9 @@ def do_build(executor, tmpdir, packager, options) RubyWasm.logger.info "Size: #{SizeFormatter.format(wasm_bytes.size)}" case options[:output] when "-" - @stdout.write wasm_bytes.pack("C*") + @stdout.write wasm_bytes else - File.binwrite(options[:output], wasm_bytes.pack("C*")) + File.binwrite(options[:output], wasm_bytes) RubyWasm.logger.debug "Wrote #{options[:output]}" end end diff --git a/lib/ruby_wasm/packager.rb b/lib/ruby_wasm/packager.rb index 7706c5ba58..c8ca59b3dc 100644 --- a/lib/ruby_wasm/packager.rb +++ b/lib/ruby_wasm/packager.rb @@ -27,9 +27,7 @@ def package(executor, dest_dir, options) fs = RubyWasm::Packager::FileSystem.new(dest_dir, self) fs.package_ruby_root(tarball, executor) - - ruby_wasm_bin = File.expand_path("bin/ruby", fs.ruby_root) - wasm_bytes = File.binread(ruby_wasm_bin).bytes + wasm_bytes = ruby_core.build_and_link_exts(executor) fs.package_gems fs.remove_non_runtime_files(executor) @@ -58,7 +56,9 @@ def ruby_core_build # Retrieves the specs from the Bundler definition, excluding the excluded gems. def specs return [] unless @definition - @definition.specs.reject { |spec| EXCLUDED_GEMS.include?(spec.name) } + @specs ||= @definition.resolve.materialize(@definition.requested_dependencies) + .reject { |spec| EXCLUDED_GEMS.include?(spec.name) } + @specs end # Checks if dynamic linking is supported. diff --git a/lib/ruby_wasm/packager/component_adapter.rb b/lib/ruby_wasm/packager/component_adapter.rb new file mode 100644 index 0000000000..6cd722a710 --- /dev/null +++ b/lib/ruby_wasm/packager/component_adapter.rb @@ -0,0 +1,14 @@ +module RubyWasm::Packager::ComponentAdapter + module_function + + # The path to the component adapter for the given WASI execution model. + # + # @param exec_model [String] "command" or "reactor" + def wasi_snapshot_preview1(exec_model) + File.join( + File.dirname(__FILE__), + "component_adapter", + "wasi_snapshot_preview1.#{exec_model}.wasm" + ) + end +end diff --git a/lib/ruby_wasm/packager/component_adapter/wasi_snapshot_preview1.command.wasm b/lib/ruby_wasm/packager/component_adapter/wasi_snapshot_preview1.command.wasm new file mode 100644 index 0000000000..c5490babbb Binary files /dev/null and b/lib/ruby_wasm/packager/component_adapter/wasi_snapshot_preview1.command.wasm differ diff --git a/lib/ruby_wasm/packager/component_adapter/wasi_snapshot_preview1.reactor.wasm b/lib/ruby_wasm/packager/component_adapter/wasi_snapshot_preview1.reactor.wasm new file mode 100644 index 0000000000..e2a3f4dc95 Binary files /dev/null and b/lib/ruby_wasm/packager/component_adapter/wasi_snapshot_preview1.reactor.wasm differ diff --git a/lib/ruby_wasm/packager/core.rb b/lib/ruby_wasm/packager/core.rb index c3c79ef754..4cc533b905 100644 --- a/lib/ruby_wasm/packager/core.rb +++ b/lib/ruby_wasm/packager/core.rb @@ -12,7 +12,7 @@ def build(executor, options) extend Forwardable - def_delegators :build_strategy, :cache_key, :artifact + def_delegators :build_strategy, :cache_key, :artifact, :build_and_link_exts private @@ -37,6 +37,10 @@ def build(executor, options) raise NotImplementedError end + def build_and_link_exts(executor) + raise NotImplementedError + end + # Array of paths to extconf.rb files. def specs_with_extensions @packager.specs.filter_map do |spec| @@ -66,6 +70,7 @@ def build(executor, options) force_rebuild = options[:remake] || options[:clean] || options[:reconfigure] if File.exist?(build.crossruby.artifact) && !force_rebuild + # Always build extensions because they are usually not expensive to build return build.crossruby.artifact end build.crossruby.clean(executor) if options[:clean] @@ -88,8 +93,68 @@ def build(executor, options) build.crossruby.artifact end - def build_exts(build) - specs_with_extensions.flat_map do |spec, exts| + def build_and_link_exts(executor) + build = derive_build + self.build_exts(executor, build) + self.link_exts(executor, build) + end + + def link_exts(executor, build) + ruby_root = build.crossruby.dest_dir + + libraries = [File.join(ruby_root, "usr", "local", "bin", "ruby")] + + # TODO: Should be computed from dyinfo of ruby binary + wasi_libc_shared_libs = [ + "libc.so", + "libwasi-emulated-getpid.so", + "libwasi-emulated-mman.so", + "libwasi-emulated-process-clocks.so", + "libwasi-emulated-signal.so", + ] + + wasi_libc_shared_libs.each do |lib| + # @type var toolchain: RubyWasm::WASISDK + toolchain = build.toolchain + wasi_sdk_path = toolchain.wasi_sdk_path + libraries << File.join(wasi_sdk_path, "share/wasi-sysroot/lib/wasm32-wasi", lib) + end + wasi_adapter = RubyWasm::Packager::ComponentAdapter.wasi_snapshot_preview1("command") + adapters = [wasi_adapter] + dl_openable_libs = Dir.glob(File.join(ruby_root, "usr", "local", "lib", "ruby", "**", "*.so")) + linker = RubyWasmExt::ComponentLink.new + linker.use_built_in_libdl(true) + linker.stub_missing_functions(false) + linker.validate(true) + + libraries.each do |lib| + # Non-DL openable libraries should be referenced as base name + lib_name = File.basename(lib) + module_bytes = File.binread(lib) + RubyWasm.logger.info "Linking #{lib_name} (#{module_bytes.size} bytes)" + linker.library(lib_name, module_bytes, false) + end + + dl_openable_libs.each do |lib| + # DL openable lib_name should be a relative path from ruby_root + lib_name = "/" + Pathname.new(lib).relative_path_from(Pathname.new(ruby_root)).to_s + module_bytes = File.binread(lib) + RubyWasm.logger.info "Linking #{lib_name} (#{module_bytes.size} bytes)" + linker.library(lib_name, module_bytes, true) + end + + adapters.each do |adapter| + adapter_name = File.basename(adapter) + # e.g. wasi_snapshot_preview1.command.wasm -> wasi_snapshot_preview1 + adapter_name = adapter_name.split(".")[0] + module_bytes = File.binread(adapter) + linker.adapter(adapter_name, module_bytes) + end + return linker.encode() + end + + def build_exts(executor, build) + exts = specs_with_extensions.flat_map do |spec, exts| exts.map do |ext| ext_feature = File.dirname(ext) # e.g. "ext/cgi/escape" ext_srcdir = File.join(spec.full_gem_path, ext_feature) @@ -101,6 +166,12 @@ def build_exts(build) ) end end + + exts.each do |prod| + executor.begin_section prod.class, prod.name, "Building" + prod.build(executor, build.crossruby) + executor.end_section prod.class, prod.name + end end def cache_key(digest) @@ -127,7 +198,7 @@ def derive_build build.crossruby.cflags = %w[-fPIC -fvisibility=default] if @packager.full_build_options[:target] != "wasm32-unknown-emscripten" build.crossruby.debugflags = %w[-g] - build.crossruby.wasmoptflags = %w[-O3 -g] + build.crossruby.wasmoptflags = %w[-O3 -g --pass-arg=asyncify-relocatable] build.crossruby.ldflags = %w[ -Xlinker --stack-first @@ -225,6 +296,12 @@ def derive_build build end + def build_and_link_exts(executor) + build = derive_build + ruby_root = build.crossruby.dest_dir + File.binread(File.join(ruby_root, "usr", "local", "bin", "ruby")) + end + def user_exts(build) @user_exts ||= specs_with_extensions.flat_map do |spec, exts| diff --git a/lib/ruby_wasm/packager/file_system.rb b/lib/ruby_wasm/packager/file_system.rb index 955354ef7f..45dd06723e 100644 --- a/lib/ruby_wasm/packager/file_system.rb +++ b/lib/ruby_wasm/packager/file_system.rb @@ -65,12 +65,14 @@ def setup_rb_content end def remove_non_runtime_files(executor) - %w[ - **/*.so + patterns = %w[ usr/local/lib/libruby-static.a usr/local/bin/ruby usr/local/include - ].each do |pattern| + ] + + patterns << "**/*.so" unless @packager.support_dynamic_linking? + patterns.each do |pattern| Dir .glob(File.join(@dest_dir, pattern)) .each do |entry| diff --git a/packages/gems/js/ext/witapi/depend b/packages/gems/js/ext/witapi/depend index 3cc21419b9..01fb6e656a 100644 --- a/packages/gems/js/ext/witapi/depend +++ b/packages/gems/js/ext/witapi/depend @@ -8,4 +8,4 @@ witapi-core.o: $(srcdir)/bindgen/rb-abi-guest.h bindgen/%.o: $(srcdir)/bindgen/%.c @mkdir -p "$(@D)" - $(CC) -c -I$(srcdir)/bindgen -o $@ $< + $(Q) $(CC) $(INCFLAGS) $(CPPFLAGS) $(CFLAGS) $(COUTFLAG)$@ -c $(CSRCFLAG)$< -I$(srcdir)/bindgen diff --git a/rakelib/packaging.rake b/rakelib/packaging.rake index 167fcb9244..7f544fd262 100644 --- a/rakelib/packaging.rake +++ b/rakelib/packaging.rake @@ -154,3 +154,12 @@ namespace :standalone do end end end + +namespace :gem do + task :update_component_adapters do + ["command", "reactor"].each do |exec_model| + sh "curl", "-L", "-o", "lib/ruby_wasm/packager/component_adapter/wasi_snapshot_preview1.#{exec_model}.wasm", + "https://github.com/bytecodealliance/wasmtime/releases/download/v19.0.1/wasi_snapshot_preview1.#{exec_model}.wasm" + end + end +end diff --git a/sig/ruby_wasm/build.rbs b/sig/ruby_wasm/build.rbs index 206fb042ed..c20f3aa36d 100644 --- a/sig/ruby_wasm/build.rbs +++ b/sig/ruby_wasm/build.rbs @@ -170,6 +170,8 @@ module RubyWasm def build: (BuildExecutor executor, CrossRubyProduct crossruby) -> void def do_extconf: (BuildExecutor executor, CrossRubyProduct crossruby) -> void def do_install_rb: (BuildExecutor executor, CrossRubyProduct crossruby) -> void + + private def do_legacy_extconf: (BuildExecutor executor, CrossRubyProduct crossruby) -> void end class CrossRubyProduct < AutoconfProduct @@ -184,6 +186,7 @@ module RubyWasm @openssl: OpenSSLProduct @wasi_vfs: WasiVfsProduct + attr_reader target: Target attr_reader source: BuildSource attr_reader toolchain: Toolchain attr_accessor user_exts: Array[CrossRubyExtProduct] @@ -197,6 +200,7 @@ module RubyWasm def initialize: (BuildParams params, String build_dir, String rubies_dir, BaseRubyProduct baseruby, BuildSource source, Toolchain toolchain) -> void def configure: (BuildExecutor executor, ?reconfigure: bool) -> void def need_exts_build?: -> bool + def need_extinit_obj?: -> bool def build_exts: (BuildExecutor executor) -> void def build: (BuildExecutor executor, ?remake: bool, ?reconfigure: bool) -> void def clean: (BuildExecutor executor) -> void diff --git a/sig/ruby_wasm/ext.rbs b/sig/ruby_wasm/ext.rbs index 8bad0c0e5a..4d2efa4aaa 100644 --- a/sig/ruby_wasm/ext.rbs +++ b/sig/ruby_wasm/ext.rbs @@ -1,5 +1,7 @@ module RubyWasmExt - def self.preinitialize: (Array[Integer] module_bytes) -> Array[Integer] + type bytes = String + + def self.preinitialize: (bytes module_bytes) -> bytes class WasiVfs def initialize: () -> void @@ -8,6 +10,17 @@ module RubyWasmExt def map_dir: (String guest_path, String host_path) -> void - def pack: (Array[Integer] module_bytes) -> Array[Integer] + def pack: (bytes module_bytes) -> bytes + end + + class ComponentLink + def initialize: () -> void + def library: (String name, bytes module, bool dl_openable) -> void + def adapter: (String name, bytes module) -> void + def validate: (bool) -> void + def stack_size: (Integer) -> void + def stub_missing_functions: (bool) -> void + def use_built_in_libdl: (bool) -> void + def encode: () -> bytes end end diff --git a/sig/ruby_wasm/packager.rbs b/sig/ruby_wasm/packager.rbs index f973353bde..a80bcfeb66 100644 --- a/sig/ruby_wasm/packager.rbs +++ b/sig/ruby_wasm/packager.rbs @@ -20,12 +20,14 @@ class RubyWasm::Packager type build_config = Hash[untyped, untyped] + type bytes = String + @definition: untyped @config: build_config def initialize: (string root, build_config?, untyped? definition) -> void - def package: (RubyWasm::BuildExecutor, string dest_dir, untyped options) -> Array[Integer] + def package: (RubyWasm::BuildExecutor, string dest_dir, untyped options) -> bytes @ruby_core_build: RubyWasm::Packager::Core? def ruby_core_build: () -> RubyWasm::Packager::Core @@ -48,6 +50,7 @@ class RubyWasm::Packager @packager: RubyWasm::Packager def initialize: (RubyWasm::Packager) -> void def build: (RubyWasm::BuildExecutor, untyped options) -> String + def build_and_link_exts: (RubyWasm::BuildExecutor) -> bytes extend Forwardable @@ -63,12 +66,16 @@ class RubyWasm::Packager def initialize: (RubyWasm::Packager) -> void def build: (RubyWasm::BuildExecutor, untyped options) -> String def specs_with_extensions: () -> Array[[untyped, Array[string]]] + def build_and_link_exts: (RubyWasm::BuildExecutor) -> bytes end class DynamicLinking < RubyWasm::Packager::Core::BuildStrategy @build: RubyWasm::Build def derive_build: () -> RubyWasm::Build + def build_exts: (RubyWasm::BuildExecutor, RubyWasm::Build) -> void def name: () -> string + + private def link_exts: (RubyWasm::BuildExecutor, RubyWasm::Build) -> bytes end class StaticLinking < RubyWasm::Packager::Core::BuildStrategy @@ -108,4 +115,8 @@ class RubyWasm::Packager def ruby_version: () -> String def rubyarchdir: () -> String end + + module ComponentAdapter + def self.wasi_snapshot_preview1: (String exec_model) -> String + end end