about summary refs log tree commit diff
diff options
context:
space:
mode:
m---------src/liblibc0
-rw-r--r--src/librustc/middle/cstore.rs17
-rw-r--r--src/librustc_back/target/linux_musl_base.rs4
-rw-r--r--src/librustc_back/target/mod.rs6
-rw-r--r--src/librustc_driver/target_features.rs29
-rw-r--r--src/librustc_metadata/creader.rs49
-rw-r--r--src/librustc_metadata/cstore.rs12
-rw-r--r--src/librustc_metadata/cstore_impl.rs6
-rw-r--r--src/librustc_metadata/decoder.rs4
-rw-r--r--src/librustc_metadata/encoder.rs11
-rw-r--r--src/librustc_metadata/schema.rs4
-rw-r--r--src/librustc_trans/back/archive.rs27
-rw-r--r--src/librustc_trans/back/link.rs154
-rw-r--r--src/librustc_trans/back/write.rs11
-rw-r--r--src/libsyntax/feature_gate.rs3
-rw-r--r--src/test/compile-fail/crt-static-gated.rs14
-rw-r--r--src/test/compile-fail/link-cfg-gated.rs15
-rw-r--r--src/test/run-make/link-cfg/Makefile22
-rw-r--r--src/test/run-make/link-cfg/dep-with-staticlib.rs18
-rw-r--r--src/test/run-make/link-cfg/dep.rs18
-rw-r--r--src/test/run-make/link-cfg/no-deps.rs30
-rw-r--r--src/test/run-make/link-cfg/return1.c16
-rw-r--r--src/test/run-make/link-cfg/return2.c16
-rw-r--r--src/test/run-make/link-cfg/return3.c16
-rw-r--r--src/test/run-make/link-cfg/with-deps.rs24
-rw-r--r--src/test/run-make/link-cfg/with-staticlib-deps.rs24
-rw-r--r--src/test/run-pass/auxiliary/link-cfg-works-transitive-dylib.rs14
-rw-r--r--src/test/run-pass/auxiliary/link-cfg-works-transitive-rlib.rs17
-rw-r--r--src/test/run-pass/crt-static-off-works.rs17
-rw-r--r--src/test/run-pass/crt-static-on-works.rs16
-rw-r--r--src/test/run-pass/link-cfg-works.rs23
31 files changed, 546 insertions, 91 deletions
diff --git a/src/liblibc b/src/liblibc
-Subproject 7d9b71f0971f8fa196d864d7071f216a59036d6
+Subproject 6e8c1b490ccbe5e84d248bab883515bc85394b5
diff --git a/src/librustc/middle/cstore.rs b/src/librustc/middle/cstore.rs
index 3583ccdb97b..f61978271e7 100644
--- a/src/librustc/middle/cstore.rs
+++ b/src/librustc/middle/cstore.rs
@@ -89,6 +89,13 @@ pub enum NativeLibraryKind {
     NativeUnknown,   // default way to specify a dynamic library
 }
 
+#[derive(Clone, Hash, RustcEncodable, RustcDecodable)]
+pub struct NativeLibrary {
+    pub kind: NativeLibraryKind,
+    pub name: String,
+    pub cfg: Option<P<ast::MetaItem>>,
+}
+
 /// The data we save and restore about an inlined item or method.  This is not
 /// part of the AST that we parse from a file, but it becomes part of the tree
 /// that we trans.
@@ -204,7 +211,7 @@ pub trait CrateStore<'tcx> {
     fn crate_hash(&self, cnum: CrateNum) -> Svh;
     fn crate_disambiguator(&self, cnum: CrateNum) -> InternedString;
     fn plugin_registrar_fn(&self, cnum: CrateNum) -> Option<DefId>;
-    fn native_libraries(&self, cnum: CrateNum) -> Vec<(NativeLibraryKind, String)>;
+    fn native_libraries(&self, cnum: CrateNum) -> Vec<NativeLibrary>;
     fn reachable_ids(&self, cnum: CrateNum) -> Vec<DefId>;
     fn is_no_builtins(&self, cnum: CrateNum) -> bool;
 
@@ -231,7 +238,7 @@ pub trait CrateStore<'tcx> {
     // This is basically a 1-based range of ints, which is a little
     // silly - I may fix that.
     fn crates(&self) -> Vec<CrateNum>;
-    fn used_libraries(&self) -> Vec<(String, NativeLibraryKind)>;
+    fn used_libraries(&self) -> Vec<NativeLibrary>;
     fn used_link_args(&self) -> Vec<String>;
 
     // utility functions
