Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 957d3e9

Browse files
committedNov 15, 2016
rustc: Implement #[link(cfg(..))] and crt-static
This commit is an implementation of [RFC 1721] which adds a new target feature to the compiler, `crt-static`, which can be used to select how the C runtime for a target is linked. Most targets dynamically linke the C runtime by default with the notable exception of some of the musl targets. [RFC 1721]: https://github.com/rust-lang/rfcs/blob/master/text/1721-crt-static.md This commit first adds the new target-feature, `crt-static`. If enabled, then the `cfg(target_feature = "crt-static")` will be available. Targets like musl will have this enabled by default. This feature can be controlled through the standard target-feature interface, `-C target-feature=+crt-static` or `-C target-feature=-crt-static`. Next this adds an gated and unstable `#[link(cfg(..))]` feature to enable the `crt-static` semantics we want with libc. The exact behavior of this attribute is a little squishy, but it's intended to be a forever-unstable implementation detail of the liblibc crate. Specifically the `#[link(cfg(..))]` annotation means that the `#[link]` directive is only active in a compilation unit if that `cfg` value is satisfied. For example when compiling an rlib, these directives are just encoded and ignored for dylibs, and all staticlibs are continued to be put into the rlib as usual. When placing that rlib into a staticlib, executable, or dylib, however, the `cfg` is evaluated *as if it were defined in the final artifact* and the library is decided to be linked or not. Essentially, what'll happen is: * On MSVC with `-C target-feature=-crt-static`, the `msvcrt.lib` library will be linked to. * On MSVC with `-C target-feature=+crt-static`, the `libcmt.lib` library will be linked to. * On musl with `-C target-feature=-crt-static`, the object files in liblibc.rlib are removed and `-lc` is passed instead. * On musl with `-C target-feature=+crt-static`, the object files in liblibc.rlib are used and `-lc` is not passed. This commit does **not** include an update to the liblibc module to implement these changes. I plan to do that just after the 1.14.0 beta release is cut to ensure we get ample time to test this feature. cc #37406
1 parent c8867f8 commit 957d3e9

31 files changed

+547
-92
lines changed
 

‎src/librustc/middle/cstore.rs

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,13 @@ pub enum NativeLibraryKind {
8989
NativeUnknown, // default way to specify a dynamic library
9090
}
9191

92+
#[derive(Clone, Hash, RustcEncodable, RustcDecodable)]
93+
pub struct NativeLibrary {
94+
pub kind: NativeLibraryKind,
95+
pub name: String,
96+
pub cfg: Option<P<ast::MetaItem>>,
97+
}
98+
9299
/// The data we save and restore about an inlined item or method. This is not
93100
/// part of the AST that we parse from a file, but it becomes part of the tree
94101
/// that we trans.
@@ -204,7 +211,7 @@ pub trait CrateStore<'tcx> {
204211
fn crate_hash(&self, cnum: CrateNum) -> Svh;
205212
fn crate_disambiguator(&self, cnum: CrateNum) -> InternedString;
206213
fn plugin_registrar_fn(&self, cnum: CrateNum) -> Option<DefId>;
207-
fn native_libraries(&self, cnum: CrateNum) -> Vec<(NativeLibraryKind, String)>;
214+
fn native_libraries(&self, cnum: CrateNum) -> Vec<NativeLibrary>;
208215
fn reachable_ids(&self, cnum: CrateNum) -> Vec<DefId>;
209216
fn is_no_builtins(&self, cnum: CrateNum) -> bool;
210217

@@ -231,7 +238,7 @@ pub trait CrateStore<'tcx> {
231238
// This is basically a 1-based range of ints, which is a little
232239
// silly - I may fix that.
233240
fn crates(&self) -> Vec<CrateNum>;
234-
fn used_libraries(&self) -> Vec<(String, NativeLibraryKind)>;
241+
fn used_libraries(&self) -> Vec<NativeLibrary>;
235242
fn used_link_args(&self) -> Vec<String>;
236243

