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