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::decoder;
23 use util::nodemap::{FnvHashMap, NodeMap};
25 use std::cell::RefCell;
29 use syntax::codemap::Span;
30 use syntax::parse::token::IdentInterner;
32 // A map from external crate numbers (as decoded from some crate file) to
33 // local crate numbers (as generated during this session). Each external
34 // crate may refer to types in other external crates, and each has their
36 pub type cnum_map = FnvHashMap<ast::CrateNum, ast::CrateNum>;
38 pub enum MetadataBlob {
39 MetadataVec(CVec<u8>),
40 MetadataArchive(loader::ArchiveMetadata),
43 pub struct crate_metadata {
45 pub data: MetadataBlob,
46 pub cnum_map: cnum_map,
47 pub cnum: ast::CrateNum,
51 #[deriving(Copy, Show, PartialEq, Clone)]
52 pub enum LinkagePreference {
57 #[deriving(Copy, Clone, PartialEq, FromPrimitive)]
58 pub enum NativeLibraryKind {
59 NativeStatic, // native static library (.a archive)
60 NativeFramework, // OSX-specific
61 NativeUnknown, // default way to specify a dynamic library
64 // Where a crate came from on the local filesystem. One of these two options
66 #[deriving(PartialEq, Clone)]
67 pub struct CrateSource {
68 pub dylib: Option<Path>,
69 pub rlib: Option<Path>,
70 pub cnum: ast::CrateNum,
74 metas: RefCell<FnvHashMap<ast::CrateNum, Rc<crate_metadata>>>,
75 /// Map from NodeId's of local extern crate statements to crate numbers
76 extern_mod_crate_map: RefCell<NodeMap<ast::CrateNum>>,
77 used_crate_sources: RefCell<Vec<CrateSource>>,
78 used_libraries: RefCell<Vec<(String, NativeLibraryKind)>>,
79 used_link_args: RefCell<Vec<String>>,
80 pub intr: Rc<IdentInterner>,
84 pub fn new(intr: Rc<IdentInterner>) -> CStore {
86 metas: RefCell::new(FnvHashMap::new()),
87 extern_mod_crate_map: RefCell::new(FnvHashMap::new()),
88 used_crate_sources: RefCell::new(Vec::new()),
89 used_libraries: RefCell::new(Vec::new()),
90 used_link_args: RefCell::new(Vec::new()),
95 pub fn next_crate_num(&self) -> ast::CrateNum {
96 self.metas.borrow().len() as ast::CrateNum + 1
99 pub fn get_crate_data(&self, cnum: ast::CrateNum) -> Rc<crate_metadata> {
100 (*self.metas.borrow())[cnum].clone()
103 pub fn get_crate_hash(&self, cnum: ast::CrateNum) -> Svh {
104 let cdata = self.get_crate_data(cnum);
105 decoder::get_crate_hash(cdata.data())
108 pub fn set_crate_data(&self, cnum: ast::CrateNum, data: Rc<crate_metadata>) {
109 self.metas.borrow_mut().insert(cnum, data);
112 pub fn iter_crate_data<I>(&self, mut i: I) where
113 I: FnMut(ast::CrateNum, &crate_metadata),
115 for (&k, v) in self.metas.borrow().iter() {
120 /// Like `iter_crate_data`, but passes source paths (if available) as well.
121 pub fn iter_crate_data_origins<I>(&self, mut i: I) where
122 I: FnMut(ast::CrateNum, &crate_metadata, Option<CrateSource>),
124 for (&k, v) in self.metas.borrow().iter() {
125 let origin = self.get_used_crate_source(k);
126 origin.as_ref().map(|cs| { assert!(k == cs.cnum); });
131 pub fn add_used_crate_source(&self, src: CrateSource) {
132 let mut used_crate_sources = self.used_crate_sources.borrow_mut();
133 if !used_crate_sources.contains(&src) {
134 used_crate_sources.push(src);
138 pub fn get_used_crate_source(&self, cnum: ast::CrateNum)
139 -> Option<CrateSource> {
140 self.used_crate_sources.borrow_mut()
141 .iter().find(|source| source.cnum == cnum)
142 .map(|source| source.clone())
145 pub fn reset(&self) {
146 self.metas.borrow_mut().clear();
147 self.extern_mod_crate_map.borrow_mut().clear();
148 self.used_crate_sources.borrow_mut().clear();
149 self.used_libraries.borrow_mut().clear();
150 self.used_link_args.borrow_mut().clear();
153 // This method is used when generating the command line to pass through to
154 // system linker. The linker expects undefined symbols on the left of the
155 // command line to be defined in libraries on the right, not the other way
156 // around. For more info, see some comments in the add_used_library function
159 // In order to get this left-to-right dependency ordering, we perform a
160 // topological sort of all crates putting the leaves at the right-most
162 pub fn get_used_crates(&self, prefer: LinkagePreference)
163 -> Vec<(ast::CrateNum, Option<Path>)> {
164 let mut ordering = Vec::new();
165 fn visit(cstore: &CStore, cnum: ast::CrateNum,
166 ordering: &mut Vec<ast::CrateNum>) {
167 if ordering.contains(&cnum) { return }
168 let meta = cstore.get_crate_data(cnum);
169 for (_, &dep) in meta.cnum_map.iter() {
170 visit(cstore, dep, ordering);
174 for (&num, _) in self.metas.borrow().iter() {
175 visit(self, num, &mut ordering);
178 let mut libs = self.used_crate_sources.borrow()
180 .map(|src| (src.cnum, match prefer {
181 RequireDynamic => src.dylib.clone(),
182 RequireStatic => src.rlib.clone(),
184 .collect::<Vec<(ast::CrateNum, Option<Path>)>>();
185 libs.sort_by(|&(a, _), &(b, _)| {
186 ordering.position_elem(&a).cmp(&ordering.position_elem(&b))
191 pub fn add_used_library(&self, lib: String, kind: NativeLibraryKind) {
192 assert!(!lib.is_empty());
193 self.used_libraries.borrow_mut().push((lib, kind));
196 pub fn get_used_libraries<'a>(&'a self)
197 -> &'a RefCell<Vec<(String,
198 NativeLibraryKind)>> {
202 pub fn add_used_link_args(&self, args: &str) {
203 for s in args.split(' ').filter(|s| !s.is_empty()) {
204 self.used_link_args.borrow_mut().push(s.to_string());
208 pub fn get_used_link_args<'a>(&'a self) -> &'a RefCell<Vec<String> > {
212 pub fn add_extern_mod_stmt_cnum(&self,
213 emod_id: ast::NodeId,
214 cnum: ast::CrateNum) {
215 self.extern_mod_crate_map.borrow_mut().insert(emod_id, cnum);
218 pub fn find_extern_mod_stmt_cnum(&self, emod_id: ast::NodeId)
219 -> Option<ast::CrateNum> {
220 self.extern_mod_crate_map.borrow().get(&emod_id).map(|x| *x)
224 impl crate_metadata {
225 pub fn data<'a>(&'a self) -> &'a [u8] { self.data.as_slice() }
226 pub fn name(&self) -> String { decoder::get_crate_name(self.data()) }
227 pub fn hash(&self) -> Svh { decoder::get_crate_hash(self.data()) }
231 pub fn as_slice<'a>(&'a self) -> &'a [u8] {
232 let slice = match *self {
233 MetadataVec(ref vec) => vec.as_slice(),
234 MetadataArchive(ref ar) => ar.as_slice(),
237 &[] // corrupt metadata
239 let len = (((slice[0] as u32) << 24) |
240 ((slice[1] as u32) << 16) |
241 ((slice[2] as u32) << 8) |
242 ((slice[3] as u32) << 0)) as uint;
243 if len + 4 <= slice.len() {
244 slice.slice(4, len + 4)
246 &[] // corrupt or old metadata