diff --git a/.gitattributes b/.gitattributes index 6486387fd29b..4a30688065f1 100644 --- a/.gitattributes +++ b/.gitattributes @@ -2,3 +2,4 @@ CHANGELOG.md merge=union *.wast linguist-vendored *.wat linguist-vendored scene*.txt -text +*.stdin -text diff --git a/.github/ci-constants.env b/.github/ci-constants.env index 163657207d35..6db4329db72a 100644 --- a/.github/ci-constants.env +++ b/.github/ci-constants.env @@ -1,3 +1,5 @@ # Shared CI constants. Loaded into GITHUB_ENV by workflows that need them. # Pinned wasix-libc sysroot (wasix-org/wasix-libc release tag). WASIX_LIBC_SYSROOT_TAG=v2026-07-30.1 +# Pinned WASIX rust toolchain (wasix-org/rust release tag). +WASIX_RUST_TOOLCHAIN_TAG=v2026-08-06.1+rust-1.97 diff --git a/.github/workflows/copilot-setup-steps.yml b/.github/workflows/copilot-setup-steps.yml index 6483727c20d4..e24c1fd0341d 100644 --- a/.github/workflows/copilot-setup-steps.yml +++ b/.github/workflows/copilot-setup-steps.yml @@ -81,6 +81,10 @@ jobs: env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: WASIXCC_SYSROOT_PREFIX=~/.wasixcc/sysroot-v2026-05-12.1 wasixccenv download-sysroot v2026-05-12.1 + - name: Install cargo-wasix + uses: wasix-org/cargo-wasix@main + with: + toolchain-version: ${{ env.WASIX_RUST_TOOLCHAIN_TAG }} - name: Install wasm-tools run: | cargo install --locked wasm-tools @@ -95,6 +99,8 @@ jobs: wasm-tools --version # Check wasixcc is installed wasixcc --version + # Check cargo-wasix is installed + cargo wasix --version # Check wasm-opt is available wasm-opt --version # Check that the repo exists diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index ddd2366a5915..f8693ea6174f 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -113,6 +113,18 @@ jobs: echo "Pinned sysroot ($WASIX_LIBC_SYSROOT_TAG) is older than latest release ($latest)" exit 1 fi + - name: Verify pinned wasix rust toolchain is up to date + shell: bash + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + source .github/ci-constants.env + latest=$(gh release list --exclude-pre-releases --order desc -R wasix-org/rust --json tagName -q '.[0].tagName') + newest=$(printf '%s\n' "$latest" "$WASIX_RUST_TOOLCHAIN_TAG" | sort -V | tail -1) + if [ "$WASIX_RUST_TOOLCHAIN_TAG" != "$newest" ]; then + echo "Pinned rust toolchain ($WASIX_RUST_TOOLCHAIN_TAG) is older than latest release ($latest)" + exit 1 + fi cargo_deny: name: cargo-deny runs-on: ubuntu-22.04 @@ -596,20 +608,26 @@ jobs: - description: "CLI integ. tests" make: test-integration-cli-ci metadata: + # `wasix_rust_toolchain` marks the hosts wasix-org/rust publishes a + # toolchain for, i.e. the ones that collect the Rust wasm_tests + # fixtures (see lib/wasix/tests/wasm_tests/README.md). - build: linux-x64 os: ubuntu-22.04 target: x86_64-unknown-linux-gnu exe: "" + wasix_rust_toolchain: true llvm_url: "https://github.com/wasmerio/llvm-custom-builds/releases/download/22.x/llvm-linux-amd64.tar.xz" - build: linux-arm64 os: ubuntu-22.04-arm target: aarch64-unknown-linux-gnu exe: "" + wasix_rust_toolchain: true llvm_url: "https://github.com/wasmerio/llvm-custom-builds/releases/download/22.x/llvm-linux-aarch64.tar.xz" - build: macos-arm os: depot-macos-14 target: aarch64-apple-darwin exe: "" + wasix_rust_toolchain: true llvm_url: "https://github.com/wasmerio/llvm-custom-builds/releases/download/22.x/llvm-darwin-aarch64.tar.xz" - build: windows-x64 os: windows-2022 @@ -696,6 +714,8 @@ jobs: with: toolchain: ${{ steps.load_toolchain.outputs.rust_toolchain }} target: ${{ matrix.metadata.target }} + # For the wasip1-toolchain variants of the Rust wasm_tests fixtures, which + # build on every platform we support. - name: Install Rust WASI targets if: matrix.stage.make == 'test-all' shell: bash @@ -716,6 +736,12 @@ jobs: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: WASIXCC_SYSROOT_PREFIX=~/.wasixcc/sysroot-v2026-05-12.1 wasixccenv download-sysroot v2026-05-12.1 if: matrix.metadata.build != 'windows-x64' + # For the wasix-toolchain variants of the Rust wasm_tests fixtures. + - name: Install cargo-wasix + if: matrix.stage.make == 'test-all' && matrix.metadata.wasix_rust_toolchain + uses: wasix-org/cargo-wasix@main + with: + toolchain-version: ${{ env.WASIX_RUST_TOOLCHAIN_TAG }} - name: Install LLVM shell: bash if: matrix.metadata.llvm_url diff --git a/Makefile b/Makefile index c44bb2779524..019dbdc98b7f 100644 --- a/Makefile +++ b/Makefile @@ -950,6 +950,9 @@ lint-package-crate: lint-formatting: cargo fmt --all -- --check cargo fmt --manifest-path fuzz/Cargo.toml -- --check + # The wasm_tests Rust fixtures are not part of any crate, so `cargo fmt` + # does not cover them. + cd lib/wasix/tests/wasm_tests && find . -path ./build -prune -o -type f -name '*.rs' -exec rustfmt --edition 2024 --check {} + lint: lint-yamlfmt lint-clang-format lint-formatting lint-packages lint-taplo diff --git a/lib/wasix/tests/wasm_tests/README.md b/lib/wasix/tests/wasm_tests/README.md index 0a0d19bfd262..4f97506131e7 100644 --- a/lib/wasix/tests/wasm_tests/README.md +++ b/lib/wasix/tests/wasm_tests/README.md @@ -10,9 +10,18 @@ The `wasix-wasm` integration test target discovers tests automatically from this directory. Any subdirectory that contains one of these primary files is treated as a test fixture: +- `build.sh` or other `*.sh` primary sources +- `Cargo.toml` - `main.c` - `main.cpp` -- `$name.sh` +- `*.rs` + +Discovery precedence within a fixture directory is: + +1. `*.sh` shell primary sources +2. `Cargo.toml` (full Cargo project) +3. `main.c` / `main.cpp` +4. `*.rs` (each Rust source is an independent test) The harness builds each discovered fixture, runs the resulting `main` module through the WASIX runner, and registers one test per configuration each of the enabled engines. @@ -24,6 +33,9 @@ The supported directives are documented in [`../wasm_tests.rs`](../wasm_tests.rs If a fixture has more than one `.sh` file, each shell file is treated as a primary source, where `build.sh` is the default shell source name. +Fixtures with an explicit `Cargo.toml` are built as full Cargo projects. Directives +can be placed in `##Directive: Args` comments in the manifest. + The former `tests/wasi-fyi` shell suite now lives in [`wasi_fyi/`](./wasi_fyi/) as Rust primary sources with inline directives. @@ -34,7 +46,10 @@ The harness then builds them as follows: - `main.c` is compiled with `CC`, or `wasixcc` if `CC` is unset. - `main.cpp` is compiled with `CXX`, or `wasix++` if `CXX` is unset. -- `*.rs` is compiled with `rustc --target=wasm32-wasip1`. +- `*.rs` is built with `cargo wasix build` using an ephemeral `Cargo.toml` generated + in the build directory. +- `Cargo.toml` fixtures are built with `cargo wasix build` and the single binary + artifact is copied to `main`. - `build.sh` and other shell primary sources are executed with `bash`; the harness sets `CC=wasixcc`, `CXX=wasix++`, and `WASIXCC_DISCARD_UNSUPPORTED_FLAGS=yes`. @@ -50,7 +65,22 @@ the primary source, for example `//#BuildEnv: WASIXCC_PIC=1` in C/C++ sources or These tests run through the normal `wasix` integration test target, so standard Cargo and nextest filtering both work. Before running the suite, make sure `wasixcc` is installed and available in your shell environment. -Rust `.rs` tests also require `rustc` with the `wasm32-wasip1` target installed. +Rust fixtures also require `cargo-wasix` on `PATH` (`cargo install cargo-wasix`). + +Single-file Rust fixtures build with two Rust toolchains by default (see the +`Toolchains` directive): `wasix` (cargo-wasix), which runs on every engine +except Singlepass — the WASIX toolchain emits exception-handling opcodes +Singlepass does not support — and `wasip1` (`rustc --target wasm32-wasip1`, +nightly when the source uses `#![feature(...)]`), which runs on every engine. +The wasip1 variants need `rustup target add wasm32-wasip1` (plus the same +target on nightly). + +We do not publish the WASIX Rust toolchain for every platform yet, so the +`wasix` variants are only collected on hosts that have one: gnu Linux on x86_64 +and aarch64, and macOS on aarch64. They are skipped on musl, which has no +toolchain, and on Windows, which `wasixcc` does not cover either. The `wasip1` +variants build everywhere, so single-file Rust fixtures keep running on those +hosts. On macOS, this suite collects and runs the LLVM variants only because Cranelift exception-handling support is still incomplete there: diff --git a/lib/wasix/tests/wasm_tests/mod.rs b/lib/wasix/tests/wasm_tests/mod.rs index 6a13fbf047e5..8c1b28d2bd4a 100644 --- a/lib/wasix/tests/wasm_tests/mod.rs +++ b/lib/wasix/tests/wasm_tests/mod.rs @@ -5,7 +5,7 @@ //! own arguments, environment setup, expected exit status, and output/file checks. //! //! Directives use `//#Directive: Args` in C/C++/Rust sources and -//! `##Directive: Args` in shell sources. +//! `##Directive: Args` in shell sources and `Cargo.toml` comments. //! //! Supported directives: //! @@ -45,6 +45,11 @@ //! `SkipEngine:{engine}:{reason}` marks the configuration as ignored for //! a given engine (LLVM, Cranelift, V8, Singlepass). //! +//! `Toolchains:{list}` selects which Rust toolchains build a single-file Rust +//! fixture: `wasix` (cargo-wasix; runs on every engine except Singlepass) and +//! `wasip1` (rustc with the wasm32-wasip1 target; runs on every engine). +//! Defaults to `wasix,wasip1` for single-file Rust fixtures. +//! //! `UnixOnly:{bool}` ignores the configuration on non-Unix hosts when true. //! //! `MinimalLibc:{version}` ignores the configuration when the selected sysroot @@ -100,6 +105,20 @@ mod runner; const TESTED_LIBC_VERSIONS: &[Option<&str>] = &[None, Some("v2026-05-12.1")]; +/// Whether the WASIX Rust toolchain is published for this host: we don't +/// provide it for every platform yet. Only the `cargo wasix` variants of the +/// Rust fixtures are gated on it; their `wasm32-wasip1` counterparts build +/// everywhere. Windows is left out on purpose, since `wasixcc` does not cover +/// it either. +const WASIX_RUST_TOOLCHAIN_AVAILABLE: bool = cfg!(any( + all( + target_os = "linux", + target_env = "gnu", + any(target_arch = "x86_64", target_arch = "aarch64") + ), + all(target_os = "macos", target_arch = "aarch64"), +)); + fn should_emit_colour() -> bool { std::io::stdout().is_terminal() || std::env::var("CARGO_TERM_COLOR").as_deref() == Ok("always") @@ -151,6 +170,42 @@ pub enum Engine { V8, } +/// Which Rust toolchain builds a Rust fixture. The WASIX toolchain emits +/// exception-handling opcodes, so its output cannot run on Singlepass; the +/// plain `wasm32-wasip1` rustup target can, and is available on every host +/// platform. +#[derive(Debug, Clone, Copy, PartialEq, Eq, strum::Display, strum::EnumString)] +#[strum(ascii_case_insensitive, serialize_all = "lowercase")] +enum RustToolchain { + Wasix, + Wasip1, +} + +/// Whether `engine` can run wasm produced by a WASIX toolchain (cargo-wasix +/// for Rust fixtures, wasixcc for the rest). Singlepass lacks exception +/// handling, which that output relies on. +fn engine_runs_wasix_output(engine: Engine) -> bool { + #[cfg(feature = "singlepass")] + let is_singlepass = engine == Engine::Singlepass; + #[cfg(not(feature = "singlepass"))] + let is_singlepass = { + let _ = engine; + false + }; + !is_singlepass +} + +impl RustToolchain { + /// Engines that can run this toolchain's output. wasip1-built wasm runs on + /// every engine; WASIX-built wasm cannot run on Singlepass. + fn supports_engine(self, engine: Engine) -> bool { + match self { + Self::Wasix => engine_runs_wasix_output(engine), + Self::Wasip1 => true, + } + } +} + #[derive(Debug, Clone, Copy, PartialEq, Eq, strum::Display, strum::EnumIter, strum::EnumString)] #[strum(ascii_case_insensitive, serialize_all = "lowercase")] enum FileSystemKind { @@ -187,6 +242,8 @@ struct Config { test_name: String, config_name: String, engine: Engine, + rust_toolchain: RustToolchain, + rust_toolchains: Option>, selected_file_system: FileSystemKind, file_systems: Option>, is_abstract: bool, @@ -230,6 +287,8 @@ impl Config { engine: Engine::V8, #[cfg(not(target_os = "windows"))] engine: Engine::Cranelift, + rust_toolchain: RustToolchain::Wasix, + rust_toolchains: None, file_systems: None, selected_file_system: FileSystemKind::Host, is_abstract: false, @@ -271,6 +330,9 @@ impl Config { if let Some(sysroot_version) = &self.sysroot_version { parts.push(sysroot_version.to_string()); } + if self.rust_toolchain != RustToolchain::Wasix { + parts.push(self.rust_toolchain.to_string()); + } parts.push(self.engine.to_string()); parts.join("/") } @@ -308,19 +370,8 @@ fn parse_configs(default_config: &Config) -> Result> { let mut config = default_config.clone(); let mut build_env = Vec::new(); - let directive_prefix = match src_filename - .extension() - .expect("extension expected") - .to_str() - .expect("must be valid string") - { - "c" | "cpp" | "rs" => "//#", - "sh" => "##", - suffix => bail!("unexpected extension '{suffix}' of a primary source: {src_filename:?}"), - }; - for (i, line) in source.lines().enumerate() { - if let Some(rest) = line.trim().strip_prefix(directive_prefix) { + if let Some(rest) = default_config.source.parse_directive_line(line) { process_directive( rest, &mut build_env, @@ -553,6 +604,28 @@ fn process_directive( "DefaultMappedDirectories" => { config.default_mapped_directories = arg.parse::()?; } + "Toolchains" => { + let rust_toolchains = arg + .split(',') + .map(|toolchain| { + toolchain + .trim() + .parse::() + .map_err(|_| anyhow!("unsupported toolchain: '{toolchain}'")) + }) + .collect::>>()?; + ensure!( + !rust_toolchains.is_empty(), + "at least one toolchain must be selected" + ); + if rust_toolchains.contains(&RustToolchain::Wasip1) { + ensure!( + matches!(config.source, PrimarySource::RustSourceFile(_)), + "the wasip1 toolchain is only supported for single-file Rust fixtures" + ); + } + config.rust_toolchains = Some(rust_toolchains); + } "FileSystems" => { config.file_systems = Some(if arg == "all" { FileSystemKind::iter().collect() @@ -657,6 +730,13 @@ fn read_fixture_bytes(test_src_dir: &Path, arg: &str, directive: &str) -> Result .with_context(|| format!("failed to read {directive} {}", path.display())) } +fn parse_cargo_toml_directive_line(line: &str) -> Option<&str> { + let rest = line.trim().strip_prefix("##")?.trim(); + rest.split_once(':').map(|_| rest) +} + +const CARGO_WASIX_ARTIFACT_DIR: &str = "target/wasm32-wasmer-wasi/debug"; + fn rustc_command(toolchain: Option<&str>) -> Command { if let Some(toolchain) = toolchain { // rustc +version multiplexing is unsupported on Windows, use the documented approach: @@ -669,6 +749,90 @@ fn rustc_command(toolchain: Option<&str>) -> Command { } } +fn rustc_wasip1_build_command(build_dir: &Path, source_filename: &str) -> Result { + let primary_source = build_dir.join(source_filename); + let source = std::fs::read_to_string(&primary_source) + .with_context(|| format!("Failed to read {}", primary_source.display()))?; + let mut cmd = rustc_command(source.contains("#![feature(").then_some("nightly")); + cmd.arg("--target=wasm32-wasip1") + .arg("-o") + .arg("main") + .arg(&primary_source) + .current_dir(build_dir); + Ok(cmd) +} + +fn cargo_wasix_build_command(build_dir: &Path) -> Command { + let mut cmd = Command::new("cargo"); + cmd.arg("wasix") + .arg("build") + .current_dir(build_dir) + // Ensure deterministic output location regardless of the caller environment. + .env("CARGO_TARGET_DIR", build_dir.join("target")); + cmd +} + +fn write_ephemeral_cargo_toml(build_dir: &Path, source_filename: &str) -> Result<()> { + let manifest = format!( + r#"[package] +name = "main" +version = "0.0.0" +# 2021 rather than 2024 so fixtures ported from the old direct-rustc build +# (which used edition 2015) can keep their non-unsafe extern blocks. +edition = "2021" + +[[bin]] +name = "main" +path = "{source_filename}" + +[workspace] +"# + ); + fs::write(build_dir.join("Cargo.toml"), manifest) + .with_context(|| format!("failed to write {}", build_dir.join("Cargo.toml").display())) +} + +fn cargo_bin_name_from_manifest(manifest_path: &Path) -> Result { + let contents = fs::read_to_string(manifest_path) + .with_context(|| format!("failed to read {}", manifest_path.display()))?; + let manifest: toml::Value = toml::from_str(&contents).context("failed to parse Cargo.toml")?; + + if let Some(bins) = manifest.get("bin").and_then(|bins| bins.as_array()) { + ensure!( + bins.len() == 1, + "expected exactly one [[bin]] in {}", + manifest_path.display() + ); + return Ok(bins[0] + .get("name") + .and_then(|name| name.as_str()) + .context("[[bin]] is missing name")? + .to_owned()); + } + + manifest + .get("package") + .and_then(|package| package.get("name")) + .and_then(|name| name.as_str()) + .context("missing package.name") + .map(str::to_owned) +} + +fn copy_cargo_wasix_artifact(build_dir: &Path, bin_name: &str) -> Result { + let wasm = build_dir + .join(CARGO_WASIX_ARTIFACT_DIR) + .join(format!("{bin_name}.wasm")); + let main_path = build_dir.join("main"); + fs::copy(&wasm, &main_path).with_context(|| { + format!( + "failed to copy {} to {}", + wasm.display(), + main_path.display() + ) + })?; + Ok(main_path) +} + fn run_build_script(config: &Config) -> anyhow::Result { // First, copy the test source directory to the 'build' subfolder that will // be unique for each configuration of a test. @@ -706,7 +870,9 @@ fn run_build_script(config: &Config) -> anyhow::Result { std::env::var("CXX").unwrap_or_else(|_| "wasix++".to_string()) } PrimarySource::BashScript(_) => unreachable!("handled above"), - PrimarySource::RustSourceFile(_) => unreachable!("handled below"), + PrimarySource::RustSourceFile(_) | PrimarySource::CargoProject => { + unreachable!("handled below") + } }; let mut cmd = Command::new(&compiler); cmd.arg(&primary_source) @@ -716,18 +882,14 @@ fn run_build_script(config: &Config) -> anyhow::Result { .env("WASIXCC_DISCARD_UNSUPPORTED_FLAGS", "yes"); cmd } - PrimarySource::RustSourceFile(filename) => { - let primary_source = build_test_path.join(filename); - let source = std::fs::read_to_string(&primary_source) - .with_context(|| format!("Failed to read {}", primary_source.display()))?; - let mut cmd = rustc_command(source.contains("#![feature(").then_some("nightly")); - cmd.arg("--target=wasm32-wasip1") - .arg("-o") - .arg("main") - .arg(&primary_source) - .current_dir(&build_test_path); - cmd - } + PrimarySource::RustSourceFile(filename) => match config.rust_toolchain { + RustToolchain::Wasix => { + write_ephemeral_cargo_toml(&build_test_path, filename)?; + cargo_wasix_build_command(&build_test_path) + } + RustToolchain::Wasip1 => rustc_wasip1_build_command(&build_test_path, filename)?, + }, + PrimarySource::CargoProject => cargo_wasix_build_command(&build_test_path), }; for (k, v) in &config.build_env { @@ -742,7 +904,24 @@ fn run_build_script(config: &Config) -> anyhow::Result { anyhow::bail!("Build failed for {}", build_test_path.display()); } - Ok(build_test_path.join("main")) + let main_path = match (&config.source, config.rust_toolchain) { + (PrimarySource::RustSourceFile(_), RustToolchain::Wasix) => { + copy_cargo_wasix_artifact(&build_test_path, "main")? + } + (PrimarySource::CargoProject, _) => { + let bin_name = cargo_bin_name_from_manifest(&build_test_path.join("Cargo.toml"))?; + copy_cargo_wasix_artifact(&build_test_path, &bin_name)? + } + (PrimarySource::RustSourceFile(_), RustToolchain::Wasip1) + | ( + PrimarySource::BashScript(_) + | PrimarySource::CSourceFile(_) + | PrimarySource::CppSourceFile(_), + _, + ) => build_test_path.join("main"), + }; + + Ok(main_path) } struct CopyHostTreeActions { @@ -1120,13 +1299,14 @@ fn run_integration_test(config: Config) -> Result { Ok(libtest_mimic::Completion::Completed) } -const PRIMARY_SOURCE_FILES: &[&str] = &["main.c", "main.cpp", "build.sh"]; +const PRIMARY_SOURCE_FILES: &[&str] = &["main.c", "main.cpp", "build.sh", "Cargo.toml"]; #[derive(Debug, Clone, PartialEq, Eq)] enum PrimarySource { CSourceFile(String), CppSourceFile(String), RustSourceFile(String), + CargoProject, BashScript(String), } @@ -1155,6 +1335,7 @@ impl PrimarySource { .to_string() } } + Self::CargoProject => "default".to_owned(), } } @@ -1164,6 +1345,7 @@ impl PrimarySource { | Self::CppSourceFile(filename) | Self::RustSourceFile(filename) => filename.clone(), Self::BashScript(filename) => filename.clone(), + Self::CargoProject => "Cargo.toml".to_owned(), } } @@ -1174,6 +1356,21 @@ impl PrimarySource { } Self::RustSourceFile(_) => false, Self::BashScript(filename) => filename == "build.sh", + Self::CargoProject => true, + } + } + + fn is_rust(&self) -> bool { + matches!(self, Self::RustSourceFile(_) | Self::CargoProject) + } + + fn parse_directive_line<'a>(&self, line: &'a str) -> Option<&'a str> { + match self { + Self::CargoProject => parse_cargo_toml_directive_line(line), + Self::BashScript(_) => line.trim().strip_prefix("##"), + Self::CSourceFile(_) | Self::CppSourceFile(_) | Self::RustSourceFile(_) => { + line.trim().strip_prefix("//#") + } } } } @@ -1196,6 +1393,10 @@ fn identify_primary_sources(test_src_dir: &Path) -> Result> { return Ok(shell_sources); } + if test_src_dir.join("Cargo.toml").is_file() { + return Ok(vec![PrimarySource::CargoProject]); + } + for file in ["main.c", "main.cpp"] { let path = test_src_dir.join(file); if path.exists() { @@ -1230,7 +1431,7 @@ fn identify_primary_sources(test_src_dir: &Path) -> Result> { bail!( "{} must contain {}", test_src_dir.display(), - "main.c, main.cpp, build.sh, or *.rs" + "build.sh, Cargo.toml, main.c, main.cpp, or *.rs" ); } @@ -1287,6 +1488,18 @@ fn collect_tests(tests: &mut Vec) -> Result<()> { let default_file_systems = vec![FileSystemKind::Host]; for primary_source in primary_sources { + // Single-file Rust fixtures historically built with wasm32-wasip1; + // keep that variant alongside the cargo-wasix one, since it is the + // only one Singlepass can run. Every other source has no toolchain + // axis: it is built by wasixcc, or by cargo-wasix for Cargo + // projects, whose output behaves like the WASIX toolchain's. + let default_rust_toolchains = match &primary_source { + PrimarySource::RustSourceFile(_) => { + vec![RustToolchain::Wasix, RustToolchain::Wasip1] + } + _ => vec![RustToolchain::Wasix], + }; + let configs = parse_configs(&Config::new( primary_source, entry.path().to_path_buf(), @@ -1301,23 +1514,6 @@ fn collect_tests(tests: &mut Vec) -> Result<()> { .unwrap_or(&default_file_systems) { for engine in &supported_engines { - // In general, the WASIX tests expect support for more advanced WebAssembly extensions (like exception handling), - // but we can still run selectively some tests with Singlepass. - #[cfg(feature = "singlepass")] - { - let test_name = entry - .path() - .file_name() - .expect("must be valid filename") - .to_string_lossy() - .to_string(); - if *engine == Engine::Singlepass - && !["wasi_fyi", "wasi_wast"].contains(&test_name.as_str()) - { - continue; - } - } - // WASIXCC toolchain does not cover Windows yet. if cfg!(target_os = "windows") && !matches!(config.source, PrimarySource::RustSourceFile(..)) @@ -1337,20 +1533,49 @@ fn collect_tests(tests: &mut Vec) -> Result<()> { } } - let mut config = config.clone(); - config.engine = *engine; - config.selected_file_system = *file_system; - if let Some(sysroot_version) = sysroot { - config.set_sysroot(sysroot_version)?; - } + for rust_toolchain in config + .rust_toolchains + .as_ref() + .unwrap_or(&default_rust_toolchains) + { + if !rust_toolchain.supports_engine(*engine) { + continue; + } + + // wasip1 builds go through rustc and never see + // the wasix-libc sysroot, so the compatibility + // variants would just duplicate the default one. + if sysroot.is_some() && *rust_toolchain == RustToolchain::Wasip1 { + continue; + } - tests.push(libtest_mimic::Trial::ignorable_test( - config.full_test_name(), - move || { - run_integration_test(config) - .map_err(|e| libtest_mimic::Failed::from(format!("{e:?}"))) - }, - )); + // We don't publish the WASIX Rust toolchain for + // every platform yet; the wasip1 variants build + // anywhere. + if config.source.is_rust() + && *rust_toolchain == RustToolchain::Wasix + && !WASIX_RUST_TOOLCHAIN_AVAILABLE + { + continue; + } + + let mut config = config.clone(); + config.engine = *engine; + config.rust_toolchain = *rust_toolchain; + config.selected_file_system = *file_system; + if let Some(sysroot_version) = sysroot { + config.set_sysroot(sysroot_version)?; + } + + tests.push(libtest_mimic::Trial::ignorable_test( + config.full_test_name(), + move || { + run_integration_test(config).map_err(|e| { + libtest_mimic::Failed::from(format!("{e:?}")) + }) + }, + )); + } } } } diff --git a/lib/wasix/tests/wasm_tests/wasi_fyi/env_args-many.rs b/lib/wasix/tests/wasm_tests/wasi_fyi/env_args-many.rs index 03604659f888..541842d0e028 100644 --- a/lib/wasix/tests/wasm_tests/wasi_fyi/env_args-many.rs +++ b/lib/wasix/tests/wasm_tests/wasi_fyi/env_args-many.rs @@ -4,10 +4,10 @@ use std::env; fn main() { - let args = env::args().collect::>(); - assert_eq!(args.len(), 4); - assert_eq!(args[0], "env_args-many.wasm"); - assert_eq!(args[1], "none"); - assert_eq!(args[2], "some"); - assert_eq!(args[3], "many"); + let args = env::args().collect::>(); + assert_eq!(args.len(), 4); + assert_eq!(args[0], "env_args-many.wasm"); + assert_eq!(args[1], "none"); + assert_eq!(args[2], "some"); + assert_eq!(args[3], "many"); } diff --git a/lib/wasix/tests/wasm_tests/wasi_fyi/env_args-none.rs b/lib/wasix/tests/wasm_tests/wasi_fyi/env_args-none.rs index c21b9d628455..984436d90427 100644 --- a/lib/wasix/tests/wasm_tests/wasi_fyi/env_args-none.rs +++ b/lib/wasix/tests/wasm_tests/wasi_fyi/env_args-none.rs @@ -4,7 +4,7 @@ use std::env; fn main() { - let args = env::args().collect::>(); - assert_eq!(args.len(), 1); - assert_eq!(args[0], "env_args-none.wasm"); + let args = env::args().collect::>(); + assert_eq!(args.len(), 1); + assert_eq!(args[0], "env_args-none.wasm"); } diff --git a/lib/wasix/tests/wasm_tests/wasi_fyi/env_args-some.rs b/lib/wasix/tests/wasm_tests/wasi_fyi/env_args-some.rs index 15b260ee1752..a798c3ef5bd1 100644 --- a/lib/wasix/tests/wasm_tests/wasi_fyi/env_args-some.rs +++ b/lib/wasix/tests/wasm_tests/wasi_fyi/env_args-some.rs @@ -4,8 +4,8 @@ use std::env; fn main() { - let args = env::args().collect::>(); - assert_eq!(args.len(), 2); - assert_eq!(args[0], "env_args-some.wasm"); - assert_eq!(args[1], "some"); + let args = env::args().collect::>(); + assert_eq!(args.len(), 2); + assert_eq!(args[0], "env_args-some.wasm"); + assert_eq!(args[1], "some"); } diff --git a/lib/wasix/tests/wasm_tests/wasi_fyi/env_vars-none.rs b/lib/wasix/tests/wasm_tests/wasi_fyi/env_vars-none.rs index a4165bae05fa..ce6ed0835881 100644 --- a/lib/wasix/tests/wasm_tests/wasi_fyi/env_vars-none.rs +++ b/lib/wasix/tests/wasm_tests/wasi_fyi/env_vars-none.rs @@ -2,6 +2,6 @@ use std::env; fn main() { - let vars = env::vars().collect::>(); - assert_eq!(vars.len(), 0); + let vars = env::vars().collect::>(); + assert_eq!(vars.len(), 0); } diff --git a/lib/wasix/tests/wasm_tests/wasi_fyi/env_vars-some.rs b/lib/wasix/tests/wasm_tests/wasi_fyi/env_vars-some.rs index c2780ba4fc9d..3e74edca8003 100644 --- a/lib/wasix/tests/wasm_tests/wasi_fyi/env_vars-some.rs +++ b/lib/wasix/tests/wasm_tests/wasi_fyi/env_vars-some.rs @@ -3,7 +3,7 @@ use std::env; fn main() { - let vars = env::vars().collect::>(); - assert_eq!(vars.len(), 1); - assert_eq!(vars[0], ("SOME".to_string(), "some".to_string())); + let vars = env::vars().collect::>(); + assert_eq!(vars.len(), 1); + assert_eq!(vars[0], ("SOME".to_string(), "some".to_string())); } diff --git a/lib/wasix/tests/wasm_tests/wasi_fyi/fs_file_create.rs b/lib/wasix/tests/wasm_tests/wasi_fyi/fs_file_create.rs index 798d2cfae5e0..e58358fddb2a 100644 --- a/lib/wasix/tests/wasm_tests/wasi_fyi/fs_file_create.rs +++ b/lib/wasix/tests/wasm_tests/wasi_fyi/fs_file_create.rs @@ -3,8 +3,10 @@ use std::fs; fn main() { assert!(fs::File::create("/fyi/fs_file_create.dir/new_file").is_ok()); - assert!(fs::metadata("/fyi/fs_file_create.dir/new_file") - .unwrap() - .is_file()); + assert!( + fs::metadata("/fyi/fs_file_create.dir/new_file") + .unwrap() + .is_file() + ); assert!(fs::remove_file("/fyi/fs_file_create.dir/new_file").is_ok()); } diff --git a/lib/wasix/tests/wasm_tests/wasi_fyi/fs_seek_append_mode.rs b/lib/wasix/tests/wasm_tests/wasi_fyi/fs_seek_append_mode.rs index 2b06683f4f1b..bd0f95180d04 100644 --- a/lib/wasix/tests/wasm_tests/wasi_fyi/fs_seek_append_mode.rs +++ b/lib/wasix/tests/wasm_tests/wasi_fyi/fs_seek_append_mode.rs @@ -1,7 +1,7 @@ //#AbstractConfigFile: wasi-fyi.config use std::fs::OpenOptions; -use std::io::prelude::*; use std::io::SeekFrom; +use std::io::prelude::*; fn main() { let mut file = OpenOptions::new() diff --git a/lib/wasix/tests/wasm_tests/wasi_fyi/fs_write-and-seek.rs b/lib/wasix/tests/wasm_tests/wasi_fyi/fs_write-and-seek.rs index 1341256f2947..7153ce485063 100644 --- a/lib/wasix/tests/wasm_tests/wasi_fyi/fs_write-and-seek.rs +++ b/lib/wasix/tests/wasm_tests/wasi_fyi/fs_write-and-seek.rs @@ -1,5 +1,5 @@ //#AbstractConfigFile: wasi-fyi.config -use std::fs::{metadata, OpenOptions}; +use std::fs::{OpenOptions, metadata}; use std::io::{Seek, SeekFrom, Write}; fn main() { diff --git a/lib/wasix/tests/wasm_tests/wasi_fyi/io_stderr-beowulf.rs b/lib/wasix/tests/wasm_tests/wasi_fyi/io_stderr-beowulf.rs index e77d99d33b4e..3accb8ea60bf 100644 --- a/lib/wasix/tests/wasm_tests/wasi_fyi/io_stderr-beowulf.rs +++ b/lib/wasix/tests/wasm_tests/wasi_fyi/io_stderr-beowulf.rs @@ -4,5 +4,9 @@ use std::io; use std::io::Write; fn main() { - assert!(io::stderr().write_all(include_bytes!("io_stderr-beowulf.stderr")).is_ok()); + assert!( + io::stderr() + .write_all(include_bytes!("io_stderr-beowulf.stderr")) + .is_ok() + ); } diff --git a/lib/wasix/tests/wasm_tests/wasi_fyi/io_stderr-hello.rs b/lib/wasix/tests/wasm_tests/wasi_fyi/io_stderr-hello.rs index d0ca0d6597a2..381363b4b210 100644 --- a/lib/wasix/tests/wasm_tests/wasi_fyi/io_stderr-hello.rs +++ b/lib/wasix/tests/wasm_tests/wasi_fyi/io_stderr-hello.rs @@ -4,5 +4,9 @@ use std::io; use std::io::Write; fn main() { - assert!(io::stderr().write_all(include_bytes!("io_stderr-hello.stderr")).is_ok()); + assert!( + io::stderr() + .write_all(include_bytes!("io_stderr-hello.stderr")) + .is_ok() + ); } diff --git a/lib/wasix/tests/wasm_tests/wasi_fyi/io_stdout-beowulf.rs b/lib/wasix/tests/wasm_tests/wasi_fyi/io_stdout-beowulf.rs index d5f504c665cd..e9fff7682d30 100644 --- a/lib/wasix/tests/wasm_tests/wasi_fyi/io_stdout-beowulf.rs +++ b/lib/wasix/tests/wasm_tests/wasi_fyi/io_stdout-beowulf.rs @@ -4,5 +4,9 @@ use std::io; use std::io::Write; fn main() { - assert!(io::stdout().write_all(include_bytes!("io_stdout-beowulf.stdout")).is_ok()); + assert!( + io::stdout() + .write_all(include_bytes!("io_stdout-beowulf.stdout")) + .is_ok() + ); } diff --git a/lib/wasix/tests/wasm_tests/wasi_fyi/io_stdout-hello.rs b/lib/wasix/tests/wasm_tests/wasi_fyi/io_stdout-hello.rs index eea186f1b406..7334f42fc937 100644 --- a/lib/wasix/tests/wasm_tests/wasi_fyi/io_stdout-hello.rs +++ b/lib/wasix/tests/wasm_tests/wasi_fyi/io_stdout-hello.rs @@ -4,5 +4,9 @@ use std::io; use std::io::Write; fn main() { - assert!(io::stdout().write_all(include_bytes!("io_stdout-hello.stdout")).is_ok()); + assert!( + io::stdout() + .write_all(include_bytes!("io_stdout-hello.stdout")) + .is_ok() + ); } diff --git a/lib/wasix/tests/wasm_tests/wasi_fyi/ported_close_preopen_fd.rs b/lib/wasix/tests/wasm_tests/wasi_fyi/ported_close_preopen_fd.rs index 0989636fcab5..bcfe62e75043 100644 --- a/lib/wasix/tests/wasm_tests/wasi_fyi/ported_close_preopen_fd.rs +++ b/lib/wasix/tests/wasm_tests/wasi_fyi/ported_close_preopen_fd.rs @@ -4,7 +4,7 @@ // mapdir: hamlet:test_fs/hamlet #[link(wasm_import_module = "wasi_unstable")] -extern "C" { +unsafe extern "C" { fn fd_close(fd: u32) -> u16; fn fd_fdstat_set_flags(fd: u32, flags: u16) -> u16; } diff --git a/lib/wasix/tests/wasm_tests/wasi_fyi/ported_poll_oneoff.rs b/lib/wasix/tests/wasm_tests/wasi_fyi/ported_poll_oneoff.rs index 5547235a1cc5..90c61100f4e4 100644 --- a/lib/wasix/tests/wasm_tests/wasi_fyi/ported_poll_oneoff.rs +++ b/lib/wasix/tests/wasm_tests/wasi_fyi/ported_poll_oneoff.rs @@ -132,11 +132,7 @@ fn poll(fds: &[u32], read: &[bool], write: &[bool]) -> Result u16; fn fd_fdstat_set_flags(fd: u32, flags: u16) -> u16; } diff --git a/lib/wasix/tests/wasm_tests/wasi_wast/fd_close.rs b/lib/wasix/tests/wasm_tests/wasi_wast/fd_close.rs index 6315782144a4..9fdea93345c6 100644 --- a/lib/wasix/tests/wasm_tests/wasi_wast/fd_close.rs +++ b/lib/wasix/tests/wasm_tests/wasi_wast/fd_close.rs @@ -16,8 +16,8 @@ extern "C" { fn main() { #[cfg(not(target_os = "wasi"))] let mut base = PathBuf::from("test_fs/hamlet"); -#[cfg(target_os = "wasi")] -let mut base = PathBuf::from("hamlet"); + #[cfg(target_os = "wasi")] + let mut base = PathBuf::from("hamlet"); base.push("act3/scene3.txt"); let file = fs::File::open(&base).expect("could not open file"); diff --git a/lib/wasix/tests/wasm_tests/wasi_wast/fd_read.rs b/lib/wasix/tests/wasm_tests/wasi_wast/fd_read.rs index 16d13a70f3f7..9e788f1fea43 100644 --- a/lib/wasix/tests/wasm_tests/wasi_wast/fd_read.rs +++ b/lib/wasix/tests/wasm_tests/wasi_wast/fd_read.rs @@ -48,8 +48,8 @@ fn read(fd: u32, iovs: &[&mut [u8]]) -> u32 { fn main() { #[cfg(not(target_os = "wasi"))] let mut base = PathBuf::from("test_fs/hamlet"); -#[cfg(target_os = "wasi")] -let mut base = PathBuf::from("hamlet"); + #[cfg(target_os = "wasi")] + let mut base = PathBuf::from("hamlet"); base.push("act3/scene4.txt"); let mut file = fs::File::open(&base).expect("Could not open file"); diff --git a/lib/wasix/tests/wasm_tests/wasi_wast/fd_rename_path.rs b/lib/wasix/tests/wasm_tests/wasi_wast/fd_rename_path.rs index 6995476dbf03..182b5e50b53a 100644 --- a/lib/wasix/tests/wasm_tests/wasi_wast/fd_rename_path.rs +++ b/lib/wasix/tests/wasm_tests/wasi_wast/fd_rename_path.rs @@ -6,14 +6,15 @@ use std::path::PathBuf; fn main() { let mut idx = 0; - fs::create_dir_all(PathBuf::from("test_fs/wasitests")).expect("cannot create the parent directory"); + fs::create_dir_all(PathBuf::from("test_fs/wasitests")) + .expect("cannot create the parent directory"); let old_path = loop { let old_path = PathBuf::from(format!("test_fs/wasitests/dirtorename-{}", idx)); if fs::create_dir(old_path.clone()).ok().is_some() { break old_path; } - idx+=1; + idx += 1; if idx > 10 { panic!("too many try at creating the folder"); } diff --git a/lib/wasix/tests/wasm_tests/wasi_wast/fseek.rs b/lib/wasix/tests/wasm_tests/wasi_wast/fseek.rs index 54709573d48d..86c85942e91e 100644 --- a/lib/wasix/tests/wasm_tests/wasi_wast/fseek.rs +++ b/lib/wasix/tests/wasm_tests/wasi_wast/fseek.rs @@ -9,8 +9,8 @@ use std::path::PathBuf; fn main() { #[cfg(not(target_os = "wasi"))] let mut base = PathBuf::from("test_fs/hamlet"); -#[cfg(target_os = "wasi")] -let mut base = PathBuf::from("hamlet"); + #[cfg(target_os = "wasi")] + let mut base = PathBuf::from("hamlet"); base.push("act1/scene3.txt"); diff --git a/lib/wasix/tests/wasm_tests/wasi_wast/inode.rs b/lib/wasix/tests/wasm_tests/wasi_wast/inode.rs index 74fa425512fc..fc9aa82129e1 100644 --- a/lib/wasix/tests/wasm_tests/wasi_wast/inode.rs +++ b/lib/wasix/tests/wasm_tests/wasi_wast/inode.rs @@ -14,16 +14,22 @@ use std::os::wasi::fs::MetadataExt; fn main() { #[cfg(target = "wasi")] { - let meta1 = fs::metadata("test_fs/hamlet/act1/scene1.txt").expect("could not find src file"); - let meta2 = fs::metadata("test_fs/hamlet/act1/scene2.txt").expect("could not find src file"); + let meta1 = + fs::metadata("test_fs/hamlet/act1/scene1.txt").expect("could not find src file"); + let meta2 = + fs::metadata("test_fs/hamlet/act1/scene2.txt").expect("could not find src file"); if meta1.dev() == meta2.dev() && meta1.ino() == meta2.ino() { println!("Warning, different files from same folder have same dev/inod"); } - let meta3 = fs::metadata("test_fs/hamlet/act2/scene1.txt").expect("could not find src file"); + let meta3 = + fs::metadata("test_fs/hamlet/act2/scene1.txt").expect("could not find src file"); if meta1.dev() == meta3.dev() && meta1.ino() == meta3.ino() { - println!("Warning, different files from different folder with same name have same dev/inod"); + println!( + "Warning, different files from different folder with same name have same dev/inod" + ); } - let meta4 = fs::metadata("test_fs/hamlet/act1/../act1/scene1.txt").expect("could not find src file"); + let meta4 = fs::metadata("test_fs/hamlet/act1/../act1/scene1.txt") + .expect("could not find src file"); if meta1.dev() != meta4.dev() || meta1.ino() != meta4.ino() { println!("Warning, same files have different dev/inod"); } diff --git a/lib/wasix/tests/wasm_tests/wasi_wast/path_rename.rs b/lib/wasix/tests/wasm_tests/wasi_wast/path_rename.rs index fc4f1b73add8..7f35ab0e7103 100644 --- a/lib/wasix/tests/wasm_tests/wasi_wast/path_rename.rs +++ b/lib/wasix/tests/wasm_tests/wasi_wast/path_rename.rs @@ -123,7 +123,6 @@ fn run_with_toplevel_dir_overwrite() { println!("The original file does not still exist!"); } - if !file_to_rename_to.exists() { println!("The moved file does not exist!"); return; diff --git a/lib/wasix/tests/wasm_tests/wasi_wast/poll_oneoff.rs b/lib/wasix/tests/wasm_tests/wasi_wast/poll_oneoff.rs index 58106f5587fc..cbdee0a75d75 100644 --- a/lib/wasix/tests/wasm_tests/wasi_wast/poll_oneoff.rs +++ b/lib/wasix/tests/wasm_tests/wasi_wast/poll_oneoff.rs @@ -131,11 +131,7 @@ fn poll(fds: &[u32], read: &[bool], write: &[bool]) -> Result>(); roots.sort();