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, // ... 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") {