diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 75bcbcd..8d4709f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -18,7 +18,7 @@ jobs: rust: - nightly # Check a ~3 months old nightly as "oldest supported version" - - nightly-2025-05-01 + - nightly-2026-01-01 # We want to run all of the above on Linux, macOS, windows-msvc, windows-gnu. # The semantics of combining `include` with other things in GHA are very strange # so this seems like the best way of doing that. @@ -51,6 +51,18 @@ jobs: - name: Run tests run: cargo test --locked --target ${{ matrix.target }} + build-dir-new-layout: + name: Test Suite (build-dir-new-layout) + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: dtolnay/rust-toolchain@master + with: + toolchain: nightly + components: rust-src + - name: Run tests + run: CARGO_UNSTABLE_BUILD_DIR_NEW_LAYOUT=true cargo test --locked + check: name: Checks runs-on: ubuntu-latest diff --git a/src/lib.rs b/src/lib.rs index 225c265..814b046 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -531,17 +531,17 @@ impl<'a> SysrootBuilder<'a> { fs::create_dir(&staging_lib_dir).context("failed to create staging/lib dir")?; let out_dir = build_target_dir .join(&target_name) - .join(DEFAULT_SYSROOT_PROFILE) - .join("deps"); - for entry in fs::read_dir(&out_dir).context("failed to read cargo out dir")? { - let entry = entry.context("failed to read cargo out dir entry")?; - assert!( - entry.file_type().unwrap().is_file(), - "cargo out dir must not contain directories" - ); - let entry = entry.path(); - fs::copy(&entry, staging_lib_dir.join(entry.file_name().unwrap())) - .context("failed to copy cargo out file")?; + .join(DEFAULT_SYSROOT_PROFILE); + if out_dir.join("deps").exists() { + // Old build dir layout: $out/deps + copy_files(&out_dir.join("deps"), &staging_lib_dir) + .context("failed to copy cargo out dir (old layout)")?; + } else { + // New build dir layout: $out/build/*/*/out. + for_each_dir(&out_dir.join("build"), |dir| { + for_each_dir(dir, |dir| copy_files(&dir.join("out"), &staging_lib_dir)) + }) + .context("failed to copy cargo out dir (new layout)")?; } // Write the hash file (into the staging dir). @@ -564,6 +564,31 @@ impl<'a> SysrootBuilder<'a> { } } +/// Coopy all files in `from` to `to`. +fn copy_files(from: &Path, to: &Path) -> Result<()> { + for entry in fs::read_dir(from)? { + let entry = entry?; + assert!( + entry.file_type()?.is_file(), + "cargo out dir must not contain directories" + ); + fs::copy(&entry.path(), to.join(entry.file_name()))?; + } + Ok(()) +} + +/// Invoke the closure for each directory inside `path`. +fn for_each_dir(path: &Path, f: impl Fn(&Path) -> Result<()>) -> Result<()> { + for entry in fs::read_dir(path)? { + let entry = entry?; + if !entry.file_type()?.is_dir() { + continue; + } + f(&entry.path())?; + } + Ok(()) +} + /// Collect the patches from the sysroot's workspace `Cargo.toml`. fn extract_patches(src_dir: &Path) -> Table { // Assume no patch is needed if the workspace Cargo.toml doesn't exist diff --git a/tests/tests.rs b/tests/tests.rs index 22e5927..4935b81 100644 --- a/tests/tests.rs +++ b/tests/tests.rs @@ -1,3 +1,5 @@ +#![allow(clippy::useless_format)] + use std::fs; use std::process::{self, Command}; @@ -17,9 +19,10 @@ fn run(cmd: &mut Command) { fn build_sysroot(b: SysrootBuilder) { let src_dir = rustc_sysroot_src(Command::new("rustc")).unwrap(); - b.cargo(Command::new("cargo")) - .build_from_source(&src_dir) - .unwrap(); + let mut cargo = Command::new("cargo"); + // Cargo complains about unknown `-Z` flags but not about unknown env vars. :) + cargo.env("CARGO_UNSTABLE_JSON_TARGET_SPEC", "true"); + b.cargo(cargo).build_from_source(&src_dir).unwrap(); } fn test_sysroot_build(target: &str, mode: BuildMode, rustc_version: &VersionMeta) { @@ -91,28 +94,11 @@ fn no_std() { #[test] fn json_target() { - // The syntax for `target-pointer-width` changed from `"64"`` to `64`. Figure out which one - // this rustc needs... - let sample_json = Command::new("rustc") - .args([ - "-Zunstable-options", - "--print=target-spec-json", - "--target=x86_64-unknown-none", - ]) - .output() - .unwrap() - .stdout; - let sample_json = String::from_utf8(sample_json).unwrap(); - let ptr_width = if sample_json.contains(r#""target-pointer-width": 64"#) { - "64" - } else { - r#""64""# - }; let target = format!( r#"{{ "llvm-target": "x86_64-unknown-none", "target-endian": "little", - "target-pointer-width": {ptr_width}, + "target-pointer-width": 64, "target-c-int-width": 32, "data-layout": "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128", "arch": "x86_64",