Skip to content

Canonicalize src path for fingerprint #7078

Open
@nmattia

Description

@nmattia

Describe the problem you are trying to solve

When cargo registers information used later on to figure out whether or not to recompile a unit, the path to the source is tracked in the fingerprint:

fn path_args(bcx: &BuildContext<'_, '_>, unit: &Unit<'_>) -> (PathBuf, PathBuf) {
let ws_root = bcx.ws.root();
let src = match unit.target.src_path() {
TargetSourcePath::Path(path) => path.to_path_buf(),
TargetSourcePath::Metabuild => unit.pkg.manifest().metabuild_path(bcx.ws.target_dir()),
};
assert!(src.is_absolute());
if unit.pkg.package_id().source_id().is_path() {
if let Ok(path) = src.strip_prefix(ws_root) {
return (path.to_path_buf(), ws_root.to_path_buf());
}
}
(src, unit.pkg.root().to_path_buf())
}

However this path is not canonicalized, meaning that e.g. symlinks aren't resolved before the source paths are added to the fingerprint.

This causes two kinds of issues:

  1. It's convenient to use symlinks to point to a local registry when using source replacement. But since the paths are not canonicalized this can cause spurious rebuilds if the symlink source changes (while the symlink target doesn't).
  2. Same use case as above, but say the symlink source doesn't change, while the symlink target changes. In this case cargo will reuse outdated build artifacts.

Describe the solution you'd like

The paths can be canonicalized before being returned:

diff --git a/src/cargo/core/compiler/mod.rs b/src/cargo/core/compiler/mod.rs
index 628ac8bb..dcc668e8 100644
--- a/src/cargo/core/compiler/mod.rs
+++ b/src/cargo/core/compiler/mod.rs
@@ -688,6 +688,7 @@ fn path_args(bcx: &BuildContext<'_, '_>, unit: &Unit<'_>) -> (PathBuf, PathBuf)
         TargetSourcePath::Metabuild => unit.pkg.manifest().metabuild_path(bcx.ws.target_dir()),
     };
     assert!(src.is_absolute());
+    let src = fs::canonicalize(&src).unwrap_or(src);
     if unit.pkg.package_id().source_id().is_path() {
         if let Ok(path) = src.strip_prefix(ws_root) {
             return (path.to_path_buf(), ws_root.to_path_buf());

One drawback is that cache miss info (with CARGO_LOG=cargo::core::compiler::fingerprint=trace) may confuse the user in the presence of symlinks.

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-rebuild-detectionArea: rebuild detection and fingerprintingC-enhancementCategory: enhancementS-needs-team-inputStatus: Needs input from team on whether/how to proceed.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions