about summary refs log tree commit diff
diff options
context:
space:
mode:
authorAlex Crichton <alex@alexcrichton.com>2015-03-23 15:07:33 -0700
committerAlex Crichton <alex@alexcrichton.com>2015-03-23 15:07:33 -0700
commite98d4d9589974c9cf0f12266fa53fb690a28cd99 (patch)
tree46713139543c82eb7822573c320cbe26e6f4c69d
parent67e516c5c2ddd0dbed6b07ccca6b5bdd4ad10b36 (diff)
parent9ec9bc68fb310aac29e984d26cc37952de328f1e (diff)
downloadrust-e98d4d9589974c9cf0f12266fa53fb690a28cd99.tar.gz
rust-e98d4d9589974c9cf0f12266fa53fb690a28cd99.zip
rollup merge of #23283: brson/rpathfix
Fix regression in -C rpath that causes failures with symlinks

The new `relative_from` method no longer supports the case on unix
where both paths are absolute, which `-C rpath` depended on. This
version fixes the problem by copying the old path_relative_from
function into the rpath module.

Fixes #23140

After experimenting with the new `relative_from` function on `Path` I'm not sure what it's use case is. It no longer even figures out that the relative path from `/foo/bar` to `/foo/baz/qux` is `../baz/qux`.
-rw-r--r--src/librustc_back/rpath.rs58
-rw-r--r--src/libstd/path.rs3
2 files changed, 46 insertions, 15 deletions
diff --git a/src/librustc_back/rpath.rs b/src/librustc_back/rpath.rs
index 4f9f1447d8a..68d21abb50e 100644
--- a/src/librustc_back/rpath.rs
+++ b/src/librustc_back/rpath.rs
@@ -99,30 +99,58 @@ fn get_rpath_relative_to_output(config: &mut RPathConfig, lib: &Path) -> String
     lib.pop();
     let mut output = (config.realpath)(&cwd.join(&config.out_filename)).unwrap();
     output.pop();
-    let relative = relativize(&lib, &output);
+    let relative = path_relative_from(&lib, &output)
+        .expect(&format!("couldn't create relative path from {:?} to {:?}", output, lib));
     // FIXME (#9639): This needs to handle non-utf8 paths
     format!("{}/{}", prefix,
             relative.to_str().expect("non-utf8 component in path"))
 }
 
-fn relativize(path: &Path, rel: &Path) -> PathBuf {
-    let mut res = PathBuf::new("");
-    let mut cur = rel;
-    while !path.starts_with(cur) {
-        res.push("..");
-        match cur.parent() {
-            Some(p) => cur = p,
-            None => panic!("can't create relative paths across filesystems"),
+// This routine is adapted from the *old* Path's `path_relative_from`
+// function, which works differently from the new `relative_from` function.
+// In particular, this handles the case on unix where both paths are
+// absolute but with only the root as the common directory.
+fn path_relative_from(path: &Path, base: &Path) -> Option<PathBuf> {
+    use std::path::Component;
+
+    if path.is_absolute() != base.is_absolute() {
+        if path.is_absolute() {
+            Some(PathBuf::new(path))
+        } else {
+            None
         }
+    } else {
+        let mut ita = path.components();
+        let mut itb = base.components();
+        let mut comps: Vec<Component> = vec![];
+        loop {
+            match (ita.next(), itb.next()) {
+                (None, None) => break,
+                (Some(a), None) => {
+                    comps.push(a);
+                    comps.extend(ita.by_ref());
+                    break;
+                }
+                (None, _) => comps.push(Component::ParentDir),
+                (Some(a), Some(b)) if comps.is_empty() && a == b => (),
+                (Some(a), Some(b)) if b == Component::CurDir => comps.push(a),
+                (Some(_), Some(b)) if b == Component::ParentDir => return None,
+                (Some(a), Some(_)) => {
+                    comps.push(Component::ParentDir);
+                    for _ in itb {
+                        comps.push(Component::ParentDir);
+                    }
+                    comps.push(a);
+                    comps.extend(ita.by_ref());
+                    break;
+                }
+            }
+        }
+        Some(comps.iter().map(|c| c.as_os_str()).collect())
     }
-    match path.relative_from(cur) {
-        Some(s) => { res.push(s); res }
-        None => panic!("couldn't create relative path from {:?} to {:?}",
-                       rel, path),
-    }
-
 }
 
+
 fn get_install_prefix_rpath(config: &mut RPathConfig) -> String {
     let path = (config.get_install_prefix_lib_path)();
     let path = env::current_dir().unwrap().join(&path);
diff --git a/src/libstd/path.rs b/src/libstd/path.rs
index ddceed14cc6..05c7761be7b 100644
--- a/src/libstd/path.rs
+++ b/src/libstd/path.rs
@@ -1243,6 +1243,9 @@ impl Path {
     }
 
     /// Returns a path that, when joined onto `base`, yields `self`.
+    ///
+    /// If `base` is not a prefix of `self` (i.e. `starts_with`
+    /// returns false), then `relative_from` returns `None`.
     #[unstable(feature = "path_relative_from", reason = "see #23284")]
     pub fn relative_from<'a, P: ?Sized>(&'a self, base: &'a P) -> Option<&Path> where
         P: AsPath