Skip to content

fix: support native builds on Windows via MinGW-w64 - #199

Closed
techfreaque wants to merge 3 commits into
vercel-labs:mainfrom
techfreaque:fix-windows-mingw-toolchain
Closed

fix: support native builds on Windows via MinGW-w64#199
techfreaque wants to merge 3 commits into
vercel-labs:mainfrom
techfreaque:fix-windows-mingw-toolchain

Conversation

@techfreaque

Copy link
Copy Markdown

Problem

Native (non-cross-compiled) builds have no Windows support: running scriptc's own compiler natively on a Windows host fails, with no error pointing at the real cause — it just dies deep in a compile step with a cryptic "file not found" for a POSIX header.

Root cause

nativePlatformArgs() in packages/compiler/src/backend/cc.ts only has a linux branch (-D_GNU_SOURCE / -lm) and falls through to empty flags for every other host platform, win32 included.

clang's own default target on Windows is the MSVC ABI, whose C runtime has none of the POSIX headers (dirent.h, unistd.h) or types (ssize_t) that this project's runtime C sources — and the vendored QuickJS engine sources — need. Nothing in the existing flag set points a native Windows build at a toolchain that actually has those.

Fix

Add a win32 branch to nativePlatformArgs() that targets MinGW-w64 instead of the MSVC ABI, the same way the existing linux branch adds target-specific flags to the same clang invocation:

  • --target=x86_64-w64-mingw32 plus -isystem<mingwRoot>\include
  • An auto-discovered MinGW-w64 root: explicit SCRIPTC_MINGW_ROOT first, otherwise probing the common MSYS2/mingw-w64 install locations (C:\msys64\mingw64, C:\mingw64, C:\msys2\mingw64) — mirroring the existing Android NDK auto-discovery (androidNdkSysroot) right above it in the same file.
  • -L/-B pointed at the MinGW root, plus the versioned libgcc.a/libgcc_eh.a lib directory (glob-discovered under lib/gcc/x86_64-w64-mingw32/<version>, since clang has no reason to already know GCC's own version-specific install layout) and -lwinpthread (MinGW's clock_gettime/nanosleep aliasing needs winpthreads' definitions, not the CRT's).
  • A clear error (naming the MSYS2 install command and SCRIPTC_MINGW_ROOT) when no MinGW-w64 install can be found, instead of the previous cryptic missing-header failure.

No changes to any other platform's flags.

