]> git.lizzy.rs Git - rust.git/blob - src/librustc/metadata/cstore.rs
Auto merge of #22517 - brson:relnotes, r=Gankro
[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 pub use self::LinkagePreference::*;
18 pub use self::NativeLibraryKind::*;
19
20 use back::svh::Svh;
21 use metadata::decoder;
22 use metadata::loader;
23 use session::search_paths::PathKind;
24 use util::nodemap::{FnvHashMap, NodeMap};
25
26 use std::cell::RefCell;
27 use std::rc::Rc;
28 use flate::Bytes;
29 use syntax::ast;
30 use syntax::codemap::Span;
31 use syntax::parse::token::IdentInterner;
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.
37 pub type cnum_map = FnvHashMap<ast::CrateNum, ast::CrateNum>;
38
39 pub enum MetadataBlob {
40     MetadataVec(Bytes),
41     MetadataArchive(loader::ArchiveMetadata),
42 }
43
44 pub struct crate_metadata {
45     pub name: String,
46     pub data: MetadataBlob,
47     pub cnum_map: cnum_map,
48     pub cnum: ast::CrateNum,
49     pub span: Span,
50 }
51
52 #[derive(Copy, Debug, PartialEq, Clone)]
53 pub enum LinkagePreference {
54     RequireDynamic,
55     RequireStatic,
56 }
57
58 #[derive(Copy, Clone, PartialEq, FromPrimitive)]
59 pub enum NativeLibraryKind {
60     NativeStatic,    // native static library (.a archive)
61     NativeFramework, // OSX-specific
62     NativeUnknown,   // default way to specify a dynamic library
63 }
64
65 // Where a crate came from on the local filesystem. One of these two options
66 // must be non-None.
67 #[derive(PartialEq, Clone)]
68 pub struct CrateSource {
69     pub dylib: Option<(Path, PathKind)>,
70     pub rlib: Option<(Path, PathKind)>,
71     pub cnum: ast::CrateNum,
72 }
73
74 pub struct CStore {
75     metas: RefCell<FnvHashMap<ast::CrateNum, Rc<crate_metadata>>>,
76     /// Map from NodeId's of local extern crate statements to crate numbers
77     extern_mod_crate_map: RefCell<NodeMap<ast::CrateNum>>,
78     used_crate_sources: RefCell<Vec<CrateSource>>,
79     used_libraries: RefCell<Vec<(String, NativeLibraryKind)>>,
80     used_link_args: RefCell<Vec<String>>,
81     pub intr: Rc<IdentInterner>,
82 }
83
84 impl CStore {
85     pub fn new(intr: Rc<IdentInterner>) -> CStore {
86         CStore {
87             metas: RefCell::new(FnvHashMap()),
88             extern_mod_crate_map: RefCell::new(FnvHashMap()),
89             used_crate_sources: RefCell::new(Vec::new()),
90             used_libraries: RefCell::new(Vec::new()),
91             used_link_args: RefCell::new(Vec::new()),
92             intr: intr
93         }
94     }
95
96     pub fn next_crate_num(&self) -> ast::CrateNum {
97         self.metas.borrow().len() as ast::CrateNum + 1
98     }
99
100     pub fn get_crate_data(&self, cnum: ast::CrateNum) -> Rc<crate_metadata> {
101         (*self.metas.borrow())[cnum].clone()
102     }
103
104     pub fn get_crate_hash(&self, cnum: ast::CrateNum) -> Svh {
105         let cdata = self.get_crate_data(cnum);
106         decoder::get_crate_hash(cdata.data())
107     }
108
109     pub fn set_crate_data(&self, cnum: ast::CrateNum, data: Rc<crate_metadata>) {
110         self.metas.borrow_mut().insert(cnum, data);
111     }
112
113     pub fn iter_crate_data<I>(&self, mut i: I) where
114         I: FnMut(ast::CrateNum, &crate_metadata),
115     {
116         for (&k, v) in &*self.metas.borrow() {
117             i(k, &**v);
118         }
119     }
120
121     /// Like `iter_crate_data`, but passes source paths (if available) as well.
122     pub fn iter_crate_data_origins<I>(&self, mut i: I) where
123         I: FnMut(ast::CrateNum, &crate_metadata, Option<CrateSource>),
124     {
125         for (&k, v) in &*self.metas.borrow() {
126             let origin = self.get_used_crate_source(k);
127             origin.as_ref().map(|cs| { assert!(k == cs.cnum); });
128             i(k, &**v, origin);
129         }
130     }
131
132     pub fn add_used_crate_source(&self, src: CrateSource) {
133         let mut used_crate_sources = self.used_crate_sources.borrow_mut();
134         if !used_crate_sources.contains(&src) {
135             used_crate_sources.push(src);
136         }
137     }
138
139     pub fn get_used_crate_source(&self, cnum: ast::CrateNum)
140                                      -> Option<CrateSource> {
141         self.used_crate_sources.borrow_mut()
142             .iter().find(|source| source.cnum == cnum)
143             .map(|source| source.clone())
144     }
145
146     pub fn reset(&self) {
147         self.metas.borrow_mut().clear();
148         self.extern_mod_crate_map.borrow_mut().clear();
149         self.used_crate_sources.borrow_mut().clear();
150         self.used_libraries.borrow_mut().clear();
151         self.used_link_args.borrow_mut().clear();
152     }
153
154     // This method is used when generating the command line to pass through to
155     // system linker. The linker expects undefined symbols on the left of the
156     // command line to be defined in libraries on the right, not the other way
157     // around. For more info, see some comments in the add_used_library function
158     // below.
159     //
160     // In order to get this left-to-right dependency ordering, we perform a
161     // topological sort of all crates putting the leaves at the right-most
162     // positions.
163     pub fn get_used_crates(&self, prefer: LinkagePreference)
164                            -> Vec<(ast::CrateNum, Option<Path>)> {
165         let mut ordering = Vec::new();
166         fn visit(cstore: &CStore, cnum: ast::CrateNum,
167                  ordering: &mut Vec<ast::CrateNum>) {
168             if ordering.contains(&cnum) { return }
169             let meta = cstore.get_crate_data(cnum);
170             for (_, &dep) in &meta.cnum_map {
171                 visit(cstore, dep, ordering);
172             }
173             ordering.push(cnum);
174         };
175         for (&num, _) in &*self.metas.borrow() {
176             visit(self, num, &mut ordering);
177         }
178         ordering.reverse();
179         let mut libs = self.used_crate_sources.borrow()
180             .iter()
181             .map(|src| (src.cnum, match prefer {
182                 RequireDynamic => src.dylib.clone().map(|p| p.0),
183                 RequireStatic => src.rlib.clone().map(|p| p.0),
184             }))
185             .collect::<Vec<_>>();
186         libs.sort_by(|&(a, _), &(b, _)| {
187             ordering.position_elem(&a).cmp(&ordering.position_elem(&b))
188         });
189         libs
190     }
191
192     pub fn add_used_library(&self, lib: String, kind: NativeLibraryKind) {
193         assert!(!lib.is_empty());
194         self.used_libraries.borrow_mut().push((lib, kind));
195     }
196
197     pub fn get_used_libraries<'a>(&'a self)
198                               -> &'a RefCell<Vec<(String,
199                                                   NativeLibraryKind)>> {
200         &self.used_libraries
201     }
202
203     pub fn add_used_link_args(&self, args: &str) {
204         for s in args.split(' ').filter(|s| !s.is_empty()) {
205             self.used_link_args.borrow_mut().push(s.to_string());
206         }
207     }
208
209     pub fn get_used_link_args<'a>(&'a self) -> &'a RefCell<Vec<String> > {
210         &self.used_link_args
211     }
212
213     pub fn add_extern_mod_stmt_cnum(&self,
214                                     emod_id: ast::NodeId,
215                                     cnum: ast::CrateNum) {
216         self.extern_mod_crate_map.borrow_mut().insert(emod_id, cnum);
217     }
218
219     pub fn find_extern_mod_stmt_cnum(&self, emod_id: ast::NodeId)
220                                      -> Option<ast::CrateNum> {
221         self.extern_mod_crate_map.borrow().get(&emod_id).map(|x| *x)
222     }
223 }
224
225 impl crate_metadata {
226     pub fn data<'a>(&'a self) -> &'a [u8] { self.data.as_slice() }
227     pub fn name(&self) -> String { decoder::get_crate_name(self.data()) }
228     pub fn hash(&self) -> Svh { decoder::get_crate_hash(self.data()) }
229 }
230
231 impl MetadataBlob {
232     pub fn as_slice<'a>(&'a self) -> &'a [u8] {
233         let slice = match *self {
234             MetadataVec(ref vec) => vec.as_slice(),
235             MetadataArchive(ref ar) => ar.as_slice(),
236         };
237         if slice.len() < 4 {
238             &[] // corrupt metadata
239         } else {
240             let len = (((slice[0] as u32) << 24) |
241                        ((slice[1] as u32) << 16) |
242                        ((slice[2] as u32) << 8) |
243                        ((slice[3] as u32) << 0)) as uint;
244             if len + 4 <= slice.len() {
245                 &slice[4.. len + 4]
246             } else {
247                 &[] // corrupt or old metadata
248             }
249         }
250     }
251 }