Skip to content

LLVM bakes a mingw triple into a compiler that targets MSVC - #320

Merged
tamnd merged 1 commit into
mainfrom
mingw-triple
Sep 9, 2026
Merged

tamnd merged 1 commit into
mainfrom
mingw-triple

Conversation

@tamnd

@tamnd tamnd commented Sep 9, 2026

Copy link
Copy Markdown
Owner

Closes #318.

A mojo.exe built for Windows thinks its default target is x86_64-w64-windows-gnu. Ask it for LLVM IR and the module header says so, on a build where the C toolchain passes --target=x86_64-pc-windows-msvc, the Mojo compiler passes -target-triple=x86_64-pc-windows-msvc, and the sysroot is the Microsoft one.

The triple comes from LLVM's own Bazel files. config.bzl picks LLVM_HOST_TRIPLE and LLVM_DEFAULT_TARGET_TRIPLE out of a select, and the arm it lands on for us is is_x86_64_windows_clang_mingw. That name is misleading. The config_setting behind it is Windows, x86_64, and a compiler that calls itself clang, and ours does, because it is clang. LLVM reads the name as a claim about the ABI on the assumption that clang on Windows means the GNU driver and only clang-cl means MSVC, and we are the third case, which is the clang driver targeting MSVC.

What it breaks

Nothing notices until something asks the compiler to generate code without naming a target on the command line, which is what mojo run does. Then:

JIT session error: Symbols not found: [ _setmode, GetConsoleMode, SetConsoleMode, _write, memcpy, ___chkstk_ms, __main, GetStdHandle, SetConsoleCP, SetConsoleOutputCP ]
error: Failed to materialize symbols: { (exec, { main }) }

___chkstk_ms is libgcc's stack probe and __main is the mingw static constructor hook. Neither has an MSVC equivalent to find, so no work on the JIT side fixes this. It is what blocks #31.

The change

One line in the LLVM overlay, patched in the same place and for the same reason as llvm_windows_stack_flag.patch, which already carries a comment saying that this arm means "Windows and clang" rather than "mingw".

Only the x86_64 arm is changed. The aarch64 one above it has the same problem, but nothing here builds for that target, so there is no way to find out whether the triple is the only thing wrong with it.

Why not clang-cl

The other way to move the select is to say compiler = "clang-cl" in our own toolchain, which is what the issue suggested before this was written. Two things against it. It describes the driver as something it is not, and it is a single value shared by every target, so it would also drop us off the is_windows_clang_mingw arm that llvm_windows_stack_flag.patch attaches the Windows stack size and the ole32, uuid and ws2_32 link flags to. It also does not land on an MSVC arm in config.bzl, because there is no is_x86_64_windows_clang_cl entry in that select. It falls through to the plain Windows default, which happens to be close enough by accident.

@tamnd tamnd added this to the M6 Tier 2 and native hosting milestone Sep 9, 2026
@tamnd tamnd added area/build Bazel, toolchain, sysroot type/bug Something is broken priority/p1 Important. Needed for the milestone labels Sep 9, 2026
A mojo.exe built for Windows thinks its default target is x86_64-w64-windows-gnu. Ask it for LLVM IR and the module header says so, on a build where the C toolchain, the Mojo compiler flags and the sysroot all say x86_64-pc-windows-msvc.

The triple comes from LLVM's own Bazel files. config.bzl picks LLVM_HOST_TRIPLE and LLVM_DEFAULT_TARGET_TRIPLE out of a select, and the arm it lands on for us is is_x86_64_windows_clang_mingw, which is not a statement about mingw at all: the config_setting behind it is Windows, x86_64, and a compiler that calls itself clang. Ours does, because it is clang. LLVM reads that as a claim about the ABI, on the assumption that clang on Windows means the GNU driver and only clang-cl means MSVC, and we are the third case.

Nothing notices until something asks the compiler to generate code without naming a target, which is what mojo run does. The code then wants ___chkstk_ms and __main, which are libgcc and mingw entry points, and the JIT cannot resolve them because a Windows machine has no reason to have either.

Fixed in the same place as the stack flag patch, which is already there for the same reason and says so in its own comment. Saying clang-cl in our toolchain instead would also move the select, but it would move it by describing the driver as something it is not, and it would drop us off the arm the stack flag patch is attached to.
@tamnd

tamnd commented Sep 9, 2026

Copy link
Copy Markdown
Owner Author

Verified on a Windows host with a cross linked mojo.exe staged out of bazel-bin.

Before:

target triple = "x86_64-w64-windows-gnu"
JIT session error: Symbols not found: [ _setmode, GetConsoleMode, SetConsoleMode, _write, memcpy, ___chkstk_ms, __main, GetStdHandle, SetConsoleCP, SetConsoleOutputCP ]

After:

target triple = "x86_64-pc-windows-msvc"
JIT session error: Symbols not found: [ __chkstk, SetConsoleOutputCP, GetConsoleMode, _write, _setmode, GetStdHandle, SetConsoleCP, memcpy, SetConsoleMode ]

___chkstk_ms and __main are gone and __chkstk has taken their place, which is the MSVC spelling and a symbol that actually exists on the machine. What is left is the CRT and kernel32 names, which is #31: the JIT has nothing telling it where to find the C runtime or the system DLLs. That is a real problem and a different one, and it could not be seen until this was fixed.

mojo build --emit=llvm exits 0 and mojo.exe --version still works.

@tamnd
tamnd merged commit dff3191 into main Sep 9, 2026
7 checks passed
@tamnd
tamnd deleted the mingw-triple branch September 9, 2026 03:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/build Bazel, toolchain, sysroot priority/p1 Important. Needed for the milestone type/bug Something is broken

Projects

None yet

Development

Successfully merging this pull request may close these issues.

mojo.exe defaults to the MinGW target triple

1 participant