Skip to content

Commit 4e0b8ff

Browse files
committed
Use binary-dep-depinfo to resolve UI dependencies
1 parent a4910a4 commit 4e0b8ff

File tree

3 files changed

+55
-57
lines changed

3 files changed

+55
-57
lines changed

.cargo/config

+2-1
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,5 @@ lintcheck = "run --target-dir lintcheck/target --package lintcheck --bin lintche
55
collect-metadata = "test --test dogfood --features metadata-collector-lint -- run_metadata_collection_lint --ignored"
66

77
[build]
8-
rustflags = ["-Zunstable-options"]
8+
# -Zbinary-dep-depinfo allows us to track which rlib files to use for compiling UI tests
9+
rustflags = ["-Zunstable-options", "-Zbinary-dep-depinfo"]

Cargo.toml

+9-4
Original file line numberDiff line numberDiff line change
@@ -32,11 +32,7 @@ tempfile = { version = "3.1.0", optional = true }
3232
cargo_metadata = "0.12"
3333
compiletest_rs = { version = "0.6.0", features = ["tmp"] }
3434
tester = "0.9"
35-
serde = { version = "1.0", features = ["derive"] }
36-
derive-new = "0.5"
3735
regex = "1.4"
38-
quote = "1"
39-
syn = { version = "1", features = ["full"] }
4036
# This is used by the `collect-metadata` alias.
4137
filetime = "0.2"
4238

@@ -45,6 +41,15 @@ filetime = "0.2"
4541
# for more information.
4642
rustc-workspace-hack = "1.0.0"
4743

44+
# UI test dependencies
45+
clippy_utils = { path = "clippy_utils" }
46+
derive-new = "0.5"
47+
if_chain = "1.0"
48+
itertools = "0.10.1"
49+
quote = "1"
50+
serde = { version = "1.0", features = ["derive"] }
51+
syn = { version = "1", features = ["full"] }
52+
4853
[build-dependencies]
4954
rustc_tools_util = { version = "0.2.0", path = "rustc_tools_util" }
5055

tests/compile-test.rs

+44-52
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,15 @@
22
#![feature(once_cell)]
33
#![feature(try_blocks)]
44

5+
// Some `extern crate`s are needed to ensure that UI test dependencies
6+
// show up in the depinfo file.
7+
extern crate clippy_utils;
8+
extern crate derive_new;
9+
extern crate if_chain;
10+
extern crate itertools;
11+
extern crate quote;
12+
extern crate syn;
13+
514
use compiletest_rs as compiletest;
615
use compiletest_rs::common::Mode as TestMode;
716

