Skip to content

fix(backend): use the zig toolchain for vendored prerequisites and zlib on host-native zigcc builds - #253

Open
euxaristia wants to merge 1 commit into
vercel-labs:mainfrom
euxaristia:fix/host-native-zigcc-vendor-toolchain
Open

fix(backend): use the zig toolchain for vendored prerequisites and zlib on host-native zigcc builds#253
euxaristia wants to merge 1 commit into
vercel-labs:mainfrom
euxaristia:fix/host-native-zigcc-vendor-toolchain

Conversation

@euxaristia

Copy link
Copy Markdown

Summary

Refs #252

The vendored-prerequisite recipes and the zlib link keyed their toolchain choices on driver.target === null — "is this a host build?" — which conflates the build being native with a POSIX toolchain and system libraries being present. Those are independent properties.

Under SCRIPTC_CC=zigcc with no SCRIPTC_TARGET, the quickjs and mbedTLS archives were therefore built with a system clang and packed with a system ar, and the link took a system -lz while the vendored zlib headers and objects were skipped — even though the program TU, the lre/zlib objects, and the final link all used zig cc.

On Linux/macOS that silently mixes toolchains but usually links, which is why CI stays green. On Windows it fails outright, in three stages: ENOENT on ar, then unable to find dynamic system library 'z', then scr_fetch.c:95: 'zlib.h' file not found. SCRIPTC_TARGET=<host triple> already avoids all of it, because every one of these sites is correct on the cross path.

ensureLreObjects and ensureZlibObjects already solve this correctly, under the comment "a zig-cc-built object set must never be handed to a clang link (or vice versa)". This makes the remaining sites agree with that rule.

Changes

Three helpers in vendor-archives.ts, which is the leaf module here (native-toolchain.ts already imports runtime values from it, and it takes CcDriver as a type only, so there is no cycle):

  • driverUsesZig(driver)driver.argv[0] === "zig"
  • vendorArArgv(driver)zig ar for a zig driver, else ar
  • usesVendoredZlib(driver) — every cross build, and every zig-driven host build

Applied at the sites that were keyed on driver.target:

  • buildEngineArchiveDirect (quickjs) and ensureTlsArchive (mbedTLS) now compile with driver.argv and archive with vendorArArgv(driver).
  • currentVendorCacheBuildIdentity only adds clang/ar to the identity for a bare-clang host build, so a zig host build no longer records tools it does not use.
  • The six zlib gates in native-toolchain.ts use usesVendoredZlib(driver). Because the -I vendorZlibDir() spread is already keyed on zlibObjects.length > 0, the header path follows from the gate change.

No cache-key change is needed: currentVendorCacheBuildIdentity starts its command list with driver.argv[0], so clang-driven and zig-driven builds already resolve to different buildIdentity values and never share an archive.

Behavior for the bare-clang host driver and for every cross build is unchanged.

Test plan

New co-located vendor-archives.test.ts (5 tests), driven off real resolveCc output rather than hand-built driver objects:

  • bare clang host driver still selects a system ar and a system -lz
  • host-native zigcc archives with zig ar
  • host-native zigcc links the vendored zlib
  • cross builds keep the zig toolchain and vendored zlib
  • the archiver spelling derives from argv[0] rather than a literal

Reverting the helper bodies to the previous driver.target semantics fails the two host-zig tests while the bare-clang control still passes, so these pin the corrected behavior rather than merely restating it.

Also run: tsc --noEmit clean; eslint 0 errors with no new warnings (the pre-existing 40 no-non-null-assertion warnings in native-toolchain.ts are unchanged).

Not run: the full test:sandbox gate, which needs Vercel credentials. Worth a maintainer running both lanes before merge.

End-to-end, an out-of-tree project that previously failed on Windows builds, links, and runs under plain SCRIPTC_CC=zigcc with this change and no PATH shims, with results identical to the SCRIPTC_TARGET=x86_64-windows-gnu path.

…target

The vendored quickjs and mbedTLS recipes and the zlib link keyed their
toolchain choices on `driver.target === null`, which conflates a build
being host-native with a POSIX toolchain and system libraries being
present. Those are independent: under SCRIPTC_CC=zigcc a host build
handed a clang-built vendor archive to a zig link, and on Windows it
could not work at all, since there is no system `ar` and no system libz.

Dispatch on the driver instead, matching the rule ensureLreObjects and
ensureZlibObjects already follow. Behavior for the bare-clang host
driver and for every cross build is unchanged.

Refs vercel-labs#252
@vercel

vercel Bot commented Aug 28, 2026

Copy link
Copy Markdown
Contributor

@euxaristia is attempting to deploy a commit to the Vercel Labs Team on Vercel.

A member of the Team first needs to authorize it.

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.

1 participant