about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2017-08-23 08:43:52 +0000
committerbors <bors@rust-lang.org>2017-08-23 08:43:52 +0000
commita3f0ee9a7b17d522bfc6385f841d040445730f28 (patch)
treedb1c5edb8cd72fd64450656f9ca6568d1acbd76a /src
parentca898411c35d9b68c91e04d2b9d20392fa3d4805 (diff)
parente6cd9413718a51e9ce3207cdf4efad6319a34327 (diff)
downloadrust-a3f0ee9a7b17d522bfc6385f841d040445730f28.tar.gz
rust-a3f0ee9a7b17d522bfc6385f841d040445730f28.zip
Auto merge of #40113 - smaeul:native-musl, r=alexcrichton
Support dynamically-linked and/or native musl targets

These changes allow native compilation on musl-based distributions and the use of dynamic libraries on linux-musl targets. This is intended to remove limitations based on past assumptions about musl targets, while maintaining existing behavior by default.

A minor related bugfix is included.
Diffstat (limited to 'src')
-rw-r--r--src/bootstrap/bin/rustc.rs10
-rw-r--r--src/bootstrap/builder.rs4
-rw-r--r--src/bootstrap/compile.rs40
-rw-r--r--src/bootstrap/config.rs3
-rw-r--r--src/bootstrap/lib.rs10
-rw-r--r--src/bootstrap/sanity.rs9
-rw-r--r--src/librustc/session/mod.rs25
-rw-r--r--src/librustc_back/target/linux_musl_base.rs9
-rw-r--r--src/librustc_back/target/mod.rs10
-rw-r--r--src/librustc_back/target/windows_msvc_base.rs2
-rw-r--r--src/librustc_driver/target_features.rs16
-rw-r--r--src/librustc_trans/back/link.rs8
-rw-r--r--src/librustc_trans/back/linker.rs10
-rw-r--r--src/librustc_trans_utils/link.rs7
-rw-r--r--src/libstd/build.rs2
-rw-r--r--src/libunwind/build.rs2
-rw-r--r--src/libunwind/lib.rs6
-rw-r--r--src/test/run-pass-fulldeps/issue-13560.rs1
-rw-r--r--src/test/run-pass-fulldeps/linkage-visibility.rs1
19 files changed, 127 insertions, 48 deletions
diff --git a/src/bootstrap/bin/rustc.rs b/src/bootstrap/bin/rustc.rs
index f6ed4ee91b3..0baca9e58f4 100644
--- a/src/bootstrap/bin/rustc.rs
+++ b/src/bootstrap/bin/rustc.rs
@@ -237,9 +237,13 @@ 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("RUSTC_CRT_STATIC") {
+            if s == "true" {
+                cmd.arg("-C").arg("target-feature=+crt-static");
+            }
+            if s == "false" {
+                cmd.arg("-C").arg("target-feature=-crt-static");
+            }
         }
 
         // Force all crates compiled by this compiler to (a) be unstable and (b)
diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs
index e325fc65f05..298f6a004a2 100644
--- a/src/bootstrap/builder.rs
+++ b/src/bootstrap/builder.rs
@@ -503,6 +503,10 @@ impl<'a> Builder<'a> {
             cargo.env("RUSTC_METADATA_SUFFIX", "rustc");
         }
 
+        if let Some(x) = self.crt_static(target) {
+            cargo.env("RUSTC_CRT_STATIC", x.to_string());
+        }
+
         // Enable usage of unstable features
         cargo.env("RUSTC_BOOTSTRAP", "1");
         self.add_rust_test_threads(&mut cargo);
diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs
index 78bc225447b..335e1690a2e 100644
--- a/src/bootstrap/compile.rs
+++ b/src/bootstrap/compile.rs
@@ -77,6 +77,14 @@ impl Step for Std {
                 target,
             });
             println!("Uplifting stage1 std ({} -> {})", from.host, target);
