]>
Commit | Line | Data |
---|---|---|
1a4d82fc | 1 | // Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT |
223e47cc LB |
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 | ||
1a4d82fc | 11 | #![allow(non_camel_case_types)] |
223e47cc LB |
12 | |
13 | // The crate store - a central repo for information collected about external | |
14 | // crates and libraries | |
15 | ||
1a4d82fc JJ |
16 | pub use self::MetadataBlob::*; |
17 | pub use self::LinkagePreference::*; | |
18 | pub use self::NativeLibraryKind::*; | |
223e47cc | 19 | |
1a4d82fc | 20 | use back::svh::Svh; |
62682a34 | 21 | use metadata::{creader, decoder, loader}; |
85aaf69f | 22 | use session::search_paths::PathKind; |
1a4d82fc | 23 | use util::nodemap::{FnvHashMap, NodeMap}; |
223e47cc | 24 | |
62682a34 | 25 | use std::cell::{RefCell, Ref}; |
1a4d82fc | 26 | use std::rc::Rc; |
c34b1796 | 27 | use std::path::PathBuf; |
1a4d82fc | 28 | use flate::Bytes; |
223e47cc | 29 | use syntax::ast; |
c34b1796 | 30 | use syntax::codemap; |
1a4d82fc | 31 | use syntax::parse::token::IdentInterner; |
223e47cc LB |
32 | |
33 | // A map from external crate numbers (as decoded from some crate file) to | |
34 | // local crate numbers (as generated during this session). Each external | |
35 | // crate may refer to types in other external crates, and each has their | |
36 | // own crate numbers. | |
1a4d82fc | 37 | pub type cnum_map = FnvHashMap<ast::CrateNum, ast::CrateNum>; |
223e47cc | 38 | |
1a4d82fc JJ |
39 | pub enum MetadataBlob { |
40 | MetadataVec(Bytes), | |
41 | MetadataArchive(loader::ArchiveMetadata), | |
223e47cc LB |
42 | } |
43 | ||
c34b1796 AL |
44 | /// Holds information about a codemap::FileMap imported from another crate. |
45 | /// See creader::import_codemap() for more information. | |
46 | pub struct ImportedFileMap { | |
47 | /// This FileMap's byte-offset within the codemap of its original crate | |
48 | pub original_start_pos: codemap::BytePos, | |
49 | /// The end of this FileMap within the codemap of its original crate | |
50 | pub original_end_pos: codemap::BytePos, | |
51 | /// The imported FileMap's representation within the local codemap | |
52 | pub translated_filemap: Rc<codemap::FileMap> | |
53 | } | |
54 | ||
1a4d82fc JJ |
55 | pub struct crate_metadata { |
56 | pub name: String, | |
57 | pub data: MetadataBlob, | |
58 | pub cnum_map: cnum_map, | |
59 | pub cnum: ast::CrateNum, | |
62682a34 | 60 | pub codemap_import_info: RefCell<Vec<ImportedFileMap>>, |
c34b1796 | 61 | pub span: codemap::Span, |
223e47cc LB |
62 | } |
63 | ||
85aaf69f | 64 | #[derive(Copy, Debug, PartialEq, Clone)] |
1a4d82fc JJ |
65 | pub enum LinkagePreference { |
66 | RequireDynamic, | |
67 | RequireStatic, | |
223e47cc LB |
68 | } |
69 | ||
9346a6ac AL |
70 | enum_from_u32! { |
71 | #[derive(Copy, Clone, PartialEq)] | |
72 | pub enum NativeLibraryKind { | |
73 | NativeStatic, // native static library (.a archive) | |
74 | NativeFramework, // OSX-specific | |
75 | NativeUnknown, // default way to specify a dynamic library | |
76 | } | |
223e47cc LB |
77 | } |
78 | ||
1a4d82fc JJ |
79 | // Where a crate came from on the local filesystem. One of these two options |
80 | // must be non-None. | |
81 | #[derive(PartialEq, Clone)] | |
82 | pub struct CrateSource { | |
c34b1796 AL |
83 | pub dylib: Option<(PathBuf, PathKind)>, |
84 | pub rlib: Option<(PathBuf, PathKind)>, | |
1a4d82fc | 85 | pub cnum: ast::CrateNum, |
223e47cc LB |
86 | } |
87 | ||
1a4d82fc JJ |
88 | pub struct CStore { |
89 | metas: RefCell<FnvHashMap<ast::CrateNum, Rc<crate_metadata>>>, | |
90 | /// Map from NodeId's of local extern crate statements to crate numbers | |
91 | extern_mod_crate_map: RefCell<NodeMap<ast::CrateNum>>, | |
92 | used_crate_sources: RefCell<Vec<CrateSource>>, | |
93 | used_libraries: RefCell<Vec<(String, NativeLibraryKind)>>, | |
94 | used_link_args: RefCell<Vec<String>>, | |
95 | pub intr: Rc<IdentInterner>, | |
96 | } | |
97 | ||
98 | impl CStore { | |
99 | pub fn new(intr: Rc<IdentInterner>) -> CStore { | |
100 | CStore { | |
85aaf69f SL |
101 | metas: RefCell::new(FnvHashMap()), |
102 | extern_mod_crate_map: RefCell::new(FnvHashMap()), | |
1a4d82fc JJ |
103 | used_crate_sources: RefCell::new(Vec::new()), |
104 | used_libraries: RefCell::new(Vec::new()), | |
105 | used_link_args: RefCell::new(Vec::new()), | |
106 | intr: intr | |
107 | } | |
108 | } | |
223e47cc | 109 | |
1a4d82fc JJ |
110 | pub fn next_crate_num(&self) -> ast::CrateNum { |
111 | self.metas.borrow().len() as ast::CrateNum + 1 | |
112 | } | |
223e47cc | 113 | |
1a4d82fc | 114 | pub fn get_crate_data(&self, cnum: ast::CrateNum) -> Rc<crate_metadata> { |
c34b1796 | 115 | self.metas.borrow().get(&cnum).unwrap().clone() |
1a4d82fc | 116 | } |
223e47cc | 117 | |
1a4d82fc JJ |
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()) | |
223e47cc | 121 | } |
223e47cc | 122 | |
1a4d82fc JJ |
123 | pub fn set_crate_data(&self, cnum: ast::CrateNum, data: Rc<crate_metadata>) { |
124 | self.metas.borrow_mut().insert(cnum, data); | |
223e47cc | 125 | } |
223e47cc | 126 | |
1a4d82fc JJ |
127 | pub fn iter_crate_data<I>(&self, mut i: I) where |
128 | I: FnMut(ast::CrateNum, &crate_metadata), | |
129 | { | |
62682a34 | 130 | for (&k, v) in self.metas.borrow().iter() { |
1a4d82fc JJ |
131 | i(k, &**v); |
132 | } | |
133 | } | |
223e47cc | 134 | |
1a4d82fc JJ |
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 | { | |
62682a34 | 139 | for (&k, v) in self.metas.borrow().iter() { |
1a4d82fc JJ |
140 | let origin = self.get_used_crate_source(k); |
141 | origin.as_ref().map(|cs| { assert!(k == cs.cnum); }); | |
142 | i(k, &**v, origin); | |
143 | } | |
144 | } | |
223e47cc | 145 | |
1a4d82fc JJ |
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 | } | |
223e47cc | 152 | |
1a4d82fc JJ |
153 | pub fn get_used_crate_source(&self, cnum: ast::CrateNum) |
154 | -> Option<CrateSource> { | |
155 | self.used_crate_sources.borrow_mut() | |
85aaf69f | 156 | .iter().find(|source| source.cnum == cnum).cloned() |
1a4d82fc | 157 | } |
223e47cc | 158 | |
1a4d82fc JJ |
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(); | |
223e47cc | 165 | } |
223e47cc | 166 | |
1a4d82fc JJ |
167 | // This method is used when generating the command line to pass through to |
168 | // system linker. The linker expects undefined symbols on the left of the | |
169 | // command line to be defined in libraries on the right, not the other way | |
170 | // around. For more info, see some comments in the add_used_library function | |
171 | // below. | |
172 | // | |
173 | // In order to get this left-to-right dependency ordering, we perform a | |
174 | // topological sort of all crates putting the leaves at the right-most | |
175 | // positions. | |
176 | pub fn get_used_crates(&self, prefer: LinkagePreference) | |
c34b1796 | 177 | -> Vec<(ast::CrateNum, Option<PathBuf>)> { |
1a4d82fc JJ |
178 | let mut ordering = Vec::new(); |
179 | fn visit(cstore: &CStore, cnum: ast::CrateNum, | |
180 | ordering: &mut Vec<ast::CrateNum>) { | |
181 | if ordering.contains(&cnum) { return } | |
182 | let meta = cstore.get_crate_data(cnum); | |
85aaf69f | 183 | for (_, &dep) in &meta.cnum_map { |
1a4d82fc JJ |
184 | visit(cstore, dep, ordering); |
185 | } | |
186 | ordering.push(cnum); | |
187 | }; | |
62682a34 | 188 | for (&num, _) in self.metas.borrow().iter() { |
1a4d82fc JJ |
189 | visit(self, num, &mut ordering); |
190 | } | |
191 | ordering.reverse(); | |
192 | let mut libs = self.used_crate_sources.borrow() | |
193 | .iter() | |
194 | .map(|src| (src.cnum, match prefer { | |
85aaf69f SL |
195 | RequireDynamic => src.dylib.clone().map(|p| p.0), |
196 | RequireStatic => src.rlib.clone().map(|p| p.0), | |
1a4d82fc | 197 | })) |
85aaf69f | 198 | .collect::<Vec<_>>(); |
1a4d82fc JJ |
199 | libs.sort_by(|&(a, _), &(b, _)| { |
200 | ordering.position_elem(&a).cmp(&ordering.position_elem(&b)) | |
201 | }); | |
202 | libs | |
203 | } | |
223e47cc | 204 | |
1a4d82fc JJ |
205 | pub fn add_used_library(&self, lib: String, kind: NativeLibraryKind) { |
206 | assert!(!lib.is_empty()); | |
207 | self.used_libraries.borrow_mut().push((lib, kind)); | |
208 | } | |
223e47cc | 209 | |
1a4d82fc JJ |
210 | pub fn get_used_libraries<'a>(&'a self) |
211 | -> &'a RefCell<Vec<(String, | |
212 | NativeLibraryKind)>> { | |
213 | &self.used_libraries | |
214 | } | |
223e47cc | 215 | |
1a4d82fc JJ |
216 | pub fn add_used_link_args(&self, args: &str) { |
217 | for s in args.split(' ').filter(|s| !s.is_empty()) { | |
218 | self.used_link_args.borrow_mut().push(s.to_string()); | |
219 | } | |
220 | } | |
221 | ||
222 | pub fn get_used_link_args<'a>(&'a self) -> &'a RefCell<Vec<String> > { | |
223 | &self.used_link_args | |
223e47cc LB |
224 | } |
225 | ||
1a4d82fc JJ |
226 | pub fn add_extern_mod_stmt_cnum(&self, |
227 | emod_id: ast::NodeId, | |
228 | cnum: ast::CrateNum) { | |
229 | self.extern_mod_crate_map.borrow_mut().insert(emod_id, cnum); | |
230 | } | |
223e47cc | 231 | |
1a4d82fc JJ |
232 | pub fn find_extern_mod_stmt_cnum(&self, emod_id: ast::NodeId) |
233 | -> Option<ast::CrateNum> { | |
85aaf69f | 234 | self.extern_mod_crate_map.borrow().get(&emod_id).cloned() |
223e47cc | 235 | } |
1a4d82fc | 236 | } |
223e47cc | 237 | |
1a4d82fc JJ |
238 | impl crate_metadata { |
239 | pub fn data<'a>(&'a self) -> &'a [u8] { self.data.as_slice() } | |
240 | pub fn name(&self) -> String { decoder::get_crate_name(self.data()) } | |
241 | pub fn hash(&self) -> Svh { decoder::get_crate_hash(self.data()) } | |
62682a34 SL |
242 | pub fn imported_filemaps<'a>(&'a self, codemap: &codemap::CodeMap) |
243 | -> Ref<'a, Vec<ImportedFileMap>> { | |
244 | let filemaps = self.codemap_import_info.borrow(); | |
245 | if filemaps.is_empty() { | |
246 | drop(filemaps); | |
247 | let filemaps = creader::import_codemap(codemap, &self.data); | |
248 | ||
249 | // This shouldn't borrow twice, but there is no way to downgrade RefMut to Ref. | |
250 | *self.codemap_import_info.borrow_mut() = filemaps; | |
251 | self.codemap_import_info.borrow() | |
252 | } else { | |
253 | filemaps | |
254 | } | |
255 | } | |
1a4d82fc JJ |
256 | } |
257 | ||
258 | impl MetadataBlob { | |
259 | pub fn as_slice<'a>(&'a self) -> &'a [u8] { | |
260 | let slice = match *self { | |
c34b1796 | 261 | MetadataVec(ref vec) => &vec[..], |
1a4d82fc JJ |
262 | MetadataArchive(ref ar) => ar.as_slice(), |
263 | }; | |
264 | if slice.len() < 4 { | |
265 | &[] // corrupt metadata | |
266 | } else { | |
267 | let len = (((slice[0] as u32) << 24) | | |
268 | ((slice[1] as u32) << 16) | | |
269 | ((slice[2] as u32) << 8) | | |
c34b1796 | 270 | ((slice[3] as u32) << 0)) as usize; |
1a4d82fc | 271 | if len + 4 <= slice.len() { |
85aaf69f | 272 | &slice[4.. len + 4] |
1a4d82fc JJ |
273 | } else { |
274 | &[] // corrupt or old metadata | |
275 | } | |
276 | } | |
277 | } | |
223e47cc | 278 | } |