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
::DepKind
;
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
::common
::record_time
;
26 use rustc
::util
::nodemap
::FxHashSet
;
27 use rustc
::middle
::cstore
::NativeLibrary
;
28 use rustc
::hir
::map
::Definitions
;
30 use std
::cell
::{RefCell, Cell}
;
32 use std
::path
::PathBuf
;
39 use syntax
::ext
::base
::SyntaxExtension
;
40 use syntax
::feature_gate
::{self, GateIssue}
;
41 use syntax
::symbol
::Symbol
;
42 use syntax_pos
::{Span, DUMMY_SP}
;
46 pub dylib
: Option
<(PathBuf
, PathKind
)>,
47 pub rlib
: Option
<(PathBuf
, PathKind
)>,
48 pub rmeta
: Option
<(PathBuf
, PathKind
)>,
49 pub metadata
: MetadataBlob
,
52 pub struct CrateLoader
<'a
> {
53 pub sess
: &'a Session
,
55 next_crate_num
: CrateNum
,
56 local_crate_name
: Symbol
,
59 fn dump_crates(cstore
: &CStore
) {
60 info
!("resolved crates:");
61 cstore
.iter_crate_data(|_
, data
| {
62 info
!(" name: {}", data
.name());
63 info
!(" cnum: {}", data
.cnum
);
64 info
!(" hash: {}", data
.hash());
65 info
!(" reqd: {:?}", data
.dep_kind
.get());
66 let CrateSource { dylib, rlib, rmeta }
= data
.source
.clone();
67 dylib
.map(|dl
| info
!(" dylib: {}", dl
.0.display()));
68 rlib
.map(|rl
| info
!(" rlib: {}", rl
.0.display()));
69 rmeta
.map(|rl
| info
!(" rmeta: {}", rl
.0.display()));
74 struct ExternCrateInfo
{
81 fn register_native_lib(sess
: &Session
,
85 if lib
.name
.as_str().is_empty() {
88 struct_span_err
!(sess
, span
, E0454
,
89 "#[link(name = \"\")] given with empty name")
90 .span_label(span
, &format
!("empty name given"))
94 sess
.err("empty library name given via `-l`");
99 let is_osx
= sess
.target
.target
.options
.is_like_osx
;
100 if lib
.kind
== cstore
::NativeFramework
&& !is_osx
{
101 let msg
= "native frameworks are only available on OSX targets";
103 Some(span
) => span_err
!(sess
, span
, E0455
, "{}", msg
),
104 None
=> sess
.err(msg
),
107 if lib
.cfg
.is_some() && !sess
.features
.borrow().link_cfg
{
108 feature_gate
::emit_feature_err(&sess
.parse_sess
,
114 cstore
.add_used_library(lib
);
117 fn relevant_lib(sess
: &Session
, lib
: &NativeLibrary
) -> bool
{
119 Some(ref cfg
) => attr
::cfg_matches(cfg
, &sess
.parse_sess
, None
),
124 // Extra info about a crate loaded for plugins or exported macros.
125 struct ExtensionCrate
{
127 dylib
: Option
<PathBuf
>,
132 Registered(Rc
<cstore
::CrateMetadata
>),
136 impl Deref
for PMDSource
{
137 type Target
= MetadataBlob
;
139 fn deref(&self) -> &MetadataBlob
{
141 PMDSource
::Registered(ref cmd
) => &cmd
.blob
,
142 PMDSource
::Owned(ref lib
) => &lib
.metadata
152 impl<'a
> CrateLoader
<'a
> {
153 pub fn new(sess
: &'a Session
, cstore
: &'a CStore
, local_crate_name
: &str) -> Self {
157 next_crate_num
: cstore
.next_crate_num(),
158 local_crate_name
: Symbol
::intern(local_crate_name
),
162 fn extract_crate_info(&self, i
: &ast
::Item
) -> Option
<ExternCrateInfo
> {
164 ast
::ItemKind
::ExternCrate(ref path_opt
) => {
165 debug
!("resolving extern crate stmt. ident: {} path_opt: {:?}",
167 let name
= match *path_opt
{
169 validate_crate_name(Some(self.sess
), &name
.as_str(),
173 None
=> i
.ident
.name
,
175 Some(ExternCrateInfo
{
179 dep_kind
: if attr
::contains_name(&i
.attrs
, "no_link") {
180 DepKind
::UnexportedMacrosOnly
190 fn existing_match(&self, name
: Symbol
, hash
: Option
<&Svh
>, kind
: PathKind
)
191 -> Option
<CrateNum
> {
193 self.cstore
.iter_crate_data(|cnum
, data
| {
194 if data
.name
!= name { return }
197 Some(hash
) if *hash
== data
.hash() => { ret = Some(cnum); return }
202 // When the hash is None we're dealing with a top-level dependency
203 // in which case we may have a specification on the command line for
204 // this library. Even though an upstream library may have loaded
205 // something of the same name, we have to make sure it was loaded
206 // from the exact same location as well.
208 // We're also sure to compare *paths*, not actual byte slices. The
209 // `source` stores paths which are normalized which may be different
210 // from the strings on the command line.
211 let source
= self.cstore
.used_crate_source(cnum
);
212 if let Some(locs
) = self.sess
.opts
.externs
.get(&*name
.as_str()) {
213 let found
= locs
.iter().any(|l
| {
214 let l
= fs
::canonicalize(l
).ok();
215 source
.dylib
.as_ref().map(|p
| &p
.0) == l
.as_ref() ||
216 source
.rlib
.as_ref().map(|p
| &p
.0) == l
.as_ref()
224 // Alright, so we've gotten this far which means that `data` has the
225 // right name, we don't have a hash, and we don't have a --extern
226 // pointing for ourselves. We're still not quite yet done because we
227 // have to make sure that this crate was found in the crate lookup
228 // path (this is a top-level dependency) as we don't want to
229 // implicitly load anything inside the dependency lookup path.
230 let prev_kind
= source
.dylib
.as_ref().or(source
.rlib
.as_ref())
232 if ret
.is_none() && (prev_kind
== kind
|| prev_kind
== PathKind
::All
) {
239 fn verify_no_symbol_conflicts(&self,
242 // Check for (potential) conflicts with the local crate
243 if self.local_crate_name
== root
.name
&&
244 self.sess
.local_crate_disambiguator() == root
.disambiguator
{
245 span_fatal
!(self.sess
, span
, E0519
,
246 "the current crate is indistinguishable from one of its \
247 dependencies: it has the same crate-name `{}` and was \
248 compiled with the same `-C metadata` arguments. This \
249 will result in symbol conflicts between the two.",
253 // Check for conflicts with any crate loaded so far
254 self.cstore
.iter_crate_data(|_
, other
| {
255 if other
.name() == root
.name
&& // same crate-name
256 other
.disambiguator() == root
.disambiguator
&& // same crate-disambiguator
257 other
.hash() != root
.hash
{ // but different SVH
258 span_fatal
!(self.sess
, span
, E0523
,
259 "found two different crates with name `{}` that are \
260 not distinguished by differing `-C metadata`. This \
261 will result in symbol conflicts between the two.",
267 fn register_crate(&mut self,
268 root
: &Option
<CratePaths
>,
274 -> (CrateNum
, Rc
<cstore
::CrateMetadata
>) {
275 info
!("register crate `extern crate {} as {}`", name
, ident
);
276 let crate_root
= lib
.metadata
.get_root();
277 self.verify_no_symbol_conflicts(span
, &crate_root
);
279 // Claim this crate number and cache it
280 let cnum
= self.next_crate_num
;
281 self.next_crate_num
= CrateNum
::from_u32(cnum
.as_u32() + 1);
283 // Stash paths for top-most crate locally if necessary.
284 let crate_paths
= if root
.is_none() {
286 ident
: ident
.to_string(),
287 dylib
: lib
.dylib
.clone().map(|p
| p
.0),
288 rlib
: lib
.rlib
.clone().map(|p
| p
.0),
289 rmeta
: lib
.rmeta
.clone().map(|p
| p
.0),
294 // Maintain a reference to the top most crate.
295 let root
= if root
.is_some() { root }
else { &crate_paths }
;
297 let Library { dylib, rlib, rmeta, metadata }
= lib
;
299 let cnum_map
= self.resolve_crate_deps(root
, &crate_root
, &metadata
, cnum
, span
, dep_kind
);
301 let def_path_table
= record_time(&self.sess
.perf_stats
.decode_def_path_tables_time
, || {
302 crate_root
.def_path_table
.decode(&metadata
)
305 let exported_symbols
= crate_root
.exported_symbols
.decode(&metadata
).collect();
307 let mut cmeta
= cstore
::CrateMetadata
{
309 extern_crate
: Cell
::new(None
),
310 def_path_table
: def_path_table
,
311 exported_symbols
: exported_symbols
,
312 proc_macros
: crate_root
.macro_derive_registrar
.map(|_
| {
313 self.load_derive_macros(&crate_root
, dylib
.clone().map(|p
| p
.0), span
)
317 cnum_map
: RefCell
::new(cnum_map
),
319 codemap_import_info
: RefCell
::new(vec
![]),
320 dep_kind
: Cell
::new(dep_kind
),
321 source
: cstore
::CrateSource
{
326 dllimport_foreign_items
: FxHashSet(),
329 let dllimports
: Vec
<_
> = cmeta
.get_native_libraries().iter()
330 .filter(|lib
| relevant_lib(self.sess
, lib
) &&
331 lib
.kind
== cstore
::NativeLibraryKind
::NativeUnknown
)
332 .flat_map(|lib
| &lib
.foreign_items
)
335 cmeta
.dllimport_foreign_items
.extend(dllimports
);
337 let cmeta
= Rc
::new(cmeta
);
338 self.cstore
.set_crate_data(cnum
, cmeta
.clone());
342 fn resolve_crate(&mut self,
343 root
: &Option
<CratePaths
>,
349 mut dep_kind
: DepKind
)
350 -> (CrateNum
, Rc
<cstore
::CrateMetadata
>) {
351 info
!("resolving crate `extern crate {} as {}`", name
, ident
);
352 let result
= if let Some(cnum
) = self.existing_match(name
, hash
, path_kind
) {
353 LoadResult
::Previous(cnum
)
355 info
!("falling back to a load");
356 let mut locate_ctxt
= locator
::Context
{
361 hash
: hash
.map(|a
| &*a
),
362 filesearch
: self.sess
.target_filesearch(path_kind
),
363 target
: &self.sess
.target
.target
,
364 triple
: &self.sess
.opts
.target_triple
,
366 rejected_via_hash
: vec
![],
367 rejected_via_triple
: vec
![],
368 rejected_via_kind
: vec
![],
369 rejected_via_version
: vec
![],
370 rejected_via_filename
: vec
![],
371 should_match_name
: true,
372 is_proc_macro
: Some(false),
375 self.load(&mut locate_ctxt
).or_else(|| {
376 dep_kind
= DepKind
::UnexportedMacrosOnly
;
378 let mut proc_macro_locator
= locator
::Context
{
379 target
: &self.sess
.host
,
380 triple
: config
::host_triple(),
381 filesearch
: self.sess
.host_filesearch(path_kind
),
382 rejected_via_hash
: vec
![],
383 rejected_via_triple
: vec
![],
384 rejected_via_kind
: vec
![],
385 rejected_via_version
: vec
![],
386 rejected_via_filename
: vec
![],
387 is_proc_macro
: Some(true),
391 self.load(&mut proc_macro_locator
)
392 }).unwrap_or_else(|| locate_ctxt
.report_errs())
396 LoadResult
::Previous(cnum
) => {
397 let data
= self.cstore
.get_crate_data(cnum
);
398 if data
.root
.macro_derive_registrar
.is_some() {
399 dep_kind
= DepKind
::UnexportedMacrosOnly
;
401 data
.dep_kind
.set(cmp
::max(data
.dep_kind
.get(), dep_kind
));
404 LoadResult
::Loaded(library
) => {
405 self.register_crate(root
, ident
, name
, span
, library
, dep_kind
)
410 fn load(&mut self, locate_ctxt
: &mut locator
::Context
) -> Option
<LoadResult
> {
411 let library
= match locate_ctxt
.maybe_load_library_crate() {
416 // In the case that we're loading a crate, but not matching
417 // against a hash, we could load a crate which has the same hash
418 // as an already loaded crate. If this is the case prevent
419 // duplicates by just using the first crate.
421 // Note that we only do this for target triple crates, though, as we
422 // don't want to match a host crate against an equivalent target one
424 let root
= library
.metadata
.get_root();
425 if locate_ctxt
.triple
== self.sess
.opts
.target_triple
{
426 let mut result
= LoadResult
::Loaded(library
);
427 self.cstore
.iter_crate_data(|cnum
, data
| {
428 if data
.name() == root
.name
&& root
.hash
== data
.hash() {
429 assert
!(locate_ctxt
.hash
.is_none());
430 info
!("load success, going to previous cnum: {}", cnum
);
431 result
= LoadResult
::Previous(cnum
);
436 Some(LoadResult
::Loaded(library
))
440 fn update_extern_crate(&mut self,
442 mut extern_crate
: ExternCrate
,
443 visited
: &mut FxHashSet
<(CrateNum
, bool
)>)
445 if !visited
.insert((cnum
, extern_crate
.direct
)) { return }
447 let cmeta
= self.cstore
.get_crate_data(cnum
);
448 let old_extern_crate
= cmeta
.extern_crate
.get();
451 // - something over nothing (tuple.0);
452 // - direct extern crate to indirect (tuple.1);
453 // - shorter paths to longer (tuple.2).
454 let new_rank
= (true, extern_crate
.direct
, !extern_crate
.path_len
);
455 let old_rank
= match old_extern_crate
{
456 None
=> (false, false, !0),
457 Some(ref c
) => (true, c
.direct
, !c
.path_len
),
460 if old_rank
>= new_rank
{
461 return; // no change needed
464 cmeta
.extern_crate
.set(Some(extern_crate
));
465 // Propagate the extern crate info to dependencies.
466 extern_crate
.direct
= false;
467 for &dep_cnum
in cmeta
.cnum_map
.borrow().iter() {
468 self.update_extern_crate(dep_cnum
, extern_crate
, visited
);
472 // Go through the crate metadata and load any crates that it references
473 fn resolve_crate_deps(&mut self,
474 root
: &Option
<CratePaths
>,
475 crate_root
: &CrateRoot
,
476 metadata
: &MetadataBlob
,
480 -> cstore
::CrateNumMap
{
481 debug
!("resolving deps of external crate");
482 if crate_root
.macro_derive_registrar
.is_some() {
483 return cstore
::CrateNumMap
::new();
486 // The map from crate numbers in the crate we're resolving to local crate numbers.
487 // We map 0 and all other holes in the map to our parent crate. The "additional"
488 // self-dependencies should be harmless.
489 ::std
::iter
::once(krate
).chain(crate_root
.crate_deps
.decode(metadata
).map(|dep
| {
490 debug
!("resolving dep crate {} hash: `{}`", dep
.name
, dep
.hash
);
491 if dep
.kind
== DepKind
::UnexportedMacrosOnly
{
494 let dep_kind
= match dep_kind
{
495 DepKind
::MacrosOnly
=> DepKind
::MacrosOnly
,
498 let (local_cnum
, ..) = self.resolve_crate(
499 root
, dep
.name
, dep
.name
, Some(&dep
.hash
), span
, PathKind
::Dependency
, dep_kind
,
505 fn read_extension_crate(&mut self, span
: Span
, info
: &ExternCrateInfo
) -> ExtensionCrate
{
506 info
!("read extension crate {} `extern crate {} as {}` dep_kind={:?}",
507 info
.id
, info
.name
, info
.ident
, info
.dep_kind
);
508 let target_triple
= &self.sess
.opts
.target_triple
[..];
509 let is_cross
= target_triple
!= config
::host_triple();
510 let mut target_only
= false;
511 let mut locate_ctxt
= locator
::Context
{
515 crate_name
: info
.name
,
517 filesearch
: self.sess
.host_filesearch(PathKind
::Crate
),
518 target
: &self.sess
.host
,
519 triple
: config
::host_triple(),
521 rejected_via_hash
: vec
![],
522 rejected_via_triple
: vec
![],
523 rejected_via_kind
: vec
![],
524 rejected_via_version
: vec
![],
525 rejected_via_filename
: vec
![],
526 should_match_name
: true,
529 let library
= self.load(&mut locate_ctxt
).or_else(|| {
533 // Try loading from target crates. This will abort later if we
534 // try to load a plugin registrar function,
537 locate_ctxt
.target
= &self.sess
.target
.target
;
538 locate_ctxt
.triple
= target_triple
;
539 locate_ctxt
.filesearch
= self.sess
.target_filesearch(PathKind
::Crate
);
541 self.load(&mut locate_ctxt
)
543 let library
= match library
{
545 None
=> locate_ctxt
.report_errs(),
548 let (dylib
, metadata
) = match library
{
549 LoadResult
::Previous(cnum
) => {
550 let data
= self.cstore
.get_crate_data(cnum
);
551 (data
.source
.dylib
.clone(), PMDSource
::Registered(data
))
553 LoadResult
::Loaded(library
) => {
554 let dylib
= library
.dylib
.clone();
555 let metadata
= PMDSource
::Owned(library
);
562 dylib
: dylib
.map(|p
| p
.0),
563 target_only
: target_only
,
567 /// Load custom derive macros.
569 /// Note that this is intentionally similar to how we load plugins today,
570 /// but also intentionally separate. Plugins are likely always going to be
571 /// implemented as dynamic libraries, but we have a possible future where
572 /// custom derive (and other macro-1.1 style features) are implemented via
573 /// executables and custom IPC.
574 fn load_derive_macros(&mut self, root
: &CrateRoot
, dylib
: Option
<PathBuf
>, span
: Span
)
575 -> Vec
<(ast
::Name
, Rc
<SyntaxExtension
>)> {
577 use proc_macro
::TokenStream
;
578 use proc_macro
::__internal
::Registry
;
579 use rustc_back
::dynamic_lib
::DynamicLibrary
;
580 use syntax_ext
::deriving
::custom
::CustomDerive
;
581 use syntax_ext
::proc_macro_impl
::AttrProcMacro
;
583 let path
= match dylib
{
584 Some(dylib
) => dylib
,
585 None
=> span_bug
!(span
, "proc-macro crate not dylib"),
587 // Make sure the path contains a / or the linker will search for it.
588 let path
= env
::current_dir().unwrap().join(path
);
589 let lib
= match DynamicLibrary
::open(Some(&path
)) {
591 Err(err
) => self.sess
.span_fatal(span
, &err
),
594 let sym
= self.sess
.generate_derive_registrar_symbol(&root
.hash
,
595 root
.macro_derive_registrar
.unwrap());
596 let registrar
= unsafe {
597 let sym
= match lib
.symbol(&sym
) {
599 Err(err
) => self.sess
.span_fatal(span
, &err
),
601 mem
::transmute
::<*mut u8, fn(&mut Registry
)>(sym
)
604 struct MyRegistrar(Vec
<(ast
::Name
, Rc
<SyntaxExtension
>)>);
606 impl Registry
for MyRegistrar
{
607 fn register_custom_derive(&mut self,
609 expand
: fn(TokenStream
) -> TokenStream
,
610 attributes
: &[&'
static str]) {
611 let attrs
= attributes
.iter().cloned().map(Symbol
::intern
).collect();
612 let derive
= SyntaxExtension
::CustomDerive(
613 Box
::new(CustomDerive
::new(expand
, attrs
))
615 self.0.push((Symbol
::intern(trait_name
), Rc
::new(derive
)));
618 fn register_attr_proc_macro(&mut self,
620 expand
: fn(TokenStream
, TokenStream
) -> TokenStream
) {
621 let expand
= SyntaxExtension
::AttrProcMacro(
622 Box
::new(AttrProcMacro { inner: expand }
)
624 self.0.push((Symbol
::intern(name
), Rc
::new(expand
)));
628 let mut my_registrar
= MyRegistrar(Vec
::new());
629 registrar(&mut my_registrar
);
631 // Intentionally leak the dynamic library. We can't ever unload it
632 // since the library can make things that will live arbitrarily long.
637 /// Look for a plugin registrar. Returns library path, crate
638 /// SVH and DefIndex of the registrar function.
639 pub fn find_plugin_registrar(&mut self, span
: Span
, name
: &str)
640 -> Option
<(PathBuf
, Svh
, DefIndex
)> {
641 let ekrate
= self.read_extension_crate(span
, &ExternCrateInfo
{
642 name
: Symbol
::intern(name
),
643 ident
: Symbol
::intern(name
),
644 id
: ast
::DUMMY_NODE_ID
,
645 dep_kind
: DepKind
::UnexportedMacrosOnly
,
648 if ekrate
.target_only
{
649 // Need to abort before syntax expansion.
650 let message
= format
!("plugin `{}` is not available for triple `{}` \
653 config
::host_triple(),
654 self.sess
.opts
.target_triple
);
655 span_fatal
!(self.sess
, span
, E0456
, "{}", &message
[..]);
658 let root
= ekrate
.metadata
.get_root();
659 match (ekrate
.dylib
.as_ref(), root
.plugin_registrar_fn
) {
660 (Some(dylib
), Some(reg
)) => {
661 Some((dylib
.to_path_buf(), root
.hash
, reg
))
664 span_err
!(self.sess
, span
, E0457
,
665 "plugin `{}` only found in rlib format, but must be available \
668 // No need to abort because the loading code will just ignore this
676 fn get_foreign_items_of_kind(&self, kind
: cstore
::NativeLibraryKind
) -> Vec
<DefIndex
> {
677 let mut items
= vec
![];
678 let libs
= self.cstore
.get_used_libraries();
679 for lib
in libs
.borrow().iter() {
680 if relevant_lib(self.sess
, lib
) && lib
.kind
== kind
{
681 items
.extend(&lib
.foreign_items
);
687 fn register_statically_included_foreign_items(&mut self) {
688 for id
in self.get_foreign_items_of_kind(cstore
::NativeStatic
) {
689 self.cstore
.add_statically_included_foreign_item(id
);
693 fn register_dllimport_foreign_items(&mut self) {
694 let mut dllimports
= self.cstore
.dllimport_foreign_items
.borrow_mut();
695 for id
in self.get_foreign_items_of_kind(cstore
::NativeUnknown
) {
696 dllimports
.insert(id
);
700 fn inject_panic_runtime(&mut self, krate
: &ast
::Crate
) {
701 // If we're only compiling an rlib, then there's no need to select a
702 // panic runtime, so we just skip this section entirely.
703 let any_non_rlib
= self.sess
.crate_types
.borrow().iter().any(|ct
| {
704 *ct
!= config
::CrateTypeRlib
707 info
!("panic runtime injection skipped, only generating rlib");
711 // If we need a panic runtime, we try to find an existing one here. At
712 // the same time we perform some general validation of the DAG we've got
713 // going such as ensuring everything has a compatible panic strategy.
715 // The logic for finding the panic runtime here is pretty much the same
716 // as the allocator case with the only addition that the panic strategy
717 // compilation mode also comes into play.
718 let desired_strategy
= self.sess
.panic_strategy();
719 let mut runtime_found
= false;
720 let mut needs_panic_runtime
= attr
::contains_name(&krate
.attrs
,
721 "needs_panic_runtime");
722 self.cstore
.iter_crate_data(|cnum
, data
| {
723 needs_panic_runtime
= needs_panic_runtime
|| data
.needs_panic_runtime();
724 if data
.is_panic_runtime() {
725 // Inject a dependency from all #![needs_panic_runtime] to this
726 // #![panic_runtime] crate.
727 self.inject_dependency_if(cnum
, "a panic runtime",
728 &|data
| data
.needs_panic_runtime());
729 runtime_found
= runtime_found
|| data
.dep_kind
.get() == DepKind
::Explicit
;
733 // If an explicitly linked and matching panic runtime was found, or if
734 // we just don't need one at all, then we're done here and there's
735 // nothing else to do.
736 if !needs_panic_runtime
|| runtime_found
{
740 // By this point we know that we (a) need a panic runtime and (b) no
741 // panic runtime was explicitly linked. Here we just load an appropriate
742 // default runtime for our panic strategy and then inject the
745 // We may resolve to an already loaded crate (as the crate may not have
746 // been explicitly linked prior to this) and we may re-inject
747 // dependencies again, but both of those situations are fine.
749 // Also note that we have yet to perform validation of the crate graph
750 // in terms of everyone has a compatible panic runtime format, that's
751 // performed later as part of the `dependency_format` module.
752 let name
= match desired_strategy
{
753 PanicStrategy
::Unwind
=> Symbol
::intern("panic_unwind"),
754 PanicStrategy
::Abort
=> Symbol
::intern("panic_abort"),
756 info
!("panic runtime not found -- loading {}", name
);
758 let dep_kind
= DepKind
::Implicit
;
760 self.resolve_crate(&None
, name
, name
, None
, DUMMY_SP
, PathKind
::Crate
, dep_kind
);
762 // Sanity check the loaded crate to ensure it is indeed a panic runtime
763 // and the panic strategy is indeed what we thought it was.
764 if !data
.is_panic_runtime() {
765 self.sess
.err(&format
!("the crate `{}` is not a panic runtime",
768 if data
.panic_strategy() != desired_strategy
{
769 self.sess
.err(&format
!("the crate `{}` does not have the panic \
771 name
, desired_strategy
.desc()));
774 self.sess
.injected_panic_runtime
.set(Some(cnum
));
775 self.inject_dependency_if(cnum
, "a panic runtime",
776 &|data
| data
.needs_panic_runtime());
779 fn inject_allocator_crate(&mut self) {
780 // Make sure that we actually need an allocator, if none of our
781 // dependencies need one then we definitely don't!
783 // Also, if one of our dependencies has an explicit allocator, then we
784 // also bail out as we don't need to implicitly inject one.
785 let mut needs_allocator
= false;
786 let mut found_required_allocator
= false;
787 self.cstore
.iter_crate_data(|cnum
, data
| {
788 needs_allocator
= needs_allocator
|| data
.needs_allocator();
789 if data
.is_allocator() {
790 info
!("{} required by rlib and is an allocator", data
.name());
791 self.inject_dependency_if(cnum
, "an allocator",
792 &|data
| data
.needs_allocator());
793 found_required_allocator
= found_required_allocator
||
794 data
.dep_kind
.get() == DepKind
::Explicit
;
797 if !needs_allocator
|| found_required_allocator { return }
799 // At this point we've determined that we need an allocator and no
800 // previous allocator has been activated. We look through our outputs of
801 // crate types to see what kind of allocator types we may need.
803 // The main special output type here is that rlibs do **not** need an
804 // allocator linked in (they're just object files), only final products
805 // (exes, dylibs, staticlibs) need allocators.
806 let mut need_lib_alloc
= false;
807 let mut need_exe_alloc
= false;
808 for ct
in self.sess
.crate_types
.borrow().iter() {
810 config
::CrateTypeExecutable
=> need_exe_alloc
= true,
811 config
::CrateTypeDylib
|
812 config
::CrateTypeProcMacro
|
813 config
::CrateTypeCdylib
|
814 config
::CrateTypeStaticlib
=> need_lib_alloc
= true,
815 config
::CrateTypeRlib
=> {}
818 if !need_lib_alloc
&& !need_exe_alloc { return }
820 // The default allocator crate comes from the custom target spec, and we
821 // choose between the standard library allocator or exe allocator. This
822 // distinction exists because the default allocator for binaries (where
823 // the world is Rust) is different than library (where the world is
824 // likely *not* Rust).
826 // If a library is being produced, but we're also flagged with `-C
827 // prefer-dynamic`, then we interpret this as a *Rust* dynamic library
828 // is being produced so we use the exe allocator instead.
830 // What this boils down to is:
832 // * Binaries use jemalloc
833 // * Staticlibs and Rust dylibs use system malloc
834 // * Rust dylibs used as dependencies to rust use jemalloc
835 let name
= if need_lib_alloc
&& !self.sess
.opts
.cg
.prefer_dynamic
{
836 Symbol
::intern(&self.sess
.target
.target
.options
.lib_allocation_crate
)
838 Symbol
::intern(&self.sess
.target
.target
.options
.exe_allocation_crate
)
840 let dep_kind
= DepKind
::Implicit
;
842 self.resolve_crate(&None
, name
, name
, None
, DUMMY_SP
, PathKind
::Crate
, dep_kind
);
844 // Sanity check the crate we loaded to ensure that it is indeed an
846 if !data
.is_allocator() {
847 self.sess
.err(&format
!("the allocator crate `{}` is not tagged \
848 with #![allocator]", data
.name()));
851 self.sess
.injected_allocator
.set(Some(cnum
));
852 self.inject_dependency_if(cnum
, "an allocator",
853 &|data
| data
.needs_allocator());
856 fn inject_dependency_if(&self,
859 needs_dep
: &Fn(&cstore
::CrateMetadata
) -> bool
) {
860 // don't perform this validation if the session has errors, as one of
861 // those errors may indicate a circular dependency which could cause
862 // this to stack overflow.
863 if self.sess
.has_errors() {
867 // Before we inject any dependencies, make sure we don't inject a
868 // circular dependency by validating that this crate doesn't
869 // transitively depend on any crates satisfying `needs_dep`.
870 for dep
in self.cstore
.crate_dependencies_in_rpo(krate
) {
871 let data
= self.cstore
.get_crate_data(dep
);
872 if needs_dep(&data
) {
873 self.sess
.err(&format
!("the crate `{}` cannot depend \
874 on a crate that needs {}, but \
876 self.cstore
.get_crate_data(krate
).name(),
882 // All crates satisfying `needs_dep` do not explicitly depend on the
883 // crate provided for this compile, but in order for this compilation to
884 // be successfully linked we need to inject a dependency (to order the
885 // crates on the command line correctly).
886 self.cstore
.iter_crate_data(|cnum
, data
| {
887 if !needs_dep(data
) {
891 info
!("injecting a dep from {} to {}", cnum
, krate
);
892 data
.cnum_map
.borrow_mut().push(krate
);
897 impl<'a
> CrateLoader
<'a
> {
898 pub fn preprocess(&mut self, krate
: &ast
::Crate
) {
899 for attr
in krate
.attrs
.iter().filter(|m
| m
.name() == "link_args") {
900 if let Some(linkarg
) = attr
.value_str() {
901 self.cstore
.add_used_link_args(&linkarg
.as_str());
906 fn process_foreign_mod(&mut self, i
: &ast
::Item
, fm
: &ast
::ForeignMod
,
907 definitions
: &Definitions
) {
908 if fm
.abi
== Abi
::Rust
|| fm
.abi
== Abi
::RustIntrinsic
|| fm
.abi
== Abi
::PlatformIntrinsic
{
912 // First, add all of the custom #[link_args] attributes
913 for m
in i
.attrs
.iter().filter(|a
| a
.check_name("link_args")) {
914 if let Some(linkarg
) = m
.value_str() {
915 self.cstore
.add_used_link_args(&linkarg
.as_str());
919 // Next, process all of the #[link(..)]-style arguments
920 for m
in i
.attrs
.iter().filter(|a
| a
.check_name("link")) {
921 let items
= match m
.meta_item_list() {
925 let kind
= items
.iter().find(|k
| {
927 }).and_then(|a
| a
.value_str()).map(Symbol
::as_str
);
928 let kind
= match kind
.as_ref().map(|s
| &s
[..]) {
929 Some("static") => cstore
::NativeStatic
,
930 Some("dylib") => cstore
::NativeUnknown
,
931 Some("framework") => cstore
::NativeFramework
,
933 struct_span_err
!(self.sess
, m
.span
, E0458
,
934 "unknown kind: `{}`", k
)
935 .span_label(m
.span
, &format
!("unknown kind")).emit();
936 cstore
::NativeUnknown
938 None
=> cstore
::NativeUnknown
940 let n
= items
.iter().find(|n
| {
942 }).and_then(|a
| a
.value_str());
946 struct_span_err
!(self.sess
, m
.span
, E0459
,
947 "#[link(...)] specified without `name = \"foo\"`")
948 .span_label(m
.span
, &format
!("missing `name` argument")).emit();
949 Symbol
::intern("foo")
952 let cfg
= items
.iter().find(|k
| {
954 }).and_then(|a
| a
.meta_item_list());
955 let cfg
= cfg
.map(|list
| {
956 list
[0].meta_item().unwrap().clone()
958 let foreign_items
= fm
.items
.iter()
959 .map(|it
| definitions
.opt_def_index(it
.id
).unwrap())
961 let lib
= NativeLibrary
{
965 foreign_items
: foreign_items
,
967 register_native_lib(self.sess
, self.cstore
, Some(m
.span
), lib
);
972 impl<'a
> middle
::cstore
::CrateLoader
for CrateLoader
<'a
> {
973 fn postprocess(&mut self, krate
: &ast
::Crate
) {
974 self.inject_allocator_crate();
975 self.inject_panic_runtime(krate
);
977 if log_enabled
!(log
::INFO
) {
978 dump_crates(&self.cstore
);
981 // Process libs passed on the command line
982 // First, check for errors
983 let mut renames
= FxHashSet();
984 for &(ref name
, ref new_name
, _
) in &self.sess
.opts
.libs
{
985 if let &Some(ref new_name
) = new_name
{
986 if new_name
.is_empty() {
988 &format
!("an empty renaming target was specified for library `{}`",name
));
989 } else if !self.cstore
.get_used_libraries().borrow().iter()
990 .any(|lib
| lib
.name
== name
as &str) {
991 self.sess
.err(&format
!("renaming of the library `{}` was specified, \
992 however this crate contains no #[link(...)] \
993 attributes referencing this library.", name
));
994 } else if renames
.contains(name
) {
995 self.sess
.err(&format
!("multiple renamings were specified for library `{}` .",
998 renames
.insert(name
);
1002 // Update kind and, optionally, the name of all native libaries
1003 // (there may be more than one) with the specified name.
1004 for &(ref name
, ref new_name
, kind
) in &self.sess
.opts
.libs
{
1005 let mut found
= false;
1006 for lib
in self.cstore
.get_used_libraries().borrow_mut().iter_mut() {
1007 if lib
.name
== name
as &str {
1009 if let &Some(ref new_name
) = new_name
{
1010 lib
.name
= Symbol
::intern(new_name
);
1017 let new_name
= new_name
.as_ref().map(|s
| &**s
); // &Option<String> -> Option<&str>
1018 let lib
= NativeLibrary
{
1019 name
: Symbol
::intern(new_name
.unwrap_or(name
)),
1022 foreign_items
: Vec
::new(),
1024 register_native_lib(self.sess
, self.cstore
, None
, lib
);
1027 self.register_statically_included_foreign_items();
1028 self.register_dllimport_foreign_items();
1031 fn process_item(&mut self, item
: &ast
::Item
, definitions
: &Definitions
) {
1033 ast
::ItemKind
::ForeignMod(ref fm
) => {
1034 self.process_foreign_mod(item
, fm
, definitions
)
1036 ast
::ItemKind
::ExternCrate(_
) => {
1037 let info
= self.extract_crate_info(item
).unwrap();
1038 let (cnum
, ..) = self.resolve_crate(
1039 &None
, info
.ident
, info
.name
, None
, item
.span
, PathKind
::Crate
, info
.dep_kind
,
1042 let def_id
= definitions
.opt_local_def_id(item
.id
).unwrap();
1043 let len
= definitions
.def_path(def_id
.index
).data
.len();
1046 ExternCrate { def_id: def_id, span: item.span, direct: true, path_len: len }
;
1047 self.update_extern_crate(cnum
, extern_crate
, &mut FxHashSet());
1048 self.cstore
.add_extern_mod_stmt_cnum(info
.id
, cnum
);