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
::*;
23 use rustc
::back
::svh
::Svh
;
24 use rustc
::front
::map
as ast_map
;
25 use rustc
::util
::nodemap
::{FnvHashMap, NodeMap, NodeSet}
;
27 use std
::cell
::{RefCell, Ref, Cell}
;
29 use std
::path
::PathBuf
;
34 use syntax
::parse
::token
;
35 use syntax
::parse
::token
::IdentInterner
;
36 use syntax
::util
::small_vector
::SmallVector
;
38 pub use middle
::cstore
::{NativeLibraryKind, LinkagePreference}
;
39 pub use middle
::cstore
::{NativeStatic, NativeFramework, NativeUnknown}
;
40 pub use middle
::cstore
::{CrateSource, LinkMeta}
;
42 // A map from external crate numbers (as decoded from some crate file) to
43 // local crate numbers (as generated during this session). Each external
44 // crate may refer to types in other external crates, and each has their
46 pub type cnum_map
= FnvHashMap
<ast
::CrateNum
, ast
::CrateNum
>;
48 pub enum MetadataBlob
{
50 MetadataArchive(loader
::ArchiveMetadata
),
53 /// Holds information about a codemap::FileMap imported from another crate.
54 /// See creader::import_codemap() for more information.
55 pub struct ImportedFileMap
{
56 /// This FileMap's byte-offset within the codemap of its original crate
57 pub original_start_pos
: codemap
::BytePos
,
58 /// The end of this FileMap within the codemap of its original crate
59 pub original_end_pos
: codemap
::BytePos
,
60 /// The imported FileMap's representation within the local codemap
61 pub translated_filemap
: Rc
<codemap
::FileMap
>
64 pub struct crate_metadata
{
66 pub local_path
: RefCell
<SmallVector
<ast_map
::PathElem
>>,
67 pub local_def_path
: RefCell
<ast_map
::DefPath
>,
68 pub data
: MetadataBlob
,
69 pub cnum_map
: RefCell
<cnum_map
>,
70 pub cnum
: ast
::CrateNum
,
71 pub codemap_import_info
: RefCell
<Vec
<ImportedFileMap
>>,
72 pub span
: codemap
::Span
,
75 pub index
: index
::Index
,
76 pub xref_index
: index
::DenseIndex
,
78 /// Flag if this crate is required by an rlib version of this crate, or in
79 /// other words whether it was explicitly linked to. An example of a crate
80 /// where this is false is when an allocator crate is injected into the
81 /// dependency list, and therefore isn't actually needed to link an rlib.
82 pub explicitly_linked
: Cell
<bool
>,
86 metas
: RefCell
<FnvHashMap
<ast
::CrateNum
, Rc
<crate_metadata
>>>,
87 /// Map from NodeId's of local extern crate statements to crate numbers
88 extern_mod_crate_map
: RefCell
<NodeMap
<ast
::CrateNum
>>,
89 used_crate_sources
: RefCell
<Vec
<CrateSource
>>,
90 used_libraries
: RefCell
<Vec
<(String
, NativeLibraryKind
)>>,
91 used_link_args
: RefCell
<Vec
<String
>>,
92 statically_included_foreign_items
: RefCell
<NodeSet
>,
93 pub intr
: Rc
<IdentInterner
>,
97 pub fn new(intr
: Rc
<IdentInterner
>) -> CStore
{
99 metas
: RefCell
::new(FnvHashMap()),
100 extern_mod_crate_map
: RefCell
::new(FnvHashMap()),
101 used_crate_sources
: RefCell
::new(Vec
::new()),
102 used_libraries
: RefCell
::new(Vec
::new()),
103 used_link_args
: RefCell
::new(Vec
::new()),
105 statically_included_foreign_items
: RefCell
::new(NodeSet()),
109 pub fn next_crate_num(&self) -> ast
::CrateNum
{
110 self.metas
.borrow().len() as ast
::CrateNum
+ 1
113 pub fn get_crate_data(&self, cnum
: ast
::CrateNum
) -> Rc
<crate_metadata
> {
114 self.metas
.borrow().get(&cnum
).unwrap().clone()
117 pub fn get_crate_hash(&self, cnum
: ast
::CrateNum
) -> Svh
{
118 let cdata
= self.get_crate_data(cnum
);
119 decoder
::get_crate_hash(cdata
.data())
122 pub fn set_crate_data(&self, cnum
: ast
::CrateNum
, data
: Rc
<crate_metadata
>) {
123 self.metas
.borrow_mut().insert(cnum
, data
);
126 pub fn iter_crate_data
<I
>(&self, mut i
: I
) where
127 I
: FnMut(ast
::CrateNum
, &Rc
<crate_metadata
>),
129 for (&k
, v
) in self.metas
.borrow().iter() {
134 /// Like `iter_crate_data`, but passes source paths (if available) as well.
135 pub fn iter_crate_data_origins
<I
>(&self, mut i
: I
) where
136 I
: FnMut(ast
::CrateNum
, &crate_metadata
, Option
<CrateSource
>),
138 for (&k
, v
) in self.metas
.borrow().iter() {
139 let origin
= self.opt_used_crate_source(k
);
140 origin
.as_ref().map(|cs
| { assert!(k == cs.cnum); }
);
145 pub fn add_used_crate_source(&self, src
: CrateSource
) {
146 let mut used_crate_sources
= self.used_crate_sources
.borrow_mut();
147 if !used_crate_sources
.contains(&src
) {
148 used_crate_sources
.push(src
);
152 pub fn opt_used_crate_source(&self, cnum
: ast
::CrateNum
)
153 -> Option
<CrateSource
> {
154 self.used_crate_sources
.borrow_mut()
155 .iter().find(|source
| source
.cnum
== cnum
).cloned()
158 pub fn reset(&self) {
159 self.metas
.borrow_mut().clear();
160 self.extern_mod_crate_map
.borrow_mut().clear();
161 self.used_crate_sources
.borrow_mut().clear();
162 self.used_libraries
.borrow_mut().clear();
163 self.used_link_args
.borrow_mut().clear();
164 self.statically_included_foreign_items
.borrow_mut().clear();
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
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
176 pub fn do_get_used_crates(&self, prefer
: LinkagePreference
)
177 -> Vec
<(ast
::CrateNum
, Option
<PathBuf
>)> {
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
);
183 for (_
, &dep
) in meta
.cnum_map
.borrow().iter() {
184 visit(cstore
, dep
, ordering
);
188 for (&num
, _
) in self.metas
.borrow().iter() {
189 visit(self, num
, &mut ordering
);
191 info
!("topological ordering: {:?}", ordering
);
193 let mut libs
= self.used_crate_sources
.borrow()
195 .map(|src
| (src
.cnum
, match prefer
{
196 LinkagePreference
::RequireDynamic
=> src
.dylib
.clone().map(|p
| p
.0),
197 LinkagePreference
::RequireStatic
=> src
.rlib
.clone().map(|p
| p
.0),
199 .collect
::<Vec
<_
>>();
200 libs
.sort_by(|&(a
, _
), &(b
, _
)| {
201 let a
= ordering
.iter().position(|x
| *x
== a
);
202 let b
= ordering
.iter().position(|x
| *x
== b
);
208 pub fn add_used_library(&self, lib
: String
, kind
: NativeLibraryKind
) {
209 assert
!(!lib
.is_empty());
210 self.used_libraries
.borrow_mut().push((lib
, kind
));
213 pub fn get_used_libraries
<'a
>(&'a
self)
214 -> &'a RefCell
<Vec
<(String
,
215 NativeLibraryKind
)>> {
219 pub fn add_used_link_args(&self, args
: &str) {
220 for s
in args
.split(' '
).filter(|s
| !s
.is_empty()) {
221 self.used_link_args
.borrow_mut().push(s
.to_string());
225 pub fn get_used_link_args
<'a
>(&'a
self) -> &'a RefCell
<Vec
<String
> > {
229 pub fn add_extern_mod_stmt_cnum(&self,
230 emod_id
: ast
::NodeId
,
231 cnum
: ast
::CrateNum
) {
232 self.extern_mod_crate_map
.borrow_mut().insert(emod_id
, cnum
);
235 pub fn add_statically_included_foreign_item(&self, id
: ast
::NodeId
) {
236 self.statically_included_foreign_items
.borrow_mut().insert(id
);
239 pub fn do_is_statically_included_foreign_item(&self, id
: ast
::NodeId
) -> bool
{
240 self.statically_included_foreign_items
.borrow().contains(&id
)
243 pub fn do_extern_mod_stmt_cnum(&self, emod_id
: ast
::NodeId
) -> Option
<ast
::CrateNum
>
245 self.extern_mod_crate_map
.borrow().get(&emod_id
).cloned()
249 impl crate_metadata
{
250 pub fn data
<'a
>(&'a
self) -> &'a
[u8] { self.data.as_slice() }
251 pub fn name(&self) -> String { decoder::get_crate_name(self.data()) }
252 pub fn hash(&self) -> Svh { decoder::get_crate_hash(self.data()) }
253 pub fn imported_filemaps
<'a
>(&'a
self, codemap
: &codemap
::CodeMap
)
254 -> Ref
<'a
, Vec
<ImportedFileMap
>> {
255 let filemaps
= self.codemap_import_info
.borrow();
256 if filemaps
.is_empty() {
258 let filemaps
= creader
::import_codemap(codemap
, &self.data
);
260 // This shouldn't borrow twice, but there is no way to downgrade RefMut to Ref.
261 *self.codemap_import_info
.borrow_mut() = filemaps
;
262 self.codemap_import_info
.borrow()
268 pub fn with_local_path
<T
, F
>(&self, f
: F
) -> T
269 where F
: Fn(&[ast_map
::PathElem
]) -> T
271 let cpath
= self.local_path
.borrow();
272 if cpath
.is_empty() {
273 let name
= ast_map
::PathMod(token
::intern(&self.name
));
280 pub fn update_local_path
<'a
, 'b
>(&self, candidate
: ast_map
::PathElems
<'a
, 'b
>) {
281 let mut cpath
= self.local_path
.borrow_mut();
282 let cap
= cpath
.len();
284 0 => *cpath
= candidate
.collect(),
287 let candidate
: SmallVector
<_
> = candidate
.collect();
288 if candidate
.len() < cap
{
295 pub fn local_def_path(&self) -> ast_map
::DefPath
{
296 let local_def_path
= self.local_def_path
.borrow();
297 if local_def_path
.is_empty() {
298 let name
= ast_map
::DefPathData
::DetachedCrate(token
::intern(&self.name
));
299 vec
![ast_map
::DisambiguatedDefPathData { data: name, disambiguator: 0 }
]
301 local_def_path
.clone()
305 pub fn update_local_def_path(&self, candidate
: ast_map
::DefPath
) {
306 let mut local_def_path
= self.local_def_path
.borrow_mut();
307 if local_def_path
.is_empty() || candidate
.len() < local_def_path
.len() {
308 *local_def_path
= candidate
;
312 pub fn is_allocator(&self) -> bool
{
313 let attrs
= decoder
::get_crate_attributes(self.data());
314 attr
::contains_name(&attrs
, "allocator")
317 pub fn needs_allocator(&self) -> bool
{
318 let attrs
= decoder
::get_crate_attributes(self.data());
319 attr
::contains_name(&attrs
, "needs_allocator")
324 pub fn as_slice
<'a
>(&'a
self) -> &'a
[u8] {
325 let slice
= match *self {
326 MetadataVec(ref vec
) => &vec
[..],
327 MetadataArchive(ref ar
) => ar
.as_slice(),
330 &[] // corrupt metadata
332 let len
= (((slice
[0] as u32) << 24) |
333 ((slice
[1] as u32) << 16) |
334 ((slice
[2] as u32) << 8) |
335 ((slice
[3] as u32) << 0)) as usize;
336 if len
+ 4 <= slice
.len() {
339 &[] // corrupt or old metadata