From af1b19555ce636788c19dba979b57536792d90e9 Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Fri, 11 Nov 2016 10:00:33 +1300 Subject: [PATCH] Rebasing and review changes --- src/librustc/middle/cstore.rs | 12 +++++ src/librustc/session/config.rs | 2 +- src/librustc_metadata/creader.rs | 3 +- src/librustc_metadata/cstore.rs | 3 +- src/librustc_metadata/decoder.rs | 3 +- src/librustc_metadata/locator.rs | 55 +++++++++++++--------- src/librustc_trans/back/link.rs | 26 +++++----- src/librustc_trans/back/write.rs | 8 ++-- src/test/run-pass/auxiliary/rmeta_rlib.rs | 18 +++++++ src/test/run-pass/auxiliary/rmeta_rmeta.rs | 18 +++++++ src/test/run-pass/rmeta.rs | 22 +++++++++ 11 files changed, 126 insertions(+), 44 deletions(-) create mode 100644 src/test/run-pass/auxiliary/rmeta_rlib.rs create mode 100644 src/test/run-pass/auxiliary/rmeta_rmeta.rs create mode 100644 src/test/run-pass/rmeta.rs diff --git a/src/librustc/middle/cstore.rs b/src/librustc/middle/cstore.rs index 1468e94459e..653f9852e66 100644 --- a/src/librustc/middle/cstore.rs +++ b/src/librustc/middle/cstore.rs @@ -65,6 +65,18 @@ pub struct CrateSource { pub rmeta: Option<(PathBuf, PathKind)>, } +#[derive(RustcEncodable, RustcDecodable, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Debug)] +pub enum DepKind { + /// A dependency that is only used for its macros. + MacrosOnly, + /// A dependency that is always injected into the dependency list and so + /// doesn't need to be linked to an rlib, e.g. the injected allocator. + Implicit, + /// A dependency that is required by an rlib version of this crate. + /// Ordinary `extern crate`s result in `Explicit` dependencies. + Explicit, +} + #[derive(PartialEq, Clone, Debug)] pub enum LibSource { Some(PathBuf), diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index 4a073288273..3dc533d61f0 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -1634,7 +1634,7 @@ impl fmt::Display for CrateType { CrateTypeStaticlib => "staticlib".fmt(f), CrateTypeCdylib => "cdylib".fmt(f), CrateTypeProcMacro => "proc-macro".fmt(f), - CrateTypeMetadata => "rmeta".fmt(f), + CrateTypeMetadata => "metadata".fmt(f), } } } diff --git a/src/librustc_metadata/creader.rs b/src/librustc_metadata/creader.rs index 693b04ae661..12a70da636d 100644 --- a/src/librustc_metadata/creader.rs +++ b/src/librustc_metadata/creader.rs @@ -67,8 +67,7 @@ fn dump_crates(cstore: &CStore) { dylib.map(|dl| info!(" dylib: {}", dl.0.display())); rlib.map(|rl| info!(" rlib: {}", rl.0.display())); rmeta.map(|rl| info!(" rmeta: {}", rl.0.display())); - }); - }) + }); } #[derive(Debug)] diff --git a/src/librustc_metadata/cstore.rs b/src/librustc_metadata/cstore.rs index e5f7964d7eb..c2ed7ca7ce0 100644 --- a/src/librustc_metadata/cstore.rs +++ b/src/librustc_metadata/cstore.rs @@ -43,6 +43,7 @@ pub type CrateNumMap = IndexVec; pub enum MetadataBlob { Inflated(Bytes), Archive(locator::ArchiveMetadata), + Raw(Vec), } /// Holds information about a syntax_pos::FileMap imported from another crate. @@ -203,7 +204,7 @@ impl CStore { let path = match path { Some(p) => LibSource::Some(p), None => { - if data.rmeta.is_some() { + if data.source.rmeta.is_some() { LibSource::MetadataOnly } else { LibSource::None diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index 3af9d291ae5..3ba899f41d8 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -88,8 +88,9 @@ pub trait Metadata<'a, 'tcx>: Copy { impl<'a, 'tcx> Metadata<'a, 'tcx> for &'a MetadataBlob { fn raw_bytes(self) -> &'a [u8] { match *self { - MetadataBlob::Inflated(ref vec) => &vec[..], + MetadataBlob::Inflated(ref vec) => vec, MetadataBlob::Archive(ref ar) => ar.as_slice(), + MetadataBlob::Raw(ref vec) => vec, } } } diff --git a/src/librustc_metadata/locator.rs b/src/librustc_metadata/locator.rs index 6cdd8b46464..2b06851cb8b 100644 --- a/src/librustc_metadata/locator.rs +++ b/src/librustc_metadata/locator.rs @@ -53,8 +53,8 @@ //! is a platform-defined dynamic library. Each library has a metadata somewhere //! inside of it. //! -//! A third kind of dependency is an rmeta file. These are rlibs, which contain -//! metadata, but no code. To a first approximation, these are treated in the +//! A third kind of dependency is an rmeta file. These are metadata files and do +//! not contain any code, etc. To a first approximation, these are treated in the //! same way as rlibs. Where there is both an rlib and an rmeta file, the rlib //! gets priority (even if the rmeta file is newer). An rmeta file is only //! useful for checking a downstream crate, attempting to link one will cause an @@ -239,8 +239,8 @@ use rustc_back::target::Target; use std::cmp; use std::fmt; -use std::fs; -use std::io; +use std::fs::{self, File}; +use std::io::{self, Read}; use std::path::{Path, PathBuf}; use std::ptr; use std::slice; @@ -462,22 +462,23 @@ impl<'a> Context<'a> { None => return FileDoesntMatch, Some(file) => file, }; - let (hash, found_kind) = if file.starts_with(&rlib_prefix[..]) && file.ends_with(".rlib") { - (&file[(rlib_prefix.len())..(file.len() - ".rlib".len())], CrateFlavor::Rlib) - } else if file.starts_with(&rlib_prefix[..]) && file.ends_with(".rmeta") { - (&file[(rlib_prefix.len())..(file.len() - ".rmeta".len())], CrateFlavor::Rmeta) - } else if file.starts_with(&dylib_prefix) && - file.ends_with(&dypair.1) { - (&file[(dylib_prefix.len())..(file.len() - dypair.1.len())], CrateFlavor::Dylib) - } else { - if file.starts_with(&staticlib_prefix[..]) && file.ends_with(&staticpair.1) { - staticlibs.push(CrateMismatch { - path: path.to_path_buf(), - got: "static".to_string(), - }); - } - return FileDoesntMatch; - }; + let (hash, found_kind) = + if file.starts_with(&rlib_prefix[..]) && file.ends_with(".rlib") { + (&file[(rlib_prefix.len())..(file.len() - ".rlib".len())], CrateFlavor::Rlib) + } else if file.starts_with(&rlib_prefix[..]) && file.ends_with(".rmeta") { + (&file[(rlib_prefix.len())..(file.len() - ".rmeta".len())], CrateFlavor::Rmeta) + } else if file.starts_with(&dylib_prefix) && + file.ends_with(&dypair.1) { + (&file[(dylib_prefix.len())..(file.len() - dypair.1.len())], CrateFlavor::Dylib) + } else { + if file.starts_with(&staticlib_prefix[..]) && file.ends_with(&staticpair.1) { + staticlibs.push(CrateMismatch { + path: path.to_path_buf(), + got: "static".to_string(), + }); + } + return FileDoesntMatch; + }; info!("lib candidate: {}", path.display()); let hash_str = hash.to_string(); @@ -731,7 +732,8 @@ impl<'a> Context<'a> { return false; } }; - if file.starts_with("lib") && file.ends_with(".rlib") { + if file.starts_with("lib") && + (file.ends_with(".rlib") || file.ends_with(".rmeta")) { return true; } else { let (ref prefix, ref suffix) = dylibname; @@ -846,7 +848,7 @@ fn get_metadata_section_imp(target: &Target, if !filename.exists() { return Err(format!("no such file: '{}'", filename.display())); } - if flavor == CrateFlavor::Rlib || flavor == CrateFlavor::Rmeta { + 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. @@ -864,6 +866,15 @@ fn get_metadata_section_imp(target: &Target, 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); diff --git a/src/librustc_trans/back/link.rs b/src/librustc_trans/back/link.rs index 7938ddde4ce..40c2de7b889 100644 --- a/src/librustc_trans/back/link.rs +++ b/src/librustc_trans/back/link.rs @@ -190,7 +190,6 @@ pub fn link_binary(sess: &Session, let mut out_filenames = Vec::new(); for &crate_type in sess.crate_types.borrow().iter() { // Ignore executable crates if we have -Z no-trans, as they will error. - // TODO do we need to check for CrateTypeMetadata here? if sess.opts.debugging_opts.no_trans && crate_type == config::CrateTypeExecutable { continue; @@ -312,7 +311,8 @@ pub fn each_linked_rlib(sess: &Session, let path = match path { LibSource::Some(p) => p, LibSource::MetadataOnly => { - sess.fatal(&format!("could not find rlib for: `{}`, found rmeta (metadata) file", name)); + sess.fatal(&format!("could not find rlib for: `{}`, found rmeta (metadata) file", + name)); } LibSource::None => { sess.fatal(&format!("could not find rlib for: `{}`", name)); @@ -351,13 +351,16 @@ fn link_binary_output(sess: &Session, }; match crate_type { - config::CrateTypeRlib | config::CrateTypeMetadata => { + config::CrateTypeRlib => { link_rlib(sess, Some(trans), &objects, &out_filename, tmpdir.path()).build(); } config::CrateTypeStaticlib => { link_staticlib(sess, &objects, &out_filename, tmpdir.path()); } + config::CrateTypeMetadata => { + emit_metadata(sess, trans, &out_filename); + } _ => { link_natively(sess, crate_type, &objects, &out_filename, trans, outputs, tmpdir.path()); @@ -396,6 +399,13 @@ fn archive_config<'a>(sess: &'a Session, } } +fn emit_metadata<'a>(sess: &'a Session, trans: &CrateTranslation, out_filename: &Path) { + let result = fs::File::create(out_filename).and_then(|mut f| f.write_all(&trans.metadata)); + if let Err(e) = result { + sess.fatal(&format!("failed to write {}: {}", out_filename.display(), e)); + } +} + // Create an 'rlib' // // An rlib in its current incarnation is essentially a renamed .a file. The @@ -471,15 +481,7 @@ fn link_rlib<'a>(sess: &'a Session, // 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()); - match fs::File::create(&metadata).and_then(|mut f| { - f.write_all(&trans.metadata) - }) { - Ok(..) => {} - Err(e) => { - sess.fatal(&format!("failed to write {}: {}", - metadata.display(), e)); - } - } + emit_metadata(sess, trans, &metadata); ab.add_file(&metadata); // For LTO purposes, the bytecode of this library is also inserted diff --git a/src/librustc_trans/back/write.rs b/src/librustc_trans/back/write.rs index 29e3efb3b3a..01eea08c50b 100644 --- a/src/librustc_trans/back/write.rs +++ b/src/librustc_trans/back/write.rs @@ -691,12 +691,10 @@ pub fn run_passes(sess: &Session, // Whenever an rlib is created, the bitcode is inserted into the // archive in order to allow LTO against it. let needs_crate_bitcode = - (sess.crate_types.borrow().contains(&config::CrateTypeRlib) && - sess.opts.output_types.contains_key(&OutputType::Exe)) || - sess.crate_types.borrow().contains(&config::CrateTypeMetadata); + sess.crate_types.borrow().contains(&config::CrateTypeRlib) && + sess.opts.output_types.contains_key(&OutputType::Exe); let needs_crate_object = - sess.opts.output_types.contains_key(&OutputType::Exe) || - sess.crate_types.borrow().contains(&config::CrateTypeMetadata); + sess.opts.output_types.contains_key(&OutputType::Exe); if needs_crate_bitcode { modules_config.emit_bc = true; } diff --git a/src/test/run-pass/auxiliary/rmeta_rlib.rs b/src/test/run-pass/auxiliary/rmeta_rlib.rs new file mode 100644 index 00000000000..28c11315fa1 --- /dev/null +++ b/src/test/run-pass/auxiliary/rmeta_rlib.rs @@ -0,0 +1,18 @@ +// Copyright 2016 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// no-prefer-dynamic + +#![crate_type="rlib"] +#![crate_name="rmeta_aux"] + +pub struct Foo { + pub field: i32, +} diff --git a/src/test/run-pass/auxiliary/rmeta_rmeta.rs b/src/test/run-pass/auxiliary/rmeta_rmeta.rs new file mode 100644 index 00000000000..394845b66f3 --- /dev/null +++ b/src/test/run-pass/auxiliary/rmeta_rmeta.rs @@ -0,0 +1,18 @@ +// Copyright 2016 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// no-prefer-dynamic + +#![crate_type="metadata"] +#![crate_name="rmeta_aux"] + +pub struct Foo { + pub field2: i32, +} diff --git a/src/test/run-pass/rmeta.rs b/src/test/run-pass/rmeta.rs new file mode 100644 index 00000000000..11684d8663a --- /dev/null +++ b/src/test/run-pass/rmeta.rs @@ -0,0 +1,22 @@ +// Copyright 2016 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Test that using rlibs and rmeta dep crates work together. Specifically, that +// there can be both an rmeta and an rlib file and rustc will prefer the rlib. + +// aux-build:rmeta_rmeta.rs +// aux-build:rmeta_rlib.rs + +extern crate rmeta_aux; +use rmeta_aux::Foo; + +pub fn main() { + let _ = Foo { field: 42 }; +}