From: Shiz Date: Thu, 20 Aug 2017 01:44:12 +0200 Subject: [PATCH] Minimize generated RPATH in end products By default, RPATH generation adds both the install prefix and the generated relative path to the install prefix. This is unnecessary, so we add the install prefix to a list of absolute paths to omit in the relative path generation, and skip it there. --- a/src/librustc_codegen_llvm/back/rpath.rs +++ b/src/librustc_codegen_llvm/back/rpath.rs @@ -69,14 +69,15 @@ debug!(" {:?}", libpath.display()); } + // The backup rpath is the global library location. + // We also omit this path from the relative rpaths. + let fallback_rpaths = vec![get_install_prefix_rpath(config)]; + // Use relative paths to the libraries. Binaries can be moved // as long as they maintain the relative relationship to the // crates they depend on. - let rel_rpaths = get_rpaths_relative_to_output(config, libs); + let rel_rpaths = get_rpaths_relative_to_output(config, libs, &fallback_rpaths); - // And a final backup rpath to the global library location. - let fallback_rpaths = vec![get_install_prefix_rpath(config)]; - fn log_rpaths(desc: &str, rpaths: &[String]) { debug!("{} rpaths:", desc); for rpath in rpaths { @@ -96,11 +97,13 @@ } fn get_rpaths_relative_to_output(config: &mut RPathConfig, - libs: &[PathBuf]) -> Vec { - libs.iter().map(|a| get_rpath_relative_to_output(config, a)).collect() + libs: &[PathBuf], + omit: &Vec) -> Vec { + libs.iter().filter_map(|a| get_rpath_relative_to_output(config, a, omit)).collect() } -fn get_rpath_relative_to_output(config: &mut RPathConfig, lib: &Path) -> String { +fn get_rpath_relative_to_output(config: &mut RPathConfig, lib: &Path, + omit: &Vec) -> Option { // Mac doesn't appear to support $ORIGIN let prefix = if config.is_like_osx { "@loader_path" @@ -114,11 +117,18 @@ let mut output = cwd.join(&config.out_filename); output.pop(); let output = fs::canonicalize(&output).unwrap_or(output); - let relative = path_relative_from(&lib, &output).unwrap_or_else(|| - panic!("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")) + let libpath = lib.to_str().expect("non-utf8 component in path").to_string(); + if omit.contains(&libpath) { + None + } else { + 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 + Some(format!("{}/{}", prefix, + relative.to_str().expect("non-utf8 component in path"))) + } } // This routine is adapted from the *old* Path's `path_relative_from` @@ -239,6 +249,7 @@ #[test] fn test_rpath_relative() { if cfg!(target_os = "macos") { + let omit = Vec::new(); let config = &mut RPathConfig { used_crates: Vec::new(), has_rpath: true, @@ -248,9 +259,11 @@ get_install_prefix_lib_path: &mut || panic!(), }; let res = get_rpath_relative_to_output(config, - Path::new("lib/libstd.so")); + Path::new("lib/libstd.so"), + &omit); assert_eq!(res, "@loader_path/../lib"); } else { + let omit = Vec::new(); let config = &mut RPathConfig { used_crates: Vec::new(), out_filename: PathBuf::from("bin/rustc"), @@ -260,7 +273,8 @@ linker_is_gnu: true, }; let res = get_rpath_relative_to_output(config, - Path::new("lib/libstd.so")); + Path::new("lib/libstd.so"), + &omit); assert_eq!(res, "$ORIGIN/../lib"); } }