Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ anstream = "0.6.18"

[dev-dependencies]
cargo_metadata = "0.23"
ui_test = "0.30.2"
ui_test = "0.30.5"
regex = "1.5.5"
serde = { version = "1.0.145", features = ["derive"] }
serde_json = "1.0.122"
Expand Down
62 changes: 57 additions & 5 deletions tests/compile-test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -89,11 +89,33 @@ fn internal_extern_flags() -> Vec<String> {
help: Try adding to dev-dependencies in Cargo.toml\n\
help: Be sure to also add `extern crate ...;` to tests/compile-test.rs",
);
crates

let mut args: Vec<String> = crates
.into_iter()
.map(|(name, path)| format!("--extern={name}={path}"))
.chain([format!("-Ldependency={}", deps_path.display())])
.collect()
.collect();

if deps_path.ends_with("deps") {
args.push(format!("-Ldependency={}", deps_path.display()));
} else {
// If the dep_path does not point to `/deps` it very likely means Cargo is using the v2 build-dir
// layout
assert!(deps_path.ends_with("out"));

// Get a path to `target/<platform-profile>/build`
let build_dir = {
let mut d = deps_path.to_path_buf();
d.pop(); // remove `out`
d.pop(); // remove `<hash>`
d.pop(); // remove `<pkgname>`
d
};

let out_dirs = discover_out_dirs(&build_dir);
args.extend(out_dirs.iter().map(|path| format!("-Ldependency={}", path.display())));
}

args
}

// whether to run internal tests or not
Expand Down Expand Up @@ -214,8 +236,21 @@ impl TestContext {
config.program.envs.push(("RUSTC_ICE".into(), Some("0".into())));

if let Some(host_libs) = option_env!("HOST_LIBS") {
let dep = format!("-Ldependency={}", Path::new(host_libs).join("deps").display());
config.program.args.push(dep.into());
let deps_dir = Path::new(host_libs).join("deps");

if deps_dir.exists() {
let dep = format!("-Ldependency={}", deps_dir.display());
config.program.args.push(dep.into());
} else {
// If `/deps` does not exist, assume Cargo v2 build-dir layout
let build_dir = Path::new(host_libs).join("build");
let dependencies = discover_out_dirs(&build_dir);
Copy link
Copy Markdown
Member

@samueltardieu samueltardieu May 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not familiar with the new layout, but when I look at my local Clippy ui_test's debug/build I can see several versions of the proc-macro2 crate:

libc-cef78c73a588beef
lock_api-322a98564ef4bbc0
parking_lot_core-6b4e77ee5c9c43aa
proc-macro2-29604991fe83921e
proc-macro2-70ecf6aed0aea7e6
proc-macro2-b8940090bfe979a4
serde-de22b5d9748dde25

Can this be a problem, or will the compiler sort them out? (even though there is a debug/deps so this won't be used right now)

View changes since the review

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is expected. Those are actually different Cargo "build units" of the same crate.
proc-macro2 has a build.rs meaning those 3 units are likely:

  • the proc-macro library itself (.rmeta)
  • the build script binary (build_script_build[.exe])
  • the build script execution

This should not affect compilation as Cargo know's which units it needs to add.
In the case of the test logic, there should be no difference since previous we were adding -L .../deps which adds everything to library search path. With the new layout we have to pass multiple -L args since they are in different directories, but the result should stay the same.

Ideally Cargo could have a better mechanism for exposing these paths in the future.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Another novice question: isn't there a risk if an old deps directory still lies around when build starts being used? Wouldn't deps get precedence even though it is now obsolete?

Copy link
Copy Markdown
Member Author

@ranger-ross ranger-ross May 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That is correct. (though only for the tests, cargo build will always use the correct one)
I went with a backwards compatible change here to ease the transition as there are many changes needed to enable in rust-lang/rust.

Once the new build-dir layout is stabilized we can remove support for building with older Cargos that still use deps


for dep in dependencies {
let dep = format!("-Ldependency={}", dep.display());
config.program.args.push(dep.into());
}
}
}
if let Some(sysroot) = option_env!("TEST_SYSROOT") {
config.program.args.push(format!("--sysroot={sysroot}").into());
Expand Down Expand Up @@ -648,3 +683,20 @@ impl LintMetadata {
}
}
}

/// Gets all of the `out` dirs in a given Cargo `build-dir/<profile>/build` dir.
fn discover_out_dirs(dir: &Path) -> Vec<PathBuf> {
if !dir.exists() {
return Vec::new();
}

let read_dir = |path: &Path| path.read_dir().ok().into_iter().flatten().filter_map(Result::ok);
dir.read_dir()
.unwrap_or_else(|e| panic!("Couldn't read {}: {}", dir.display(), e))
.map(|e| e.unwrap())
.flat_map(|e| read_dir(&e.path()))
.flat_map(|e| read_dir(&e.path()))
.map(|e| e.path())
.filter(|path| path.ends_with("out"))
.collect::<Vec<_>>()
}