about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2016-11-22 21:54:10 -0600
committerGitHub <noreply@github.com>2016-11-22 21:54:10 -0600
commit5196ca85189291adbb488339b321026a95330c45 (patch)
tree964d130609bc82c03bc10f440f883a3460e4adba /src
parent1cabe2151299c63497abc3a20bd08c04c0cd32a3 (diff)
parentaf1b19555ce636788c19dba979b57536792d90e9 (diff)
downloadrust-5196ca85189291adbb488339b321026a95330c45.tar.gz
rust-5196ca85189291adbb488339b321026a95330c45.zip
Auto merge of #37681 - nrc:crate-metadata, r=@alexcrichton
add --crate-type metadata

r? @alexcrichton
Diffstat (limited to 'src')
-rw-r--r--src/librustc/middle/cstore.rs31
-rw-r--r--src/librustc/middle/dependency_format.rs4
-rw-r--r--src/librustc/middle/reachable.rs2
-rw-r--r--src/librustc/middle/weak_lang_items.rs3
-rw-r--r--src/librustc/session/config.rs29
-rw-r--r--src/librustc_driver/driver.rs3
-rw-r--r--src/librustc_metadata/creader.rs13
-rw-r--r--src/librustc_metadata/cstore.rs16
-rw-r--r--src/librustc_metadata/cstore_impl.rs5
-rw-r--r--src/librustc_metadata/decoder.rs3
-rw-r--r--src/librustc_metadata/locator.rs89
-rw-r--r--src/librustc_trans/back/archive.rs2
-rw-r--r--src/librustc_trans/back/link.rs37
-rw-r--r--src/librustc_trans/back/rpath.rs5
-rw-r--r--src/librustc_trans/base.rs6
-rw-r--r--src/test/compile-fail/auxiliary/rmeta_meta.rs17
-rw-r--r--src/test/compile-fail/auxiliary/rmeta_rlib.rs15
-rw-r--r--src/test/compile-fail/rmeta-lib-pass.rs25
-rw-r--r--src/test/compile-fail/rmeta-pass.rs26
-rw-r--r--src/test/compile-fail/rmeta.rs19
-rw-r--r--src/test/compile-fail/rmeta_lib.rs23
-rw-r--r--src/test/compile-fail/rmeta_meta_main.rs24
-rw-r--r--src/test/run-pass/auxiliary/rmeta_rlib.rs18
-rw-r--r--src/test/run-pass/auxiliary/rmeta_rmeta.rs18
-rw-r--r--src/test/run-pass/rmeta.rs22
25 files changed, 374 insertions, 81 deletions
diff --git a/src/librustc/middle/cstore.rs b/src/librustc/middle/cstore.rs
index 168aba77433..a7f28dd6d58 100644
--- a/src/librustc/middle/cstore.rs
+++ b/src/librustc/middle/cstore.rs
@@ -56,12 +56,13 @@ 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)]
@@ -76,6 +77,30 @@ pub enum DepKind {
     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<PathBuf> {
+        match *self {
+            LibSource::Some(ref p) => Some(p.clone()),
+            LibSource::MetadataOnly | LibSource::None => None,
+        }
+    }
+}
+
 #[derive(Copy, Debug, PartialEq, Clone, RustcEncodable, RustcDecodable)]
 pub enum LinkagePreference {
     RequireDynamic,
@@ -244,7 +269,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<PathBuf>)>;
+    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 encode_metadata<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>,
@@ -427,7 +452,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<PathBuf>)>
+    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<CrateNum> { None }
diff --git a/src/librustc/middle/dependency_format.rs b/src/librustc/middle/dependency_format.rs
index 92d1ab85c5a..ee7f13f9e6e 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.
@@ -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/middle/reachable.rs b/src/librustc/middle/reachable.rs
index ac614494355..35e0e494771 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 ec6971d596b..30690c09919 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 103e2a949df..f3677b80819 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)]
@@ -1147,7 +1148,7 @@ pub fn rustc_short_optgroups() -> Vec<RustcOptGroup> {
                              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 \
@@ -1539,6 +1540,7 @@ pub fn parse_crate_types_from_list(list_list: Vec<String>) -> Result<Vec<CrateTy
                 "cdylib"    => CrateTypeCdylib,
                 "bin"       => CrateTypeExecutable,
                 "proc-macro" => CrateTypeProcMacro,
+                "metadata"  => CrateTypeMetadata,
                 _ => {
                     return Err(format!("unknown crate type: `{}`",
                                        part));
@@ -1623,6 +1625,7 @@ impl fmt::Display for CrateType {
             CrateTypeStaticlib => "staticlib".fmt(f),
             CrateTypeCdylib => "cdylib".fmt(f),
             CrateTypeProcMacro => "proc-macro".fmt(f),
+            CrateTypeMetadata => "metadata".fmt(f),
         }
     }
 }
diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs
index 756b0457b78..5cbb8f93fc9 100644
--- a/src/librustc_driver/driver.rs
+++ b/src/librustc_driver/driver.rs
@@ -1182,6 +1182,9 @@ pub fn collect_crate_types(session: &Session, attrs: &[ast::Attribute]) -> Vec<c
                          Some(ref n) if *n == "rlib" => {
                              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/librustc_metadata/creader.rs b/src/librustc_metadata/creader.rs
index 269fb1dcea4..27c00481bfd 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,10 +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()));
+    });
 }
 
 #[derive(Debug)]
@@ -278,6 +280,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 +288,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 +308,7 @@ impl<'a> CrateLoader<'a> {
             source: cstore::CrateSource {
                 dylib: dylib,
                 rlib: rlib,
+                rmeta: rmeta,
             },
         });
 
