1 // Copyright 2012-2015 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.
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.
11 //! Validates all used crates and extern libraries and loads their metadata
13 use cstore
::{self, CStore, CrateSource, MetadataBlob}
;
14 use locator
::{self, CratePaths}
;
15 use schema
::CrateRoot
;
17 use rustc
::hir
::def_id
::{CrateNum, DefIndex}
;
18 use rustc
::hir
::svh
::Svh
;
19 use rustc
::middle
::cstore
::LoadedMacros
;
20 use rustc
::session
::{config, Session}
;
21 use rustc_back
::PanicStrategy
;
22 use rustc
::session
::search_paths
::PathKind
;
24 use rustc
::middle
::cstore
::{CrateStore, validate_crate_name, ExternCrate}
;
25 use rustc
::util
::nodemap
::{FnvHashMap, FnvHashSet}
;
26 use rustc
::hir
::map
::Definitions
;
28 use std
::cell
::{RefCell, Cell}
;
30 use std
::path
::PathBuf
;
38 use syntax
::ext
::base
::SyntaxExtension
;
39 use syntax
::parse
::token
::{InternedString, intern}
;
40 use syntax_pos
::{self, Span, mk_sp}
;
44 pub dylib
: Option
<(PathBuf
, PathKind
)>,
45 pub rlib
: Option
<(PathBuf
, PathKind
)>,
46 pub metadata
: MetadataBlob
,
49 pub struct CrateLoader
<'a
> {
50 pub sess
: &'a Session
,
52 next_crate_num
: CrateNum
,
53 foreign_item_map
: FnvHashMap
<String
, Vec
<ast
::NodeId
>>,
54 local_crate_name
: String
,
57 fn dump_crates(cstore
: &CStore
) {
58 info
!("resolved crates:");
59 cstore
.iter_crate_data_origins(|_
, data
, opt_source
| {
60 info
!(" name: {}", data
.name());
61 info
!(" cnum: {}", data
.cnum
);
62 info
!(" hash: {}", data
.hash());
63 info
!(" reqd: {}", data
.explicitly_linked
.get());
65 let CrateSource { dylib, rlib, cnum: _ }
= cs
;
66 dylib
.map(|dl
| info
!(" dylib: {}", dl
.0.display()));
67 rlib
.map(|rl
| info
!(" rlib: {}", rl
.0.display()));
72 fn should_link(i
: &ast
::Item
) -> bool
{
73 !attr
::contains_name(&i
.attrs
, "no_link")
77 struct ExternCrateInfo
{
84 fn register_native_lib(sess
: &Session
,
88 kind
: cstore
::NativeLibraryKind
) {
92 struct_span_err
!(sess
, span
, E0454
,
93 "#[link(name = \"\")] given with empty name")
94 .span_label(span
, &format
!("empty name given"))
98 sess
.err("empty library name given via `-l`");
103 let is_osx
= sess
.target
.target
.options
.is_like_osx
;
104 if kind
== cstore
::NativeFramework
&& !is_osx
{
105 let msg
= "native frameworks are only available on OSX targets";
108 span_err
!(sess
, span
, E0455
,
111 None
=> sess
.err(msg
),
114 cstore
.add_used_library(name
, kind
);
117 // Extra info about a crate loaded for plugins or exported macros.
118 struct ExtensionCrate
{
120 dylib
: Option
<PathBuf
>,
125 Registered(Rc
<cstore
::CrateMetadata
>),
129 impl Deref
for PMDSource
{
130 type Target
= MetadataBlob
;
132 fn deref(&self) -> &MetadataBlob
{
134 PMDSource
::Registered(ref cmd
) => &cmd
.blob
,
135 PMDSource
::Owned(ref lib
) => &lib
.metadata
145 impl<'a
> CrateLoader
<'a
> {
146 pub fn new(sess
: &'a Session
, cstore
: &'a CStore
, local_crate_name
: &str) -> Self {
150 next_crate_num
: cstore
.next_crate_num(),
151 foreign_item_map
: FnvHashMap(),
152 local_crate_name
: local_crate_name
.to_owned(),
156 fn extract_crate_info(&self, i
: &ast
::Item
) -> Option
<ExternCrateInfo
> {
158 ast
::ItemKind
::ExternCrate(ref path_opt
) => {
159 debug
!("resolving extern crate stmt. ident: {} path_opt: {:?}",
161 let name
= match *path_opt
{
163 validate_crate_name(Some(self.sess
), &name
.as_str(),
167 None
=> i
.ident
.to_string(),
169 Some(ExternCrateInfo
{
170 ident
: i
.ident
.to_string(),
173 should_link
: should_link(i
),
180 fn existing_match(&self, name
: &str, hash
: Option
<&Svh
>, kind
: PathKind
)
181 -> Option
<CrateNum
> {
183 self.cstore
.iter_crate_data(|cnum
, data
| {
184 if data
.name
!= name { return }
187 Some(hash
) if *hash
== data
.hash() => { ret = Some(cnum); return }
192 // When the hash is None we're dealing with a top-level dependency
193 // in which case we may have a specification on the command line for
194 // this library. Even though an upstream library may have loaded
195 // something of the same name, we have to make sure it was loaded
196 // from the exact same location as well.
198 // We're also sure to compare *paths*, not actual byte slices. The
199 // `source` stores paths which are normalized which may be different
200 // from the strings on the command line.
201 let source
= self.cstore
.used_crate_source(cnum
);
202 if let Some(locs
) = self.sess
.opts
.externs
.get(name
) {
203 let found
= locs
.iter().any(|l
| {
204 let l
= fs
::canonicalize(l
).ok();
205 source
.dylib
.as_ref().map(|p
| &p
.0) == l
.as_ref() ||
206 source
.rlib
.as_ref().map(|p
| &p
.0) == l
.as_ref()
214 // Alright, so we've gotten this far which means that `data` has the
215 // right name, we don't have a hash, and we don't have a --extern
216 // pointing for ourselves. We're still not quite yet done because we
217 // have to make sure that this crate was found in the crate lookup
218 // path (this is a top-level dependency) as we don't want to
219 // implicitly load anything inside the dependency lookup path.
220 let prev_kind
= source
.dylib
.as_ref().or(source
.rlib
.as_ref())
222 if ret
.is_none() && (prev_kind
== kind
|| prev_kind
== PathKind
::All
) {
229 fn verify_no_symbol_conflicts(&self,
232 // Check for (potential) conflicts with the local crate
233 if self.local_crate_name
== root
.name
&&
234 self.sess
.local_crate_disambiguator() == &root
.disambiguator
[..] {
235 span_fatal
!(self.sess
, span
, E0519
,
236 "the current crate is indistinguishable from one of its \
237 dependencies: it has the same crate-name `{}` and was \
238 compiled with the same `-C metadata` arguments. This \
239 will result in symbol conflicts between the two.",
243 // Check for conflicts with any crate loaded so far
244 self.cstore
.iter_crate_data(|_
, other
| {
245 if other
.name() == root
.name
&& // same crate-name
246 other
.disambiguator() == root
.disambiguator
&& // same crate-disambiguator
247 other
.hash() != root
.hash
{ // but different SVH
248 span_fatal
!(self.sess
, span
, E0523
,
249 "found two different crates with name `{}` that are \
250 not distinguished by differing `-C metadata`. This \
251 will result in symbol conflicts between the two.",
257 fn register_crate(&mut self,
258 root
: &Option
<CratePaths
>,
263 explicitly_linked
: bool
)
264 -> (CrateNum
, Rc
<cstore
::CrateMetadata
>,
265 cstore
::CrateSource
) {
266 info
!("register crate `extern crate {} as {}`", name
, ident
);
267 let crate_root
= lib
.metadata
.get_root();
268 self.verify_no_symbol_conflicts(span
, &crate_root
);
270 // Claim this crate number and cache it
271 let cnum
= self.next_crate_num
;
272 self.next_crate_num
= CrateNum
::from_u32(cnum
.as_u32() + 1);
274 // Stash paths for top-most crate locally if necessary.
275 let crate_paths
= if root
.is_none() {
277 ident
: ident
.to_string(),
278 dylib
: lib
.dylib
.clone().map(|p
| p
.0),
279 rlib
: lib
.rlib
.clone().map(|p
| p
.0),
284 // Maintain a reference to the top most crate.
285 let root
= if root
.is_some() { root }
else { &crate_paths }
;
287 let Library { dylib, rlib, metadata }
= lib
;
289 let cnum_map
= self.resolve_crate_deps(root
, &crate_root
, &metadata
, cnum
, span
);
291 if crate_root
.macro_derive_registrar
.is_some() {
292 self.sess
.span_err(span
, "crates of the `proc-macro` crate type \
293 cannot be linked at runtime");
296 let cmeta
= Rc
::new(cstore
::CrateMetadata
{
297 name
: name
.to_string(),
298 extern_crate
: Cell
::new(None
),
299 key_map
: metadata
.load_key_map(crate_root
.index
),
302 cnum_map
: RefCell
::new(cnum_map
),
304 codemap_import_info
: RefCell
::new(vec
![]),
305 explicitly_linked
: Cell
::new(explicitly_linked
),
308 let source
= cstore
::CrateSource
{
314 self.cstore
.set_crate_data(cnum
, cmeta
.clone());
315 self.cstore
.add_used_crate_source(source
.clone());
316 (cnum
, cmeta
, source
)
319 fn resolve_crate(&mut self,
320 root
: &Option
<CratePaths
>,
326 explicitly_linked
: bool
)
327 -> (CrateNum
, Rc
<cstore
::CrateMetadata
>, cstore
::CrateSource
) {
328 info
!("resolving crate `extern crate {} as {}`", name
, ident
);
329 let result
= match self.existing_match(name
, hash
, kind
) {
330 Some(cnum
) => LoadResult
::Previous(cnum
),
332 info
!("falling back to a load");
333 let mut locate_ctxt
= locator
::Context
{
338 hash
: hash
.map(|a
| &*a
),
339 filesearch
: self.sess
.target_filesearch(kind
),
340 target
: &self.sess
.target
.target
,
341 triple
: &self.sess
.opts
.target_triple
,
343 rejected_via_hash
: vec
![],
344 rejected_via_triple
: vec
![],
345 rejected_via_kind
: vec
![],
346 rejected_via_version
: vec
![],
347 should_match_name
: true,
349 match self.load(&mut locate_ctxt
) {
350 Some(result
) => result
,
351 None
=> locate_ctxt
.report_errs(),
357 LoadResult
::Previous(cnum
) => {
358 let data
= self.cstore
.get_crate_data(cnum
);
359 if explicitly_linked
&& !data
.explicitly_linked
.get() {
360 data
.explicitly_linked
.set(explicitly_linked
);
362 (cnum
, data
, self.cstore
.used_crate_source(cnum
))
364 LoadResult
::Loaded(library
) => {
365 self.register_crate(root
, ident
, name
, span
, library
,
371 fn load(&mut self, locate_ctxt
: &mut locator
::Context
) -> Option
<LoadResult
> {
372 let library
= match locate_ctxt
.maybe_load_library_crate() {
377 // In the case that we're loading a crate, but not matching
378 // against a hash, we could load a crate which has the same hash
379 // as an already loaded crate. If this is the case prevent
380 // duplicates by just using the first crate.
382 // Note that we only do this for target triple crates, though, as we
383 // don't want to match a host crate against an equivalent target one
385 let root
= library
.metadata
.get_root();
386 if locate_ctxt
.triple
== self.sess
.opts
.target_triple
{
387 let mut result
= LoadResult
::Loaded(library
);
388 self.cstore
.iter_crate_data(|cnum
, data
| {
389 if data
.name() == root
.name
&& root
.hash
== data
.hash() {
390 assert
!(locate_ctxt
.hash
.is_none());
391 info
!("load success, going to previous cnum: {}", cnum
);
392 result
= LoadResult
::Previous(cnum
);
397 Some(LoadResult
::Loaded(library
))
401 fn update_extern_crate(&mut self,
403 mut extern_crate
: ExternCrate
,
404 visited
: &mut FnvHashSet
<(CrateNum
, bool
)>)
406 if !visited
.insert((cnum
, extern_crate
.direct
)) { return }
408 let cmeta
= self.cstore
.get_crate_data(cnum
);
409 let old_extern_crate
= cmeta
.extern_crate
.get();
412 // - something over nothing (tuple.0);
413 // - direct extern crate to indirect (tuple.1);
414 // - shorter paths to longer (tuple.2).
415 let new_rank
= (true, extern_crate
.direct
, !extern_crate
.path_len
);
416 let old_rank
= match old_extern_crate
{
417 None
=> (false, false, !0),
418 Some(ref c
) => (true, c
.direct
, !c
.path_len
),
421 if old_rank
>= new_rank
{
422 return; // no change needed
425 cmeta
.extern_crate
.set(Some(extern_crate
));
426 // Propagate the extern crate info to dependencies.
427 extern_crate
.direct
= false;
428 for &dep_cnum
in cmeta
.cnum_map
.borrow().iter() {
429 self.update_extern_crate(dep_cnum
, extern_crate
, visited
);
433 // Go through the crate metadata and load any crates that it references
434 fn resolve_crate_deps(&mut self,
435 root
: &Option
<CratePaths
>,
436 crate_root
: &CrateRoot
,
437 metadata
: &MetadataBlob
,
440 -> cstore
::CrateNumMap
{
441 debug
!("resolving deps of external crate");
442 // The map from crate numbers in the crate we're resolving to local crate
444 let deps
= crate_root
.crate_deps
.decode(metadata
);
445 let map
: FnvHashMap
<_
, _
> = deps
.enumerate().map(|(crate_num
, dep
)| {
446 debug
!("resolving dep crate {} hash: `{}`", dep
.name
, dep
.hash
);
447 let (local_cnum
, ..) = self.resolve_crate(root
,
452 PathKind
::Dependency
,
453 dep
.explicitly_linked
);
454 (CrateNum
::new(crate_num
+ 1), local_cnum
)
457 let max_cnum
= map
.values().cloned().max().map(|cnum
| cnum
.as_u32()).unwrap_or(0);
459 // we map 0 and all other holes in the map to our parent crate. The "additional"
460 // self-dependencies should be harmless.
461 (0..max_cnum
+1).map(|cnum
| {
462 map
.get(&CrateNum
::from_u32(cnum
)).cloned().unwrap_or(krate
)
466 fn read_extension_crate(&mut self, span
: Span
, info
: &ExternCrateInfo
) -> ExtensionCrate
{
467 info
!("read extension crate {} `extern crate {} as {}` linked={}",
468 info
.id
, info
.name
, info
.ident
, info
.should_link
);
469 let target_triple
= &self.sess
.opts
.target_triple
[..];
470 let is_cross
= target_triple
!= config
::host_triple();
471 let mut target_only
= false;
472 let ident
= info
.ident
.clone();
473 let name
= info
.name
.clone();
474 let mut locate_ctxt
= locator
::Context
{
478 crate_name
: &name
[..],
480 filesearch
: self.sess
.host_filesearch(PathKind
::Crate
),
481 target
: &self.sess
.host
,
482 triple
: config
::host_triple(),
484 rejected_via_hash
: vec
![],
485 rejected_via_triple
: vec
![],
486 rejected_via_kind
: vec
![],
487 rejected_via_version
: vec
![],
488 should_match_name
: true,
490 let library
= self.load(&mut locate_ctxt
).or_else(|| {
494 // Try loading from target crates. This will abort later if we
495 // try to load a plugin registrar function,
498 locate_ctxt
.target
= &self.sess
.target
.target
;
499 locate_ctxt
.triple
= target_triple
;
500 locate_ctxt
.filesearch
= self.sess
.target_filesearch(PathKind
::Crate
);
502 self.load(&mut locate_ctxt
)
504 let library
= match library
{
506 None
=> locate_ctxt
.report_errs(),
509 let (dylib
, metadata
) = match library
{
510 LoadResult
::Previous(cnum
) => {
511 let dylib
= self.cstore
.opt_used_crate_source(cnum
).unwrap().dylib
;
512 let data
= self.cstore
.get_crate_data(cnum
);
513 (dylib
, PMDSource
::Registered(data
))
515 LoadResult
::Loaded(library
) => {
516 let dylib
= library
.dylib
.clone();
517 let metadata
= PMDSource
::Owned(library
);
524 dylib
: dylib
.map(|p
| p
.0),
525 target_only
: target_only
,
529 fn read_macros(&mut self, item
: &ast
::Item
, ekrate
: &ExtensionCrate
) -> LoadedMacros
{
530 let root
= ekrate
.metadata
.get_root();
531 let source_name
= format
!("<{} macros>", item
.ident
);
532 let mut macro_rules
= Vec
::new();
534 for def
in root
.macro_defs
.decode(&*ekrate
.metadata
) {
535 // NB: Don't use parse::parse_tts_from_source_str because it parses with
537 let mut p
= parse
::new_parser_from_source_str(&self.sess
.parse_sess
,
541 let body
= match p
.parse_all_token_trees() {
545 self.sess
.abort_if_errors();
549 let local_span
= mk_sp(lo
, p
.prev_span
.hi
);
551 // Mark the attrs as used
552 for attr
in &def
.attrs
{
553 attr
::mark_used(attr
);
556 macro_rules
.push(ast
::MacroDef
{
557 ident
: ast
::Ident
::with_empty_ctxt(def
.name
),
558 id
: ast
::DUMMY_NODE_ID
,
560 imported_from
: Some(item
.ident
),
561 allow_internal_unstable
: attr
::contains_name(&def
.attrs
, "allow_internal_unstable"),
565 self.sess
.imported_macro_spans
.borrow_mut()
566 .insert(local_span
, (def
.name
.as_str().to_string(), def
.span
));
569 if let Some(id
) = root
.macro_derive_registrar
{
570 let dylib
= match ekrate
.dylib
.clone() {
571 Some(dylib
) => dylib
,
572 None
=> span_bug
!(item
.span
, "proc-macro crate not dylib"),
574 if ekrate
.target_only
{
575 let message
= format
!("proc-macro crate is not available for \
576 triple `{}` (only found {})",
577 config
::host_triple(),
578 self.sess
.opts
.target_triple
);
579 self.sess
.span_fatal(item
.span
, &message
);
582 // custom derive crates currently should not have any macro_rules!
583 // exported macros, enforced elsewhere
584 assert_eq
!(macro_rules
.len(), 0);
585 LoadedMacros
::ProcMacros(self.load_derive_macros(item
, id
, root
.hash
, dylib
))
587 LoadedMacros
::MacroRules(macro_rules
)
591 /// Load custom derive macros.
593 /// Note that this is intentionally similar to how we load plugins today,
594 /// but also intentionally separate. Plugins are likely always going to be
595 /// implemented as dynamic libraries, but we have a possible future where
596 /// custom derive (and other macro-1.1 style features) are implemented via
597 /// executables and custom IPC.
598 fn load_derive_macros(&mut self, item
: &ast
::Item
, index
: DefIndex
, svh
: Svh
, path
: PathBuf
)
599 -> Vec
<(ast
::Name
, SyntaxExtension
)> {
601 use proc_macro
::TokenStream
;
602 use proc_macro
::__internal
::Registry
;
603 use rustc_back
::dynamic_lib
::DynamicLibrary
;
604 use syntax_ext
::deriving
::custom
::CustomDerive
;
606 // Make sure the path contains a / or the linker will search for it.
607 let path
= env
::current_dir().unwrap().join(path
);
608 let lib
= match DynamicLibrary
::open(Some(&path
)) {
610 Err(err
) => self.sess
.span_fatal(item
.span
, &err
),
613 let sym
= self.sess
.generate_derive_registrar_symbol(&svh
, index
);
614 let registrar
= unsafe {
615 let sym
= match lib
.symbol(&sym
) {
617 Err(err
) => self.sess
.span_fatal(item
.span
, &err
),
619 mem
::transmute
::<*mut u8, fn(&mut Registry
)>(sym
)
622 struct MyRegistrar(Vec
<(ast
::Name
, SyntaxExtension
)>);
624 impl Registry
for MyRegistrar
{
625 fn register_custom_derive(&mut self,
627 expand
: fn(TokenStream
) -> TokenStream
) {
628 let derive
= SyntaxExtension
::CustomDerive(Box
::new(CustomDerive
::new(expand
)));
629 self.0.push((intern(trait_name
), derive
));
633 let mut my_registrar
= MyRegistrar(Vec
::new());
634 registrar(&mut my_registrar
);
636 // Intentionally leak the dynamic library. We can't ever unload it
637 // since the library can make things that will live arbitrarily long.
642 /// Look for a plugin registrar. Returns library path, crate
643 /// SVH and DefIndex of the registrar function.
644 pub fn find_plugin_registrar(&mut self, span
: Span
, name
: &str)
645 -> Option
<(PathBuf
, Svh
, DefIndex
)> {
646 let ekrate
= self.read_extension_crate(span
, &ExternCrateInfo
{
647 name
: name
.to_string(),
648 ident
: name
.to_string(),
649 id
: ast
::DUMMY_NODE_ID
,
653 if ekrate
.target_only
{
654 // Need to abort before syntax expansion.
655 let message
= format
!("plugin `{}` is not available for triple `{}` \
658 config
::host_triple(),
659 self.sess
.opts
.target_triple
);
660 span_fatal
!(self.sess
, span
, E0456
, "{}", &message
[..]);
663 let root
= ekrate
.metadata
.get_root();
664 match (ekrate
.dylib
.as_ref(), root
.plugin_registrar_fn
) {
665 (Some(dylib
), Some(reg
)) => {
666 Some((dylib
.to_path_buf(), root
.hash
, reg
))
669 span_err
!(self.sess
, span
, E0457
,
670 "plugin `{}` only found in rlib format, but must be available \
673 // No need to abort because the loading code will just ignore this
681 fn register_statically_included_foreign_items(&mut self) {
682 let libs
= self.cstore
.get_used_libraries();
683 for (lib
, list
) in self.foreign_item_map
.iter() {
684 let is_static
= libs
.borrow().iter().any(|&(ref name
, kind
)| {
685 lib
== name
&& kind
== cstore
::NativeStatic
689 self.cstore
.add_statically_included_foreign_item(*id
);
695 fn inject_panic_runtime(&mut self, krate
: &ast
::Crate
) {
696 // If we're only compiling an rlib, then there's no need to select a
697 // panic runtime, so we just skip this section entirely.
698 let any_non_rlib
= self.sess
.crate_types
.borrow().iter().any(|ct
| {
699 *ct
!= config
::CrateTypeRlib
702 info
!("panic runtime injection skipped, only generating rlib");
706 // If we need a panic runtime, we try to find an existing one here. At
707 // the same time we perform some general validation of the DAG we've got
708 // going such as ensuring everything has a compatible panic strategy.
710 // The logic for finding the panic runtime here is pretty much the same
711 // as the allocator case with the only addition that the panic strategy
712 // compilation mode also comes into play.
713 let desired_strategy
= self.sess
.panic_strategy();
714 let mut runtime_found
= false;
715 let mut needs_panic_runtime
= attr
::contains_name(&krate
.attrs
,
716 "needs_panic_runtime");
717 self.cstore
.iter_crate_data(|cnum
, data
| {
718 needs_panic_runtime
= needs_panic_runtime
|| data
.needs_panic_runtime();
719 if data
.is_panic_runtime() {
720 // Inject a dependency from all #![needs_panic_runtime] to this
721 // #![panic_runtime] crate.
722 self.inject_dependency_if(cnum
, "a panic runtime",
723 &|data
| data
.needs_panic_runtime());
724 runtime_found
= runtime_found
|| data
.explicitly_linked
.get();
728 // If an explicitly linked and matching panic runtime was found, or if
729 // we just don't need one at all, then we're done here and there's
730 // nothing else to do.
731 if !needs_panic_runtime
|| runtime_found
{
735 // By this point we know that we (a) need a panic runtime and (b) no
736 // panic runtime was explicitly linked. Here we just load an appropriate
737 // default runtime for our panic strategy and then inject the
740 // We may resolve to an already loaded crate (as the crate may not have
741 // been explicitly linked prior to this) and we may re-inject
742 // dependencies again, but both of those situations are fine.
744 // Also note that we have yet to perform validation of the crate graph
745 // in terms of everyone has a compatible panic runtime format, that's
746 // performed later as part of the `dependency_format` module.
747 let name
= match desired_strategy
{
748 PanicStrategy
::Unwind
=> "panic_unwind",
749 PanicStrategy
::Abort
=> "panic_abort",
751 info
!("panic runtime not found -- loading {}", name
);
753 let (cnum
, data
, _
) = self.resolve_crate(&None
, name
, name
, None
,
754 syntax_pos
::DUMMY_SP
,
755 PathKind
::Crate
, false);
757 // Sanity check the loaded crate to ensure it is indeed a panic runtime
758 // and the panic strategy is indeed what we thought it was.
759 if !data
.is_panic_runtime() {
760 self.sess
.err(&format
!("the crate `{}` is not a panic runtime",
763 if data
.panic_strategy() != desired_strategy
{
764 self.sess
.err(&format
!("the crate `{}` does not have the panic \
766 name
, desired_strategy
.desc()));
769 self.sess
.injected_panic_runtime
.set(Some(cnum
));
770 self.inject_dependency_if(cnum
, "a panic runtime",
771 &|data
| data
.needs_panic_runtime());
774 fn inject_allocator_crate(&mut self) {
775 // Make sure that we actually need an allocator, if none of our
776 // dependencies need one then we definitely don't!
778 // Also, if one of our dependencies has an explicit allocator, then we
779 // also bail out as we don't need to implicitly inject one.
780 let mut needs_allocator
= false;
781 let mut found_required_allocator
= false;
782 self.cstore
.iter_crate_data(|cnum
, data
| {
783 needs_allocator
= needs_allocator
|| data
.needs_allocator();
784 if data
.is_allocator() {
785 info
!("{} required by rlib and is an allocator", data
.name());
786 self.inject_dependency_if(cnum
, "an allocator",
787 &|data
| data
.needs_allocator());
788 found_required_allocator
= found_required_allocator
||
789 data
.explicitly_linked
.get();
792 if !needs_allocator
|| found_required_allocator { return }
794 // At this point we've determined that we need an allocator and no
795 // previous allocator has been activated. We look through our outputs of
796 // crate types to see what kind of allocator types we may need.
798 // The main special output type here is that rlibs do **not** need an
799 // allocator linked in (they're just object files), only final products
800 // (exes, dylibs, staticlibs) need allocators.
801 let mut need_lib_alloc
= false;
802 let mut need_exe_alloc
= false;
803 for ct
in self.sess
.crate_types
.borrow().iter() {
805 config
::CrateTypeExecutable
=> need_exe_alloc
= true,
806 config
::CrateTypeDylib
|
807 config
::CrateTypeProcMacro
|
808 config
::CrateTypeCdylib
|
809 config
::CrateTypeStaticlib
=> need_lib_alloc
= true,
810 config
::CrateTypeRlib
=> {}
813 if !need_lib_alloc
&& !need_exe_alloc { return }
815 // The default allocator crate comes from the custom target spec, and we
816 // choose between the standard library allocator or exe allocator. This
817 // distinction exists because the default allocator for binaries (where
818 // the world is Rust) is different than library (where the world is
819 // likely *not* Rust).
821 // If a library is being produced, but we're also flagged with `-C
822 // prefer-dynamic`, then we interpret this as a *Rust* dynamic library
823 // is being produced so we use the exe allocator instead.
825 // What this boils down to is:
827 // * Binaries use jemalloc
828 // * Staticlibs and Rust dylibs use system malloc
829 // * Rust dylibs used as dependencies to rust use jemalloc
830 let name
= if need_lib_alloc
&& !self.sess
.opts
.cg
.prefer_dynamic
{
831 &self.sess
.target
.target
.options
.lib_allocation_crate
833 &self.sess
.target
.target
.options
.exe_allocation_crate
835 let (cnum
, data
, _
) = self.resolve_crate(&None
, name
, name
, None
,
836 syntax_pos
::DUMMY_SP
,
837 PathKind
::Crate
, false);
839 // Sanity check the crate we loaded to ensure that it is indeed an
841 if !data
.is_allocator() {
842 self.sess
.err(&format
!("the allocator crate `{}` is not tagged \
843 with #![allocator]", data
.name()));
846 self.sess
.injected_allocator
.set(Some(cnum
));
847 self.inject_dependency_if(cnum
, "an allocator",
848 &|data
| data
.needs_allocator());
851 fn inject_dependency_if(&self,
854 needs_dep
: &Fn(&cstore
::CrateMetadata
) -> bool
) {
855 // don't perform this validation if the session has errors, as one of
856 // those errors may indicate a circular dependency which could cause
857 // this to stack overflow.
858 if self.sess
.has_errors() {
862 // Before we inject any dependencies, make sure we don't inject a
863 // circular dependency by validating that this crate doesn't
864 // transitively depend on any crates satisfying `needs_dep`.
865 for dep
in self.cstore
.crate_dependencies_in_rpo(krate
) {
866 let data
= self.cstore
.get_crate_data(dep
);
867 if needs_dep(&data
) {
868 self.sess
.err(&format
!("the crate `{}` cannot depend \
869 on a crate that needs {}, but \
871 self.cstore
.get_crate_data(krate
).name(),
877 // All crates satisfying `needs_dep` do not explicitly depend on the
878 // crate provided for this compile, but in order for this compilation to
879 // be successfully linked we need to inject a dependency (to order the
880 // crates on the command line correctly).
881 self.cstore
.iter_crate_data(|cnum
, data
| {
882 if !needs_dep(data
) {
886 info
!("injecting a dep from {} to {}", cnum
, krate
);
887 data
.cnum_map
.borrow_mut().push(krate
);
892 impl<'a
> CrateLoader
<'a
> {
893 pub fn preprocess(&mut self, krate
: &ast
::Crate
) {
894 for attr
in krate
.attrs
.iter().filter(|m
| m
.name() == "link_args") {
895 if let Some(ref linkarg
) = attr
.value_str() {
896 self.cstore
.add_used_link_args(&linkarg
);
901 fn process_foreign_mod(&mut self, i
: &ast
::Item
, fm
: &ast
::ForeignMod
) {
902 if fm
.abi
== Abi
::Rust
|| fm
.abi
== Abi
::RustIntrinsic
|| fm
.abi
== Abi
::PlatformIntrinsic
{
906 // First, add all of the custom #[link_args] attributes
907 for m
in i
.attrs
.iter().filter(|a
| a
.check_name("link_args")) {
908 if let Some(linkarg
) = m
.value_str() {
909 self.cstore
.add_used_link_args(&linkarg
);
913 // Next, process all of the #[link(..)]-style arguments
914 for m
in i
.attrs
.iter().filter(|a
| a
.check_name("link")) {
915 let items
= match m
.meta_item_list() {
919 let kind
= items
.iter().find(|k
| {
921 }).and_then(|a
| a
.value_str());
922 let kind
= match kind
.as_ref().map(|s
| &s
[..]) {
923 Some("static") => cstore
::NativeStatic
,
924 Some("dylib") => cstore
::NativeUnknown
,
925 Some("framework") => cstore
::NativeFramework
,
927 struct_span_err
!(self.sess
, m
.span
, E0458
,
928 "unknown kind: `{}`", k
)
929 .span_label(m
.span
, &format
!("unknown kind")).emit();
930 cstore
::NativeUnknown
932 None
=> cstore
::NativeUnknown
934 let n
= items
.iter().find(|n
| {
936 }).and_then(|a
| a
.value_str());
940 struct_span_err
!(self.sess
, m
.span
, E0459
,
941 "#[link(...)] specified without `name = \"foo\"`")
942 .span_label(m
.span
, &format
!("missing `name` argument")).emit();
943 InternedString
::new("foo")
946 register_native_lib(self.sess
, self.cstore
, Some(m
.span
), n
.to_string(), kind
);
949 // Finally, process the #[linked_from = "..."] attribute
950 for m
in i
.attrs
.iter().filter(|a
| a
.check_name("linked_from")) {
951 let lib_name
= match m
.value_str() {
955 let list
= self.foreign_item_map
.entry(lib_name
.to_string())
956 .or_insert(Vec
::new());
957 list
.extend(fm
.items
.iter().map(|it
| it
.id
));
962 impl<'a
> middle
::cstore
::CrateLoader
for CrateLoader
<'a
> {
963 fn postprocess(&mut self, krate
: &ast
::Crate
) {
964 self.inject_allocator_crate();
965 self.inject_panic_runtime(krate
);
967 if log_enabled
!(log
::INFO
) {
968 dump_crates(&self.cstore
);
971 for &(ref name
, kind
) in &self.sess
.opts
.libs
{
972 register_native_lib(self.sess
, self.cstore
, None
, name
.clone(), kind
);
974 self.register_statically_included_foreign_items();
977 fn process_item(&mut self, item
: &ast
::Item
, definitions
: &Definitions
, load_macros
: bool
)
978 -> Option
<LoadedMacros
> {
980 ast
::ItemKind
::ExternCrate(_
) => {}
981 ast
::ItemKind
::ForeignMod(ref fm
) => {
982 self.process_foreign_mod(item
, fm
);
988 let info
= self.extract_crate_info(item
).unwrap();
989 let loaded_macros
= if load_macros
{
990 let ekrate
= self.read_extension_crate(item
.span
, &info
);
991 let loaded_macros
= self.read_macros(item
, &ekrate
);
993 // If this is a proc-macro crate or `#[no_link]` crate, it is only used at compile time,
994 // so we return here to avoid registering the crate.
995 if loaded_macros
.is_proc_macros() || !info
.should_link
{
996 return Some(loaded_macros
);
999 // Register crate now to avoid double-reading metadata
1000 if let PMDSource
::Owned(lib
) = ekrate
.metadata
{
1001 if ekrate
.target_only
|| config
::host_triple() == self.sess
.opts
.target_triple
{
1002 let ExternCrateInfo { ref ident, ref name, .. }
= info
;
1003 self.register_crate(&None
, ident
, name
, item
.span
, lib
, true);
1009 if !info
.should_link
{
1015 let (cnum
, ..) = self.resolve_crate(
1016 &None
, &info
.ident
, &info
.name
, None
, item
.span
, PathKind
::Crate
, true,
1019 let def_id
= definitions
.opt_local_def_id(item
.id
).unwrap();
1020 let len
= definitions
.def_path(def_id
.index
).data
.len();
1023 ExternCrate { def_id: def_id, span: item.span, direct: true, path_len: len }
;
1024 self.update_extern_crate(cnum
, extern_crate
, &mut FnvHashSet());
1025 self.cstore
.add_extern_mod_stmt_cnum(info
.id
, cnum
);