Skip to content

Commit 06242ff

Browse files
committed
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 06242ff

31 files changed

+547
-92
lines changed

src/librustc/middle/cstore.rs

+13-4
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

+3-1
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

+6
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

+29
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 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.clone().any(|r| r == "-crt-static");
56+
let found_positive = requested_features.clone().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

+35-14
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

+6-6
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

+3-3
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

+2-2
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

+3-8
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

+2-2
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>,

0 commit comments

Comments
 (0)