diff --git a/src/bootstrap/bin/rustc.rs b/src/bootstrap/bin/rustc.rs index a996240f61650..7f6d0ce1acba8 100644 --- a/src/bootstrap/bin/rustc.rs +++ b/src/bootstrap/bin/rustc.rs @@ -207,9 +207,15 @@ 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"); + 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"); + } } } 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/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 071d0b0b09009..e167fd0bb8301 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,16 @@ impl Build { return base } + /// Returns if this target should statically link the C runtime, if specified + fn crt_static(&self, target: &str) -> Option { + 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 fn musl_root(&self, target: &str) -> Option<&Path> { self.config.target_config.get(target) diff --git a/src/bootstrap/sanity.rs b/src/bootstrap/sanity.rs index bc439d6f7826d..3ee11135165b8 100644 --- a/src/bootstrap/sanity.rs +++ b/src/bootstrap/sanity.rs @@ -157,8 +157,15 @@ 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") { + // 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() { 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_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(), 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")))); } } 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); 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"); diff --git a/src/libunwind/build.rs b/src/libunwind/build.rs index ed3d5212bf256..d49d85e9cd6ec 100644 --- a/src/libunwind/build.rs +++ b/src/libunwind/build.rs @@ -15,8 +15,8 @@ fn main() { let target = env::var("TARGET").expect("TARGET was not set"); if target.contains("linux") { - if target.contains("musl") && !target.contains("mips") { - println!("cargo:rustc-link-lib=static=unwind"); + if target.contains("musl") { + // 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 {}