diff --git a/src/cargo/core/compiler/mod.rs b/src/cargo/core/compiler/mod.rs index 628ac8bbff8..5c8728d683b 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 = canonicalize_path_arg(&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()); @@ -696,6 +697,19 @@ fn path_args(bcx: &BuildContext<'_, '_>, unit: &Unit<'_>) -> (PathBuf, PathBuf) (src, unit.pkg.root().to_path_buf()) } +#[cfg(windows)] +// On Windows cargo cannot read back the canonicalized paths. The paths are +// canonicalized to resolve symlinks, which aren't as ordinary on Windows as +// they are on other platforms, so we simply skip this. +pub fn canonicalize_path_arg>(path: P) -> CargoResult { + Ok(path.as_ref().to_path_buf()) +} + +#[cfg(not(windows))] +pub fn canonicalize_path_arg>(path: P) -> CargoResult { + Ok(fs::canonicalize(path)?) +} + fn add_path_args(bcx: &BuildContext<'_, '_>, unit: &Unit<'_>, cmd: &mut ProcessBuilder) { let (arg, cwd) = path_args(bcx, unit); cmd.arg(arg); diff --git a/tests/testsuite/build.rs b/tests/testsuite/build.rs index e1fae224237..8f1c6891111 100644 --- a/tests/testsuite/build.rs +++ b/tests/testsuite/build.rs @@ -4703,3 +4703,58 @@ d ) .run(); } + +#[cargo_test] +#[cfg(not(target_os = "windows"))] +fn symlink_rebuild() { + // Create a crate foo that depends on one crate: a. + // After the initial build we swap the 'a' directory for a symlink to 'b'. + // Since the underlying crate changed, cargo should perform a rebuild. + let project = project() + .file( + "Cargo.toml", + r#" + [package] + name = "foo" + version = "0.1.0" + [dependencies] + a = { path = "a" } + "#, + ) + .file("src/main.rs", "fn main(){}") + .file( + "a/Cargo.toml", + r#" + [package] + name = "a" + version = "0.1.0" + "#, + ) + .file("a/src/lib.rs", "") + .file( + "b/Cargo.toml", + r#" + [package] + name = "a" + version = "0.1.0" + "#, + ) + .file("b/src/lib.rs", "pub fn not_a(){}"); + + let foo = project.build(); + + foo.cargo("build -p foo") + .with_status(0) + .with_stderr_contains("[..] Compiling a v0.1.0 [..]") + .run(); + + let root = foo.root(); + + fs::remove_dir_all(root.join("a")).unwrap(); + std::os::unix::fs::symlink(root.join("b"), root.join("a")).unwrap(); + + foo.cargo("build -p foo") + .with_status(0) + .with_stderr_contains("[..] Compiling a v0.1.0 [..]") + .run(); +}