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
use session::Session;
use metadata::creader::CrateReader;
use plugin::registry::Registry;
use std::mem;
use std::env;
use std::dynamic_lib::DynamicLibrary;
use std::borrow::ToOwned;
use syntax::ast;
use syntax::codemap::{Span, COMMAND_LINE_SP};
use syntax::ptr::P;
use syntax::attr::AttrMetaMethods;
pub type PluginRegistrarFun =
fn(&mut Registry);
pub struct PluginRegistrar {
pub fun: PluginRegistrarFun,
pub args: Vec<P<ast::MetaItem>>,
}
struct PluginLoader<'a> {
sess: &'a Session,
reader: CrateReader<'a>,
plugins: Vec<PluginRegistrar>,
}
pub fn load_plugins(sess: &Session, krate: &ast::Crate,
addl_plugins: Option<Vec<String>>) -> Vec<PluginRegistrar> {
let mut loader = PluginLoader::new(sess);
for attr in &krate.attrs {
if !attr.check_name("plugin") {
continue;
}
let plugins = match attr.meta_item_list() {
Some(xs) => xs,
None => {
sess.span_err(attr.span, "malformed plugin attribute");
continue;
}
};
for plugin in plugins {
if plugin.value_str().is_some() {
sess.span_err(attr.span, "malformed plugin attribute");
continue;
}
let args = plugin.meta_item_list().map(ToOwned::to_owned).unwrap_or_default();
loader.load_plugin(plugin.span, &*plugin.name(), args);
}
}
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) -> PluginLoader<'a> {
PluginLoader {
sess: sess,
reader: CrateReader::new(sess),
plugins: vec![],
}
}
fn load_plugin(&mut self, span: Span, name: &str, args: Vec<P<ast::MetaItem>>) {
let registrar = self.reader.find_plugin_registrar(span, name);
if let Some((lib, symbol)) = registrar {
let fun = self.dylink_registrar(span, lib, symbol);
self.plugins.push(PluginRegistrar {
fun: fun,
args: args,
});
}
}
fn dylink_registrar(&mut self,
span: Span,
path: Path,
symbol: String) -> PluginRegistrarFun {
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
}
}
}