rustc_codegen_ssa/back/
rpath.rs
1use std::ffi::OsString;
2use std::path::{Path, PathBuf};
3
4use pathdiff::diff_paths;
5use rustc_data_structures::fx::FxHashSet;
6use rustc_fs_util::try_canonicalize;
7use tracing::debug;
8
9pub(super) struct RPathConfig<'a> {
10 pub libs: &'a [&'a Path],
11 pub out_filename: PathBuf,
12 pub is_like_osx: bool,
13 pub linker_is_gnu: bool,
14}
15
16pub(super) fn get_rpath_linker_args(config: &RPathConfig<'_>) -> Vec<OsString> {
17 debug!("preparing the RPATH!");
18
19 let rpaths = get_rpaths(config);
20 let mut args = Vec::with_capacity(rpaths.len() * 2); for rpath in rpaths {
23 args.push("-rpath".into());
24 args.push(rpath);
25 }
26
27 if config.linker_is_gnu {
28 args.push("--enable-new-dtags".into());
30
31 args.push("-z".into());
33 args.push("origin".into());
34 }
35
36 args
37}
38
39fn get_rpaths(config: &RPathConfig<'_>) -> Vec<OsString> {
40 debug!("output: {:?}", config.out_filename.display());
41 debug!("libs:");
42 for libpath in config.libs {
43 debug!(" {:?}", libpath.display());
44 }
45
46 let rpaths = get_rpaths_relative_to_output(config);
50
51 debug!("rpaths:");
52 for rpath in &rpaths {
53 debug!(" {:?}", rpath);
54 }
55
56 minimize_rpaths(&rpaths)
58}
59
60fn get_rpaths_relative_to_output(config: &RPathConfig<'_>) -> Vec<OsString> {
61 config.libs.iter().map(|a| get_rpath_relative_to_output(config, a)).collect()
62}
63
64fn get_rpath_relative_to_output(config: &RPathConfig<'_>, lib: &Path) -> OsString {
65 let prefix = if config.is_like_osx { "@loader_path" } else { "$ORIGIN" };
67
68 let lib = lib.parent().unwrap();
70 let output = config.out_filename.parent().unwrap();
71
72 let lib = if lib == Path::new("") { Path::new(".") } else { lib };
74 let output = if output == Path::new("") { Path::new(".") } else { output };
75
76 let lib = try_canonicalize(lib).unwrap();
77 let output = try_canonicalize(output).unwrap();
78 let relative = path_relative_from(&lib, &output)
79 .unwrap_or_else(|| panic!("couldn't create relative path from {output:?} to {lib:?}"));
80
81 let mut rpath = OsString::from(prefix);
82 rpath.push("/");
83 rpath.push(relative);
84 rpath
85}
86
87fn path_relative_from(path: &Path, base: &Path) -> Option<PathBuf> {
92 diff_paths(path, base)
93}
94
95fn minimize_rpaths(rpaths: &[OsString]) -> Vec<OsString> {
96 let mut set = FxHashSet::default();
97 let mut minimized = Vec::new();
98 for rpath in rpaths {
99 if set.insert(rpath) {
100 minimized.push(rpath.clone());
101 }
102 }
103 minimized
104}
105
106#[cfg(all(unix, test))]
107mod tests;