1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
use rustc::session::Session;
use rustc_metadata::creader::CrateLoader;
use rustc_metadata::cstore::CStore;
use registry::Registry;
use std::borrow::ToOwned;
use std::env;
use std::mem;
use std::path::PathBuf;
use syntax::ast;
use syntax_pos::{Span, COMMAND_LINE_SP};
pub type PluginRegistrarFun =
fn(&mut Registry);
pub struct PluginRegistrar {
pub fun: PluginRegistrarFun,
pub args: Vec<ast::NestedMetaItem>,
}
struct PluginLoader<'a> {
sess: &'a Session,
reader: CrateLoader<'a>,
plugins: Vec<PluginRegistrar>,
}
fn call_malformed_plugin_attribute(a: &Session, b: Span) {
span_err!(a, b, E0498, "malformed plugin attribute");
}
pub fn load_plugins(sess: &Session,
cstore: &CStore,
krate: &ast::Crate,
crate_name: &str,
addl_plugins: Option<Vec<String>>) -> Vec<PluginRegistrar> {
let mut loader = PluginLoader::new(sess, cstore, crate_name);
if sess.features.borrow().plugin {
for attr in &krate.attrs {
if !attr.check_name("plugin") {
continue;
}
let plugins = match attr.meta_item_list() {
Some(xs) => xs,
None => {
call_malformed_plugin_attribute(sess, attr.span);
continue;
}
};
for plugin in plugins {
match plugin.name() {
Some(name) if !plugin.is_value_str() => {
let args = plugin.meta_item_list().map(ToOwned::to_owned);
loader.load_plugin(plugin.span, &name.as_str(), args.unwrap_or_default());
},
_ => call_malformed_plugin_attribute(sess, attr.span),
}
}
}
}
if let Some(plugins) = addl_plugins {
for plugin in plugins {
loader.load_plugin(COMMAND_LINE_SP, &plugin, vec![]);
}
}
loader.plugins
}
impl<'a> PluginLoader<'a> {
fn new(sess: &'a Session, cstore: &'a CStore, crate_name: &str) -> Self {
PluginLoader {
sess: sess,
reader: CrateLoader::new(sess, cstore, crate_name),
plugins: vec![],
}
}
fn load_plugin(&mut self, span: Span, name: &str, args: Vec<ast::NestedMetaItem>) {
let registrar = self.reader.find_plugin_registrar(span, name);
if let Some((lib, svh, index)) = registrar {
let symbol = self.sess.generate_plugin_registrar_symbol(&svh, index);
let fun = self.dylink_registrar(span, lib, symbol);
self.plugins.push(PluginRegistrar {
fun: fun,
args: args,
});
}
}
fn dylink_registrar(&mut self,
span: Span,
path: PathBuf,
symbol: String) -> PluginRegistrarFun {
use rustc_back::dynamic_lib::DynamicLibrary;
let path = env::current_dir().unwrap().join(&path);
let lib = match DynamicLibrary::open(Some(&path)) {
Ok(lib) => lib,
Err(err) => {
self.sess.span_fatal(span, &err[..])
}
};
unsafe {
let registrar =
match lib.symbol(&symbol[..]) {
Ok(registrar) => {
mem::transmute::<*mut u8,PluginRegistrarFun>(registrar)
}
Err(err) => {
self.sess.span_fatal(span, &err[..])
}
};
mem::forget(lib);
registrar
}
}
}