Skip to content

Commit 0a38a21

Browse files
committed
Auto merge of #9647 - ehuss:fingerprint-linker, r=alexcrichton
Include the linker in the fingerprint. This adds the linker from the `[target]` config table to the fingerprint. Previously, changing the value would not trigger a rebuild.
2 parents 6e31c13 + 28c3bef commit 0a38a21

File tree

4 files changed

+60
-42
lines changed

4 files changed

+60
-42
lines changed

crates/cargo-test-support/src/lib.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1035,6 +1035,11 @@ pub fn rustc_host() -> &'static str {
10351035
&RUSTC_INFO.host
10361036
}
10371037

1038+
/// The host triple suitable for use in a cargo environment variable (uppercased).
1039+
pub fn rustc_host_env() -> String {
1040+
rustc_host().to_uppercase().replace('-', "_")
1041+
}
1042+
10381043
pub fn is_nightly() -> bool {
10391044
let vv = &RUSTC_INFO.verbose_version;
10401045
env::var("CARGO_TEST_DISABLE_NIGHTLY").is_err()

src/cargo/core/compiler/fingerprint.rs

Lines changed: 25 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -315,7 +315,7 @@
315315
use std::collections::hash_map::{Entry, HashMap};
316316
use std::convert::TryInto;
317317
use std::env;
318-
use std::hash::{self, Hasher};
318+
use std::hash::{self, Hash, Hasher};
319319
use std::path::{Path, PathBuf};
320320
use std::str;
321321
use std::sync::{Arc, Mutex};
@@ -334,7 +334,7 @@ use crate::core::Package;
334334
use crate::util;
335335
use crate::util::errors::CargoResult;
336336
use crate::util::interning::InternedString;
337-
use crate::util::{internal, path_args, profile};
337+
use crate::util::{internal, path_args, profile, StableHasher};
338338
use crate::CARGO_ENV;
339339

340340
use super::custom_build::BuildDeps;
@@ -502,7 +502,7 @@ struct DepFingerprint {
502502
/// as a fingerprint (all source files must be modified *before* this mtime).
503503
/// This dep-info file is not generated, however, until after the crate is
504504
/// compiled. As a result, this structure can be thought of as a fingerprint
505-
/// to-be. The actual value can be calculated via `hash()`, but the operation
505+
/// to-be. The actual value can be calculated via `hash_u64()`, but the operation
506506
/// may fail as some files may not have been generated.
507507
///
508508
/// Note that dependencies are taken into account for fingerprints because rustc
@@ -594,7 +594,7 @@ impl Serialize for DepFingerprint {
594594
&self.pkg_id,
595595
&self.name,
596596
&self.public,
597-
&self.fingerprint.hash(),
597+
&self.fingerprint.hash_u64(),
598598
)
599599
.serialize(ser)
600600
}
@@ -812,7 +812,7 @@ impl Fingerprint {
812812
*self.memoized_hash.lock().unwrap() = None;
813813
}
814814

815-
fn hash(&self) -> u64 {
815+
fn hash_u64(&self) -> u64 {
816816
if let Some(s) = *self.memoized_hash.lock().unwrap() {
817817
return s;
818818
}
@@ -956,13 +956,13 @@ impl Fingerprint {
956956
return Err(e);
957957
}
958958

959-
if a.fingerprint.hash() != b.fingerprint.hash() {
959+
if a.fingerprint.hash_u64() != b.fingerprint.hash_u64() {
960960
let e = format_err!(
961961
"new ({}/{:x}) != old ({}/{:x})",
962962
a.name,
963-
a.fingerprint.hash(),
963+
a.fingerprint.hash_u64(),
964964
b.name,
965-
b.fingerprint.hash()
965+
b.fingerprint.hash_u64()
966966
)
967967
.context("unit dependency information changed");
968968
return Err(e);
@@ -1145,7 +1145,7 @@ impl hash::Hash for Fingerprint {
11451145
name.hash(h);
11461146
public.hash(h);
11471147
// use memoized dep hashes to avoid exponential blowup
1148-
h.write_u64(Fingerprint::hash(fingerprint));
1148+
h.write_u64(fingerprint.hash_u64());
11491149
}
11501150
}
11511151
}
@@ -1318,12 +1318,17 @@ fn calculate_normal(cx: &mut Context<'_, '_>, unit: &Unit) -> CargoResult<Finger
13181318
// Include metadata since it is exposed as environment variables.
13191319
let m = unit.pkg.manifest().metadata();
13201320
let metadata = util::hash_u64((&m.authors, &m.description, &m.homepage, &m.repository));
1321-
let mut config = 0u64;
1321+
let mut config = StableHasher::new();
1322+
if let Some(linker) = cx.bcx.linker(unit.kind) {
1323+
linker.hash(&mut config);
1324+
}
13221325
if unit.mode.is_doc() && cx.bcx.config.cli_unstable().rustdoc_map {
1323-
config = config.wrapping_add(cx.bcx.config.doc_extern_map().map_or(0, util::hash_u64));
1326+
if let Ok(map) = cx.bcx.config.doc_extern_map() {
1327+
map.hash(&mut config);
1328+
}
13241329
}
13251330
if let Some(allow_features) = &cx.bcx.config.cli_unstable().allow_features {
1326-
config = config.wrapping_add(util::hash_u64(allow_features));
1331+
allow_features.hash(&mut config);
13271332
}
13281333
let compile_kind = unit.kind.fingerprint_hash();
13291334
Ok(Fingerprint {
@@ -1338,7 +1343,7 @@ fn calculate_normal(cx: &mut Context<'_, '_>, unit: &Unit) -> CargoResult<Finger
13381343
local: Mutex::new(local),
13391344
memoized_hash: Mutex::new(None),
13401345
metadata,
1341-
config,
1346+
config: config.finish(),
13421347
compile_kind,
13431348
rustflags: extra_flags,
13441349
fs_status: FsStatus::Stale,
@@ -1570,14 +1575,14 @@ fn write_fingerprint(loc: &Path, fingerprint: &Fingerprint) -> CargoResult<()> {
15701575
// fingerprint::new().rustc == 0, make sure it doesn't make it to the file system.
15711576
// This is mostly so outside tools can reliably find out what rust version this file is for,
15721577
// as we can use the full hash.
1573-
let hash = fingerprint.hash();
1578+
let hash = fingerprint.hash_u64();
15741579
debug!("write fingerprint ({:x}) : {}", hash, loc.display());
15751580
paths::write(loc, util::to_hex(hash).as_bytes())?;
15761581

15771582
let json = serde_json::to_string(fingerprint).unwrap();
15781583
if cfg!(debug_assertions) {
15791584
let f: Fingerprint = serde_json::from_str(&json).unwrap();
1580-
assert_eq!(f.hash(), hash);
1585+
assert_eq!(f.hash_u64(), hash);
15811586
}
15821587
paths::write(&loc.with_extension("json"), json.as_bytes())?;
15831588
Ok(())
@@ -1621,7 +1626,7 @@ fn compare_old_fingerprint(
16211626
paths::set_file_time_no_err(loc, t);
16221627
}
16231628

1624-
let new_hash = new_fingerprint.hash();
1629+
let new_hash = new_fingerprint.hash_u64();
16251630

16261631
if util::to_hex(new_hash) == old_fingerprint_short && new_fingerprint.fs_status.up_to_date() {
16271632
return Ok(());
@@ -1632,7 +1637,10 @@ fn compare_old_fingerprint(
16321637
.with_context(|| internal("failed to deserialize json"))?;
16331638
// Fingerprint can be empty after a failed rebuild (see comment in prepare_target).
16341639
if !old_fingerprint_short.is_empty() {
1635-
debug_assert_eq!(util::to_hex(old_fingerprint.hash()), old_fingerprint_short);
1640+
debug_assert_eq!(
1641+
util::to_hex(old_fingerprint.hash_u64()),
1642+
old_fingerprint_short
1643+
);
16361644
}
16371645
let result = new_fingerprint.compare(&old_fingerprint);
16381646
assert!(result.is_err());

tests/testsuite/freshness.rs

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,9 @@ use std::time::SystemTime;
1313
use super::death;
1414
use cargo_test_support::paths::{self, CargoPathExt};
1515
use cargo_test_support::registry::Package;
16-
use cargo_test_support::{basic_manifest, is_coarse_mtime, project, rustc_host, sleep_ms};
16+
use cargo_test_support::{
17+
basic_manifest, is_coarse_mtime, project, rustc_host, rustc_host_env, sleep_ms,
18+
};
1719

1820
#[cargo_test]
1921
fn modifying_and_moving() {
@@ -2405,10 +2407,7 @@ fn linking_interrupted() {
24052407

24062408
// Make a change, start a build, then interrupt it.
24072409
p.change_file("src/lib.rs", "// modified");
2408-
let linker_env = format!(
2409-
"CARGO_TARGET_{}_LINKER",
2410-
rustc_host().to_uppercase().replace('-', "_")
2411-
);
2410+
let linker_env = format!("CARGO_TARGET_{}_LINKER", rustc_host_env());
24122411
// NOTE: This assumes that the paths to the linker or rustc are not in the
24132412
// fingerprint. But maybe they should be?
24142413
let mut cmd = p
@@ -2641,3 +2640,22 @@ fn cargo_env_changes() {
26412640
)
26422641
.run();
26432642
}
2643+
2644+
#[cargo_test]
2645+
fn changing_linker() {
2646+
// Changing linker should rebuild.
2647+
let p = project().file("src/main.rs", "fn main() {}").build();
2648+
p.cargo("build").run();
2649+
let linker_env = format!("CARGO_TARGET_{}_LINKER", rustc_host_env());
2650+
p.cargo("build --verbose")
2651+
.env(&linker_env, "nonexistent-linker")
2652+
.with_status(101)
2653+
.with_stderr_contains(
2654+
"\
2655+
[COMPILING] foo v0.0.1 ([..])
2656+
[RUNNING] `rustc [..] -C linker=nonexistent-linker [..]`
2657+
[ERROR] [..]linker[..]
2658+
",
2659+
)
2660+
.run();
2661+
}

tests/testsuite/tool_paths.rs

Lines changed: 7 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
//! Tests for configuration values that point to programs.
22
3-
use cargo_test_support::{basic_lib_manifest, no_such_file_err_msg, project, rustc_host};
3+
use cargo_test_support::{
4+
basic_lib_manifest, no_such_file_err_msg, project, rustc_host, rustc_host_env,
5+
};
46

57
#[cargo_test]
68
fn pathless_tools() {
@@ -262,13 +264,9 @@ second match `cfg(not(target_os = \"none\"))` located in [..]/foo/.cargo/config
262264

263265
#[cargo_test]
264266
fn custom_runner_env() {
265-
let target = rustc_host();
266267
let p = project().file("src/main.rs", "fn main() {}").build();
267268

268-
let key = format!(
269-
"CARGO_TARGET_{}_RUNNER",
270-
target.to_uppercase().replace('-', "_")
271-
);
269+
let key = format!("CARGO_TARGET_{}_RUNNER", rustc_host_env());
272270

273271
p.cargo("run")
274272
.env(&key, "nonexistent-runner --foo")
@@ -305,10 +303,7 @@ fn custom_runner_env_overrides_config() {
305303
)
306304
.build();
307305

308-
let key = format!(
309-
"CARGO_TARGET_{}_RUNNER",
310-
target.to_uppercase().replace('-', "_")
311-
);
306+
let key = format!("CARGO_TARGET_{}_RUNNER", rustc_host_env());
312307

313308
p.cargo("run")
314309
.env(&key, "should-run --foo")
@@ -322,13 +317,9 @@ fn custom_runner_env_overrides_config() {
322317
fn custom_runner_env_true() {
323318
// Check for a bug where "true" was interpreted as a boolean instead of
324319
// the executable.
325-
let target = rustc_host();
326320
let p = project().file("src/main.rs", "fn main() {}").build();
327321

328-
let key = format!(
329-
"CARGO_TARGET_{}_RUNNER",
330-
target.to_uppercase().replace('-', "_")
331-
);
322+
let key = format!("CARGO_TARGET_{}_RUNNER", rustc_host_env());
332323

333324
p.cargo("run")
334325
.env(&key, "true")
@@ -338,13 +329,9 @@ fn custom_runner_env_true() {
338329

339330
#[cargo_test]
340331
fn custom_linker_env() {
341-
let target = rustc_host();
342332
let p = project().file("src/main.rs", "fn main() {}").build();
343333

344-
let key = format!(
345-
"CARGO_TARGET_{}_LINKER",
346-
target.to_uppercase().replace('-', "_")
347-
);
334+
let key = format!("CARGO_TARGET_{}_LINKER", rustc_host_env());
348335

349336
p.cargo("build -v")
350337
.env(&key, "nonexistent-linker")

0 commit comments

Comments
 (0)