+
+            // Even if we're not building std this stage, the new sysroot must
+            // still contain the musl startup objects.
+            if target.contains("musl") && !target.contains("mips") {
+                let libdir = builder.sysroot_libdir(compiler, target);
+                copy_musl_third_party_objects(build, target, &libdir);
+            }
+
             builder.ensure(StdLink {
                 compiler: from,
                 target_compiler: compiler,
@@ -89,6 +97,11 @@ impl Step for Std {
         println!("Building stage{} std artifacts ({} -> {})", compiler.stage,
                 &compiler.host, target);
 
+        if target.contains("musl") && !target.contains("mips") {
+            let libdir = builder.sysroot_libdir(compiler, target);
+            copy_musl_third_party_objects(build, target, &libdir);
+        }
+
         let out_dir = build.cargo_out(compiler, Mode::Libstd, target);
         build.clear_if_dirty(&out_dir, &builder.rustc(compiler));
         let mut cargo = builder.cargo(compiler, Mode::Libstd, target, "build");
@@ -105,6 +118,20 @@ impl Step for Std {
     }
 }
 
+/// Copies the crt(1,i,n).o startup objects
+///
+/// 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: Interned<String>,
+                                 into: &Path) {
+    for &obj in &["crt1.o", "crti.o", "crtn.o"] {
+        copy(&build.musl_root(target).unwrap().join("lib").join(obj), &into.join(obj));
+    }
+}
+
 /// Configure cargo to compile the standard library, adding appropriate env vars
 /// and such.
 pub fn std_cargo(build: &Build,
@@ -189,10 +216,6 @@ impl Step for StdLink {
         let libdir = builder.sysroot_libdir(target_compiler, target);
         add_to_sysroot(&libdir, &libstd_stamp(build, compiler, target));
 
-        if target.contains("musl") && !target.contains("mips") {
-            copy_musl_third_party_objects(build, target, &libdir);
-        }
-
         if build.config.sanitizers && compiler.stage != 0 && target == "x86_64-apple-darwin" {
             // The sanitizers are only built in stage1 or above, so the dylibs will
             // be missing in stage0 and causes panic. See the `std()` function above
@@ -208,15 +231,6 @@ impl Step for StdLink {
     }
 }
 
-/// Copies the crt(1,i,n).o startup objects
-///
-/// Only required for musl targets that statically link to libc
-fn copy_musl_third_party_objects(build: &Build, target: Interned<String>, into: &Path) {
-    for &obj in &["crt1.o", "crti.o", "crtn.o"] {
-        copy(&build.musl_root(target).unwrap().join("lib").join(obj), &into.join(obj));
-    }
-}
-
 fn copy_apple_sanitizer_dylibs(native_dir: &Path, platform: &str, into: &Path) {
     for &sanitizer in &["asan", "tsan"] {
         let filename = format!("libclang_rt.{}_{}_dynamic.dylib", sanitizer, platform);
diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs
index aa688fc66e2..f43035fbfe8 100644
--- a/src/bootstrap/config.rs
+++ b/src/bootstrap/config.rs
@@ -143,6 +143,7 @@ pub struct Target {
     pub cc: Option<PathBuf>,
     pub cxx: Option<PathBuf>,
     pub ndk: Option<PathBuf>,
+    pub crt_static: Option<bool>,
     pub musl_root: Option<PathBuf>,
     pub qemu_rootfs: Option<PathBuf>,
 }
@@ -275,6 +276,7 @@ struct TomlTarget {
     cc: Option<String>,
     cxx: Option<String>,
     android_ndk: Option<String>,
+    crt_static: Option<bool>,
     musl_root: Option<String>,
     qemu_rootfs: Option<String>,
 }
@@ -446,6 +448,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 b6e00981576..55358f2ffcb 100644
--- a/src/bootstrap/lib.rs
+++ b/src/bootstrap/lib.rs
@@ -656,6 +656,16 @@ impl Build {
         base
     }
 
+    /// Returns if this target should statically link the C runtime, if specified
+    fn crt_static(&self, target: Interned<String>) -> Option<bool> {
+        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: Interned<String>) -> Option<&Path> {
         self.config.target_config.get(&target)
diff --git a/src/bootstrap/sanity.rs b/src/bootstrap/sanity.rs
index 436a13500f2..a64a6130929 100644
--- a/src/bootstrap/sanity.rs
+++ b/src/bootstrap/sanity.rs
@@ -151,8 +151,15 @@ pub fn check(build: &mut Build) {
             panic!("the iOS target is only supported on macOS");
         }
 
-        // Make sure musl-root is valid if specified
+        // Make sure musl-root is valid
         if target.contains("musl") && !target.contains("mips") {
+            // 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 3aea0722d0e..23dcaf27c2c 100644
--- a/src/librustc/session/mod.rs
+++ b/src/librustc/session/mod.rs
@@ -429,6 +429,31 @@ impl Session {
             .unwrap_or(self.opts.debug_assertions)
     }
 
+    pub fn crt_static(&self) -> bool {
+        // If the target does not opt in to crt-static support, use its default.
+        if self.target.target.options.crt_static_respected {
+            self.crt_static_feature()
+        } else {
+            self.target.target.options.crt_static_default
+        }
+    }
+
+    pub fn crt_static_feature(&self) -> bool {
+        let requested_features = self.opts.cg.target_feature.split(',');
+        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.
+        if self.target.target.options.crt_static_default {
+            !found_negative
+        } else {
+            found_positive
+        }
+    }
+
     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 236f2c1ef0a..6e5e139715c 100644
--- a/src/librustc_back/target/linux_musl_base.rs
+++ b/src/librustc_back/target/linux_musl_base.rs
@@ -60,15 +60,10 @@ 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
     base.crt_static_default = true;
+    // These targets allow the user to choose between static and dynamic linking.
+    base.crt_static_respected = true;
 
     base
 }
diff --git a/src/librustc_back/target/mod.rs b/src/librustc_back/target/mod.rs
index 08b94d5a01c..130e1b695db 100644
--- a/src/librustc_back/target/mod.rs
+++ b/src/librustc_back/target/mod.rs
@@ -416,8 +416,12 @@ pub struct TargetOptions {
     /// ABIs are considered to be supported on all platforms and cannot be blacklisted.
     pub abi_blacklist: Vec<Abi>,
 
+    /// Whether or not linking dylibs to a static CRT is allowed.
+    pub crt_static_allows_dylibs: bool,
     /// Whether or not the CRT is statically linked by default.
     pub crt_static_default: bool,
+    /// Whether or not crt-static is respected by the compiler (or is a no-op).
+    pub crt_static_respected: bool,
 
     /// Whether or not stack probes (__rust_probestack) are enabled
     pub stack_probes: bool,
@@ -478,7 +482,9 @@ impl Default for TargetOptions {
             max_atomic_width: None,
             panic_strategy: PanicStrategy::Unwind,
             abi_blacklist: vec![],
+            crt_static_allows_dylibs: false,
             crt_static_default: false,
+            crt_static_respected: false,
             stack_probes: false,
         }
     }
@@ -714,7 +720,9 @@ impl Target {
         key!(max_atomic_width, Option<u64>);
         key!(min_atomic_width, Option<u64>);
         try!(key!(panic_strategy, PanicStrategy));
+        key!(crt_static_allows_dylibs, bool);
         key!(crt_static_default, bool);
+        key!(crt_static_respected, bool);
         key!(stack_probes, bool);
 
         if let Some(array) = obj.find("abi-blacklist").and_then(Json::as_array) {
@@ -902,7 +910,9 @@ impl ToJson for Target {
         target_option_val!(min_atomic_width);
         target_option_val!(max_atomic_width);
         target_option_val!(panic_strategy);
+        target_option_val!(crt_static_allows_dylibs);
         target_option_val!(crt_static_default);
+        target_option_val!(crt_static_respected);
         target_option_val!(stack_probes);
 
         if default.abi_blacklist != self.options.abi_blacklist {
diff --git a/src/librustc_back/target/windows_msvc_base.rs b/src/librustc_back/target/windows_msvc_base.rs
index c07321e418e..42a4e6f5f11 100644
--- a/src/librustc_back/target/windows_msvc_base.rs
+++ b/src/librustc_back/target/windows_msvc_base.rs
@@ -63,6 +63,8 @@ pub fn opts() -> TargetOptions {
         is_like_windows: true,
         is_like_msvc: true,
         pre_link_args: args,
+        crt_static_allows_dylibs: true,
+        crt_static_respected: true,
 
         .. Default::default()
     }
diff --git a/src/librustc_driver/target_features.rs b/src/librustc_driver/target_features.rs
index bee61bb3980..96264472b5f 100644
--- a/src/librustc_driver/target_features.rs
+++ b/src/librustc_driver/target_features.rs
@@ -25,21 +25,7 @@ pub fn add_configuration(cfg: &mut ast::CrateConfig, sess: &Session) {
         cfg.insert((tf, Some(feat)));
     }
 
-    let requested_features = sess.opts.cg.target_feature.split(',');
-    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 crt_static {
+    if sess.crt_static_feature() {
         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 338f3bb08aa..4e211d83cff 100644
--- a/src/librustc_trans/back/link.rs
+++ b/src/librustc_trans/back/link.rs
@@ -902,7 +902,7 @@ fn link_args(cmd: &mut Linker,
         let mut args = args.iter().chain(more_args.iter()).chain(used_link_args.iter());
 
         if get_reloc_model(sess) == llvm::RelocMode::PIC
-            && !args.any(|x| *x == "-static") {
+            && !sess.crt_static() && !args.any(|x| *x == "-static") {
             cmd.position_independent_executable();
         }
     }
@@ -966,11 +966,13 @@ fn link_args(cmd: &mut Linker,
     add_upstream_rust_crates(cmd, sess, crate_type, tmpdir);
     add_upstream_native_libraries(cmd, sess, crate_type);
 
-    // # Telling the linker what we're doing
-
+    // Tell the linker what we're doing.
     if crate_type != config::CrateTypeExecutable {
         cmd.build_dylib(out_filename);
     }
+    if crate_type == config::CrateTypeExecutable && sess.crt_static() {
+        cmd.build_static_executable();
+    }
 
     // FIXME (#2397): At some point we want to rpath our guesses as to
     // where extern libraries might live, based on the
diff --git a/src/librustc_trans/back/linker.rs b/src/librustc_trans/back/linker.rs
index ab401465b56..9b0a5e3f4a5 100644
--- a/src/librustc_trans/back/linker.rs
+++ b/src/librustc_trans/back/linker.rs
@@ -110,6 +110,7 @@ pub trait Linker {
     fn debuginfo(&mut self);
     fn no_default_libraries(&mut self);
     fn build_dylib(&mut self, out_filename: &Path);
+    fn build_static_executable(&mut self);
     fn args(&mut self, args: &[String]);
     fn export_symbols(&mut self, tmpdir: &Path, crate_type: CrateType);
     fn subsystem(&mut self, subsystem: &str);
@@ -179,6 +180,7 @@ impl<'a> Linker for GccLinker<'a> {
     fn position_independent_executable(&mut self) { self.cmd.arg("-pie"); }
     fn partial_relro(&mut self) { self.linker_arg("-z,relro"); }
     fn full_relro(&mut self) { self.linker_arg("-z,relro,-z,now"); }
+    fn build_static_executable(&mut self) { self.cmd.arg("-static"); }
     fn args(&mut self, args: &[String]) { self.cmd.args(args); }
 
     fn link_rust_dylib(&mut self, lib: &str, _path: &Path) {
@@ -396,6 +398,10 @@ impl<'a> Linker for MsvcLinker<'a> {
         self.cmd.arg(arg);
     }
 
+    fn build_static_executable(&mut self) {
+        // noop
+    }
+
     fn gc_sections(&mut self, _keep_metadata: bool) {
         // MSVC's ICF (Identical COMDAT Folding) link optimization is
         // slow for Rust and thus we disable it by default when not in
@@ -683,6 +689,10 @@ impl<'a> Linker for EmLinker<'a> {
         bug!("building dynamic library is unsupported on Emscripten")
     }
 
+    fn build_static_executable(&mut self) {
+        // noop
+    }
+
     fn export_symbols(&mut self, _tmpdir: &Path, crate_type: CrateType) {
         let symbols = &self.info.exports[&crate_type];
 
diff --git a/src/librustc_trans_utils/link.rs b/src/librustc_trans_utils/link.rs
index 264158f0de9..aa8637fabe8 100644
--- a/src/librustc_trans_utils/link.rs
+++ b/src/librustc_trans_utils/link.rs
@@ -123,8 +123,11 @@ pub fn invalid_output_for_target(sess: &Session,
     match (sess.target.target.options.dynamic_linking,
            sess.target.target.options.executables, crate_type) {
         (false, _, config::CrateTypeCdylib) |
-        (false, _, config::CrateTypeProcMacro) |
-        (false, _, config::CrateTypeDylib) => true,
+        (false, _, config::CrateTypeDylib) |
+        (false, _, config::CrateTypeProcMacro) => true,
+        (true, _, config::CrateTypeCdylib) |
+        (true, _, config::CrateTypeDylib) => sess.crt_static() &&
+            !sess.target.target.options.crt_static_allows_dylibs,
         (_, false, config::CrateTypeExecutable) => true,
         _ => false
     }
diff --git a/src/libstd/build.rs b/src/libstd/build.rs
index ab304f4c965..f57dec98b79 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 cb8cb90e9ca..dc1464b905b 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 d4d52322ada..1ff0a1e19d7 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)]
 #![feature(static_nobundle)]
@@ -28,3 +29,8 @@ extern crate libc;
 mod libunwind;
 #[cfg(not(target_env = "msvc"))]
 pub use libunwind::*;
+
+#[cfg(target_env = "musl")]
+#[link(name = "unwind", kind = "static-nobundle", cfg(target_feature = "crt-static"))]
+#[link(name = "gcc_s", cfg(not(target_feature = "crt-static")))]
+extern {}
diff --git a/src/test/run-pass-fulldeps/issue-13560.rs b/src/test/run-pass-fulldeps/issue-13560.rs
index 88be7fe1212..0ceb5ed5e75 100644
--- a/src/test/run-pass-fulldeps/issue-13560.rs
+++ b/src/test/run-pass-fulldeps/issue-13560.rs
@@ -11,7 +11,6 @@
 // aux-build:issue-13560-1.rs
 // aux-build:issue-13560-2.rs
 // aux-build:issue-13560-3.rs
-// ignore-musl
 
 // Regression test for issue #13560, the test itself is all in the dependent
 // libraries. The fail which previously failed to compile is the one numbered 3.
diff --git a/src/test/run-pass-fulldeps/linkage-visibility.rs b/src/test/run-pass-fulldeps/linkage-visibility.rs
index f884bb2098e..9839a2c7041 100644
--- a/src/test/run-pass-fulldeps/linkage-visibility.rs
+++ b/src/test/run-pass-fulldeps/linkage-visibility.rs
@@ -11,7 +11,6 @@
 // aux-build:linkage-visibility.rs
 // ignore-android: FIXME(#10356)
 // ignore-windows: std::dynamic_lib does not work on Windows well
-// ignore-musl
 // ignore-emscripten no dynamic linking
 
 extern crate linkage_visibility as foo;