|
@@ -9,27 +9,15 @@ use std::borrow::ToOwned; |
|
|
use std::env; |
|
|
use std::mem; |
|
|
use std::path::PathBuf; |
|
|
use syntax::ast; |
|
|
use syntax::ast::{Crate, Ident}; |
|
|
use syntax::struct_span_err; |
|
|
use syntax::symbol::{Symbol, kw, sym}; |
|
|
use syntax_pos::{Span, DUMMY_SP}; |
|
|
use syntax::symbol::sym; |
|
|
use syntax_pos::Span; |
|
|
|
|
|
use rustc_error_codes::*; |
|
|
|
|
|
/// Pointer to a registrar function. |
|
|
pub type PluginRegistrarFun = |
|
|
fn(&mut Registry<'_>); |
|
|
|
|
|
pub struct PluginRegistrar { |
|
|
pub fun: PluginRegistrarFun, |
|
|
pub args: Vec<ast::NestedMetaItem>, |
|
|
} |
|
|
|
|
|
struct PluginLoader<'a> { |
|
|
sess: &'a Session, |
|
|
metadata_loader: &'a dyn MetadataLoader, |
|
|
plugins: Vec<PluginRegistrar>, |
|
|
} |
|
|
type PluginRegistrarFn = fn(&mut Registry<'_>); |
|
|
|
|
|
fn call_malformed_plugin_attribute(sess: &Session, span: Span) { |
|
|
struct_span_err!(sess, span, E0498, "malformed `plugin` attribute") |
|
@@ -40,98 +28,81 @@ fn call_malformed_plugin_attribute(sess: &Session, span: Span) { |
|
|
/// Read plugin metadata and dynamically load registrar functions. |
|
|
pub fn load_plugins(sess: &Session, |
|
|
metadata_loader: &dyn MetadataLoader, |
|
|
krate: &ast::Crate, |
|
|
addl_plugins: Option<Vec<String>>) -> Vec<PluginRegistrar> { |
|
|
let mut loader = PluginLoader { sess, metadata_loader, plugins: Vec::new() }; |
|
|
|
|
|
// do not report any error now. since crate attributes are |
|
|
// not touched by expansion, every use of plugin without |
|
|
// the feature enabled will result in an error later... |
|
|
if sess.features_untracked().plugin { |
|
|
for attr in &krate.attrs { |
|
|
if !attr.check_name(sym::plugin) { |
|
|
continue; |
|
|
} |
|
|
|
|
|
let plugins = match attr.meta_item_list() { |
|
|
Some(xs) => xs, |
|
|
None => continue, |
|
|
}; |
|
|
krate: &Crate, |
|
|
addl_plugins: Option<Vec<String>>) -> Vec<PluginRegistrarFn> { |
|
|
let mut plugins = Vec::new(); |
|
|
let mut load_plugin = |ident| load_plugin(&mut plugins, sess, metadata_loader, ident); |
|
|
|
|
|
for attr in &krate.attrs { |
|
|
if !attr.check_name(sym::plugin) { |
|
|
continue; |
|
|
} |
|
|
|
|
|
for plugin in plugins { |
|
|
// plugins must have a name and can't be key = value |
|
|
let name = plugin.name_or_empty(); |
|
|
if name != kw::Invalid && !plugin.is_value_str() { |
|
|
let args = plugin.meta_item_list().map(ToOwned::to_owned); |
|
|
loader.load_plugin(plugin.span(), name, args.unwrap_or_default()); |
|
|
} else { |
|
|
call_malformed_plugin_attribute(sess, attr.span); |
|
|
} |
|
|
for plugin in attr.meta_item_list().unwrap_or_default() { |
|
|
match plugin.ident() { |
|
|
Some(ident) if plugin.is_word() => load_plugin(ident), |
|
|
_ => call_malformed_plugin_attribute(sess, plugin.span()), |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
if let Some(plugins) = addl_plugins { |
|
|
for plugin in plugins { |
|
|
loader.load_plugin(DUMMY_SP, Symbol::intern(&plugin), vec![]); |
|
|
} |
|
|
for plugin in addl_plugins.unwrap_or_default() { |
|
|
load_plugin(Ident::from_str(&plugin)); |
|
|
} |
|
|
|
|
|
loader.plugins |
|
|
plugins |
|
|
} |
|
|
|
|
|
impl<'a> PluginLoader<'a> { |
|
|
fn load_plugin(&mut self, span: Span, name: Symbol, args: Vec<ast::NestedMetaItem>) { |
|
|
let registrar = locator::find_plugin_registrar(self.sess, self.metadata_loader, span, name); |
|
|
|
|
|
if let Some((lib, disambiguator)) = registrar { |
|
|
let symbol = self.sess.generate_plugin_registrar_symbol(disambiguator); |
|
|
let fun = self.dylink_registrar(span, lib, symbol); |
|
|
self.plugins.push(PluginRegistrar { |
|
|
fun, |
|
|
args, |
|
|
}); |
|
|
} |
|
|
fn load_plugin(plugins: &mut Vec<PluginRegistrarFn>, |
|
|
sess: &Session, |
|
|
metadata_loader: &dyn MetadataLoader, |
|
|
ident: Ident) { |
|
|
let registrar = locator::find_plugin_registrar(sess, metadata_loader, ident.span, ident.name); |
|
|
|
|
|
if let Some((lib, disambiguator)) = registrar { |
|
|
let symbol = sess.generate_plugin_registrar_symbol(disambiguator); |
|
|
let fun = dylink_registrar(sess, ident.span, lib, symbol); |
|
|
plugins.push(fun); |
|
|
} |
|
|
} |
|
|
|
|
|
// Dynamically link a registrar function into the compiler process. |
|
|
fn dylink_registrar(&mut self, |
|
|
span: Span, |
|
|
path: PathBuf, |
|
|
symbol: String) -> PluginRegistrarFun { |
|
|
use rustc_metadata::dynamic_lib::DynamicLibrary; |
|
|
|
|
|
// Make sure the path contains a / or the linker will search for it. |
|
|
let path = env::current_dir().unwrap().join(&path); |
|
|
|
|
|
let lib = match DynamicLibrary::open(Some(&path)) { |
|
|
Ok(lib) => lib, |
|
|
// this is fatal: there are almost certainly macros we need |
|
|
// inside this crate, so continue would spew "macro undefined" |
|
|
// errors |
|
|
Err(err) => { |
|
|
self.sess.span_fatal(span, &err) |
|
|
} |
|
|
}; |
|
|
|
|
|
unsafe { |
|
|
let registrar = |
|
|
match lib.symbol(&symbol) { |
|
|
Ok(registrar) => { |
|
|
mem::transmute::<*mut u8,PluginRegistrarFun>(registrar) |
|
|
} |
|
|
// again fatal if we can't register macros |
|
|
Err(err) => { |
|
|
self.sess.span_fatal(span, &err) |
|
|
} |
|
|
}; |
|
|
|
|
|
// Intentionally leak the dynamic library. We can't ever unload it |
|
|
// since the library can make things that will live arbitrarily long |
|
|
// (e.g., an @-box cycle or a thread). |
|
|
mem::forget(lib); |
|
|
|
|
|
registrar |
|
|
// Dynamically link a registrar function into the compiler process. |
|
|
fn dylink_registrar(sess: &Session, |
|
|
span: Span, |
|
|
path: PathBuf, |
|
|
symbol: String) -> PluginRegistrarFn { |
|
|
use rustc_metadata::dynamic_lib::DynamicLibrary; |
|
|
|
|
|
// Make sure the path contains a / or the linker will search for it. |
|
|
let path = env::current_dir().unwrap().join(&path); |
|
|
|
|
|
let lib = match DynamicLibrary::open(Some(&path)) { |
|
|
Ok(lib) => lib, |
|
|
// this is fatal: there are almost certainly macros we need |
|
|
// inside this crate, so continue would spew "macro undefined" |
|
|
// errors |
|
|
Err(err) => { |
|
|
sess.span_fatal(span, &err) |
|
|
} |
|
|
}; |
|
|
|
|
|
unsafe { |
|
|
let registrar = |
|
|
match lib.symbol(&symbol) { |
|
|
Ok(registrar) => { |
|
|
mem::transmute::<*mut u8, PluginRegistrarFn>(registrar) |
|
|
} |
|
|
// again fatal if we can't register macros |
|
|
Err(err) => { |
|
|
sess.span_fatal(span, &err) |
|
|
} |
|
|
}; |
|
|
|
|
|
// Intentionally leak the dynamic library. We can't ever unload it |
|
|
// since the library can make things that will live arbitrarily long |
|
|
// (e.g., an @-box cycle or a thread). |
|
|
mem::forget(lib); |
|
|
|
|
|
registrar |
|
|
} |
|
|
} |
0 comments on commit
55ba05b