Skip to content

Commit 6bda5b3

Browse files
committed
Auto merge of #90716 - euclio:libloading, r=cjgillot
replace dynamic library module with libloading This PR deletes the `rustc_metadata::dynamic_lib` module in favor of the popular and better tested [`libloading` crate](https://github.com/nagisa/rust_libloading/). We don't benefit from `libloading`'s symbol lifetimes since we end up leaking the loaded library in all cases, but the call-sites look much nicer by improving error handling and abstracting away some transmutes. We also can remove `rustc_metadata`'s direct dependencies on `libc` and `winapi`. This PR also adds an exception for `libloading` (and its license) to tidy, so this will need sign-off from the compiler team.
2 parents 753e569 + 923f939 commit 6bda5b3

File tree

15 files changed

+91
-313
lines changed

15 files changed

+91
-313
lines changed

Cargo.lock

+14-2
Original file line numberDiff line numberDiff line change
@@ -1926,6 +1926,16 @@ dependencies = [
19261926
"pkg-config",
19271927
]
19281928

1929+
[[package]]
1930+
name = "libloading"
1931+
version = "0.7.1"
1932+
source = "registry+https://github.com/rust-lang/crates.io-index"
1933+
checksum = "c0cf036d15402bea3c5d4de17b3fce76b3e4a56ebc1f577be0e7a72f7c607cf0"
1934+
dependencies = [
1935+
"cfg-if 1.0.0",
1936+
"winapi",
1937+
]
1938+
19291939
[[package]]
19301940
name = "libm"
19311941
version = "0.1.4"
@@ -3694,6 +3704,7 @@ dependencies = [
36943704
"bitflags",
36953705
"cstr",
36963706
"libc",
3707+
"libloading",
36973708
"measureme 10.0.0",
36983709
"rustc-demangle",
36993710
"rustc_arena",
@@ -3978,6 +3989,7 @@ name = "rustc_interface"
39783989
version = "0.0.0"
39793990
dependencies = [
39803991
"libc",
3992+
"libloading",
39813993
"rustc-rayon",
39823994
"rustc-rayon-core",
39833995
"rustc_ast",
@@ -4090,7 +4102,7 @@ dependencies = [
40904102
name = "rustc_metadata"
40914103
version = "0.0.0"
40924104
dependencies = [
4093-
"libc",
4105+
"libloading",
40944106
"odht",
40954107
"rustc_ast",
40964108
"rustc_attr",
@@ -4110,7 +4122,6 @@ dependencies = [
41104122
"smallvec",
41114123
"snap",
41124124
"tracing",
4113-
"winapi",
41144125
]
41154126

41164127
[[package]]
@@ -4283,6 +4294,7 @@ dependencies = [
42834294
name = "rustc_plugin_impl"
42844295
version = "0.0.0"
42854296
dependencies = [
4297+
"libloading",
42864298
"rustc_ast",
42874299
"rustc_errors",
42884300
"rustc_hir",

compiler/rustc_codegen_llvm/Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ doctest = false
1111
bitflags = "1.0"
1212
cstr = "0.2"
1313
libc = "0.2"
14+
libloading = "0.7.1"
1415
measureme = "10.0.0"
1516
tracing = "0.1"
1617
rustc_middle = { path = "../rustc_middle" }

compiler/rustc_codegen_llvm/src/llvm_util.rs

+8-9
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
use crate::back::write::create_informational_target_machine;
22
use crate::{llvm, llvm_util};
33
use libc::c_int;
4+
use libloading::Library;
45
use rustc_codegen_ssa::target_features::supported_target_features;
56
use rustc_data_structures::fx::FxHashSet;
6-
use rustc_metadata::dynamic_lib::DynamicLibrary;
77
use rustc_middle::bug;
88
use rustc_session::config::PrintRequest;
99
use rustc_session::Session;
@@ -13,7 +13,6 @@ use std::ffi::{CStr, CString};
1313
use tracing::debug;
1414

1515
use std::mem;
16-
use std::path::Path;
1716
use std::ptr;
1817
use std::slice;
1918
use std::str;
@@ -120,14 +119,14 @@ unsafe fn configure_llvm(sess: &Session) {
120119

121120
llvm::LLVMInitializePasses();
122121

122+
// Register LLVM plugins by loading them into the compiler process.
123123
for plugin in &sess.opts.debugging_opts.llvm_plugins {
124-
let path = Path::new(plugin);
125-
let res = DynamicLibrary::open(path);
126-
match res {
127-
Ok(_) => debug!("LLVM plugin loaded succesfully {} ({})", path.display(), plugin),
128-
Err(e) => bug!("couldn't load plugin: {}", e),
129-
}
130-
mem::forget(res);
124+
let lib = Library::new(plugin).unwrap_or_else(|e| bug!("couldn't load plugin: {}", e));
125+
debug!("LLVM plugin loaded successfully {:?} ({})", lib, plugin);
126+
127+
// Intentionally leak the dynamic library. We can't ever unload it
128+
// since the library can make things that will live arbitrarily long.
129+
mem::forget(lib);
131130
}
132131

133132
rustc_llvm::initialize_available_targets();

compiler/rustc_interface/Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ doctest = false
88

99
[dependencies]
1010
libc = "0.2"
11+
libloading = "0.7.1"
1112
tracing = "0.1"
1213
rustc-rayon-core = "0.3.1"
1314
rayon = { version = "0.3.1", package = "rustc-rayon" }

compiler/rustc_interface/src/util.rs

+21-25
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use libloading::Library;
12
use rustc_ast::mut_visit::{visit_clobber, MutVisitor, *};
23
use rustc_ast::ptr::P;
34
use rustc_ast::{self as ast, AttrVec, BlockCheckMode};
@@ -7,7 +8,6 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet};
78
use rustc_data_structures::jobserver;
89
use rustc_data_structures::sync::Lrc;
910
use rustc_errors::registry::Registry;
10-
use rustc_metadata::dynamic_lib::DynamicLibrary;
1111
#[cfg(parallel_compiler)]
1212
use rustc_middle::ty::tls;
1313
use rustc_parse::validate_attr;
@@ -39,6 +39,9 @@ use std::sync::{Arc, Mutex};
3939
use std::thread;
4040
use tracing::info;
4141

42+
/// Function pointer type that constructs a new CodegenBackend.
43+
pub type MakeBackendFn = fn() -> Box<dyn CodegenBackend>;
44+
4245
/// Adds `target_feature = "..."` cfgs for a variety of platform
4346
/// specific features (SSE, NEON etc.).
4447
///
@@ -211,28 +214,24 @@ pub fn setup_callbacks_and_run_in_thread_pool_with_globals<F: FnOnce() -> R + Se
211214
})
212215
}
213216

214-
fn load_backend_from_dylib(path: &Path) -> fn() -> Box<dyn CodegenBackend> {
215-
let lib = DynamicLibrary::open(path).unwrap_or_else(|err| {
216-
let err = format!("couldn't load codegen backend {:?}: {:?}", path, err);
217+
fn load_backend_from_dylib(path: &Path) -> MakeBackendFn {
218+
let lib = unsafe { Library::new(path) }.unwrap_or_else(|err| {
219+
let err = format!("couldn't load codegen backend {:?}: {}", path, err);
217220
early_error(ErrorOutputType::default(), &err);
218221
});
219-
unsafe {
220-
match lib.symbol("__rustc_codegen_backend") {
221-
Ok(f) => {
222-
mem::forget(lib);
223-
mem::transmute::<*mut u8, _>(f)
224-
}
225-
Err(e) => {
226-
let err = format!(
227-
"couldn't load codegen backend as it \
228-
doesn't export the `__rustc_codegen_backend` \
229-
symbol: {:?}",
230-
e
231-
);
232-
early_error(ErrorOutputType::default(), &err);
233-
}
234-
}
235-
}
222+
223+
let backend_sym = unsafe { lib.get::<MakeBackendFn>(b"__rustc_codegen_backend") }
224+
.unwrap_or_else(|e| {
225+
let err = format!("couldn't load codegen backend: {}", e);
226+
early_error(ErrorOutputType::default(), &err);
227+
});
228+
229+
// Intentionally leak the dynamic library. We can't ever unload it
230+
// since the library can make things that will live arbitrarily long.
231+
let backend_sym = unsafe { backend_sym.into_raw() };
232+
mem::forget(lib);
233+
234+
*backend_sym
236235
}
237236

238237
/// Get the codegen backend based on the name and specified sysroot.
@@ -380,10 +379,7 @@ fn sysroot_candidates() -> Vec<PathBuf> {
380379
}
381380
}
382381

383-
pub fn get_codegen_sysroot(
384-
maybe_sysroot: &Option<PathBuf>,
385-
backend_name: &str,
386-
) -> fn() -> Box<dyn CodegenBackend> {
382+
pub fn get_codegen_sysroot(maybe_sysroot: &Option<PathBuf>, backend_name: &str) -> MakeBackendFn {
387383
// For now we only allow this function to be called once as it'll dlopen a
388384
// few things, which seems to work best if we only do that once. In
389385
// general this assertion never trips due to the once guard in `get_codegen_backend`,

compiler/rustc_metadata/Cargo.toml

+1-4
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ edition = "2021"
77
doctest = false
88

99
[dependencies]
10-
libc = "0.2"
10+
libloading = "0.7.1"
1111
odht = { version = "0.3.1", features = ["nightly"] }
1212
snap = "1"
1313
tracing = "0.1"
@@ -27,6 +27,3 @@ rustc_ast = { path = "../rustc_ast" }
2727
rustc_expand = { path = "../rustc_expand" }
2828
rustc_span = { path = "../rustc_span" }
2929
rustc_session = { path = "../rustc_session" }
30-
31-
[target.'cfg(windows)'.dependencies]
32-
winapi = { version = "0.3", features = ["errhandlingapi", "libloaderapi"] }

compiler/rustc_metadata/src/creader.rs

+7-14
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
//! Validates all used crates and extern libraries and loads their metadata
22
3-
use crate::dynamic_lib::DynamicLibrary;
43
use crate::locator::{CrateError, CrateLocator, CratePaths};
54
use crate::rmeta::{CrateDep, CrateMetadata, CrateNumMap, CrateRoot, MetadataBlob};
65

@@ -676,25 +675,19 @@ impl<'a> CrateLoader<'a> {
676675
) -> Result<&'static [ProcMacro], CrateError> {
677676
// Make sure the path contains a / or the linker will search for it.
678677
let path = env::current_dir().unwrap().join(path);
679-
let lib = match DynamicLibrary::open(&path) {
680-
Ok(lib) => lib,
681-
Err(s) => return Err(CrateError::DlOpen(s)),
682-
};
678+
let lib = unsafe { libloading::Library::new(path) }
679+
.map_err(|err| CrateError::DlOpen(err.to_string()))?;
683680

684-
let sym = self.sess.generate_proc_macro_decls_symbol(stable_crate_id);
685-
let decls = unsafe {
686-
let sym = match lib.symbol(&sym) {
687-
Ok(f) => f,
688-
Err(s) => return Err(CrateError::DlSym(s)),
689-
};
690-
*(sym as *const &[ProcMacro])
691-
};
681+
let sym_name = self.sess.generate_proc_macro_decls_symbol(stable_crate_id);
682+
let sym = unsafe { lib.get::<*const &[ProcMacro]>(sym_name.as_bytes()) }
683+
.map_err(|err| CrateError::DlSym(err.to_string()))?;
692684

693685
// Intentionally leak the dynamic library. We can't ever unload it
694686
// since the library can make things that will live arbitrarily long.
687+
let sym = unsafe { sym.into_raw() };
695688
std::mem::forget(lib);
696689

697-
Ok(decls)
690+
Ok(unsafe { **sym })
698691
}
699692

700693
fn inject_panic_runtime(&mut self, krate: &ast::Crate) {

0 commit comments

Comments
 (0)