Skip to content

Only use dlltool.exe on MinGW if -Cdlltool is passed - #161050

Open
bjorn3 wants to merge 1 commit into
rust-lang:mainfrom
bjorn3:default_no_dlltool
Open

Only use dlltool.exe on MinGW if -Cdlltool is passed#161050
bjorn3 wants to merge 1 commit into
rust-lang:mainfrom
bjorn3:default_no_dlltool

Conversation

@bjorn3

@bjorn3 bjorn3 commented Aug 13, 2026

Copy link
Copy Markdown
Member

View all comments

The linker used by MinGW now works with ar_archive_writer generated short import libraries too.

Implements rust-lang/compiler-team#1029

r? @mati865

@rustbot rustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. labels Aug 13, 2026
@mati865 mati865 added the S-waiting-on-MCP Status: PR has a compiler MCP and is waiting for the compiler MCP to complete. label Aug 13, 2026
Comment thread compiler/rustc_codegen_ssa/src/back/archive.rs Outdated
@bjorn3
bjorn3 force-pushed the default_no_dlltool branch from 7dda195 to fd82481 Compare August 14, 2026 09:48

@mati865 mati865 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Blocked only the on MCP.

View changes since this review

@mati865 mati865 added S-blocked Status: Blocked on something else such as an RFC or other implementation work. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Aug 14, 2026
@bjorn3

bjorn3 commented Aug 24, 2026

Copy link
Copy Markdown
Member Author

@rustbot ready

MCP has been accepted.

@rustbot rustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. and removed S-blocked Status: Blocked on something else such as an RFC or other implementation work. labels Aug 24, 2026
@mati865

mati865 commented Aug 24, 2026

Copy link
Copy Markdown
Member

@bors r+

@rust-bors

rust-bors Bot commented Aug 24, 2026

Copy link
Copy Markdown
Contributor

📋 This PR cannot be approved because it currently has the following label: S-waiting-on-MCP.

@mati865 mati865 removed the S-waiting-on-MCP Status: PR has a compiler MCP and is waiting for the compiler MCP to complete. label Aug 24, 2026
@mati865

mati865 commented Aug 24, 2026

Copy link
Copy Markdown
Member

@bors r+

I suppose we will want to include it in release notes, no?

@rust-bors

rust-bors Bot commented Aug 24, 2026

Copy link
Copy Markdown
Contributor

📌 Commit fd82481 has been approved by mati865

It is now in the queue for this repository.

@rust-bors rust-bors Bot added S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Aug 24, 2026
@bjorn3 bjorn3 added the relnotes Marks issues that should be documented in the release notes of the next release. label Aug 24, 2026
JonathanBrouwer added a commit to JonathanBrouwer/rust that referenced this pull request Aug 24, 2026
Only use dlltool.exe on MinGW if -Cdlltool is passed

The linker used by MinGW now works with ar_archive_writer generated short import libraries too.

Implements rust-lang/compiler-team#1029

r? @mati865
JonathanBrouwer added a commit to JonathanBrouwer/rust that referenced this pull request Aug 24, 2026
Only use dlltool.exe on MinGW if -Cdlltool is passed

The linker used by MinGW now works with ar_archive_writer generated short import libraries too.

Implements rust-lang/compiler-team#1029

r? @mati865
JonathanBrouwer added a commit to JonathanBrouwer/rust that referenced this pull request Aug 24, 2026
Only use dlltool.exe on MinGW if -Cdlltool is passed

The linker used by MinGW now works with ar_archive_writer generated short import libraries too.

Implements rust-lang/compiler-team#1029

r? @mati865
rust-bors Bot pushed a commit that referenced this pull request Aug 24, 2026
…uwer

Rollup of 6 pull requests

Successful merges:

 - #155499 (stabilize never type)
 - #161294 (add crashtests [6/N])
 - #161050 (Only use dlltool.exe on MinGW if -Cdlltool is passed)
 - #159583 (Add new `invalid_markdown_table` rustdoc lint)
 - #161098 (PassWrapper: handle LLVM 24 change in function types)
 - #161661 (Don't treat slashes as path seps after drive letters in verbatim paths)
rust-bors Bot pushed a commit that referenced this pull request Aug 24, 2026
…uwer

