Skip to content

Commit 8e3467c

Browse files
committed
Link to libgcc dynamically on windows-gnu when using dylib crates
1 parent 1c950e5 commit 8e3467c

File tree

4 files changed

+62
-4
lines changed

4 files changed

+62
-4
lines changed

src/librustc_codegen_ssa/back/link.rs

+14
Original file line numberDiff line numberDiff line change
@@ -490,6 +490,11 @@ fn link_natively<'a, B: ArchiveBuilder<'a>>(
490490
info!("preparing {:?} to {:?}", crate_type, out_filename);
491491
let (linker, flavor) = linker_and_flavor(sess);
492492

493+
let any_dynamic_crate = crate_type == config::CrateType::Dylib
494+
|| codegen_results.crate_info.dependency_formats.iter().any(|(ty, list)| {
495+
*ty == crate_type && list.iter().any(|&linkage| linkage == Linkage::Dynamic)
496+
});
497+
493498
// The invocations of cc share some flags across platforms
494499
let (pname, mut cmd) = get_linker(sess, &linker, flavor);
495500

@@ -555,6 +560,15 @@ fn link_natively<'a, B: ArchiveBuilder<'a>>(
555560
if let Some(args) = sess.target.target.options.late_link_args.get(&flavor) {
556561
cmd.args(args);
557562
}
563+
if any_dynamic_crate {
564+
if let Some(args) = sess.target.target.options.late_link_args_dynamic.get(&flavor) {
565+
cmd.args(args);
566+
}
567+
} else {
568+
if let Some(args) = sess.target.target.options.late_link_args_static.get(&flavor) {
569+
cmd.args(args);
570+
}
571+
}
558572
for obj in &sess.target.target.options.post_link_objects {
559573
cmd.arg(get_file_path(sess, obj));
560574
}

src/librustc_target/spec/mod.rs

+12
Original file line numberDiff line numberDiff line change
@@ -579,6 +579,12 @@ pub struct TargetOptions {
579579
/// user-defined but before post_link_objects. Standard platform
580580
/// libraries that should be always be linked to, usually go here.
581581
pub late_link_args: LinkArgs,
582+
/// Linker arguments used in addition to `late_link_args` if at least one
583+
/// Rust dependency is dynamically linked.
584+
pub late_link_args_dynamic: LinkArgs,
585+
/// Linker arguments used in addition to `late_link_args` if aall Rust
586+
/// dependencies are statically linked.
587+
pub late_link_args_static: LinkArgs,
582588
/// Objects to link after all others, always found within the
583589
/// sysroot folder.
584590
pub post_link_objects: Vec<String>, // ... unconditionally
@@ -858,6 +864,8 @@ impl Default for TargetOptions {
858864
post_link_objects: Vec::new(),
859865
post_link_objects_crt: Vec::new(),
860866
late_link_args: LinkArgs::new(),
867+
late_link_args_dynamic: LinkArgs::new(),
868+
late_link_args_static: LinkArgs::new(),
861869
link_env: Vec::new(),
862870
link_env_remove: Vec::new(),
863871
archive_format: "gnu".to_string(),
@@ -1136,6 +1144,8 @@ impl Target {
11361144
key!(pre_link_objects_exe_crt, list);
11371145
key!(pre_link_objects_dll, list);
11381146
key!(late_link_args, link_args);
1147+
key!(late_link_args_dynamic, link_args);
1148+
key!(late_link_args_static, link_args);
11391149
key!(post_link_objects, list);
11401150
key!(post_link_objects_crt, list);
11411151
key!(post_link_args, link_args);
@@ -1363,6 +1373,8 @@ impl ToJson for Target {
13631373
target_option_val!(pre_link_objects_exe_crt);
13641374
target_option_val!(pre_link_objects_dll);
13651375
target_option_val!(link_args - late_link_args);
1376+
target_option_val!(link_args - late_link_args_dynamic);
1377+
target_option_val!(link_args - late_link_args_static);
13661378
target_option_val!(post_link_objects);
13671379
target_option_val!(post_link_objects_crt);
13681380
target_option_val!(link_args - post_link_args);

src/librustc_target/spec/windows_base.rs

+29-2
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,13 @@ pub fn opts() -> TargetOptions {
1717
);
1818

1919
let mut late_link_args = LinkArgs::new();
20+
let mut late_link_args_dynamic = LinkArgs::new();
21+
let mut late_link_args_static = LinkArgs::new();
2022
late_link_args.insert(
2123
LinkerFlavor::Gcc,
2224
vec![
2325
"-lmingwex".to_string(),
2426
"-lmingw32".to_string(),
25-
"-lgcc".to_string(), // alas, mingw* libraries above depend on libgcc
2627
"-lmsvcrt".to_string(),
2728
// mingw's msvcrt is a weird hybrid import library and static library.
2829
// And it seems that the linker fails to use import symbols from msvcrt
@@ -37,6 +38,31 @@ pub fn opts() -> TargetOptions {
3738
"-lkernel32".to_string(),
3839
],
3940
);
41+
late_link_args_dynamic.insert(
42+
LinkerFlavor::Gcc,
43+
vec![
44+
// If any of our crates are dynamically linked then we need to use
45+
// the shared libgcc_s-dw2-1.dll. This is required to support
46+
// unwinding across DLL boundaries.
47+
"-lgcc_s".to_string(),
48+
"-lgcc".to_string(),
49+
"-lkernel32".to_string(),
50+
],
51+
);
52+
late_link_args_static.insert(
53+
LinkerFlavor::Gcc,
54+
vec![
55+
// If all of our crates are statically linked then we can get away
56+
// with statically linking the libgcc unwinding code. This allows
57+
// binaries to be redistributed without the libgcc_s-dw2-1.dll
58+
// dependency, but unfortunately break unwinding across DLL
59+
// boundaries when unwinding across FFI boundaries.
60+
"-lgcc".to_string(),
61+
"-lgcc_eh".to_string(),
62+
"-lpthread".to_string(),
63+
"-lkernel32".to_string(),
64+
],
65+
);
4066

4167
TargetOptions {
4268
// FIXME(#13846) this should be enabled for windows
@@ -63,8 +89,9 @@ pub fn opts() -> TargetOptions {
6389
"rsbegin.o".to_string(),
6490
],
6591
late_link_args,
92+
late_link_args_dynamic,
93+
late_link_args_static,
6694
post_link_objects: vec!["rsend.o".to_string()],
67-
custom_unwind_resume: true,
6895
abi_return_struct_as_int: true,
6996
emit_debug_gdb_scripts: false,
7097
requires_uwtable: true,

src/libunwind/build.rs

+7-2
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,13 @@ fn main() {
3333
} else if target.contains("dragonfly") {
3434
println!("cargo:rustc-link-lib=gcc_pic");
3535
} else if target.contains("pc-windows-gnu") {
36-
println!("cargo:rustc-link-lib=static-nobundle=gcc_eh");
37-
println!("cargo:rustc-link-lib=static-nobundle=pthread");
36+
// This is handled in the target spec with late_link_args_[static|dynamic]
37+
38+
// cfg!(bootstrap) doesn't work in build scripts
39+
if env::var("RUSTC_STAGE").ok() == Some("0".to_string()) {
40+
println!("cargo:rustc-link-lib=static-nobundle=gcc_eh");
41+
println!("cargo:rustc-link-lib=static-nobundle=pthread");
42+
}
3843
} else if target.contains("uwp-windows-gnu") {
3944
println!("cargo:rustc-link-lib=unwind");
4045
} else if target.contains("fuchsia") {

0 commit comments

Comments
 (0)