1 // Copyright 2016 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 use context::SharedCrateContext;
12 use monomorphize::Instance;
13 use symbol_map::SymbolMap;
14 use util::nodemap::FxHashMap;
15 use rustc::hir::def_id::{DefId, CrateNum, LOCAL_CRATE};
16 use rustc::session::config;
18 use trans_item::TransItem;
20 /// The SymbolExportLevel of a symbols specifies from which kinds of crates
21 /// the symbol will be exported. `C` symbols will be exported from any
22 /// kind of crate, including cdylibs which export very few things.
23 /// `Rust` will only be exported if the crate produced is a Rust
25 #[derive(Eq, PartialEq, Debug, Copy, Clone)]
26 pub enum SymbolExportLevel {
31 /// The set of symbols exported from each crate in the crate graph.
32 pub struct ExportedSymbols {
33 exports: FxHashMap<CrateNum, Vec<(String, SymbolExportLevel)>>,
36 impl ExportedSymbols {
38 pub fn empty() -> ExportedSymbols {
44 pub fn compute_from<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
45 symbol_map: &SymbolMap<'tcx>)
47 let mut local_crate: Vec<_> = scx
51 scx.tcx().map.local_def_id(node_id)
54 (symbol_for_def_id(scx, def_id, symbol_map),
55 export_level(scx, def_id))
59 if scx.sess().entry_fn.borrow().is_some() {
60 local_crate.push(("main".to_string(), SymbolExportLevel::C));
63 if scx.sess().crate_types.borrow().contains(&config::CrateTypeDylib) {
64 local_crate.push((scx.metadata_symbol_name(),
65 SymbolExportLevel::Rust));
68 let mut exports = FxHashMap();
69 exports.insert(LOCAL_CRATE, local_crate);
71 for cnum in scx.sess().cstore.crates() {
72 debug_assert!(cnum != LOCAL_CRATE);
74 if scx.sess().cstore.plugin_registrar_fn(cnum).is_some() ||
75 scx.sess().cstore.derive_registrar_fn(cnum).is_some() {
79 let crate_exports = scx
82 .exported_symbols(cnum)
85 debug!("EXTERN-SYMBOL: {:?}", def_id);
86 let name = Instance::mono(scx, def_id).symbol_name(scx);
87 (name, export_level(scx, def_id))
91 exports.insert(cnum, crate_exports);
94 return ExportedSymbols {
98 fn export_level(scx: &SharedCrateContext,
100 -> SymbolExportLevel {
101 let attrs = scx.tcx().get_attrs(sym_def_id);
102 if attr::contains_extern_indicator(scx.sess().diagnostic(), &attrs) {
105 SymbolExportLevel::Rust
110 pub fn exported_symbols(&self,
112 -> &[(String, SymbolExportLevel)] {
113 match self.exports.get(&cnum) {
114 Some(exports) => &exports[..],
119 pub fn for_each_exported_symbol<F>(&self,
121 export_threshold: SymbolExportLevel,
123 where F: FnMut(&str, SymbolExportLevel)
125 for &(ref name, export_level) in self.exported_symbols(cnum) {
126 if is_below_threshold(export_level, export_threshold) {
127 f(&name[..], export_level)
133 pub fn crate_export_threshold(crate_type: config::CrateType)
134 -> SymbolExportLevel {
136 config::CrateTypeExecutable |
137 config::CrateTypeStaticlib |
138 config::CrateTypeCdylib => SymbolExportLevel::C,
139 config::CrateTypeProcMacro |
140 config::CrateTypeRlib |
141 config::CrateTypeMetadata |
142 config::CrateTypeDylib => SymbolExportLevel::Rust,
146 pub fn crates_export_threshold(crate_types: &[config::CrateType])
147 -> SymbolExportLevel {
148 if crate_types.iter().any(|&crate_type| {
149 crate_export_threshold(crate_type) == SymbolExportLevel::Rust
151 SymbolExportLevel::Rust
157 pub fn is_below_threshold(level: SymbolExportLevel,
158 threshold: SymbolExportLevel)
160 if threshold == SymbolExportLevel::Rust {
161 // We export everything from Rust dylibs
164 level == SymbolExportLevel::C
168 fn symbol_for_def_id<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
170 symbol_map: &SymbolMap<'tcx>)
172 // Just try to look things up in the symbol map. If nothing's there, we
174 if let Some(node_id) = scx.tcx().map.as_local_node_id(def_id) {
175 if let Some(sym) = symbol_map.get(TransItem::Static(node_id)) {
176 return sym.to_owned();
180 let instance = Instance::mono(scx, def_id);
182 symbol_map.get(TransItem::Fn(instance))
184 .unwrap_or_else(|| instance.symbol_name(scx))