Rollup of 5 pull requests

Successful merges:

 - #161294 (add crashtests [6/N])
 - #161050 (Only use dlltool.exe on MinGW if -Cdlltool is passed)
 - #159583 (Add new `invalid_markdown_table` rustdoc lint)
 - #161098 (PassWrapper: handle LLVM 24 change in function types)
 - #161661 (Don't treat slashes as path seps after drive letters in verbatim paths)
JonathanBrouwer added a commit to JonathanBrouwer/rust that referenced this pull request Aug 24, 2026
Only use dlltool.exe on MinGW if -Cdlltool is passed

The linker used by MinGW now works with ar_archive_writer generated short import libraries too.

Implements rust-lang/compiler-team#1029

r? @mati865
rust-bors Bot pushed a commit that referenced this pull request Aug 24, 2026
…uwer

Rollup of 6 pull requests

Successful merges:

 - #155499 (stabilize never type)
 - #161294 (add crashtests [6/N])
 - #161050 (Only use dlltool.exe on MinGW if -Cdlltool is passed)
 - #159583 (Add new `invalid_markdown_table` rustdoc lint)
 - #161098 (PassWrapper: handle LLVM 24 change in function types)
 - #161661 (Don't treat slashes as path seps after drive letters in verbatim paths)
@JonathanBrouwer

Copy link
Copy Markdown
Member

@bors try jobs=dist-i686-mingw

@rust-bors

This comment has been minimized.

rust-bors Bot pushed a commit that referenced this pull request Aug 24, 2026
Only use dlltool.exe on MinGW if -Cdlltool is passed


try-job: dist-i686-mingw
@mati865

mati865 commented Aug 24, 2026

Copy link
Copy Markdown
Member

I can look into that failure tomorrow. Looks like we don't prefix import symbols correctly on i686 windows GNU for some reason.

@JonathanBrouwer

Copy link
Copy Markdown
Member

@bors r-
This is probably the problem

@rust-bors rust-bors Bot added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. and removed S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. labels Aug 24, 2026
@rust-bors

rust-bors Bot commented Aug 24, 2026

Copy link
Copy Markdown
Contributor

This pull request was unapproved.

