diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 1808cc17050..41dc932c5ed 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -247,6 +247,53 @@ jobs: path: ./target/libmozjs-${{ matrix.target }}.tar.gz name: libmozjs-${{ matrix.target }}.tar.gz + wasi: + name: wasm32-${{ matrix.target }} + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + target: + - wasip1 + - wasip2 + steps: + - uses: actions/checkout@v4 + - name: Install Rust + uses: dtolnay/rust-toolchain@master + id: toolchain + with: + toolchain: "1.85.0" + targets: "wasm32-${{ matrix.target }}" + - uses: bytecodealliance/actions/wasmtime/setup@v1 + - name: Install WASI-SDK + run: | + cd /tmp + curl --retry 5 --retry-all-errors -OL https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-25/wasi-sdk-25.0-x86_64-linux.tar.gz + tar -xzf wasi-sdk-25.0-x86_64-linux.tar.gz + mv wasi-sdk-25.0-x86_64-linux wasi-sdk + - name: Build + run: | + cargo +${{ steps.toolchain.outputs.name }} build --target=wasm32-${{ matrix.target }} + env: + WASI_SDK_PATH: "/tmp/wasi-sdk" + - name: Test + run: | + export CARGO_TARGET_WASM32_WASIP1_RUNNER="wasmtime run --dir=$PWD::/cwd" + export CARGO_TARGET_WASM32_WASIP2_RUNNER="wasmtime run --dir=$PWD::/cwd" + cargo +${{ steps.toolchain.outputs.name }} test --tests --examples --target=wasm32-${{ matrix.target }} + env: + WASI_SDK_PATH: "/tmp/wasi-sdk" + - name: Generate artifact attestation + uses: actions/attest-build-provenance@v1 + if: ${{ inputs.release }} + with: + subject-path: "./target/libmozjs-wasm32-${{ matrix.target }}.tar.gz" + - name: Upload artifact + uses: actions/upload-artifact@v4 + with: + path: ./target/libmozjs-wasm32-${{ matrix.target }}.tar.gz + name: libmozjs-wasm32-${{ matrix.target }}.tar.gz + linux-cross-compile: name: linux (${{ matrix.target }}) runs-on: ubuntu-latest diff --git a/mozjs-sys/Cargo.toml b/mozjs-sys/Cargo.toml index 053598385d3..9935a559d19 100644 --- a/mozjs-sys/Cargo.toml +++ b/mozjs-sys/Cargo.toml @@ -2,7 +2,7 @@ name = "mozjs_sys" description = "System crate for the Mozilla SpiderMonkey JavaScript engine." repository.workspace = true -version = "0.140.0-5" +version = "0.140.0-6" authors = ["Mozilla", "The Servo Project Developers"] links = "mozjs" license.workspace = true diff --git a/mozjs-sys/build.rs b/mozjs-sys/build.rs index 8321c3e9ff0..479103440dd 100644 --- a/mozjs-sys/build.rs +++ b/mozjs-sys/build.rs @@ -45,6 +45,7 @@ const SM_TARGET_ENV_VARS: &'static [&'static str] = &[ "CXXFLAGS", "READELF", "OBJCOPY", + "WASI_SDK_PATH", ]; const EXTRA_FILES: &'static [&'static str] = &["makefile.cargo"]; @@ -60,6 +61,18 @@ fn main() { // https://github.com/servo/servo/issues/14759 env::set_var("MOZ_NO_DEBUG_RTL", "1"); + if let Some(path) = wasi_sdk() { + env::set_var( + "WASI_SYSROOT", + PathBuf::from(&path).join("share").join("wasi-sysroot"), + ); + env::set_var("TARGET_CC", PathBuf::from(&path).join("bin").join("clang")); + env::set_var( + "TARGET_CXX", + PathBuf::from(&path).join("bin").join("clang++"), + ); + } + let out_dir = PathBuf::from(env::var_os("OUT_DIR").unwrap()); let build_dir = out_dir.join("build"); @@ -209,7 +222,9 @@ fn build_spidermonkey(build_dir: &Path) { pkg_config_path.push(":"); pkg_config_path.push(env_pkg_config_path); } - cmd.env("PKG_CONFIG_PATH", pkg_config_path); + cmd.env("PKG_CONFIG_PATH", &pkg_config_path); + // If we are cross compiling, we have patched SM to use this env var instead of empty string + cmd.env("TARGET_PKG_CONFIG_PATH", pkg_config_path); } if let Ok(include) = env::var("DEP_Z_INCLUDE") { @@ -342,6 +357,12 @@ fn build_bindings(build_dir: &Path, target: BuildTarget) { .formatter(Formatter::Rustfmt) .clang_args(cc_flags(true)); + if env::var("TARGET").unwrap().contains("wasi") { + builder = builder + .clang_arg("--sysroot") + .clang_arg(env::var("WASI_SYSROOT").unwrap().to_string()); + } + if target == BuildTarget::JSGlue { builder = builder .parse_callbacks(Box::new(JSGlueCargoCallbacks::default())) @@ -437,9 +458,15 @@ fn link_static_lib_binaries(build_dir: &Path) { println!("cargo:rustc-link-lib=c++"); } else if target.contains("windows") && target.contains("gnu") { println!("cargo:rustc-link-lib=stdc++"); - } else if !target.contains("windows") { + } else if !target.contains("windows") && !target.contains("wasi") { + // The build works without this for WASI, and specifying it means + // needing to use the WASI-SDK's clang for linking, which is annoying. println!("cargo:rustc-link-lib=stdc++") } + + if target.contains("wasi") { + println!("cargo:rustc-link-lib=wasi-emulated-getpid"); + } } fn link_bindgen_static_lib_binaries(build_dir: &Path) { @@ -518,6 +545,13 @@ fn cc_flags(bindgen: bool) -> Vec<&'static str> { if env::var_os("CARGO_FEATURE_PROFILEMOZJS").is_some() { flags.push("-fno-omit-frame-pointer"); } + + if target.contains("wasi") { + // Unconditionally target p1 for now. Even if the application + // targets p2, an adapter will take care of it. + flags.push("--target=wasm32-wasip1"); + flags.push("-fvisibility=default"); + } } flags.extend(&["-DSTATIC_JS_API", "-DRUST_BINDGEN"]); @@ -541,6 +575,10 @@ fn cc_flags(bindgen: bool) -> Vec<&'static str> { flags.push("-stdlib=libc++"); } + if target.contains("wasi") { + flags.push("-D_WASI_EMULATED_GETPID"); + } + flags } @@ -561,6 +599,14 @@ fn js_config_path(build_dir: &Path) -> String { .to_string() } +fn wasi_sdk() -> Option { + if env::var("TARGET").unwrap().contains("wasi") { + get_cc_rs_env_os("WASI_SDK_PATH") + } else { + None + } +} + #[derive(Clone, Copy, Debug, Eq, PartialEq)] enum BuildTarget { JSApi, diff --git a/mozjs-sys/etc/patches/0033-zlib.patch b/mozjs-sys/etc/patches/0033-zlib.patch index 94bcfa2fb10..939f02a6c88 100644 --- a/mozjs-sys/etc/patches/0033-zlib.patch +++ b/mozjs-sys/etc/patches/0033-zlib.patch @@ -95,3 +95,16 @@ index c6305ec3d..62adc8d84 100644 /* * If you *really* need a unique prefix for all types and library functions, * compile with -DZ_PREFIX. The "standard" zlib should be compiled without it. +diff --git a/build/moz.configure/pkg.configure b/build/moz.configure/pkg.configure +index 418331b87..9ae5b1eee 100644 +--- a/build/moz.configure/pkg.configure ++++ b/build/moz.configure/pkg.configure +@@ -69,7 +69,7 @@ def pkg_config_vars(target, sysroot_path, multiarch_dir): + if target.bitness == 64: + pkgconfig_dirs.insert(0, "usr/lib64/pkgconfig") + return namespace( +- PKG_CONFIG_PATH="", ++ PKG_CONFIG_PATH=environ.get("TARGET_PKG_CONFIG_PATH", ""), + PKG_CONFIG_SYSROOT_DIR=sysroot_path, + PKG_CONFIG_LIBDIR=pathsep.join( + os.path.join(sysroot_path, d) for d in pkgconfig_dirs diff --git a/mozjs-sys/makefile.cargo b/mozjs-sys/makefile.cargo index e324e4afedc..303df1f2c63 100644 --- a/mozjs-sys/makefile.cargo +++ b/mozjs-sys/makefile.cargo @@ -20,7 +20,13 @@ ifeq (,$(CARGO_FEATURE_INTL)) endif ifneq (,$(CARGO_FEATURE_DEBUGMOZJS)) - CONFIGURE_FLAGS += --enable-debug --disable-optimize --enable-gczeal + CONFIGURE_FLAGS += --enable-debug --enable-gczeal + ifneq (,$(findstring -wasi,$(TARGET))) + # wasm-opt chokes on -O0 builds. + CONFIGURE_FLAGS += --enable-optimize=-O1 + else + CONFIGURE_FLAGS += --disable-optimize + endif endif ifneq (,$(CARGO_FEATURE_PROFILEMOZJS)) @@ -76,6 +82,32 @@ ifneq ($(HOST),$(TARGET)) TARGET = aarch64-linux-gnu endif + ifneq (,$(findstring -wasi,$(TARGET))) + ifeq (,$(WASI_SDK_PATH)) + $(error WASI_SDK_PATH environment variable must be set when building for wasm32) + endif + WASI_SYSROOT = $(WASI_SDK_PATH)/share/wasi-sysroot + CC = $(WASI_SDK_PATH)/bin/clang + CPP = $(WASI_SDK_PATH)/bin/clang -E + CXX = $(WASI_SDK_PATH)/bin/clang++ + AR = $(WASI_SDK_PATH)/bin/ar + HOST_CC = clang + HOST_CXX = clang++ + CONFIGURE_FLAGS += \ + --enable-portable-baseline-interp \ + --disable-clang-plugin \ + --disable-jit \ + --disable-shared-memory \ + --with-sysroot=$(WASI_SDK_PATH)/share/wasi-sysroot \ + $(NULL) + # LTO makes `cargo test --wasm32-wasi` take a very very long time. Since build scripts + # don't have a way to detect if the build is for `cargo test`, enable LTO for release + # builds only. + ifneq (debug,$(PROFILE)) + CONFIGURE_FLAGS += --lto=thin + endif + endif + ifeq (android,$(findstring android,$(TARGET))) # Force use of lld on android. Mozilla build system tries to use # gold or bfd linker on Android to support their 'elfhack'functionality in @@ -154,7 +186,7 @@ all: maybe-configure JSSRC := '$(SRC_DIR)'/js/src # Keep track of all input variables to configure, so we don't skip reconfigure # when we do need to reconfigure -CONFIGURE_INPUTS := "$(CC)$(CFLAGS)$(CPP)$(CPPFLAGS)$(CXX)$(CXXFLAGS)$(AS)$(AR)$(CONFIGURE_FLAGS)" +CONFIGURE_INPUTS := "$(CC)$(CFLAGS)$(CPP)$(CPPFLAGS)$(CXX)$(CXXFLAGS)$(AS)$(AR)$(HOST_CC)$(HOST_CXX)$(WASI_SYSROOT)$(CONFIGURE_FLAGS)" LAST_CONFIGURE_INPUTS := "$(shell cat reconfigure.inputs)" maybe-configure: [[ $(JSSRC)/configure -ot $(JSSRC)/configure.in ]] && touch $(JSSRC)/configure || true @@ -165,6 +197,9 @@ maybe-configure: CC="$(CC)" CFLAGS="$(CFLAGS)" \ CPP="$(CPP)" CPPFLAGS="$(CPPFLAGS)" \ CXX="$(CXX)" CXXFLAGS="$(CXXFLAGS)" \ + HOST_CC="$(HOST_CC)" \ + HOST_CXX="$(HOST_CXX)" \ + WASI_SYSROOT="$(WASI_SYSROOT)" \ AS="$(AS)" AR="$(AR)" \ $(JSSRC)/configure $(strip $(CONFIGURE_FLAGS)) || (cat config.log && exit 1) ; \ fi diff --git a/mozjs-sys/mozjs/build/moz.configure/pkg.configure b/mozjs-sys/mozjs/build/moz.configure/pkg.configure index 418331b874f..9ae5b1eee1c 100644 --- a/mozjs-sys/mozjs/build/moz.configure/pkg.configure +++ b/mozjs-sys/mozjs/build/moz.configure/pkg.configure @@ -69,7 +69,7 @@ def pkg_config_vars(target, sysroot_path, multiarch_dir): if target.bitness == 64: pkgconfig_dirs.insert(0, "usr/lib64/pkgconfig") return namespace( - PKG_CONFIG_PATH="", + PKG_CONFIG_PATH=environ.get("TARGET_PKG_CONFIG_PATH", ""), PKG_CONFIG_SYSROOT_DIR=sysroot_path, PKG_CONFIG_LIBDIR=pathsep.join( os.path.join(sysroot_path, d) for d in pkgconfig_dirs diff --git a/mozjs-sys/src/jsglue.cpp b/mozjs-sys/src/jsglue.cpp index 2f0c60bfba4..71b65321aa3 100644 --- a/mozjs-sys/src/jsglue.cpp +++ b/mozjs-sys/src/jsglue.cpp @@ -883,7 +883,7 @@ bool AppendToRootedObjectVector(JS::PersistentRootedObjectVector* v, void DeleteRootedObjectVector(JS::PersistentRootedObjectVector* v) { delete v; } -#if defined(__linux__) +#if defined(__linux__) || defined(__wasi__) # include #elif defined(__APPLE__) # include @@ -897,7 +897,7 @@ void DeleteRootedObjectVector(JS::PersistentRootedObjectVector* v) { delete v; } // SpiderMonkey-in-Rust currently uses system malloc, not jemalloc. static size_t MallocSizeOf(const void* aPtr) { -#if defined(__linux__) +#if defined(__linux__) || defined(__wasi__) return malloc_usable_size((void*)aPtr); #elif defined(__APPLE__) return malloc_size((void*)aPtr); diff --git a/mozjs/Cargo.toml b/mozjs/Cargo.toml index e6ddd13ac1f..a94f0c15fd0 100644 --- a/mozjs/Cargo.toml +++ b/mozjs/Cargo.toml @@ -27,7 +27,10 @@ libc.workspace = true log = "0.4" mozjs_sys = { path = "../mozjs-sys" } -[dev-dependencies] +[target.'cfg(target_arch = "wasm32")'.dev-dependencies] +criterion = { version = "0.6", default-features = false, features = ["html_reports"] } + +[target.'cfg(not(target_arch = "wasm32"))'.dev-dependencies] criterion = "0.6" [build-dependencies] diff --git a/mozjs/examples/wasm.rs b/mozjs/examples/wasm.rs index 05ef1b027dc..93693c67160 100644 --- a/mozjs/examples/wasm.rs +++ b/mozjs/examples/wasm.rs @@ -6,6 +6,9 @@ //! and do some setup on both of these. You also need to enter a "realm" //! (environment within one global object) before you can execute code. +// The wasm example does not work on wasm32 targets. +#![cfg(not(target_arch = "wasm32"))] + use ::std::ptr; use ::std::ptr::null_mut; diff --git a/mozjs/tests/runtime.rs b/mozjs/tests/runtime.rs index 9588e360187..fe2993655c3 100644 --- a/mozjs/tests/runtime.rs +++ b/mozjs/tests/runtime.rs @@ -2,6 +2,8 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#![cfg(not(target_arch = "wasm32"))] + use std::ptr; use std::sync::mpsc::channel; use std::thread;