From ba90261fd144f879571298066bbe129ad813c324 Mon Sep 17 00:00:00 2001 From: Martin Liska Date: Tue, 5 May 2026 19:38:52 +0200 Subject: [PATCH 1/7] ci: support only host Platform --- wild/tests/integration_tests.rs | 139 +++++++++++++++----------------- 1 file changed, 64 insertions(+), 75 deletions(-) diff --git a/wild/tests/integration_tests.rs b/wild/tests/integration_tests.rs index ddffc4e7e..fd3e4fb70 100644 --- a/wild/tests/integration_tests.rs +++ b/wild/tests/integration_tests.rs @@ -283,80 +283,82 @@ fn collect_tests(tests: &mut Vec, filter: &Filter) -> Result { let host_arch = get_host_architecture(); - for platform in [PlatformKind::Elf, PlatformKind::MachO] { - let linkers = platform.available_linkers()?; + let Some(platform) = PlatformKind::host() else { + return Ok(()); + }; - let platform_name = platform.to_str(); + let linkers = platform.available_linkers()?; - if filter.excludes(platform_name) { - continue; - } + let platform_name = platform.to_str(); + + if filter.excludes(platform_name) { + return Ok(()); + } - let root = src_path(platform_name); - let dir = std::fs::read_dir(&root) - .with_context(|| format!("Failed to read directory {}", root.display()))?; + let root = src_path(platform_name); + let dir = std::fs::read_dir(&root) + .with_context(|| format!("Failed to read directory {}", root.display()))?; - let is_nextest = std::env::var("NEXTEST").is_ok(); + let is_nextest = std::env::var("NEXTEST").is_ok(); - for entry in dir { - let entry = entry?; - let path = entry.path(); - if path.ends_with("common") { + for entry in dir { + let entry = entry?; + let path = entry.path(); + if path.ends_with("common") { + continue; + } + + let base_name = path + .file_name() + .context("Missing filename")? + .to_str() + .context("Non-UTF-8 path")? + .to_owned(); + + for &arch in platform.supported_architectures() { + let name_prefix = format!("{platform_name}/{arch}/{base_name}"); + if filter.excludes(&name_prefix) { continue; } - let base_name = path - .file_name() - .context("Missing filename")? - .to_str() - .context("Non-UTF-8 path")? - .to_owned(); + let primary_source_file = identify_primary_source(&path, &base_name)?; + + let configs = parse_configs( + &primary_source_file, + &Config::new( + base_name.clone(), + platform, + arch, + path.clone(), + &test_config, + &linkers, + ), + )?; - for &arch in platform.supported_architectures() { - let name_prefix = format!("{platform_name}/{arch}/{base_name}"); - if filter.excludes(&name_prefix) { + let program_inputs = ProgramInputs::new(primary_source_file.clone())?; + + for config in configs { + if config.should_skip(arch) { continue; } - let primary_source_file = identify_primary_source(&path, &base_name)?; - - let configs = parse_configs( - &primary_source_file, - &Config::new( - base_name.clone(), - platform, - arch, - path.clone(), - &test_config, - &linkers, - ), - )?; - - let program_inputs = ProgramInputs::new(primary_source_file.clone())?; - - for config in configs { - if config.should_skip(arch) { - continue; - } - - let full_name = format!("{name_prefix}/{}", config.config_name); - let test_config = test_config.clone(); - let program_inputs = program_inputs.clone(); - - // Nextest spawns a process for every test, so emitting a large number of tests - // that we'll ignore at runtime is a bit wasteful. There are various different - // criteria for ignoring tests, but the biggest one is that the architecture - // isn't enabled. So we just filter for that and only when running under - // nextest. For the normal test runner, it doesn't matter much. - if is_nextest && arch != host_arch && !test_config.qemu_arch.contains(&arch) { - continue; - } + let full_name = format!("{name_prefix}/{}", config.config_name); + let test_config = test_config.clone(); + let program_inputs = program_inputs.clone(); - tests.push(libtest_mimic::Trial::ignorable_test(full_name, move || { - run_integration_test(arch, &program_inputs, config, &test_config) - .map_err(|e| libtest_mimic::Failed::from(e.to_string())) - })); + // Nextest spawns a process for every test, so emitting a large number of tests + // that we'll ignore at runtime is a bit wasteful. There are various different + // criteria for ignoring tests, but the biggest one is that the architecture + // isn't enabled. So we just filter for that and only when running under + // nextest. For the normal test runner, it doesn't matter much. + if is_nextest && arch != host_arch && !test_config.qemu_arch.contains(&arch) { + continue; } + + tests.push(libtest_mimic::Trial::ignorable_test(full_name, move || { + run_integration_test(arch, &program_inputs, config, &test_config) + .map_err(|e| libtest_mimic::Failed::from(e.to_string())) + })); } } } @@ -1290,7 +1292,7 @@ impl Config { remove_sections: Vec::new(), compiler: platform.default_c_compiler().to_owned(), should_diff: platform.diff_supported(), - should_run: platform.can_execute_on_host(), + should_run: true, run_dyn_sym: None, should_error: false, expect_stderr: Default::default(), @@ -2569,7 +2571,7 @@ fn add_cross_args( return; } - if !platform.is_host() || cross_arch.is_some() { + if cross_arch.is_some() { let arch = cross_arch.unwrap_or_else(get_host_architecture); let target = get_target(compiler_args) .cloned() @@ -4585,11 +4587,6 @@ fn run_integration_test( let cross_arch = (arch != get_host_architecture()).then_some(arch); - // For cross-platform tests (e.g., Mac binaries on Linux), link but don't execute - if !config.platform.can_execute_on_host() { - config.should_run = false; - } - config.rustc_channel = test_config.rustc_channel; if !test_config.allow_rust_musl_target && config.requires_rust_musl { @@ -4854,14 +4851,6 @@ impl PlatformKind { } } - fn is_host(self) -> bool { - Some(self) == PlatformKind::host() - } - - fn can_execute_on_host(self) -> bool { - self.is_host() - } - fn diff_supported(self) -> bool { self == PlatformKind::Elf } From edcc0d2a03bac3902e092312351199961157b58a Mon Sep 17 00:00:00 2001 From: Martin Liska Date: Wed, 6 May 2026 19:16:14 +0200 Subject: [PATCH 2/7] skip 2 tests --- linker-diff/src/utils.rs | 1 + wild/tests/sources/macho/trivial/trivial.c | 1 + 2 files changed, 2 insertions(+) diff --git a/linker-diff/src/utils.rs b/linker-diff/src/utils.rs index 8be62a248..02a299f96 100644 --- a/linker-diff/src/utils.rs +++ b/linker-diff/src/utils.rs @@ -53,6 +53,7 @@ pub fn decode_insn_with_objdump(insn: &[u8], address: u64, arch: ArchKind) -> Re } #[test] +#[cfg(target_os = "linux")] fn test_align_up() { // Some distributions don't enable the features in objdump required for disassembly of aarch64, // so we only check that we can disassemble if we're running on aarch64 or if test diff --git a/wild/tests/sources/macho/trivial/trivial.c b/wild/tests/sources/macho/trivial/trivial.c index edc10d7ce..1886d7149 100644 --- a/wild/tests/sources/macho/trivial/trivial.c +++ b/wild/tests/sources/macho/trivial/trivial.c @@ -1,6 +1,7 @@ //#Object:runtime.c //#ExpectSym:_main //#TestUpdateInPlace:true +//#RunEnabled: false #include "../common/runtime.h" From 63e26825f0169af4deb77d194c5223c6f7cf154c Mon Sep 17 00:00:00 2001 From: Martin Liska Date: Wed, 6 May 2026 19:17:20 +0200 Subject: [PATCH 3/7] enable tests on Macho-O --- .github/workflows/ci.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 220db91c3..ad526cca2 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -110,6 +110,7 @@ jobs: id: rust-toolchain - uses: Swatinem/rust-cache@v2 - run: cargo build --profile ci --workspace --no-default-features + - run: cargo test --profile ci --workspace minimal-versions: runs-on: ubuntu-24.04 From dcb4c6613fd245fcc5a1986968fa92a340168603 Mon Sep 17 00:00:00 2001 From: Martin Liska Date: Wed, 6 May 2026 19:20:11 +0200 Subject: [PATCH 4/7] skip clang-format on MachO --- libwild/src/tidy_tests.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/libwild/src/tidy_tests.rs b/libwild/src/tidy_tests.rs index d38cd6aee..038e8f48c 100644 --- a/libwild/src/tidy_tests.rs +++ b/libwild/src/tidy_tests.rs @@ -6,11 +6,13 @@ use crate::error::Result; use std::env; use std::fs::read_dir; use std::path::Path; -use std::process::Command; -use std::process::Stdio; #[test] +#[cfg(target_os = "linux")] fn check_sources_format() -> Result { + use std::process::Command; + use std::process::Stdio; + if std::env::var_os("WILD_TEST_IGNORE_FORMAT").is_some() { return Ok(()); } From 9df23f8aaa988615097b784affdbd4f5e0c7a777 Mon Sep 17 00:00:00 2001 From: Martin Liska Date: Wed, 6 May 2026 22:36:42 +0200 Subject: [PATCH 5/7] align job names --- .github/workflows/ci.yml | 143 ++++++++++++++++++++------------------- 1 file changed, 72 insertions(+), 71 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ad526cca2..542fde302 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -15,7 +15,7 @@ env: jobs: test-nightly: - name: Test (${{ contains(matrix.runs-on, 'arm') && 'AArch64' || 'x86_64'}}, ${{ matrix.container }}${{ matrix.test-qemu && ', QEMU' || ''}}) + name: Test Linux (${{ contains(matrix.runs-on, 'arm') && 'AArch64' || 'x86_64'}}, ${{ matrix.container }}${{ matrix.test-qemu && ', QEMU' || ''}}) strategy: matrix: @@ -85,9 +85,10 @@ jobs: - run: cargo test --profile ci --features plugins if: ${{ matrix.test-plugins }} - run: WILD_TEST_CROSS=$WILD_TEST_CROSS cargo test --profile ci --workspace - windows-build: - name: Windows build - runs-on: windows-latest + + riscv-build: + name: Build Linux (RISC-V) + runs-on: ubuntu-24.04 timeout-minutes: 10 steps: - uses: actions/checkout@v6 @@ -95,11 +96,62 @@ jobs: persist-credentials: false - uses: dtolnay/rust-toolchain@stable id: rust-toolchain + with: + targets: riscv64gc-unknown-linux-gnu - uses: Swatinem/rust-cache@v2 - - run: cargo build --profile ci --workspace --no-default-features + - run: sudo apt-get update && sudo apt-get install build-essential lld gcc-riscv64-linux-gnu g++-riscv64-linux-gnu + - run: cp -f .cargo/config.toml.cross-riscv .cargo/config.toml + - run: cargo build --target riscv64gc-unknown-linux-gnu - macos-build: - name: macOS build + loongarch64-build: + name: Build Linux (LoongArch64) + runs-on: ubuntu-24.04 + timeout-minutes: 10 + container: + image: ubuntu:25.10 + steps: + - uses: actions/checkout@v6 + with: + persist-credentials: false + - run: apt-get update && apt-get install -y build-essential lld gcc gcc-loongarch64-linux-gnu g++-loongarch64-linux-gnu curl + - uses: dtolnay/rust-toolchain@stable + id: rust-toolchain + with: + targets: loongarch64-unknown-linux-gnu + - uses: Swatinem/rust-cache@v2 + - run: cp -f .cargo/config.toml.cross-loongarch64 .cargo/config.toml + - run: cargo build --target loongarch64-unknown-linux-gnu + + wasip1-build: + name: Build wasip1 + runs-on: ubuntu-24.04 + timeout-minutes: 10 + container: + image: ubuntu:25.10 + steps: + - name: Install xz-utils + run: apt-get update && apt-get install -y xz-utils + - name: Setup Wasmtime + uses: bytecodealliance/actions/wasmtime/setup@v1 + with: + version: '43.0.0' + - uses: actions/checkout@v6 + with: + persist-credentials: false + - run: apt-get install --update -y build-essential gcc gcc-multilib clang curl + - uses: dtolnay/rust-toolchain@stable + id: rust-toolchain + with: + targets: wasm32-wasip1 + - uses: Swatinem/rust-cache@v2 + - run: cargo build --target wasm32-wasip1 + - run: cp -f .cargo/config.toml.cross-wasm32p1 .cargo/config.toml + # -p libwild prevents integration tests from running. they depend on + # spawning processes, which isn't supported on wasi. + - run: cargo test --profile ci -p libwild --target wasm32-wasip1 + + macho-build: + name: Test Mach-O (AArch64) runs-on: macos-latest timeout-minutes: 10 steps: @@ -112,6 +164,19 @@ jobs: - run: cargo build --profile ci --workspace --no-default-features - run: cargo test --profile ci --workspace + windows-build: + name: Build Windows (x86_64) + runs-on: windows-latest + timeout-minutes: 10 + steps: + - uses: actions/checkout@v6 + with: + persist-credentials: false + - uses: dtolnay/rust-toolchain@stable + id: rust-toolchain + - uses: Swatinem/rust-cache@v2 + - run: cargo build --profile ci --workspace --no-default-features + minimal-versions: runs-on: ubuntu-24.04 timeout-minutes: 10 @@ -177,70 +242,6 @@ jobs: - run: echo "$(go env GOPATH)/bin" >> "$GITHUB_PATH" - run: yamlfmt -lint . - riscv-build: - name: RISC-V build - runs-on: ubuntu-24.04 - timeout-minutes: 10 - steps: - - uses: actions/checkout@v6 - with: - persist-credentials: false - - uses: dtolnay/rust-toolchain@stable - id: rust-toolchain - with: - targets: riscv64gc-unknown-linux-gnu - - uses: Swatinem/rust-cache@v2 - - run: sudo apt-get update && sudo apt-get install build-essential lld gcc-riscv64-linux-gnu g++-riscv64-linux-gnu - - run: cp -f .cargo/config.toml.cross-riscv .cargo/config.toml - - run: cargo build --target riscv64gc-unknown-linux-gnu - - loongarch64-build: - name: LoongArch64 build - runs-on: ubuntu-24.04 - timeout-minutes: 10 - container: - image: ubuntu:25.10 - steps: - - uses: actions/checkout@v6 - with: - persist-credentials: false - - run: apt-get update && apt-get install -y build-essential lld gcc gcc-loongarch64-linux-gnu g++-loongarch64-linux-gnu curl - - uses: dtolnay/rust-toolchain@stable - id: rust-toolchain - with: - targets: loongarch64-unknown-linux-gnu - - uses: Swatinem/rust-cache@v2 - - run: cp -f .cargo/config.toml.cross-loongarch64 .cargo/config.toml - - run: cargo build --target loongarch64-unknown-linux-gnu - - wasip1-build: - name: wasip1 build - runs-on: ubuntu-24.04 - timeout-minutes: 10 - container: - image: ubuntu:25.10 - steps: - - name: Install xz-utils - run: apt-get update && apt-get install -y xz-utils - - name: Setup Wasmtime - uses: bytecodealliance/actions/wasmtime/setup@v1 - with: - version: '43.0.0' - - uses: actions/checkout@v6 - with: - persist-credentials: false - - run: apt-get install --update -y build-essential gcc gcc-multilib clang curl - - uses: dtolnay/rust-toolchain@stable - id: rust-toolchain - with: - targets: wasm32-wasip1 - - uses: Swatinem/rust-cache@v2 - - run: cargo build --target wasm32-wasip1 - - run: cp -f .cargo/config.toml.cross-wasm32p1 .cargo/config.toml - # -p libwild prevents integration tests from running. they depend on - # spawning processes, which isn't supported on wasi. - - run: cargo test --profile ci -p libwild --target wasm32-wasip1 - spelling: name: Spell Check with Typos runs-on: ubuntu-24.04 From 04f8b41709ac16bc912a57a2ed424004f4c7a68b Mon Sep 17 00:00:00 2001 From: Martin Liska Date: Thu, 7 May 2026 07:57:48 +0200 Subject: [PATCH 6/7] revert change partially --- wild/tests/integration_tests.rs | 139 +++++++++++++++++--------------- 1 file changed, 75 insertions(+), 64 deletions(-) diff --git a/wild/tests/integration_tests.rs b/wild/tests/integration_tests.rs index fd3e4fb70..ddffc4e7e 100644 --- a/wild/tests/integration_tests.rs +++ b/wild/tests/integration_tests.rs @@ -283,82 +283,80 @@ fn collect_tests(tests: &mut Vec, filter: &Filter) -> Result { let host_arch = get_host_architecture(); - let Some(platform) = PlatformKind::host() else { - return Ok(()); - }; - - let linkers = platform.available_linkers()?; - - let platform_name = platform.to_str(); - - if filter.excludes(platform_name) { - return Ok(()); - } + for platform in [PlatformKind::Elf, PlatformKind::MachO] { + let linkers = platform.available_linkers()?; - let root = src_path(platform_name); - let dir = std::fs::read_dir(&root) - .with_context(|| format!("Failed to read directory {}", root.display()))?; + let platform_name = platform.to_str(); - let is_nextest = std::env::var("NEXTEST").is_ok(); - - for entry in dir { - let entry = entry?; - let path = entry.path(); - if path.ends_with("common") { + if filter.excludes(platform_name) { continue; } - let base_name = path - .file_name() - .context("Missing filename")? - .to_str() - .context("Non-UTF-8 path")? - .to_owned(); - - for &arch in platform.supported_architectures() { - let name_prefix = format!("{platform_name}/{arch}/{base_name}"); - if filter.excludes(&name_prefix) { + let root = src_path(platform_name); + let dir = std::fs::read_dir(&root) + .with_context(|| format!("Failed to read directory {}", root.display()))?; + + let is_nextest = std::env::var("NEXTEST").is_ok(); + + for entry in dir { + let entry = entry?; + let path = entry.path(); + if path.ends_with("common") { continue; } - let primary_source_file = identify_primary_source(&path, &base_name)?; - - let configs = parse_configs( - &primary_source_file, - &Config::new( - base_name.clone(), - platform, - arch, - path.clone(), - &test_config, - &linkers, - ), - )?; + let base_name = path + .file_name() + .context("Missing filename")? + .to_str() + .context("Non-UTF-8 path")? + .to_owned(); - let program_inputs = ProgramInputs::new(primary_source_file.clone())?; - - for config in configs { - if config.should_skip(arch) { + for &arch in platform.supported_architectures() { + let name_prefix = format!("{platform_name}/{arch}/{base_name}"); + if filter.excludes(&name_prefix) { continue; } - let full_name = format!("{name_prefix}/{}", config.config_name); - let test_config = test_config.clone(); - let program_inputs = program_inputs.clone(); + let primary_source_file = identify_primary_source(&path, &base_name)?; + + let configs = parse_configs( + &primary_source_file, + &Config::new( + base_name.clone(), + platform, + arch, + path.clone(), + &test_config, + &linkers, + ), + )?; + + let program_inputs = ProgramInputs::new(primary_source_file.clone())?; + + for config in configs { + if config.should_skip(arch) { + continue; + } - // Nextest spawns a process for every test, so emitting a large number of tests - // that we'll ignore at runtime is a bit wasteful. There are various different - // criteria for ignoring tests, but the biggest one is that the architecture - // isn't enabled. So we just filter for that and only when running under - // nextest. For the normal test runner, it doesn't matter much. - if is_nextest && arch != host_arch && !test_config.qemu_arch.contains(&arch) { - continue; - } + let full_name = format!("{name_prefix}/{}", config.config_name); + let test_config = test_config.clone(); + let program_inputs = program_inputs.clone(); + + // Nextest spawns a process for every test, so emitting a large number of tests + // that we'll ignore at runtime is a bit wasteful. There are various different + // criteria for ignoring tests, but the biggest one is that the architecture + // isn't enabled. So we just filter for that and only when running under + // nextest. For the normal test runner, it doesn't matter much. + if is_nextest && arch != host_arch && !test_config.qemu_arch.contains(&arch) { + continue; + } - tests.push(libtest_mimic::Trial::ignorable_test(full_name, move || { - run_integration_test(arch, &program_inputs, config, &test_config) - .map_err(|e| libtest_mimic::Failed::from(e.to_string())) - })); + tests.push(libtest_mimic::Trial::ignorable_test(full_name, move || { + run_integration_test(arch, &program_inputs, config, &test_config) + .map_err(|e| libtest_mimic::Failed::from(e.to_string())) + })); + } } } } @@ -1292,7 +1290,7 @@ impl Config { remove_sections: Vec::new(), compiler: platform.default_c_compiler().to_owned(), should_diff: platform.diff_supported(), - should_run: true, + should_run: platform.can_execute_on_host(), run_dyn_sym: None, should_error: false, expect_stderr: Default::default(), @@ -2571,7 +2569,7 @@ fn add_cross_args( return; } - if cross_arch.is_some() { + if !platform.is_host() || cross_arch.is_some() { let arch = cross_arch.unwrap_or_else(get_host_architecture); let target = get_target(compiler_args) .cloned() @@ -4587,6 +4585,11 @@ fn run_integration_test( let cross_arch = (arch != get_host_architecture()).then_some(arch); + // For cross-platform tests (e.g., Mac binaries on Linux), link but don't execute + if !config.platform.can_execute_on_host() { + config.should_run = false; + } + config.rustc_channel = test_config.rustc_channel; if !test_config.allow_rust_musl_target && config.requires_rust_musl { @@ -4851,6 +4854,14 @@ impl PlatformKind { } } + fn is_host(self) -> bool { + Some(self) == PlatformKind::host() + } + + fn can_execute_on_host(self) -> bool { + self.is_host() + } + fn diff_supported(self) -> bool { self == PlatformKind::Elf } From bad2fdaaef7ab2c2aac611382f6202d3c84f0032 Mon Sep 17 00:00:00 2001 From: Martin Liska Date: Thu, 7 May 2026 07:59:11 +0200 Subject: [PATCH 7/7] skip ELF integration tests on Mach-O --- wild/tests/integration_tests.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/wild/tests/integration_tests.rs b/wild/tests/integration_tests.rs index ddffc4e7e..561458f13 100644 --- a/wild/tests/integration_tests.rs +++ b/wild/tests/integration_tests.rs @@ -284,6 +284,11 @@ fn collect_tests(tests: &mut Vec, filter: &Filter) -> Result { let host_arch = get_host_architecture(); for platform in [PlatformKind::Elf, PlatformKind::MachO] { + // Right now, the Mach-O provided Clang and the ld linker do not support the ELF format. + if platform == PlatformKind::Elf && cfg!(target_os = "macos") { + continue; + } + let linkers = platform.available_linkers()?; let platform_name = platform.to_str();