]> git.lizzy.rs Git - rust.git/blob - src/librustc_metadata/cstore.rs
track the extern-crate def-id rather than path
[rust.git] / src / librustc_metadata / cstore.rs
1 // Copyright 2012-2014 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 #![allow(non_camel_case_types)]
12
13 // The crate store - a central repo for information collected about external
14 // crates and libraries
15
16 pub use self::MetadataBlob::*;
17
18 use creader;
19 use decoder;
20 use index;
21 use loader;
22
23 use rustc::back::svh::Svh;
24 use rustc::middle::cstore::{ExternCrate};
25 use rustc::util::nodemap::{FnvHashMap, NodeMap, NodeSet};
26
27 use std::cell::{RefCell, Ref, Cell};
28 use std::rc::Rc;
29 use std::path::PathBuf;
30 use flate::Bytes;
31 use syntax::ast;
32 use syntax::attr;
33 use syntax::codemap;
34 use syntax::parse::token::IdentInterner;
35
36 pub use middle::cstore::{NativeLibraryKind, LinkagePreference};
37 pub use middle::cstore::{NativeStatic, NativeFramework, NativeUnknown};
38 pub use middle::cstore::{CrateSource, LinkMeta};
39
40 // A map from external crate numbers (as decoded from some crate file) to
41 // local crate numbers (as generated during this session). Each external
42 // crate may refer to types in other external crates, and each has their
43 // own crate numbers.
44 pub type cnum_map = FnvHashMap<ast::CrateNum, ast::CrateNum>;
45
46 pub enum MetadataBlob {
47     MetadataVec(Bytes),
48     MetadataArchive(loader::ArchiveMetadata),
49 }
50
51 /// Holds information about a codemap::FileMap imported from another crate.
52 /// See creader::import_codemap() for more information.
53 pub struct ImportedFileMap {
54     /// This FileMap's byte-offset within the codemap of its original crate
55     pub original_start_pos: codemap::BytePos,
56     /// The end of this FileMap within the codemap of its original crate
57     pub original_end_pos: codemap::BytePos,
58     /// The imported FileMap's representation within the local codemap
59     pub translated_filemap: Rc<codemap::FileMap>
60 }
61
62 pub struct crate_metadata {
63     pub name: String,
64
65     /// Information about the extern crate that caused this crate to
66     /// be loaded. If this is `None`, then the crate was injected
67     /// (e.g., by the allocator)
68     pub extern_crate: Cell<Option<ExternCrate>>,
69
70     pub data: MetadataBlob,
71     pub cnum_map: RefCell<cnum_map>,
72     pub cnum: ast::CrateNum,
73     pub codemap_import_info: RefCell<Vec<ImportedFileMap>>,
74     pub staged_api: bool,
75
76     pub index: index::Index,
77     pub xref_index: index::DenseIndex,
78
79     /// Flag if this crate is required by an rlib version of this crate, or in
80     /// other words whether it was explicitly linked to. An example of a crate
81     /// where this is false is when an allocator crate is injected into the
82     /// dependency list, and therefore isn't actually needed to link an rlib.
83     pub explicitly_linked: Cell<bool>,
84 }
85
86 pub struct CStore {
87     metas: RefCell<FnvHashMap<ast::CrateNum, Rc<crate_metadata>>>,
88     /// Map from NodeId's of local extern crate statements to crate numbers
89     extern_mod_crate_map: RefCell<NodeMap<ast::CrateNum>>,
90     used_crate_sources: RefCell<Vec<CrateSource>>,
91     used_libraries: RefCell<Vec<(String, NativeLibraryKind)>>,
92     used_link_args: RefCell<Vec<String>>,
93     statically_included_foreign_items: RefCell<NodeSet>,
94     pub intr: Rc<IdentInterner>,
95 }
96
97 impl CStore {
98     pub fn new(intr: Rc<IdentInterner>) -> CStore {
99         CStore {
100             metas: RefCell::new(FnvHashMap()),
101             extern_mod_crate_map: RefCell::new(FnvHashMap()),
102             used_crate_sources: RefCell::new(Vec::new()),
103             used_libraries: RefCell::new(Vec::new()),
104             used_link_args: RefCell::new(Vec::new()),
105             intr: intr,
106             statically_included_foreign_items: RefCell::new(NodeSet()),
107         }
108     }
109
110     pub fn next_crate_num(&self) -> ast::CrateNum {
111         self.metas.borrow().len() as ast::CrateNum + 1
112     }
113
114     pub fn get_crate_data(&self, cnum: ast::CrateNum) -> Rc<crate_metadata> {
115         self.metas.borrow().get(&cnum).unwrap().clone()
116     }
117
118     pub fn get_crate_hash(&self, cnum: ast::CrateNum) -> Svh {
119         let cdata = self.get_crate_data(cnum);
120         decoder::get_crate_hash(cdata.data())
121     }
122
123     pub fn set_crate_data(&self, cnum: ast::CrateNum, data: Rc<crate_metadata>) {
124         self.metas.borrow_mut().insert(cnum, data);
125     }
126
127     pub fn iter_crate_data<I>(&self, mut i: I) where
128         I: FnMut(ast::CrateNum, &Rc<crate_metadata>),
129     {
130         for (&k, v) in self.metas.borrow().iter() {
131             i(k, v);
132         }
133     }
134
135     /// Like `iter_crate_data`, but passes source paths (if available) as well.
136     pub fn iter_crate_data_origins<I>(&self, mut i: I) where
137         I: FnMut(ast::CrateNum, &crate_metadata, Option<CrateSource>),
138     {
139         for (&k, v) in self.metas.borrow().iter() {
140             let origin = self.opt_used_crate_source(k);
141             origin.as_ref().map(|cs| { assert!(k == cs.cnum); });
142             i(k, &v, origin);
143         }
144     }
145
146     pub fn add_used_crate_source(&self, src: CrateSource) {
147         let mut used_crate_sources = self.used_crate_sources.borrow_mut();
148         if !used_crate_sources.contains(&src) {
149             used_crate_sources.push(src);
150         }
151     }
152
153     pub fn opt_used_crate_source(&self, cnum: ast::CrateNum)
154                                  -> Option<CrateSource> {
155         self.used_crate_sources.borrow_mut()
156             .iter().find(|source| source.cnum == cnum).cloned()
157     }
158
159     pub fn reset(&self) {
160         self.metas.borrow_mut().clear();
161         self.extern_mod_crate_map.borrow_mut().clear();
162         self.used_crate_sources.borrow_mut().clear();
163         self.used_libraries.borrow_mut().clear();
164         self.used_link_args.borrow_mut().clear();
165         self.statically_included_foreign_items.borrow_mut().clear();
166     }
167
168     // This method is used when generating the command line to pass through to
169     // system linker. The linker expects undefined symbols on the left of the
170     // command line to be defined in libraries on the right, not the other way
171     // around. For more info, see some comments in the add_used_library function
172     // below.
173     //
174     // In order to get this left-to-right dependency ordering, we perform a
175     // topological sort of all crates putting the leaves at the right-most
176     // positions.
177     pub fn do_get_used_crates(&self, prefer: LinkagePreference)
178                               -> Vec<(ast::CrateNum, Option<PathBuf>)> {
179         let mut ordering = Vec::new();
180         fn visit(cstore: &CStore, cnum: ast::CrateNum,
181                  ordering: &mut Vec<ast::CrateNum>) {
182             if ordering.contains(&cnum) { return }
183             let meta = cstore.get_crate_data(cnum);
184             for (_, &dep) in meta.cnum_map.borrow().iter() {
185                 visit(cstore, dep, ordering);
186             }
187             ordering.push(cnum);
188         }
189         for (&num, _) in self.metas.borrow().iter() {
190             visit(self, num, &mut ordering);
191         }
192         info!("topological ordering: {:?}", ordering);
193         ordering.reverse();
194         let mut libs = self.used_crate_sources.borrow()
195             .iter()
196             .map(|src| (src.cnum, match prefer {
197                 LinkagePreference::RequireDynamic => src.dylib.clone().map(|p| p.0),
198                 LinkagePreference::RequireStatic => src.rlib.clone().map(|p| p.0),
199             }))
200             .collect::<Vec<_>>();
201         libs.sort_by(|&(a, _), &(b, _)| {
202             let a = ordering.iter().position(|x| *x == a);
203             let b = ordering.iter().position(|x| *x == b);
204             a.cmp(&b)
205         });
206         libs
207     }
208
209     pub fn add_used_library(&self, lib: String, kind: NativeLibraryKind) {
210         assert!(!lib.is_empty());
211         self.used_libraries.borrow_mut().push((lib, kind));
212     }
213
214     pub fn get_used_libraries<'a>(&'a self)
215                               -> &'a RefCell<Vec<(String,
216                                                   NativeLibraryKind)>> {
217         &self.used_libraries
218     }
219
220     pub fn add_used_link_args(&self, args: &str) {
221         for s in args.split(' ').filter(|s| !s.is_empty()) {
222             self.used_link_args.borrow_mut().push(s.to_string());
223         }
224     }
225
226     pub fn get_used_link_args<'a>(&'a self) -> &'a RefCell<Vec<String> > {
227         &self.used_link_args
228     }
229
230     pub fn add_extern_mod_stmt_cnum(&self,
231                                     emod_id: ast::NodeId,
232                                     cnum: ast::CrateNum) {
233         self.extern_mod_crate_map.borrow_mut().insert(emod_id, cnum);
234     }
235
236     pub fn add_statically_included_foreign_item(&self, id: ast::NodeId) {
237         self.statically_included_foreign_items.borrow_mut().insert(id);
238     }
239
240     pub fn do_is_statically_included_foreign_item(&self, id: ast::NodeId) -> bool {
241         self.statically_included_foreign_items.borrow().contains(&id)
242     }
243
244     pub fn do_extern_mod_stmt_cnum(&self, emod_id: ast::NodeId) -> Option<ast::CrateNum>
245     {
246         self.extern_mod_crate_map.borrow().get(&emod_id).cloned()
247     }
248 }
249
250 impl crate_metadata {
251     pub fn data<'a>(&'a self) -> &'a [u8] { self.data.as_slice() }
252     pub fn name(&self) -> &str { decoder::get_crate_name(self.data()) }
253     pub fn hash(&self) -> Svh { decoder::get_crate_hash(self.data()) }
254     pub fn disambiguator(&self) -> &str {
255         decoder::get_crate_disambiguator(self.data())
256     }
257     pub fn imported_filemaps<'a>(&'a self, codemap: &codemap::CodeMap)
258                                  -> Ref<'a, Vec<ImportedFileMap>> {
259         let filemaps = self.codemap_import_info.borrow();
260         if filemaps.is_empty() {
261             drop(filemaps);
262             let filemaps = creader::import_codemap(codemap, &self.data);
263
264             // This shouldn't borrow twice, but there is no way to downgrade RefMut to Ref.
265             *self.codemap_import_info.borrow_mut() = filemaps;
266             self.codemap_import_info.borrow()
267         } else {
268             filemaps
269         }
270     }
271
272     pub fn is_allocator(&self) -> bool {
273         let attrs = decoder::get_crate_attributes(self.data());
274         attr::contains_name(&attrs, "allocator")
275     }
276
277     pub fn needs_allocator(&self) -> bool {
278         let attrs = decoder::get_crate_attributes(self.data());
279         attr::contains_name(&attrs, "needs_allocator")
280     }
281 }
282
283 impl MetadataBlob {
284     pub fn as_slice<'a>(&'a self) -> &'a [u8] {
285         let slice = match *self {
286             MetadataVec(ref vec) => &vec[..],
287             MetadataArchive(ref ar) => ar.as_slice(),
288         };
289         if slice.len() < 4 {
290             &[] // corrupt metadata
291         } else {
292             let len = (((slice[0] as u32) << 24) |
293                        ((slice[1] as u32) << 16) |
294                        ((slice[2] as u32) << 8) |
295                        ((slice[3] as u32) << 0)) as usize;
296             if len + 4 <= slice.len() {
297                 &slice[4.. len + 4]
298             } else {
299                 &[] // corrupt or old metadata
300             }
301         }
302     }
303 }