]>
Commit | Line | Data |
---|---|---|
1a4d82fc JJ |
1 | // Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT |
2 | // file at the top-level directory of this distribution and at | |
3 | // http://rust-lang.org/COPYRIGHT. | |
4 | // | |
5 | // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or | |
6 | // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license | |
7 | // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your | |
8 | // option. This file may not be copied, modified, or distributed | |
9 | // except according to those terms. | |
10 | ||
85aaf69f | 11 | //! Used by `rustc` when loading a plugin. |
1a4d82fc | 12 | |
92a42be0 | 13 | use rustc::session::Session; |
c30ab7b3 | 14 | use rustc_metadata::creader::CrateLoader; |
92a42be0 SL |
15 | use rustc_metadata::cstore::CStore; |
16 | use registry::Registry; | |
1a4d82fc | 17 | |
85aaf69f | 18 | use std::borrow::ToOwned; |
c34b1796 AL |
19 | use std::env; |
20 | use std::mem; | |
21 | use std::path::PathBuf; | |
1a4d82fc | 22 | use syntax::ast; |
cc61c64b | 23 | use syntax_pos::{Span, DUMMY_SP}; |
1a4d82fc JJ |
24 | |
25 | /// Pointer to a registrar function. | |
26 | pub type PluginRegistrarFun = | |
27 | fn(&mut Registry); | |
28 | ||
29 | pub struct PluginRegistrar { | |
30 | pub fun: PluginRegistrarFun, | |
9e0c209e | 31 | pub args: Vec<ast::NestedMetaItem>, |
1a4d82fc JJ |
32 | } |
33 | ||
85aaf69f | 34 | struct PluginLoader<'a> { |
1a4d82fc | 35 | sess: &'a Session, |
c30ab7b3 | 36 | reader: CrateLoader<'a>, |
85aaf69f | 37 | plugins: Vec<PluginRegistrar>, |
1a4d82fc JJ |
38 | } |
39 | ||
b039eaaf SL |
40 | fn call_malformed_plugin_attribute(a: &Session, b: Span) { |
41 | span_err!(a, b, E0498, "malformed plugin attribute"); | |
42 | } | |
43 | ||
1a4d82fc | 44 | /// Read plugin metadata and dynamically load registrar functions. |
54a0048b SL |
45 | pub fn load_plugins(sess: &Session, |
46 | cstore: &CStore, | |
47 | krate: &ast::Crate, | |
48 | crate_name: &str, | |
85aaf69f | 49 | addl_plugins: Option<Vec<String>>) -> Vec<PluginRegistrar> { |
c30ab7b3 | 50 | let mut loader = PluginLoader::new(sess, cstore, crate_name); |
1a4d82fc | 51 | |
a7813a04 XL |
52 | // do not report any error now. since crate attributes are |
53 | // not touched by expansion, every use of plugin without | |
54 | // the feature enabled will result in an error later... | |
55 | if sess.features.borrow().plugin { | |
56 | for attr in &krate.attrs { | |
57 | if !attr.check_name("plugin") { | |
85aaf69f | 58 | continue; |
1a4d82fc | 59 | } |
85aaf69f | 60 | |
a7813a04 XL |
61 | let plugins = match attr.meta_item_list() { |
62 | Some(xs) => xs, | |
63 | None => { | |
64 | call_malformed_plugin_attribute(sess, attr.span); | |
65 | continue; | |
66 | } | |
67 | }; | |
68 | ||
69 | for plugin in plugins { | |
9e0c209e SL |
70 | // plugins must have a name and can't be key = value |
71 | match plugin.name() { | |
476ff2be | 72 | Some(name) if !plugin.is_value_str() => { |
9e0c209e | 73 | let args = plugin.meta_item_list().map(ToOwned::to_owned); |
476ff2be | 74 | loader.load_plugin(plugin.span, &name.as_str(), args.unwrap_or_default()); |
9e0c209e SL |
75 | }, |
76 | _ => call_malformed_plugin_attribute(sess, attr.span), | |
a7813a04 | 77 | } |
a7813a04 | 78 | } |
85aaf69f | 79 | } |
1a4d82fc JJ |
80 | } |
81 | ||
85aaf69f SL |
82 | if let Some(plugins) = addl_plugins { |
83 | for plugin in plugins { | |
cc61c64b | 84 | loader.load_plugin(DUMMY_SP, &plugin, vec![]); |
85aaf69f | 85 | } |
1a4d82fc | 86 | } |
85aaf69f SL |
87 | |
88 | loader.plugins | |
1a4d82fc JJ |
89 | } |
90 | ||
91 | impl<'a> PluginLoader<'a> { | |
c30ab7b3 | 92 | fn new(sess: &'a Session, cstore: &'a CStore, crate_name: &str) -> Self { |
85aaf69f | 93 | PluginLoader { |
3b2f2976 | 94 | sess, |
c30ab7b3 | 95 | reader: CrateLoader::new(sess, cstore, crate_name), |
85aaf69f | 96 | plugins: vec![], |
1a4d82fc | 97 | } |
85aaf69f | 98 | } |
1a4d82fc | 99 | |
9e0c209e | 100 | fn load_plugin(&mut self, span: Span, name: &str, args: Vec<ast::NestedMetaItem>) { |
85aaf69f | 101 | let registrar = self.reader.find_plugin_registrar(span, name); |
1a4d82fc | 102 | |
cc61c64b XL |
103 | if let Some((lib, disambiguator, index)) = registrar { |
104 | let symbol = self.sess.generate_plugin_registrar_symbol(disambiguator, index); | |
85aaf69f SL |
105 | let fun = self.dylink_registrar(span, lib, symbol); |
106 | self.plugins.push(PluginRegistrar { | |
3b2f2976 XL |
107 | fun, |
108 | args, | |
1a4d82fc JJ |
109 | }); |
110 | } | |
111 | } | |
112 | ||
113 | // Dynamically link a registrar function into the compiler process. | |
85aaf69f SL |
114 | fn dylink_registrar(&mut self, |
115 | span: Span, | |
c34b1796 | 116 | path: PathBuf, |
1a4d82fc | 117 | symbol: String) -> PluginRegistrarFun { |
54a0048b | 118 | use rustc_back::dynamic_lib::DynamicLibrary; |
b039eaaf | 119 | |
1a4d82fc | 120 | // Make sure the path contains a / or the linker will search for it. |
85aaf69f | 121 | let path = env::current_dir().unwrap().join(&path); |
1a4d82fc JJ |
122 | |
123 | let lib = match DynamicLibrary::open(Some(&path)) { | |
124 | Ok(lib) => lib, | |
125 | // this is fatal: there are almost certainly macros we need | |
126 | // inside this crate, so continue would spew "macro undefined" | |
127 | // errors | |
128 | Err(err) => { | |
cc61c64b | 129 | self.sess.span_fatal(span, &err) |
1a4d82fc JJ |
130 | } |
131 | }; | |
132 | ||
133 | unsafe { | |
134 | let registrar = | |
cc61c64b | 135 | match lib.symbol(&symbol) { |
1a4d82fc JJ |
136 | Ok(registrar) => { |
137 | mem::transmute::<*mut u8,PluginRegistrarFun>(registrar) | |
138 | } | |
139 | // again fatal if we can't register macros | |
140 | Err(err) => { | |
cc61c64b | 141 | self.sess.span_fatal(span, &err) |
1a4d82fc JJ |
142 | } |
143 | }; | |
144 | ||
145 | // Intentionally leak the dynamic library. We can't ever unload it | |
146 | // since the library can make things that will live arbitrarily long | |
bd371182 | 147 | // (e.g. an @-box cycle or a thread). |
1a4d82fc JJ |
148 | mem::forget(lib); |
149 | ||
150 | registrar | |
151 | } | |
152 | } | |
153 | } |