1 //! Used by `rustc` when loading a plugin.
3 use crate::errors::{LoadPluginError, MalformedPluginAttribute};
5 use libloading::Library;
7 use rustc_metadata::locator;
8 use rustc_session::cstore::MetadataLoader;
9 use rustc_session::Session;
10 use rustc_span::symbol::{sym, Ident};
14 use std::path::PathBuf;
16 /// Pointer to a registrar function.
17 type PluginRegistrarFn = fn(&mut Registry<'_>);
19 /// Read plugin metadata and dynamically load registrar functions.
22 metadata_loader: &dyn MetadataLoader,
24 ) -> Vec<PluginRegistrarFn> {
25 let mut plugins = Vec::new();
27 for attr in &krate.attrs {
28 if !attr.has_name(sym::plugin) {
32 for plugin in attr.meta_item_list().unwrap_or_default() {
33 match plugin.ident() {
34 Some(ident) if plugin.is_word() => {
35 load_plugin(&mut plugins, sess, metadata_loader, ident)
38 sess.emit_err(MalformedPluginAttribute { span: plugin.span() });
48 plugins: &mut Vec<PluginRegistrarFn>,
50 metadata_loader: &dyn MetadataLoader,
53 let lib = locator::find_plugin_registrar(sess, metadata_loader, ident.span, ident.name);
54 let fun = dylink_registrar(lib).unwrap_or_else(|err| {
55 // This is fatal: there are almost certainly macros we need inside this crate, so
56 // continuing would spew "macro undefined" errors.
57 sess.emit_fatal(LoadPluginError { span: ident.span, msg: err.to_string() });
62 /// Dynamically link a registrar function into the compiler process.
63 fn dylink_registrar(lib_path: PathBuf) -> Result<PluginRegistrarFn, libloading::Error> {
64 // Make sure the path contains a / or the linker will search for it.
65 let lib_path = env::current_dir().unwrap().join(&lib_path);
67 let lib = unsafe { Library::new(&lib_path) }?;
69 let registrar_sym = unsafe { lib.get::<PluginRegistrarFn>(b"__rustc_plugin_registrar") }?;
71 // Intentionally leak the dynamic library. We can't ever unload it
72 // since the library can make things that will live arbitrarily long
73 // (e.g., an Rc cycle or a thread).
74 let registrar_sym = unsafe { registrar_sym.into_raw() };