Skip to content

Commit f6070b3

Browse files
committed
Don't re-use rustc cache when RUSTC_WRAPPER changes
We cache initial `rustc --version` invocations, to speed up noop builds. We check the mtime of `rustc` to bust the cache if the complier changed. However, before this PR, we didn't look at mtimes of `RUSTC_WRAPPER` / `RUSTC_WORKSPACE_WRAPPER`, so we could've re-use old cache with new wrapper.
1 parent 57c512b commit f6070b3

File tree

3 files changed

+146
-33
lines changed

3 files changed

+146
-33
lines changed

src/cargo/core/compiler/build_context/target_info.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,7 @@ impl TargetInfo {
139139
"RUSTFLAGS",
140140
)?;
141141
let extra_fingerprint = kind.fingerprint_hash();
142-
let mut process = rustc.process();
142+
let mut process = rustc.workspace_process();
143143
process
144144
.arg("-")
145145
.arg("--crate-name")

src/cargo/util/rustc.rs

Lines changed: 39 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,13 @@ impl Rustc {
4545
) -> CargoResult<Rustc> {
4646
let _p = profile::start("Rustc::new");
4747

48-
let mut cache = Cache::load(&path, rustup_rustc, cache_location);
48+
let mut cache = Cache::load(
49+
wrapper.as_deref(),
50+
workspace_wrapper.as_deref(),
51+
&path,
52+
rustup_rustc,
53+
cache_location,
54+
);
4955

5056
let mut cmd = ProcessBuilder::new(&path);
5157
cmd.arg("-vV");
@@ -154,8 +160,17 @@ struct Output {
154160
}
155161

156162
impl Cache {
157-
fn load(rustc: &Path, rustup_rustc: &Path, cache_location: Option<PathBuf>) -> Cache {
158-
match (cache_location, rustc_fingerprint(rustc, rustup_rustc)) {
163+
fn load(
164+
wrapper: Option<&Path>,
165+
workspace_wrapper: Option<&Path>,
166+
rustc: &Path,
167+
rustup_rustc: &Path,
168+
cache_location: Option<PathBuf>,
169+
) -> Cache {
170+
match (
171+
cache_location,
172+
rustc_fingerprint(wrapper, workspace_wrapper, rustc, rustup_rustc),
173+
) {
159174
(Some(cache_location), Ok(rustc_fingerprint)) => {
160175
let empty = CacheData {
161176
rustc_fingerprint,
@@ -272,13 +287,29 @@ impl Drop for Cache {
272287
}
273288
}
274289

275-
fn rustc_fingerprint(path: &Path, rustup_rustc: &Path) -> CargoResult<u64> {
290+
fn rustc_fingerprint(
291+
wrapper: Option<&Path>,
292+
workspace_wrapper: Option<&Path>,
293+
rustc: &Path,
294+
rustup_rustc: &Path,
295+
) -> CargoResult<u64> {
276296
let mut hasher = StableHasher::new();
277297

278-
let path = paths::resolve_executable(path)?;
279-
path.hash(&mut hasher);
298+
let hash_exe = |hasher: &mut _, path| -> CargoResult<()> {
299+
let path = paths::resolve_executable(path)?;
300+
path.hash(hasher);
301+
302+
paths::mtime(&path)?.hash(hasher);
303+
Ok(())
304+
};
280305

281-
paths::mtime(&path)?.hash(&mut hasher);
306+
hash_exe(&mut hasher, rustc)?;
307+
if let Some(wrapper) = wrapper {
308+
hash_exe(&mut hasher, wrapper)?;
309+
}
310+
if let Some(workspace_wrapper) = workspace_wrapper {
311+
hash_exe(&mut hasher, workspace_wrapper)?;
312+
}
282313

283314
// Rustup can change the effective compiler without touching
284315
// the `rustc` binary, so we try to account for this here.
@@ -291,7 +322,7 @@ fn rustc_fingerprint(path: &Path, rustup_rustc: &Path) -> CargoResult<u64> {
291322
//
292323
// If we don't see rustup env vars, but it looks like the compiler
293324
// is managed by rustup, we conservatively bail out.
294-
let maybe_rustup = rustup_rustc == path;
325+
let maybe_rustup = rustup_rustc == rustc;
295326
match (
296327
maybe_rustup,
297328
env::var("RUSTUP_HOME"),

tests/testsuite/rustc_info_cache.rs

Lines changed: 106 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,40 +1,40 @@
11
//! Tests for the cache file for the rustc version info.
22
3-
use cargo_test_support::paths::CargoPathExt;
3+
use cargo_test_support::{basic_bin_manifest, paths::CargoPathExt};
44
use cargo_test_support::{basic_manifest, project};
55
use std::env;
66

7+
const MISS: &str = "[..] rustc info cache miss[..]";
8+
const HIT: &str = "[..]rustc info cache hit[..]";
9+
const UPDATE: &str = "[..]updated rustc info cache[..]";
10+
711
#[cargo_test]
812
fn rustc_info_cache() {
913
let p = project()
1014
.file("src/main.rs", r#"fn main() { println!("hello"); }"#)
1115
.build();
1216

13-
let miss = "[..] rustc info cache miss[..]";
14-
let hit = "[..]rustc info cache hit[..]";
15-
let update = "[..]updated rustc info cache[..]";
16-
1717
p.cargo("build")
1818
.env("CARGO_LOG", "cargo::util::rustc=debug")
1919
.with_stderr_contains("[..]failed to read rustc info cache[..]")
20-
.with_stderr_contains(miss)
21-
.with_stderr_does_not_contain(hit)
22-
.with_stderr_contains(update)
20+
.with_stderr_contains(MISS)
21+
.with_stderr_does_not_contain(HIT)
22+
.with_stderr_contains(UPDATE)
2323
.run();
2424

2525
p.cargo("build")
2626
.env("CARGO_LOG", "cargo::util::rustc=debug")
2727
.with_stderr_contains("[..]reusing existing rustc info cache[..]")
28-
.with_stderr_contains(hit)
29-
.with_stderr_does_not_contain(miss)
30-
.with_stderr_does_not_contain(update)
28+
.with_stderr_contains(HIT)
29+
.with_stderr_does_not_contain(MISS)
30+
.with_stderr_does_not_contain(UPDATE)
3131
.run();
3232

3333
p.cargo("build")
3434
.env("CARGO_LOG", "cargo::util::rustc=debug")
3535
.env("CARGO_CACHE_RUSTC_INFO", "0")
3636
.with_stderr_contains("[..]rustc info cache disabled[..]")
37-
.with_stderr_does_not_contain(update)
37+
.with_stderr_does_not_contain(UPDATE)
3838
.run();
3939

4040
let other_rustc = {
@@ -68,18 +68,18 @@ fn rustc_info_cache() {
6868
.env("CARGO_LOG", "cargo::util::rustc=debug")
6969
.env("RUSTC", other_rustc.display().to_string())
7070
.with_stderr_contains("[..]different compiler, creating new rustc info cache[..]")
71-
.with_stderr_contains(miss)
72-
.with_stderr_does_not_contain(hit)
73-
.with_stderr_contains(update)
71+
.with_stderr_contains(MISS)
72+
.with_stderr_does_not_contain(HIT)
73+
.with_stderr_contains(UPDATE)
7474
.run();
7575

7676
p.cargo("build")
7777
.env("CARGO_LOG", "cargo::util::rustc=debug")
7878
.env("RUSTC", other_rustc.display().to_string())
7979
.with_stderr_contains("[..]reusing existing rustc info cache[..]")
80-
.with_stderr_contains(hit)
81-
.with_stderr_does_not_contain(miss)
82-
.with_stderr_does_not_contain(update)
80+
.with_stderr_contains(HIT)
81+
.with_stderr_does_not_contain(MISS)
82+
.with_stderr_does_not_contain(UPDATE)
8383
.run();
8484

8585
other_rustc.move_into_the_future();
@@ -88,17 +88,99 @@ fn rustc_info_cache() {
8888
.env("CARGO_LOG", "cargo::util::rustc=debug")
8989
.env("RUSTC", other_rustc.display().to_string())
9090
.with_stderr_contains("[..]different compiler, creating new rustc info cache[..]")
91-
.with_stderr_contains(miss)
92-
.with_stderr_does_not_contain(hit)
93-
.with_stderr_contains(update)
91+
.with_stderr_contains(MISS)
92+
.with_stderr_does_not_contain(HIT)
93+
.with_stderr_contains(UPDATE)
9494
.run();
9595

9696
p.cargo("build")
9797
.env("CARGO_LOG", "cargo::util::rustc=debug")
9898
.env("RUSTC", other_rustc.display().to_string())
9999
.with_stderr_contains("[..]reusing existing rustc info cache[..]")
100-
.with_stderr_contains(hit)
101-
.with_stderr_does_not_contain(miss)
102-
.with_stderr_does_not_contain(update)
100+
.with_stderr_contains(HIT)
101+
.with_stderr_does_not_contain(MISS)
102+
.with_stderr_does_not_contain(UPDATE)
103103
.run();
104104
}
105+
106+
#[cargo_test]
107+
fn rustc_info_cache_with_wrappers() {
108+
let wrapper_project = project()
109+
.at("wrapper")
110+
.file("Cargo.toml", &basic_bin_manifest("wrapper"))
111+
.file("src/main.rs", r#"fn main() { }"#)
112+
.build();
113+
let wrapper = wrapper_project.bin("wrapper");
114+
115+
let p = project()
116+
.file(
117+
"Cargo.toml",
118+
r#"
119+
[package]
120+
name = "test"
121+
version = "0.0.0"
122+
authors = []
123+
[workspace]
124+
"#,
125+
)
126+
.file("src/main.rs", r#"fn main() { println!("hello"); }"#)
127+
.build();
128+
129+
for &wrapper_env in ["RUSTC_WRAPPER", "RUSTC_WORKSPACE_WRAPPER"].iter() {
130+
p.cargo("clean").with_status(0).run();
131+
wrapper_project.change_file(
132+
"src/main.rs",
133+
r#"
134+
fn main() {
135+
let mut args = std::env::args_os();
136+
let _me = args.next().unwrap();
137+
let rustc = args.next().unwrap();
138+
let status = std::process::Command::new(rustc).args(args).status().unwrap();
139+
std::process::exit(if status.success() { 0 } else { 1 })
140+
}
141+
"#,
142+
);
143+
wrapper_project.cargo("build").with_status(0).run();
144+
145+
p.cargo("build")
146+
.env("CARGO_LOG", "cargo::util::rustc=debug")
147+
.env(wrapper_env, &wrapper)
148+
.with_stderr_contains("[..]failed to read rustc info cache[..]")
149+
.with_stderr_contains(MISS)
150+
.with_stderr_contains(UPDATE)
151+
.with_stderr_does_not_contain(HIT)
152+
.with_status(0)
153+
.run();
154+
p.cargo("build")
155+
.env("CARGO_LOG", "cargo::util::rustc=debug")
156+
.env(wrapper_env, &wrapper)
157+
.with_stderr_contains("[..]reusing existing rustc info cache[..]")
158+
.with_stderr_contains(HIT)
159+
.with_stderr_does_not_contain(UPDATE)
160+
.with_stderr_does_not_contain(MISS)
161+
.with_status(0)
162+
.run();
163+
164+
wrapper_project.change_file("src/main.rs", r#"fn main() { panic!() }"#);
165+
wrapper_project.cargo("build").with_status(0).run();
166+
167+
p.cargo("build")
168+
.env("CARGO_LOG", "cargo::util::rustc=debug")
169+
.env(wrapper_env, &wrapper)
170+
.with_stderr_contains("[..]different compiler, creating new rustc info cache[..]")
171+
.with_stderr_contains(MISS)
172+
.with_stderr_contains(UPDATE)
173+
.with_stderr_does_not_contain(HIT)
174+
.with_status(101)
175+
.run();
176+
p.cargo("build")
177+
.env("CARGO_LOG", "cargo::util::rustc=debug")
178+
.env(wrapper_env, &wrapper)
179+
.with_stderr_contains("[..]reusing existing rustc info cache[..]")
180+
.with_stderr_contains(HIT)
181+
.with_stderr_does_not_contain(UPDATE)
182+
.with_stderr_does_not_contain(MISS)
183+
.with_status(101)
184+
.run();
185+
}
186+
}

0 commit comments

Comments
 (0)