@@ -767,7 +771,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_metadata/cstore.rs b/src/librustc_metadata/cstore.rs
index ce47b936ddc..7c1834c1576 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;
@@ -34,7 +33,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
@@ -45,6 +44,7 @@ pub type CrateNumMap = IndexVec<CrateNum, CrateNum>;
 pub enum MetadataBlob {
     Inflated(Bytes),
     Archive(locator::ArchiveMetadata),
+    Raw(Vec<u8>),
 }
 
 /// Holds information about a syntax_pos::FileMap imported from another crate.
@@ -186,7 +186,7 @@ impl CStore {
     // positions.
     pub fn do_get_used_crates(&self,
                               prefer: LinkagePreference)
-                              -> Vec<(CrateNum, Option<PathBuf>)> {
+                              -> Vec<(CrateNum, LibSource)> {
         let mut ordering = Vec::new();
         for (&num, _) in self.metas.borrow().iter() {
             self.push_dependencies_in_postorder(&mut ordering, num);
@@ -202,6 +202,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.source.rmeta.is_some() {
+                            LibSource::MetadataOnly
+                        } else {
+                            LibSource::None
+                        }
+                    }
+                };
                 Some((cnum, path))
             })
             .collect::<Vec<_>>();
diff --git a/src/librustc_metadata/cstore_impl.rs b/src/librustc_metadata/cstore_impl.rs
index 407166203de..ead933384b9 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::new_parser_from_source_str;
@@ -545,7 +544,7 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore {
         locator::meta_section_name(target)
     }
 
-    fn used_crates(&self, prefer: LinkagePreference) -> Vec<(CrateNum, Option<PathBuf>)>
+    fn used_crates(&self, prefer: LinkagePreference) -> Vec<(CrateNum, LibSource)>
     {
         self.do_get_used_crates(prefer)
     }
diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs
index fb1314992c0..8a187bb9796 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 f5196f7ea84..be9284baa74 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 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
+//! 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
@@ -233,8 +240,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;
@@ -276,6 +283,7 @@ pub struct CratePaths {
     pub ident: String,
     pub dylib: Option<PathBuf>,
     pub rlib: Option<PathBuf>,
+    pub rmeta: Option<PathBuf>,
 }
 
 pub const METADATA_FILENAME: &'static str = "rust.metadata.bin";
@@ -283,6 +291,7 @@ pub const METADATA_FILENAME: &'static str = "rust.metadata.bin";
 #[derive(Copy, Clone, PartialEq)]
 enum CrateFlavor {
     Rlib,
+    Rmeta,
     Dylib,
 }
 
@@ -290,6 +299,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",
         })
     }
@@ -297,12 +307,7 @@ impl fmt::Display for CrateFlavor {
 
 impl CratePaths {
     fn paths(&self) -> Vec<PathBuf> {
-        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()
     }
 }
 
@@ -458,32 +463,35 @@ 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)
-            } else if file.starts_with(&dylib_prefix) &&
-                                         file.ends_with(&dypair.1) {
-                (&file[(dylib_prefix.len())..(file.len() - dypair.1.len())], false)
-            } 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();
             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
                 })
@@ -500,15 +508,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,
                                  });
             }
@@ -704,6 +714,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| {
@@ -722,7 +733,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;
@@ -745,6 +757,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);
                 }
@@ -754,9 +768,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 {
@@ -764,6 +779,7 @@ impl<'a> Context<'a> {
                 Some(Library {
                     dylib: dylib,
                     rlib: rlib,
+                    rmeta: rmeta,
                     metadata: metadata,
                 })
             }
@@ -851,6 +867,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);
@@ -934,6 +959,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/archive.rs b/src/librustc_trans/back/archive.rs
index df8dd7750ae..11ab6dcaa87 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<ArchiveKind, &str> {
-        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 d0339775a78..648dc4c24c9 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;
@@ -124,7 +124,6 @@ pub fn find_crate_name(sess: Option<&Session>,
     }
 
     "rust_out".to_string()
-
 }
 
 pub fn build_link_meta(incremental_hashes_map: &IncrementalHashesMap,
@@ -264,6 +263,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 => {
@@ -299,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] {
@@ -308,8 +310,12 @@ 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));
             }
         };
@@ -353,6 +359,9 @@ fn link_binary_output(sess: &Session,
         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());
@@ -391,6 +400,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
@@ -404,6 +420,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);
     }
@@ -465,15 +482,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/rpath.rs b/src/librustc_trans/back/rpath.rs
index 8758cdcf9d0..ccaa0d4e1b1 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<PathBuf>)>,
+    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<String> {
     debug!("preparing the RPATH!");
 
     let libs = config.used_crates.clone();
-    let libs = libs.into_iter().filter_map(|(_, l)| l).collect::<Vec<_>>();
+    let libs = libs.into_iter().filter_map(|(_, l)| l.option()).collect::<Vec<_>>();
     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 78a676d3033..4353c7bd586 100644
--- a/src/librustc_trans/base.rs
+++ b/src/librustc_trans/base.rs
@@ -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/test/compile-fail/auxiliary/rmeta_meta.rs b/src/test/compile-fail/auxiliary/rmeta_meta.rs
new file mode 100644
index 00000000000..7bd1a96f452
--- /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 <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.
+
+// 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 00000000000..6096c4df05b
--- /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 <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.
+
+#![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 00000000000..f2ac37a2ce9
--- /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 <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.
+
+// 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 00000000000..2c0b6f77c1e
--- /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 <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.
+
+// 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 00000000000..e81e0541096
--- /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 <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.
+
+// 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 00000000000..3b7d1f3cc90
--- /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 <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.
+
+// 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 00000000000..1c922c28139
--- /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 <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.
+
+// 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/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 <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.
+
+// 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 <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.
+
+// 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 <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.
+
+// 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 };
+}