Skip to content

Commit 92836db

Browse files
committed
fix(trim-paths): sanitize absolute source paths in fingerprint
With `trim-paths`, rustc only sees remapped source paths. There is no reason that fingerprint still tracks original paths. This sanitizes absolute paths in Cargo fingerprint by applying the same remap rules with trim-paths. Without this, moving `CARGO_HOME` would cause rebuilds, even the compiled artifacts are byte-identical. One caveat is that because the "object" scope doesn't remap diagonstics, if diagnostics were also cached, a replay may show the "wrong" cached paths. The "all" scope doesn't have this issue btw.
1 parent c5d1e7f commit 92836db

3 files changed

Lines changed: 55 additions & 25 deletions

File tree

‎src/compiler/fingerprint/mod.rs‎

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@
7979
//! `__CARGO_DEFAULT_LIB_METADATA`[^4] | | ✓ | ✓
8080
//! `__CARGO_RUSTC_BOOTSTRAP_WS_REMAP`[^2] | ✓ | |
8181
//! `package_id` | | ✓ | ✓
82-
//! Target src path relative to ws | ✓ | |
82+
//! Target src path relative to ws[^9] | ✓ | |
8383
//! Target flags (test/bench/for_host/edition) | ✓ | |
8484
//! -C incremental=… flag | ✓ | |
8585
//! mtime of sources | ✓[^3] | |
@@ -111,6 +111,9 @@
111111
//!
112112
//! [^8]: including `-Cextra-filename`
113113
//!
114+
//! [^9]: Absolute source paths, for example registry deps,
115+
//! are hashed after remapping when `trim-paths` is enabled.
116+
//!
114117
//! When deciding what should go in the Metadata vs the Fingerprint, consider
115118
//! that some files (like dylibs) do not have a hash in their filename. Thus,
116119
//! if a value changes, only the fingerprint will detect the change (consider,
@@ -396,6 +399,7 @@ use std::time::SystemTime;
396399
use anyhow::Context as _;
397400
use anyhow::format_err;
398401
use cargo_util::paths;
402+
use cargo_util_schemas::manifest::TomlTrimPaths;
399403
use filetime::FileTime;
400404
use serde::de;
401405
use serde::ser;
@@ -1705,13 +1709,35 @@ fn calculate_normal(
17051709
let mut declared_features = unit.pkg.summary().features().keys().collect::<Vec<_>>();
17061710
declared_features.sort(); // to avoid useless rebuild if the user orders it's features
17071711
// differently
1712+
1713+
let src_path = {
1714+
// Note that .0 is hashed here, not .1 which is the cwd. That doesn't
1715+
// actually affect the output artifact so there's no need to hash it.
1716+
let src_path = path_args(build_runner.bcx.ws, unit).0;
1717+
1718+
// Some CI has random CI path for different runs.
1719+
// By tracking remapped paths, we avoid rebuilds when `CARGO_HOME` moves.
1720+
// See rust-lang/cargo#10915
1721+
let should_remap = match unit.profile.trim_paths {
1722+
TomlTrimPaths::None => false,
1723+
TomlTrimPaths::Object | TomlTrimPaths::All => true,
1724+
};
1725+
1726+
if should_remap
1727+
&& src_path.is_absolute()
1728+
&& let Some(remapped) = super::trim_paths::remap_path(build_runner, unit, &src_path)
1729+
{
1730+
remapped
1731+
} else {
1732+
src_path
1733+
}
1734+
};
1735+
17081736
Ok(Fingerprint {
17091737
rustc: util::hash_u64(&build_runner.bcx.rustc().verbose_version),
17101738
target: util::hash_u64(&unit.target),
17111739
profile: profile_hash,
1712-
// Note that .0 is hashed here, not .1 which is the cwd. That doesn't
1713-
// actually affect the output artifact so there's no need to hash it.
1714-
path: util::hash_u64(path_args(build_runner.bcx.ws, unit).0),
1740+
path: util::hash_u64(src_path),
17151741
features: format!("{:?}", unit.features),
17161742
declared_features: format!("{declared_features:?}"),
17171743
deps,

‎src/compiler/trim_paths.rs‎

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,23 @@ pub(crate) fn trim_paths_remap(build_runner: &BuildRunner<'_, '_>, unit: &Unit)
105105
remap_pairs(build_runner, unit).map(join_remap).collect()
106106
}
107107

108+
/// Remaps `path` the same way rustc does with [`trim_paths_remap`] rules,
109+
/// like the last takes precedence.
110+
///
111+
/// `None` if no rule matches.
112+
pub(crate) fn remap_path(
113+
build_runner: &BuildRunner<'_, '_>,
114+
unit: &Unit,
115+
path: &Path,
116+
) -> Option<PathBuf> {
117+
remap_pairs(build_runner, unit)
118+
.filter_map(|(from, to)| {
119+
let rest = path.strip_prefix(&from).ok()?;
120+
Some(Path::new(&to).join(rest))
121+
})
122+
.last()
123+
}
124+
108125
/// Like [`trim_paths_remap`] but yields `(from, to)` pairs.
109126
fn remap_pairs(build_runner: &BuildRunner<'_, '_>, unit: &Unit) -> impl Iterator<Item = RemapPair> {
110127
package_remap(build_runner, unit).into_iter().chain([

‎tests/testsuite/profile_trim_paths.rs‎

Lines changed: 8 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -2212,16 +2212,10 @@ fn cargo_home_moved_trim_paths_object() {
22122212
.env("CARGO_HOME", &new_cargo_home)
22132213
.with_stderr_data(
22142214
str![[r#"
2215-
[DIRTY] bar v0.0.1: the path to the source changed
2216-
[COMPILING] bar v0.0.1
2217-
[RUNNING] `rustc --crate-name bar [..]`
2218-
[DIRTY] baz v0.0.1 ([ROOTURL]/baz#[..]): the path to the source changed
2219-
[COMPILING] baz v0.0.1 ([ROOTURL]/baz#[..])
2220-
[RUNNING] `rustc --crate-name baz [..]`
2221-
[COMPILING] foo v0.0.1 ([ROOT]/foo)
2222-
[RUNNING] `rustc --crate-name foo [..]`
2215+
[FRESH] bar v0.0.1
2216+
[FRESH] baz v0.0.1 ([ROOTURL]/baz#[..])
2217+
[FRESH] foo v0.0.1 ([ROOT]/foo)
22232218
[FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s
2224-
[DIRTY] foo v0.0.1 ([ROOT]/foo): info of dependency `[..]` changed
22252219
22262220
"#]]
22272221
.unordered(),
@@ -2245,16 +2239,10 @@ fn cargo_home_moved_trim_paths_all() {
22452239
.env("CARGO_HOME", &new_cargo_home)
22462240
.with_stderr_data(
22472241
str![[r#"
2248-
[DIRTY] bar v0.0.1: the path to the source changed
2249-
[COMPILING] bar v0.0.1
2250-
[RUNNING] `rustc --crate-name bar [..]`
2251-
[DIRTY] baz v0.0.1 ([ROOTURL]/baz#[..]): the path to the source changed
2252-
[COMPILING] baz v0.0.1 ([ROOTURL]/baz#[..])
2253-
[RUNNING] `rustc --crate-name baz [..]`
2254-
[COMPILING] foo v0.0.1 ([ROOT]/foo)
2255-
[RUNNING] `rustc --crate-name foo [..]`
2242+
[FRESH] bar v0.0.1
2243+
[FRESH] baz v0.0.1 ([ROOTURL]/baz#[..])
2244+
[FRESH] foo v0.0.1 ([ROOT]/foo)
22562245
[FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s
2257-
[DIRTY] foo v0.0.1 ([ROOT]/foo): info of dependency `[..]` changed
22582246
22592247
"#]]
22602248
.unordered(),
@@ -2305,10 +2293,9 @@ fn cargo_home_moved_trim_paths_object_with_diagnostics() {
23052293
.env("CARGO_HOME", &new_cargo_home)
23062294
.with_stderr_data(str![[r#"
23072295
...
2308-
[DIRTY] bar v0.0.1: the path to the source changed
2309-
...
2296+
[FRESH] bar v0.0.1
23102297
[WARNING] unused variable: `unused`
2311-
--> [ROOT]/home/.cargo-moved/registry/src/-[..]/bar-0.0.1/src/lib.rs:1:18
2298+
--> [ROOT]/home/.cargo/registry/src/-[..]/bar-0.0.1/src/lib.rs:1:18
23122299
...
23132300
"#]])
23142301
.run();

0 commit comments

Comments
 (0)