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.
This commit is contained in:
parent
0987e41d1c
commit
f25c90a83f
@ -4047,7 +4047,6 @@ dependencies = [
|
|||||||
name = "rustc_interface"
|
name = "rustc_interface"
|
||||||
version = "0.0.0"
|
version = "0.0.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libloading",
|
|
||||||
"rustc-rayon",
|
"rustc-rayon",
|
||||||
"rustc-rayon-core",
|
"rustc-rayon-core",
|
||||||
"rustc_ast",
|
"rustc_ast",
|
||||||
|
@ -5,7 +5,6 @@ edition = "2021"
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
# tidy-alphabetical-start
|
# tidy-alphabetical-start
|
||||||
libloading = "0.8.0"
|
|
||||||
rustc-rayon = { version = "0.5.0", optional = true }
|
rustc-rayon = { version = "0.5.0", optional = true }
|
||||||
rustc-rayon-core = { version = "0.5.0", optional = true }
|
rustc-rayon-core = { version = "0.5.0", optional = true }
|
||||||
rustc_ast = { path = "../rustc_ast" }
|
rustc_ast = { path = "../rustc_ast" }
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
#![feature(decl_macro)]
|
#![feature(decl_macro)]
|
||||||
#![feature(error_iter)]
|
|
||||||
#![feature(generic_nonzero)]
|
#![feature(generic_nonzero)]
|
||||||
#![feature(lazy_cell)]
|
#![feature(lazy_cell)]
|
||||||
#![feature(let_chains)]
|
#![feature(let_chains)]
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
use crate::errors;
|
use crate::errors;
|
||||||
use info;
|
use info;
|
||||||
use libloading::Library;
|
|
||||||
use rustc_ast as ast;
|
use rustc_ast as ast;
|
||||||
use rustc_codegen_ssa::traits::CodegenBackend;
|
use rustc_codegen_ssa::traits::CodegenBackend;
|
||||||
#[cfg(parallel_compiler)]
|
#[cfg(parallel_compiler)]
|
||||||
use rustc_data_structures::sync;
|
use rustc_data_structures::sync;
|
||||||
|
use rustc_metadata::{load_symbol_from_dylib, DylibError};
|
||||||
use rustc_parse::validate_attr;
|
use rustc_parse::validate_attr;
|
||||||
use rustc_session as session;
|
use rustc_session as session;
|
||||||
use rustc_session::config::{self, Cfg, CrateType, OutFileName, OutputFilenames, OutputTypes};
|
use rustc_session::config::{self, Cfg, CrateType, OutFileName, OutputFilenames, OutputTypes};
|
||||||
@ -17,7 +17,6 @@
|
|||||||
use session::EarlyDiagCtxt;
|
use session::EarlyDiagCtxt;
|
||||||
use std::env;
|
use std::env;
|
||||||
use std::env::consts::{DLL_PREFIX, DLL_SUFFIX};
|
use std::env::consts::{DLL_PREFIX, DLL_SUFFIX};
|
||||||
use std::mem;
|
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
use std::sync::atomic::{AtomicBool, Ordering};
|
use std::sync::atomic::{AtomicBool, Ordering};
|
||||||
use std::sync::OnceLock;
|
use std::sync::OnceLock;
|
||||||
@ -162,29 +161,19 @@ pub(crate) fn run_in_thread_pool_with_globals<F: FnOnce() -> R + Send, R: Send>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn load_backend_from_dylib(early_dcx: &EarlyDiagCtxt, path: &Path) -> MakeBackendFn {
|
fn load_backend_from_dylib(early_dcx: &EarlyDiagCtxt, path: &Path) -> MakeBackendFn {
|
||||||
fn format_err(e: &(dyn std::error::Error + 'static)) -> String {
|
match unsafe { load_symbol_from_dylib::<MakeBackendFn>(path, "__rustc_codegen_backend") } {
|
||||||
e.sources().map(|e| format!(": {e}")).collect()
|
Ok(backend_sym) => backend_sym,
|
||||||
}
|
Err(DylibError::DlOpen(path, err)) => {
|
||||||
let lib = unsafe { Library::new(path) }.unwrap_or_else(|err| {
|
let err = format!("couldn't load codegen backend {path}{err}");
|
||||||
let err = format!("couldn't load codegen backend {path:?}{}", format_err(&err));
|
|
||||||
early_dcx.early_fatal(err);
|
early_dcx.early_fatal(err);
|
||||||
});
|
}
|
||||||
|
Err(DylibError::DlSym(_path, err)) => {
|
||||||
let backend_sym = unsafe { lib.get::<MakeBackendFn>(b"__rustc_codegen_backend") }
|
|
||||||
.unwrap_or_else(|e| {
|
|
||||||
let e = format!(
|
let e = format!(
|
||||||
"`__rustc_codegen_backend` symbol lookup in the codegen backend failed{}",
|
"`__rustc_codegen_backend` symbol lookup in the codegen backend failed{err}",
|
||||||
format_err(&e)
|
|
||||||
);
|
);
|
||||||
early_dcx.early_fatal(e);
|
early_dcx.early_fatal(e);
|
||||||
});
|
}
|
||||||
|
}
|
||||||
// Intentionally leak the dynamic library. We can't ever unload it
|
|
||||||
// since the library can make things that will live arbitrarily long.
|
|
||||||
let backend_sym = unsafe { backend_sym.into_raw() };
|
|
||||||
mem::forget(lib);
|
|
||||||
|
|
||||||
*backend_sym
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the codegen backend based on the name and specified sysroot.
|
/// Get the codegen backend based on the name and specified sysroot.
|
||||||
|
@ -45,7 +45,7 @@ metadata_crate_not_panic_runtime =
|
|||||||
the crate `{$crate_name}` is not a panic runtime
|
the crate `{$crate_name}` is not a panic runtime
|
||||||
|
|
||||||
metadata_dl_error =
|
metadata_dl_error =
|
||||||
{$err}
|
{$path}{$err}
|
||||||
|
|
||||||
metadata_empty_link_name =
|
metadata_empty_link_name =
|
||||||
link name must not be empty
|
link name must not be empty
|
||||||
|
@ -692,20 +692,8 @@ fn dlsym_proc_macros(
|
|||||||
path: &Path,
|
path: &Path,
|
||||||
stable_crate_id: StableCrateId,
|
stable_crate_id: StableCrateId,
|
||||||
) -> Result<&'static [ProcMacro], CrateError> {
|
) -> Result<&'static [ProcMacro], CrateError> {
|
||||||
// Make sure the path contains a / or the linker will search for it.
|
|
||||||
let path = try_canonicalize(path).unwrap();
|
|
||||||
let lib = load_dylib(&path, 5).map_err(|err| CrateError::DlOpen(err))?;
|
|
||||||
|
|
||||||
let sym_name = self.sess.generate_proc_macro_decls_symbol(stable_crate_id);
|
let sym_name = self.sess.generate_proc_macro_decls_symbol(stable_crate_id);
|
||||||
let sym = unsafe { lib.get::<*const &[ProcMacro]>(sym_name.as_bytes()) }
|
Ok(unsafe { *load_symbol_from_dylib::<*const &[ProcMacro]>(path, &sym_name)? })
|
||||||
.map_err(|err| CrateError::DlSym(err.to_string()))?;
|
|
||||||
|
|
||||||
// Intentionally leak the dynamic library. We can't ever unload it
|
|
||||||
// since the library can make things that will live arbitrarily long.
|
|
||||||
let sym = unsafe { sym.into_raw() };
|
|
||||||
std::mem::forget(lib);
|
|
||||||
|
|
||||||
Ok(unsafe { **sym })
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn inject_panic_runtime(&mut self, krate: &ast::Crate) {
|
fn inject_panic_runtime(&mut self, krate: &ast::Crate) {
|
||||||
@ -1116,6 +1104,10 @@ fn visit_item(&mut self, item: &'ast ast::Item) {
|
|||||||
f.spans
|
f.spans
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn format_dlopen_err(e: &(dyn std::error::Error + 'static)) -> String {
|
||||||
|
e.sources().map(|e| format!(": {e}")).collect()
|
||||||
|
}
|
||||||
|
|
||||||
// On Windows the compiler would sometimes intermittently fail to open the
|
// On Windows the compiler would sometimes intermittently fail to open the
|
||||||
// proc-macro DLL with `Error::LoadLibraryExW`. It is suspected that something in the
|
// proc-macro DLL with `Error::LoadLibraryExW`. It is suspected that something in the
|
||||||
// system still holds a lock on the file, so we retry a few times before calling it
|
// 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
|
|||||||
|
|
||||||
let last_error = last_error.unwrap();
|
let last_error = last_error.unwrap();
|
||||||
let message = if let Some(src) = last_error.source() {
|
let message = if let Some(src) = last_error.source() {
|
||||||
format!("{last_error} ({src}) (retried {max_attempts} times)")
|
format!("{} ({src}) (retried {max_attempts} times)", format_dlopen_err(&last_error))
|
||||||
} else {
|
} else {
|
||||||
format!("{last_error} (retried {max_attempts} times)")
|
format!("{} (retried {max_attempts} times)", format_dlopen_err(&last_error))
|
||||||
};
|
};
|
||||||
Err(message)
|
Err(message)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub enum DylibError {
|
||||||
|
DlOpen(String, String),
|
||||||
|
DlSym(String, String),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<DylibError> for CrateError {
|
||||||
|
fn from(err: DylibError) -> CrateError {
|
||||||
|
match err {
|
||||||
|
DylibError::DlOpen(path, err) => CrateError::DlOpen(path, err),
|
||||||
|
DylibError::DlSym(path, err) => CrateError::DlSym(path, err),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn load_symbol_from_dylib<T: Copy>(
|
||||||
|
path: &Path,
|
||||||
|
sym_name: &str,
|
||||||
|
) -> Result<T, DylibError> {
|
||||||
|
// Make sure the path contains a / or the linker will search for it.
|
||||||
|
let path = try_canonicalize(path).unwrap();
|
||||||
|
let lib =
|
||||||
|
load_dylib(&path, 5).map_err(|err| DylibError::DlOpen(path.display().to_string(), err))?;
|
||||||
|
|
||||||
|
let sym = unsafe { lib.get::<T>(sym_name.as_bytes()) }
|
||||||
|
.map_err(|err| DylibError::DlSym(path.display().to_string(), format_dlopen_err(&err)))?;
|
||||||
|
|
||||||
|
// Intentionally leak the dynamic library. We can't ever unload it
|
||||||
|
// since the library can make things that will live arbitrarily long.
|
||||||
|
let sym = unsafe { sym.into_raw() };
|
||||||
|
std::mem::forget(lib);
|
||||||
|
|
||||||
|
Ok(*sym)
|
||||||
|
}
|
||||||
|
@ -535,6 +535,7 @@ pub struct StableCrateIdCollision {
|
|||||||
pub struct DlError {
|
pub struct DlError {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
|
pub path: String,
|
||||||
pub err: String,
|
pub err: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
#![feature(rustdoc_internals)]
|
#![feature(rustdoc_internals)]
|
||||||
#![allow(internal_features)]
|
#![allow(internal_features)]
|
||||||
#![feature(decl_macro)]
|
#![feature(decl_macro)]
|
||||||
|
#![feature(error_iter)]
|
||||||
#![feature(extract_if)]
|
#![feature(extract_if)]
|
||||||
#![feature(coroutines)]
|
#![feature(coroutines)]
|
||||||
#![feature(generic_nonzero)]
|
#![feature(generic_nonzero)]
|
||||||
@ -39,6 +40,7 @@
|
|||||||
pub mod fs;
|
pub mod fs;
|
||||||
pub mod locator;
|
pub mod locator;
|
||||||
|
|
||||||
|
pub use creader::{load_symbol_from_dylib, DylibError};
|
||||||
pub use fs::{emit_wrapper_file, METADATA_FILENAME};
|
pub use fs::{emit_wrapper_file, METADATA_FILENAME};
|
||||||
pub use native_libs::find_native_static_library;
|
pub use native_libs::find_native_static_library;
|
||||||
pub use rmeta::{encode_metadata, rendered_const, EncodedMetadata, METADATA_HEADER};
|
pub use rmeta::{encode_metadata, rendered_const, EncodedMetadata, METADATA_HEADER};
|
||||||
|
@ -921,8 +921,8 @@ pub(crate) enum CrateError {
|
|||||||
MultipleCandidates(Symbol, CrateFlavor, Vec<PathBuf>),
|
MultipleCandidates(Symbol, CrateFlavor, Vec<PathBuf>),
|
||||||
SymbolConflictsCurrent(Symbol),
|
SymbolConflictsCurrent(Symbol),
|
||||||
StableCrateIdCollision(Symbol, Symbol),
|
StableCrateIdCollision(Symbol, Symbol),
|
||||||
DlOpen(String),
|
DlOpen(String, String),
|
||||||
DlSym(String),
|
DlSym(String, String),
|
||||||
LocatorCombined(Box<CombinedLocatorError>),
|
LocatorCombined(Box<CombinedLocatorError>),
|
||||||
NotFound(Symbol),
|
NotFound(Symbol),
|
||||||
}
|
}
|
||||||
@ -967,8 +967,8 @@ pub(crate) fn report(self, sess: &Session, span: Span, missing_core: bool) {
|
|||||||
CrateError::StableCrateIdCollision(crate_name0, crate_name1) => {
|
CrateError::StableCrateIdCollision(crate_name0, crate_name1) => {
|
||||||
dcx.emit_err(errors::StableCrateIdCollision { span, crate_name0, crate_name1 });
|
dcx.emit_err(errors::StableCrateIdCollision { span, crate_name0, crate_name1 });
|
||||||
}
|
}
|
||||||
CrateError::DlOpen(s) | CrateError::DlSym(s) => {
|
CrateError::DlOpen(path, err) | CrateError::DlSym(path, err) => {
|
||||||
dcx.emit_err(errors::DlError { span, err: s });
|
dcx.emit_err(errors::DlError { span, path, err });
|
||||||
}
|
}
|
||||||
CrateError::LocatorCombined(locator) => {
|
CrateError::LocatorCombined(locator) => {
|
||||||
let crate_name = locator.crate_name;
|
let crate_name = locator.crate_name;
|
||||||
|
Loading…
Reference in New Issue
Block a user