Skip to content

Commit 584e83d

Browse files
committed
Auto merge of rust-lang#72049 - mati865:mingw-lld, r=petrochenkov
MinGW: enable dllexport/dllimport Fixes (only when using LLD) rust-lang#50176 Fixes rust-lang#72319 This makes `windows-gnu` on pair with `windows-msvc` when it comes to symbol exporting. For MinGW it means both good things like correctly working dllimport/dllexport, ability to link with LLD and bad things like rust-lang#27438. Not sure but maybe this should land behind unstable compiler option (`-Z`) or environment variable?
2 parents 06e7b93 + 87abd65 commit 584e83d

File tree

9 files changed

+61
-14
lines changed

9 files changed

+61
-14
lines changed

src/librustc_codegen_llvm/callee.rs

+6-1
Original file line numberDiff line numberDiff line change
@@ -172,7 +172,12 @@ pub fn get_fn(cx: &CodegenCx<'ll, 'tcx>, instance: Instance<'tcx>) -> &'ll Value
172172
}
173173
}
174174

175-
if cx.use_dll_storage_attrs && tcx.is_dllimport_foreign_item(instance_def_id) {
175+
// MinGW: For backward compatibility we rely on the linker to decide whether it
176+
// should use dllimport for functions.
177+
if cx.use_dll_storage_attrs
178+
&& tcx.is_dllimport_foreign_item(instance_def_id)
179+
&& tcx.sess.target.target.target_env != "gnu"
180+
{
176181
unsafe {
177182
llvm::LLVMSetDLLStorageClass(llfn, llvm::DLLStorageClass::DllImport);
178183
}

src/librustc_codegen_llvm/consts.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -287,7 +287,7 @@ impl CodegenCx<'ll, 'tcx> {
287287
// argument validation.
288288
debug_assert!(
289289
!(self.tcx.sess.opts.cg.linker_plugin_lto.enabled()
290-
&& self.tcx.sess.target.target.options.is_like_msvc
290+
&& self.tcx.sess.target.target.options.is_like_windows
291291
&& self.tcx.sess.opts.cg.prefer_dynamic)
292292
);
293293

src/librustc_codegen_llvm/context.rs

+12-3
Original file line numberDiff line numberDiff line change
@@ -217,7 +217,16 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> {
217217
// attributes in LLVM IR as well as native dependencies (in C these
218218
// correspond to `__declspec(dllimport)`).
219219
//
220-
// Whenever a dynamic library is built by MSVC it must have its public
220+
// LD (BFD) in MinGW mode can often correctly guess `dllexport` but
221+
// relying on that can result in issues like #50176.
222+
// LLD won't support that and expects symbols with proper attributes.
223+
// Because of that we make MinGW target emit dllexport just like MSVC.
224+
// When it comes to dllimport we use it for constants but for functions
225+
// rely on the linker to do the right thing. Opposed to dllexport this
226+
// task is easy for them (both LD and LLD) and allows us to easily use
227+
// symbols from static libraries in shared libraries.
228+
//
229+
// Whenever a dynamic library is built on Windows it must have its public
221230
// interface specified by functions tagged with `dllexport` or otherwise
222231
// they're not available to be linked against. This poses a few problems
223232
// for the compiler, some of which are somewhat fundamental, but we use
@@ -254,8 +263,8 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> {
254263
// this effect) by marking very little as `dllimport` and praying the
255264
// linker will take care of everything. Fixing this problem will likely
256265
// require adding a few attributes to Rust itself (feature gated at the
257-
// start) and then strongly recommending static linkage on MSVC!
258-
let use_dll_storage_attrs = tcx.sess.target.target.options.is_like_msvc;
266+
// start) and then strongly recommending static linkage on Windows!
267+
let use_dll_storage_attrs = tcx.sess.target.target.options.is_like_windows;
259268

260269
let check_overflow = tcx.sess.overflow_checks();
261270

src/librustc_codegen_ssa/back/linker.rs

+21-2
Original file line numberDiff line numberDiff line change
@@ -523,8 +523,9 @@ impl<'a> Linker for GccLinker<'a> {
523523
return;
524524
}
525525

526+
let is_windows = self.sess.target.target.options.is_like_windows;
526527
let mut arg = OsString::new();
527-
let path = tmpdir.join("list");
528+
let path = tmpdir.join(if is_windows { "list.def" } else { "list" });
528529

529530
debug!("EXPORTED SYMBOLS:");
530531

@@ -540,6 +541,21 @@ impl<'a> Linker for GccLinker<'a> {
540541
if let Err(e) = res {
541542
self.sess.fatal(&format!("failed to write lib.def file: {}", e));
542543
}
544+
} else if is_windows {
545+
let res: io::Result<()> = try {
546+
let mut f = BufWriter::new(File::create(&path)?);
547+
548+
// .def file similar to MSVC one but without LIBRARY section
549+
// because LD doesn't like when it's empty
550+
writeln!(f, "EXPORTS")?;
551+
for symbol in self.info.exports[&crate_type].iter() {
552+
debug!(" _{}", symbol);
553+
writeln!(f, " {}", symbol)?;
554+
}
555+
};
556+
if let Err(e) = res {
557+
self.sess.fatal(&format!("failed to write list.def file: {}", e));
558+
}
543559
} else {
544560
// Write an LD version script
545561
let res: io::Result<()> = try {
@@ -573,7 +589,10 @@ impl<'a> Linker for GccLinker<'a> {
573589
if !self.is_ld {
574590
arg.push("-Wl,")
575591
}
576-
arg.push("--version-script=");
592+
// Both LD and LLD accept export list in *.def file form, there are no flags required
593+
if !is_windows {
594+
arg.push("--version-script=")
595+
}
577596
}
578597

579598
arg.push(&path);

src/librustc_codegen_ssa/back/write.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -1846,11 +1846,11 @@ fn msvc_imps_needed(tcx: TyCtxt<'_>) -> bool {
18461846
// something is wrong with commandline arg validation.
18471847
assert!(
18481848
!(tcx.sess.opts.cg.linker_plugin_lto.enabled()
1849-
&& tcx.sess.target.target.options.is_like_msvc
1849+
&& tcx.sess.target.target.options.is_like_windows
18501850
&& tcx.sess.opts.cg.prefer_dynamic)
18511851
);
18521852

1853-
tcx.sess.target.target.options.is_like_msvc &&
1853+
tcx.sess.target.target.options.is_like_windows &&
18541854
tcx.sess.crate_types().iter().any(|ct| *ct == CrateType::Rlib) &&
18551855
// ThinLTO can't handle this workaround in all cases, so we don't
18561856
// emit the `__imp_` symbols. Instead we make them unnecessary by disallowing

src/librustc_session/session.rs

+5-5
Original file line numberDiff line numberDiff line change
@@ -1294,19 +1294,19 @@ pub fn build_session(
12941294
// commandline argument, you can do so here.
12951295
fn validate_commandline_args_with_session_available(sess: &Session) {
12961296
// Since we don't know if code in an rlib will be linked to statically or
1297-
// dynamically downstream, rustc generates `__imp_` symbols that help the
1298-
// MSVC linker deal with this lack of knowledge (#27438). Unfortunately,
1297+
// dynamically downstream, rustc generates `__imp_` symbols that help linkers
1298+
// on Windows deal with this lack of knowledge (#27438). Unfortunately,
12991299
// these manually generated symbols confuse LLD when it tries to merge
1300-
// bitcode during ThinLTO. Therefore we disallow dynamic linking on MSVC
1300+
// bitcode during ThinLTO. Therefore we disallow dynamic linking on Windows
13011301
// when compiling for LLD ThinLTO. This way we can validly just not generate
13021302
// the `dllimport` attributes and `__imp_` symbols in that case.
13031303
if sess.opts.cg.linker_plugin_lto.enabled()
13041304
&& sess.opts.cg.prefer_dynamic
1305-
&& sess.target.target.options.is_like_msvc
1305+
&& sess.target.target.options.is_like_windows
13061306
{
13071307
sess.err(
13081308
"Linker plugin based LTO is not supported together with \
1309-
`-C prefer-dynamic` when targeting MSVC",
1309+
`-C prefer-dynamic` when targeting Windows-like targets",
13101310
);
13111311
}
13121312

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
include ../tools.mk
2+
3+
# only-windows-gnu
4+
5+
all:
6+
$(RUSTC) foo.rs
7+
# FIXME: we should make sure __stdcall calling convention is used here
8+
# but that only works with LLD right now
9+
nm -g "$(call IMPLIB,foo)" | $(CGREP) bar
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
#![crate_type = "cdylib"]
2+
3+
#[no_mangle]
4+
pub extern "system" fn bar() {}

src/test/run-make-fulldeps/tools.mk

+1
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ ifdef IS_MSVC
5151
STATICLIB = $(TMPDIR)/$(1).lib
5252
STATICLIB_GLOB = $(1)*.lib
5353
else
54+
IMPLIB = $(TMPDIR)/lib$(1).dll.a
5455
STATICLIB = $(TMPDIR)/lib$(1).a
5556
STATICLIB_GLOB = lib$(1)*.a
5657
endif

0 commit comments

Comments
 (0)