diff --git a/src/cargo/core/compiler/fingerprint.rs b/src/cargo/core/compiler/fingerprint.rs index e145a7b9f09..4f1ad49c016 100644 --- a/src/cargo/core/compiler/fingerprint.rs +++ b/src/cargo/core/compiler/fingerprint.rs @@ -549,7 +549,7 @@ impl LocalFingerprint { // unit has never been compiled! LocalFingerprint::CheckDepInfo { dep_info } => { let dep_info = target_root.join(dep_info); - if let Some(paths) = parse_dep_info(pkg_root, &dep_info)? { + if let Some(paths) = parse_dep_info(pkg_root, target_root, &dep_info)? { Ok(find_stale_file(&dep_info, paths.iter())) } else { Ok(Some(StaleFile::Missing(dep_info))) @@ -1408,7 +1408,11 @@ fn log_compare(unit: &Unit<'_>, compare: &CargoResult<()>) { } // Parse the dep-info into a list of paths -pub fn parse_dep_info(pkg_root: &Path, dep_info: &Path) -> CargoResult>> { +pub fn parse_dep_info( + pkg_root: &Path, + target_root: &Path, + dep_info: &Path, +) -> CargoResult>> { let data = match paths::read_bytes(dep_info) { Ok(data) => data, Err(_) => return Ok(None), @@ -1416,7 +1420,18 @@ pub fn parse_dep_info(pkg_root: &Path, dep_info: &Path) -> CargoResult ty, + None => return Err(internal("dep-info invalid")), + }; + let path = util::bytes2path(&p[1..])?; + match ty { + DepInfoPathType::PackageRootRelative => Ok(pkg_root.join(path)), + // N.B. path might be absolute here in which case the join will have no effect + DepInfoPathType::TargetRootRelative => Ok(target_root.join(path)), + } + }) .collect::, _>>()?; if paths.is_empty() { Ok(None) @@ -1503,6 +1518,25 @@ fn filename<'a, 'cfg>(cx: &mut Context<'a, 'cfg>, unit: &Unit<'a>) -> String { format!("{}{}-{}", flavor, kind, file_stem) } +#[repr(u8)] +enum DepInfoPathType { + // src/, e.g. src/lib.rs + PackageRootRelative = 1, + // target/debug/deps/lib... + // or an absolute path /.../sysroot/... + TargetRootRelative = 2, +} + +impl DepInfoPathType { + fn from_byte(b: u8) -> Option { + match b { + 1 => Some(DepInfoPathType::PackageRootRelative), + 2 => Some(DepInfoPathType::TargetRootRelative), + _ => None, + } + } +} + /// Parses the dep-info file coming out of rustc into a Cargo-specific format. /// /// This function will parse `rustc_dep_info` as a makefile-style dep info to @@ -1522,8 +1556,9 @@ fn filename<'a, 'cfg>(cx: &mut Context<'a, 'cfg>, unit: &Unit<'a>) -> String { pub fn translate_dep_info( rustc_dep_info: &Path, cargo_dep_info: &Path, - pkg_root: &Path, rustc_cwd: &Path, + pkg_root: &Path, + target_root: &Path, ) -> CargoResult<()> { let target = parse_rustc_dep_info(rustc_dep_info)?; let deps = &target @@ -1533,9 +1568,20 @@ pub fn translate_dep_info( let mut new_contents = Vec::new(); for file in deps { - let absolute = rustc_cwd.join(file); - let path = absolute.strip_prefix(pkg_root).unwrap_or(&absolute); - new_contents.extend(util::path2bytes(path)?); + let file = rustc_cwd.join(file); + let (ty, path) = if let Ok(stripped) = file.strip_prefix(pkg_root) { + (DepInfoPathType::PackageRootRelative, stripped) + } else if let Ok(stripped) = file.strip_prefix(target_root) { + (DepInfoPathType::TargetRootRelative, stripped) + } else { + // It's definitely not target root relative, but this is an absolute path (since it was + // joined to rustc_cwd) and as such re-joining it later to the target root will have no + // effect. + assert!(file.is_absolute(), "{:?} is absolute", file); + (DepInfoPathType::TargetRootRelative, &*file) + }; + new_contents.push(ty as u8); + new_contents.extend(util::path2bytes(&path)?); new_contents.push(0); } paths::write(cargo_dep_info, &new_contents)?; diff --git a/src/cargo/core/compiler/mod.rs b/src/cargo/core/compiler/mod.rs index ffaf598e88c..628ac8bbff8 100644 --- a/src/cargo/core/compiler/mod.rs +++ b/src/cargo/core/compiler/mod.rs @@ -315,13 +315,19 @@ fn rustc<'a, 'cfg>( } if rustc_dep_info_loc.exists() { - fingerprint::translate_dep_info(&rustc_dep_info_loc, &dep_info_loc, &pkg_root, &cwd) - .chain_err(|| { - internal(format!( - "could not parse/generate dep info at: {}", - rustc_dep_info_loc.display() - )) - })?; + fingerprint::translate_dep_info( + &rustc_dep_info_loc, + &dep_info_loc, + &cwd, + &pkg_root, + &root_output, + ) + .chain_err(|| { + internal(format!( + "could not parse/generate dep info at: {}", + rustc_dep_info_loc.display() + )) + })?; filetime::set_file_times(dep_info_loc, timestamp, timestamp)?; } diff --git a/src/cargo/core/compiler/output_depinfo.rs b/src/cargo/core/compiler/output_depinfo.rs index b09f5344c58..d9d9eb4d33b 100644 --- a/src/cargo/core/compiler/output_depinfo.rs +++ b/src/cargo/core/compiler/output_depinfo.rs @@ -39,7 +39,11 @@ fn add_deps_for_unit<'a, 'b>( if !unit.mode.is_run_custom_build() { // Add dependencies from rustc dep-info output (stored in fingerprint directory) let dep_info_loc = fingerprint::dep_info_loc(context, unit); - if let Some(paths) = fingerprint::parse_dep_info(unit.pkg.root(), &dep_info_loc)? { + if let Some(paths) = fingerprint::parse_dep_info( + unit.pkg.root(), + context.files().host_root(), + &dep_info_loc, + )? { for path in paths { deps.insert(path); } diff --git a/tests/testsuite/freshness.rs b/tests/testsuite/freshness.rs index 3932eaa5553..6d3de5d30f6 100644 --- a/tests/testsuite/freshness.rs +++ b/tests/testsuite/freshness.rs @@ -2026,3 +2026,70 @@ fn rename_with_path_deps() { .with_stderr("[FINISHED] [..]") .run(); } + +#[cargo_test] +fn move_target_directory_with_path_deps() { + let p = project() + .file( + "Cargo.toml", + r#" + [project] + name = "foo" + version = "0.5.0" + authors = [] + + [dependencies] + a = { path = "a" } + "#, + ) + .file( + "a/Cargo.toml", + r#" + [project] + name = "a" + version = "0.5.0" + authors = [] + "#, + ) + .file("src/lib.rs", "extern crate a; pub use a::print_msg;") + .file( + "a/build.rs", + r###" + use std::env; + use std::fs; + use std::path::Path; + + fn main() { + println!("cargo:rerun-if-changed=build.rs"); + let out_dir = env::var("OUT_DIR").unwrap(); + let dest_path = Path::new(&out_dir).join("hello.rs"); + fs::write(&dest_path, r#" + pub fn message() -> &'static str { + "Hello, World!" + } + "#).unwrap(); + } + "###, + ) + .file( + "a/src/lib.rs", + r#" + include!(concat!(env!("OUT_DIR"), "/hello.rs")); + pub fn print_msg() { message(); } + "#, + ); + let p = p.build(); + + let mut parent = p.root(); + parent.pop(); + + p.cargo("build").run(); + + let new_target = p.root().join("target2"); + fs::rename(p.root().join("target"), &new_target).unwrap(); + + p.cargo("build") + .env("CARGO_TARGET_DIR", &new_target) + .with_stderr("[FINISHED] [..]") + .run(); +}