This PR was contained in a rollup (#161688), which was unapproved.

View changes since this unapproval

@rust-bors

rust-bors Bot commented Aug 24, 2026

Copy link
Copy Markdown
Contributor

💔 Test for 3d9e5bb failed: CI. Failed job:

@rust-log-analyzer

This comment has been minimized.

@mati865

mati865 commented Aug 24, 2026

Copy link
Copy Markdown
Member

I can look into that failure tomorrow. Looks like we don't prefix import symbols correctly on i686 windows GNU for some reason.

Okay, I couldn't resist.
This refactor will make it clearer how things work: #161701 and this is how this PR should look like (modulo updated comments): mati865@fe906617

@rust-bors

This comment has been minimized.

The linker used by MinGW now works with ar_archive_writer generated short
import libraries too.
@bjorn3

bjorn3 commented Aug 27, 2026

Copy link
Copy Markdown
Member Author

and this is how this PR should look like (modulo updated comments): mati865@fe906617

Doesn't that mean -Cdlltool=foo would require recompiling the standard library as the standard library would contain ar_archive_writer generated import libraries, but functions that contains calls against these import libraries this might be monomorphized in crates that have -Cdlltool passed to them.

@bjorn3
bjorn3 force-pushed the default_no_dlltool branch from fd82481 to 3b99205 Compare August 27, 2026 09:57
@rustbot

rustbot commented Aug 27, 2026

Copy link
Copy Markdown
Collaborator

This PR was rebased onto a different main commit. Here's a range-diff highlighting what actually changed.

Rebasing is a normal part of keeping PRs up to date, so no action is needed—this note is just to help reviewers.

@mati865

mati865 commented Aug 27, 2026

Copy link
Copy Markdown
Member

Uhm, that's a good point about stdlib. I was under impression we don't use raw-dylib by default there, but that's not the case.
That's because https://github.com/rust-lang/rust/blob/e457a7b0d326d67b4322ef0d11bd715cfaeda48f/library/windows_link/src/lib.rs is not the only way we import Windows libs as I previously thought.
Some of them are always using raw-dylib, like

link(name = "bcryptprimitives", kind = "raw-dylib", import_name_type = "undecorated")
or
kind = "raw-dylib",

So, your change already make the std contain ar_archive_writer generated import libraries and user cannot opt out them without rebuilding std.

And we only saw that because without changes in mati865@fe906617 your PR creates mismatch in symbol decoration logic (ar_archive_writer vs dlltool). And that logic is scattered across many places as you can see in my commit.

@mati865

mati865 commented Sep 2, 2026

Copy link
Copy Markdown
Member

If we apply mati865@fe906617 and build std with -Cdlltool for now, we wouldn't need to worry about monorphization, right?

@bjorn3

bjorn3 commented Sep 2, 2026

Copy link
Copy Markdown
Member Author

Wouldn't we need to record whether dlltool was used into the raw-dylib definition and then choose between the codegen path for dlltool vs ar_archive_writer when codegening calls to this raw-dylib? Otherwise standard library functions codegened outside the standard library would assume ar_archive_writer even though only a dlltool import library is present.

@mati865

mati865 commented Sep 2, 2026

Copy link
Copy Markdown
Member

Otherwise standard library functions codegened outside the standard library would assume ar_archive_writer even though only a dlltool import library is present.

Certainly I'm not up to speed in this area. Does that mean we might feed ar_archive_writer an undecorated symbol (meant for dlltool)?
If that's the case, then pulling the rug and removing dlltool support altogether might be the only sensible way forward.

@bjorn3

bjorn3 commented Sep 2, 2026

Copy link
Copy Markdown
Member Author

If I understand correctly ar_archive_writer and dlltool generated import libraries will expose the imported functions under different names. (I think one exposes them with their decorated name and the other with their undecorated name) And because of this cg_llvm has to generate different calls depending on if the import library was generated by ar_archive_writer or by dlltool. If I recall correctly the import library is generated (and thus the symbol name set to one or the other option) when compiling the crate that defines the raw-dylib. But if calls are generated in another crate, mati865@fe906617 would pick the symbol name to call based on the local -Cdlltool value rather than when the import library was generated.

If that's the case, then pulling the rug and removing dlltool support altogether might be the only sensible way forward.

I'm afraid so.

@mati865

mati865 commented Sep 2, 2026

Copy link
Copy Markdown
Member

If I understand correctly ar_archive_writer and dlltool generated import libraries will expose the imported functions under different names. (I think one exposes them with their decorated name and the other with their undecorated name)

Dlltool adds the decorations itself (or rather adds them unless you pass --no-leading-underscore like we started doing at some point), so we have to skip them in that branch. This case is similar to how we use it:

❯ printf 'EXPORTS\nbar' > foo.def

❯ i686-w64-mingw32-dlltool -d foo.def -D foo.dll -l libfoo.dll.a

❯ nm libfoo.dll.a | rg bar
00000000 T _bar
00000000 I __imp__bar

We asked it to create dllimported bar, so it prefixed it with __imp_, but since this is i686 it also added the underscore right before bar part, resulting in __imp__bar. The exact same names will be made by ar_archive_writer, we just have to feed it the already decorated names.

There goes the theory, I just checked the binaries and in the practice we mess up big time here.
This is how our raw-dylib import symbols should look like:

❯ llvm-nm /usr/i686-w64-mingw32/lib/libbcryptprimitives.a | rg ProcessPrng | rg -v Guid
00000000 T _ProcessPrng@8
00000000 I __imp__ProcessPrng@8
# or (both are fine)
❯ llvm-nm /opt/llvm-mingw/llvm-mingw-ucrt/i686-w64-mingw32/lib/libbcryptprimitives.a | rg ProcessPrng | rg -v Guid
00000000 T _ProcessPrng@8
00000000 T __imp__ProcessPrng@8

And sure i686-pc-windows-gnullvm looks like that:

❯ llvm-nm ~/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/i686-pc-windows-gnullvm/lib/libstd-5c84ca49ba3e22ca.rlib | rg ProcessPrng
         U __imp__ProcessPrng@8
00000000 T _ProcessPrng@8
00000000 T __imp__ProcessPrng@8

But what the heck happened with i686-pc-windows-gnu?

❯ llvm-nm ~/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/i686-pc-windows-gnu/lib/libstd-28eef08820bd8b87.rlib | rg ProcessPrng
         U __imp_ProcessPrng
00000000 T ProcessPrng
00000000 I __imp_ProcessPrng

_ProcessPrng@8 is stdcall calling convention, _ProcessPrng would be cdecl, but ProcessPrng, on i686?
I knew that mingw-w64 and the linker can fixup wrong calling convention, but bad mangling? That's a novelty to me, and I have no idea how it doesn't straight up crash when running (I made an example using that symbol, it really works).

And because of this cg_llvm has to generate different calls depending on if the import library was generated by ar_archive_writer or by dlltool. If I recall correctly the import library is generated (and thus the symbol name set to one or the other option) when compiling the crate that defines the raw-dylib.

We should always generate call to the same dllimport symbol, no matter how the import lib was made.

"Do as I say, not as I do"

// MinGW: For backward compatibility we rely on the linker to decide whether it
// should use dllimport for functions.
if cx.use_dll_storage_attrs
&& let Some(library) = tcx.native_library(instance_def_id)
&& library.kind.is_dllimport()
&& !matches!(tcx.sess.target.env, Env::Gnu | Env::Uclibc)

But that is irrelevant for our raw-dylib consideration.

So, if we fix this cursed dlltool hack and both ar_archive_writer and dlltool generate the symbols, there should be no problem with switching between them?
But is it even worth investing time into that? Nuking all dlltool usage from the compiler would be so much easier...

@ChrisDenton

Copy link
Copy Markdown
Member

But is it even worth investing time into that? Nuking all dlltool usage from the compiler would be so much easier...

Yes, I think we should just nuke it. If it had worked with the ar_archive_writer implementation from the beginning then we would never have introduced dlltool in the first place. I'm not sure what keeping it around in zombie form gains us, tbh. I guess it could be a hedge against any implementation issues but I'd rather put the effort into fixing any bugs or compatibility problems that may (or hopefully won't) crop up.

@mati865

mati865 commented Sep 3, 2026

Copy link
Copy Markdown
Member

Haven't ran the tests on Windows machine yet and some changes are done hastily without deep consideration, but that looks like a nice cleanup in addition to fixing the discrepancy: main...mati865:rust:push-wwnqklwnwkwu

Before:

❯ nm build/x86_64-unknown-linux-gnu/stage1-std/i686-pc-windows-gnu/dist/build/std/47b34ecc0226a577/out/libstd-47b34ecc0226a577.rlib | rg ProcessPrng
         U __imp_ProcessPrng
00000000 I __imp_ProcessPrng
00000000 T ProcessPrng

❯ nm build/x86_64-unknown-linux-gnu/stage1-std/i686-pc-windows-gnullvm/dist/build/std/d118868017530d1d/out/libstd-d118868017530d1d.rlib | rg ProcessPrng
         U __imp__ProcessPrng@8
00000000 I __imp__ProcessPrng@8
00000000 T _ProcessPrng@8

After:

❯ nm build/x86_64-unknown-linux-gnu/stage1-std/i686-pc-windows-gnu/dist/build/std/47b34ecc0226a577/out/libstd-47b34ecc0226a577.rlib | rg ProcessPrng
         U __imp__ProcessPrng@8
00000000 I __imp__ProcessPrng@8
00000000 T _ProcessPrng@8

❯ nm build/x86_64-unknown-linux-gnu/stage1-std/i686-pc-windows-gnullvm/dist/build/std/d118868017530d1d/out/libstd-d118868017530d1d.rlib | rg ProcessPrng
         U __imp__ProcessPrng@8
00000000 I __imp__ProcessPrng@8
00000000 T _ProcessPrng@8

@mati865

mati865 commented Sep 3, 2026

Copy link
Copy Markdown
Member

^^ no, forget about it. Dlltool was not designed to handle all our cases. Achieving identical symbol decorations for typical use cases is easy, but handling import_name_type would require us to create multiple import libs for the same library with different dlltool options, and I don't even know if this will link successfully.

We are left only with the nuclear solution.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

relnotes Marks issues that should be documented in the release notes of the next release. S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants