From dff31910264095cc7c6f391862d3f0eaac0ebcbd Mon Sep 17 00:00:00 2001 From: tamnd <1218621+tamnd@users.noreply.github.com> Date: Wed, 9 Sep 2026 10:43:56 +0700 Subject: [PATCH] LLVM bakes a mingw triple into a compiler that targets MSVC (#320) 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. --- overlay/MANIFEST | 1 + overlay/MODULE.bazel | 1 + .../llvm_windows_target_triple.patch | 26 +++++++++++++++++++ 3 files changed, 28 insertions(+) create mode 100644 overlay/bazel/public-patches/llvm_windows_target_triple.patch diff --git a/overlay/MANIFEST b/overlay/MANIFEST index 7dd79e5..c72fff7 100644 --- a/overlay/MANIFEST +++ b/overlay/MANIFEST @@ -225,6 +225,7 @@ new - bazel/public-patches/curl_private_lib_includes.patch new - bazel/public-patches/google_benchmark_gnu_driver_flags.patch new - bazel/public-patches/llvm_windows_absolute_symlinks.patch new - bazel/public-patches/llvm_windows_stack_flag.patch +new - bazel/public-patches/llvm_windows_target_triple.patch new - bazel/public-patches/mimalloc.BUILD new - bazel/public-patches/protobuf_windows_link_libs.patch new - bazel/public-patches/rules_cc_copy_dynamic_libraries_same_package.patch diff --git a/overlay/MODULE.bazel b/overlay/MODULE.bazel index e667ea1..bbaeed5 100644 --- a/overlay/MODULE.bazel +++ b/overlay/MODULE.bazel @@ -57,6 +57,7 @@ llvm_source = use_extension("//bazel/public-patches:llvm_source.bzl", "llvm_sour llvm_source.configure(extra_patches = [ "//bazel/public-patches:llvm_windows_stack_flag.patch", "//bazel/public-patches:llvm_windows_absolute_symlinks.patch", + "//bazel/public-patches:llvm_windows_target_triple.patch", ]) use_repo(llvm_source, "llvm-raw") diff --git a/overlay/bazel/public-patches/llvm_windows_target_triple.patch b/overlay/bazel/public-patches/llvm_windows_target_triple.patch new file mode 100644 index 0000000..d14acfe --- /dev/null +++ b/overlay/bazel/public-patches/llvm_windows_target_triple.patch @@ -0,0 +1,26 @@ +--- a/utils/bazel/llvm-project-overlay/llvm/config.bzl ++++ b/utils/bazel/llvm-project-overlay/llvm/config.bzl +@@ -144,7 +144,22 @@ + Label("//llvm:is_aarch64_windows_clang_mingw"): native_arch_defines("AArch64", "aarch64-w64-windows-gnu"), + Label("//llvm:is_aarch64_windows_clang_cl"): native_arch_defines("AArch64", "aarch64-pc-windows-msvc"), + Label("//llvm:is_aarch64_windows_msvc"): native_arch_defines("AArch64", "aarch64-pc-windows-msvc"), +- Label("//llvm:is_x86_64_windows_clang_mingw"): native_arch_defines("X86", "x86_64-w64-windows-gnu"), ++ # The name of this arm says mingw, but the condition underneath it is just ++ # "Windows, and the compiler is clang", which is us. We are clang driving ++ # lld-link with --target=x86_64-pc-windows-msvc against a Microsoft sysroot, ++ # and the pair of triples this bakes in is the only thing in the whole build ++ # that says GNU. ++ # ++ # They are what the compiler falls back on when nothing on the command line ++ # names a target, which is the case for mojo run. The code it generates then ++ # asks for ___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 one. ++ # ++ # Only the x86_64 arm is touched. The aarch64 one above has the same problem, ++ # but nothing here builds for that target, so there is no way to find out ++ # whether it is the only thing wrong with it. ++ Label("//llvm:is_x86_64_windows_clang_mingw"): native_arch_defines("X86", "x86_64-pc-windows-msvc"), + Label("//llvm:darwin_arm64"): native_arch_defines("AArch64", "arm64-apple-darwin"), + Label("//llvm:darwin_x86_64"): native_arch_defines("X86", "x86_64-unknown-darwin"), + Label("//llvm:linux_aarch64"): native_arch_defines("AArch64", "aarch64-unknown-linux-gnu"),