about summary refs log tree commit diff
diff options
context:
space:
mode:
authorAmanieu d'Antras <amanieu@gmail.com>2020-03-03 20:41:37 +0000
committerAmanieu d'Antras <amanieu@gmail.com>2020-03-05 17:36:50 +0000
commit8e3467c2150eddc636e88346255bec20feb38b3a (patch)
tree7eb749f55ddd0b0a1e47c5048670cd0d7c1ad95f
parent1c950e5c6f85422283bb23bb4bad07ae6c3d2fe1 (diff)
downloadrust-8e3467c2150eddc636e88346255bec20feb38b3a.tar.gz
rust-8e3467c2150eddc636e88346255bec20feb38b3a.zip
Link to libgcc dynamically on windows-gnu when using dylib crates
-rw-r--r--src/librustc_codegen_ssa/back/link.rs14
-rw-r--r--src/librustc_target/spec/mod.rs12
-rw-r--r--src/librustc_target/spec/windows_base.rs31
-rw-r--r--src/libunwind/build.rs9
4 files changed, 62 insertions, 4 deletions
diff --git a/src/librustc_codegen_ssa/back/link.rs b/src/librustc_codegen_ssa/back/link.rs
index 90601521b19..fb0205dffe7 100644
--- a/src/librustc_codegen_ssa/back/link.rs
+++ b/src/librustc_codegen_ssa/back/link.rs
@@ -490,6 +490,11 @@ fn link_natively<'a, B: ArchiveBuilder<'a>>(
     info!("preparing {:?} to {:?}", crate_type, out_filename);
     let (linker, flavor) = linker_and_flavor(sess);
 
+    let any_dynamic_crate = crate_type == config::CrateType::Dylib
+        || codegen_results.crate_info.dependency_formats.iter().any(|(ty, list)| {
+            *ty == crate_type && list.iter().any(|&linkage| linkage == Linkage::Dynamic)
+        });
+
     // The invocations of cc share some flags across platforms
     let (pname, mut cmd) = get_linker(sess, &linker, flavor);
 
@@ -555,6 +560,15 @@ fn link_natively<'a, B: ArchiveBuilder<'a>>(
     if let Some(args) = sess.target.target.options.late_link_args.get(&flavor) {
         cmd.args(args);
     }
+    if any_dynamic_crate {
+        if let Some(args) = sess.target.target.options.late_link_args_dynamic.get(&flavor) {
+            cmd.args(args);
+        }
+    } else {
+        if let Some(args) = sess.target.target.options.late_link_args_static.get(&flavor) {
+            cmd.args(args);
+        }
+    }
     for obj in &sess.target.target.options.post_link_objects {
         cmd.arg(get_file_path(sess, obj));
     }
diff --git a/src/librustc_target/spec/mod.rs b/src/librustc_target/spec/mod.rs
index 542bcd27507..9c3d760451c 100644
--- a/src/librustc_target/spec/mod.rs
+++ b/src/librustc_target/spec/mod.rs
@@ -579,6 +579,12 @@ pub struct TargetOptions {
     /// user-defined but before post_link_objects. Standard platform
     /// libraries that should be always be linked to, usually go here.
     pub late_link_args: LinkArgs,
+    /// Linker arguments used in addition to `late_link_args` if at least one
+    /// Rust dependency is dynamically linked.
+    pub late_link_args_dynamic: LinkArgs,
+    /// Linker arguments used in addition to `late_link_args` if aall Rust
+    /// dependencies are statically linked.
+    pub late_link_args_static: LinkArgs,
     /// Objects to link after all others, always found within the
     /// sysroot folder.
     pub post_link_objects: Vec<String>, // ... unconditionally
@@ -858,6 +864,8 @@ impl Default for TargetOptions {
             post_link_objects: Vec::new(),
             post_link_objects_crt: Vec::new(),
             late_link_args: LinkArgs::new(),
+            late_link_args_dynamic: LinkArgs::new(),
+            late_link_args_static: LinkArgs::new(),
             link_env: Vec::new(),
             link_env_remove: Vec::new(),
             archive_format: "gnu".to_string(),
@@ -1136,6 +1144,8 @@ impl Target {
         key!(pre_link_objects_exe_crt, list);
         key!(pre_link_objects_dll, list);
         key!(late_link_args, link_args);
+        key!(late_link_args_dynamic, link_args);
+        key!(late_link_args_static, link_args);
         key!(post_link_objects, list);
         key!(post_link_objects_crt, list);
         key!(post_link_args, link_args);
@@ -1363,6 +1373,8 @@ impl ToJson for Target {
         target_option_val!(pre_link_objects_exe_crt);
         target_option_val!(pre_link_objects_dll);
         target_option_val!(link_args - late_link_args);
+        target_option_val!(link_args - late_link_args_dynamic);
+        target_option_val!(link_args - late_link_args_static);
         target_option_val!(post_link_objects);
         target_option_val!(post_link_objects_crt);
         target_option_val!(link_args - post_link_args);
diff --git a/src/librustc_target/spec/windows_base.rs b/src/librustc_target/spec/windows_base.rs
index 693a343d5a5..188548b41fe 100644
--- a/src/librustc_target/spec/windows_base.rs
+++ b/src/librustc_target/spec/windows_base.rs
@@ -17,12 +17,13 @@ pub fn opts() -> TargetOptions {
     );
 
     let mut late_link_args = LinkArgs::new();
+    let mut late_link_args_dynamic = LinkArgs::new();
+    let mut late_link_args_static = LinkArgs::new();
     late_link_args.insert(
         LinkerFlavor::Gcc,
         vec![
             "-lmingwex".to_string(),
             "-lmingw32".to_string(),
-            "-lgcc".to_string(), // alas, mingw* libraries above depend on libgcc
             "-lmsvcrt".to_string(),
             // mingw's msvcrt is a weird hybrid import library and static library.
             // And it seems that the linker fails to use import symbols from msvcrt
@@ -37,6 +38,31 @@ pub fn opts() -> TargetOptions {
             "-lkernel32".to_string(),
         ],
     );
+    late_link_args_dynamic.insert(
+        LinkerFlavor::Gcc,
+        vec![
+            // If any of our crates are dynamically linked then we need to use
+            // the shared libgcc_s-dw2-1.dll. This is required to support
+            // unwinding across DLL boundaries.
+            "-lgcc_s".to_string(),
+            "-lgcc".to_string(),
+            "-lkernel32".to_string(),
+        ],
+    );
+    late_link_args_static.insert(
+        LinkerFlavor::Gcc,
+        vec![
+            // If all of our crates are statically linked then we can get away
+            // with statically linking the libgcc unwinding code. This allows
+            // binaries to be redistributed without the libgcc_s-dw2-1.dll
+            // dependency, but unfortunately break unwinding across DLL
+            // boundaries when unwinding across FFI boundaries.
+            "-lgcc".to_string(),
+            "-lgcc_eh".to_string(),
+            "-lpthread".to_string(),
+            "-lkernel32".to_string(),
+        ],
+    );
 
     TargetOptions {
         // FIXME(#13846) this should be enabled for windows
@@ -63,8 +89,9 @@ pub fn opts() -> TargetOptions {
             "rsbegin.o".to_string(),
         ],
         late_link_args,
+        late_link_args_dynamic,
+        late_link_args_static,
         post_link_objects: vec!["rsend.o".to_string()],
-        custom_unwind_resume: true,
         abi_return_struct_as_int: true,
         emit_debug_gdb_scripts: false,
         requires_uwtable: true,
diff --git a/src/libunwind/build.rs b/src/libunwind/build.rs
index a24808b3250..0628e5d2fc0 100644
--- a/src/libunwind/build.rs
+++ b/src/libunwind/build.rs
@@ -33,8 +33,13 @@ fn main() {
     } else if target.contains("dragonfly") {
         println!("cargo:rustc-link-lib=gcc_pic");
     } else if target.contains("pc-windows-gnu") {
-        println!("cargo:rustc-link-lib=static-nobundle=gcc_eh");
-        println!("cargo:rustc-link-lib=static-nobundle=pthread");
+        // This is handled in the target spec with late_link_args_[static|dynamic]
+
+        // cfg!(bootstrap) doesn't work in build scripts
+        if env::var("RUSTC_STAGE").ok() == Some("0".to_string()) {
+            println!("cargo:rustc-link-lib=static-nobundle=gcc_eh");
+            println!("cargo:rustc-link-lib=static-nobundle=pthread");
+        }
     } else if target.contains("uwp-windows-gnu") {
         println!("cargo:rustc-link-lib=unwind");
     } else if target.contains("fuchsia") {