]> git.lizzy.rs Git - rust.git/blob - src/librustc_trans/back/symbol_export.rs
Change --crate-type metadata to --emit=metadata
[rust.git] / src / librustc_trans / back / symbol_export.rs
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.
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
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;
17 use syntax::attr;
18 use trans_item::TransItem;
19
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
24 /// dylib.
25 #[derive(Eq, PartialEq, Debug, Copy, Clone)]
26 pub enum SymbolExportLevel {
27     C,
28     Rust,
29 }
30
31 /// The set of symbols exported from each crate in the crate graph.
32 pub struct ExportedSymbols {
33     exports: FxHashMap<CrateNum, Vec<(String, SymbolExportLevel)>>,
34 }
35
36 impl ExportedSymbols {
37
38     pub fn empty() -> ExportedSymbols {
39         ExportedSymbols {
40             exports: FxHashMap(),
41         }
42     }
43
44     pub fn compute_from<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
45                                   symbol_map: &SymbolMap<'tcx>)
46                                   -> ExportedSymbols {
47         let mut local_crate: Vec<_> = scx
48             .exported_symbols()
49             .iter()
50             .map(|&node_id| {
51                 scx.tcx().map.local_def_id(node_id)
52             })
53             .map(|def_id| {
54                 let name = symbol_for_def_id(scx, def_id, symbol_map);
55                 let export_level = export_level(scx, def_id);
56                 debug!("EXPORTED SYMBOL (local): {} ({:?})", name, export_level);
57                 (name, export_level)
58             })
59             .collect();
60
61         if scx.sess().entry_fn.borrow().is_some() {
62             local_crate.push(("main".to_string(), SymbolExportLevel::C));
63         }
64
65         if let Some(id) = scx.sess().derive_registrar_fn.get() {
66             let svh = &scx.link_meta().crate_hash;
67             let def_id = scx.tcx().map.local_def_id(id);
68             let idx = def_id.index;
69             let registrar = scx.sess().generate_derive_registrar_symbol(svh, idx);
70             local_crate.push((registrar, SymbolExportLevel::C));
71         }
72
73         if scx.sess().crate_types.borrow().contains(&config::CrateTypeDylib) {
74             local_crate.push((scx.metadata_symbol_name(),
75                               SymbolExportLevel::Rust));
76         }
77
78         let mut exports = FxHashMap();
79         exports.insert(LOCAL_CRATE, local_crate);
80
81         for cnum in scx.sess().cstore.crates() {
82             debug_assert!(cnum != LOCAL_CRATE);
83
84             if scx.sess().cstore.plugin_registrar_fn(cnum).is_some() ||
85                scx.sess().cstore.derive_registrar_fn(cnum).is_some() {
86                 continue;
87             }
88
89             let crate_exports = scx
90                 .sess()
91                 .cstore
92                 .exported_symbols(cnum)
93                 .iter()
94                 .map(|&def_id| {
95                     let name = Instance::mono(scx, def_id).symbol_name(scx);
96                     let export_level = export_level(scx, def_id);
97                     debug!("EXPORTED SYMBOL (re-export): {} ({:?})", name, export_level);
98                     (name, export_level)
99                 })
100                 .collect();
101
102             exports.insert(cnum, crate_exports);
103         }
104
105         return ExportedSymbols {
106             exports: exports
107         };
108
109         fn export_level(scx: &SharedCrateContext,
110                         sym_def_id: DefId)
111                         -> SymbolExportLevel {
112             let attrs = scx.tcx().get_attrs(sym_def_id);
113             if attr::contains_extern_indicator(scx.sess().diagnostic(), &attrs) {
114                 SymbolExportLevel::C
115             } else {
116                 SymbolExportLevel::Rust
117             }
118         }
119     }
120
121     pub fn exported_symbols(&self,
122                             cnum: CrateNum)
123                             -> &[(String, SymbolExportLevel)] {
124         match self.exports.get(&cnum) {
125             Some(exports) => &exports[..],
126             None => &[]
127         }
128     }
129
130     pub fn for_each_exported_symbol<F>(&self,
131                                        cnum: CrateNum,
132                                        export_threshold: SymbolExportLevel,
133                                        mut f: F)
134         where F: FnMut(&str, SymbolExportLevel)
135     {
136         for &(ref name, export_level) in self.exported_symbols(cnum) {
137             if is_below_threshold(export_level, export_threshold) {
138                 f(&name[..], export_level)
139             }
140         }
141     }
142 }
143
144 pub fn crate_export_threshold(crate_type: config::CrateType)
145                                      -> SymbolExportLevel {
146     match crate_type {
147         config::CrateTypeExecutable |
148         config::CrateTypeStaticlib  |
149         config::CrateTypeProcMacro  |
150         config::CrateTypeCdylib     => SymbolExportLevel::C,
151         config::CrateTypeRlib       |
152         config::CrateTypeDylib      => SymbolExportLevel::Rust,
153     }
154 }
155
156 pub fn crates_export_threshold(crate_types: &[config::CrateType])
157                                       -> SymbolExportLevel {
158     if crate_types.iter().any(|&crate_type| {
159         crate_export_threshold(crate_type) == SymbolExportLevel::Rust
160     }) {
161         SymbolExportLevel::Rust
162     } else {
163         SymbolExportLevel::C
164     }
165 }
166
167 pub fn is_below_threshold(level: SymbolExportLevel,
168                           threshold: SymbolExportLevel)
169                           -> bool {
170     if threshold == SymbolExportLevel::Rust {
171         // We export everything from Rust dylibs
172         true
173     } else {
174         level == SymbolExportLevel::C
175     }
176 }
177
178 fn symbol_for_def_id<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
179                                def_id: DefId,
180                                symbol_map: &SymbolMap<'tcx>)
181                                -> String {
182     // Just try to look things up in the symbol map. If nothing's there, we
183     // recompute.
184     if let Some(node_id) = scx.tcx().map.as_local_node_id(def_id) {
185         if let Some(sym) = symbol_map.get(TransItem::Static(node_id)) {
186             return sym.to_owned();
187         }
188     }
189
190     let instance = Instance::mono(scx, def_id);
191
192     symbol_map.get(TransItem::Fn(instance))
193               .map(str::to_owned)
194               .unwrap_or_else(|| instance.symbol_name(scx))
195 }