]>
Commit | Line | Data |
---|---|---|
3dfed10e | 1 | use pathdiff::diff_paths; |
b7449926 | 2 | use rustc_data_structures::fx::FxHashSet; |
85aaf69f | 3 | use std::env; |
d9579d0f | 4 | use std::fs; |
dfeec247 | 5 | use std::path::{Path, PathBuf}; |
9e0c209e | 6 | |
dfeec247 | 7 | use rustc_hir::def_id::CrateNum; |
ba9703b0 | 8 | use rustc_middle::middle::cstore::LibSource; |
1a4d82fc | 9 | |
c34b1796 | 10 | pub struct RPathConfig<'a> { |
ea8adc8c | 11 | pub used_crates: &'a [(CrateNum, LibSource)], |
c34b1796 | 12 | pub out_filename: PathBuf, |
1a4d82fc JJ |
13 | pub is_like_osx: bool, |
14 | pub has_rpath: bool, | |
9cc50fc6 | 15 | pub linker_is_gnu: bool, |
8faf50e0 | 16 | pub get_install_prefix_lib_path: &'a mut dyn FnMut() -> PathBuf, |
1a4d82fc JJ |
17 | } |
18 | ||
9fa01778 | 19 | pub fn get_rpath_flags(config: &mut RPathConfig<'_>) -> Vec<String> { |
1a4d82fc JJ |
20 | // No rpath on windows |
21 | if !config.has_rpath { | |
22 | return Vec::new(); | |
23 | } | |
24 | ||
1a4d82fc JJ |
25 | debug!("preparing the RPATH!"); |
26 | ||
27 | let libs = config.used_crates.clone(); | |
ea8adc8c | 28 | let libs = libs.iter().filter_map(|&(_, ref l)| l.option()).collect::<Vec<_>>(); |
cc61c64b | 29 | let rpaths = get_rpaths(config, &libs); |
a1dfa0c6 | 30 | let mut flags = rpaths_to_flags(&rpaths); |
9cc50fc6 SL |
31 | |
32 | // Use DT_RUNPATH instead of DT_RPATH if available | |
33 | if config.linker_is_gnu { | |
a1dfa0c6 | 34 | flags.push("-Wl,--enable-new-dtags".to_owned()); |
9cc50fc6 SL |
35 | } |
36 | ||
1a4d82fc JJ |
37 | flags |
38 | } | |
39 | ||
40 | fn rpaths_to_flags(rpaths: &[String]) -> Vec<String> { | |
a1dfa0c6 XL |
41 | let mut ret = Vec::with_capacity(rpaths.len()); // the minimum needed capacity |
42 | ||
85aaf69f | 43 | for rpath in rpaths { |
32a655c1 SL |
44 | if rpath.contains(',') { |
45 | ret.push("-Wl,-rpath".into()); | |
46 | ret.push("-Xlinker".into()); | |
47 | ret.push(rpath.clone()); | |
48 | } else { | |
49 | ret.push(format!("-Wl,-rpath,{}", &(*rpath))); | |
50 | } | |
1a4d82fc | 51 | } |
a1dfa0c6 XL |
52 | |
53 | ret | |
1a4d82fc JJ |
54 | } |
55 | ||
9fa01778 | 56 | fn get_rpaths(config: &mut RPathConfig<'_>, libs: &[PathBuf]) -> Vec<String> { |
1a4d82fc JJ |
57 | debug!("output: {:?}", config.out_filename.display()); |
58 | debug!("libs:"); | |
85aaf69f | 59 | for libpath in libs { |
1a4d82fc JJ |
60 | debug!(" {:?}", libpath.display()); |
61 | } | |
62 | ||
63 | // Use relative paths to the libraries. Binaries can be moved | |
64 | // as long as they maintain the relative relationship to the | |
65 | // crates they depend on. | |
c34b1796 | 66 | let rel_rpaths = get_rpaths_relative_to_output(config, libs); |
1a4d82fc JJ |
67 | |
68 | // And a final backup rpath to the global library location. | |
c30ab7b3 | 69 | let fallback_rpaths = vec![get_install_prefix_rpath(config)]; |
1a4d82fc JJ |
70 | |
71 | fn log_rpaths(desc: &str, rpaths: &[String]) { | |
72 | debug!("{} rpaths:", desc); | |
85aaf69f | 73 | for rpath in rpaths { |
1a4d82fc JJ |
74 | debug!(" {}", *rpath); |
75 | } | |
76 | } | |
77 | ||
cc61c64b XL |
78 | log_rpaths("relative", &rel_rpaths); |
79 | log_rpaths("fallback", &fallback_rpaths); | |
1a4d82fc JJ |
80 | |
81 | let mut rpaths = rel_rpaths; | |
cc61c64b | 82 | rpaths.extend_from_slice(&fallback_rpaths); |
1a4d82fc JJ |
83 | |
84 | // Remove duplicates | |
ba9703b0 | 85 | minimize_rpaths(&rpaths) |
1a4d82fc JJ |
86 | } |
87 | ||
dfeec247 | 88 | fn get_rpaths_relative_to_output(config: &mut RPathConfig<'_>, libs: &[PathBuf]) -> Vec<String> { |
1a4d82fc JJ |
89 | libs.iter().map(|a| get_rpath_relative_to_output(config, a)).collect() |
90 | } | |
91 | ||
9fa01778 | 92 | fn get_rpath_relative_to_output(config: &mut RPathConfig<'_>, lib: &Path) -> String { |
1a4d82fc | 93 | // Mac doesn't appear to support $ORIGIN |
dfeec247 | 94 | let prefix = if config.is_like_osx { "@loader_path" } else { "$ORIGIN" }; |
1a4d82fc | 95 | |
85aaf69f | 96 | let cwd = env::current_dir().unwrap(); |
0bf4aa26 | 97 | let mut lib = fs::canonicalize(&cwd.join(lib)).unwrap_or_else(|_| cwd.join(lib)); |
9fa01778 | 98 | lib.pop(); // strip filename |
9346a6ac | 99 | let mut output = cwd.join(&config.out_filename); |
9fa01778 | 100 | output.pop(); // strip filename |
d9579d0f | 101 | let output = fs::canonicalize(&output).unwrap_or(output); |
dfeec247 XL |
102 | let relative = path_relative_from(&lib, &output) |
103 | .unwrap_or_else(|| panic!("couldn't create relative path from {:?} to {:?}", output, lib)); | |
1a4d82fc | 104 | // FIXME (#9639): This needs to handle non-utf8 paths |
a1dfa0c6 | 105 | format!("{}/{}", prefix, relative.to_str().expect("non-utf8 component in path")) |
1a4d82fc JJ |
106 | } |
107 | ||
c34b1796 AL |
108 | // This routine is adapted from the *old* Path's `path_relative_from` |
109 | // function, which works differently from the new `relative_from` function. | |
110 | // In particular, this handles the case on unix where both paths are | |
111 | // absolute but with only the root as the common directory. | |
112 | fn path_relative_from(path: &Path, base: &Path) -> Option<PathBuf> { | |
3dfed10e | 113 | diff_paths(path, base) |
c34b1796 AL |
114 | } |
115 | ||
9fa01778 | 116 | fn get_install_prefix_rpath(config: &mut RPathConfig<'_>) -> String { |
1a4d82fc | 117 | let path = (config.get_install_prefix_lib_path)(); |
85aaf69f | 118 | let path = env::current_dir().unwrap().join(&path); |
1a4d82fc | 119 | // FIXME (#9639): This needs to handle non-utf8 paths |
a1dfa0c6 | 120 | path.to_str().expect("non-utf8 component in rpath").to_owned() |
1a4d82fc JJ |
121 | } |
122 | ||
123 | fn minimize_rpaths(rpaths: &[String]) -> Vec<String> { | |
b7449926 | 124 | let mut set = FxHashSet::default(); |
1a4d82fc | 125 | let mut minimized = Vec::new(); |
85aaf69f | 126 | for rpath in rpaths { |
cc61c64b | 127 | if set.insert(rpath) { |
1a4d82fc JJ |
128 | minimized.push(rpath.clone()); |
129 | } | |
130 | } | |
131 | minimized | |
132 | } | |
133 | ||
134 | #[cfg(all(unix, test))] | |
dc9dc135 | 135 | mod tests; |