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.
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 #![allow(non_camel_case_types)]
13 // The crate store - a central repo for information collected about external
14 // crates and libraries
16 pub use self::MetadataBlob::*;
17 pub use self::LinkagePreference::*;
18 pub use self::NativeLibraryKind::*;
21 use metadata::{creader, decoder, index, loader};
22 use session::search_paths::PathKind;
23 use util::nodemap::{FnvHashMap, NodeMap, NodeSet};
25 use std::cell::{RefCell, Ref, Cell};
27 use std::path::PathBuf;
32 use syntax::parse::token;
33 use syntax::parse::token::IdentInterner;
34 use syntax::util::small_vector::SmallVector;
35 use front::map as ast_map;
37 // A map from external crate numbers (as decoded from some crate file) to
38 // local crate numbers (as generated during this session). Each external
39 // crate may refer to types in other external crates, and each has their
41 pub type cnum_map = FnvHashMap<ast::CrateNum, ast::CrateNum>;
43 pub enum MetadataBlob {
45 MetadataArchive(loader::ArchiveMetadata),
48 /// Holds information about a codemap::FileMap imported from another crate.
49 /// See creader::import_codemap() for more information.
50 pub struct ImportedFileMap {
51 /// This FileMap's byte-offset within the codemap of its original crate
52 pub original_start_pos: codemap::BytePos,
53 /// The end of this FileMap within the codemap of its original crate
54 pub original_end_pos: codemap::BytePos,
55 /// The imported FileMap's representation within the local codemap
56 pub translated_filemap: Rc<codemap::FileMap>
59 pub struct crate_metadata {
61 pub local_path: RefCell<SmallVector<ast_map::PathElem>>,
62 pub data: MetadataBlob,
63 pub cnum_map: RefCell<cnum_map>,
64 pub cnum: ast::CrateNum,
65 pub codemap_import_info: RefCell<Vec<ImportedFileMap>>,
66 pub span: codemap::Span,
68 pub index: index::Index,
70 /// Flag if this crate is required by an rlib version of this crate, or in
71 /// other words whether it was explicitly linked to. An example of a crate
72 /// where this is false is when an allocator crate is injected into the
73 /// dependency list, and therefore isn't actually needed to link an rlib.
74 pub explicitly_linked: Cell<bool>,
77 #[derive(Copy, Debug, PartialEq, Clone)]
78 pub enum LinkagePreference {
84 #[derive(Copy, Clone, PartialEq)]
85 pub enum NativeLibraryKind {
86 NativeStatic, // native static library (.a archive)
87 NativeFramework, // OSX-specific
88 NativeUnknown, // default way to specify a dynamic library
92 // Where a crate came from on the local filesystem. One of these two options
94 #[derive(PartialEq, Clone)]
95 pub struct CrateSource {
96 pub dylib: Option<(PathBuf, PathKind)>,
97 pub rlib: Option<(PathBuf, PathKind)>,
98 pub cnum: ast::CrateNum,
102 metas: RefCell<FnvHashMap<ast::CrateNum, Rc<crate_metadata>>>,
103 /// Map from NodeId's of local extern crate statements to crate numbers
104 extern_mod_crate_map: RefCell<NodeMap<ast::CrateNum>>,
105 used_crate_sources: RefCell<Vec<CrateSource>>,
106 used_libraries: RefCell<Vec<(String, NativeLibraryKind)>>,
107 used_link_args: RefCell<Vec<String>>,
108 statically_included_foreign_items: RefCell<NodeSet>,
109 pub intr: Rc<IdentInterner>,
112 /// Item definitions in the currently-compiled crate would have the CrateNum
113 /// LOCAL_CRATE in their DefId.
114 pub const LOCAL_CRATE: ast::CrateNum = 0;
117 pub fn new(intr: Rc<IdentInterner>) -> CStore {
119 metas: RefCell::new(FnvHashMap()),
120 extern_mod_crate_map: RefCell::new(FnvHashMap()),
121 used_crate_sources: RefCell::new(Vec::new()),
122 used_libraries: RefCell::new(Vec::new()),
123 used_link_args: RefCell::new(Vec::new()),
125 statically_included_foreign_items: RefCell::new(NodeSet()),
129 pub fn next_crate_num(&self) -> ast::CrateNum {
130 self.metas.borrow().len() as ast::CrateNum + 1
133 pub fn get_crate_data(&self, cnum: ast::CrateNum) -> Rc<crate_metadata> {
134 self.metas.borrow().get(&cnum).unwrap().clone()
137 pub fn get_crate_hash(&self, cnum: ast::CrateNum) -> Svh {
138 let cdata = self.get_crate_data(cnum);
139 decoder::get_crate_hash(cdata.data())
142 pub fn set_crate_data(&self, cnum: ast::CrateNum, data: Rc<crate_metadata>) {
143 self.metas.borrow_mut().insert(cnum, data);
146 pub fn iter_crate_data<I>(&self, mut i: I) where
147 I: FnMut(ast::CrateNum, &Rc<crate_metadata>),
149 for (&k, v) in self.metas.borrow().iter() {
154 /// Like `iter_crate_data`, but passes source paths (if available) as well.
155 pub fn iter_crate_data_origins<I>(&self, mut i: I) where
156 I: FnMut(ast::CrateNum, &crate_metadata, Option<CrateSource>),
158 for (&k, v) in self.metas.borrow().iter() {
159 let origin = self.get_used_crate_source(k);
160 origin.as_ref().map(|cs| { assert!(k == cs.cnum); });
165 pub fn add_used_crate_source(&self, src: CrateSource) {
166 let mut used_crate_sources = self.used_crate_sources.borrow_mut();
167 if !used_crate_sources.contains(&src) {
168 used_crate_sources.push(src);
172 pub fn get_used_crate_source(&self, cnum: ast::CrateNum)
173 -> Option<CrateSource> {
174 self.used_crate_sources.borrow_mut()
175 .iter().find(|source| source.cnum == cnum).cloned()
178 pub fn reset(&self) {
179 self.metas.borrow_mut().clear();
180 self.extern_mod_crate_map.borrow_mut().clear();
181 self.used_crate_sources.borrow_mut().clear();
182 self.used_libraries.borrow_mut().clear();
183 self.used_link_args.borrow_mut().clear();
184 self.statically_included_foreign_items.borrow_mut().clear();
187 // This method is used when generating the command line to pass through to
188 // system linker. The linker expects undefined symbols on the left of the
189 // command line to be defined in libraries on the right, not the other way
190 // around. For more info, see some comments in the add_used_library function
193 // In order to get this left-to-right dependency ordering, we perform a
194 // topological sort of all crates putting the leaves at the right-most
196 pub fn get_used_crates(&self, prefer: LinkagePreference)
197 -> Vec<(ast::CrateNum, Option<PathBuf>)> {
198 let mut ordering = Vec::new();
199 fn visit(cstore: &CStore, cnum: ast::CrateNum,
200 ordering: &mut Vec<ast::CrateNum>) {
201 if ordering.contains(&cnum) { return }
202 let meta = cstore.get_crate_data(cnum);
203 for (_, &dep) in meta.cnum_map.borrow().iter() {
204 visit(cstore, dep, ordering);
208 for (&num, _) in self.metas.borrow().iter() {
209 visit(self, num, &mut ordering);
211 info!("topological ordering: {:?}", ordering);
213 let mut libs = self.used_crate_sources.borrow()
215 .map(|src| (src.cnum, match prefer {
216 RequireDynamic => src.dylib.clone().map(|p| p.0),
217 RequireStatic => src.rlib.clone().map(|p| p.0),
219 .collect::<Vec<_>>();
220 libs.sort_by(|&(a, _), &(b, _)| {
221 let a = ordering.iter().position(|x| *x == a);
222 let b = ordering.iter().position(|x| *x == b);
228 pub fn add_used_library(&self, lib: String, kind: NativeLibraryKind) {
229 assert!(!lib.is_empty());
230 self.used_libraries.borrow_mut().push((lib, kind));
233 pub fn get_used_libraries<'a>(&'a self)
234 -> &'a RefCell<Vec<(String,
235 NativeLibraryKind)>> {
239 pub fn add_used_link_args(&self, args: &str) {
240 for s in args.split(' ').filter(|s| !s.is_empty()) {
241 self.used_link_args.borrow_mut().push(s.to_string());
245 pub fn get_used_link_args<'a>(&'a self) -> &'a RefCell<Vec<String> > {
249 pub fn add_extern_mod_stmt_cnum(&self,
250 emod_id: ast::NodeId,
251 cnum: ast::CrateNum) {
252 self.extern_mod_crate_map.borrow_mut().insert(emod_id, cnum);
255 pub fn find_extern_mod_stmt_cnum(&self, emod_id: ast::NodeId)
256 -> Option<ast::CrateNum> {
257 self.extern_mod_crate_map.borrow().get(&emod_id).cloned()
260 pub fn add_statically_included_foreign_item(&self, id: ast::NodeId) {
261 self.statically_included_foreign_items.borrow_mut().insert(id);
264 pub fn is_statically_included_foreign_item(&self, id: ast::NodeId) -> bool {
265 self.statically_included_foreign_items.borrow().contains(&id)
269 impl crate_metadata {
270 pub fn data<'a>(&'a self) -> &'a [u8] { self.data.as_slice() }
271 pub fn name(&self) -> String { decoder::get_crate_name(self.data()) }
272 pub fn hash(&self) -> Svh { decoder::get_crate_hash(self.data()) }
273 pub fn imported_filemaps<'a>(&'a self, codemap: &codemap::CodeMap)
274 -> Ref<'a, Vec<ImportedFileMap>> {
275 let filemaps = self.codemap_import_info.borrow();
276 if filemaps.is_empty() {
278 let filemaps = creader::import_codemap(codemap, &self.data);
280 // This shouldn't borrow twice, but there is no way to downgrade RefMut to Ref.
281 *self.codemap_import_info.borrow_mut() = filemaps;
282 self.codemap_import_info.borrow()
288 pub fn with_local_path<T, F>(&self, f: F) -> T
289 where F: Fn(&[ast_map::PathElem]) -> T
291 let cpath = self.local_path.borrow();
292 if cpath.is_empty() {
293 let name = ast_map::PathMod(token::intern(&self.name));
300 pub fn update_local_path<'a, 'b>(&self, candidate: ast_map::PathElems<'a, 'b>) {
301 let mut cpath = self.local_path.borrow_mut();
302 let cap = cpath.len();
304 0 => *cpath = candidate.collect(),
307 let candidate: SmallVector<_> = candidate.collect();
308 if candidate.len() < cap {
315 pub fn is_allocator(&self) -> bool {
316 let attrs = decoder::get_crate_attributes(self.data());
317 attr::contains_name(&attrs, "allocator")
320 pub fn needs_allocator(&self) -> bool {
321 let attrs = decoder::get_crate_attributes(self.data());
322 attr::contains_name(&attrs, "needs_allocator")
327 pub fn as_slice<'a>(&'a self) -> &'a [u8] {
328 let slice = match *self {
329 MetadataVec(ref vec) => &vec[..],
330 MetadataArchive(ref ar) => ar.as_slice(),
333 &[] // corrupt metadata
335 let len = (((slice[0] as u32) << 24) |
336 ((slice[1] as u32) << 16) |
337 ((slice[2] as u32) << 8) |
338 ((slice[3] as u32) << 0)) as usize;
339 if len + 4 <= slice.len() {
342 &[] // corrupt or old metadata