1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
use pathdiff::diff_paths;
use rustc_data_structures::fx::FxHashSet;
use std::env;
use std::fs;
use std::path::{Path, PathBuf};
use rustc_hir::def_id::CrateNum;
use rustc_middle::middle::cstore::LibSource;
pub struct RPathConfig<'a> {
pub used_crates: &'a [(CrateNum, LibSource)],
pub out_filename: PathBuf,
pub is_like_osx: bool,
pub has_rpath: bool,
pub linker_is_gnu: bool,
pub get_install_prefix_lib_path: &'a mut dyn FnMut() -> PathBuf,
}
pub fn get_rpath_flags(config: &mut RPathConfig<'_>) -> Vec<String> {
if !config.has_rpath {
return Vec::new();
}
debug!("preparing the RPATH!");
let libs = config.used_crates.clone();
let libs = libs.iter().filter_map(|&(_, ref l)| l.option()).collect::<Vec<_>>();
let rpaths = get_rpaths(config, &libs);
let mut flags = rpaths_to_flags(&rpaths);
if config.linker_is_gnu {
flags.push("-Wl,--enable-new-dtags".to_owned());
}
flags
}
fn rpaths_to_flags(rpaths: &[String]) -> Vec<String> {
let mut ret = Vec::with_capacity(rpaths.len());
for rpath in rpaths {
if rpath.contains(',') {
ret.push("-Wl,-rpath".into());
ret.push("-Xlinker".into());
ret.push(rpath.clone());
} else {
ret.push(format!("-Wl,-rpath,{}", &(*rpath)));
}
}
ret
}
fn get_rpaths(config: &mut RPathConfig<'_>, libs: &[PathBuf]) -> Vec<String> {
debug!("output: {:?}", config.out_filename.display());
debug!("libs:");
for libpath in libs {
debug!(" {:?}", libpath.display());
}
let rel_rpaths = get_rpaths_relative_to_output(config, libs);
let fallback_rpaths = vec![get_install_prefix_rpath(config)];
fn log_rpaths(desc: &str, rpaths: &[String]) {
debug!("{} rpaths:", desc);
for rpath in rpaths {
debug!(" {}", *rpath);
}
}
log_rpaths("relative", &rel_rpaths);
log_rpaths("fallback", &fallback_rpaths);
let mut rpaths = rel_rpaths;
rpaths.extend_from_slice(&fallback_rpaths);
minimize_rpaths(&rpaths)
}
fn get_rpaths_relative_to_output(config: &mut RPathConfig<'_>, libs: &[PathBuf]) -> Vec<String> {
libs.iter().map(|a| get_rpath_relative_to_output(config, a)).collect()
}
fn get_rpath_relative_to_output(config: &mut RPathConfig<'_>, lib: &Path) -> String {
let prefix = if config.is_like_osx { "@loader_path" } else { "$ORIGIN" };
let cwd = env::current_dir().unwrap();
let mut lib = fs::canonicalize(&cwd.join(lib)).unwrap_or_else(|_| cwd.join(lib));
lib.pop();
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));
format!("{}/{}", prefix, relative.to_str().expect("non-utf8 component in path"))
}
fn path_relative_from(path: &Path, base: &Path) -> Option<PathBuf> {
diff_paths(path, base)
}
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);
path.to_str().expect("non-utf8 component in rpath").to_owned()
}
fn minimize_rpaths(rpaths: &[String]) -> Vec<String> {
let mut set = FxHashSet::default();
let mut minimized = Vec::new();
for rpath in rpaths {
if set.insert(rpath) {
minimized.push(rpath.clone());
}
}
minimized
}
#[cfg(all(unix, test))]
mod tests;