1 use pathdiff
::diff_paths
;
2 use rustc_data_structures
::fx
::FxHashSet
;
5 use std
::path
::{Path, PathBuf}
;
7 use rustc_hir
::def_id
::CrateNum
;
8 use rustc_middle
::middle
::cstore
::LibSource
;
10 pub struct RPathConfig
<'a
> {
11 pub used_crates
: &'a
[(CrateNum
, LibSource
)],
12 pub out_filename
: PathBuf
,
13 pub is_like_osx
: bool
,
15 pub linker_is_gnu
: bool
,
16 pub get_install_prefix_lib_path
: &'a
mut dyn FnMut() -> PathBuf
,
19 pub fn get_rpath_flags(config
: &mut RPathConfig
<'_
>) -> Vec
<String
> {
20 // No rpath on windows
21 if !config
.has_rpath
{
25 debug
!("preparing the RPATH!");
27 let libs
= config
.used_crates
.clone();
28 let libs
= libs
.iter().filter_map(|&(_
, ref l
)| l
.option()).collect
::<Vec
<_
>>();
29 let rpaths
= get_rpaths(config
, &libs
);
30 let mut flags
= rpaths_to_flags(&rpaths
);
32 // Use DT_RUNPATH instead of DT_RPATH if available
33 if config
.linker_is_gnu
{
34 flags
.push("-Wl,--enable-new-dtags".to_owned());
40 fn rpaths_to_flags(rpaths
: &[String
]) -> Vec
<String
> {
41 let mut ret
= Vec
::with_capacity(rpaths
.len()); // the minimum needed capacity
44 if rpath
.contains('
,'
) {
45 ret
.push("-Wl,-rpath".into());
46 ret
.push("-Xlinker".into());
47 ret
.push(rpath
.clone());
49 ret
.push(format
!("-Wl,-rpath,{}", &(*rpath
)));
56 fn get_rpaths(config
: &mut RPathConfig
<'_
>, libs
: &[PathBuf
]) -> Vec
<String
> {
57 debug
!("output: {:?}", config
.out_filename
.display());
60 debug
!(" {:?}", libpath
.display());
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.
66 let rel_rpaths
= get_rpaths_relative_to_output(config
, libs
);
68 // And a final backup rpath to the global library location.
69 let fallback_rpaths
= vec
![get_install_prefix_rpath(config
)];
71 fn log_rpaths(desc
: &str, rpaths
: &[String
]) {
72 debug
!("{} rpaths:", desc
);
74 debug
!(" {}", *rpath
);
78 log_rpaths("relative", &rel_rpaths
);
79 log_rpaths("fallback", &fallback_rpaths
);
81 let mut rpaths
= rel_rpaths
;
82 rpaths
.extend_from_slice(&fallback_rpaths
);
85 minimize_rpaths(&rpaths
)
88 fn get_rpaths_relative_to_output(config
: &mut RPathConfig
<'_
>, libs
: &[PathBuf
]) -> Vec
<String
> {
89 libs
.iter().map(|a
| get_rpath_relative_to_output(config
, a
)).collect()
92 fn get_rpath_relative_to_output(config
: &mut RPathConfig
<'_
>, lib
: &Path
) -> String
{
93 // Mac doesn't appear to support $ORIGIN
94 let prefix
= if config
.is_like_osx { "@loader_path" }
else { "$ORIGIN" }
;
96 let cwd
= env
::current_dir().unwrap();
97 let mut lib
= fs
::canonicalize(&cwd
.join(lib
)).unwrap_or_else(|_
| cwd
.join(lib
));
98 lib
.pop(); // strip filename
99 let mut output
= cwd
.join(&config
.out_filename
);
100 output
.pop(); // strip filename
101 let output
= fs
::canonicalize(&output
).unwrap_or(output
);
102 let relative
= path_relative_from(&lib
, &output
)
103 .unwrap_or_else(|| panic
!("couldn't create relative path from {:?} to {:?}", output
, lib
));
104 // FIXME (#9639): This needs to handle non-utf8 paths
105 format
!("{}/{}", prefix
, relative
.to_str().expect("non-utf8 component in path"))
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
> {
113 diff_paths(path
, base
)
116 fn get_install_prefix_rpath(config
: &mut RPathConfig
<'_
>) -> String
{
117 let path
= (config
.get_install_prefix_lib_path
)();
118 let path
= env
::current_dir().unwrap().join(&path
);
119 // FIXME (#9639): This needs to handle non-utf8 paths
120 path
.to_str().expect("non-utf8 component in rpath").to_owned()
123 fn minimize_rpaths(rpaths
: &[String
]) -> Vec
<String
> {
124 let mut set
= FxHashSet
::default();
125 let mut minimized
= Vec
::new();
126 for rpath
in rpaths
{
127 if set
.insert(rpath
) {
128 minimized
.push(rpath
.clone());
134 #[cfg(all(unix, test))]