version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
+[[package]]
+name = "owning_ref"
+version = "0.3.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "stable_deref_trait 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
[[package]]
name = "panic_abort"
version = "0.0.0"
"fmt_macros 0.0.0",
"graphviz 0.0.0",
"log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
+ "owning_ref 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc_back 0.0.0",
"rustc_bitflags 0.0.0",
"rustc_const_math 0.0.0",
dependencies = [
"flate 0.0.0",
"log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
+ "owning_ref 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
"proc_macro 0.0.0",
"rustc 0.0.0",
"rustc_back 0.0.0",
"rustc_const_math 0.0.0",
"rustc_data_structures 0.0.0",
"rustc_errors 0.0.0",
- "rustc_llvm 0.0.0",
"serialize 0.0.0",
"syntax 0.0.0",
"syntax_ext 0.0.0",
dependencies = [
"flate 0.0.0",
"log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
+ "owning_ref 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc 0.0.0",
"rustc_back 0.0.0",
"rustc_bitflags 0.0.0",
name = "serialize"
version = "0.0.0"
+[[package]]
+name = "stable_deref_trait"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
[[package]]
name = "std"
version = "0.0.0"
"checksum num-traits 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)" = "e1cbfa3781f3fe73dc05321bed52a06d2d491eaa764c52335cf4399f046ece99"
"checksum num_cpus 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ca313f1862c7ec3e0dfe8ace9fa91b1d9cb5c84ace3d00f5ec4216238e93c167"
"checksum open 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3478ed1686bd1300c8a981a940abc92b06fac9cbef747f4c668d4e032ff7b842"
+"checksum owning_ref 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "cdf84f41639e037b484f93433aa3897863b561ed65c6e59c7073d7c561710f37"
"checksum pest 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "0a6dda33d67c26f0aac90d324ab2eb7239c819fc7b2552fe9faa4fe88441edc8"
"checksum pulldown-cmark 0.0.14 (registry+https://github.com/rust-lang/crates.io-index)" = "d9ab1e588ef8efd702c7ed9d2bd774db5e6f4d878bb5a1a9f371828fbdff6973"
"checksum pulldown-cmark 0.0.8 (registry+https://github.com/rust-lang/crates.io-index)" = "1058d7bb927ca067656537eec4e02c2b4b70eaaa129664c5b90c111e20326f41"
"checksum rustc-serialize 0.3.23 (registry+https://github.com/rust-lang/crates.io-index)" = "684ce48436d6465300c9ea783b6b14c4361d6b8dcbb1375b486a69cc19e2dfb0"
"checksum serde 0.9.11 (registry+https://github.com/rust-lang/crates.io-index)" = "a702319c807c016e51f672e5c77d6f0b46afddd744b5e437d6b8436b888b458f"
"checksum serde_json 0.9.9 (registry+https://github.com/rust-lang/crates.io-index)" = "dbc45439552eb8fb86907a2c41c1fd0ef97458efb87ff7f878db466eb581824e"
+"checksum stable_deref_trait 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "15132e0e364248108c5e2c02e3ab539be8d6f5d52a01ca9bbf27ed657316f02b"
"checksum strsim 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b4d15c810519a91cf877e7e36e63fe068815c678181439f2f29e2562147c3694"
"checksum term_size 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "07b6c1ac5b3fffd75073276bca1ceed01f67a28537097a2a9539e116e50fb21a"
"checksum thread-id 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4437c97558c70d129e40629a5b385b3fb1ffac301e63941335e4d354081ec14a"
fmt_macros = { path = "../libfmt_macros" }
graphviz = { path = "../libgraphviz" }
log = "0.3"
+owning_ref = "0.3.3"
rustc_back = { path = "../librustc_back" }
rustc_bitflags = { path = "../librustc_bitflags" }
rustc_const_math = { path = "../librustc_const_math" }
extern crate getopts;
extern crate graphviz;
extern crate libc;
+extern crate owning_ref;
extern crate rustc_llvm as llvm;
extern crate rustc_back;
extern crate rustc_data_structures;
use util::nodemap::{NodeSet, DefIdMap};
use std::any::Any;
-use std::path::PathBuf;
+use std::path::{Path, PathBuf};
use std::rc::Rc;
+use owning_ref::ErasedBoxRef;
use syntax::ast;
use syntax::ext::base::SyntaxExtension;
use syntax::symbol::Symbol;
}
}
+/// The backend's way to give the crate store access to the metadata in a library.
+/// Note that it returns the raw metadata bytes stored in the library file, whether
+/// it is compressed, uncompressed, some weird mix, etc.
+/// rmeta files are backend independent and not handled here.
+///
+/// At the time of this writing, there is only one backend and one way to store
+/// metadata in library -- this trait just serves to decouple rustc_metadata from
+/// the archive reader, which depends on LLVM.
+pub trait MetadataLoader {
+ fn get_rlib_metadata(&self,
+ target: &Target,
+ filename: &Path)
+ -> Result<ErasedBoxRef<[u8]>, String>;
+ fn get_dylib_metadata(&self,
+ target: &Target,
+ filename: &Path)
+ -> Result<ErasedBoxRef<[u8]>, String>;
+}
+
/// A store of Rust crates, through with their metadata
/// can be accessed.
pub trait CrateStore {
fn crate_data_as_rc_any(&self, krate: CrateNum) -> Rc<Any>;
+ // access to the metadata loader
+ fn metadata_loader(&self) -> &MetadataLoader;
+
// item info
fn visibility(&self, def: DefId) -> ty::Visibility;
fn visible_parent_map<'a>(&'a self) -> ::std::cell::Ref<'a, DefIdMap<DefId>>;
fn used_link_args(&self) -> Vec<String>;
// utility functions
- fn metadata_filename(&self) -> &str;
- fn metadata_section_name(&self, target: &Target) -> &str;
fn used_crates(&self, prefer: LinkagePreference) -> Vec<(CrateNum, LibSource)>;
fn used_crate_source(&self, cnum: CrateNum) -> CrateSource;
fn extern_mod_stmt_cnum(&self, emod_id: ast::NodeId) -> Option<CrateNum>;
fn used_link_args(&self) -> Vec<String> { vec![] }
// utility functions
- fn metadata_filename(&self) -> &str { bug!("metadata_filename") }
- fn metadata_section_name(&self, target: &Target) -> &str { bug!("metadata_section_name") }
fn used_crates(&self, prefer: LinkagePreference) -> Vec<(CrateNum, LibSource)>
{ vec![] }
fn used_crate_source(&self, cnum: CrateNum) -> CrateSource { bug!("used_crate_source") }
bug!("encode_metadata")
}
fn metadata_encoding_version(&self) -> &[u8] { bug!("metadata_encoding_version") }
+
+ // access to the metadata loader
+ fn metadata_loader(&self) -> &MetadataLoader { bug!("metadata_loader") }
}
pub trait CrateLoader {
};
let dep_graph = DepGraph::new(sopts.build_dep_graph());
- let cstore = Rc::new(CStore::new(&dep_graph));
+ let cstore = Rc::new(CStore::new(&dep_graph, box rustc_trans::LlvmMetadataLoader));
let loader = file_loader.unwrap_or(box RealFileLoader);
let codemap = Rc::new(CodeMap::with_file_loader(loader, sopts.file_path_mapping()));
return None;
}
let dep_graph = DepGraph::new(sopts.build_dep_graph());
- let cstore = Rc::new(CStore::new(&dep_graph));
+ let cstore = Rc::new(CStore::new(&dep_graph, box rustc_trans::LlvmMetadataLoader));
let mut sess = build_session(sopts.clone(),
&dep_graph,
None,
&Input::File(ref ifile) => {
let path = &(*ifile);
let mut v = Vec::new();
- locator::list_file_metadata(&sess.target.target, path, &mut v).unwrap();
+ locator::list_file_metadata(&sess.target.target,
+ path,
+ sess.cstore.metadata_loader(),
+ &mut v)
+ .unwrap();
println!("{}", String::from_utf8(v).unwrap());
}
&Input::Str { .. } => {
use rustc::dep_graph::DepGraph;
use rustc_lint;
use rustc_resolve::MakeGlobMap;
+use rustc_trans;
use rustc::middle::lang_items;
use rustc::middle::free_region::FreeRegionMap;
use rustc::middle::region::{CodeExtent, RegionMaps};
let dep_graph = DepGraph::new(false);
let _ignore = dep_graph.in_ignore();
- let cstore = Rc::new(CStore::new(&dep_graph));
+ let cstore = Rc::new(CStore::new(&dep_graph, box rustc_trans::LlvmMetadataLoader));
let sess = session::build_session_(options,
&dep_graph,
None,
[dependencies]
flate = { path = "../libflate" }
log = "0.3"
+owning_ref = "0.3.3"
proc_macro = { path = "../libproc_macro" }
rustc = { path = "../librustc" }
rustc_back = { path = "../librustc_back" }
rustc_const_math = { path = "../librustc_const_math" }
rustc_data_structures = { path = "../librustc_data_structures" }
rustc_errors = { path = "../librustc_errors" }
-rustc_llvm = { path = "../librustc_llvm" }
serialize = { path = "../libserialize" }
syntax = { path = "../libsyntax" }
syntax_ext = { path = "../libsyntax_ext" }
rejected_via_filename: vec![],
should_match_name: true,
is_proc_macro: Some(false),
+ metadata_loader: &*self.cstore.metadata_loader,
};
self.load(&mut locate_ctxt).or_else(|| {
rejected_via_filename: vec![],
should_match_name: true,
is_proc_macro: None,
+ metadata_loader: &*self.cstore.metadata_loader,
};
let library = self.load(&mut locate_ctxt).or_else(|| {
if !is_cross {
// The crate store - a central repo for information collected about external
// crates and libraries
-use locator;
use schema::{self, Tracked};
use rustc::dep_graph::{DepGraph, DepNode, GlobalMetaDataKind};
use rustc::hir::def_id::{CRATE_DEF_INDEX, LOCAL_CRATE, CrateNum, DefIndex, DefId};
use rustc::hir::map::definitions::DefPathTable;
use rustc::hir::svh::Svh;
-use rustc::middle::cstore::{DepKind, ExternCrate};
+use rustc::middle::cstore::{DepKind, ExternCrate, MetadataLoader};
use rustc_back::PanicStrategy;
use rustc_data_structures::indexed_vec::IndexVec;
use rustc::util::nodemap::{FxHashMap, FxHashSet, NodeMap, DefIdMap};
use std::cell::{RefCell, Cell};
use std::rc::Rc;
-use flate::Bytes;
+use owning_ref::ErasedBoxRef;
use syntax::{ast, attr};
use syntax::ext::base::SyntaxExtension;
use syntax::symbol::Symbol;
// own crate numbers.
pub type CrateNumMap = IndexVec<CrateNum, CrateNum>;
-pub enum MetadataBlob {
- Inflated(Bytes),
- Archive(locator::ArchiveMetadata),
- Raw(Vec<u8>),
-}
+pub struct MetadataBlob(pub ErasedBoxRef<[u8]>);
/// Holds information about a syntax_pos::FileMap imported from another crate.
/// See `imported_filemaps()` for more information.
statically_included_foreign_items: RefCell<FxHashSet<DefIndex>>,
pub dllimport_foreign_items: RefCell<FxHashSet<DefIndex>>,
pub visible_parent_map: RefCell<DefIdMap<DefId>>,
+ pub metadata_loader: Box<MetadataLoader>,
}
impl CStore {
- pub fn new(dep_graph: &DepGraph) -> CStore {
+ pub fn new(dep_graph: &DepGraph, metadata_loader: Box<MetadataLoader>) -> CStore {
CStore {
dep_graph: dep_graph.clone(),
metas: RefCell::new(FxHashMap()),
statically_included_foreign_items: RefCell::new(FxHashSet()),
dllimport_foreign_items: RefCell::new(FxHashSet()),
visible_parent_map: RefCell::new(FxHashMap()),
+ metadata_loader: metadata_loader,
}
}
use cstore;
use encoder;
-use locator;
use schema;
use rustc::dep_graph::DepTrackingMapConfig;
use rustc::middle::cstore::{CrateStore, CrateSource, LibSource, DepKind,
- ExternCrate, NativeLibrary, LinkMeta,
+ ExternCrate, NativeLibrary, MetadataLoader, LinkMeta,
LinkagePreference, LoadedMacro, EncodedMetadata};
use rustc::hir::def;
use rustc::middle::lang_items;
use syntax::symbol::Symbol;
use syntax_pos::{Span, NO_EXPANSION};
use rustc::hir::svh::Svh;
-use rustc_back::target::Target;
use rustc::hir;
macro_rules! provide {
self.get_crate_data(krate)
}
+ fn metadata_loader(&self) -> &MetadataLoader {
+ &*self.metadata_loader
+ }
+
fn visibility(&self, def: DefId) -> ty::Visibility {
self.dep_graph.read(DepNode::MetaData(def));
self.get_crate_data(def.krate).get_visibility(def.index)
{
self.get_used_link_args().borrow().clone()
}
-
- fn metadata_filename(&self) -> &str
- {
- locator::METADATA_FILENAME
- }
-
- fn metadata_section_name(&self, target: &Target) -> &str
- {
- locator::meta_section_name(target)
- }
-
fn used_crates(&self, prefer: LinkagePreference) -> Vec<(CrateNum, LibSource)>
{
self.do_get_used_crates(prefer)
drop(visible_parent_map);
self.visible_parent_map.borrow()
}
-}
+}
\ No newline at end of file
impl<'a, 'tcx> Metadata<'a, 'tcx> for &'a MetadataBlob {
fn raw_bytes(self) -> &'a [u8] {
- match *self {
- MetadataBlob::Inflated(ref vec) => vec,
- MetadataBlob::Archive(ref ar) => ar.as_slice(),
- MetadataBlob::Raw(ref vec) => vec,
- }
+ &self.0
}
}
extern crate syntax_pos;
extern crate flate;
extern crate serialize as rustc_serialize; // used by deriving
+extern crate owning_ref;
extern crate rustc_errors as errors;
extern crate syntax_ext;
extern crate proc_macro;
extern crate rustc_back;
extern crate rustc_const_math;
extern crate rustc_data_structures;
-extern crate rustc_llvm;
mod diagnostics;
use schema::{METADATA_HEADER, rustc_version};
use rustc::hir::svh::Svh;
+use rustc::middle::cstore::MetadataLoader;
use rustc::session::{config, Session};
use rustc::session::filesearch::{FileSearch, FileMatches, FileDoesntMatch};
use rustc::session::search_paths::PathKind;
-use rustc::util::common;
use rustc::util::nodemap::FxHashMap;
-use rustc_llvm as llvm;
-use rustc_llvm::{False, ObjectFile, mk_section_iter};
-use rustc_llvm::archive_ro::ArchiveRO;
use errors::DiagnosticBuilder;
use syntax::symbol::Symbol;
use syntax_pos::Span;
use std::fs::{self, File};
use std::io::{self, Read};
use std::path::{Path, PathBuf};
-use std::ptr;
-use std::slice;
use std::time::Instant;
use flate;
+use owning_ref::{ErasedBoxRef, OwningRef};
pub struct CrateMismatch {
path: PathBuf,
pub rejected_via_filename: Vec<CrateMismatch>,
pub should_match_name: bool,
pub is_proc_macro: Option<bool>,
-}
-
-pub struct ArchiveMetadata {
- _archive: ArchiveRO,
- // points into self._archive
- data: *const [u8],
+ pub metadata_loader: &'a MetadataLoader,
}
pub struct CratePaths {
pub rmeta: Option<PathBuf>,
}
-pub const METADATA_FILENAME: &'static str = "rust.metadata.bin";
-
#[derive(Copy, Clone, PartialEq)]
enum CrateFlavor {
Rlib,
let mut err: Option<DiagnosticBuilder> = None;
for (lib, kind) in m {
info!("{} reading metadata from: {}", flavor, lib.display());
- let (hash, metadata) = match get_metadata_section(self.target, flavor, &lib) {
- Ok(blob) => {
- if let Some(h) = self.crate_matches(&blob, &lib) {
- (h, blob)
- } else {
- info!("metadata mismatch");
+ let (hash, metadata) =
+ match get_metadata_section(self.target, flavor, &lib, self.metadata_loader) {
+ Ok(blob) => {
+ if let Some(h) = self.crate_matches(&blob, &lib) {
+ (h, blob)
+ } else {
+ info!("metadata mismatch");
+ continue;
+ }
+ }
+ Err(err) => {
+ info!("no metadata found: {}", err);
continue;
}
- }
- Err(err) => {
- info!("no metadata found: {}", err);
- continue;
- }
- };
+ };
// If we see multiple hashes, emit an error about duplicate candidates.
if slot.as_ref().map_or(false, |s| s.0 != hash) {
let mut e = struct_span_err!(self.sess,
err.note(&format!("crate name: {}", name));
}
-impl ArchiveMetadata {
- fn new(ar: ArchiveRO) -> Option<ArchiveMetadata> {
- let data = {
- let section = ar.iter()
- .filter_map(|s| s.ok())
- .find(|sect| sect.name() == Some(METADATA_FILENAME));
- match section {
- Some(s) => s.data() as *const [u8],
- None => {
- debug!("didn't find '{}' in the archive", METADATA_FILENAME);
- return None;
- }
- }
- };
-
- Some(ArchiveMetadata {
- _archive: ar,
- data: data,
- })
- }
-
- pub fn as_slice<'a>(&'a self) -> &'a [u8] {
- unsafe { &*self.data }
- }
-}
-
-fn verify_decompressed_encoding_version(blob: &MetadataBlob,
- filename: &Path)
- -> Result<(), String> {
- if !blob.is_compatible() {
- Err((format!("incompatible metadata version found: '{}'",
- filename.display())))
- } else {
- Ok(())
- }
-}
-
// Just a small wrapper to time how long reading metadata takes.
fn get_metadata_section(target: &Target,
flavor: CrateFlavor,
- filename: &Path)
+ filename: &Path,
+ loader: &MetadataLoader)
-> Result<MetadataBlob, String> {
let start = Instant::now();
- let ret = get_metadata_section_imp(target, flavor, filename);
+ let ret = get_metadata_section_imp(target, flavor, filename, loader);
info!("reading {:?} => {:?}",
filename.file_name().unwrap(),
start.elapsed());
fn get_metadata_section_imp(target: &Target,
flavor: CrateFlavor,
- filename: &Path)
+ filename: &Path,
+ loader: &MetadataLoader)
-> Result<MetadataBlob, String> {
if !filename.exists() {
return Err(format!("no such file: '{}'", filename.display()));
}
- if flavor == CrateFlavor::Rlib {
- // Use ArchiveRO for speed here, it's backed by LLVM and uses mmap
- // internally to read the file. We also avoid even using a memcpy by
- // just keeping the archive along while the metadata is in use.
- let archive = match ArchiveRO::open(filename) {
- Some(ar) => ar,
- None => {
- debug!("llvm didn't like `{}`", filename.display());
- return Err(format!("failed to read rlib metadata: '{}'", filename.display()));
+ let raw_bytes: ErasedBoxRef<[u8]> = match flavor {
+ CrateFlavor::Rlib => loader.get_rlib_metadata(target, filename)?,
+ CrateFlavor::Dylib => {
+ let buf = loader.get_dylib_metadata(target, filename)?;
+ // The header is uncompressed
+ let header_len = METADATA_HEADER.len();
+ debug!("checking {} bytes of metadata-version stamp", header_len);
+ let header = &buf[..cmp::min(header_len, buf.len())];
+ if header != METADATA_HEADER {
+ return Err(format!("incompatible metadata version found: '{}'",
+ filename.display()));
}
- };
- return match ArchiveMetadata::new(archive).map(|ar| MetadataBlob::Archive(ar)) {
- None => Err(format!("failed to read rlib metadata: '{}'", filename.display())),
- Some(blob) => {
- verify_decompressed_encoding_version(&blob, filename)?;
- Ok(blob)
- }
- };
- } else if flavor == CrateFlavor::Rmeta {
- let mut file = File::open(filename).map_err(|_|
- format!("could not open file: '{}'", filename.display()))?;
- let mut buf = vec![];
- file.read_to_end(&mut buf).map_err(|_|
- format!("failed to read rlib metadata: '{}'", filename.display()))?;
- let blob = MetadataBlob::Raw(buf);
- verify_decompressed_encoding_version(&blob, filename)?;
- return Ok(blob);
- }
- unsafe {
- let buf = common::path2cstr(filename);
- let mb = llvm::LLVMRustCreateMemoryBufferWithContentsOfFile(buf.as_ptr());
- if mb as isize == 0 {
- return Err(format!("error reading library: '{}'", filename.display()));
- }
- let of = match ObjectFile::new(mb) {
- Some(of) => of,
- _ => {
- return Err((format!("provided path not an object file: '{}'", filename.display())))
- }
- };
- let si = mk_section_iter(of.llof);
- while llvm::LLVMIsSectionIteratorAtEnd(of.llof, si.llsi) == False {
- let mut name_buf = ptr::null();
- let name_len = llvm::LLVMRustGetSectionName(si.llsi, &mut name_buf);
- let name = slice::from_raw_parts(name_buf as *const u8, name_len as usize).to_vec();
- let name = String::from_utf8(name).unwrap();
- debug!("get_metadata_section: name {}", name);
- if read_meta_section_name(target) == name {
- let cbuf = llvm::LLVMGetSectionContents(si.llsi);
- let csz = llvm::LLVMGetSectionSize(si.llsi) as usize;
- let cvbuf: *const u8 = cbuf as *const u8;
- let vlen = METADATA_HEADER.len();
- debug!("checking {} bytes of metadata-version stamp", vlen);
- let minsz = cmp::min(vlen, csz);
- let buf0 = slice::from_raw_parts(cvbuf, minsz);
- let version_ok = buf0 == METADATA_HEADER;
- if !version_ok {
- return Err((format!("incompatible metadata version found: '{}'",
- filename.display())));
- }
- let cvbuf1 = cvbuf.offset(vlen as isize);
- debug!("inflating {} bytes of compressed metadata", csz - vlen);
- let bytes = slice::from_raw_parts(cvbuf1, csz - vlen);
- match flate::inflate_bytes(bytes) {
- Ok(inflated) => {
- let blob = MetadataBlob::Inflated(inflated);
- verify_decompressed_encoding_version(&blob, filename)?;
- return Ok(blob);
- }
- Err(_) => {}
+ // Header is okay -> inflate the actual metadata
+ let compressed_bytes = &buf[header_len..];
+ debug!("inflating {} bytes of compressed metadata", compressed_bytes.len());
+ match flate::inflate_bytes(compressed_bytes) {
+ Ok(inflated) => {
+ let buf = unsafe { OwningRef::new_assert_stable_address(inflated) };
+ buf.map_owner_box().erase_owner()
+ }
+ Err(_) => {
+ return Err(format!("failed to decompress metadata: {}", filename.display()));
}
}
- llvm::LLVMMoveToNextSection(si.llsi);
}
- Err(format!("metadata not found: '{}'", filename.display()))
- }
-}
-
-pub fn meta_section_name(target: &Target) -> &'static str {
- // Historical note:
- //
- // When using link.exe it was seen that the section name `.note.rustc`
- // was getting shortened to `.note.ru`, and according to the PE and COFF
- // specification:
- //
- // > Executable images do not use a string table and do not support
- // > section names longer than 8 characters
- //
- // https://msdn.microsoft.com/en-us/library/windows/hardware/gg463119.aspx
- //
- // As a result, we choose a slightly shorter name! As to why
- // `.note.rustc` works on MinGW, that's another good question...
-
- if target.options.is_like_osx {
- "__DATA,.rustc"
+ CrateFlavor::Rmeta => {
+ let mut file = File::open(filename).map_err(|_|
+ format!("could not open file: '{}'", filename.display()))?;
+ let mut buf = vec![];
+ file.read_to_end(&mut buf).map_err(|_|
+ format!("failed to read rmeta metadata: '{}'", filename.display()))?;
+ OwningRef::new(buf).map_owner_box().erase_owner()
+ }
+ };
+ let blob = MetadataBlob(raw_bytes);
+ if blob.is_compatible() {
+ Ok(blob)
} else {
- ".rustc"
+ Err(format!("incompatible metadata version found: '{}'", filename.display()))
}
}
-pub fn read_meta_section_name(_target: &Target) -> &'static str {
- ".rustc"
-}
-
// A diagnostic function for dumping crate metadata to an output stream
-pub fn list_file_metadata(target: &Target, path: &Path, out: &mut io::Write) -> io::Result<()> {
+pub fn list_file_metadata(target: &Target,
+ path: &Path,
+ loader: &MetadataLoader,
+ out: &mut io::Write)
+ -> io::Result<()> {
let filename = path.file_name().unwrap().to_str().unwrap();
let flavor = if filename.ends_with(".rlib") {
CrateFlavor::Rlib
} else {
CrateFlavor::Dylib
};
- match get_metadata_section(target, flavor, path) {
+ match get_metadata_section(target, flavor, path, loader) {
Ok(metadata) => metadata.list_crate_metadata(out),
Err(msg) => write!(out, "{}\n", msg),
}
[dependencies]
flate = { path = "../libflate" }
log = "0.3"
+owning_ref = "0.3.3"
rustc = { path = "../librustc" }
rustc_back = { path = "../librustc_back" }
rustc_bitflags = { path = "../librustc_bitflags" }
use libc;
use llvm::archive_ro::{ArchiveRO, Child};
use llvm::{self, ArchiveKind};
+use metadata::METADATA_FILENAME;
use rustc::session::Session;
pub struct ArchiveConfig<'a> {
// Ignoring all bytecode files, no matter of
// name
let bc_ext = ".bytecode.deflate";
- let metadata_filename =
- self.config.sess.cstore.metadata_filename().to_owned();
self.add_archive(rlib, move |fname: &str| {
- if fname.ends_with(bc_ext) || fname == metadata_filename {
+ if fname.ends_with(bc_ext) || fname == METADATA_FILENAME {
return true
}
use super::rpath::RPathConfig;
use super::rpath;
use super::msvc;
+use metadata::METADATA_FILENAME;
use session::config;
use session::config::NoDebugInfo;
use session::config::{OutputFilenames, Input, OutputType};
// contain the metadata in a separate file. We use a temp directory
// here so concurrent builds in the same directory don't try to use
// the same filename for metadata (stomping over one another)
- let metadata = tmpdir.join(sess.cstore.metadata_filename());
+ let metadata = tmpdir.join(METADATA_FILENAME);
emit_metadata(sess, trans, &metadata);
ab.add_file(&metadata);
archive.update_symbols();
for f in archive.src_files() {
- if f.ends_with("bytecode.deflate") ||
- f == sess.cstore.metadata_filename() {
+ if f.ends_with("bytecode.deflate") || f == METADATA_FILENAME {
archive.remove_file(&f);
continue
}
let mut any_objects = false;
for f in archive.src_files() {
- if f.ends_with("bytecode.deflate") ||
- f == sess.cstore.metadata_filename() {
+ if f.ends_with("bytecode.deflate") || f == METADATA_FILENAME {
archive.remove_file(&f);
continue
}
use back::symbol_export::{self, ExportedSymbols};
use llvm::{ContextRef, Linkage, ModuleRef, ValueRef, Vector, get_param};
use llvm;
+use metadata;
use rustc::hir::def_id::LOCAL_CRATE;
use middle::lang_items::StartFnLangItem;
use middle::cstore::EncodedMetadata;
};
unsafe {
llvm::LLVMSetInitializer(llglobal, llconst);
- let section_name =
- tcx.sess.cstore.metadata_section_name(&tcx.sess.target.target);
+ let section_name = metadata::metadata_section_name(&tcx.sess.target.target);
let name = CString::new(section_name).unwrap();
llvm::LLVMSetSection(llglobal, name.as_ptr());
extern crate flate;
extern crate libc;
+extern crate owning_ref;
#[macro_use] extern crate rustc;
extern crate rustc_back;
extern crate rustc_data_structures;
pub use base::trans_crate;
pub use back::symbol_names::provide;
+pub use metadata::LlvmMetadataLoader;
+
pub mod back {
pub use rustc::hir::svh;
mod glue;
mod intrinsic;
mod machine;
+mod metadata;
mod meth;
mod mir;
mod monomorphize;
--- /dev/null
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use rustc::util::common;
+use rustc::middle::cstore::MetadataLoader;
+use rustc_back::target::Target;
+use llvm;
+use llvm::{False, ObjectFile, mk_section_iter};
+use llvm::archive_ro::ArchiveRO;
+
+use owning_ref::{ErasedBoxRef, OwningRef};
+use std::path::Path;
+use std::ptr;
+use std::slice;
+
+pub const METADATA_FILENAME: &str = "rust.metadata.bin";
+
+pub struct LlvmMetadataLoader;
+
+impl MetadataLoader for LlvmMetadataLoader {
+ fn get_rlib_metadata(&self, _: &Target, filename: &Path) -> Result<ErasedBoxRef<[u8]>, String> {
+ // Use ArchiveRO for speed here, it's backed by LLVM and uses mmap
+ // internally to read the file. We also avoid even using a memcpy by
+ // just keeping the archive along while the metadata is in use.
+ let archive = ArchiveRO::open(filename)
+ .map(|ar| OwningRef::new(box ar))
+ .ok_or_else(|| {
+ debug!("llvm didn't like `{}`", filename.display());
+ format!("failed to read rlib metadata: '{}'", filename.display())
+ })?;
+ let buf: OwningRef<_, [u8]> = archive
+ .try_map(|ar| {
+ ar.iter()
+ .filter_map(|s| s.ok())
+ .find(|sect| sect.name() == Some(METADATA_FILENAME))
+ .map(|s| s.data())
+ .ok_or_else(|| {
+ debug!("didn't find '{}' in the archive", METADATA_FILENAME);
+ format!("failed to read rlib metadata: '{}'",
+ filename.display())
+ })
+ })?;
+ Ok(buf.erase_owner())
+ }
+
+ fn get_dylib_metadata(&self,
+ target: &Target,
+ filename: &Path)
+ -> Result<ErasedBoxRef<[u8]>, String> {
+ unsafe {
+ let buf = common::path2cstr(filename);
+ let mb = llvm::LLVMRustCreateMemoryBufferWithContentsOfFile(buf.as_ptr());
+ if mb as isize == 0 {
+ return Err(format!("error reading library: '{}'", filename.display()));
+ }
+ let of = ObjectFile::new(mb)
+ .map(|of| OwningRef::new(box of))
+ .ok_or_else(|| format!("provided path not an object file: '{}'",
+ filename.display()))?;
+ let buf = of.try_map(|of| search_meta_section(of, target, filename))?;
+ Ok(buf.erase_owner())
+ }
+ }
+}
+
+fn search_meta_section<'a>(of: &'a ObjectFile,
+ target: &Target,
+ filename: &Path)
+ -> Result<&'a [u8], String> {
+ unsafe {
+ let si = mk_section_iter(of.llof);
+ while llvm::LLVMIsSectionIteratorAtEnd(of.llof, si.llsi) == False {
+ let mut name_buf = ptr::null();
+ let name_len = llvm::LLVMRustGetSectionName(si.llsi, &mut name_buf);
+ let name = slice::from_raw_parts(name_buf as *const u8, name_len as usize).to_vec();
+ let name = String::from_utf8(name).unwrap();
+ debug!("get_metadata_section: name {}", name);
+ if read_metadata_section_name(target) == name {
+ let cbuf = llvm::LLVMGetSectionContents(si.llsi);
+ let csz = llvm::LLVMGetSectionSize(si.llsi) as usize;
+ // The buffer is valid while the object file is around
+ let buf: &'a [u8] = slice::from_raw_parts(cbuf as *const u8, csz);
+ return Ok(buf);
+ }
+ llvm::LLVMMoveToNextSection(si.llsi);
+ }
+ }
+ Err(format!("metadata not found: '{}'", filename.display()))
+}
+
+pub fn metadata_section_name(target: &Target) -> &'static str {
+ // Historical note:
+ //
+ // When using link.exe it was seen that the section name `.note.rustc`
+ // was getting shortened to `.note.ru`, and according to the PE and COFF
+ // specification:
+ //
+ // > Executable images do not use a string table and do not support
+ // > section names longer than 8 characters
+ //
+ // https://msdn.microsoft.com/en-us/library/windows/hardware/gg463119.aspx
+ //
+ // As a result, we choose a slightly shorter name! As to why
+ // `.note.rustc` works on MinGW, that's another good question...
+
+ if target.options.is_like_osx {
+ "__DATA,.rustc"
+ } else {
+ ".rustc"
+ }
+}
+
+fn read_metadata_section_name(_target: &Target) -> &'static str {
+ ".rustc"
+}
use rustc::hir::map as hir_map;
use rustc::lint;
use rustc::util::nodemap::FxHashMap;
+use rustc_trans;
use rustc_trans::back::link;
use rustc_resolve as resolve;
use rustc_metadata::cstore::CStore;
let dep_graph = DepGraph::new(false);
let _ignore = dep_graph.in_ignore();
- let cstore = Rc::new(CStore::new(&dep_graph));
+ let cstore = Rc::new(CStore::new(&dep_graph, box rustc_trans::LlvmMetadataLoader));
let mut sess = session::build_session_(
sessopts, &dep_graph, cpath, diagnostic_handler, codemap, cstore.clone()
);
use rustc_driver::driver::phase_2_configure_and_expand;
use rustc_metadata::cstore::CStore;
use rustc_resolve::MakeGlobMap;
+use rustc_trans;
use rustc_trans::back::link;
use syntax::ast;
use syntax::codemap::CodeMap;
let dep_graph = DepGraph::new(false);
let _ignore = dep_graph.in_ignore();
- let cstore = Rc::new(CStore::new(&dep_graph));
+ let cstore = Rc::new(CStore::new(&dep_graph, box rustc_trans::LlvmMetadataLoader));
let mut sess = session::build_session_(
sessopts, &dep_graph, Some(input_path.clone()), handler, codemap.clone(), cstore.clone(),
);
let diagnostic_handler = errors::Handler::with_emitter(true, false, box emitter);
let dep_graph = DepGraph::new(false);
- let cstore = Rc::new(CStore::new(&dep_graph));
+ let cstore = Rc::new(CStore::new(&dep_graph, box rustc_trans::LlvmMetadataLoader));
let mut sess = session::build_session_(
sessopts, &dep_graph, None, diagnostic_handler, codemap, cstore.clone(),
);
extern crate rustc_lint;
extern crate rustc_metadata;
extern crate rustc_errors;
+extern crate rustc_trans;
extern crate syntax;
use rustc::dep_graph::DepGraph;
let descriptions = Registry::new(&rustc::DIAGNOSTICS);
let dep_graph = DepGraph::new(opts.build_dep_graph());
- let cstore = Rc::new(CStore::new(&dep_graph));
+ let cstore = Rc::new(CStore::new(&dep_graph, Box::new(rustc_trans::LlvmMetadataLoader)));
let sess = build_session(opts, &dep_graph, None, descriptions, cstore.clone());
rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess));
(sess, cstore)