@@ -377,7 +384,7 @@ impl<'tcx> CrateStore<'tcx> for DummyCrateStore {
                            -> InternedString { bug!("crate_disambiguator") }
     fn plugin_registrar_fn(&self, cnum: CrateNum) -> Option<DefId>
         { bug!("plugin_registrar_fn") }
-    fn native_libraries(&self, cnum: CrateNum) -> Vec<(NativeLibraryKind, String)>
+    fn native_libraries(&self, cnum: CrateNum) -> Vec<NativeLibrary>
         { bug!("native_libraries") }
     fn reachable_ids(&self, cnum: CrateNum) -> Vec<DefId> { bug!("reachable_ids") }
     fn is_no_builtins(&self, cnum: CrateNum) -> bool { bug!("is_no_builtins") }
@@ -412,7 +419,9 @@ impl<'tcx> CrateStore<'tcx> for DummyCrateStore {
     // This is basically a 1-based range of ints, which is a little
     // silly - I may fix that.
     fn crates(&self) -> Vec<CrateNum> { vec![] }
-    fn used_libraries(&self) -> Vec<(String, NativeLibraryKind)> { vec![] }
+    fn used_libraries(&self) -> Vec<NativeLibrary> {
+        vec![]
+    }
     fn used_link_args(&self) -> Vec<String> { vec![] }
 
     // utility functions
diff --git a/src/librustc_back/target/linux_musl_base.rs b/src/librustc_back/target/linux_musl_base.rs
index d55907aeedf..18cca425a32 100644
--- a/src/librustc_back/target/linux_musl_base.rs
+++ b/src/librustc_back/target/linux_musl_base.rs
@@ -16,7 +16,6 @@ pub fn opts() -> TargetOptions {
     // Make sure that the linker/gcc really don't pull in anything, including
     // default objects, libs, etc.
     base.pre_link_args.push("-nostdlib".to_string());
-    base.pre_link_args.push("-static".to_string());
 
     // At least when this was tested, the linker would not add the
     // `GNU_EH_FRAME` program header to executables generated, which is required
@@ -67,5 +66,8 @@ pub fn opts() -> TargetOptions {
     base.has_rpath = false;
     base.position_independent_executables = false;
 
+    // These targets statically link libc by default
+    base.crt_static_default = true;
+
     base
 }
diff --git a/src/librustc_back/target/mod.rs b/src/librustc_back/target/mod.rs
index cc04582b19e..f195ccb3f42 100644
--- a/src/librustc_back/target/mod.rs
+++ b/src/librustc_back/target/mod.rs
@@ -373,6 +373,9 @@ pub struct TargetOptions {
     /// A blacklist of ABIs unsupported by the current target. Note that generic
     /// ABIs are considered to be supported on all platforms and cannot be blacklisted.
     pub abi_blacklist: Vec<Abi>,
+
+    /// Whether or not the CRT is statically linked by default.
+    pub crt_static_default: bool,
 }
 
 impl Default for TargetOptions {
@@ -425,6 +428,7 @@ impl Default for TargetOptions {
             max_atomic_width: None,
             panic_strategy: PanicStrategy::Unwind,
             abi_blacklist: vec![],
+            crt_static_default: false,
         }
     }
 }
@@ -585,6 +589,7 @@ impl Target {
         key!(no_integrated_as, bool);
         key!(max_atomic_width, Option<u64>);
         try!(key!(panic_strategy, PanicStrategy));
+        key!(crt_static_default, bool);
 
         if let Some(array) = obj.find("abi-blacklist").and_then(Json::as_array) {
             for name in array.iter().filter_map(|abi| abi.as_string()) {
@@ -745,6 +750,7 @@ impl ToJson for Target {
         target_option_val!(no_integrated_as);
         target_option_val!(max_atomic_width);
         target_option_val!(panic_strategy);
+        target_option_val!(crt_static_default);
 
         if default.abi_blacklist != self.options.abi_blacklist {
             d.insert("abi-blacklist".to_string(), self.options.abi_blacklist.iter()
diff --git a/src/librustc_driver/target_features.rs b/src/librustc_driver/target_features.rs
index ba51947a333..57a9edc5c58 100644
--- a/src/librustc_driver/target_features.rs
+++ b/src/librustc_driver/target_features.rs
@@ -12,6 +12,7 @@ use syntax::{ast, attr};
 use llvm::LLVMRustHasFeature;
 use rustc::session::Session;
 use rustc_trans::back::write::create_target_machine;
+use syntax::feature_gate::UnstableFeatures;
 use syntax::parse::token::InternedString;
 use syntax::parse::token::intern_and_get_ident as intern;
 use libc::c_char;
@@ -47,4 +48,32 @@ pub fn add_configuration(cfg: &mut ast::CrateConfig, sess: &Session) {
             cfg.push(attr::mk_name_value_item_str(tf.clone(), intern(&feat[..feat.len() - 1])))
         }
     }
+
+    let requested_features = sess.opts.cg.target_feature.split(',');
+    let unstable_options = sess.opts.debugging_opts.unstable_options;
+    let is_nightly = UnstableFeatures::from_environment().is_nightly_build();
+    let found_negative = requested_features.clone().any(|r| r == "-crt-static");
+    let found_positive = requested_features.clone().any(|r| r == "+crt-static");
+
+    // If the target we're compiling for requests a static crt by default,
+    // then see if the `-crt-static` feature was passed to disable that.
+    // Otherwise if we don't have a static crt by default then see if the
+    // `+crt-static` feature was passed.
+    let crt_static = if sess.target.target.options.crt_static_default {
+        !found_negative
+    } else {
+        found_positive
+    };
+
+    // If we switched from the default then that's only allowed on nightly, so
+    // gate that here.
+    if (found_positive || found_negative) && (!is_nightly || !unstable_options) {
+        sess.fatal("specifying the `crt-static` target feature is only allowed \
+                    on the nightly channel with `-Z unstable-options` passed \
+                    as well");
+    }
+
+    if crt_static {
+        cfg.push(attr::mk_name_value_item_str(tf.clone(), intern("crt-static")));
+    }
 }
diff --git a/src/librustc_metadata/creader.rs b/src/librustc_metadata/creader.rs
index 75944122f5c..4298bb47fea 100644
--- a/src/librustc_metadata/creader.rs
+++ b/src/librustc_metadata/creader.rs
@@ -23,6 +23,7 @@ use rustc::session::search_paths::PathKind;
 use rustc::middle;
 use rustc::middle::cstore::{CrateStore, validate_crate_name, ExternCrate};
 use rustc::util::nodemap::{FxHashMap, FxHashSet};
+use rustc::middle::cstore::NativeLibrary;
 use rustc::hir::map::Definitions;
 
 use std::cell::{RefCell, Cell};
@@ -35,6 +36,7 @@ use syntax::ast;
 use syntax::abi::Abi;
 use syntax::attr;
 use syntax::ext::base::SyntaxExtension;
+use syntax::feature_gate::{self, GateIssue};
 use syntax::parse::token::{InternedString, intern};
 use syntax_pos::{Span, DUMMY_SP};
 use log;
@@ -77,9 +79,8 @@ struct ExternCrateInfo {
 fn register_native_lib(sess: &Session,
                        cstore: &CStore,
                        span: Option<Span>,
-                       name: String,
-                       kind: cstore::NativeLibraryKind) {
-    if name.is_empty() {
+                       lib: NativeLibrary) {
+    if lib.name.is_empty() {
         match span {
             Some(span) => {
                 struct_span_err!(sess, span, E0454,
@@ -94,17 +95,21 @@ fn register_native_lib(sess: &Session,
         return
     }
     let is_osx = sess.target.target.options.is_like_osx;
-    if kind == cstore::NativeFramework && !is_osx {
+    if lib.kind == cstore::NativeFramework && !is_osx {
         let msg = "native frameworks are only available on OSX targets";
         match span {
-            Some(span) => {
-                span_err!(sess, span, E0455,
-                          "{}", msg)
-            }
+            Some(span) => span_err!(sess, span, E0455, "{}", msg),
             None => sess.err(msg),
         }
     }
-    cstore.add_used_library(name, kind);
+    if lib.cfg.is_some() && !sess.features.borrow().link_cfg {
+        feature_gate::emit_feature_err(&sess.parse_sess,
+                                       "link_cfg",
+                                       span.unwrap(),
+                                       GateIssue::Language,
+                                       "is feature gated");
+    }
+    cstore.add_used_library(lib);
 }
 
 // Extra info about a crate loaded for plugins or exported macros.
@@ -635,9 +640,9 @@ impl<'a> CrateLoader<'a> {
 
     fn register_statically_included_foreign_items(&mut self) {
         let libs = self.cstore.get_used_libraries();
-        for (lib, list) in self.foreign_item_map.iter() {
-            let is_static = libs.borrow().iter().any(|&(ref name, kind)| {
-                lib == name && kind == cstore::NativeStatic
+        for (foreign_lib, list) in self.foreign_item_map.iter() {
+            let is_static = libs.borrow().iter().any(|lib| {
+                *foreign_lib == lib.name && lib.kind == cstore::NativeStatic
             });
             if is_static {
                 for id in list {
@@ -898,7 +903,18 @@ impl<'a> CrateLoader<'a> {
                     InternedString::new("foo")
                 }
             };
-            register_native_lib(self.sess, self.cstore, Some(m.span), n.to_string(), kind);
+            let cfg = items.iter().find(|k| {
+                k.check_name("cfg")
+            }).and_then(|a| a.meta_item_list());
+            let cfg = cfg.map(|list| {
+                list[0].meta_item().unwrap().clone()
+            });
+            let lib = NativeLibrary {
+                name: n.to_string(),
+                kind: kind,
+                cfg: cfg,
+            };
+            register_native_lib(self.sess, self.cstore, Some(m.span), lib);
         }
 
         // Finally, process the #[linked_from = "..."] attribute
@@ -924,7 +940,12 @@ impl<'a> middle::cstore::CrateLoader for CrateLoader<'a> {
         }
 
         for &(ref name, kind) in &self.sess.opts.libs {
-            register_native_lib(self.sess, self.cstore, None, name.clone(), kind);
+            let lib = NativeLibrary {
+                name: name.clone(),
+                kind: kind,
+                cfg: None,
+            };
+            register_native_lib(self.sess, self.cstore, None, lib);
         }
         self.register_statically_included_foreign_items();
     }
diff --git a/src/librustc_metadata/cstore.rs b/src/librustc_metadata/cstore.rs
index 8c95e4aec0a..37853b7473a 100644
--- a/src/librustc_metadata/cstore.rs
+++ b/src/librustc_metadata/cstore.rs
@@ -31,7 +31,7 @@ use syntax::{ast, attr};
 use syntax::ext::base::SyntaxExtension;
 use syntax_pos;
 
-pub use rustc::middle::cstore::{NativeLibraryKind, LinkagePreference};
+pub use rustc::middle::cstore::{NativeLibrary, LinkagePreference};
 pub use rustc::middle::cstore::{NativeStatic, NativeFramework, NativeUnknown};
 pub use rustc::middle::cstore::{CrateSource, LinkMeta};
 
@@ -97,7 +97,7 @@ pub struct CStore {
     metas: RefCell<FxHashMap<CrateNum, Rc<CrateMetadata>>>,
     /// Map from NodeId's of local extern crate statements to crate numbers
     extern_mod_crate_map: RefCell<NodeMap<CrateNum>>,
-    used_libraries: RefCell<Vec<(String, NativeLibraryKind)>>,
+    used_libraries: RefCell<Vec<NativeLibrary>>,
     used_link_args: RefCell<Vec<String>>,
     statically_included_foreign_items: RefCell<NodeSet>,
     pub inlined_item_cache: RefCell<DefIdMap<Option<CachedInlinedItem>>>,
@@ -212,12 +212,12 @@ impl CStore {
         libs
     }
 
-    pub fn add_used_library(&self, lib: String, kind: NativeLibraryKind) {
-        assert!(!lib.is_empty());
-        self.used_libraries.borrow_mut().push((lib, kind));
+    pub fn add_used_library(&self, lib: NativeLibrary) {
+        assert!(!lib.name.is_empty());
+        self.used_libraries.borrow_mut().push(lib);
     }
 
-    pub fn get_used_libraries<'a>(&'a self) -> &'a RefCell<Vec<(String, NativeLibraryKind)>> {
+    pub fn get_used_libraries(&self) -> &RefCell<Vec<NativeLibrary>> {
         &self.used_libraries
     }
 
diff --git a/src/librustc_metadata/cstore_impl.rs b/src/librustc_metadata/cstore_impl.rs
index 83de8acdb60..5419f9955e4 100644
--- a/src/librustc_metadata/cstore_impl.rs
+++ b/src/librustc_metadata/cstore_impl.rs
@@ -14,7 +14,7 @@ use locator;
 use schema;
 
 use rustc::middle::cstore::{InlinedItem, CrateStore, CrateSource, DepKind, ExternCrate};
-use rustc::middle::cstore::{NativeLibraryKind, LinkMeta, LinkagePreference, LoadedMacro};
+use rustc::middle::cstore::{NativeLibrary, LinkMeta, LinkagePreference, LoadedMacro};
 use rustc::hir::def::{self, Def};
 use rustc::middle::lang_items;
 use rustc::session::Session;
@@ -295,7 +295,7 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore {
         })
     }
 
-    fn native_libraries(&self, cnum: CrateNum) -> Vec<(NativeLibraryKind, String)>
+    fn native_libraries(&self, cnum: CrateNum) -> Vec<NativeLibrary>
     {
         self.get_crate_data(cnum).get_native_libraries()
     }
@@ -524,7 +524,7 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore {
         result
     }
 
-    fn used_libraries(&self) -> Vec<(String, NativeLibraryKind)>
+    fn used_libraries(&self) -> Vec<NativeLibrary>
     {
         self.get_used_libraries().borrow().clone()
     }
diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs
index ba85544326f..6ffe5334533 100644
--- a/src/librustc_metadata/decoder.rs
+++ b/src/librustc_metadata/decoder.rs
@@ -11,7 +11,7 @@
 // Decoding metadata from a single crate's metadata
 
 use astencode::decode_inlined_item;
-use cstore::{self, CrateMetadata, MetadataBlob, NativeLibraryKind};
+use cstore::{self, CrateMetadata, MetadataBlob, NativeLibrary};
 use index::Index;
 use schema::*;
 
@@ -980,7 +980,7 @@ impl<'a, 'tcx> CrateMetadata {
     }
 
 
-    pub fn get_native_libraries(&self) -> Vec<(NativeLibraryKind, String)> {
+    pub fn get_native_libraries(&self) -> Vec<NativeLibrary> {
         self.root.native_libraries.decode(self).collect()
     }
 
diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs
index 778a9d185e1..823c50e1e5f 100644
--- a/src/librustc_metadata/encoder.rs
+++ b/src/librustc_metadata/encoder.rs
@@ -13,7 +13,7 @@ use index::Index;
 use schema::*;
 
 use rustc::middle::cstore::{InlinedItemRef, LinkMeta};
-use rustc::middle::cstore::{LinkagePreference, NativeLibraryKind};
+use rustc::middle::cstore::{LinkagePreference, NativeLibrary};
 use rustc::hir::def;
 use rustc::hir::def_id::{CrateNum, CRATE_DEF_INDEX, DefIndex, DefId};
 use rustc::middle::dependency_format::Linkage;
@@ -1134,14 +1134,9 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
          self.lazy_seq_ref(&tcx.lang_items.missing))
     }
 
-    fn encode_native_libraries(&mut self) -> LazySeq<(NativeLibraryKind, String)> {
+    fn encode_native_libraries(&mut self) -> LazySeq<NativeLibrary> {
         let used_libraries = self.tcx.sess.cstore.used_libraries();
-        self.lazy_seq(used_libraries.into_iter().filter_map(|(lib, kind)| {
-            match kind {
-                cstore::NativeStatic => None, // these libraries are not propagated
-                cstore::NativeFramework | cstore::NativeUnknown => Some((kind, lib)),
-            }
-        }))
+        self.lazy_seq(used_libraries)
     }
 
     fn encode_codemap(&mut self) -> LazySeq<syntax_pos::FileMap> {
diff --git a/src/librustc_metadata/schema.rs b/src/librustc_metadata/schema.rs
index d7a5f7ad715..5292a4a7c37 100644
--- a/src/librustc_metadata/schema.rs
+++ b/src/librustc_metadata/schema.rs
@@ -14,7 +14,7 @@ use index;
 use rustc::hir;
 use rustc::hir::def::{self, CtorKind};
 use rustc::hir::def_id::{DefIndex, DefId};
-use rustc::middle::cstore::{DepKind, LinkagePreference, NativeLibraryKind};
+use rustc::middle::cstore::{DepKind, LinkagePreference, NativeLibrary};
 use rustc::middle::lang_items;
 use rustc::mir;
 use rustc::ty::{self, Ty};
@@ -175,7 +175,7 @@ pub struct CrateRoot {
     pub dylib_dependency_formats: LazySeq<Option<LinkagePreference>>,
     pub lang_items: LazySeq<(DefIndex, usize)>,
     pub lang_items_missing: LazySeq<lang_items::LangItem>,
-    pub native_libraries: LazySeq<(NativeLibraryKind, String)>,
+    pub native_libraries: LazySeq<NativeLibrary>,
     pub codemap: LazySeq<syntax_pos::FileMap>,
     pub impls: LazySeq<TraitImpls>,
     pub reachable_ids: LazySeq<DefIndex>,
diff --git a/src/librustc_trans/back/archive.rs b/src/librustc_trans/back/archive.rs
index e063209799f..df8dd7750ae 100644
--- a/src/librustc_trans/back/archive.rs
+++ b/src/librustc_trans/back/archive.rs
@@ -145,8 +145,11 @@ impl<'a> ArchiveBuilder<'a> {
     ///
     /// This ignores adding the bytecode from the rlib, and if LTO is enabled
     /// then the object file also isn't added.
-    pub fn add_rlib(&mut self, rlib: &Path, name: &str, lto: bool)
-                    -> io::Result<()> {
+    pub fn add_rlib(&mut self,
+                    rlib: &Path,
+                    name: &str,
+                    lto: bool,
+                    skip_objects: bool) -> io::Result<()> {
         // Ignoring obj file starting with the crate name
         // as simple comparison is not enough - there
         // might be also an extra name suffix
@@ -159,9 +162,23 @@ impl<'a> ArchiveBuilder<'a> {
             self.config.sess.cstore.metadata_filename().to_owned();
 
         self.add_archive(rlib, move |fname: &str| {
-            let skip_obj = lto && fname.starts_with(&obj_start)
-                && fname.ends_with(".o");
-            skip_obj || fname.ends_with(bc_ext) || fname == metadata_filename
+            if fname.ends_with(bc_ext) || fname == metadata_filename {
+                return true
+            }
+
+            // Don't include Rust objects if LTO is enabled
+            if lto && fname.starts_with(&obj_start) && fname.ends_with(".o") {
+                return true
+            }
+
+            // Otherwise if this is *not* a rust object and we're skipping
+            // objects then skip this file
+            if skip_objects && (!fname.starts_with(&obj_start) || !fname.ends_with(".o")) {
+                return true
+            }
+
+            // ok, don't skip this
+            return false
         })
     }
 
diff --git a/src/librustc_trans/back/link.rs b/src/librustc_trans/back/link.rs
index ad8e0c1ee59..95d63311ee6 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};
+use middle::cstore::{self, LinkMeta, NativeLibrary};
 use middle::cstore::{LinkagePreference, NativeLibraryKind};
 use middle::dependency_format::Linkage;
 use CrateTranslation;
@@ -43,6 +43,7 @@ use std::process::Command;
 use std::str;
 use flate;
 use syntax::ast;
+use syntax::attr;
 use syntax_pos::Span;
 
 // RLIB LLVM-BYTECODE OBJECT LAYOUT
@@ -406,12 +407,29 @@ fn link_rlib<'a>(sess: &'a Session,
         ab.add_file(obj);
     }
 
-    for (l, kind) in sess.cstore.used_libraries() {
-        match kind {
-            NativeLibraryKind::NativeStatic => ab.add_native_library(&l),
+    // Note that in this loop we are ignoring the value of `lib.cfg`. That is,
+    // we may not be configured to actually include a static library if we're
+    // adding it here. That's because later when we consume this rlib we'll
+    // decide whether we actually needed the static library or not.
+    //
+    // To do this "correctly" we'd need to keep track of which libraries added
+    // which object files to the archive. We don't do that here, however. The
+    // #[link(cfg(..))] feature is unstable, though, and only intended to get
+    // liblibc working. In that sense the check below just indicates that if
+    // there are any libraries we want to omit object files for at link time we
+    // just exclude all custom object files.
+    //
+    // Eventually if we want to stabilize or flesh out the #[link(cfg(..))]
+    // feature then we'll need to figure out how to record what objects were
+    // loaded from the libraries found here and then encode that into the
+    // metadata of the rlib we're generating somehow.
+    for lib in sess.cstore.used_libraries() {
+        match lib.kind {
+            NativeLibraryKind::NativeStatic => {}
             NativeLibraryKind::NativeFramework |
-            NativeLibraryKind::NativeUnknown => {}
+            NativeLibraryKind::NativeUnknown => continue,
         }
+        ab.add_native_library(&lib.name);
     }
 
     // After adding all files to the archive, we need to update the
@@ -578,10 +596,28 @@ fn link_staticlib(sess: &Session, objects: &[PathBuf], out_filename: &Path,
 
     each_linked_rlib(sess, &mut |cnum, path| {
         let name = sess.cstore.crate_name(cnum);
-        ab.add_rlib(path, &name, sess.lto()).unwrap();
-
         let native_libs = sess.cstore.native_libraries(cnum);
-        all_native_libs.extend(native_libs);
+
+        // Here when we include the rlib into our staticlib we need to make a
+        // decision whether to include the extra object files along the way.
+        // These extra object files come from statically included native
+        // libraries, but they may be cfg'd away with #[link(cfg(..))].
+        //
+        // This unstable feature, though, only needs liblibc to work. The only
+        // use case there is where musl is statically included in liblibc.rlib,
+        // so if we don't want the included version we just need to skip it. As
+        // a result the logic here is that if *any* linked library is cfg'd away
+        // we just skip all object files.
+        //
+        // Clearly this is not sufficient for a general purpose feature, and
+        // we'd want to read from the library's metadata to determine which
+        // object files come from where and selectively skip them.
+        let skip_object_files = native_libs.iter().any(|lib| {
+            lib.kind == NativeLibraryKind::NativeStatic && !relevant_lib(sess, lib)
+        });
+        ab.add_rlib(path, &name, sess.lto(), skip_object_files).unwrap();
+
+        all_native_libs.extend(sess.cstore.native_libraries(cnum));
     });
 
     ab.update_symbols();
@@ -594,13 +630,14 @@ fn link_staticlib(sess: &Session, objects: &[PathBuf], out_filename: &Path,
                                  platforms, and so may need to be preserved");
     }
 
-    for &(kind, ref lib) in &all_native_libs {
-        let name = match kind {
-            NativeLibraryKind::NativeStatic => "static library",
+    for lib in all_native_libs.iter().filter(|l| relevant_lib(sess, l)) {
+        let name = match lib.kind {
             NativeLibraryKind::NativeUnknown => "library",
             NativeLibraryKind::NativeFramework => "framework",
+            // These are included, no need to print them
+            NativeLibraryKind::NativeStatic => continue,
         };
-        sess.note_without_error(&format!("{}: {}", name, *lib));
+        sess.note_without_error(&format!("{}: {}", name, lib.name));
     }
 }
 
@@ -876,14 +913,12 @@ fn add_local_native_libraries(cmd: &mut Linker, sess: &Session) {
         }
     });
 
-    let libs = sess.cstore.used_libraries();
-
-    let staticlibs = libs.iter().filter_map(|&(ref l, kind)| {
-        if kind == NativeLibraryKind::NativeStatic {Some(l)} else {None}
-    });
-    let others = libs.iter().filter(|&&(_, kind)| {
-        kind != NativeLibraryKind::NativeStatic
+    let pair = sess.cstore.used_libraries().into_iter().filter(|l| {
+        relevant_lib(sess, l)
+    }).partition(|lib| {
+        lib.kind == NativeLibraryKind::NativeStatic
     });
+    let (staticlibs, others): (Vec<_>, Vec<_>) = pair;
 
     // Some platforms take hints about whether a library is static or dynamic.
     // For those that support this, we ensure we pass the option if the library
@@ -899,15 +934,15 @@ fn add_local_native_libraries(cmd: &mut Linker, sess: &Session) {
         // don't otherwise explicitly reference them. This can occur for
         // libraries which are just providing bindings, libraries with generic
         // functions, etc.
-        cmd.link_whole_staticlib(l, &search_path);
+        cmd.link_whole_staticlib(&l.name, &search_path);
     }
 
     cmd.hint_dynamic();
 
-    for &(ref l, kind) in others {
-        match kind {
-            NativeLibraryKind::NativeUnknown => cmd.link_dylib(l),
-            NativeLibraryKind::NativeFramework => cmd.link_framework(l),
+    for lib in others {
+        match lib.kind {
+            NativeLibraryKind::NativeUnknown => cmd.link_dylib(&lib.name),
+            NativeLibraryKind::NativeFramework => cmd.link_framework(&lib.name),
             NativeLibraryKind::NativeStatic => bug!(),
         }
     }
@@ -1017,7 +1052,16 @@ fn add_upstream_rust_crates(cmd: &mut Linker,
                         cnum: CrateNum) {
         let src = sess.cstore.used_crate_source(cnum);
         let cratepath = &src.rlib.unwrap().0;
-        if !sess.lto() && crate_type != config::CrateTypeDylib {
+
+        // See the comment above in `link_staticlib` and `link_rlib` for why if
+        // there's a static library that's not relevant we skip all object
+        // files.
+        let native_libs = sess.cstore.native_libraries(cnum);
+        let skip_native = native_libs.iter().any(|lib| {
+            lib.kind == NativeLibraryKind::NativeStatic && !relevant_lib(sess, lib)
+        });
+
+        if !sess.lto() && crate_type != config::CrateTypeDylib && !skip_native {
             cmd.link_rlib(&fix_windows_verbatim_for_gcc(cratepath));
             return
         }
@@ -1029,33 +1073,42 @@ fn add_upstream_rust_crates(cmd: &mut Linker,
         time(sess.time_passes(), &format!("altering {}.rlib", name), || {
             let cfg = archive_config(sess, &dst, Some(cratepath));
             let mut archive = ArchiveBuilder::new(cfg);
-            archive.remove_file(sess.cstore.metadata_filename());
             archive.update_symbols();
 
             let mut any_objects = false;
             for f in archive.src_files() {
-                if f.ends_with("bytecode.deflate") {
+                if f.ends_with("bytecode.deflate") ||
+                   f == sess.cstore.metadata_filename() {
                     archive.remove_file(&f);
                     continue
                 }
+
                 let canonical = f.replace("-", "_");
                 let canonical_name = name.replace("-", "_");
 
+                let is_rust_object =
+                    canonical.starts_with(&canonical_name) && {
+                        let num = &f[name.len()..f.len() - 2];
+                        num.len() > 0 && num[1..].parse::<u32>().is_ok()
+                    };
+
+                // If we've been requested to skip all native object files
+                // (those not generated by the rust compiler) then we can skip
+                // this file. See above for why we may want to do this.
+                let skip_because_cfg_say_so = skip_native && !is_rust_object;
+
                 // If we're performing LTO and this is a rust-generated object
                 // file, then we don't need the object file as it's part of the
                 // LTO module. Note that `#![no_builtins]` is excluded from LTO,
                 // though, so we let that object file slide.
-                if sess.lto() &&
-                   !sess.cstore.is_no_builtins(cnum) &&
-                   canonical.starts_with(&canonical_name) &&
-                   canonical.ends_with(".o") {
-                    let num = &f[name.len()..f.len() - 2];
-                    if num.len() > 0 && num[1..].parse::<u32>().is_ok() {
-                        archive.remove_file(&f);
-                        continue
-                    }
+                let skip_because_lto = sess.lto() && is_rust_object &&
+                                        !sess.cstore.is_no_builtins(cnum);
+
+                if skip_because_cfg_say_so || skip_because_lto {
+                    archive.remove_file(&f);
+                } else {
+                    any_objects = true;
                 }
-                any_objects = true;
             }
 
             if !any_objects {
@@ -1127,15 +1180,26 @@ fn add_upstream_native_libraries(cmd: &mut Linker, sess: &Session) {
     // the paths.
     let crates = sess.cstore.used_crates(LinkagePreference::RequireStatic);
     for (cnum, _) in crates {
-        let libs = sess.cstore.native_libraries(cnum);
-        for &(kind, ref lib) in &libs {
-            match kind {
-                NativeLibraryKind::NativeUnknown => cmd.link_dylib(lib),
-                NativeLibraryKind::NativeFramework => cmd.link_framework(lib),
-                NativeLibraryKind::NativeStatic => {
-                    bug!("statics shouldn't be propagated");
-                }
+        for lib in sess.cstore.native_libraries(cnum) {
+            if !relevant_lib(sess, &lib) {
+                continue
+            }
+            match lib.kind {
+                NativeLibraryKind::NativeUnknown => cmd.link_dylib(&lib.name),
+                NativeLibraryKind::NativeFramework => cmd.link_framework(&lib.name),
+
+                // ignore statically included native libraries here as we've
+                // already included them when we included the rust library
+                // previously
+                NativeLibraryKind::NativeStatic => {}
             }
         }
     }
 }
+
+fn relevant_lib(sess: &Session, lib: &NativeLibrary) -> bool {
+    match lib.cfg {
+        Some(ref cfg) => attr::cfg_matches(cfg, &sess.parse_sess, None),
+        None => true,
+    }
+}
diff --git a/src/librustc_trans/back/write.rs b/src/librustc_trans/back/write.rs
index 9012914deeb..01eea08c50b 100644
--- a/src/librustc_trans/back/write.rs
+++ b/src/librustc_trans/back/write.rs
@@ -147,7 +147,16 @@ impl Emitter for SharedEmitter {
 // arise as some of intrinsics are converted into function calls
 // and nobody provides implementations those functions
 fn target_feature(sess: &Session) -> String {
-    format!("{},{}", sess.target.target.options.features, sess.opts.cg.target_feature)
+    let rustc_features = [
+        "crt-static",
+    ];
+    let requested_features = sess.opts.cg.target_feature.split(',');
+    let llvm_features = requested_features.filter(|f| {
+        !rustc_features.iter().any(|s| f.contains(s))
+    });
+    format!("{},{}",
+            sess.target.target.options.features,
+            llvm_features.collect::<Vec<_>>().join(","))
 }
 
 fn get_llvm_opt_level(optimize: config::OptLevel) -> llvm::CodeGenOptLevel {
diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs
index 9116b392f17..27f720b7609 100644
--- a/src/libsyntax/feature_gate.rs
+++ b/src/libsyntax/feature_gate.rs
@@ -311,6 +311,9 @@ declare_features! (
 
     // Allows using `Self` and associated types in struct expressions and patterns.
     (active, more_struct_aliases, "1.14.0", Some(37544)),
+
+    // Allows #[link(..., cfg(..))]
+    (active, link_cfg, "1.14.0", Some(37406)),
 );
 
 declare_features! (
diff --git a/src/test/compile-fail/crt-static-gated.rs b/src/test/compile-fail/crt-static-gated.rs
new file mode 100644
index 00000000000..6c7c60b653a
--- /dev/null
+++ b/src/test/compile-fail/crt-static-gated.rs
@@ -0,0 +1,14 @@
+// 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.
+
+// compile-flags:-C target-feature=+crt-static
+// error-pattern: specifying the `crt-static` target feature is only allowed
+
+fn main() {}
diff --git a/src/test/compile-fail/link-cfg-gated.rs b/src/test/compile-fail/link-cfg-gated.rs
new file mode 100644
index 00000000000..27918a27caf
--- /dev/null
+++ b/src/test/compile-fail/link-cfg-gated.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.
+
+#[link(name = "foo", cfg(foo))]
+//~^ ERROR: is feature gated
+extern {}
+
+fn main() {}
diff --git a/src/test/run-make/link-cfg/Makefile b/src/test/run-make/link-cfg/Makefile
new file mode 100644
index 00000000000..4abc0caa698
--- /dev/null
+++ b/src/test/run-make/link-cfg/Makefile
@@ -0,0 +1,22 @@
+-include ../tools.mk
+
+all: $(call DYLIB,return1) $(call DYLIB,return2) $(call NATIVE_STATICLIB,return3)
+	ls $(TMPDIR)
+	$(RUSTC) --print cfg --target x86_64-unknown-linux-musl | grep crt-static
+
+	$(RUSTC) no-deps.rs --cfg foo
+	$(call RUN,no-deps)
+	$(RUSTC) no-deps.rs --cfg bar
+	$(call RUN,no-deps)
+
+	$(RUSTC) dep.rs
+	$(RUSTC) with-deps.rs --cfg foo
+	$(call RUN,with-deps)
+	$(RUSTC) with-deps.rs --cfg bar
+	$(call RUN,with-deps)
+
+	$(RUSTC) dep-with-staticlib.rs
+	$(RUSTC) with-staticlib-deps.rs --cfg foo
+	$(call RUN,with-staticlib-deps)
+	$(RUSTC) with-staticlib-deps.rs --cfg bar
+	$(call RUN,with-staticlib-deps)
diff --git a/src/test/run-make/link-cfg/dep-with-staticlib.rs b/src/test/run-make/link-cfg/dep-with-staticlib.rs
new file mode 100644
index 00000000000..ecc2365ddb0
--- /dev/null
+++ b/src/test/run-make/link-cfg/dep-with-staticlib.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.
+
+#![feature(link_cfg)]
+#![crate_type = "rlib"]
+
+#[link(name = "return1", cfg(foo))]
+#[link(name = "return3", kind = "static", cfg(bar))]
+extern {
+    pub fn my_function() -> i32;
+}
diff --git a/src/test/run-make/link-cfg/dep.rs b/src/test/run-make/link-cfg/dep.rs
new file mode 100644
index 00000000000..7da879c2bfa
--- /dev/null
+++ b/src/test/run-make/link-cfg/dep.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.
+
+#![feature(link_cfg)]
+#![crate_type = "rlib"]
+
+#[link(name = "return1", cfg(foo))]
+#[link(name = "return2", cfg(bar))]
+extern {
+    pub fn my_function() -> i32;
+}
diff --git a/src/test/run-make/link-cfg/no-deps.rs b/src/test/run-make/link-cfg/no-deps.rs
new file mode 100644
index 00000000000..6b114106744
--- /dev/null
+++ b/src/test/run-make/link-cfg/no-deps.rs
@@ -0,0 +1,30 @@
+// 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.
+
+#![feature(link_cfg)]
+
+#[link(name = "return1", cfg(foo))]
+#[link(name = "return2", cfg(bar))]
+extern {
+    fn my_function() -> i32;
+}
+
+fn main() {
+    unsafe {
+        let v = my_function();
+        if cfg!(foo) {
+            assert_eq!(v, 1);
+        } else if cfg!(bar) {
+            assert_eq!(v, 2);
+        } else {
+            panic!("unknown");
+        }
+    }
+}
diff --git a/src/test/run-make/link-cfg/return1.c b/src/test/run-make/link-cfg/return1.c
new file mode 100644
index 00000000000..a2a3d051dd1
--- /dev/null
+++ b/src/test/run-make/link-cfg/return1.c
@@ -0,0 +1,16 @@
+// 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.
+
+#ifdef _WIN32
+__declspec(dllexport)
+#endif
+int my_function() {
+  return 1;
+}
diff --git a/src/test/run-make/link-cfg/return2.c b/src/test/run-make/link-cfg/return2.c
new file mode 100644
index 00000000000..d6ddcccf2fb
--- /dev/null
+++ b/src/test/run-make/link-cfg/return2.c
@@ -0,0 +1,16 @@
+// 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.
+
+#ifdef _WIN32
+__declspec(dllexport)
+#endif
+int my_function() {
+  return 2;
+}
diff --git a/src/test/run-make/link-cfg/return3.c b/src/test/run-make/link-cfg/return3.c
new file mode 100644
index 00000000000..6a3b695f208
--- /dev/null
+++ b/src/test/run-make/link-cfg/return3.c
@@ -0,0 +1,16 @@
+// 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.
+
+#ifdef _WIN32
+__declspec(dllexport)
+#endif
+int my_function() {
+  return 3;
+}
diff --git a/src/test/run-make/link-cfg/with-deps.rs b/src/test/run-make/link-cfg/with-deps.rs
new file mode 100644
index 00000000000..799555c500a
--- /dev/null
+++ b/src/test/run-make/link-cfg/with-deps.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.
+
+extern crate dep;
+
+fn main() {
+    unsafe {
+        let v = dep::my_function();
+        if cfg!(foo) {
+            assert_eq!(v, 1);
+        } else if cfg!(bar) {
+            assert_eq!(v, 2);
+        } else {
+            panic!("unknown");
+        }
+    }
+}
diff --git a/src/test/run-make/link-cfg/with-staticlib-deps.rs b/src/test/run-make/link-cfg/with-staticlib-deps.rs
new file mode 100644
index 00000000000..33a9c7720e2
--- /dev/null
+++ b/src/test/run-make/link-cfg/with-staticlib-deps.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.
+
+extern crate dep_with_staticlib;
+
+fn main() {
+    unsafe {
+        let v = dep_with_staticlib::my_function();
+        if cfg!(foo) {
+            assert_eq!(v, 1);
+        } else if cfg!(bar) {
+            assert_eq!(v, 3);
+        } else {
+            panic!("unknown");
+        }
+    }
+}
diff --git a/src/test/run-pass/auxiliary/link-cfg-works-transitive-dylib.rs b/src/test/run-pass/auxiliary/link-cfg-works-transitive-dylib.rs
new file mode 100644
index 00000000000..d41fd490f58
--- /dev/null
+++ b/src/test/run-pass/auxiliary/link-cfg-works-transitive-dylib.rs
@@ -0,0 +1,14 @@
+// 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.
+
+#![feature(link_cfg)]
+
+#[link(name = "foo", cfg(foo))]
+extern {}
diff --git a/src/test/run-pass/auxiliary/link-cfg-works-transitive-rlib.rs b/src/test/run-pass/auxiliary/link-cfg-works-transitive-rlib.rs
new file mode 100644
index 00000000000..9f096c351fb
--- /dev/null
+++ b/src/test/run-pass/auxiliary/link-cfg-works-transitive-rlib.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
+
+#![feature(link_cfg)]
+#![crate_type = "rlib"]
+
+#[link(name = "foo", cfg(foo))]
+extern {}
diff --git a/src/test/run-pass/crt-static-off-works.rs b/src/test/run-pass/crt-static-off-works.rs
new file mode 100644
index 00000000000..c94c877c12c
--- /dev/null
+++ b/src/test/run-pass/crt-static-off-works.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.
+
+// compile-flags:-C target-feature=-crt-static -Z unstable-options
+// ignore-musl - requires changing the linker which is hard
+
+#![feature(cfg_target_feature)]
+
+#[cfg(not(target_feature = "crt-static"))]
+fn main() {}
diff --git a/src/test/run-pass/crt-static-on-works.rs b/src/test/run-pass/crt-static-on-works.rs
new file mode 100644
index 00000000000..ae8e5f62970
--- /dev/null
+++ b/src/test/run-pass/crt-static-on-works.rs
@@ -0,0 +1,16 @@
+// 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.
+
+// compile-flags:-C target-feature=+crt-static -Z unstable-options
+
+#![feature(cfg_target_feature)]
+
+#[cfg(target_feature = "crt-static")]
+fn main() {}
diff --git a/src/test/run-pass/link-cfg-works.rs b/src/test/run-pass/link-cfg-works.rs
new file mode 100644
index 00000000000..7db948c7daa
--- /dev/null
+++ b/src/test/run-pass/link-cfg-works.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:link-cfg-works-transitive-rlib.rs
+// aux-build:link-cfg-works-transitive-dylib.rs
+
+#![feature(link_cfg)]
+
+extern crate link_cfg_works_transitive_rlib;
+extern crate link_cfg_works_transitive_dylib;
+
+#[link(name = "foo", cfg(foo))]
+extern {}
+
+fn main() {}
+