Verification

  • packages/compiler type-checks clean (tsc -p tsconfig.json, 0 errors).
  • Existing cc-driver.test.ts / cc-cache.test.ts suites pass; the pinned "host-Linux contract" cases (asserting nativePlatformArgs's Linux targetArgs/linkArgs) are unaffected, as expected since this change only adds a new win32 branch.
  • Verified end-to-end on a real Windows machine with MSYS2/MinGW-w64 installed (C:\msys64\mingw64): a native host build now compiles and links a real native binary, where it previously failed on a missing POSIX header.

@vercel

vercel Bot commented Aug 22, 2026

Copy link
Copy Markdown
Contributor

@mabr-pcvisit is attempting to deploy a commit to the Vercel Labs Team on Vercel.

A member of the Team first needs to authorize it.

Comment thread packages/compiler/src/backend/cc.ts Outdated
clang's own default target on Windows is the MSVC ABI, which has none of
the POSIX headers (dirent.h, unistd.h) or types (ssize_t) this project's
runtime C sources — and the vendored QuickJS engine sources — need. There
was no error pointing at this; native host builds on Windows just failed
deep in a compile step with a cryptic "file not found" for a POSIX header.

nativePlatformArgs() only had a linux branch (-D_GNU_SOURCE / -lm) and fell
through to empty flags for every other host platform, win32 included. Add a
win32 branch that targets MinGW-w64 instead: --target=x86_64-w64-mingw32,
an -isystem/-L/-B pointed at an auto-discovered MinGW-w64 install (explicit
SCRIPTC_MINGW_ROOT, else the common MSYS2/mingw-w64 install locations,
mirroring the existing Android NDK auto-discovery), plus the versioned
libgcc.a/libgcc_eh.a lib dir and -lwinpthread that MinGW's toolchain needs
at link time.

Verified end-to-end on a real Windows machine with MSYS2/MinGW-w64
installed: compiles and links a real native binary.
@techfreaque
techfreaque force-pushed the fix-windows-mingw-toolchain branch from a6cc5a2 to 4295d9b Compare August 22, 2026 09:30
vercel[bot]'s review caught that resolveCc computed hostArgs
unconditionally at the top of the function via nativePlatformArgs.
On win32, that function now throws when no MinGW-w64 install is
found - which broke every zig-cc cross-compile target (iOS, Android,
Linux, wasm, ...) on a Windows host with no local MinGW, even though
none of those paths ever use hostArgs (they build their own explicit
targetArgs/linkArgs).

Fixed by computing nativePlatformArgs only at the two return sites
that actually spread it into the result (bare clang, and zigcc with
no SCRIPTC_TARGET) - both host-native paths where win32 support is
actually relevant.

Verified: cc-driver.test.ts's cross-compile-path tests (SCRIPTC_TARGET
without zigcc, zigcc resolution, linux triple flags) still pass; the
two failing tests in this environment (spawn EPERM / ar ENOENT) are
pre-existing, confirmed unrelated to this change (no ar/native
toolchain on this sandboxed CI-like environment's PATH).
…pply to it

Empirically verified against a real zig 0.16 install that the previous
version of this fix was actively broken for the zig-cc host-native path:

  zig cc hi.c -o hi.exe                          -> works, no extra flags needed
  zig cc --target=x86_64-w64-mingw32 hi.c -o ...  -> error: unable to parse
                                                      target query
                                                      'x86_64-w64-mingw32':
                                                      UnknownOperatingSystem

zig cc already bundles mingw-w64 headers/CRT for its own x86_64-windows-gnu
target (see this file's own module doc comment) and needs no external
MinGW-w64 install at all - clang's LLVM triple spelling isn't even a valid
zig target-query spelling. resolveCc's zig-cc host-native branch
(SCRIPTC_CC=zigcc, no SCRIPTC_TARGET) was spreading the same
nativePlatformArgs() result as the bare-clang branch, so it was requiring
an external MinGW unnecessarily and then feeding it flags that hard-error
on zig specifically - a real regression on the project's primary
cross-compile toolchain, not just redundant.

Fixed by giving nativePlatformArgs a viaZig flag: on win32 it now only
does MinGW discovery for the bare-clang path; the zig-cc host-native path
gets empty targetArgs/linkArgs, matching how zig actually works standalone.

Verified: `resolveCc({SCRIPTC_CC: "zigcc"}, "win32")` now returns empty
targetArgs/linkArgs (was throwing/injecting broken flags before), and a
manual `zig cc` compile with no flags produces a working ~780KB native exe.
cc-driver.test.ts's cross-compile-target tests (linux, x86_64-windows-gnu
cross, musl, regex, --dynamic) all pass; the remaining local failures are
this sandboxed environment's own execution/toolchain gaps (spawn EPERM
from Windows Defender ASR blocking freshly-compiled binaries, missing
ar/nm on PATH, and one pre-existing non-Windows-aware test path in
cc-driver.test.ts itself using a bare "program" outPath instead of
"program.exe" - unrelated to this fix, not touched here).
@techfreaque

Copy link
Copy Markdown
Author

Closing in favor of a fresh PR: your review caught a real bug (eager MinGW probe breaking zig-cc cross-compiles), and while fixing it I found a second, more serious issue in the same code before merge — zig cc already bundles its own mingw-w64 sysroot and doesn't need (or accept) the external-MinGW target flags this PR was applying to it too. Rather than layer more fixup commits on top of a branch with that history, I squashed the corrected version into a clean single commit with an accurate description: #(new PR link follows).

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants