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
::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}
;
28 use std
::cell
::{RefCell, Ref, Cell}
;
30 use std
::path
::PathBuf
;
35 use syntax
::parse
::token
::IdentInterner
;
37 pub use middle
::cstore
::{NativeLibraryKind, LinkagePreference}
;
38 pub use middle
::cstore
::{NativeStatic, NativeFramework, NativeUnknown}
;
39 pub use middle
::cstore
::{CrateSource, LinkMeta}
;
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
45 pub type cnum_map
= FnvHashMap
<ast
::CrateNum
, ast
::CrateNum
>;
47 pub enum MetadataBlob
{
49 MetadataArchive(loader
::ArchiveMetadata
),
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
>
63 pub struct crate_metadata
{
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
>>,
71 pub data
: MetadataBlob
,
72 pub cnum_map
: RefCell
<cnum_map
>,
73 pub cnum
: ast
::CrateNum
,
74 pub codemap_import_info
: RefCell
<Vec
<ImportedFileMap
>>,
77 pub index
: index
::Index
,
78 pub xref_index
: index
::DenseIndex
,
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
>,
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
>>,
100 pub fn new(intr
: Rc
<IdentInterner
>) -> 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()),
108 statically_included_foreign_items
: RefCell
::new(NodeSet()),
109 visible_parent_map
: RefCell
::new(FnvHashMap()),
113 pub fn next_crate_num(&self) -> ast
::CrateNum
{
114 self.metas
.borrow().len() as ast
::CrateNum
+ 1
117 pub fn get_crate_data(&self, cnum
: ast
::CrateNum
) -> Rc
<crate_metadata
> {
118 self.metas
.borrow().get(&cnum
).unwrap().clone()
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())
126 pub fn set_crate_data(&self, cnum
: ast
::CrateNum
, data
: Rc
<crate_metadata
>) {
127 self.metas
.borrow_mut().insert(cnum
, data
);
130 pub fn iter_crate_data
<I
>(&self, mut i
: I
) where
131 I
: FnMut(ast
::CrateNum
, &Rc
<crate_metadata
>),
133 for (&k
, v
) in self.metas
.borrow().iter() {
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
>),
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); }
);
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
);
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()
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();
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
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
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
);
192 for (&num
, _
) in self.metas
.borrow().iter() {
193 visit(self, num
, &mut ordering
);
195 info
!("topological ordering: {:?}", ordering
);
197 let mut libs
= self.used_crate_sources
.borrow()
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),
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
);
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
));
217 pub fn get_used_libraries
<'a
>(&'a
self)
218 -> &'a RefCell
<Vec
<(String
,
219 NativeLibraryKind
)>> {
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());
229 pub fn get_used_link_args
<'a
>(&'a
self) -> &'a RefCell
<Vec
<String
> > {
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
);
239 pub fn add_statically_included_foreign_item(&self, id
: ast
::NodeId
) {
240 self.statically_included_foreign_items
.borrow_mut().insert(id
);
243 pub fn do_is_statically_included_foreign_item(&self, id
: ast
::NodeId
) -> bool
{
244 self.statically_included_foreign_items
.borrow().contains(&id
)
247 pub fn do_extern_mod_stmt_cnum(&self, emod_id
: ast
::NodeId
) -> Option
<ast
::CrateNum
>
249 self.extern_mod_crate_map
.borrow().get(&emod_id
).cloned()
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())
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() {
265 let filemaps
= creader
::import_codemap(codemap
, &self.data
);
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()
275 pub fn is_allocator(&self) -> bool
{
276 let attrs
= decoder
::get_crate_attributes(self.data());
277 attr
::contains_name(&attrs
, "allocator")
280 pub fn needs_allocator(&self) -> bool
{
281 let attrs
= decoder
::get_crate_attributes(self.data());
282 attr
::contains_name(&attrs
, "needs_allocator")
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(),
293 &[] // corrupt metadata
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() {
302 &[] // corrupt or old metadata