From b286a2f0817dbe33de95c3746b6289a1e5bd6a81 Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Wed, 26 Oct 2016 11:14:02 +1300 Subject: [PATCH 1/4] Add --crate-type metadata With the same semantics as -Zno-trans --- src/librustc/middle/dependency_format.rs | 2 +- src/librustc/middle/reachable.rs | 2 +- src/librustc/middle/weak_lang_items.rs | 3 ++- src/librustc/session/config.rs | 29 +++++++++++++----------- src/librustc_driver/driver.rs | 1 + src/librustc_metadata/creader.rs | 3 ++- src/librustc_trans/back/archive.rs | 2 +- src/librustc_trans/back/link.rs | 8 ++++++- src/librustc_trans/back/write.rs | 8 ++++--- src/librustc_trans/base.rs | 8 ++++--- src/tools/compiletest/src/runtest.rs | 3 ++- 11 files changed, 43 insertions(+), 26 deletions(-) diff --git a/src/librustc/middle/dependency_format.rs b/src/librustc/middle/dependency_format.rs index 92d1ab85c5a05..aeccaac385ac5 100644 --- a/src/librustc/middle/dependency_format.rs +++ b/src/librustc/middle/dependency_format.rs @@ -114,7 +114,7 @@ fn calculate_type(sess: &session::Session, // No linkage happens with rlibs, we just needed the metadata (which we // got long ago), so don't bother with anything. - config::CrateTypeRlib => return Vec::new(), + config::CrateTypeRlib | config::CrateTypeMetadata => return Vec::new(), // Staticlibs and cdylibs must have all static dependencies. If any fail // to be found, we generate some nice pretty errors. diff --git a/src/librustc/middle/reachable.rs b/src/librustc/middle/reachable.rs index ac614494355a2..35e0e494771ba 100644 --- a/src/librustc/middle/reachable.rs +++ b/src/librustc/middle/reachable.rs @@ -140,7 +140,7 @@ impl<'a, 'tcx> ReachableContext<'a, 'tcx> { fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> ReachableContext<'a, 'tcx> { let any_library = tcx.sess.crate_types.borrow().iter().any(|ty| { *ty == config::CrateTypeRlib || *ty == config::CrateTypeDylib || - *ty == config::CrateTypeProcMacro + *ty == config::CrateTypeProcMacro || *ty == config::CrateTypeMetadata }); ReachableContext { tcx: tcx, diff --git a/src/librustc/middle/weak_lang_items.rs b/src/librustc/middle/weak_lang_items.rs index 12d32bf31b13d..dd4d09ccb662a 100644 --- a/src/librustc/middle/weak_lang_items.rs +++ b/src/librustc/middle/weak_lang_items.rs @@ -75,7 +75,8 @@ fn verify(sess: &Session, items: &lang_items::LanguageItems) { config::CrateTypeCdylib | config::CrateTypeExecutable | config::CrateTypeStaticlib => true, - config::CrateTypeRlib => false, + config::CrateTypeRlib | + config::CrateTypeMetadata => false, } }); if !needs_check { diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index 16522a73f56a5..4a0732882730e 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -78,18 +78,6 @@ pub enum OutputType { DepInfo, } -#[derive(Clone, Copy, Debug, PartialEq, Eq)] -pub enum ErrorOutputType { - HumanReadable(ColorConfig), - Json, -} - -impl Default for ErrorOutputType { - fn default() -> ErrorOutputType { - ErrorOutputType::HumanReadable(ColorConfig::Auto) - } -} - impl OutputType { fn is_compatible_with_codegen_units_and_single_output_file(&self) -> bool { match *self { @@ -125,6 +113,18 @@ impl OutputType { } } +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum ErrorOutputType { + HumanReadable(ColorConfig), + Json, +} + +impl Default for ErrorOutputType { + fn default() -> ErrorOutputType { + ErrorOutputType::HumanReadable(ColorConfig::Auto) + } +} + // Use tree-based collections to cheaply get a deterministic Hash implementation. // DO NOT switch BTreeMap out for an unsorted container type! That would break // dependency tracking for commandline arguments. @@ -483,6 +483,7 @@ pub enum CrateType { CrateTypeStaticlib, CrateTypeCdylib, CrateTypeProcMacro, + CrateTypeMetadata, } #[derive(Clone, Hash)] @@ -1159,7 +1160,7 @@ pub fn rustc_short_optgroups() -> Vec { assumed.", "[KIND=]NAME"), opt::multi_s("", "crate-type", "Comma separated list of types of crates for the compiler to emit", - "[bin|lib|rlib|dylib|cdylib|staticlib]"), + "[bin|lib|rlib|dylib|cdylib|staticlib|metadata]"), opt::opt_s("", "crate-name", "Specify the name of the crate being built", "NAME"), opt::multi_s("", "emit", "Comma separated list of types of output for \ @@ -1548,6 +1549,7 @@ pub fn parse_crate_types_from_list(list_list: Vec) -> Result CrateTypeCdylib, "bin" => CrateTypeExecutable, "proc-macro" => CrateTypeProcMacro, + "metadata" => CrateTypeMetadata, _ => { return Err(format!("unknown crate type: `{}`", part)); @@ -1632,6 +1634,7 @@ impl fmt::Display for CrateType { CrateTypeStaticlib => "staticlib".fmt(f), CrateTypeCdylib => "cdylib".fmt(f), CrateTypeProcMacro => "proc-macro".fmt(f), + CrateTypeMetadata => "rmeta".fmt(f), } } } diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index 6a3a1bbb55ca2..9c207108374db 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -1093,6 +1093,7 @@ pub fn phase_5_run_llvm_passes(sess: &Session, "serialize work products", move || rustc_incremental::save_work_products(sess)); + println!("finish phase 5: {}", sess.err_count()); if sess.err_count() > 0 { Err(sess.err_count()) } else { diff --git a/src/librustc_metadata/creader.rs b/src/librustc_metadata/creader.rs index 5384535024e53..313b3b0fddf4d 100644 --- a/src/librustc_metadata/creader.rs +++ b/src/librustc_metadata/creader.rs @@ -767,7 +767,8 @@ impl<'a> CrateLoader<'a> { config::CrateTypeProcMacro | config::CrateTypeCdylib | config::CrateTypeStaticlib => need_lib_alloc = true, - config::CrateTypeRlib => {} + config::CrateTypeRlib | + config::CrateTypeMetadata => {} } } if !need_lib_alloc && !need_exe_alloc { return } diff --git a/src/librustc_trans/back/archive.rs b/src/librustc_trans/back/archive.rs index df8dd7750ae0c..11ab6dcaa87f9 100644 --- a/src/librustc_trans/back/archive.rs +++ b/src/librustc_trans/back/archive.rs @@ -231,7 +231,7 @@ impl<'a> ArchiveBuilder<'a> { } fn llvm_archive_kind(&self) -> Result { - let kind = &self.config.sess.target.target.options.archive_format[..]; + let kind = &*self.config.sess.target.target.options.archive_format; kind.parse().map_err(|_| kind) } diff --git a/src/librustc_trans/back/link.rs b/src/librustc_trans/back/link.rs index 95d63311ee6e4..fcbead49a2635 100644 --- a/src/librustc_trans/back/link.rs +++ b/src/librustc_trans/back/link.rs @@ -191,6 +191,7 @@ 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; @@ -263,6 +264,9 @@ pub fn filename_for_input(sess: &Session, config::CrateTypeRlib => { outputs.out_directory.join(&format!("lib{}.rlib", libname)) } + config::CrateTypeMetadata => { + outputs.out_directory.join(&format!("lib{}.rmeta", libname)) + } config::CrateTypeCdylib | config::CrateTypeProcMacro | config::CrateTypeDylib => { @@ -322,6 +326,7 @@ fn link_binary_output(sess: &Session, outputs: &OutputFilenames, crate_name: &str) -> PathBuf { let objects = object_filenames(trans, outputs); + println!("objects: {:?}", objects); let default_filename = filename_for_input(sess, crate_type, crate_name, outputs); let out_filename = outputs.outputs.get(&OutputType::Exe) @@ -345,7 +350,7 @@ fn link_binary_output(sess: &Session, }; match crate_type { - config::CrateTypeRlib => { + config::CrateTypeRlib | config::CrateTypeMetadata => { link_rlib(sess, Some(trans), &objects, &out_filename, tmpdir.path()).build(); } @@ -403,6 +408,7 @@ fn link_rlib<'a>(sess: &'a Session, tmpdir: &Path) -> ArchiveBuilder<'a> { info!("preparing rlib from {:?} to {:?}", objects, out_filename); let mut ab = ArchiveBuilder::new(archive_config(sess, out_filename, None)); + for obj in objects { ab.add_file(obj); } diff --git a/src/librustc_trans/back/write.rs b/src/librustc_trans/back/write.rs index 01eea08c50bc5..29e3efb3b3a0d 100644 --- a/src/librustc_trans/back/write.rs +++ b/src/librustc_trans/back/write.rs @@ -691,10 +691,12 @@ 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::CrateTypeRlib) && + sess.opts.output_types.contains_key(&OutputType::Exe)) || + sess.crate_types.borrow().contains(&config::CrateTypeMetadata); let needs_crate_object = - sess.opts.output_types.contains_key(&OutputType::Exe); + sess.opts.output_types.contains_key(&OutputType::Exe) || + sess.crate_types.borrow().contains(&config::CrateTypeMetadata); if needs_crate_bitcode { modules_config.emit_bc = true; } diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index 0c0b7fbf4afea..59d81d5c6902d 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -45,7 +45,7 @@ use rustc::ty::adjustment::CustomCoerceUnsized; use rustc::dep_graph::{DepNode, WorkProduct}; use rustc::hir::map as hir_map; use rustc::util::common::time; -use session::config::{self, NoDebugInfo}; +use session::config::{self, NoDebugInfo, OutputType}; use rustc_incremental::IncrementalHashesMap; use session::Session; use abi::{self, Abi, FnType}; @@ -1260,7 +1260,8 @@ fn write_metadata(cx: &SharedCrateContext, config::CrateTypeStaticlib | config::CrateTypeCdylib => MetadataKind::None, - config::CrateTypeRlib => MetadataKind::Uncompressed, + config::CrateTypeRlib | + config::CrateTypeMetadata => MetadataKind::Uncompressed, config::CrateTypeDylib | config::CrateTypeProcMacro => MetadataKind::Compressed, @@ -1600,7 +1601,8 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, assert_module_sources::assert_module_sources(tcx, &modules); // Skip crate items and just output metadata in -Z no-trans mode. - if tcx.sess.opts.debugging_opts.no_trans { + if tcx.sess.opts.debugging_opts.no_trans || + tcx.sess.crate_types.borrow().iter().all(|ct| ct == &config::CrateTypeMetadata) { let linker_info = LinkerInfo::new(&shared_ccx, &[]); return CrateTranslation { modules: modules, diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index 3cc14541fcdf2..e732ff6b64c17 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -396,7 +396,8 @@ actual:\n\ // FIXME (#9639): This needs to handle non-utf8 paths let mut args = vec!["-".to_owned(), - "-Zno-trans".to_owned(), + "--emit".to_owned(), + "metadata".to_owned(), "--out-dir".to_owned(), out_dir.to_str().unwrap().to_owned(), format!("--target={}", target), From 534556a445743d605cba8dc552c732ff1eb7d925 Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Thu, 10 Nov 2016 15:57:30 +1300 Subject: [PATCH 2/4] Read in rmeta crates --- src/librustc/middle/cstore.rs | 39 ++++++++++++------ src/librustc/middle/dependency_format.rs | 2 +- src/librustc_driver/driver.rs | 1 - src/librustc_metadata/creader.rs | 9 +++- src/librustc_metadata/cstore.rs | 15 +++++-- src/librustc_metadata/cstore_impl.rs | 5 +-- src/librustc_metadata/locator.rs | 52 ++++++++++++++++-------- src/librustc_trans/back/link.rs | 13 +++--- src/librustc_trans/back/rpath.rs | 5 ++- src/librustc_trans/base.rs | 2 +- 10 files changed, 93 insertions(+), 50 deletions(-) diff --git a/src/librustc/middle/cstore.rs b/src/librustc/middle/cstore.rs index f61978271e7f6..1468e94459e63 100644 --- a/src/librustc/middle/cstore.rs +++ b/src/librustc/middle/cstore.rs @@ -56,24 +56,37 @@ pub struct LinkMeta { pub crate_hash: Svh, } -// Where a crate came from on the local filesystem. One of these two options +// Where a crate came from on the local filesystem. One of these three options // must be non-None. #[derive(PartialEq, Clone, Debug)] pub struct CrateSource { pub dylib: Option<(PathBuf, PathKind)>, pub rlib: Option<(PathBuf, PathKind)>, + 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), + MetadataOnly, + None, +} + +impl LibSource { + pub fn is_some(&self) -> bool { + if let LibSource::Some(_) = *self { + true + } else { + false + } + } + + pub fn option(&self) -> Option { + match *self { + LibSource::Some(ref p) => Some(p.clone()), + LibSource::MetadataOnly | LibSource::None => None, + } + } } #[derive(Copy, Debug, PartialEq, Clone, RustcEncodable, RustcDecodable)] @@ -244,7 +257,7 @@ pub trait CrateStore<'tcx> { // utility functions fn metadata_filename(&self) -> &str; fn metadata_section_name(&self, target: &Target) -> &str; - fn used_crates(&self, prefer: LinkagePreference) -> Vec<(CrateNum, Option)>; + 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; fn encode_metadata<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, @@ -427,7 +440,7 @@ impl<'tcx> CrateStore<'tcx> for DummyCrateStore { // 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, Option)> + fn used_crates(&self, prefer: LinkagePreference) -> Vec<(CrateNum, LibSource)> { vec![] } fn used_crate_source(&self, cnum: CrateNum) -> CrateSource { bug!("used_crate_source") } fn extern_mod_stmt_cnum(&self, emod_id: ast::NodeId) -> Option { None } diff --git a/src/librustc/middle/dependency_format.rs b/src/librustc/middle/dependency_format.rs index aeccaac385ac5..ee7f13f9e6e22 100644 --- a/src/librustc/middle/dependency_format.rs +++ b/src/librustc/middle/dependency_format.rs @@ -192,7 +192,7 @@ fn calculate_type(sess: &session::Session, if src.dylib.is_none() && !formats.contains_key(&cnum) && sess.cstore.dep_kind(cnum) == DepKind::Explicit { - assert!(src.rlib.is_some()); + assert!(src.rlib.is_some() || src.rmeta.is_some()); info!("adding staticlib: {}", sess.cstore.crate_name(cnum)); add_library(sess, cnum, RequireStatic, &mut formats); ret[cnum.as_usize() - 1] = Linkage::Static; diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index 9c207108374db..6a3a1bbb55ca2 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -1093,7 +1093,6 @@ pub fn phase_5_run_llvm_passes(sess: &Session, "serialize work products", move || rustc_incremental::save_work_products(sess)); - println!("finish phase 5: {}", sess.err_count()); if sess.err_count() > 0 { Err(sess.err_count()) } else { diff --git a/src/librustc_metadata/creader.rs b/src/librustc_metadata/creader.rs index 313b3b0fddf4d..693b04ae661cd 100644 --- a/src/librustc_metadata/creader.rs +++ b/src/librustc_metadata/creader.rs @@ -44,6 +44,7 @@ use log; pub struct Library { pub dylib: Option<(PathBuf, PathKind)>, pub rlib: Option<(PathBuf, PathKind)>, + pub rmeta: Option<(PathBuf, PathKind)>, pub metadata: MetadataBlob, } @@ -62,9 +63,11 @@ fn dump_crates(cstore: &CStore) { info!(" cnum: {}", data.cnum); info!(" hash: {}", data.hash()); info!(" reqd: {:?}", data.dep_kind.get()); - let CrateSource { dylib, rlib } = data.source.clone(); + let CrateSource { dylib, rlib, rmeta } = data.source.clone(); dylib.map(|dl| info!(" dylib: {}", dl.0.display())); rlib.map(|rl| info!(" rlib: {}", rl.0.display())); + rmeta.map(|rl| info!(" rmeta: {}", rl.0.display())); + }); }) } @@ -278,6 +281,7 @@ impl<'a> CrateLoader<'a> { ident: ident.to_string(), dylib: lib.dylib.clone().map(|p| p.0), rlib: lib.rlib.clone().map(|p| p.0), + rmeta: lib.rmeta.clone().map(|p| p.0), }) } else { None @@ -285,7 +289,7 @@ impl<'a> CrateLoader<'a> { // Maintain a reference to the top most crate. let root = if root.is_some() { root } else { &crate_paths }; - let Library { dylib, rlib, metadata } = lib; + let Library { dylib, rlib, rmeta, metadata } = lib; let cnum_map = self.resolve_crate_deps(root, &crate_root, &metadata, cnum, span, dep_kind); @@ -305,6 +309,7 @@ impl<'a> CrateLoader<'a> { source: cstore::CrateSource { dylib: dylib, rlib: rlib, + rmeta: rmeta, }, }); diff --git a/src/librustc_metadata/cstore.rs b/src/librustc_metadata/cstore.rs index 37853b7473a65..e5f7964d7eb9c 100644 --- a/src/librustc_metadata/cstore.rs +++ b/src/librustc_metadata/cstore.rs @@ -25,7 +25,6 @@ use rustc::util::nodemap::{FxHashMap, NodeMap, NodeSet, DefIdMap}; use std::cell::{RefCell, Cell}; use std::rc::Rc; -use std::path::PathBuf; use flate::Bytes; use syntax::{ast, attr}; use syntax::ext::base::SyntaxExtension; @@ -33,7 +32,7 @@ use syntax_pos; pub use rustc::middle::cstore::{NativeLibrary, LinkagePreference}; pub use rustc::middle::cstore::{NativeStatic, NativeFramework, NativeUnknown}; -pub use rustc::middle::cstore::{CrateSource, LinkMeta}; +pub use rustc::middle::cstore::{CrateSource, LinkMeta, LibSource}; // A map from external crate numbers (as decoded from some crate file) to // local crate numbers (as generated during this session). Each external @@ -185,7 +184,7 @@ impl CStore { // positions. pub fn do_get_used_crates(&self, prefer: LinkagePreference) - -> Vec<(CrateNum, Option)> { + -> Vec<(CrateNum, LibSource)> { let mut ordering = Vec::new(); for (&num, _) in self.metas.borrow().iter() { self.push_dependencies_in_postorder(&mut ordering, num); @@ -201,6 +200,16 @@ impl CStore { LinkagePreference::RequireDynamic => data.source.dylib.clone().map(|p| p.0), LinkagePreference::RequireStatic => data.source.rlib.clone().map(|p| p.0), }; + let path = match path { + Some(p) => LibSource::Some(p), + None => { + if data.rmeta.is_some() { + LibSource::MetadataOnly + } else { + LibSource::None + } + } + }; Some((cnum, path)) }) .collect::>(); diff --git a/src/librustc_metadata/cstore_impl.rs b/src/librustc_metadata/cstore_impl.rs index 2018d829597d4..cf8240db1958a 100644 --- a/src/librustc_metadata/cstore_impl.rs +++ b/src/librustc_metadata/cstore_impl.rs @@ -13,7 +13,7 @@ use encoder; use locator; use schema; -use rustc::middle::cstore::{InlinedItem, CrateStore, CrateSource, DepKind, ExternCrate}; +use rustc::middle::cstore::{InlinedItem, CrateStore, CrateSource, LibSource, DepKind, ExternCrate}; use rustc::middle::cstore::{NativeLibrary, LinkMeta, LinkagePreference, LoadedMacro}; use rustc::hir::def::{self, Def}; use rustc::middle::lang_items; @@ -28,7 +28,6 @@ use rustc::mir::Mir; use rustc::util::nodemap::{NodeSet, DefIdMap}; use rustc_back::PanicStrategy; -use std::path::PathBuf; use syntax::ast; use syntax::attr; use syntax::parse::{token, new_parser_from_source_str}; @@ -544,7 +543,7 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore { locator::meta_section_name(target) } - fn used_crates(&self, prefer: LinkagePreference) -> Vec<(CrateNum, Option)> + fn used_crates(&self, prefer: LinkagePreference) -> Vec<(CrateNum, LibSource)> { self.do_get_used_crates(prefer) } diff --git a/src/librustc_metadata/locator.rs b/src/librustc_metadata/locator.rs index b677a63edc064..6cdd8b4646405 100644 --- a/src/librustc_metadata/locator.rs +++ b/src/librustc_metadata/locator.rs @@ -53,6 +53,13 @@ //! 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 +//! 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 +//! error. +//! //! When translating a crate name to a crate on the filesystem, we all of a //! sudden need to take into account both rlibs and dylibs! Linkage later on may //! use either one of these files, as each has their pros/cons. The job of crate @@ -275,6 +282,7 @@ pub struct CratePaths { pub ident: String, pub dylib: Option, pub rlib: Option, + pub rmeta: Option, } pub const METADATA_FILENAME: &'static str = "rust.metadata.bin"; @@ -282,6 +290,7 @@ pub const METADATA_FILENAME: &'static str = "rust.metadata.bin"; #[derive(Copy, Clone, PartialEq)] enum CrateFlavor { Rlib, + Rmeta, Dylib, } @@ -289,6 +298,7 @@ impl fmt::Display for CrateFlavor { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.write_str(match *self { CrateFlavor::Rlib => "rlib", + CrateFlavor::Rmeta => "rmeta", CrateFlavor::Dylib => "dylib", }) } @@ -296,12 +306,7 @@ impl fmt::Display for CrateFlavor { impl CratePaths { fn paths(&self) -> Vec { - match (&self.dylib, &self.rlib) { - (&None, &None) => vec![], - (&Some(ref p), &None) | - (&None, &Some(ref p)) => vec![p.clone()], - (&Some(ref p1), &Some(ref p2)) => vec![p1.clone(), p2.clone()], - } + self.dylib.iter().chain(self.rlib.iter()).chain(self.rmeta.iter()).cloned().collect() } } @@ -457,11 +462,13 @@ impl<'a> Context<'a> { None => return FileDoesntMatch, Some(file) => file, }; - let (hash, rlib) = if file.starts_with(&rlib_prefix[..]) && file.ends_with(".rlib") { - (&file[(rlib_prefix.len())..(file.len() - ".rlib".len())], true) + 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())], false) + (&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 { @@ -475,14 +482,14 @@ impl<'a> Context<'a> { let hash_str = hash.to_string(); let slot = candidates.entry(hash_str) - .or_insert_with(|| (FxHashMap(), FxHashMap())); - let (ref mut rlibs, ref mut dylibs) = *slot; + .or_insert_with(|| (FxHashMap(), FxHashMap(), FxHashMap())); + let (ref mut rlibs, ref mut rmetas, ref mut dylibs) = *slot; fs::canonicalize(path) .map(|p| { - if rlib { - rlibs.insert(p, kind); - } else { - dylibs.insert(p, kind); + match found_kind { + CrateFlavor::Rlib => { rlibs.insert(p, kind); } + CrateFlavor::Rmeta => { rmetas.insert(p, kind); } + CrateFlavor::Dylib => { dylibs.insert(p, kind); } } FileMatches }) @@ -499,15 +506,17 @@ impl<'a> Context<'a> { // libraries corresponds to the crate id and hash criteria that this // search is being performed for. let mut libraries = FxHashMap(); - for (_hash, (rlibs, dylibs)) in candidates { + for (_hash, (rlibs, rmetas, dylibs)) in candidates { let mut slot = None; let rlib = self.extract_one(rlibs, CrateFlavor::Rlib, &mut slot); + let rmeta = self.extract_one(rmetas, CrateFlavor::Rmeta, &mut slot); let dylib = self.extract_one(dylibs, CrateFlavor::Dylib, &mut slot); if let Some((h, m)) = slot { libraries.insert(h, Library { dylib: dylib, rlib: rlib, + rmeta: rmeta, metadata: m, }); } @@ -703,6 +712,7 @@ impl<'a> Context<'a> { let sess = self.sess; let dylibname = self.dylibname(); let mut rlibs = FxHashMap(); + let mut rmetas = FxHashMap(); let mut dylibs = FxHashMap(); { let locs = locs.map(|l| PathBuf::from(l)).filter(|loc| { @@ -744,6 +754,8 @@ impl<'a> Context<'a> { for loc in locs { if loc.file_name().unwrap().to_str().unwrap().ends_with(".rlib") { rlibs.insert(fs::canonicalize(&loc).unwrap(), PathKind::ExternFlag); + } else if loc.file_name().unwrap().to_str().unwrap().ends_with(".rmeta") { + rmetas.insert(fs::canonicalize(&loc).unwrap(), PathKind::ExternFlag); } else { dylibs.insert(fs::canonicalize(&loc).unwrap(), PathKind::ExternFlag); } @@ -753,9 +765,10 @@ impl<'a> Context<'a> { // Extract the rlib/dylib pair. let mut slot = None; let rlib = self.extract_one(rlibs, CrateFlavor::Rlib, &mut slot); + let rmeta = self.extract_one(rmetas, CrateFlavor::Rmeta, &mut slot); let dylib = self.extract_one(dylibs, CrateFlavor::Dylib, &mut slot); - if rlib.is_none() && dylib.is_none() { + if rlib.is_none() && rmeta.is_none() && dylib.is_none() { return None; } match slot { @@ -763,6 +776,7 @@ impl<'a> Context<'a> { Some(Library { dylib: dylib, rlib: rlib, + rmeta: rmeta, metadata: metadata, }) } @@ -832,7 +846,7 @@ fn get_metadata_section_imp(target: &Target, if !filename.exists() { return Err(format!("no such file: '{}'", filename.display())); } - if flavor == CrateFlavor::Rlib { + if flavor == CrateFlavor::Rlib || flavor == CrateFlavor::Rmeta { // 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. @@ -933,6 +947,8 @@ pub fn list_file_metadata(target: &Target, path: &Path, out: &mut io::Write) -> let filename = path.file_name().unwrap().to_str().unwrap(); let flavor = if filename.ends_with(".rlib") { CrateFlavor::Rlib + } else if filename.ends_with(".rmeta") { + CrateFlavor::Rmeta } else { CrateFlavor::Dylib }; diff --git a/src/librustc_trans/back/link.rs b/src/librustc_trans/back/link.rs index fcbead49a2635..7938ddde4cec7 100644 --- a/src/librustc_trans/back/link.rs +++ b/src/librustc_trans/back/link.rs @@ -19,7 +19,7 @@ use session::config::{OutputFilenames, Input, OutputType}; use session::filesearch; use session::search_paths::PathKind; use session::Session; -use middle::cstore::{self, LinkMeta, NativeLibrary}; +use middle::cstore::{self, LinkMeta, NativeLibrary, LibSource}; use middle::cstore::{LinkagePreference, NativeLibraryKind}; use middle::dependency_format::Linkage; use CrateTranslation; @@ -123,7 +123,6 @@ pub fn find_crate_name(sess: Option<&Session>, } "rust_out".to_string() - } pub fn build_link_meta(incremental_hashes_map: &IncrementalHashesMap, @@ -302,7 +301,7 @@ pub fn each_linked_rlib(sess: &Session, .or_else(|| fmts.get(&config::CrateTypeCdylib)) .or_else(|| fmts.get(&config::CrateTypeProcMacro)); let fmts = fmts.unwrap_or_else(|| { - bug!("could not find formats for rlibs") + bug!("could not find formats for rlibs"); }); for (cnum, path) in crates { match fmts[cnum.as_usize() - 1] { @@ -311,8 +310,11 @@ pub fn each_linked_rlib(sess: &Session, } let name = sess.cstore.crate_name(cnum).clone(); let path = match path { - Some(p) => p, - None => { + LibSource::Some(p) => p, + LibSource::MetadataOnly => { + sess.fatal(&format!("could not find rlib for: `{}`, found rmeta (metadata) file", name)); + } + LibSource::None => { sess.fatal(&format!("could not find rlib for: `{}`", name)); } }; @@ -326,7 +328,6 @@ fn link_binary_output(sess: &Session, outputs: &OutputFilenames, crate_name: &str) -> PathBuf { let objects = object_filenames(trans, outputs); - println!("objects: {:?}", objects); let default_filename = filename_for_input(sess, crate_type, crate_name, outputs); let out_filename = outputs.outputs.get(&OutputType::Exe) diff --git a/src/librustc_trans/back/rpath.rs b/src/librustc_trans/back/rpath.rs index 8758cdcf9d0ab..ccaa0d4e1b1b0 100644 --- a/src/librustc_trans/back/rpath.rs +++ b/src/librustc_trans/back/rpath.rs @@ -14,9 +14,10 @@ use std::path::{Path, PathBuf}; use std::fs; use rustc::hir::def_id::CrateNum; +use rustc::middle::cstore::LibSource; pub struct RPathConfig<'a> { - pub used_crates: Vec<(CrateNum, Option)>, + pub used_crates: Vec<(CrateNum, LibSource)>, pub out_filename: PathBuf, pub is_like_osx: bool, pub has_rpath: bool, @@ -35,7 +36,7 @@ pub fn get_rpath_flags(config: &mut RPathConfig) -> Vec { debug!("preparing the RPATH!"); let libs = config.used_crates.clone(); - let libs = libs.into_iter().filter_map(|(_, l)| l).collect::>(); + let libs = libs.into_iter().filter_map(|(_, l)| l.option()).collect::>(); let rpaths = get_rpaths(config, &libs[..]); flags.extend_from_slice(&rpaths_to_flags(&rpaths[..])); diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index 59d81d5c6902d..c006eb9156b6c 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -45,7 +45,7 @@ use rustc::ty::adjustment::CustomCoerceUnsized; use rustc::dep_graph::{DepNode, WorkProduct}; use rustc::hir::map as hir_map; use rustc::util::common::time; -use session::config::{self, NoDebugInfo, OutputType}; +use session::config::{self, NoDebugInfo}; use rustc_incremental::IncrementalHashesMap; use session::Session; use abi::{self, Abi, FnType}; From baedc3b70ff8ac14a1411b5780112eadd1d63413 Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Thu, 10 Nov 2016 18:29:27 +1300 Subject: [PATCH 3/4] Tests --- src/librustc_driver/driver.rs | 3 +++ src/test/compile-fail/auxiliary/rmeta_meta.rs | 17 ++++++++++++ src/test/compile-fail/auxiliary/rmeta_rlib.rs | 15 +++++++++++ src/test/compile-fail/rmeta-lib-pass.rs | 25 ++++++++++++++++++ src/test/compile-fail/rmeta-pass.rs | 26 +++++++++++++++++++ src/test/compile-fail/rmeta.rs | 19 ++++++++++++++ src/test/compile-fail/rmeta_lib.rs | 23 ++++++++++++++++ src/test/compile-fail/rmeta_meta_main.rs | 24 +++++++++++++++++ src/tools/compiletest/src/runtest.rs | 3 +-- 9 files changed, 153 insertions(+), 2 deletions(-) create mode 100644 src/test/compile-fail/auxiliary/rmeta_meta.rs create mode 100644 src/test/compile-fail/auxiliary/rmeta_rlib.rs create mode 100644 src/test/compile-fail/rmeta-lib-pass.rs create mode 100644 src/test/compile-fail/rmeta-pass.rs create mode 100644 src/test/compile-fail/rmeta.rs create mode 100644 src/test/compile-fail/rmeta_lib.rs create mode 100644 src/test/compile-fail/rmeta_meta_main.rs diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index 6a3a1bbb55ca2..5a3c481f6455f 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -1185,6 +1185,9 @@ pub fn collect_crate_types(session: &Session, attrs: &[ast::Attribute]) -> Vec { Some(config::CrateTypeRlib) } + Some(ref n) if *n == "metadata" => { + Some(config::CrateTypeMetadata) + } Some(ref n) if *n == "dylib" => { Some(config::CrateTypeDylib) } diff --git a/src/test/compile-fail/auxiliary/rmeta_meta.rs b/src/test/compile-fail/auxiliary/rmeta_meta.rs new file mode 100644 index 0000000000000..7bd1a96f452d8 --- /dev/null +++ b/src/test/compile-fail/auxiliary/rmeta_meta.rs @@ -0,0 +1,17 @@ +// 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"] + +pub struct Foo { + pub field: i32, +} diff --git a/src/test/compile-fail/auxiliary/rmeta_rlib.rs b/src/test/compile-fail/auxiliary/rmeta_rlib.rs new file mode 100644 index 0000000000000..6096c4df05bb0 --- /dev/null +++ b/src/test/compile-fail/auxiliary/rmeta_rlib.rs @@ -0,0 +1,15 @@ +// 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. + +#![crate_type="rlib"] + +pub struct Foo { + pub field: i32, +} diff --git a/src/test/compile-fail/rmeta-lib-pass.rs b/src/test/compile-fail/rmeta-lib-pass.rs new file mode 100644 index 0000000000000..f2ac37a2ce9f5 --- /dev/null +++ b/src/test/compile-fail/rmeta-lib-pass.rs @@ -0,0 +1,25 @@ +// 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. + +// aux-build:rmeta_rlib.rs +// no-prefer-dynamic +// must-compile-successfully + +// Check that building a metadata crate works with a dependent, rlib crate. +// This is a cfail test since there is no executable to run. + +#![crate_type="metadata"] + +extern crate rmeta_rlib; +use rmeta_rlib::Foo; + +pub fn main() { + let _ = Foo { field: 42 }; +} diff --git a/src/test/compile-fail/rmeta-pass.rs b/src/test/compile-fail/rmeta-pass.rs new file mode 100644 index 0000000000000..2c0b6f77c1e08 --- /dev/null +++ b/src/test/compile-fail/rmeta-pass.rs @@ -0,0 +1,26 @@ +// 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. + +// aux-build:rmeta_meta.rs +// no-prefer-dynamic +// must-compile-successfully + +// Check that building a metadata crate works with a dependent, metadata-only +// crate. +// This is a cfail test since there is no executable to run. + +#![crate_type="metadata"] + +extern crate rmeta_meta; +use rmeta_meta::Foo; + +pub fn main() { + let _ = Foo { field: 42 }; +} diff --git a/src/test/compile-fail/rmeta.rs b/src/test/compile-fail/rmeta.rs new file mode 100644 index 0000000000000..e81e0541096d6 --- /dev/null +++ b/src/test/compile-fail/rmeta.rs @@ -0,0 +1,19 @@ +// 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 + +// Check that building a metadata crate finds an error. + +#![crate_type="metadata"] + +fn main() { + let _ = Foo; //~ ERROR unresolved name `Foo` +} diff --git a/src/test/compile-fail/rmeta_lib.rs b/src/test/compile-fail/rmeta_lib.rs new file mode 100644 index 0000000000000..3b7d1f3cc904a --- /dev/null +++ b/src/test/compile-fail/rmeta_lib.rs @@ -0,0 +1,23 @@ +// 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. + +// aux-build:rmeta_meta.rs +// no-prefer-dynamic +// error-pattern: crate `rmeta_meta` required to be available in rlib, but it was not available + +// Check that building a non-metadata crate fails if a dependent crate is +// metadata-only. + +extern crate rmeta_meta; +use rmeta_meta::Foo; + +fn main() { + let _ = Foo { field: 42 }; +} diff --git a/src/test/compile-fail/rmeta_meta_main.rs b/src/test/compile-fail/rmeta_meta_main.rs new file mode 100644 index 0000000000000..1c922c281397a --- /dev/null +++ b/src/test/compile-fail/rmeta_meta_main.rs @@ -0,0 +1,24 @@ +// 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. + +// aux-build:rmeta_meta.rs +// no-prefer-dynamic + +// Check that building a metadata crate finds an error with a dependent, +// metadata-only crate. + +#![crate_type="metadata"] + +extern crate rmeta_meta; +use rmeta_meta::Foo; + +fn main() { + let _ = Foo { field2: 42 }; //~ ERROR struct `rmeta_meta::Foo` has no field named `field2` +} diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index e732ff6b64c17..3cc14541fcdf2 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -396,8 +396,7 @@ actual:\n\ // FIXME (#9639): This needs to handle non-utf8 paths let mut args = vec!["-".to_owned(), - "--emit".to_owned(), - "metadata".to_owned(), + "-Zno-trans".to_owned(), "--out-dir".to_owned(), out_dir.to_str().unwrap().to_owned(), format!("--target={}", target), From af1b19555ce636788c19dba979b57536792d90e9 Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Fri, 11 Nov 2016 10:00:33 +1300 Subject: [PATCH 4/4] 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 1468e94459e63..653f9852e66da 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 4a0732882730e..3dc533d61f0bd 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 693b04ae661cd..12a70da636de7 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 e5f7964d7eb9c..c2ed7ca7ce047 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 3af9d291ae55a..3ba899f41d8c4 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 6cdd8b4646405..2b06851cb8bdb 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 7938ddde4cec7..40c2de7b88974 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 29e3efb3b3a0d..01eea08c50bc5 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 0000000000000..28c11315fa1cd --- /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 0000000000000..394845b66f3d3 --- /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 0000000000000..11684d8663af8 --- /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 }; +}