]>
Commit | Line | Data |
---|---|---|
85aaf69f | 1 | // Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT |
223e47cc LB |
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 | ||
1a4d82fc | 11 | #![allow(non_camel_case_types)] |
223e47cc | 12 | |
1a4d82fc | 13 | //! Validates all used crates and extern libraries and loads their metadata |
223e47cc | 14 | |
1a4d82fc JJ |
15 | use back::svh::Svh; |
16 | use session::{config, Session}; | |
17 | use session::search_paths::PathKind; | |
223e47cc | 18 | use metadata::cstore; |
1a4d82fc | 19 | use metadata::cstore::{CStore, CrateSource, MetadataBlob}; |
223e47cc | 20 | use metadata::decoder; |
223e47cc | 21 | use metadata::loader; |
1a4d82fc | 22 | use metadata::loader::CratePaths; |
223e47cc | 23 | |
62682a34 | 24 | use std::cell::RefCell; |
d9579d0f | 25 | use std::path::PathBuf; |
1a4d82fc | 26 | use std::rc::Rc; |
d9579d0f AL |
27 | use std::fs; |
28 | ||
1a4d82fc JJ |
29 | use syntax::ast; |
30 | use syntax::abi; | |
223e47cc | 31 | use syntax::attr; |
1a4d82fc | 32 | use syntax::attr::AttrMetaMethods; |
c34b1796 | 33 | use syntax::codemap::{self, Span, mk_sp, Pos}; |
1a4d82fc JJ |
34 | use syntax::parse; |
35 | use syntax::parse::token::InternedString; | |
970d7e83 | 36 | use syntax::parse::token; |
223e47cc | 37 | use syntax::visit; |
1a4d82fc | 38 | use log; |
223e47cc | 39 | |
1a4d82fc JJ |
40 | pub struct CrateReader<'a> { |
41 | sess: &'a Session, | |
42 | next_crate_num: ast::CrateNum, | |
223e47cc LB |
43 | } |
44 | ||
1a4d82fc | 45 | impl<'a, 'v> visit::Visitor<'v> for CrateReader<'a> { |
1a4d82fc JJ |
46 | fn visit_item(&mut self, a: &ast::Item) { |
47 | self.process_item(a); | |
48 | visit::walk_item(self, a); | |
49 | } | |
223e47cc LB |
50 | } |
51 | ||
1a4d82fc | 52 | fn dump_crates(cstore: &CStore) { |
223e47cc | 53 | debug!("resolved crates:"); |
1a4d82fc JJ |
54 | cstore.iter_crate_data_origins(|_, data, opt_source| { |
55 | debug!(" name: {}", data.name()); | |
56 | debug!(" cnum: {}", data.cnum); | |
57 | debug!(" hash: {}", data.hash()); | |
58 | opt_source.map(|cs| { | |
59 | let CrateSource { dylib, rlib, cnum: _ } = cs; | |
85aaf69f SL |
60 | dylib.map(|dl| debug!(" dylib: {}", dl.0.display())); |
61 | rlib.map(|rl| debug!(" rlib: {}", rl.0.display())); | |
1a4d82fc JJ |
62 | }); |
63 | }) | |
223e47cc LB |
64 | } |
65 | ||
85aaf69f | 66 | fn should_link(i: &ast::Item) -> bool { |
c34b1796 | 67 | !attr::contains_name(&i.attrs, "no_link") |
1a4d82fc JJ |
68 | } |
69 | ||
70 | struct CrateInfo { | |
71 | ident: String, | |
72 | name: String, | |
73 | id: ast::NodeId, | |
74 | should_link: bool, | |
75 | } | |
223e47cc | 76 | |
1a4d82fc | 77 | pub fn validate_crate_name(sess: Option<&Session>, s: &str, sp: Option<Span>) { |
c34b1796 | 78 | let say = |s: &str| { |
1a4d82fc JJ |
79 | match (sp, sess) { |
80 | (_, None) => panic!("{}", s), | |
81 | (Some(sp), Some(sess)) => sess.span_err(sp, s), | |
82 | (None, Some(sess)) => sess.err(s), | |
83 | } | |
84 | }; | |
9346a6ac | 85 | if s.is_empty() { |
c34b1796 | 86 | say("crate name must not be empty"); |
1a4d82fc JJ |
87 | } |
88 | for c in s.chars() { | |
89 | if c.is_alphanumeric() { continue } | |
c34b1796 AL |
90 | if c == '_' { continue } |
91 | say(&format!("invalid character `{}` in crate name: `{}`", c, s)); | |
1a4d82fc JJ |
92 | } |
93 | match sess { | |
94 | Some(sess) => sess.abort_if_errors(), | |
95 | None => {} | |
96 | } | |
97 | } | |
98 | ||
99 | ||
100 | fn register_native_lib(sess: &Session, | |
101 | span: Option<Span>, | |
102 | name: String, | |
103 | kind: cstore::NativeLibraryKind) { | |
104 | if name.is_empty() { | |
105 | match span { | |
106 | Some(span) => { | |
107 | sess.span_err(span, "#[link(name = \"\")] given with \ | |
108 | empty name"); | |
970d7e83 | 109 | } |
1a4d82fc JJ |
110 | None => { |
111 | sess.err("empty library name given via `-l`"); | |
223e47cc LB |
112 | } |
113 | } | |
1a4d82fc | 114 | return |
223e47cc | 115 | } |
1a4d82fc JJ |
116 | let is_osx = sess.target.target.options.is_like_osx; |
117 | if kind == cstore::NativeFramework && !is_osx { | |
118 | let msg = "native frameworks are only available on OSX targets"; | |
119 | match span { | |
120 | Some(span) => sess.span_err(span, msg), | |
121 | None => sess.err(msg), | |
122 | } | |
123 | } | |
124 | sess.cstore.add_used_library(name, kind); | |
223e47cc LB |
125 | } |
126 | ||
85aaf69f SL |
127 | // Extra info about a crate loaded for plugins or exported macros. |
128 | struct ExtensionCrate { | |
1a4d82fc | 129 | metadata: PMDSource, |
c34b1796 | 130 | dylib: Option<PathBuf>, |
1a4d82fc | 131 | target_only: bool, |
223e47cc LB |
132 | } |
133 | ||
1a4d82fc JJ |
134 | enum PMDSource { |
135 | Registered(Rc<cstore::crate_metadata>), | |
136 | Owned(MetadataBlob), | |
137 | } | |
223e47cc | 138 | |
1a4d82fc JJ |
139 | impl PMDSource { |
140 | pub fn as_slice<'a>(&'a self) -> &'a [u8] { | |
141 | match *self { | |
142 | PMDSource::Registered(ref cmd) => cmd.data(), | |
143 | PMDSource::Owned(ref mdb) => mdb.as_slice(), | |
223e47cc LB |
144 | } |
145 | } | |
146 | } | |
147 | ||
1a4d82fc JJ |
148 | impl<'a> CrateReader<'a> { |
149 | pub fn new(sess: &'a Session) -> CrateReader<'a> { | |
150 | CrateReader { | |
151 | sess: sess, | |
152 | next_crate_num: sess.cstore.next_crate_num(), | |
153 | } | |
223e47cc | 154 | } |
223e47cc | 155 | |
c34b1796 AL |
156 | // Traverses an AST, reading all the information about use'd crates and |
157 | // extern libraries necessary for later resolving, typechecking, linking, | |
158 | // etc. | |
1a4d82fc JJ |
159 | pub fn read_crates(&mut self, krate: &ast::Crate) { |
160 | self.process_crate(krate); | |
161 | visit::walk_crate(self, krate); | |
162 | ||
163 | if log_enabled!(log::DEBUG) { | |
164 | dump_crates(&self.sess.cstore); | |
223e47cc LB |
165 | } |
166 | ||
85aaf69f | 167 | for &(ref name, kind) in &self.sess.opts.libs { |
1a4d82fc | 168 | register_native_lib(self.sess, None, name.clone(), kind); |
223e47cc | 169 | } |
1a4d82fc | 170 | } |
223e47cc | 171 | |
1a4d82fc JJ |
172 | fn process_crate(&self, c: &ast::Crate) { |
173 | for a in c.attrs.iter().filter(|m| m.name() == "link_args") { | |
174 | match a.value_str() { | |
85aaf69f | 175 | Some(ref linkarg) => self.sess.cstore.add_used_link_args(&linkarg), |
223e47cc LB |
176 | None => { /* fallthrough */ } |
177 | } | |
178 | } | |
223e47cc | 179 | } |
223e47cc | 180 | |
85aaf69f | 181 | fn extract_crate_info(&self, i: &ast::Item) -> Option<CrateInfo> { |
1a4d82fc | 182 | match i.node { |
85aaf69f SL |
183 | ast::ItemExternCrate(ref path_opt) => { |
184 | let ident = token::get_ident(i.ident); | |
1a4d82fc JJ |
185 | debug!("resolving extern crate stmt. ident: {} path_opt: {:?}", |
186 | ident, path_opt); | |
187 | let name = match *path_opt { | |
c34b1796 AL |
188 | Some(name) => { |
189 | validate_crate_name(Some(self.sess), name.as_str(), | |
1a4d82fc | 190 | Some(i.span)); |
c34b1796 | 191 | name.as_str().to_string() |
1a4d82fc | 192 | } |
85aaf69f | 193 | None => ident.to_string(), |
1a4d82fc JJ |
194 | }; |
195 | Some(CrateInfo { | |
85aaf69f | 196 | ident: ident.to_string(), |
1a4d82fc | 197 | name: name, |
85aaf69f | 198 | id: i.id, |
1a4d82fc JJ |
199 | should_link: should_link(i), |
200 | }) | |
201 | } | |
202 | _ => None | |
203 | } | |
204 | } | |
223e47cc | 205 | |
85aaf69f | 206 | fn process_item(&mut self, i: &ast::Item) { |
1a4d82fc | 207 | match i.node { |
85aaf69f SL |
208 | ast::ItemExternCrate(_) => { |
209 | if !should_link(i) { | |
210 | return; | |
211 | } | |
212 | ||
213 | match self.extract_crate_info(i) { | |
214 | Some(info) => { | |
215 | let (cnum, _, _) = self.resolve_crate(&None, | |
c34b1796 AL |
216 | &info.ident, |
217 | &info.name, | |
85aaf69f SL |
218 | None, |
219 | i.span, | |
220 | PathKind::Crate); | |
221 | self.sess.cstore.add_extern_mod_stmt_cnum(info.id, cnum); | |
222 | } | |
223 | None => () | |
224 | } | |
225 | } | |
1a4d82fc JJ |
226 | ast::ItemForeignMod(ref fm) => { |
227 | if fm.abi == abi::Rust || fm.abi == abi::RustIntrinsic { | |
228 | return; | |
229 | } | |
230 | ||
231 | // First, add all of the custom link_args attributes | |
232 | let link_args = i.attrs.iter() | |
233 | .filter_map(|at| if at.name() == "link_args" { | |
234 | Some(at) | |
235 | } else { | |
236 | None | |
237 | }) | |
238 | .collect::<Vec<&ast::Attribute>>(); | |
85aaf69f | 239 | for m in &link_args { |
1a4d82fc | 240 | match m.value_str() { |
85aaf69f | 241 | Some(linkarg) => self.sess.cstore.add_used_link_args(&linkarg), |
1a4d82fc JJ |
242 | None => { /* fallthrough */ } |
243 | } | |
244 | } | |
245 | ||
246 | // Next, process all of the #[link(..)]-style arguments | |
247 | let link_args = i.attrs.iter() | |
248 | .filter_map(|at| if at.name() == "link" { | |
249 | Some(at) | |
250 | } else { | |
251 | None | |
252 | }) | |
253 | .collect::<Vec<&ast::Attribute>>(); | |
85aaf69f | 254 | for m in &link_args { |
1a4d82fc JJ |
255 | match m.meta_item_list() { |
256 | Some(items) => { | |
257 | let kind = items.iter().find(|k| { | |
258 | k.name() == "kind" | |
259 | }).and_then(|a| a.value_str()); | |
260 | let kind = match kind { | |
261 | Some(k) => { | |
262 | if k == "static" { | |
263 | cstore::NativeStatic | |
264 | } else if self.sess.target.target.options.is_like_osx | |
265 | && k == "framework" { | |
266 | cstore::NativeFramework | |
267 | } else if k == "framework" { | |
268 | cstore::NativeFramework | |
269 | } else if k == "dylib" { | |
270 | cstore::NativeUnknown | |
271 | } else { | |
272 | self.sess.span_err(m.span, | |
273 | &format!("unknown kind: `{}`", | |
c34b1796 | 274 | k)); |
1a4d82fc JJ |
275 | cstore::NativeUnknown |
276 | } | |
277 | } | |
278 | None => cstore::NativeUnknown | |
279 | }; | |
280 | let n = items.iter().find(|n| { | |
281 | n.name() == "name" | |
282 | }).and_then(|a| a.value_str()); | |
283 | let n = match n { | |
284 | Some(n) => n, | |
285 | None => { | |
286 | self.sess.span_err(m.span, | |
287 | "#[link(...)] specified without \ | |
288 | `name = \"foo\"`"); | |
289 | InternedString::new("foo") | |
290 | } | |
291 | }; | |
292 | register_native_lib(self.sess, Some(m.span), | |
85aaf69f | 293 | n.to_string(), kind); |
1a4d82fc JJ |
294 | } |
295 | None => {} | |
296 | } | |
297 | } | |
298 | } | |
299 | _ => { } | |
223e47cc LB |
300 | } |
301 | } | |
223e47cc | 302 | |
85aaf69f SL |
303 | fn existing_match(&self, name: &str, hash: Option<&Svh>, kind: PathKind) |
304 | -> Option<ast::CrateNum> { | |
1a4d82fc JJ |
305 | let mut ret = None; |
306 | self.sess.cstore.iter_crate_data(|cnum, data| { | |
307 | if data.name != name { return } | |
223e47cc | 308 | |
1a4d82fc JJ |
309 | match hash { |
310 | Some(hash) if *hash == data.hash() => { ret = Some(cnum); return } | |
311 | Some(..) => return, | |
312 | None => {} | |
313 | } | |
223e47cc | 314 | |
85aaf69f SL |
315 | // When the hash is None we're dealing with a top-level dependency |
316 | // in which case we may have a specification on the command line for | |
317 | // this library. Even though an upstream library may have loaded | |
318 | // something of the same name, we have to make sure it was loaded | |
319 | // from the exact same location as well. | |
1a4d82fc JJ |
320 | // |
321 | // We're also sure to compare *paths*, not actual byte slices. The | |
322 | // `source` stores paths which are normalized which may be different | |
323 | // from the strings on the command line. | |
324 | let source = self.sess.cstore.get_used_crate_source(cnum).unwrap(); | |
85aaf69f SL |
325 | if let Some(locs) = self.sess.opts.externs.get(name) { |
326 | let found = locs.iter().any(|l| { | |
d9579d0f | 327 | let l = fs::canonicalize(l).ok(); |
85aaf69f SL |
328 | source.dylib.as_ref().map(|p| &p.0) == l.as_ref() || |
329 | source.rlib.as_ref().map(|p| &p.0) == l.as_ref() | |
330 | }); | |
331 | if found { | |
332 | ret = Some(cnum); | |
1a4d82fc | 333 | } |
85aaf69f SL |
334 | return |
335 | } | |
336 | ||
337 | // Alright, so we've gotten this far which means that `data` has the | |
338 | // right name, we don't have a hash, and we don't have a --extern | |
339 | // pointing for ourselves. We're still not quite yet done because we | |
340 | // have to make sure that this crate was found in the crate lookup | |
341 | // path (this is a top-level dependency) as we don't want to | |
342 | // implicitly load anything inside the dependency lookup path. | |
343 | let prev_kind = source.dylib.as_ref().or(source.rlib.as_ref()) | |
344 | .unwrap().1; | |
345 | if ret.is_none() && (prev_kind == kind || prev_kind == PathKind::All) { | |
346 | ret = Some(cnum); | |
1a4d82fc JJ |
347 | } |
348 | }); | |
349 | return ret; | |
350 | } | |
223e47cc | 351 | |
1a4d82fc JJ |
352 | fn register_crate(&mut self, |
353 | root: &Option<CratePaths>, | |
354 | ident: &str, | |
355 | name: &str, | |
356 | span: Span, | |
357 | lib: loader::Library) | |
358 | -> (ast::CrateNum, Rc<cstore::crate_metadata>, | |
359 | cstore::CrateSource) { | |
223e47cc | 360 | // Claim this crate number and cache it |
1a4d82fc JJ |
361 | let cnum = self.next_crate_num; |
362 | self.next_crate_num += 1; | |
363 | ||
364 | // Stash paths for top-most crate locally if necessary. | |
365 | let crate_paths = if root.is_none() { | |
366 | Some(CratePaths { | |
367 | ident: ident.to_string(), | |
85aaf69f SL |
368 | dylib: lib.dylib.clone().map(|p| p.0), |
369 | rlib: lib.rlib.clone().map(|p| p.0), | |
1a4d82fc JJ |
370 | }) |
371 | } else { | |
372 | None | |
373 | }; | |
374 | // Maintain a reference to the top most crate. | |
375 | let root = if root.is_some() { root } else { &crate_paths }; | |
376 | ||
c34b1796 | 377 | let loader::Library { dylib, rlib, metadata } = lib; |
1a4d82fc | 378 | |
c34b1796 | 379 | let cnum_map = self.resolve_crate_deps(root, metadata.as_slice(), span); |
1a4d82fc JJ |
380 | |
381 | let cmeta = Rc::new( cstore::crate_metadata { | |
382 | name: name.to_string(), | |
383 | data: metadata, | |
384 | cnum_map: cnum_map, | |
223e47cc | 385 | cnum: cnum, |
62682a34 | 386 | codemap_import_info: RefCell::new(vec![]), |
223e47cc | 387 | span: span, |
223e47cc | 388 | }); |
1a4d82fc JJ |
389 | |
390 | let source = cstore::CrateSource { | |
391 | dylib: dylib, | |
392 | rlib: rlib, | |
393 | cnum: cnum, | |
394 | }; | |
395 | ||
396 | self.sess.cstore.set_crate_data(cnum, cmeta.clone()); | |
397 | self.sess.cstore.add_used_crate_source(source.clone()); | |
398 | (cnum, cmeta, source) | |
399 | } | |
400 | ||
401 | fn resolve_crate(&mut self, | |
402 | root: &Option<CratePaths>, | |
403 | ident: &str, | |
404 | name: &str, | |
405 | hash: Option<&Svh>, | |
406 | span: Span, | |
407 | kind: PathKind) | |
408 | -> (ast::CrateNum, Rc<cstore::crate_metadata>, | |
409 | cstore::CrateSource) { | |
85aaf69f | 410 | match self.existing_match(name, hash, kind) { |
1a4d82fc JJ |
411 | None => { |
412 | let mut load_ctxt = loader::Context { | |
413 | sess: self.sess, | |
414 | span: span, | |
415 | ident: ident, | |
416 | crate_name: name, | |
417 | hash: hash.map(|a| &*a), | |
418 | filesearch: self.sess.target_filesearch(kind), | |
85aaf69f | 419 | target: &self.sess.target.target, |
c34b1796 | 420 | triple: &self.sess.opts.target_triple, |
1a4d82fc JJ |
421 | root: root, |
422 | rejected_via_hash: vec!(), | |
423 | rejected_via_triple: vec!(), | |
85aaf69f | 424 | rejected_via_kind: vec!(), |
1a4d82fc JJ |
425 | should_match_name: true, |
426 | }; | |
427 | let library = load_ctxt.load_library_crate(); | |
428 | self.register_crate(root, ident, name, span, library) | |
429 | } | |
430 | Some(cnum) => (cnum, | |
431 | self.sess.cstore.get_crate_data(cnum), | |
432 | self.sess.cstore.get_used_crate_source(cnum).unwrap()) | |
433 | } | |
434 | } | |
435 | ||
436 | // Go through the crate metadata and load any crates that it references | |
437 | fn resolve_crate_deps(&mut self, | |
438 | root: &Option<CratePaths>, | |
439 | cdata: &[u8], span : Span) | |
440 | -> cstore::cnum_map { | |
441 | debug!("resolving deps of external crate"); | |
442 | // The map from crate numbers in the crate we're resolving to local crate | |
443 | // numbers | |
444 | decoder::get_crate_deps(cdata).iter().map(|dep| { | |
445 | debug!("resolving dep crate {} hash: `{}`", dep.name, dep.hash); | |
446 | let (local_cnum, _, _) = self.resolve_crate(root, | |
c34b1796 AL |
447 | &dep.name, |
448 | &dep.name, | |
1a4d82fc JJ |
449 | Some(&dep.hash), |
450 | span, | |
451 | PathKind::Dependency); | |
452 | (dep.cnum, local_cnum) | |
453 | }).collect() | |
454 | } | |
455 | ||
85aaf69f | 456 | fn read_extension_crate(&mut self, span: Span, info: &CrateInfo) -> ExtensionCrate { |
c34b1796 | 457 | let target_triple = &self.sess.opts.target_triple[..]; |
1a4d82fc JJ |
458 | let is_cross = target_triple != config::host_triple(); |
459 | let mut should_link = info.should_link && !is_cross; | |
460 | let mut target_only = false; | |
461 | let ident = info.ident.clone(); | |
462 | let name = info.name.clone(); | |
463 | let mut load_ctxt = loader::Context { | |
464 | sess: self.sess, | |
465 | span: span, | |
85aaf69f SL |
466 | ident: &ident[..], |
467 | crate_name: &name[..], | |
1a4d82fc JJ |
468 | hash: None, |
469 | filesearch: self.sess.host_filesearch(PathKind::Crate), | |
85aaf69f | 470 | target: &self.sess.host, |
1a4d82fc JJ |
471 | triple: config::host_triple(), |
472 | root: &None, | |
473 | rejected_via_hash: vec!(), | |
474 | rejected_via_triple: vec!(), | |
85aaf69f | 475 | rejected_via_kind: vec!(), |
1a4d82fc JJ |
476 | should_match_name: true, |
477 | }; | |
478 | let library = match load_ctxt.maybe_load_library_crate() { | |
479 | Some(l) => l, | |
480 | None if is_cross => { | |
85aaf69f SL |
481 | // Try loading from target crates. This will abort later if we |
482 | // try to load a plugin registrar function, | |
1a4d82fc JJ |
483 | target_only = true; |
484 | should_link = info.should_link; | |
485 | ||
85aaf69f | 486 | load_ctxt.target = &self.sess.target.target; |
1a4d82fc JJ |
487 | load_ctxt.triple = target_triple; |
488 | load_ctxt.filesearch = self.sess.target_filesearch(PathKind::Crate); | |
489 | load_ctxt.load_library_crate() | |
490 | } | |
491 | None => { load_ctxt.report_load_errs(); unreachable!() }, | |
223e47cc LB |
492 | }; |
493 | ||
1a4d82fc | 494 | let dylib = library.dylib.clone(); |
c34b1796 | 495 | let register = should_link && self.existing_match(&info.name, |
85aaf69f SL |
496 | None, |
497 | PathKind::Crate).is_none(); | |
1a4d82fc JJ |
498 | let metadata = if register { |
499 | // Register crate now to avoid double-reading metadata | |
c34b1796 AL |
500 | let (_, cmd, _) = self.register_crate(&None, &info.ident, |
501 | &info.name, span, library); | |
1a4d82fc JJ |
502 | PMDSource::Registered(cmd) |
503 | } else { | |
504 | // Not registering the crate; just hold on to the metadata | |
505 | PMDSource::Owned(library.metadata) | |
506 | }; | |
507 | ||
85aaf69f | 508 | ExtensionCrate { |
1a4d82fc | 509 | metadata: metadata, |
85aaf69f | 510 | dylib: dylib.map(|p| p.0), |
1a4d82fc JJ |
511 | target_only: target_only, |
512 | } | |
223e47cc | 513 | } |
223e47cc | 514 | |
85aaf69f SL |
515 | /// Read exported macros. |
516 | pub fn read_exported_macros(&mut self, krate: &ast::Item) -> Vec<ast::MacroDef> { | |
517 | let ci = self.extract_crate_info(krate).unwrap(); | |
518 | let ekrate = self.read_extension_crate(krate.span, &ci); | |
1a4d82fc | 519 | |
85aaf69f | 520 | let source_name = format!("<{} macros>", krate.ident); |
1a4d82fc | 521 | let mut macros = vec![]; |
85aaf69f | 522 | decoder::each_exported_macro(ekrate.metadata.as_slice(), |
1a4d82fc JJ |
523 | &*self.sess.cstore.intr, |
524 | |name, attrs, body| { | |
525 | // NB: Don't use parse::parse_tts_from_source_str because it parses with | |
526 | // quote_depth > 0. | |
527 | let mut p = parse::new_parser_from_source_str(&self.sess.parse_sess, | |
528 | self.sess.opts.cfg.clone(), | |
529 | source_name.clone(), | |
530 | body); | |
531 | let lo = p.span.lo; | |
9346a6ac AL |
532 | let body = match p.parse_all_token_trees() { |
533 | Ok(body) => body, | |
534 | Err(err) => panic!(err), | |
535 | }; | |
1a4d82fc JJ |
536 | let span = mk_sp(lo, p.last_span.hi); |
537 | p.abort_if_errors(); | |
538 | macros.push(ast::MacroDef { | |
539 | ident: name.ident(), | |
540 | attrs: attrs, | |
541 | id: ast::DUMMY_NODE_ID, | |
542 | span: span, | |
85aaf69f | 543 | imported_from: Some(krate.ident), |
1a4d82fc JJ |
544 | // overridden in plugin/load.rs |
545 | export: false, | |
546 | use_locally: false, | |
c34b1796 | 547 | allow_internal_unstable: false, |
1a4d82fc JJ |
548 | |
549 | body: body, | |
550 | }); | |
551 | true | |
552 | } | |
553 | ); | |
554 | macros | |
555 | } | |
556 | ||
557 | /// Look for a plugin registrar. Returns library path and symbol name. | |
c34b1796 AL |
558 | pub fn find_plugin_registrar(&mut self, span: Span, name: &str) |
559 | -> Option<(PathBuf, String)> { | |
85aaf69f SL |
560 | let ekrate = self.read_extension_crate(span, &CrateInfo { |
561 | name: name.to_string(), | |
562 | ident: name.to_string(), | |
563 | id: ast::DUMMY_NODE_ID, | |
564 | should_link: false, | |
565 | }); | |
566 | ||
567 | if ekrate.target_only { | |
1a4d82fc | 568 | // Need to abort before syntax expansion. |
85aaf69f | 569 | let message = format!("plugin `{}` is not available for triple `{}` \ |
1a4d82fc | 570 | (only found {})", |
85aaf69f | 571 | name, |
1a4d82fc JJ |
572 | config::host_triple(), |
573 | self.sess.opts.target_triple); | |
85aaf69f | 574 | self.sess.span_err(span, &message[..]); |
1a4d82fc JJ |
575 | self.sess.abort_if_errors(); |
576 | } | |
577 | ||
85aaf69f SL |
578 | let registrar = decoder::get_plugin_registrar_fn(ekrate.metadata.as_slice()) |
579 | .map(|id| decoder::get_symbol(ekrate.metadata.as_slice(), id)); | |
1a4d82fc | 580 | |
85aaf69f | 581 | match (ekrate.dylib.as_ref(), registrar) { |
c34b1796 | 582 | (Some(dylib), Some(reg)) => Some((dylib.to_path_buf(), reg)), |
1a4d82fc | 583 | (None, Some(_)) => { |
85aaf69f | 584 | let message = format!("plugin `{}` only found in rlib format, \ |
1a4d82fc | 585 | but must be available in dylib format", |
85aaf69f SL |
586 | name); |
587 | self.sess.span_err(span, &message[..]); | |
1a4d82fc JJ |
588 | // No need to abort because the loading code will just ignore this |
589 | // empty dylib. | |
590 | None | |
591 | } | |
592 | _ => None, | |
223e47cc LB |
593 | } |
594 | } | |
223e47cc | 595 | } |
c34b1796 AL |
596 | |
597 | /// Imports the codemap from an external crate into the codemap of the crate | |
598 | /// currently being compiled (the "local crate"). | |
599 | /// | |
600 | /// The import algorithm works analogous to how AST items are inlined from an | |
601 | /// external crate's metadata: | |
602 | /// For every FileMap in the external codemap an 'inline' copy is created in the | |
603 | /// local codemap. The correspondence relation between external and local | |
604 | /// FileMaps is recorded in the `ImportedFileMap` objects returned from this | |
605 | /// function. When an item from an external crate is later inlined into this | |
606 | /// crate, this correspondence information is used to translate the span | |
607 | /// information of the inlined item so that it refers the correct positions in | |
608 | /// the local codemap (see `astencode::DecodeContext::tr_span()`). | |
609 | /// | |
610 | /// The import algorithm in the function below will reuse FileMaps already | |
611 | /// existing in the local codemap. For example, even if the FileMap of some | |
612 | /// source file of libstd gets imported many times, there will only ever be | |
613 | /// one FileMap object for the corresponding file in the local codemap. | |
614 | /// | |
615 | /// Note that imported FileMaps do not actually contain the source code of the | |
616 | /// file they represent, just information about length, line breaks, and | |
617 | /// multibyte characters. This information is enough to generate valid debuginfo | |
618 | /// for items inlined from other crates. | |
62682a34 SL |
619 | pub fn import_codemap(local_codemap: &codemap::CodeMap, |
620 | metadata: &MetadataBlob) | |
621 | -> Vec<cstore::ImportedFileMap> { | |
c34b1796 AL |
622 | let external_codemap = decoder::get_imported_filemaps(metadata.as_slice()); |
623 | ||
624 | let imported_filemaps = external_codemap.into_iter().map(|filemap_to_import| { | |
625 | // Try to find an existing FileMap that can be reused for the filemap to | |
626 | // be imported. A FileMap is reusable if it is exactly the same, just | |
627 | // positioned at a different offset within the codemap. | |
628 | let reusable_filemap = { | |
629 | local_codemap.files | |
630 | .borrow() | |
631 | .iter() | |
632 | .find(|fm| are_equal_modulo_startpos(&fm, &filemap_to_import)) | |
633 | .map(|rc| rc.clone()) | |
634 | }; | |
635 | ||
636 | match reusable_filemap { | |
637 | Some(fm) => { | |
638 | cstore::ImportedFileMap { | |
639 | original_start_pos: filemap_to_import.start_pos, | |
640 | original_end_pos: filemap_to_import.end_pos, | |
641 | translated_filemap: fm | |
642 | } | |
643 | } | |
644 | None => { | |
645 | // We can't reuse an existing FileMap, so allocate a new one | |
646 | // containing the information we need. | |
647 | let codemap::FileMap { | |
648 | name, | |
649 | start_pos, | |
650 | end_pos, | |
651 | lines, | |
652 | multibyte_chars, | |
653 | .. | |
654 | } = filemap_to_import; | |
655 | ||
656 | let source_length = (end_pos - start_pos).to_usize(); | |
657 | ||
658 | // Translate line-start positions and multibyte character | |
659 | // position into frame of reference local to file. | |
660 | // `CodeMap::new_imported_filemap()` will then translate those | |
661 | // coordinates to their new global frame of reference when the | |
662 | // offset of the FileMap is known. | |
663 | let lines = lines.into_inner().map_in_place(|pos| pos - start_pos); | |
664 | let multibyte_chars = multibyte_chars | |
665 | .into_inner() | |
666 | .map_in_place(|mbc| | |
667 | codemap::MultiByteChar { | |
bd371182 | 668 | pos: mbc.pos - start_pos, |
c34b1796 AL |
669 | bytes: mbc.bytes |
670 | }); | |
671 | ||
672 | let local_version = local_codemap.new_imported_filemap(name, | |
673 | source_length, | |
674 | lines, | |
675 | multibyte_chars); | |
676 | cstore::ImportedFileMap { | |
677 | original_start_pos: start_pos, | |
678 | original_end_pos: end_pos, | |
679 | translated_filemap: local_version | |
680 | } | |
681 | } | |
682 | } | |
683 | }).collect(); | |
684 | ||
685 | return imported_filemaps; | |
686 | ||
687 | fn are_equal_modulo_startpos(fm1: &codemap::FileMap, | |
688 | fm2: &codemap::FileMap) | |
689 | -> bool { | |
690 | if fm1.name != fm2.name { | |
691 | return false; | |
692 | } | |
693 | ||
694 | let lines1 = fm1.lines.borrow(); | |
695 | let lines2 = fm2.lines.borrow(); | |
696 | ||
697 | if lines1.len() != lines2.len() { | |
698 | return false; | |
699 | } | |
700 | ||
701 | for (&line1, &line2) in lines1.iter().zip(lines2.iter()) { | |
702 | if (line1 - fm1.start_pos) != (line2 - fm2.start_pos) { | |
703 | return false; | |
704 | } | |
705 | } | |
706 | ||
707 | let multibytes1 = fm1.multibyte_chars.borrow(); | |
708 | let multibytes2 = fm2.multibyte_chars.borrow(); | |
709 | ||
710 | if multibytes1.len() != multibytes2.len() { | |
711 | return false; | |
712 | } | |
713 | ||
714 | for (mb1, mb2) in multibytes1.iter().zip(multibytes2.iter()) { | |
715 | if (mb1.bytes != mb2.bytes) || | |
716 | ((mb1.pos - fm1.start_pos) != (mb2.pos - fm2.start_pos)) { | |
717 | return false; | |
718 | } | |
719 | } | |
720 | ||
721 | true | |
722 | } | |
723 | } |