1use std::error::Error;
2use std::path::Path;
3use std::time::Duration;
4
5use rustc_fs_util::try_canonicalize;
6use rustc_proc_macro::bridge::client::Client as ProcMacroClient;
7use rustc_session::StableCrateId;
8use tracing::debug;
9
10use crate::locator::CrateError;
11
12fn format_dlopen_err(e: &(dyn std::error::Error + 'static)) -> String {
13 e.sources().map(|e| ::alloc::__export::must_use({
::alloc::fmt::format(format_args!(": {0}", e))
})format!(": {e}")).collect()
14}
15
16fn attempt_load_dylib(path: &Path) -> Result<libloading::Library, libloading::Error> {
17 #[cfg(target_os = "aix")]
18 if let Some(ext) = path.extension()
19 && ext.eq("a")
20 {
21 let library_name = path.file_stem().expect("expect a library name");
25 let mut archive_member = std::ffi::OsString::from("a(");
26 archive_member.push(library_name);
27 archive_member.push(".so)");
28 let new_path = path.with_extension(archive_member);
29
30 let flags = libc::RTLD_LAZY | libc::RTLD_LOCAL | libc::RTLD_MEMBER;
32 return unsafe { libloading::os::unix::Library::open(Some(&new_path), flags) }
33 .map(|lib| lib.into());
34 }
35
36 unsafe { libloading::Library::new(&path) }
37}
38
39fn load_dylib(path: &Path, max_attempts: usize) -> Result<libloading::Library, String> {
44 if !(max_attempts > 0) {
::core::panicking::panic("assertion failed: max_attempts > 0")
};assert!(max_attempts > 0);
45
46 let mut last_error = None;
47
48 for attempt in 0..max_attempts {
49 {
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event compiler/rustc_metadata/src/host_dylib.rs:49",
"rustc_metadata::host_dylib", ::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_metadata/src/host_dylib.rs"),
::tracing_core::__macro_support::Option::Some(49u32),
::tracing_core::__macro_support::Option::Some("rustc_metadata::host_dylib"),
::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!("Attempt to load proc-macro `{0}`.",
path.display()) as &dyn Value))])
});
} else { ; }
};debug!("Attempt to load proc-macro `{}`.", path.display());
50 match attempt_load_dylib(path) {
51 Ok(lib) => {
52 if attempt > 0 {
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_metadata/src/host_dylib.rs:53",
"rustc_metadata::host_dylib", ::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_metadata/src/host_dylib.rs"),
::tracing_core::__macro_support::Option::Some(53u32),
::tracing_core::__macro_support::Option::Some("rustc_metadata::host_dylib"),
::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!("Loaded proc-macro `{0}` after {1} attempts.",
path.display(), attempt + 1) as &dyn Value))])
});
} else { ; }
};debug!(
54 "Loaded proc-macro `{}` after {} attempts.",
55 path.display(),
56 attempt + 1
57 );
58 }
59 return Ok(lib);
60 }
61 Err(err) => {
62 if !#[allow(non_exhaustive_omitted_patterns)] match err {
libloading::Error::LoadLibraryExW { .. } => true,
_ => false,
}matches!(err, libloading::Error::LoadLibraryExW { .. }) {
64 {
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event compiler/rustc_metadata/src/host_dylib.rs:64",
"rustc_metadata::host_dylib", ::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_metadata/src/host_dylib.rs"),
::tracing_core::__macro_support::Option::Some(64u32),
::tracing_core::__macro_support::Option::Some("rustc_metadata::host_dylib"),
::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!("Failed to load proc-macro `{0}`. Not retrying",
path.display()) as &dyn Value))])
});
} else { ; }
};debug!("Failed to load proc-macro `{}`. Not retrying", path.display());
65 let err = format_dlopen_err(&err);
66 if let Some(err) = err.strip_prefix(&::alloc::__export::must_use({
::alloc::fmt::format(format_args!(": {0}", path.display()))
})format!(": {}", path.display())) {
69 return Err(err.to_string());
70 }
71 return Err(err);
72 }
73
74 last_error = Some(err);
75 std::thread::sleep(Duration::from_millis(100));
76 {
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event compiler/rustc_metadata/src/host_dylib.rs:76",
"rustc_metadata::host_dylib", ::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_metadata/src/host_dylib.rs"),
::tracing_core::__macro_support::Option::Some(76u32),
::tracing_core::__macro_support::Option::Some("rustc_metadata::host_dylib"),
::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!("Failed to load proc-macro `{0}`. Retrying.",
path.display()) as &dyn Value))])
});
} else { ; }
};debug!("Failed to load proc-macro `{}`. Retrying.", path.display());
77 }
78 }
79 }
80
81 {
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event compiler/rustc_metadata/src/host_dylib.rs:81",
"rustc_metadata::host_dylib", ::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_metadata/src/host_dylib.rs"),
::tracing_core::__macro_support::Option::Some(81u32),
::tracing_core::__macro_support::Option::Some("rustc_metadata::host_dylib"),
::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!("Failed to load proc-macro `{0}` even after {1} attempts.",
path.display(), max_attempts) as &dyn Value))])
});
} else { ; }
};debug!("Failed to load proc-macro `{}` even after {} attempts.", path.display(), max_attempts);
82
83 let last_error = last_error.unwrap();
84 let message = if let Some(src) = last_error.source() {
85 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0} ({1}) (retried {2} times)",
format_dlopen_err(&last_error), src, max_attempts))
})format!("{} ({src}) (retried {max_attempts} times)", format_dlopen_err(&last_error))
86 } else {
87 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0} (retried {1} times)",
format_dlopen_err(&last_error), max_attempts))
})format!("{} (retried {max_attempts} times)", format_dlopen_err(&last_error))
88 };
89 Err(message)
90}
91
92pub enum DylibError {
93 DlOpen(String, String),
94 DlSym(String, String),
95}
96
97impl From<DylibError> for CrateError {
98 fn from(err: DylibError) -> CrateError {
99 match err {
100 DylibError::DlOpen(path, err) => CrateError::DlOpen(path, err),
101 DylibError::DlSym(path, err) => CrateError::DlSym(path, err),
102 }
103 }
104}
105
106pub unsafe fn load_symbol_from_dylib<T: Copy>(
107 path: &Path,
108 sym_name: &str,
109) -> Result<T, DylibError> {
110 let path = try_canonicalize(path).unwrap();
112 let lib =
113 load_dylib(&path, 5).map_err(|err| DylibError::DlOpen(path.display().to_string(), err))?;
114
115 let sym = unsafe { lib.get::<T>(sym_name.as_bytes()) }
116 .map_err(|err| DylibError::DlSym(path.display().to_string(), format_dlopen_err(&err)))?;
117
118 let sym = unsafe { sym.into_raw() };
121 std::mem::forget(lib);
122
123 Ok(*sym)
124}
125
126pub(crate) fn dlsym_proc_macros(
127 path: &Path,
128 stable_crate_id: StableCrateId,
129) -> Result<&'static [ProcMacroClient], DylibError> {
130 let sym_name = rustc_session::generate_proc_macro_decls_symbol(stable_crate_id);
131 {
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event compiler/rustc_metadata/src/host_dylib.rs:131",
"rustc_metadata::host_dylib", ::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_metadata/src/host_dylib.rs"),
::tracing_core::__macro_support::Option::Some(131u32),
::tracing_core::__macro_support::Option::Some("rustc_metadata::host_dylib"),
::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!("trying to dlsym proc_macros {0} for symbol `{1}`",
path.display(), sym_name) as &dyn Value))])
});
} else { ; }
};debug!("trying to dlsym proc_macros {} for symbol `{}`", path.display(), sym_name);
132
133 unsafe {
134 let result = crate::load_symbol_from_dylib::<*const &[ProcMacroClient]>(path, &sym_name);
136 match result {
137 Ok(result) => {
138 {
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event compiler/rustc_metadata/src/host_dylib.rs:138",
"rustc_metadata::host_dylib", ::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_metadata/src/host_dylib.rs"),
::tracing_core::__macro_support::Option::Some(138u32),
::tracing_core::__macro_support::Option::Some("rustc_metadata::host_dylib"),
::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!("loaded dlsym proc_macros {0} for symbol `{1}`",
path.display(), sym_name) as &dyn Value))])
});
} else { ; }
};debug!("loaded dlsym proc_macros {} for symbol `{}`", path.display(), sym_name);
139 Ok(*result)
140 }
141 Err(err) => {
142 {
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event compiler/rustc_metadata/src/host_dylib.rs:142",
"rustc_metadata::host_dylib", ::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_metadata/src/host_dylib.rs"),
::tracing_core::__macro_support::Option::Some(142u32),
::tracing_core::__macro_support::Option::Some("rustc_metadata::host_dylib"),
::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!("failed to dlsym proc_macros {0} for symbol `{1}`",
path.display(), sym_name) as &dyn Value))])
});
} else { ; }
};debug!("failed to dlsym proc_macros {} for symbol `{}`", path.display(), sym_name);
143 Err(err.into())
144 }
145 }
146 }
147}