]> git.proxmox.com Git - cargo.git/commitdiff
Support rustc emitting dep-info for binary dependencies
authorMark Rousskov <mark.simulacrum@gmail.com>
Wed, 12 Jun 2019 19:14:54 +0000 (13:14 -0600)
committerMark Rousskov <mark.simulacrum@gmail.com>
Fri, 14 Jun 2019 19:37:05 +0000 (13:37 -0600)
rustc wants to provide sysroot dependencies and perhaps eventually
statically/dynamically linked C libraries discovered in library serach
paths to Cargo. Mostly this is only useful today for rustbuild as
otherwise Cargo's assumption that the sysroot is only changed if `rustc`
itself changes is pretty much always correct.

src/cargo/core/compiler/fingerprint.rs
src/cargo/core/compiler/mod.rs
src/cargo/core/compiler/output_depinfo.rs
tests/testsuite/freshness.rs

index e145a7b9f0993e557e9e748fe83665c48b20117f..4f1ad49c016c700074b88f62ac7a6ccabc801833 100644 (file)
@@ -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<Option<Vec<PathBuf>>> {
+pub fn parse_dep_info(
+    pkg_root: &Path,
+    target_root: &Path,
+    dep_info: &Path,
+) -> CargoResult<Option<Vec<PathBuf>>> {
     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<Option<Ve
     let paths = data
         .split(|&x| x == 0)
         .filter(|x| !x.is_empty())
-        .map(|p| util::bytes2path(p).map(|p| pkg_root.join(p)))
+        .map(|p| {
+            let ty = match DepInfoPathType::from_byte(p[0]) {
+                Some(ty) => 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::<Result<Vec<_>, _>>()?;
     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<DepInfoPathType> {
+        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)?;
index ffaf598e88c0dfa46536e30c80ea1e3aedfb0d55..628ac8bbff8c7d4b1d7a2aeb142fbd8dfd8d2c4a 100644 (file)
@@ -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)?;
         }
 
index b09f5344c583ccc44491c7ba855db57cd8cc5013..d9d9eb4d33b8f472f667e637c630ed393ff73a30 100644 (file)
@@ -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);
             }
index 3932eaa5553b063803b054ef6c9a921cf504a64d..6d3de5d30f63c715670f11290b38ff9dcba08eff 100644 (file)
@@ -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();
+}