Skip to content

Commit 57b7597

Browse files
committed
Auto merge of #9363 - ehuss:cargo-env-fingerprint, r=alexcrichton
Track "CARGO" in environment fingerprint. There is an issue where if a package includes an `env!("CARGO")`, that value is not tracked in the fingerprint. If different cargos are used, it will not rebuild. This changes it so that the path to cargo will be tracked in the fingerprint if the CARGO env var is in the dep-info file. This came up with rust's build system where it [tracks the env](https://github.com/rust-lang/rust/blob/60158f4a7cf3e3063df6127d3f0d206921d285b0/src/bootstrap/config.rs#L574). If you build rust once, and then change the `cargo` value in `config.toml` and try building again, it would not pick up the change which caused me some confusion. In theory, cargo could fingerprint this every time, but I figure that could be disruptive and trigger needlessly in some situations. This diff is a little bigger than I would like for such an obscure case. As an alternative, I think rustbuild could just print `cargo:rerun-if-env-changed=CARGO`, but I figure this could potentially be useful for other projects.
2 parents e870eac + 2551535 commit 57b7597

File tree

2 files changed

+93
-4
lines changed

2 files changed

+93
-4
lines changed

src/cargo/core/compiler/fingerprint.rs

Lines changed: 33 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -335,6 +335,7 @@ use crate::util;
335335
use crate::util::errors::{CargoResult, CargoResultExt};
336336
use crate::util::interning::InternedString;
337337
use crate::util::{internal, path_args, profile};
338+
use crate::CARGO_ENV;
338339

339340
use super::custom_build::BuildDeps;
340341
use super::job::{Job, Work};
@@ -712,6 +713,7 @@ impl LocalFingerprint {
712713
mtime_cache: &mut HashMap<PathBuf, FileTime>,
713714
pkg_root: &Path,
714715
target_root: &Path,
716+
cargo_exe: &Path,
715717
) -> CargoResult<Option<StaleItem>> {
716718
match self {
717719
// We need to parse `dep_info`, learn about the crate's dependencies.
@@ -727,7 +729,21 @@ impl LocalFingerprint {
727729
None => return Ok(Some(StaleItem::MissingFile(dep_info))),
728730
};
729731
for (key, previous) in info.env.iter() {
730-
let current = env::var(key).ok();
732+
let current = if key == CARGO_ENV {
733+
Some(
734+
cargo_exe
735+
.to_str()
736+
.ok_or_else(|| {
737+
format_err!(
738+
"cargo exe path {} must be valid UTF-8",
739+
cargo_exe.display()
740+
)
741+
})?
742+
.to_string(),
743+
)
744+
} else {
745+
env::var(key).ok()
746+
};
731747
if current == *previous {
732748
continue;
733749
}
@@ -980,6 +996,7 @@ impl Fingerprint {
980996
mtime_cache: &mut HashMap<PathBuf, FileTime>,
981997
pkg_root: &Path,
982998
target_root: &Path,
999+
cargo_exe: &Path,
9831000
) -> CargoResult<()> {
9841001
assert!(!self.fs_status.up_to_date());
9851002

@@ -1071,7 +1088,9 @@ impl Fingerprint {
10711088
// files for this package itself. If we do find something log a helpful
10721089
// message and bail out so we stay stale.
10731090
for local in self.local.get_mut().unwrap().iter() {
1074-
if let Some(item) = local.find_stale_item(mtime_cache, pkg_root, target_root)? {
1091+
if let Some(item) =
1092+
local.find_stale_item(mtime_cache, pkg_root, target_root, cargo_exe)?
1093+
{
10751094
item.log();
10761095
return Ok(());
10771096
}
@@ -1256,7 +1275,13 @@ fn calculate(cx: &mut Context<'_, '_>, unit: &Unit) -> CargoResult<Arc<Fingerpri
12561275
// After we built the initial `Fingerprint` be sure to update the
12571276
// `fs_status` field of it.
12581277
let target_root = target_root(cx);
1259-
fingerprint.check_filesystem(&mut cx.mtime_cache, unit.pkg.root(), &target_root)?;
1278+
let cargo_exe = cx.bcx.config.cargo_exe()?;
1279+
fingerprint.check_filesystem(
1280+
&mut cx.mtime_cache,
1281+
unit.pkg.root(),
1282+
&target_root,
1283+
cargo_exe,
1284+
)?;
12601285

12611286
let fingerprint = Arc::new(fingerprint);
12621287
cx.fingerprints
@@ -1850,9 +1875,13 @@ pub fn translate_dep_info(
18501875
// you write a binary that does `println!("{}", env!("OUT_DIR"))` we won't
18511876
// recompile that if you move the target directory. Hopefully that's not too
18521877
// bad of an issue for now...
1878+
//
1879+
// This also includes `CARGO` since if the code is explicitly wanting to
1880+
// know that path, it should be rebuilt if it changes. The CARGO path is
1881+
// not tracked elsewhere in the fingerprint.
18531882
on_disk_info
18541883
.env
1855-
.retain(|(key, _)| !rustc_cmd.get_envs().contains_key(key));
1884+
.retain(|(key, _)| !rustc_cmd.get_envs().contains_key(key) || key == CARGO_ENV);
18561885

18571886
for file in depinfo.files {
18581887
// The path may be absolute or relative, canonical or not. Make sure

tests/testsuite/freshness.rs

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2581,3 +2581,63 @@ fn env_build_script_no_rebuild() {
25812581
p.cargo("build").run();
25822582
p.cargo("build").with_stderr("[FINISHED] [..]").run();
25832583
}
2584+
2585+
#[cargo_test]
2586+
fn cargo_env_changes() {
2587+
// Checks that changes to the env var CARGO in the dep-info file triggers
2588+
// a rebuild.
2589+
let p = project()
2590+
.file("Cargo.toml", &basic_manifest("foo", "1.0.0"))
2591+
.file(
2592+
"src/main.rs",
2593+
r#"
2594+
fn main() {
2595+
println!("{:?}", env!("CARGO"));
2596+
}
2597+
"#,
2598+
)
2599+
.build();
2600+
2601+
let cargo_exe = cargo_test_support::cargo_exe();
2602+
let other_cargo_path = p.root().join(cargo_exe.file_name().unwrap());
2603+
std::fs::hard_link(&cargo_exe, &other_cargo_path).unwrap();
2604+
let other_cargo = || {
2605+
let mut pb = cargo_test_support::process(&other_cargo_path);
2606+
pb.cwd(p.root());
2607+
cargo_test_support::execs().with_process_builder(pb)
2608+
};
2609+
2610+
p.cargo("check").run();
2611+
other_cargo()
2612+
.arg("check")
2613+
.arg("-v")
2614+
.with_stderr(
2615+
"\
2616+
[CHECKING] foo [..]
2617+
[RUNNING] `rustc [..]
2618+
[FINISHED] [..]
2619+
",
2620+
)
2621+
.run();
2622+
2623+
// And just to confirm that without using env! it doesn't rebuild.
2624+
p.change_file("src/main.rs", "fn main() {}");
2625+
p.cargo("check")
2626+
.with_stderr(
2627+
"\
2628+
[CHECKING] foo [..]
2629+
[FINISHED] [..]
2630+
",
2631+
)
2632+
.run();
2633+
other_cargo()
2634+
.arg("check")
2635+
.arg("-v")
2636+
.with_stderr(
2637+
"\
2638+
[FRESH] foo [..]
2639+
[FINISHED] [..]
2640+
",
2641+
)
2642+
.run();
2643+
}

0 commit comments

Comments
 (0)