Skip to content

Commit f25c90a

Browse files
committed
Unify dylib loading between proc macros and codegen backends
As bonus this makes the errors when failing to load a proc macro more informative to match the backend loading errors. In addition it makes it slightly easier to patch rustc to work on platforms that don't support dynamic linking like wasm.
1 parent 0987e41 commit f25c90a

File tree

9 files changed

+60
-45
lines changed

9 files changed

+60
-45
lines changed

Cargo.lock

-1
Original file line numberDiff line numberDiff line change
@@ -4047,7 +4047,6 @@ dependencies = [
40474047
name = "rustc_interface"
40484048
version = "0.0.0"
40494049
dependencies = [
4050-
"libloading",
40514050
"rustc-rayon",
40524051
"rustc-rayon-core",
40534052
"rustc_ast",

compiler/rustc_interface/Cargo.toml

-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ edition = "2021"
55

66
[dependencies]
77
# tidy-alphabetical-start
8-
libloading = "0.8.0"
98
rustc-rayon = { version = "0.5.0", optional = true }
109
rustc-rayon-core = { version = "0.5.0", optional = true }
1110
rustc_ast = { path = "../rustc_ast" }

compiler/rustc_interface/src/lib.rs

-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
#![feature(decl_macro)]
2-
#![feature(error_iter)]
32
#![feature(generic_nonzero)]
43
#![feature(lazy_cell)]
54
#![feature(let_chains)]

compiler/rustc_interface/src/util.rs

+11-22
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
use crate::errors;
22
use info;
3-
use libloading::Library;
43
use rustc_ast as ast;
54
use rustc_codegen_ssa::traits::CodegenBackend;
65
#[cfg(parallel_compiler)]
76
use rustc_data_structures::sync;
7+
use rustc_metadata::{load_symbol_from_dylib, DylibError};
88
use rustc_parse::validate_attr;
99
use rustc_session as session;
1010
use rustc_session::config::{self, Cfg, CrateType, OutFileName, OutputFilenames, OutputTypes};
@@ -17,7 +17,6 @@ use rustc_span::symbol::{sym, Symbol};
1717
use session::EarlyDiagCtxt;
1818
use std::env;
1919
use std::env::consts::{DLL_PREFIX, DLL_SUFFIX};
20-
use std::mem;
2120
use std::path::{Path, PathBuf};
2221
use std::sync::atomic::{AtomicBool, Ordering};
2322
use std::sync::OnceLock;
@@ -162,29 +161,19 @@ pub(crate) fn run_in_thread_pool_with_globals<F: FnOnce() -> R + Send, R: Send>(
162161
}
163162

164163
fn load_backend_from_dylib(early_dcx: &EarlyDiagCtxt, path: &Path) -> MakeBackendFn {
165-
fn format_err(e: &(dyn std::error::Error + 'static)) -> String {
166-
e.sources().map(|e| format!(": {e}")).collect()
167-
}
168-
let lib = unsafe { Library::new(path) }.unwrap_or_else(|err| {
169-
let err = format!("couldn't load codegen backend {path:?}{}", format_err(&err));
170-
early_dcx.early_fatal(err);
171-
});
172-
173-
let backend_sym = unsafe { lib.get::<MakeBackendFn>(b"__rustc_codegen_backend") }
174-
.unwrap_or_else(|e| {
164+
match unsafe { load_symbol_from_dylib::<MakeBackendFn>(path, "__rustc_codegen_backend") } {
165+
Ok(backend_sym) => backend_sym,
166+
Err(DylibError::DlOpen(path, err)) => {
167+
let err = format!("couldn't load codegen backend {path}{err}");
168+
early_dcx.early_fatal(err);
169+
}
170+
Err(DylibError::DlSym(_path, err)) => {
175171
let e = format!(
176-
"`__rustc_codegen_backend` symbol lookup in the codegen backend failed{}",
177-
format_err(&e)
172+
"`__rustc_codegen_backend` symbol lookup in the codegen backend failed{err}",
178173
);
179174
early_dcx.early_fatal(e);
180-
});
181-
182-
// Intentionally leak the dynamic library. We can't ever unload it
183-
// since the library can make things that will live arbitrarily long.
184-
let backend_sym = unsafe { backend_sym.into_raw() };
185-
mem::forget(lib);
186-
187-
*backend_sym
175+
}
176+
}
188177
}
189178

190179
/// Get the codegen backend based on the name and specified sysroot.

compiler/rustc_metadata/messages.ftl

+1-1
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ metadata_crate_not_panic_runtime =
4545
the crate `{$crate_name}` is not a panic runtime
4646
4747
metadata_dl_error =
48-
{$err}
48+
{$path}{$err}
4949
5050
metadata_empty_link_name =
5151
link name must not be empty

compiler/rustc_metadata/src/creader.rs

+41-15
Original file line numberDiff line numberDiff line change
@@ -692,20 +692,8 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
692692
path: &Path,
693693
stable_crate_id: StableCrateId,
694694
) -> Result<&'static [ProcMacro], CrateError> {
695-
// Make sure the path contains a / or the linker will search for it.
696-
let path = try_canonicalize(path).unwrap();
697-
let lib = load_dylib(&path, 5).map_err(|err| CrateError::DlOpen(err))?;
698-
699695
let sym_name = self.sess.generate_proc_macro_decls_symbol(stable_crate_id);
700-
let sym = unsafe { lib.get::<*const &[ProcMacro]>(sym_name.as_bytes()) }
701-
.map_err(|err| CrateError::DlSym(err.to_string()))?;
702-
703-
// Intentionally leak the dynamic library. We can't ever unload it
704-
// since the library can make things that will live arbitrarily long.
705-
let sym = unsafe { sym.into_raw() };
706-
std::mem::forget(lib);
707-
708-
Ok(unsafe { **sym })
696+
Ok(unsafe { *load_symbol_from_dylib::<*const &[ProcMacro]>(path, &sym_name)? })
709697
}
710698

711699
fn inject_panic_runtime(&mut self, krate: &ast::Crate) {
@@ -1116,6 +1104,10 @@ fn alloc_error_handler_spans(krate: &ast::Crate) -> Vec<Span> {
11161104
f.spans
11171105
}
11181106

1107+
fn format_dlopen_err(e: &(dyn std::error::Error + 'static)) -> String {
1108+
e.sources().map(|e| format!(": {e}")).collect()
1109+
}
1110+
11191111
// On Windows the compiler would sometimes intermittently fail to open the
11201112
// proc-macro DLL with `Error::LoadLibraryExW`. It is suspected that something in the
11211113
// system still holds a lock on the file, so we retry a few times before calling it
@@ -1154,9 +1146,43 @@ fn load_dylib(path: &Path, max_attempts: usize) -> Result<libloading::Library, S
11541146

11551147
let last_error = last_error.unwrap();
11561148
let message = if let Some(src) = last_error.source() {
1157-
format!("{last_error} ({src}) (retried {max_attempts} times)")
1149+
format!("{} ({src}) (retried {max_attempts} times)", format_dlopen_err(&last_error))
11581150
} else {
1159-
format!("{last_error} (retried {max_attempts} times)")
1151+
format!("{} (retried {max_attempts} times)", format_dlopen_err(&last_error))
11601152
};
11611153
Err(message)
11621154
}
1155+
1156+
pub enum DylibError {
1157+
DlOpen(String, String),
1158+
DlSym(String, String),
1159+
}
1160+
1161+
impl From<DylibError> for CrateError {
1162+
fn from(err: DylibError) -> CrateError {
1163+
match err {
1164+
DylibError::DlOpen(path, err) => CrateError::DlOpen(path, err),
1165+
DylibError::DlSym(path, err) => CrateError::DlSym(path, err),
1166+
}
1167+
}
1168+
}
1169+
1170+
pub unsafe fn load_symbol_from_dylib<T: Copy>(
1171+
path: &Path,
1172+
sym_name: &str,
1173+
) -> Result<T, DylibError> {
1174+
// Make sure the path contains a / or the linker will search for it.
1175+
let path = try_canonicalize(path).unwrap();
1176+
let lib =
1177+
load_dylib(&path, 5).map_err(|err| DylibError::DlOpen(path.display().to_string(), err))?;
1178+
1179+
let sym = unsafe { lib.get::<T>(sym_name.as_bytes()) }
1180+
.map_err(|err| DylibError::DlSym(path.display().to_string(), format_dlopen_err(&err)))?;
1181+
1182+
// Intentionally leak the dynamic library. We can't ever unload it
1183+
// since the library can make things that will live arbitrarily long.
1184+
let sym = unsafe { sym.into_raw() };
1185+
std::mem::forget(lib);
1186+
1187+
Ok(*sym)
1188+
}

compiler/rustc_metadata/src/errors.rs

+1
Original file line numberDiff line numberDiff line change
@@ -535,6 +535,7 @@ pub struct StableCrateIdCollision {
535535
pub struct DlError {
536536
#[primary_span]
537537
pub span: Span,
538+
pub path: String,
538539
pub err: String,
539540
}
540541

compiler/rustc_metadata/src/lib.rs

+2
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
#![feature(rustdoc_internals)]
44
#![allow(internal_features)]
55
#![feature(decl_macro)]
6+
#![feature(error_iter)]
67
#![feature(extract_if)]
78
#![feature(coroutines)]
89
#![feature(generic_nonzero)]
@@ -39,6 +40,7 @@ pub mod errors;
3940
pub mod fs;
4041
pub mod locator;
4142

43+
pub use creader::{load_symbol_from_dylib, DylibError};
4244
pub use fs::{emit_wrapper_file, METADATA_FILENAME};
4345
pub use native_libs::find_native_static_library;
4446
pub use rmeta::{encode_metadata, rendered_const, EncodedMetadata, METADATA_HEADER};

compiler/rustc_metadata/src/locator.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -921,8 +921,8 @@ pub(crate) enum CrateError {
921921
MultipleCandidates(Symbol, CrateFlavor, Vec<PathBuf>),
922922
SymbolConflictsCurrent(Symbol),
923923
StableCrateIdCollision(Symbol, Symbol),
924-
DlOpen(String),
925-
DlSym(String),
924+
DlOpen(String, String),
925+
DlSym(String, String),
926926
LocatorCombined(Box<CombinedLocatorError>),
927927
NotFound(Symbol),
928928
}
@@ -967,8 +967,8 @@ impl CrateError {
967967
CrateError::StableCrateIdCollision(crate_name0, crate_name1) => {
968968
dcx.emit_err(errors::StableCrateIdCollision { span, crate_name0, crate_name1 });
969969
}
970-
CrateError::DlOpen(s) | CrateError::DlSym(s) => {
971-
dcx.emit_err(errors::DlError { span, err: s });
970+
CrateError::DlOpen(path, err) | CrateError::DlSym(path, err) => {
971+
dcx.emit_err(errors::DlError { span, path, err });
972972
}
973973
CrateError::LocatorCombined(locator) => {
974974
let crate_name = locator.crate_name;

0 commit comments

Comments
 (0)