From ff35b11ad05132323edcad9fb0b470185ac58049 Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Sat, 25 Feb 2017 22:30:15 -0600 Subject: [PATCH 1/9] Introduce crt_static target option in config.toml This controls the value of the crt-static feature used when building the compiler and standard library. It can be set per target. --- src/bootstrap/bin/rustc.rs | 11 +++++++++++ src/bootstrap/config.rs | 3 +++ src/bootstrap/lib.rs | 10 ++++++++++ 3 files changed, 24 insertions(+) diff --git a/src/bootstrap/bin/rustc.rs b/src/bootstrap/bin/rustc.rs index a996240f61650..50548e835b061 100644 --- a/src/bootstrap/bin/rustc.rs +++ b/src/bootstrap/bin/rustc.rs @@ -211,6 +211,17 @@ fn main() { cmd.arg("-Z").arg("unstable-options"); cmd.arg("-C").arg("target-feature=+crt-static"); } + + if let Ok(s) = env::var("RUST_CRT_STATIC") { + if s == "true" { + cmd.arg("-Z").arg("unstable-options"); + cmd.arg("-C").arg("target-feature=+crt-static"); + } + if s == "false" { + cmd.arg("-Z").arg("unstable-options"); + cmd.arg("-C").arg("target-feature=-crt-static"); + } + } } if verbose > 1 { diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs index 438ce6103d624..26f2a3c3a1cf0 100644 --- a/src/bootstrap/config.rs +++ b/src/bootstrap/config.rs @@ -117,6 +117,7 @@ pub struct Target { pub cc: Option, pub cxx: Option, pub ndk: Option, + pub crt_static: Option, pub musl_root: Option, pub qemu_rootfs: Option, } @@ -231,6 +232,7 @@ struct TomlTarget { cc: Option, cxx: Option, android_ndk: Option, + crt_static: Option, musl_root: Option, qemu_rootfs: Option, } @@ -375,6 +377,7 @@ impl Config { } target.cxx = cfg.cxx.clone().map(PathBuf::from); target.cc = cfg.cc.clone().map(PathBuf::from); + target.crt_static = cfg.crt_static.clone(); target.musl_root = cfg.musl_root.clone().map(PathBuf::from); target.qemu_rootfs = cfg.qemu_rootfs.clone().map(PathBuf::from); diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index 98b68d870d375..32d981c9ec9fa 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -473,6 +473,10 @@ impl Build { .env("RUSTDOC_REAL", self.rustdoc(compiler)) .env("RUSTC_FLAGS", self.rustc_flags(target).join(" ")); + if let Some(x) = self.crt_static(target) { + cargo.env("RUST_CRT_STATIC", x.to_string()); + } + // Enable usage of unstable features cargo.env("RUSTC_BOOTSTRAP", "1"); self.add_rust_test_threads(&mut cargo); @@ -880,6 +884,12 @@ impl Build { return base } + /// Returns if this target should statically link the C runtime, if specified + fn crt_static(&self, target: &str) -> Option { + self.config.target_config.get(target) + .and_then(|t| t.crt_static) + } + /// Returns the "musl root" for this `target`, if defined fn musl_root(&self, target: &str) -> Option<&Path> { self.config.target_config.get(target) From 91fe8c5e7e72565799dc1c7ed7783e8964ece036 Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Sat, 25 Feb 2017 22:33:07 -0600 Subject: [PATCH 2/9] Factor out helper for getting C runtime linkage --- src/librustc/session/mod.rs | 29 ++++++++++++++++++++++++++ src/librustc_driver/target_features.rs | 27 +----------------------- 2 files changed, 30 insertions(+), 26 deletions(-) diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs index 3ba82f34c3266..141d3a2aee34a 100644 --- a/src/librustc/session/mod.rs +++ b/src/librustc/session/mod.rs @@ -34,6 +34,7 @@ use syntax::parse::ParseSess; use syntax::symbol::Symbol; use syntax::{ast, codemap}; use syntax::feature_gate::AttributeType; +use syntax::feature_gate::UnstableFeatures; use syntax_pos::{Span, MultiSpan}; use rustc_back::PanicStrategy; @@ -378,6 +379,34 @@ impl Session { .unwrap_or(self.opts.debug_assertions) } + pub fn crt_static(&self) -> bool { + let requested_features = self.opts.cg.target_feature.split(','); + let unstable_options = self.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 self.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) { + self.fatal("specifying the `crt-static` target feature is only allowed \ + on the nightly channel with `-Z unstable-options` passed \ + as well"); + } + + return crt_static; + } + pub fn must_not_eliminate_frame_pointers(&self) -> bool { self.opts.debuginfo != DebugInfoLevel::NoDebugInfo || !self.target.target.options.eliminate_frame_pointer diff --git a/src/librustc_driver/target_features.rs b/src/librustc_driver/target_features.rs index 0744fbbd4e925..5298071f665b7 100644 --- a/src/librustc_driver/target_features.rs +++ b/src/librustc_driver/target_features.rs @@ -12,7 +12,6 @@ use syntax::ast; use llvm::LLVMRustHasFeature; use rustc::session::Session; use rustc_trans::back::write::create_target_machine; -use syntax::feature_gate::UnstableFeatures; use syntax::symbol::Symbol; use libc::c_char; @@ -49,31 +48,7 @@ pub fn add_configuration(cfg: &mut ast::CrateConfig, sess: &Session) { } } - 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 { + if sess.crt_static() { cfg.insert((tf, Some(Symbol::intern("crt-static")))); } } From e6dbe3b537befb89c3e1db9f77869f28caaf7f46 Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Sun, 5 Mar 2017 17:49:02 -0600 Subject: [PATCH 3/9] Factor out special casing of MSVC crt This avoids the possibility of a duplicate or conflicting crt-static command line option sent to rustc. --- src/bootstrap/bin/rustc.rs | 5 ----- src/bootstrap/lib.rs | 8 ++++++-- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/src/bootstrap/bin/rustc.rs b/src/bootstrap/bin/rustc.rs index 50548e835b061..7f6d0ce1acba8 100644 --- a/src/bootstrap/bin/rustc.rs +++ b/src/bootstrap/bin/rustc.rs @@ -207,11 +207,6 @@ fn main() { } } - if target.contains("pc-windows-msvc") { - cmd.arg("-Z").arg("unstable-options"); - cmd.arg("-C").arg("target-feature=+crt-static"); - } - if let Ok(s) = env::var("RUST_CRT_STATIC") { if s == "true" { cmd.arg("-Z").arg("unstable-options"); diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index 32d981c9ec9fa..3d6b2d62baaea 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -886,8 +886,12 @@ impl Build { /// Returns if this target should statically link the C runtime, if specified fn crt_static(&self, target: &str) -> Option { - self.config.target_config.get(target) - .and_then(|t| t.crt_static) + if target.contains("pc-windows-msvc") { + Some(true) + } else { + self.config.target_config.get(target) + .and_then(|t| t.crt_static) + } } /// Returns the "musl root" for this `target`, if defined From b66c4ed51fed17d60ae0e6867d75ac5435bbe425 Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Sat, 25 Feb 2017 22:34:14 -0600 Subject: [PATCH 4/9] Only use pre/post_link_objects for static linking These options only exist for the special case of static cross-linking pure rust code for a musl-based target with a non-musl toolchain. In all other situations (dynamic linking, presence of a native or cross compiler) these objects will be automatically provided and linked by the toolchain. --- src/librustc_trans/back/link.rs | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/src/librustc_trans/back/link.rs b/src/librustc_trans/back/link.rs index b58f96033bf5b..7e5660b644cdb 100644 --- a/src/librustc_trans/back/link.rs +++ b/src/librustc_trans/back/link.rs @@ -715,13 +715,15 @@ fn link_natively(sess: &Session, let root = sess.target_filesearch(PathKind::Native).get_lib_path(); cmd.args(&sess.target.target.options.pre_link_args); - let pre_link_objects = if crate_type == config::CrateTypeExecutable { - &sess.target.target.options.pre_link_objects_exe - } else { - &sess.target.target.options.pre_link_objects_dll - }; - for obj in pre_link_objects { - cmd.arg(root.join(obj)); + if sess.crt_static() { + let pre_link_objects = if crate_type == config::CrateTypeExecutable { + &sess.target.target.options.pre_link_objects_exe + } else { + &sess.target.target.options.pre_link_objects_dll + }; + for obj in pre_link_objects { + cmd.arg(root.join(obj)); + } } if sess.target.target.options.is_like_emscripten { @@ -739,8 +741,10 @@ fn link_natively(sess: &Session, objects, out_filename, outputs, trans); } cmd.args(&sess.target.target.options.late_link_args); - for obj in &sess.target.target.options.post_link_objects { - cmd.arg(root.join(obj)); + if sess.crt_static() { + for obj in &sess.target.target.options.post_link_objects { + cmd.arg(root.join(obj)); + } } cmd.args(&sess.target.target.options.post_link_args); From 3a14de5a83e4f4bee69bebe6545e2267f5597513 Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Sat, 25 Feb 2017 23:51:58 -0600 Subject: [PATCH 5/9] Link libgcc_s over libunwind on dynamic musl --- src/libunwind/build.rs | 2 +- src/libunwind/lib.rs | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/libunwind/build.rs b/src/libunwind/build.rs index ed3d5212bf256..2c5d2d136d48d 100644 --- a/src/libunwind/build.rs +++ b/src/libunwind/build.rs @@ -16,7 +16,7 @@ fn main() { if target.contains("linux") { if target.contains("musl") && !target.contains("mips") { - println!("cargo:rustc-link-lib=static=unwind"); + // musl is handled in lib.rs } else if !target.contains("android") { println!("cargo:rustc-link-lib=gcc_s"); } diff --git a/src/libunwind/lib.rs b/src/libunwind/lib.rs index 7fa2ce650fd6c..b78e762f45ab5 100644 --- a/src/libunwind/lib.rs +++ b/src/libunwind/lib.rs @@ -15,6 +15,7 @@ #![deny(warnings)] #![feature(cfg_target_vendor)] +#![feature(link_cfg)] #![feature(staged_api)] #![feature(unwind_attributes)] @@ -27,3 +28,8 @@ extern crate libc; mod libunwind; #[cfg(not(target_env = "msvc"))] pub use libunwind::*; + +#[cfg(target_env = "musl")] +#[link(name = "unwind", kind = "static", cfg(target_feature = "crt-static"))] +#[link(name = "gcc_s", cfg(not(target_feature = "crt-static")))] +extern {} From 8edfb351dc26cad52b9e5dfa056ae31c8197f29f Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Sat, 25 Feb 2017 23:02:21 -0600 Subject: [PATCH 6/9] Support dynamic linking for musl-based targets To maintain existing behavior, it is disabled by default on all architectures except MIPS. --- src/librustc_back/target/linux_musl_base.rs | 9 +-------- src/librustc_back/target/mips_unknown_linux_musl.rs | 1 + src/librustc_back/target/mipsel_unknown_linux_musl.rs | 1 + 3 files changed, 3 insertions(+), 8 deletions(-) diff --git a/src/librustc_back/target/linux_musl_base.rs b/src/librustc_back/target/linux_musl_base.rs index 18cca425a32c8..076bbe719320b 100644 --- a/src/librustc_back/target/linux_musl_base.rs +++ b/src/librustc_back/target/linux_musl_base.rs @@ -59,14 +59,7 @@ pub fn opts() -> TargetOptions { base.pre_link_objects_exe.push("crti.o".to_string()); base.post_link_objects.push("crtn.o".to_string()); - // MUSL support doesn't currently include dynamic linking, so there's no - // need for dylibs or rpath business. Additionally `-pie` is incompatible - // with `-static`, so we can't pass `-pie`. - base.dynamic_linking = false; - base.has_rpath = false; - base.position_independent_executables = false; - - // These targets statically link libc by default + // Except for on MIPS, these targets statically link libc by default. base.crt_static_default = true; base diff --git a/src/librustc_back/target/mips_unknown_linux_musl.rs b/src/librustc_back/target/mips_unknown_linux_musl.rs index e4a6d2a55d981..77fcf9770d53b 100644 --- a/src/librustc_back/target/mips_unknown_linux_musl.rs +++ b/src/librustc_back/target/mips_unknown_linux_musl.rs @@ -25,6 +25,7 @@ pub fn target() -> TargetResult { features: "+mips32r2,+soft-float".to_string(), max_atomic_width: Some(32), + crt_static_default: false, // see #36994 exe_allocation_crate: "alloc_system".to_string(), diff --git a/src/librustc_back/target/mipsel_unknown_linux_musl.rs b/src/librustc_back/target/mipsel_unknown_linux_musl.rs index 5693bddd0488a..6339e719e1b97 100644 --- a/src/librustc_back/target/mipsel_unknown_linux_musl.rs +++ b/src/librustc_back/target/mipsel_unknown_linux_musl.rs @@ -25,6 +25,7 @@ pub fn target() -> TargetResult { features: "+mips32,+soft-float".to_string(), max_atomic_width: Some(32), + crt_static_default: false, // see #36994 exe_allocation_crate: "alloc_system".to_string(), From 470b62fe6154ec72e0835da9d3695141805f88de Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Sat, 25 Feb 2017 23:00:56 -0600 Subject: [PATCH 7/9] C library usage is not conditional upon architecture These were conditioned on architecture because traditionally MIPS was dynamically linked, while other arches used musl for static linking. Now that we support both methods of linking on all architectures, these special cases no longer make sense Add a comment explaining why copying startup files is always necessary --- src/bootstrap/compile.rs | 7 +++++-- src/bootstrap/sanity.rs | 4 ++-- src/libunwind/build.rs | 2 +- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs index 46d8d4b4aab2d..b314ce36d2ad0 100644 --- a/src/bootstrap/compile.rs +++ b/src/bootstrap/compile.rs @@ -106,14 +106,17 @@ pub fn std_link(build: &Build, t!(fs::create_dir_all(&libdir)); add_to_sysroot(&out_dir, &libdir); - if target.contains("musl") && !target.contains("mips") { + if target.contains("musl") { copy_musl_third_party_objects(build, target, &libdir); } } /// Copies the crt(1,i,n).o startup objects /// -/// Only required for musl targets that statically link to libc +/// Since musl supports fully static linking, we can cross link for it even +/// with a glibc-targeting toolchain, given we have the appropriate startup +/// files. As those shipped with glibc won't work, copy the ones provided by +/// musl so we have them on linux-gnu hosts. fn copy_musl_third_party_objects(build: &Build, target: &str, into: &Path) { for &obj in &["crt1.o", "crti.o", "crtn.o"] { copy(&build.musl_root(target).unwrap().join("lib").join(obj), &into.join(obj)); diff --git a/src/bootstrap/sanity.rs b/src/bootstrap/sanity.rs index bc439d6f7826d..245002019ef57 100644 --- a/src/bootstrap/sanity.rs +++ b/src/bootstrap/sanity.rs @@ -157,8 +157,8 @@ pub fn check(build: &mut Build) { panic!("the iOS target is only supported on OSX"); } - // Make sure musl-root is valid if specified - if target.contains("musl") && !target.contains("mips") { + // Make sure musl-root is valid + if target.contains("musl") { match build.musl_root(target) { Some(root) => { if fs::metadata(root.join("lib/libc.a")).is_err() { diff --git a/src/libunwind/build.rs b/src/libunwind/build.rs index 2c5d2d136d48d..d49d85e9cd6ec 100644 --- a/src/libunwind/build.rs +++ b/src/libunwind/build.rs @@ -15,7 +15,7 @@ fn main() { let target = env::var("TARGET").expect("TARGET was not set"); if target.contains("linux") { - if target.contains("musl") && !target.contains("mips") { + if target.contains("musl") { // musl is handled in lib.rs } else if !target.contains("android") { println!("cargo:rustc-link-lib=gcc_s"); From 5eba141e9b632dfa50085df3ad81cd84777e9874 Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Sat, 25 Feb 2017 23:01:19 -0600 Subject: [PATCH 8/9] Presence of libraries does not depend on architecture --- src/libstd/build.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libstd/build.rs b/src/libstd/build.rs index 9fb83ad75980a..a763d9727e28e 100644 --- a/src/libstd/build.rs +++ b/src/libstd/build.rs @@ -30,7 +30,7 @@ fn main() { println!("cargo:rustc-link-lib=dl"); println!("cargo:rustc-link-lib=log"); println!("cargo:rustc-link-lib=gcc"); - } else if !target.contains("musl") || target.contains("mips") { + } else if !target.contains("musl") { println!("cargo:rustc-link-lib=dl"); println!("cargo:rustc-link-lib=rt"); println!("cargo:rustc-link-lib=pthread"); From 706fc559532f24e77d0f0c1319723848ed82eb67 Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Sat, 25 Feb 2017 23:30:10 -0600 Subject: [PATCH 9/9] Infer a default musl_root for native builds --- src/bootstrap/sanity.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/bootstrap/sanity.rs b/src/bootstrap/sanity.rs index 245002019ef57..3ee11135165b8 100644 --- a/src/bootstrap/sanity.rs +++ b/src/bootstrap/sanity.rs @@ -159,6 +159,13 @@ pub fn check(build: &mut Build) { // Make sure musl-root is valid if target.contains("musl") { + // If this is a native target (host is also musl) and no musl-root is given, + // fall back to the system toolchain in /usr before giving up + if build.musl_root(target).is_none() && build.config.build == *target { + let target = build.config.target_config.entry(target.clone()) + .or_insert(Default::default()); + target.musl_root = Some("/usr".into()); + } match build.musl_root(target) { Some(root) => { if fs::metadata(root.join("lib/libc.a")).is_err() {