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_darwin: bool,
13 pub linker_is_gnu: bool,
14}
15
16pub(super) fn get_rpath_linker_args(config: &RPathConfig<'_>) -> Vec<OsString> {
17 {
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event compiler/rustc_codegen_ssa/src/back/rpath.rs:17",
"rustc_codegen_ssa::back::rpath", ::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_codegen_ssa/src/back/rpath.rs"),
::tracing_core::__macro_support::Option::Some(17u32),
::tracing_core::__macro_support::Option::Some("rustc_codegen_ssa::back::rpath"),
::tracing_core::field::FieldSet::new(&["message"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() &&
{
let interest = __CALLSITE.interest();
!interest.is_never() &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest)
};
if enabled {
(|value_set: ::tracing::field::ValueSet|
{
let meta = __CALLSITE.metadata();
::tracing::Event::dispatch(meta, &value_set);
;
})({
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
let mut iter = __CALLSITE.metadata().fields().iter();
__CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
::tracing::__macro_support::Option::Some(&format_args!("preparing the RPATH!")
as &dyn Value))])
});
} else { ; }
};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 {
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event compiler/rustc_codegen_ssa/src/back/rpath.rs:40",
"rustc_codegen_ssa::back::rpath", ::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_codegen_ssa/src/back/rpath.rs"),
::tracing_core::__macro_support::Option::Some(40u32),
::tracing_core::__macro_support::Option::Some("rustc_codegen_ssa::back::rpath"),
::tracing_core::field::FieldSet::new(&["message"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() &&
{
let interest = __CALLSITE.interest();
!interest.is_never() &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest)
};
if enabled {
(|value_set: ::tracing::field::ValueSet|
{
let meta = __CALLSITE.metadata();
::tracing::Event::dispatch(meta, &value_set);
;
})({
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
let mut iter = __CALLSITE.metadata().fields().iter();
__CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
::tracing::__macro_support::Option::Some(&format_args!("output: {0:?}",
config.out_filename.display()) as &dyn Value))])
});
} else { ; }
};debug!("output: {:?}", config.out_filename.display());
41 {
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event compiler/rustc_codegen_ssa/src/back/rpath.rs:41",
"rustc_codegen_ssa::back::rpath", ::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_codegen_ssa/src/back/rpath.rs"),
::tracing_core::__macro_support::Option::Some(41u32),
::tracing_core::__macro_support::Option::Some("rustc_codegen_ssa::back::rpath"),
::tracing_core::field::FieldSet::new(&["message"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() &&
{
let interest = __CALLSITE.interest();
!interest.is_never() &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest)
};
if enabled {
(|value_set: ::tracing::field::ValueSet|
{
let meta = __CALLSITE.metadata();
::tracing::Event::dispatch(meta, &value_set);
;
})({
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
let mut iter = __CALLSITE.metadata().fields().iter();
__CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
::tracing::__macro_support::Option::Some(&format_args!("libs:")
as &dyn Value))])
});
} else { ; }
};debug!("libs:");
42 for libpath in config.libs {
43 {
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event compiler/rustc_codegen_ssa/src/back/rpath.rs:43",
"rustc_codegen_ssa::back::rpath", ::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_codegen_ssa/src/back/rpath.rs"),
::tracing_core::__macro_support::Option::Some(43u32),
::tracing_core::__macro_support::Option::Some("rustc_codegen_ssa::back::rpath"),
::tracing_core::field::FieldSet::new(&["message"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() &&
{
let interest = __CALLSITE.interest();
!interest.is_never() &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest)
};
if enabled {
(|value_set: ::tracing::field::ValueSet|
{
let meta = __CALLSITE.metadata();
::tracing::Event::dispatch(meta, &value_set);
;
})({
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
let mut iter = __CALLSITE.metadata().fields().iter();
__CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
::tracing::__macro_support::Option::Some(&format_args!(" {0:?}",
libpath.display()) as &dyn Value))])
});
} else { ; }
};debug!(" {:?}", libpath.display());
44 }
45
46 let rpaths = get_rpaths_relative_to_output(config);
50
51 {
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event compiler/rustc_codegen_ssa/src/back/rpath.rs:51",
"rustc_codegen_ssa::back::rpath", ::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_codegen_ssa/src/back/rpath.rs"),
::tracing_core::__macro_support::Option::Some(51u32),
::tracing_core::__macro_support::Option::Some("rustc_codegen_ssa::back::rpath"),
::tracing_core::field::FieldSet::new(&["message"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() &&
{
let interest = __CALLSITE.interest();
!interest.is_never() &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest)
};
if enabled {
(|value_set: ::tracing::field::ValueSet|
{
let meta = __CALLSITE.metadata();
::tracing::Event::dispatch(meta, &value_set);
;
})({
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
let mut iter = __CALLSITE.metadata().fields().iter();
__CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
::tracing::__macro_support::Option::Some(&format_args!("rpaths:")
as &dyn Value))])
});
} else { ; }
};debug!("rpaths:");
52 for rpath in &rpaths {
53 {
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event compiler/rustc_codegen_ssa/src/back/rpath.rs:53",
"rustc_codegen_ssa::back::rpath", ::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_codegen_ssa/src/back/rpath.rs"),
::tracing_core::__macro_support::Option::Some(53u32),
::tracing_core::__macro_support::Option::Some("rustc_codegen_ssa::back::rpath"),
::tracing_core::field::FieldSet::new(&["message"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() &&
{
let interest = __CALLSITE.interest();
!interest.is_never() &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest)
};
if enabled {
(|value_set: ::tracing::field::ValueSet|
{
let meta = __CALLSITE.metadata();
::tracing::Event::dispatch(meta, &value_set);
;
})({
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
let mut iter = __CALLSITE.metadata().fields().iter();
__CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
::tracing::__macro_support::Option::Some(&format_args!(" {0:?}",
rpath) as &dyn Value))])
});
} else { ; }
};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_darwin { "@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(|| {
::core::panicking::panic_fmt(format_args!("couldn\'t create relative path from {0:?} to {1:?}",
output, lib));
}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;