@@ -38,6 +47,7 @@ fn third_party_crates() -> String {
3847
static CRATES: &[&str] = &[
3948
"clippy_lints",
4049
"clippy_utils",
50+
"derive_new",
4151
"if_chain",
4252
"itertools",
4353
"quote",
@@ -46,50 +56,38 @@ fn third_party_crates() -> String {
4656
"serde_derive",
4757
"syn",
4858
];
49-
let dep_dir = cargo::TARGET_LIB.join("deps");
50-
let mut crates: HashMap<&str, Vec<PathBuf>> = HashMap::with_capacity(CRATES.len());
51-
let mut flags = String::new();
52-
for entry in fs::read_dir(dep_dir).unwrap().flatten() {
53-
let path = entry.path();
54-
if let Some(name) = try {
55-
let name = path.file_name()?.to_str()?;
56-
let (name, _) = name.strip_suffix(".rlib")?.strip_prefix("lib")?.split_once('-')?;
57-
CRATES.iter().copied().find(|&c| c == name)?
58-
} {
59-
flags += &format!(" --extern {}={}", name, path.display());
60-
crates.entry(name).or_default().push(path.clone());
61-
}
62-
}
63-
crates.retain(|_, paths| paths.len() > 1);
64-
if !crates.is_empty() {
65-
let crate_names = crates.keys().map(|s| format!("`{}`", s)).collect::<Vec<_>>().join(", ");
66-
// add backslashes for an easy copy-paste `rm` command
67-
let paths = crates
68-
.into_values()
69-
.flatten()
70-
.map(|p| strip_current_dir(&p).display().to_string())
71-
.collect::<Vec<_>>()
72-
.join(" \\\n");
73-
// Check which action should be done in order to remove compiled deps.
74-
// If pre-installed version of compiler is used, `cargo clean` will do.
75-
// Otherwise (for bootstrapped compiler), the dependencies directory
76-
// must be removed manually.
77-
let suggested_action = if std::env::var_os("RUSTC_BOOTSTRAP").is_some() {
78-
"removing the stageN-tools directory"
79-
} else {
80-
"running `cargo clean`"
81-
};
8259

83-
panic!(
84-
"\n----------------------------------------------------------------------\n\
85-
ERROR: Found multiple rlibs for crates: {}\n\
86-
Try {} or remove the following files:\n\n{}\n\n\
87-
For details on this error see https://github.com/rust-lang/rust-clippy/issues/7343\n\
88-
----------------------------------------------------------------------\n",
89-
crate_names, suggested_action, paths
90-
);
60+
let depinfo = {
61+
let exe_path = env::current_exe().unwrap();
62+
let depinfo_filename = format!("{}.d", exe_path.file_stem().unwrap().to_str().unwrap());
63+
let mut dep_info_path = exe_path;
64+
dep_info_path.set_file_name(depinfo_filename);
65+
std::fs::read_to_string(dep_info_path).unwrap()
66+
};
67+
let mut crates: HashMap<&str, &str> = HashMap::with_capacity(CRATES.len());
68+
for line in depinfo.lines() {
69+
let path = try {
70+
let path = line.strip_suffix(':')?;
71+
let part = path
72+
.strip_suffix(".rlib")
73+
.or_else(|| path.strip_suffix(".so"))
74+
.or_else(|| path.strip_suffix(".dylib"))
75+
.or_else(|| path.strip_suffix(".dll"))?;
76+
let part = part.rsplit_once('-')?.0;
77+
let name = part.rsplit_once(|c| matches!(c, '/' | '\\'))?.1.strip_prefix("lib")?;
78+
CRATES.contains(&name).then(|| (name, path))?
79+
};
80+
if let Some((name, path)) = path {
81+
// A dependency may be listed twice if it is available in sysroot,
82+
// and the sysroot dependencies are listed first. As of the writing,
83+
// this only seems to apply to if_chain.
84+
crates.insert(name, path);
85+
}
9186
}
92-
flags
87+
crates
88+
.into_iter()
89+
.map(|(name, path)| format!("--extern {}={} ", name, path))
90+
.collect()
9391
}
9492

9593
fn default_config() -> compiletest::Config {
@@ -105,8 +103,11 @@ fn default_config() -> compiletest::Config {
105103
config.compile_lib_path = path;
106104
}
107105

106+
// Using `-L dependency={}` enforces that external dependencies are added with `--extern`.
107+
// This is valuable because a) it allows us to monitor what external dependencies are used
108+
// and b) it ensures that conflicting rlibs are resolved properly.
108109
config.target_rustcflags = Some(format!(
109-
"--emit=metadata -L {0} -L {1} -Dwarnings -Zui-testing {2}",
110+
"--emit=metadata -L dependency={} -L dependency={} -Dwarnings -Zui-testing {}",
110111
host_lib().join("deps").display(),
111112
cargo::TARGET_LIB.join("deps").display(),
112113
third_party_crates(),
@@ -316,12 +317,3 @@ impl Drop for VarGuard {
316317
}
317318
}
318319
}
319-
320-
fn strip_current_dir(path: &Path) -> &Path {
321-
if let Ok(curr) = env::current_dir() {
322-
if let Ok(stripped) = path.strip_prefix(curr) {
323-
return stripped;
324-
}
325-
}
326-
path
327-
}

0 commit comments

Comments
 (0)