237244
// utility functions
@@ -377,7 +384,7 @@ impl<'tcx> CrateStore<'tcx> for DummyCrateStore {
377384
-> InternedString { bug!("crate_disambiguator") }
378385
fn plugin_registrar_fn(&self, cnum: CrateNum) -> Option<DefId>
379386
{ bug!("plugin_registrar_fn") }
380-
fn native_libraries(&self, cnum: CrateNum) -> Vec<(NativeLibraryKind, String)>
387+
fn native_libraries(&self, cnum: CrateNum) -> Vec<NativeLibrary>
381388
{ bug!("native_libraries") }
382389
fn reachable_ids(&self, cnum: CrateNum) -> Vec<DefId> { bug!("reachable_ids") }
383390
fn is_no_builtins(&self, cnum: CrateNum) -> bool { bug!("is_no_builtins") }
@@ -412,7 +419,9 @@ impl<'tcx> CrateStore<'tcx> for DummyCrateStore {
412419
// This is basically a 1-based range of ints, which is a little
413420
// silly - I may fix that.
414421
fn crates(&self) -> Vec<CrateNum> { vec![] }
415-
fn used_libraries(&self) -> Vec<(String, NativeLibraryKind)> { vec![] }
422+
fn used_libraries(&self) -> Vec<NativeLibrary> {
423+
vec![]
424+
}
416425
fn used_link_args(&self) -> Vec<String> { vec![] }
417426

418427
// utility functions

‎src/librustc_back/target/linux_musl_base.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ pub fn opts() -> TargetOptions {
1616
// Make sure that the linker/gcc really don't pull in anything, including
1717
// default objects, libs, etc.
1818
base.pre_link_args.push("-nostdlib".to_string());
19-
base.pre_link_args.push("-static".to_string());
2019

2120
// At least when this was tested, the linker would not add the
2221
// `GNU_EH_FRAME` program header to executables generated, which is required
@@ -67,5 +66,8 @@ pub fn opts() -> TargetOptions {
6766
base.has_rpath = false;
6867
base.position_independent_executables = false;
6968

69+
// These targets statically link libc by default
70+
base.crt_static_default = true;
71+
7072
base
7173
}

‎src/librustc_back/target/mod.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -373,6 +373,9 @@ pub struct TargetOptions {
373373
/// A blacklist of ABIs unsupported by the current target. Note that generic
374374
/// ABIs are considered to be supported on all platforms and cannot be blacklisted.
375375
pub abi_blacklist: Vec<Abi>,
376+
377+
/// Whether or not the CRT is statically linked by default.
378+
pub crt_static_default: bool,
376379
}
377380

378381
impl Default for TargetOptions {
@@ -425,6 +428,7 @@ impl Default for TargetOptions {
425428
max_atomic_width: None,
426429
panic_strategy: PanicStrategy::Unwind,
427430
abi_blacklist: vec![],
431+
crt_static_default: false,
428432
}
429433
}
430434
}
@@ -585,6 +589,7 @@ impl Target {
585589
key!(no_integrated_as, bool);
586590
key!(max_atomic_width, Option<u64>);
587591
try!(key!(panic_strategy, PanicStrategy));
592+
key!(crt_static_default, bool);
588593

589594
if let Some(array) = obj.find("abi-blacklist").and_then(Json::as_array) {
590595
for name in array.iter().filter_map(|abi| abi.as_string()) {
@@ -745,6 +750,7 @@ impl ToJson for Target {
745750
target_option_val!(no_integrated_as);
746751
target_option_val!(max_atomic_width);
747752
target_option_val!(panic_strategy);
753+
target_option_val!(crt_static_default);
748754

749755
if default.abi_blacklist != self.options.abi_blacklist {
750756
d.insert("abi-blacklist".to_string(), self.options.abi_blacklist.iter()

‎src/librustc_driver/target_features.rs

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ use syntax::{ast, attr};
1212
use llvm::LLVMRustHasFeature;
1313
use rustc::session::Session;
1414
use rustc_trans::back::write::create_target_machine;
15+
use syntax::feature_gate::UnstableFeatures;
1516
use syntax::parse::token::InternedString;
1617
use syntax::parse::token::intern_and_get_ident as intern;
1718
use libc::c_char;
@@ -47,4 +48,32 @@ pub fn add_configuration(cfg: &mut ast::CrateConfig, sess: &Session) {
4748
cfg.push(attr::mk_name_value_item_str(tf.clone(), intern(&feat[..feat.len() - 1])))
4849
}
4950
}
51+
52+
let mut requested_features = sess.opts.cg.target_feature.split(',');
53+
let unstable_options = sess.opts.debugging_opts.unstable_options;
54+
let is_nightly = UnstableFeatures::from_environment().is_nightly_build();
55+
let found_negative = requested_features.any(|r| r == "-crt-static");
56+
let found_positive = requested_features.any(|r| r == "+crt-static");
57+
58+
// If the target we're compiling for requests a static crt by default,
59+
// then see if the `-crt-static` feature was passed to disable that.
60+
// Otherwise if we don't have a static crt by default then see if the
61+
// `+crt-static` feature was passed.
62+
let crt_static = if sess.target.target.options.crt_static_default {
63+
found_negative
64+
} else {
65+
found_positive
66+
};
67+
68+
// If we switched from the default then that's only allowed on nightly, so
69+
// gate that here.
70+
if (found_positive || found_negative) && (!is_nightly || !unstable_options) {
71+
sess.fatal("specifying the `crt-static` target feature is only allowed \
72+
on the nightly channel with `-Z unstable-options` passed \
73+
as well");
74+
}
75+
76+
if crt_static {
77+
cfg.push(attr::mk_name_value_item_str(tf.clone(), intern("crt-static")));
78+
}
5079
}

‎src/librustc_metadata/creader.rs

Lines changed: 35 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ use rustc::session::search_paths::PathKind;
2323
use rustc::middle;
2424
use rustc::middle::cstore::{CrateStore, validate_crate_name, ExternCrate};
2525
use rustc::util::nodemap::{FxHashMap, FxHashSet};
26+
use rustc::middle::cstore::NativeLibrary;
2627
use rustc::hir::map::Definitions;
2728

2829
use std::cell::{RefCell, Cell};
@@ -35,6 +36,7 @@ use syntax::ast;
3536
use syntax::abi::Abi;
3637
use syntax::attr;
3738
use syntax::ext::base::SyntaxExtension;
39+
use syntax::feature_gate::{self, GateIssue};
3840
use syntax::parse::token::{InternedString, intern};
3941
use syntax_pos::{Span, DUMMY_SP};
4042
use log;
@@ -77,9 +79,8 @@ struct ExternCrateInfo {
7779
fn register_native_lib(sess: &Session,
7880
cstore: &CStore,
7981
span: Option<Span>,
80-
name: String,
81-
kind: cstore::NativeLibraryKind) {
82-
if name.is_empty() {
82+
lib: NativeLibrary) {
83+
if lib.name.is_empty() {
8384
match span {
8485
Some(span) => {
8586
struct_span_err!(sess, span, E0454,
@@ -94,17 +95,21 @@ fn register_native_lib(sess: &Session,
9495
return
9596
}
9697
let is_osx = sess.target.target.options.is_like_osx;
97-
if kind == cstore::NativeFramework && !is_osx {
98+
if lib.kind == cstore::NativeFramework && !is_osx {
9899
let msg = "native frameworks are only available on OSX targets";
99100
match span {
100-
Some(span) => {
101-
span_err!(sess, span, E0455,
102-
"{}", msg)
103-
}
101+
Some(span) => span_err!(sess, span, E0455, "{}", msg),
104102
None => sess.err(msg),
105103
}
106104
}
107-
cstore.add_used_library(name, kind);
105+
if lib.cfg.is_some() && !sess.features.borrow().link_cfg {
106+
feature_gate::emit_feature_err(&sess.parse_sess,
107+
"link_cfg",
108+
span.unwrap(),
109+
GateIssue::Language,
110+
"is feature gated");
111+
}
112+
cstore.add_used_library(lib);
108113
}
109114

110115
// Extra info about a crate loaded for plugins or exported macros.
@@ -635,9 +640,9 @@ impl<'a> CrateLoader<'a> {
635640

636641
fn register_statically_included_foreign_items(&mut self) {
637642
let libs = self.cstore.get_used_libraries();
638-
for (lib, list) in self.foreign_item_map.iter() {
639-
let is_static = libs.borrow().iter().any(|&(ref name, kind)| {
640-
lib == name && kind == cstore::NativeStatic
643+
for (foreign_lib, list) in self.foreign_item_map.iter() {
644+
let is_static = libs.borrow().iter().any(|lib| {
645+
*foreign_lib == lib.name && lib.kind == cstore::NativeStatic
641646
});
642647
if is_static {
643648
for id in list {
@@ -898,7 +903,18 @@ impl<'a> CrateLoader<'a> {
898903
InternedString::new("foo")
899904
}
900905
};
901-
register_native_lib(self.sess, self.cstore, Some(m.span), n.to_string(), kind);
906+
let cfg = items.iter().find(|k| {
907+
k.check_name("cfg")
908+
}).and_then(|a| a.meta_item_list());
909+
let cfg = cfg.map(|list| {
910+
list[0].meta_item().unwrap().clone()
911+
});
912+
let lib = NativeLibrary {
913+
name: n.to_string(),
914+
kind: kind,
915+
cfg: cfg,
916+
};
917+
register_native_lib(self.sess, self.cstore, Some(m.span), lib);
902918
}
903919

904920
// Finally, process the #[linked_from = "..."] attribute
@@ -924,7 +940,12 @@ impl<'a> middle::cstore::CrateLoader for CrateLoader<'a> {
924940
}
925941

926942
for &(ref name, kind) in &self.sess.opts.libs {
927-
register_native_lib(self.sess, self.cstore, None, name.clone(), kind);
943+
let lib = NativeLibrary {
944+
name: name.clone(),
945+
kind: kind,
946+
cfg: None,
947+
};
948+
register_native_lib(self.sess, self.cstore, None, lib);
928949
}
929950
self.register_statically_included_foreign_items();
930951
}

‎src/librustc_metadata/cstore.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ use syntax::{ast, attr};
3131
use syntax::ext::base::SyntaxExtension;
3232
use syntax_pos;
3333

34-
pub use rustc::middle::cstore::{NativeLibraryKind, LinkagePreference};
34+
pub use rustc::middle::cstore::{NativeLibrary, LinkagePreference};
3535
pub use rustc::middle::cstore::{NativeStatic, NativeFramework, NativeUnknown};
3636
pub use rustc::middle::cstore::{CrateSource, LinkMeta};
3737

@@ -97,7 +97,7 @@ pub struct CStore {
9797
metas: RefCell<FxHashMap<CrateNum, Rc<CrateMetadata>>>,
9898
/// Map from NodeId's of local extern crate statements to crate numbers
9999
extern_mod_crate_map: RefCell<NodeMap<CrateNum>>,
100-
used_libraries: RefCell<Vec<(String, NativeLibraryKind)>>,
100+
used_libraries: RefCell<Vec<NativeLibrary>>,
101101
used_link_args: RefCell<Vec<String>>,
102102
statically_included_foreign_items: RefCell<NodeSet>,
103103
pub inlined_item_cache: RefCell<DefIdMap<Option<CachedInlinedItem>>>,
@@ -212,12 +212,12 @@ impl CStore {
212212
libs
213213
}
214214

215-
pub fn add_used_library(&self, lib: String, kind: NativeLibraryKind) {
216-
assert!(!lib.is_empty());
217-
self.used_libraries.borrow_mut().push((lib, kind));
215+
pub fn add_used_library(&self, lib: NativeLibrary) {
216+
assert!(!lib.name.is_empty());
217+
self.used_libraries.borrow_mut().push(lib);
218218
}
219219

220-
pub fn get_used_libraries<'a>(&'a self) -> &'a RefCell<Vec<(String, NativeLibraryKind)>> {
220+
pub fn get_used_libraries(&self) -> &RefCell<Vec<NativeLibrary>> {
221221
&self.used_libraries
222222
}
223223

‎src/librustc_metadata/cstore_impl.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ use locator;
1414
use schema;
1515

1616
use rustc::middle::cstore::{InlinedItem, CrateStore, CrateSource, DepKind, ExternCrate};
17-
use rustc::middle::cstore::{NativeLibraryKind, LinkMeta, LinkagePreference, LoadedMacro};
17+
use rustc::middle::cstore::{NativeLibrary, LinkMeta, LinkagePreference, LoadedMacro};
1818
use rustc::hir::def::{self, Def};
1919
use rustc::middle::lang_items;
2020
use rustc::session::Session;
@@ -295,7 +295,7 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore {
295295
})
296296
}
297297

298-
fn native_libraries(&self, cnum: CrateNum) -> Vec<(NativeLibraryKind, String)>
298+
fn native_libraries(&self, cnum: CrateNum) -> Vec<NativeLibrary>
299299
{
300300
self.get_crate_data(cnum).get_native_libraries()
301301
}
@@ -524,7 +524,7 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore {
524524
result
525525
}
526526

527-
fn used_libraries(&self) -> Vec<(String, NativeLibraryKind)>
527+
fn used_libraries(&self) -> Vec<NativeLibrary>
528528
{
529529
self.get_used_libraries().borrow().clone()
530530
}

‎src/librustc_metadata/decoder.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
// Decoding metadata from a single crate's metadata
1212

1313
use astencode::decode_inlined_item;
14-
use cstore::{self, CrateMetadata, MetadataBlob, NativeLibraryKind};
14+
use cstore::{self, CrateMetadata, MetadataBlob, NativeLibrary};
1515
use index::Index;
1616
use schema::*;
1717

@@ -980,7 +980,7 @@ impl<'a, 'tcx> CrateMetadata {
980980
}
981981

982982

983-
pub fn get_native_libraries(&self) -> Vec<(NativeLibraryKind, String)> {
983+
pub fn get_native_libraries(&self) -> Vec<NativeLibrary> {
984984
self.root.native_libraries.decode(self).collect()
985985
}
986986

‎src/librustc_metadata/encoder.rs

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ use index::Index;
1313
use schema::*;
1414

1515
use rustc::middle::cstore::{InlinedItemRef, LinkMeta};
16-
use rustc::middle::cstore::{LinkagePreference, NativeLibraryKind};
16+
use rustc::middle::cstore::{LinkagePreference, NativeLibrary};
1717
use rustc::hir::def;
1818
use rustc::hir::def_id::{CrateNum, CRATE_DEF_INDEX, DefIndex, DefId};
1919
use rustc::middle::dependency_format::Linkage;
@@ -1134,14 +1134,9 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
11341134
self.lazy_seq_ref(&tcx.lang_items.missing))
11351135
}
11361136

1137-
fn encode_native_libraries(&mut self) -> LazySeq<(NativeLibraryKind, String)> {
1137+
fn encode_native_libraries(&mut self) -> LazySeq<NativeLibrary> {
11381138
let used_libraries = self.tcx.sess.cstore.used_libraries();
1139-
self.lazy_seq(used_libraries.into_iter().filter_map(|(lib, kind)| {
1140-
match kind {
1141-
cstore::NativeStatic => None, // these libraries are not propagated
1142-
cstore::NativeFramework | cstore::NativeUnknown => Some((kind, lib)),
1143-
}
1144-
}))
1139+
self.lazy_seq(used_libraries)
11451140
}
11461141

11471142
fn encode_codemap(&mut self) -> LazySeq<syntax_pos::FileMap> {

‎src/librustc_metadata/schema.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ use index;
1414
use rustc::hir;
1515
use rustc::hir::def::{self, CtorKind};
1616
use rustc::hir::def_id::{DefIndex, DefId};
17-
use rustc::middle::cstore::{DepKind, LinkagePreference, NativeLibraryKind};
17+
use rustc::middle::cstore::{DepKind, LinkagePreference, NativeLibrary};
1818
use rustc::middle::lang_items;
1919
use rustc::mir;
2020
use rustc::ty::{self, Ty};
@@ -175,7 +175,7 @@ pub struct CrateRoot {
175175
pub dylib_dependency_formats: LazySeq<Option<LinkagePreference>>,
176176
pub lang_items: LazySeq<(DefIndex, usize)>,
177177
pub lang_items_missing: LazySeq<lang_items::LangItem>,
178-
pub native_libraries: LazySeq<(NativeLibraryKind, String)>,
178+
pub native_libraries: LazySeq<NativeLibrary>,
179179
pub codemap: LazySeq<syntax_pos::FileMap>,
180180
pub impls: LazySeq<TraitImpls>,
181181
pub reachable_ids: LazySeq<DefIndex>,

‎src/librustc_trans/back/archive.rs

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -145,8 +145,11 @@ impl<'a> ArchiveBuilder<'a> {
145145
///
146146
/// This ignores adding the bytecode from the rlib, and if LTO is enabled
147147
/// then the object file also isn't added.
148-
pub fn add_rlib(&mut self, rlib: &Path, name: &str, lto: bool)
149-
-> io::Result<()> {
148+
pub fn add_rlib(&mut self,
149+
rlib: &Path,
150+
name: &str,
151+
lto: bool,
152+
skip_objects: bool) -> io::Result<()> {
150153
// Ignoring obj file starting with the crate name
151154
// as simple comparison is not enough - there
152155
// might be also an extra name suffix
@@ -159,9 +162,23 @@ impl<'a> ArchiveBuilder<'a> {
159162
self.config.sess.cstore.metadata_filename().to_owned();
160163

161164
self.add_archive(rlib, move |fname: &str| {
162-
let skip_obj = lto && fname.starts_with(&obj_start)
163-
&& fname.ends_with(".o");
164-
skip_obj || fname.ends_with(bc_ext) || fname == metadata_filename
165+
if fname.ends_with(bc_ext) || fname == metadata_filename {
166+
return true
167+
}
168+
169+
// Don't include Rust objects if LTO is enabled
170+
if lto && fname.starts_with(&obj_start) && fname.ends_with(".o") {
171+
return true
172+
}
173+
174+
// Otherwise if this is *not* a rust object and we're skipping
175+
// objects then skip this file
176+
if skip_objects && (!fname.starts_with(&obj_start) || !fname.ends_with(".o")) {
177+
return true
178+
}
179+
180+
// ok, don't skip this
181+
return false
165182
})
166183
}
167184

‎src/librustc_trans/back/link.rs

Lines changed: 109 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ use session::config::{OutputFilenames, Input, OutputType};
1919
use session::filesearch;
2020
use session::search_paths::PathKind;
2121
use session::Session;
22-
use middle::cstore::{self, LinkMeta};
22+
use middle::cstore::{self, LinkMeta, NativeLibrary};
2323
use middle::cstore::{LinkagePreference, NativeLibraryKind};
2424
use middle::dependency_format::Linkage;
2525
use CrateTranslation;
@@ -43,6 +43,7 @@ use std::process::Command;
4343
use std::str;
4444
use flate;
4545
use syntax::ast;
46+
use syntax::attr;
4647
use syntax_pos::Span;
4748

4849
// RLIB LLVM-BYTECODE OBJECT LAYOUT
@@ -406,12 +407,29 @@ fn link_rlib<'a>(sess: &'a Session,
406407
ab.add_file(obj);
407408
}
408409

409-
for (l, kind) in sess.cstore.used_libraries() {
410-
match kind {
411-
NativeLibraryKind::NativeStatic => ab.add_native_library(&l),
410+
// Note that in this loop we are ignoring the value of `lib.cfg`. That is,
411+
// we may not be configured to actually include a static library if we're
412+
// adding it here. That's because later when we consume this rlib we'll
413+
// decide whether we actually needed the static library or not.
414+
//
415+
// To do this "correctly" we'd need to keep track of which libraries added
416+
// which object files to the archive. We don't do that here, however. The
417+
// #[link(cfg(..))] feature is unstable, though, and only intended to get
418+
// liblibc working. In that sense the check below just indicates that if
419+
// there are any libraries we want to omit object files for at link time we
420+
// just exclude all custom object files.
421+
//
422+
// Eventually if we want to stabilize or flesh out the #[link(cfg(..))]
423+
// feature then we'll need to figure out how to record what objects were
424+
// loaded from the libraries found here and then encode that into the
425+
// metadata of the rlib we're generating somehow.
426+
for lib in sess.cstore.used_libraries() {
427+
match lib.kind {
428+
NativeLibraryKind::NativeStatic => {}
412429
NativeLibraryKind::NativeFramework |
413-
NativeLibraryKind::NativeUnknown => {}
430+
NativeLibraryKind::NativeUnknown => continue,
414431
}
432+
ab.add_native_library(&lib.name);
415433
}
416434

417435
// 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,
578596

579597
each_linked_rlib(sess, &mut |cnum, path| {
580598
let name = sess.cstore.crate_name(cnum);
581-
ab.add_rlib(path, &name, sess.lto()).unwrap();
582-
583599
let native_libs = sess.cstore.native_libraries(cnum);
584-
all_native_libs.extend(native_libs);
600+
601+
// Here when we include the rlib into our staticlib we need to make a
602+
// decision whether to include the extra object files along the way.
603+
// These extra object files come from statically included native
604+
// libraries, but they may be cfg'd away with #[link(cfg(..))].
605+
//
606+
// This unstable feature, though, only needs liblibc to work. The only
607+
// use case there is where musl is statically included in liblibc.rlib,
608+
// so if we don't want the included version we just need to skip it. As
609+
// a result the logic here is that if *any* linked library is cfg'd away
610+
// we just skip all object files.
611+
//
612+
// Clearly this is not sufficient for a general purpose feature, and
613+
// we'd want to read from the library's metadata to determine which
614+
// object files come from where and selectively skip them.
615+
let skip_object_files = native_libs.iter().any(|lib| {
616+
lib.kind == NativeLibraryKind::NativeStatic && !relevant_lib(sess, lib)
617+
});
618+
ab.add_rlib(path, &name, sess.lto(), skip_object_files).unwrap();
619+
620+
all_native_libs.extend(sess.cstore.native_libraries(cnum));
585621
});
586622

587623
ab.update_symbols();
@@ -594,13 +630,14 @@ fn link_staticlib(sess: &Session, objects: &[PathBuf], out_filename: &Path,
594630
platforms, and so may need to be preserved");
595631
}
596632

597-
for &(kind, ref lib) in &all_native_libs {
598-
let name = match kind {
599-
NativeLibraryKind::NativeStatic => "static library",
633+
for lib in all_native_libs.iter().filter(|l| relevant_lib(sess, l)) {
634+
let name = match lib.kind {
600635
NativeLibraryKind::NativeUnknown => "library",
601636
NativeLibraryKind::NativeFramework => "framework",
637+
// These are included, no need to print them
638+
NativeLibraryKind::NativeStatic => continue,
602639
};
603-
sess.note_without_error(&format!("{}: {}", name, *lib));
640+
sess.note_without_error(&format!("{}: {}", name, lib.name));
604641
}
605642
}
606643

@@ -876,14 +913,12 @@ fn add_local_native_libraries(cmd: &mut Linker, sess: &Session) {
876913
}
877914
});
878915

879-
let libs = sess.cstore.used_libraries();
880-
881-
let staticlibs = libs.iter().filter_map(|&(ref l, kind)| {
882-
if kind == NativeLibraryKind::NativeStatic {Some(l)} else {None}
883-
});
884-
let others = libs.iter().filter(|&&(_, kind)| {
885-
kind != NativeLibraryKind::NativeStatic
916+
let pair = sess.cstore.used_libraries().into_iter().filter(|l| {
917+
relevant_lib(sess, l)
918+
}).partition(|lib| {
919+
lib.kind == NativeLibraryKind::NativeStatic
886920
});
921+
let (staticlibs, others): (Vec<_>, Vec<_>) = pair;
887922

888923
// Some platforms take hints about whether a library is static or dynamic.
889924
// 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) {
899934
// don't otherwise explicitly reference them. This can occur for
900935
// libraries which are just providing bindings, libraries with generic
901936
// functions, etc.
902-
cmd.link_whole_staticlib(l, &search_path);
937+
cmd.link_whole_staticlib(&l.name, &search_path);
903938
}
904939

905940
cmd.hint_dynamic();
906941

907-
for &(ref l, kind) in others {
908-
match kind {
909-
NativeLibraryKind::NativeUnknown => cmd.link_dylib(l),
910-
NativeLibraryKind::NativeFramework => cmd.link_framework(l),
942+
for lib in others {
943+
match lib.kind {
944+
NativeLibraryKind::NativeUnknown => cmd.link_dylib(&lib.name),
945+
NativeLibraryKind::NativeFramework => cmd.link_framework(&lib.name),
911946
NativeLibraryKind::NativeStatic => bug!(),
912947
}
913948
}
@@ -1017,7 +1052,16 @@ fn add_upstream_rust_crates(cmd: &mut Linker,
10171052
cnum: CrateNum) {
10181053
let src = sess.cstore.used_crate_source(cnum);
10191054
let cratepath = &src.rlib.unwrap().0;
1020-
if !sess.lto() && crate_type != config::CrateTypeDylib {
1055+
1056+
// See the comment above in `link_staticlib` and `link_rlib` for why if
1057+
// there's a static library that's not relevant we skip all object
1058+
// files.
1059+
let native_libs = sess.cstore.native_libraries(cnum);
1060+
let skip_native = native_libs.iter().any(|lib| {
1061+
lib.kind == NativeLibraryKind::NativeStatic && !relevant_lib(sess, lib)
1062+
});
1063+
1064+
if !sess.lto() && crate_type != config::CrateTypeDylib && !skip_native {
10211065
cmd.link_rlib(&fix_windows_verbatim_for_gcc(cratepath));
10221066
return
10231067
}
@@ -1029,33 +1073,42 @@ fn add_upstream_rust_crates(cmd: &mut Linker,
10291073
time(sess.time_passes(), &format!("altering {}.rlib", name), || {
10301074
let cfg = archive_config(sess, &dst, Some(cratepath));
10311075
let mut archive = ArchiveBuilder::new(cfg);
1032-
archive.remove_file(sess.cstore.metadata_filename());
10331076
archive.update_symbols();
10341077

10351078
let mut any_objects = false;
10361079
for f in archive.src_files() {
1037-
if f.ends_with("bytecode.deflate") {
1080+
if f.ends_with("bytecode.deflate") ||
1081+
f == sess.cstore.metadata_filename() {
10381082
archive.remove_file(&f);
10391083
continue
10401084
}
1085+
10411086
let canonical = f.replace("-", "_");
10421087
let canonical_name = name.replace("-", "_");
10431088

1089+
let is_rust_object =
1090+
canonical.starts_with(&canonical_name) && {
1091+
let num = &f[name.len()..f.len() - 2];
1092+
num.len() > 0 && num[1..].parse::<u32>().is_ok()
1093+
};
1094+
1095+
// If we've been requested to skip all native object files
1096+
// (those not generated by the rust compiler) then we can skip
1097+
// this file. See above for why we may want to do this.
1098+
let skip_because_cfg_say_so = skip_native && !is_rust_object;
1099+
10441100
// If we're performing LTO and this is a rust-generated object
10451101
// file, then we don't need the object file as it's part of the
10461102
// LTO module. Note that `#![no_builtins]` is excluded from LTO,
10471103
// though, so we let that object file slide.
1048-
if sess.lto() &&
1049-
!sess.cstore.is_no_builtins(cnum) &&
1050-
canonical.starts_with(&canonical_name) &&
1051-
canonical.ends_with(".o") {
1052-
let num = &f[name.len()..f.len() - 2];
1053-
if num.len() > 0 && num[1..].parse::<u32>().is_ok() {
1054-
archive.remove_file(&f);
1055-
continue
1056-
}
1104+
let skip_because_lto = sess.lto() && is_rust_object &&
1105+
!sess.cstore.is_no_builtins(cnum);
1106+
1107+
if skip_because_cfg_say_so || skip_because_lto {
1108+
archive.remove_file(&f);
1109+
} else {
1110+
any_objects = true;
10571111
}
1058-
any_objects = true;
10591112
}
10601113

10611114
if !any_objects {
@@ -1127,15 +1180,26 @@ fn add_upstream_native_libraries(cmd: &mut Linker, sess: &Session) {
11271180
// the paths.
11281181
let crates = sess.cstore.used_crates(LinkagePreference::RequireStatic);
11291182
for (cnum, _) in crates {
1130-
let libs = sess.cstore.native_libraries(cnum);
1131-
for &(kind, ref lib) in &libs {
1132-
match kind {
1133-
NativeLibraryKind::NativeUnknown => cmd.link_dylib(lib),
1134-
NativeLibraryKind::NativeFramework => cmd.link_framework(lib),
1135-
NativeLibraryKind::NativeStatic => {
1136-
bug!("statics shouldn't be propagated");
1137-
}
1183+
for lib in sess.cstore.native_libraries(cnum) {
1184+
if !relevant_lib(sess, &lib) {
1185+
continue
1186+
}
1187+
match lib.kind {
1188+
NativeLibraryKind::NativeUnknown => cmd.link_dylib(&lib.name),
1189+
NativeLibraryKind::NativeFramework => cmd.link_framework(&lib.name),
1190+
1191+
// ignore statically included native libraries here as we've
1192+
// already included them when we included the rust library
1193+
// previously
1194+
NativeLibraryKind::NativeStatic => {}
11381195
}
11391196
}
11401197
}
11411198
}
1199+
1200+
fn relevant_lib(sess: &Session, lib: &NativeLibrary) -> bool {
1201+
match lib.cfg {
1202+
Some(ref cfg) => attr::cfg_matches(cfg, &sess.parse_sess, None),
1203+
None => true,
1204+
}
1205+
}

‎src/librustc_trans/back/write.rs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,16 @@ impl Emitter for SharedEmitter {
147147
// arise as some of intrinsics are converted into function calls
148148
// and nobody provides implementations those functions
149149
fn target_feature(sess: &Session) -> String {
150-
format!("{},{}", sess.target.target.options.features, sess.opts.cg.target_feature)
150+
let rustc_features = [
151+
"crt-static",
152+
];
153+
let requested_features = sess.opts.cg.target_feature.split(',');
154+
let llvm_features = requested_features.filter(|f| {
155+
!rustc_features.iter().any(|s| f.contains(s))
156+
});
157+
format!("{},{}",
158+
sess.target.target.options.features,
159+
llvm_features.collect::<Vec<_>>().join(","))
151160
}
152161

153162
fn get_llvm_opt_level(optimize: config::OptLevel) -> llvm::CodeGenOptLevel {

‎src/libsyntax/feature_gate.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -311,6 +311,9 @@ declare_features! (
311311

312312
// Allows using `Self` and associated types in struct expressions and patterns.
313313
(active, more_struct_aliases, "1.14.0", Some(37544)),
314+
315+
// Allows #[link(..., cfg(..))]
316+
(active, link_cfg, "1.14.0", Some(37406)),
314317
);
315318

316319
declare_features! (
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// compile-flags:-C target-feature=+crt-static
12+
// error-pattern: specifying the `crt-static` target feature is only allowed
13+
14+
fn main() {}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
#[link(name = "foo", cfg(foo))]
12+
//~^ ERROR: is feature gated
13+
extern {}
14+
15+
fn main() {}

‎src/test/run-make/link-cfg/Makefile

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
-include ../tools.mk
2+
3+
all: $(call DYLIB,return1) $(call DYLIB,return2) $(call NATIVE_STATICLIB,return3)
4+
ls $(TMPDIR)
5+
$(RUSTC) --print cfg --target x86_64-unknown-linux-musl | grep crt-static
6+
7+
$(RUSTC) no-deps.rs --cfg foo
8+
$(call RUN,no-deps)
9+
$(RUSTC) no-deps.rs --cfg bar
10+
$(call RUN,no-deps)
11+
12+
$(RUSTC) dep.rs
13+
$(RUSTC) with-deps.rs --cfg foo
14+
$(call RUN,with-deps)
15+
$(RUSTC) with-deps.rs --cfg bar
16+
$(call RUN,with-deps)
17+
18+
$(RUSTC) dep-with-staticlib.rs
19+
$(RUSTC) with-staticlib-deps.rs --cfg foo
20+
$(call RUN,with-staticlib-deps)
21+
$(RUSTC) with-staticlib-deps.rs --cfg bar
22+
$(call RUN,with-staticlib-deps)
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
#![feature(link_cfg)]
12+
#![crate_type = "rlib"]
13+
14+
#[link(name = "return1", cfg(foo))]
15+
#[link(name = "return3", kind = "static", cfg(bar))]
16+
extern {
17+
pub fn my_function() -> i32;
18+
}

‎src/test/run-make/link-cfg/dep.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
#![feature(link_cfg)]
12+
#![crate_type = "rlib"]
13+
14+
#[link(name = "return1", cfg(foo))]
15+
#[link(name = "return2", cfg(bar))]
16+
extern {
17+
pub fn my_function() -> i32;
18+
}

‎src/test/run-make/link-cfg/no-deps.rs

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
#![feature(link_cfg)]
12+
13+
#[link(name = "return1", cfg(foo))]
14+
#[link(name = "return2", cfg(bar))]
15+
extern {
16+
fn my_function() -> i32;
17+
}
18+
19+
fn main() {
20+
unsafe {
21+
let v = my_function();
22+
if cfg!(foo) {
23+
assert_eq!(v, 1);
24+
} else if cfg!(bar) {
25+
assert_eq!(v, 2);
26+
} else {
27+
panic!("unknown");
28+
}
29+
}
30+
}

‎src/test/run-make/link-cfg/return1.c

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
#ifdef _WIN32
12+
__declspec(dllexport)
13+
#endif
14+
int my_function() {
15+
return 1;
16+
}

‎src/test/run-make/link-cfg/return2.c

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
#ifdef _WIN32
12+
__declspec(dllexport)
13+
#endif
14+
int my_function() {
15+
return 2;
16+
}

‎src/test/run-make/link-cfg/return3.c

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
#ifdef _WIN32
12+
__declspec(dllexport)
13+
#endif
14+
int my_function() {
15+
return 3;
16+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
extern crate dep;
12+
13+
fn main() {
14+
unsafe {
15+
let v = dep::my_function();
16+
if cfg!(foo) {
17+
assert_eq!(v, 1);
18+
} else if cfg!(bar) {
19+
assert_eq!(v, 2);
20+
} else {
21+
panic!("unknown");
22+
}
23+
}
24+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
extern crate dep_with_staticlib;
12+
13+
fn main() {
14+
unsafe {
15+
let v = dep_with_staticlib::my_function();
16+
if cfg!(foo) {
17+
assert_eq!(v, 1);
18+
} else if cfg!(bar) {
19+
assert_eq!(v, 3);
20+
} else {
21+
panic!("unknown");
22+
}
23+
}
24+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
#![feature(link_cfg)]
12+
13+
#[link(name = "foo", cfg(foo))]
14+
extern {}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// no-prefer-dynamic
12+
13+
#![feature(link_cfg)]
14+
#![crate_type = "rlib"]
15+
16+
#[link(name = "foo", cfg(foo))]
17+
extern {}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// compile-flags:-C target-feature=-crt-static -Z unstable-options
12+
// ignore-musl - requires changing the linker which is hard
13+
14+
#![feature(cfg_target_feature)]
15+
16+
#[cfg(not(target_feature = "crt-static"))]
17+
fn main() {}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// compile-flags:-C target-feature=+crt-static -Z unstable-options
12+
13+
#![feature(cfg_target_feature)]
14+
15+
#[cfg(target_feature = "crt-static")]
16+
fn main() {}

‎src/test/run-pass/link-cfg-works.rs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// aux-build:link-cfg-works-transitive-rlib.rs
12+
// aux-build:link-cfg-works-transitive-dylib.rs
13+
14+
#![feature(link_cfg)]
15+
16+
extern crate link_cfg_works_transitive_rlib;
17+
extern crate link_cfg_works_transitive_dylib;
18+
19+
#[link(name = "foo", cfg(foo))]
20+
extern {}
21+
22+
fn main() {}
23+

0 commit comments

Comments
 (0)
Please sign in to comment.