From 15c141ce05793e9907aaf766d08eeaeb65788140 Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Tue, 22 Aug 2017 16:24:29 -0500 Subject: [PATCH 01/14] Remove incorrect special case of mips-musl The libdl/librt/libpthread provided by musl are no-op (empty static libraries) on all architectures, mips included. --- 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 ab304f4c9652a..f57dec98b795b 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 1757a8701dfbc8627cce3a2f3624e39f525b8275 Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Tue, 22 Aug 2017 16:24:29 -0500 Subject: [PATCH 02/14] Improve explanation of musl_root --- src/bootstrap/compile.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs index 78bc225447bd0..5b03608f6875d 100644 --- a/src/bootstrap/compile.rs +++ b/src/bootstrap/compile.rs @@ -210,7 +210,10 @@ impl Step for StdLink { /// 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: Interned, into: &Path) { for &obj in &["crt1.o", "crti.o", "crtn.o"] { copy(&build.musl_root(target).unwrap().join("lib").join(obj), &into.join(obj)); From 8606782bc155a5f2a3c292a76463a582167c744e Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Tue, 22 Aug 2017 16:24:29 -0500 Subject: [PATCH 03/14] Infer a default musl_root for native builds --- src/bootstrap/sanity.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/bootstrap/sanity.rs b/src/bootstrap/sanity.rs index 436a13500f254..a64a6130929cb 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() { From 0c7a0e9851b8ac48d51fe7289257bc03ae3e3a37 Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Tue, 22 Aug 2017 16:24:29 -0500 Subject: [PATCH 04/14] Copy musl startup objects before building std They are required for linking it, even though it is a library, because crtn.o in post_link_objects, as hardcoded in src/librustc_back/target/ linux_musl_base.rs, is added to the linker command line for both executables and libraries. --- src/bootstrap/compile.rs | 43 +++++++++++++++++++++++++--------------- 1 file changed, 27 insertions(+), 16 deletions(-) diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs index 5b03608f6875d..335e1690a2ea0 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, + 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,18 +231,6 @@ impl Step for StdLink { } } -/// 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, 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); From 4b09dc6e394c3d2397ad46530a96fd5f63a1c88c Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Tue, 22 Aug 2017 16:24:29 -0500 Subject: [PATCH 05/14] Introduce crt_static target option in config.toml This controls the value of the crt-static feature used when building the standard library for a target, as well as the compiler itself when that target is the host. --- config.toml.example | 6 ++++++ src/bootstrap/bin/rustc.rs | 9 +++++++++ src/bootstrap/builder.rs | 4 ++++ src/bootstrap/config.rs | 3 +++ src/bootstrap/lib.rs | 6 ++++++ 5 files changed, 28 insertions(+) diff --git a/config.toml.example b/config.toml.example index 962be2e608501..fd1f03b9d0e24 100644 --- a/config.toml.example +++ b/config.toml.example @@ -292,6 +292,12 @@ # build native code. #android-ndk = "/path/to/ndk" +# Force static or dynamic linkage of the standard library for this target. If +# this target is a host for rustc, this will also affect the linkage of the +# compiler itself. This is useful for building rustc on targets that normally +# only use static libraries. If unset, the target's default linkage is used. +#crt-static = false + # The root location of the MUSL installation directory. The library directory # will also need to contain libunwind.a for an unwinding implementation. Note # that this option only makes sense for MUSL targets that produce statically diff --git a/src/bootstrap/bin/rustc.rs b/src/bootstrap/bin/rustc.rs index f6ed4ee91b3c5..d098806a8a002 100644 --- a/src/bootstrap/bin/rustc.rs +++ b/src/bootstrap/bin/rustc.rs @@ -242,6 +242,15 @@ fn main() { 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) // allow the `rustc_private` feature to link to other unstable crates // also in the sysroot. diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs index e325fc65f051d..298f6a004a20a 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/config.rs b/src/bootstrap/config.rs index aa688fc66e267..f43035fbfe8a1 100644 --- a/src/bootstrap/config.rs +++ b/src/bootstrap/config.rs @@ -143,6 +143,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, } @@ -275,6 +276,7 @@ struct TomlTarget { cc: Option, cxx: Option, android_ndk: Option, + crt_static: Option, musl_root: Option, qemu_rootfs: Option, } @@ -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 b6e0098157633..d6afc562f3dc8 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -656,6 +656,12 @@ impl Build { base } + /// Returns if this target should statically link the C runtime, if specified + fn crt_static(&self, target: Interned) -> 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: Interned) -> Option<&Path> { self.config.target_config.get(&target) From 52832439ad00fcb23a96ef79a216ed9f62c467c5 Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Tue, 22 Aug 2017 16:24:29 -0500 Subject: [PATCH 06/14] Inline crt-static choice for pc-windows-msvc 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 d098806a8a002..0baca9e58f4fe 100644 --- a/src/bootstrap/bin/rustc.rs +++ b/src/bootstrap/bin/rustc.rs @@ -237,11 +237,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("RUSTC_CRT_STATIC") { if s == "true" { cmd.arg("-C").arg("target-feature=+crt-static"); diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index d6afc562f3dc8..55358f2ffcb73 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -658,8 +658,12 @@ impl Build { /// Returns if this target should statically link the C runtime, if specified fn crt_static(&self, target: Interned) -> 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 3cb987862fbb4bd54a1239978965600574c20d02 Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Tue, 22 Aug 2017 16:24:29 -0500 Subject: [PATCH 07/14] Factor out a helper for the getting C runtime linkage This commit makes no functional changes. --- src/librustc/session/mod.rs | 16 ++++++++++++++++ src/librustc_driver/target_features.rs | 16 +--------------- 2 files changed, 17 insertions(+), 15 deletions(-) diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs index 3aea0722d0e2f..a3aa7594c6c2d 100644 --- a/src/librustc/session/mod.rs +++ b/src/librustc/session/mod.rs @@ -429,6 +429,22 @@ impl Session { .unwrap_or(self.opts.debug_assertions) } + pub fn crt_static(&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_driver/target_features.rs b/src/librustc_driver/target_features.rs index bee61bb398029..4616db3ae8746 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() { cfg.insert((tf, Some(Symbol::intern("crt-static")))); } } From beb8abe9a5045a232b423b909b7aaffecbf8bafc Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Tue, 22 Aug 2017 16:24:29 -0500 Subject: [PATCH 08/14] Introduce temporary target feature crt_static_respected This feature allows targets to opt in to full support of the crt-static feature. Currently, crt-static is allowed on all targets, even those that really can't or really shouldn't support it. This works because it is very loose in the specification of its effects. Changing the behavior of crt-static to be more strict in how it chooses libraries and links executables would likely cause compilation to fail on these platforms. To avoid breaking existing uses of crt-static, whitelist targets that support the new, stricter behavior. For all other targets, this changes crt-static from being "mostly a no-op" to "explicitly a no-op". --- src/librustc/session/mod.rs | 9 +++++++++ src/librustc_back/target/linux_musl_base.rs | 2 ++ src/librustc_back/target/mod.rs | 5 +++++ src/librustc_back/target/windows_msvc_base.rs | 1 + src/librustc_driver/target_features.rs | 2 +- 5 files changed, 18 insertions(+), 1 deletion(-) diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs index a3aa7594c6c2d..23dcaf27c2c70 100644 --- a/src/librustc/session/mod.rs +++ b/src/librustc/session/mod.rs @@ -430,6 +430,15 @@ impl Session { } 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"); diff --git a/src/librustc_back/target/linux_musl_base.rs b/src/librustc_back/target/linux_musl_base.rs index 236f2c1ef0aa3..e77a40e3a3aa9 100644 --- a/src/librustc_back/target/linux_musl_base.rs +++ b/src/librustc_back/target/linux_musl_base.rs @@ -69,6 +69,8 @@ pub fn opts() -> TargetOptions { // 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 08b94d5a01cb7..0ff633ffe3774 100644 --- a/src/librustc_back/target/mod.rs +++ b/src/librustc_back/target/mod.rs @@ -418,6 +418,8 @@ pub struct TargetOptions { /// 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, @@ -479,6 +481,7 @@ impl Default for TargetOptions { panic_strategy: PanicStrategy::Unwind, abi_blacklist: vec![], crt_static_default: false, + crt_static_respected: false, stack_probes: false, } } @@ -715,6 +718,7 @@ impl Target { key!(min_atomic_width, Option); try!(key!(panic_strategy, PanicStrategy)); 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) { @@ -903,6 +907,7 @@ impl ToJson for Target { target_option_val!(max_atomic_width); target_option_val!(panic_strategy); 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 c07321e418e64..f44a9b44426d8 100644 --- a/src/librustc_back/target/windows_msvc_base.rs +++ b/src/librustc_back/target/windows_msvc_base.rs @@ -63,6 +63,7 @@ pub fn opts() -> TargetOptions { is_like_windows: true, is_like_msvc: true, pre_link_args: args, + crt_static_respected: true, .. Default::default() } diff --git a/src/librustc_driver/target_features.rs b/src/librustc_driver/target_features.rs index 4616db3ae8746..96264472b5f8e 100644 --- a/src/librustc_driver/target_features.rs +++ b/src/librustc_driver/target_features.rs @@ -25,7 +25,7 @@ pub fn add_configuration(cfg: &mut ast::CrateConfig, sess: &Session) { cfg.insert((tf, Some(feat))); } - if sess.crt_static() { + if sess.crt_static_feature() { cfg.insert((tf, Some(Symbol::intern("crt-static")))); } } From 12ceed013cdbd5d431a6908d49b2b6cb6fe1d032 Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Tue, 22 Aug 2017 16:24:29 -0500 Subject: [PATCH 09/14] Introduce target feature crt_static_allows_dylibs Most UNIX-like platforms do not allow shared libraries to statically link their own libc, as libc expects to have consistent process-global state. On those platforms, when we do not have a shared libc available, we must not attempt to link dylibs or cdylibs. On Windows, however, it is expected to statically link the CRT into dynamic libraries. This feature is only relevant for targets that support both fully-static and fully-dynamic linkage, such as musl on Linux. --- src/librustc_back/target/mod.rs | 5 +++++ src/librustc_back/target/windows_msvc_base.rs | 1 + src/librustc_trans_utils/link.rs | 7 +++++-- 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/src/librustc_back/target/mod.rs b/src/librustc_back/target/mod.rs index 0ff633ffe3774..130e1b695dbd5 100644 --- a/src/librustc_back/target/mod.rs +++ b/src/librustc_back/target/mod.rs @@ -416,6 +416,8 @@ pub struct TargetOptions { /// ABIs are considered to be supported on all platforms and cannot be blacklisted. pub abi_blacklist: Vec, + /// 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). @@ -480,6 +482,7 @@ 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, @@ -717,6 +720,7 @@ impl Target { key!(max_atomic_width, Option); key!(min_atomic_width, Option); 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); @@ -906,6 +910,7 @@ 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); diff --git a/src/librustc_back/target/windows_msvc_base.rs b/src/librustc_back/target/windows_msvc_base.rs index f44a9b44426d8..42a4e6f5f1188 100644 --- a/src/librustc_back/target/windows_msvc_base.rs +++ b/src/librustc_back/target/windows_msvc_base.rs @@ -63,6 +63,7 @@ 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_trans_utils/link.rs b/src/librustc_trans_utils/link.rs index 264158f0de9ee..aa8637fabe85f 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 } From 054f31086814281fc3045bfdcc444344f0faf244 Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Tue, 22 Aug 2017 16:24:29 -0500 Subject: [PATCH 10/14] Disable PIE when linking statically Static PIE support, while supported on musl, requires a patch to GCC. Until/unless it is merged, adding '-pie' to the linker command line will override '-static' and create a binary that requires a dynamic interpreter (ld.so). --- src/librustc_trans/back/link.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc_trans/back/link.rs b/src/librustc_trans/back/link.rs index 338f3bb08aa97..fb485e71d9469 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(); } } From bab6911f8a118fc342514bd3223158f10c8a8c32 Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Tue, 22 Aug 2017 16:24:29 -0500 Subject: [PATCH 11/14] Tell the linker when we want to link a static executable If the C runtime is linked statically, explicitly tell the linker that the executable should be static. --- src/librustc_trans/back/link.rs | 6 ++++-- src/librustc_trans/back/linker.rs | 10 ++++++++++ 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/src/librustc_trans/back/link.rs b/src/librustc_trans/back/link.rs index fb485e71d9469..4e211d83cff3e 100644 --- a/src/librustc_trans/back/link.rs +++ b/src/librustc_trans/back/link.rs @@ -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 ab401465b560b..9b0a5e3f4a5b1 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]; From c9645678e86861f670ce8b422c2e565c1a232916 Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Tue, 22 Aug 2017 16:24:29 -0500 Subject: [PATCH 12/14] Update libunwind dependencies for musl Use libgcc_s when linking dynamically. Convert the static libunwind to static-nobundle, as libunwind.a is copied from musl_root and available in the library search path. --- 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 cb8cb90e9ca7a..dc1464b905b0d 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 d4d52322adab0..1ff0a1e19d7b3 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 {} From 565a863bc2574840d03dfb09fc52db9be8526b5e Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Tue, 22 Aug 2017 16:24:29 -0500 Subject: [PATCH 13/14] Support dynamic linking for musl-based targets Note that this commit does not affect mips-musl targets, as they do not inherit from linux_musl_base. --- src/librustc_back/target/linux_musl_base.rs | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/librustc_back/target/linux_musl_base.rs b/src/librustc_back/target/linux_musl_base.rs index e77a40e3a3aa9..6e5e139715ccc 100644 --- a/src/librustc_back/target/linux_musl_base.rs +++ b/src/librustc_back/target/linux_musl_base.rs @@ -60,13 +60,6 @@ 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. From e6cd9413718a51e9ce3207cdf4efad6319a34327 Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Tue, 22 Aug 2017 16:24:29 -0500 Subject: [PATCH 14/14] Update ignored tests for dynamic musl Now that musl supports dynamic libraries (although not by default) enable the tests that now pass. Additional currently-ignored tests will pass if rustc is built with crt_static=false in config.toml. --- src/test/run-pass-fulldeps/issue-13560.rs | 1 - src/test/run-pass-fulldeps/linkage-visibility.rs | 1 - 2 files changed, 2 deletions(-) diff --git a/src/test/run-pass-fulldeps/issue-13560.rs b/src/test/run-pass-fulldeps/issue-13560.rs index 88be7fe1212d1..0ceb5ed5e755d 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 f884bb2098eb1..9839a2c704105 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;