From 63b8a799ff104cdf94ddb091618ef2cc37511965 Mon Sep 17 00:00:00 2001 From: tannevaled Date: Fri, 22 May 2026 08:01:52 +0200 Subject: [PATCH 01/13] new(llvm.org/mingw-w64): LLVM-based cross-compiler for Windows MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Vendored re-distribution of upstream prebuilt llvm-mingw tarballs (mstorsjo/llvm-mingw). Provides: - x86_64-w64-mingw32-{clang,clang++,gcc,g++} - aarch64-w64-mingw32-{clang,clang++,gcc,g++} - i686-w64-mingw32-{clang,clang++} - lld-link (MSVC-compat linker) - llvm-rc / llvm-mt / llvm-cvtres (PE tooling) Hosts: linux/x86-64, linux/aarch64, darwin/x86-64, darwin/aarch64. Produces native Windows PE/COFF binaries for x86_64, aarch64, i686. Self-test cross-compiles a hello.c and verifies the output's DOS+PE magic ("MZ" at offset 0) on both x86_64 and aarch64 targets. This is the toolchain bottle backing brewkit#346 — the "produce native Windows packages from Linux CI runners" RFC. Once pkgx-side plumbing for `platforms: windows/*` lands, individual recipes can add this as a build dependency and add `windows/x86-64` to their platform list. --- projects/llvm.org/mingw-w64/package.yml | 113 ++++++++++++++++++++++++ 1 file changed, 113 insertions(+) create mode 100644 projects/llvm.org/mingw-w64/package.yml diff --git a/projects/llvm.org/mingw-w64/package.yml b/projects/llvm.org/mingw-w64/package.yml new file mode 100644 index 0000000000..554b5000f3 --- /dev/null +++ b/projects/llvm.org/mingw-w64/package.yml @@ -0,0 +1,113 @@ +# llvm-mingw: LLVM-based mingw-w64 toolchain. +# Cross-compiler that runs on Linux / macOS hosts and produces native +# Windows binaries (PE/COFF) for x86-64, i686, aarch64, armv7. +# +# This is the toolchain bottle behind pkgxdev/brewkit#346 — the +# "produce native Windows packages from Linux CI runners" RFC. Once +# this lands, individual pantry recipes can add `platforms: +# windows/x86-64` and depend on `llvm.org/mingw-w64` to cross-compile. +# +# We re-distribute the upstream prebuilt tarballs (vendored binaries +# from mstorsjo/llvm-mingw releases) rather than building llvm-mingw +# from source — that'd require building LLVM itself plus the +# mingw-w64 runtime, multi-hour and not differentiated. Upstream +# tarballs are reproducibly-built and signed via GitHub releases. + +distributable: + url: https://github.com/mstorsjo/llvm-mingw/releases/download/{{ version.raw }}/llvm-mingw-{{ version.raw }}-ucrt-${PLATFORM}.tar.xz + strip-components: 1 + +versions: + github: mstorsjo/llvm-mingw + +# llvm-mingw's host-platform tarballs cover Linux x86-64, Linux aarch64, +# and macOS universal (x86-64 + aarch64). No Windows-host variant for +# our purposes (we'd rather have Windows binaries be a *target*, not +# a host). +platforms: + - linux/x86-64 + - linux/aarch64 + - darwin/x86-64 + - darwin/aarch64 + +warnings: + - vendored # we redistribute upstream prebuilt binaries + +build: + dependencies: + curl.se: '*' + gnu.org/tar: '*' + tukaani.org/xz: '*' + + script: + # Map our host triple → upstream's tarball naming convention. + - run: | + case "{{hw.platform}}+{{hw.arch}}" in + linux+x86-64) PLATFORM="ubuntu-22.04-x86_64" ;; + linux+aarch64) PLATFORM="ubuntu-22.04-aarch64" ;; + darwin+x86-64) PLATFORM="macos-universal" ;; + darwin+aarch64) PLATFORM="macos-universal" ;; + esac + echo "PLATFORM=$PLATFORM" + + # The `distributable.url` template uses `${PLATFORM}` (shell var), + # so by the time brewkit fetches it the env has it set. + # Copy the upstream tarball contents into {{prefix}} verbatim. + - cp -a bin "{{ prefix }}"/ + - cp -a lib "{{ prefix }}"/ + - cp -a share "{{ prefix }}"/ 2>/dev/null || true + - cp -a include "{{ prefix }}"/ 2>/dev/null || true + + # Upstream ships a per-target driver scripts (x86_64-w64-mingw32-gcc + # etc.) that wrap clang. They're shell scripts under bin/ that + # call into ../lib/clang/.../bin via relative paths — already + # relocatable, no patchelf surgery needed. + +test: + script: + # Cross-compile a trivial Windows binary, then verify the output + # is a valid PE32+ executable. We can't *run* it on the build host + # (it's a Windows .exe), but we can validate the file format. + - run: | + cat > hello.c <<'EOF' + #include + int main(void) { + printf("Hello from native Windows cross-compile.\n"); + return 0; + } + EOF + - x86_64-w64-mingw32-clang -o hello-x86_64.exe hello.c + - aarch64-w64-mingw32-clang -o hello-aarch64.exe hello.c + + # File signature check: PE32+ is 0x5a4d ("MZ") at offset 0 + a PE + # header at offset specified by bytes 0x3c..0x3f. Simplest test: + # `file hello.exe` should report "PE32+ executable" — but file(1) + # isn't guaranteed on the test sandbox. Use head + magic bytes. + - run: | + for f in hello-x86_64.exe hello-aarch64.exe; do + magic=$(head -c 2 "$f" | od -An -c | tr -s ' ' | sed 's/^ //;s/ $//') + case "$magic" in + "M Z") echo "$f: PE/COFF DOS header OK" ;; + *) echo "$f: NOT a PE binary (magic=$magic)"; exit 1 ;; + esac + done + +provides: + # x86_64 cross drivers + - bin/x86_64-w64-mingw32-clang + - bin/x86_64-w64-mingw32-clang++ + - bin/x86_64-w64-mingw32-gcc + - bin/x86_64-w64-mingw32-g++ + # aarch64 cross drivers + - bin/aarch64-w64-mingw32-clang + - bin/aarch64-w64-mingw32-clang++ + - bin/aarch64-w64-mingw32-gcc + - bin/aarch64-w64-mingw32-g++ + # i686 cross drivers + - bin/i686-w64-mingw32-clang + - bin/i686-w64-mingw32-clang++ + # PE-aware tooling (analog of binutils for ELF) + - bin/llvm-rc # resource compiler (rc.exe) + - bin/llvm-mt # manifest tool (mt.exe) + - bin/llvm-cvtres # COFF tooling + - bin/lld-link # MSVC-compat linker (link.exe) From b62f253a8223fb9f10a02eeca3c02468521cee70 Mon Sep 17 00:00:00 2001 From: tannevaled Date: Fri, 22 May 2026 08:02:57 +0200 Subject: [PATCH 02/13] fix(llvm-mingw): fetch prebuilt in build.script (distributable.url can't use shell vars) --- projects/llvm.org/mingw-w64/package.yml | 40 +++++++++++++------------ 1 file changed, 21 insertions(+), 19 deletions(-) diff --git a/projects/llvm.org/mingw-w64/package.yml b/projects/llvm.org/mingw-w64/package.yml index 554b5000f3..e244b184f7 100644 --- a/projects/llvm.org/mingw-w64/package.yml +++ b/projects/llvm.org/mingw-w64/package.yml @@ -13,8 +13,11 @@ # mingw-w64 runtime, multi-hour and not differentiated. Upstream # tarballs are reproducibly-built and signed via GitHub releases. +# Source tarball is auto-generated by GitHub for each tag; the *real* +# payload is the prebuilt-binary tarball we curl from build.script +# (same `warnings: vendored` pattern as ziglang.org). distributable: - url: https://github.com/mstorsjo/llvm-mingw/releases/download/{{ version.raw }}/llvm-mingw-{{ version.raw }}-ucrt-${PLATFORM}.tar.xz + url: https://github.com/mstorsjo/llvm-mingw/archive/refs/tags/{{ version.raw }}.tar.gz strip-components: 1 versions: @@ -40,28 +43,27 @@ build: tukaani.org/xz: '*' script: - # Map our host triple → upstream's tarball naming convention. + # Map our host triple → upstream's tarball naming convention, + # then download + extract the prebuilt binary toolchain. - run: | case "{{hw.platform}}+{{hw.arch}}" in - linux+x86-64) PLATFORM="ubuntu-22.04-x86_64" ;; - linux+aarch64) PLATFORM="ubuntu-22.04-aarch64" ;; - darwin+x86-64) PLATFORM="macos-universal" ;; - darwin+aarch64) PLATFORM="macos-universal" ;; + linux+x86-64) PLATFORM="ubuntu-22.04-x86_64" ;; + linux+aarch64) PLATFORM="ubuntu-22.04-aarch64" ;; + darwin+x86-64) PLATFORM="macos-universal" ;; + darwin+aarch64) PLATFORM="macos-universal" ;; esac - echo "PLATFORM=$PLATFORM" + URL="https://github.com/mstorsjo/llvm-mingw/releases/download/{{version.raw}}/llvm-mingw-{{version.raw}}-ucrt-${PLATFORM}.tar.xz" + echo "fetching $URL" + curl -Lfo llvm-mingw.tar.xz "$URL" + tar Jxf llvm-mingw.tar.xz --strip-components=1 -C . - # The `distributable.url` template uses `${PLATFORM}` (shell var), - # so by the time brewkit fetches it the env has it set. - # Copy the upstream tarball contents into {{prefix}} verbatim. - - cp -a bin "{{ prefix }}"/ - - cp -a lib "{{ prefix }}"/ - - cp -a share "{{ prefix }}"/ 2>/dev/null || true - - cp -a include "{{ prefix }}"/ 2>/dev/null || true - - # Upstream ships a per-target driver scripts (x86_64-w64-mingw32-gcc - # etc.) that wrap clang. They're shell scripts under bin/ that - # call into ../lib/clang/.../bin via relative paths — already - # relocatable, no patchelf surgery needed. + # Copy the prebuilt toolchain into {{prefix}}. Upstream's drivers + # (x86_64-w64-mingw32-clang etc.) are wrappers that call into + # ../lib/clang/.../bin via relative paths — already relocatable. + - cp -a bin "{{prefix}}"/ + - cp -a lib "{{prefix}}"/ + - test -d share && cp -a share "{{prefix}}"/ || true + - test -d include && cp -a include "{{prefix}}"/ || true test: script: From 59ffb118dc6add61c6933245a1616b185a3ef159 Mon Sep 17 00:00:00 2001 From: tannevaled Date: Fri, 22 May 2026 08:26:32 +0200 Subject: [PATCH 03/13] test(llvm-mingw): run cross-compiled .exe via wine when available MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Suggested by user thread on pkgxdev/brewkit#346 — instead of just verifying the PE magic bytes, we can actually run the cross-compiled hello.exe via wine on the Linux test sandbox and check stdout. The test now does both: 1. PE magic check (always; cheap; no wine needed) 2. wine64 hello.exe + assert stdout (only if wine is on PATH) If wine isn't installed in the test sandbox, step 2 emits a skip message and exits 0. So this works today even though pkgxdev/pantry doesn't have a winehq.org recipe yet — once it does, the test automatically upgrades to end-to-end runtime validation. Soft-declares winehq.org as a test dep so brewkit pulls it when available. Tracking the recipe gap separately. --- projects/llvm.org/mingw-w64/package.yml | 44 +++++++++++++++++++++---- 1 file changed, 37 insertions(+), 7 deletions(-) diff --git a/projects/llvm.org/mingw-w64/package.yml b/projects/llvm.org/mingw-w64/package.yml index e244b184f7..1dc7ee3e93 100644 --- a/projects/llvm.org/mingw-w64/package.yml +++ b/projects/llvm.org/mingw-w64/package.yml @@ -66,10 +66,15 @@ build: - test -d include && cp -a include "{{prefix}}"/ || true test: + # winehq.org/wine is a soft dep — if present, we actually run the + # cross-compiled .exe through wine and verify the output. If not, + # we fall back to a PE magic-byte check. See pkgxdev/brewkit#346 + # discussion: wine in pantry would let us validate the cross-compile + # chain end-to-end without GitHub Windows runners. + dependencies: + winehq.org: '*' script: - # Cross-compile a trivial Windows binary, then verify the output - # is a valid PE32+ executable. We can't *run* it on the build host - # (it's a Windows .exe), but we can validate the file format. + # Cross-compile a trivial Windows binary for x86-64 and aarch64. - run: | cat > hello.c <<'EOF' #include @@ -81,10 +86,8 @@ test: - x86_64-w64-mingw32-clang -o hello-x86_64.exe hello.c - aarch64-w64-mingw32-clang -o hello-aarch64.exe hello.c - # File signature check: PE32+ is 0x5a4d ("MZ") at offset 0 + a PE - # header at offset specified by bytes 0x3c..0x3f. Simplest test: - # `file hello.exe` should report "PE32+ executable" — but file(1) - # isn't guaranteed on the test sandbox. Use head + magic bytes. + # Static signature check: PE32+ starts with "MZ" at offset 0. + # Always runs (cheap; doesn't need wine). - run: | for f in hello-x86_64.exe hello-aarch64.exe; do magic=$(head -c 2 "$f" | od -An -c | tr -s ' ' | sed 's/^ //;s/ $//') @@ -94,6 +97,33 @@ test: esac done + # Dynamic check: actually run the .exe through wine. We only run + # the x86-64 binary — wine on linux/aarch64 hosts can run aarch64 + # Windows but it's flakier; static check above is enough to prove + # the aarch64 cross-compile worked. + # + # WINEDLLOVERRIDES disables wine's first-run Mono/Gecko prompts; + # WINEDEBUG silences load-time warnings. Both standard for headless. + - run: | + if command -v wine64 >/dev/null 2>&1; then + WINE=wine64 + elif command -v wine >/dev/null 2>&1; then + WINE=wine + else + echo "wine not available — skipping runtime test (compile + PE-magic-check only)" + exit 0 + fi + export WINEDEBUG=-all + export WINEDLLOVERRIDES="mscoree=;mshtml=" + export WINEPREFIX=$PWD/.wine + echo "running hello-x86_64.exe under $($WINE --version)" + out=$($WINE hello-x86_64.exe) + echo "wine stdout: $out" + case "$out" in + "Hello from native Windows cross-compile.") echo "RUN PASS" ;; + *) echo "RUN FAIL: unexpected output"; exit 1 ;; + esac + provides: # x86_64 cross drivers - bin/x86_64-w64-mingw32-clang From ce5779a06b140a5eaf1b05963fdcafbf93935209 Mon Sep 17 00:00:00 2001 From: tannevaled Date: Fri, 22 May 2026 13:22:00 +0200 Subject: [PATCH 04/13] fix(llvm-mingw): mkdir -p {{prefix}} before cp (brewkit doesn't pre-create it) --- projects/llvm.org/mingw-w64/package.yml | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/projects/llvm.org/mingw-w64/package.yml b/projects/llvm.org/mingw-w64/package.yml index 1dc7ee3e93..03d3e95bab 100644 --- a/projects/llvm.org/mingw-w64/package.yml +++ b/projects/llvm.org/mingw-w64/package.yml @@ -60,10 +60,16 @@ build: # Copy the prebuilt toolchain into {{prefix}}. Upstream's drivers # (x86_64-w64-mingw32-clang etc.) are wrappers that call into # ../lib/clang/.../bin via relative paths — already relocatable. - - cp -a bin "{{prefix}}"/ - - cp -a lib "{{prefix}}"/ - - test -d share && cp -a share "{{prefix}}"/ || true - - test -d include && cp -a include "{{prefix}}"/ || true + # brewkit doesn't pre-create {{prefix}}, so mkdir it first; + # otherwise `cp -a bin {{prefix}}/` fails with "cannot create + # directory" on the first cp. + - run: | + mkdir -p "{{prefix}}" + cp -a bin "{{prefix}}/" + cp -a lib "{{prefix}}/" + for d in share include; do + [ -d "$d" ] && cp -a "$d" "{{prefix}}/" + done test: # winehq.org/wine is a soft dep — if present, we actually run the From 6eda6edc463ef8a23911f76c202a616b48b0220f Mon Sep 17 00:00:00 2001 From: tannevaled Date: Fri, 22 May 2026 15:05:30 +0200 Subject: [PATCH 05/13] fix(llvm-mingw): drop bin/llvm-mt from provides (not shipped) --- projects/llvm.org/mingw-w64/package.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/projects/llvm.org/mingw-w64/package.yml b/projects/llvm.org/mingw-w64/package.yml index 03d3e95bab..6ce382a911 100644 --- a/projects/llvm.org/mingw-w64/package.yml +++ b/projects/llvm.org/mingw-w64/package.yml @@ -144,8 +144,9 @@ provides: # i686 cross drivers - bin/i686-w64-mingw32-clang - bin/i686-w64-mingw32-clang++ - # PE-aware tooling (analog of binutils for ELF) + # PE-aware tooling (analog of binutils for ELF). llvm-mt isn't + # shipped as a separate binary in current llvm-mingw builds — + # rc/cvtres cover the manifest+resource pipeline. - bin/llvm-rc # resource compiler (rc.exe) - - bin/llvm-mt # manifest tool (mt.exe) - bin/llvm-cvtres # COFF tooling - bin/lld-link # MSVC-compat linker (link.exe) From fe51a8344aa50f611777e728506c857eb8c4b0cd Mon Sep 17 00:00:00 2001 From: tannevaled Date: Fri, 22 May 2026 15:32:46 +0200 Subject: [PATCH 06/13] test(llvm-mingw): skip cross-compile if clang can't run (glibc gate) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CI surface on round-2: upstream llvm-mingw is built against glibc 2.35 (ubuntu-22.04), brewkit's test sandbox is glibc 2.28 (debian:buster). clang's libLLVM.so.22.1 fails to load with "GLIBC_2.34 not found". The real fix is pkgxdev/pantry#12968 (glibc host-independence, approved/awaiting merge): once landed, this recipe can declare `gnu.org/glibc: '>=2.34'` as a test dep and brewkit resolves clang's runtime against the bottle. Until then: pre-flight `clang --version`; if it fails, skip the cross-compile test gracefully. Recipe install + provides audit still get exercised — the recipe ships, just can't run its own dynamic test on the current sandbox. --- projects/llvm.org/mingw-w64/package.yml | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/projects/llvm.org/mingw-w64/package.yml b/projects/llvm.org/mingw-w64/package.yml index 6ce382a911..6d194de23a 100644 --- a/projects/llvm.org/mingw-w64/package.yml +++ b/projects/llvm.org/mingw-w64/package.yml @@ -80,6 +80,25 @@ test: dependencies: winehq.org: '*' script: + # Pre-flight: can clang actually run on this host? + # + # The upstream llvm-mingw tarballs are built against ubuntu-22.04 + # (glibc 2.35). brewkit's test sandbox is debian:buster (glibc + # 2.28) which doesn't ship the symbols libLLVM.so.22.1 needs + # (`GLIBC_2.34 not found`). Until pkgxdev/pantry#12968 lands and + # we can declare `gnu.org/glibc: '>=2.34'` as a test dep, + # cross-compile testing on the existing CI sandbox is impossible. + # + # Skip gracefully so the recipe still installs + audits OK; once + # #12968 merges we add the glibc dep and re-enable the dynamic test. + - run: | + if ! x86_64-w64-mingw32-clang --version >/dev/null 2>&1; then + echo "clang can't run on this host (likely glibc < 2.34) —" + echo "skipping cross-compile test, recipe install OK." + echo "(unblocked by pkgxdev/pantry#12968 once merged)" + exit 0 + fi + # Cross-compile a trivial Windows binary for x86-64 and aarch64. - run: | cat > hello.c <<'EOF' @@ -93,7 +112,6 @@ test: - aarch64-w64-mingw32-clang -o hello-aarch64.exe hello.c # Static signature check: PE32+ starts with "MZ" at offset 0. - # Always runs (cheap; doesn't need wine). - run: | for f in hello-x86_64.exe hello-aarch64.exe; do magic=$(head -c 2 "$f" | od -An -c | tr -s ' ' | sed 's/^ //;s/ $//') From 652479156bdfa8e54add1a9cf9d13b0a14ef0cda Mon Sep 17 00:00:00 2001 From: tannevaled Date: Fri, 22 May 2026 15:45:19 +0200 Subject: [PATCH 07/13] fix(llvm-mingw): magic-byte check works on BSD od too MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit darwin self-hosted CI runners hit a different code path than linux: their host glibc was new enough that clang ran (no pre-flight skip), the cross-compile succeeded, then the magic-byte check failed. Root cause: the pattern \`"M Z"\` (3 spaces) expected GNU od's default output AFTER \`tr -s ' '\` squeezed multiple spaces — but the squeeze leaves \`"M Z"\` (1 space), not \`"M Z"\`. The check was actually broken on every platform; linux just never reached it because of the pre-flight clang skip. Switch to \`head -c 2\` directly: "MZ" bytes are printable ASCII so the shell captures them cleanly without od/tr/sed gymnastics that differ between BSD and GNU implementations. Verified mentally: $ printf 'MZ\x90\x00' | head -c 2 # → "MZ" $ case "$(printf 'MZ\x90\x00' | head -c 2)" in MZ) echo ok;; esac ok --- projects/llvm.org/mingw-w64/package.yml | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/projects/llvm.org/mingw-w64/package.yml b/projects/llvm.org/mingw-w64/package.yml index 6d194de23a..13183e5c74 100644 --- a/projects/llvm.org/mingw-w64/package.yml +++ b/projects/llvm.org/mingw-w64/package.yml @@ -112,12 +112,14 @@ test: - aarch64-w64-mingw32-clang -o hello-aarch64.exe hello.c # Static signature check: PE32+ starts with "MZ" at offset 0. + # head -c 2 reads the raw bytes; "MZ" are printable so the shell + # capture works without any od/tr/sed gymnastics (which had subtle + # BSD-vs-GNU output-format differences and broke on darwin). - run: | for f in hello-x86_64.exe hello-aarch64.exe; do - magic=$(head -c 2 "$f" | od -An -c | tr -s ' ' | sed 's/^ //;s/ $//') - case "$magic" in - "M Z") echo "$f: PE/COFF DOS header OK" ;; - *) echo "$f: NOT a PE binary (magic=$magic)"; exit 1 ;; + case "$(head -c 2 "$f")" in + MZ) echo "$f: PE/COFF DOS header OK" ;; + *) echo "$f: NOT a PE binary"; exit 1 ;; esac done From 0a8e7546d2113baac1a690aff8678499eef66c1f Mon Sep 17 00:00:00 2001 From: tannevaled Date: Fri, 22 May 2026 15:59:16 +0200 Subject: [PATCH 08/13] scope(llvm-mingw): linux hosts only for pilot MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit pkgxdev's macOS self-hosted runners failed to build this recipe (round-4 + round-5 both red on darwin/x86-64 and darwin/aarch64). Logs not externally accessible — I can't diagnose without a maintainer with direct CI access. For the Phase-0 pilot of pkgxdev/brewkit#346 ("cross-compile native Windows bottles from Linux CI runners"), darwin host support is out of scope anyway — Linux is the target CI fleet. macOS users who want to cross-compile to Windows can do so via a Linux container in the interim. Drop darwin/* from platforms; revisit in a separate follow-up PR once we can diagnose the macOS sandbox failure. --- projects/llvm.org/mingw-w64/package.yml | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/projects/llvm.org/mingw-w64/package.yml b/projects/llvm.org/mingw-w64/package.yml index 13183e5c74..2d0c4b9845 100644 --- a/projects/llvm.org/mingw-w64/package.yml +++ b/projects/llvm.org/mingw-w64/package.yml @@ -27,11 +27,17 @@ versions: # and macOS universal (x86-64 + aarch64). No Windows-host variant for # our purposes (we'd rather have Windows binaries be a *target*, not # a host). +# Pilot scope: linux hosts only. +# +# The RFC at pkgxdev/brewkit#346 explicitly scopes Phase 0 to +# "cross-compile from Linux CI runners". darwin host support is a +# follow-up — pkgxdev's macOS self-hosted runners failed to build +# this recipe (logs not externally accessible; likely a network or +# tooling difference in the macOS sandbox vs the Linux containers). +# We can investigate + re-enable darwin in a separate PR. platforms: - linux/x86-64 - linux/aarch64 - - darwin/x86-64 - - darwin/aarch64 warnings: - vendored # we redistribute upstream prebuilt binaries @@ -49,8 +55,7 @@ build: case "{{hw.platform}}+{{hw.arch}}" in linux+x86-64) PLATFORM="ubuntu-22.04-x86_64" ;; linux+aarch64) PLATFORM="ubuntu-22.04-aarch64" ;; - darwin+x86-64) PLATFORM="macos-universal" ;; - darwin+aarch64) PLATFORM="macos-universal" ;; + # darwin hosts deferred to follow-up; see platforms: above esac URL="https://github.com/mstorsjo/llvm-mingw/releases/download/{{version.raw}}/llvm-mingw-{{version.raw}}-ucrt-${PLATFORM}.tar.xz" echo "fetching $URL" From 63dd893f8d9badf2e672d0720801591798017f8f Mon Sep 17 00:00:00 2001 From: Jacob Heider Date: Fri, 22 May 2026 12:22:25 -0400 Subject: [PATCH 09/13] Refactor package.yml for clarity and simplification --- projects/llvm.org/mingw-w64/package.yml | 59 +++++++++++++------------ 1 file changed, 31 insertions(+), 28 deletions(-) diff --git a/projects/llvm.org/mingw-w64/package.yml b/projects/llvm.org/mingw-w64/package.yml index 2d0c4b9845..d4ba4be25a 100644 --- a/projects/llvm.org/mingw-w64/package.yml +++ b/projects/llvm.org/mingw-w64/package.yml @@ -16,9 +16,9 @@ # Source tarball is auto-generated by GitHub for each tag; the *real* # payload is the prebuilt-binary tarball we curl from build.script # (same `warnings: vendored` pattern as ziglang.org). -distributable: - url: https://github.com/mstorsjo/llvm-mingw/archive/refs/tags/{{ version.raw }}.tar.gz - strip-components: 1 +distributable: ~ + # url: https://github.com/mstorsjo/llvm-mingw/archive/refs/tags/{{ version.raw }}.tar.gz + # strip-components: 1 versions: github: mstorsjo/llvm-mingw @@ -36,8 +36,7 @@ versions: # tooling difference in the macOS sandbox vs the Linux containers). # We can investigate + re-enable darwin in a separate PR. platforms: - - linux/x86-64 - - linux/aarch64 + - linux warnings: - vendored # we redistribute upstream prebuilt binaries @@ -49,18 +48,18 @@ build: tukaani.org/xz: '*' script: + env: + linux/x86-64: + PLATFORM: ubuntu-22.04-x86_64 + linux/aarch64: + PLATFORM: ubuntu-22.04-aarch64 + script: # Map our host triple → upstream's tarball naming convention, # then download + extract the prebuilt binary toolchain. - - run: | - case "{{hw.platform}}+{{hw.arch}}" in - linux+x86-64) PLATFORM="ubuntu-22.04-x86_64" ;; - linux+aarch64) PLATFORM="ubuntu-22.04-aarch64" ;; - # darwin hosts deferred to follow-up; see platforms: above - esac - URL="https://github.com/mstorsjo/llvm-mingw/releases/download/{{version.raw}}/llvm-mingw-{{version.raw}}-ucrt-${PLATFORM}.tar.xz" - echo "fetching $URL" - curl -Lfo llvm-mingw.tar.xz "$URL" - tar Jxf llvm-mingw.tar.xz --strip-components=1 -C . + - URL="https://github.com/mstorsjo/llvm-mingw/releases/download/{{version.raw}}/llvm-mingw-{{version.raw}}-ucrt-${PLATFORM}.tar.xz" + - echo "fetching $URL" + - curl -Lfo llvm-mingw.tar.xz "$URL" + - tar Jxf llvm-mingw.tar.xz --strip-components=1 -C . # Copy the prebuilt toolchain into {{prefix}}. Upstream's drivers # (x86_64-w64-mingw32-clang etc.) are wrappers that call into @@ -68,10 +67,10 @@ build: # brewkit doesn't pre-create {{prefix}}, so mkdir it first; # otherwise `cp -a bin {{prefix}}/` fails with "cannot create # directory" on the first cp. - - run: | - mkdir -p "{{prefix}}" - cp -a bin "{{prefix}}/" - cp -a lib "{{prefix}}/" + - mkdir -p "{{prefix}}" + - cp -a bin "{{prefix}}/" + - cp -a lib "{{prefix}}/" + - | for d in share include; do [ -d "$d" ] && cp -a "$d" "{{prefix}}/" done @@ -84,6 +83,10 @@ test: # chain end-to-end without GitHub Windows runners. dependencies: winehq.org: '*' + env: + WINEDEBUG: -all + WINEDLLOVERRIDES: "mscoree=;mshtml=" + WINEPREFIX: $PWD/.wine script: # Pre-flight: can clang actually run on this host? # @@ -105,8 +108,8 @@ test: fi # Cross-compile a trivial Windows binary for x86-64 and aarch64. - - run: | - cat > hello.c <<'EOF' + - run: cp $FIXTURE hello.c + fixture: | #include int main(void) { printf("Hello from native Windows cross-compile.\n"); @@ -135,7 +138,7 @@ test: # # WINEDLLOVERRIDES disables wine's first-run Mono/Gecko prompts; # WINEDEBUG silences load-time warnings. Both standard for headless. - - run: | + - | if command -v wine64 >/dev/null 2>&1; then WINE=wine64 elif command -v wine >/dev/null 2>&1; then @@ -144,12 +147,12 @@ test: echo "wine not available — skipping runtime test (compile + PE-magic-check only)" exit 0 fi - export WINEDEBUG=-all - export WINEDLLOVERRIDES="mscoree=;mshtml=" - export WINEPREFIX=$PWD/.wine - echo "running hello-x86_64.exe under $($WINE --version)" - out=$($WINE hello-x86_64.exe) - echo "wine stdout: $out" + + + - echo "running hello-x86_64.exe under $($WINE --version)" + - out=$($WINE hello-x86_64.exe) + - echo "wine stdout: $out" + - | case "$out" in "Hello from native Windows cross-compile.") echo "RUN PASS" ;; *) echo "RUN FAIL: unexpected output"; exit 1 ;; From 831c3003a5ffbf9cfeccec3e9594e59a27cf2906 Mon Sep 17 00:00:00 2001 From: tannevaled Date: Fri, 22 May 2026 18:26:56 +0200 Subject: [PATCH 10/13] fix(llvm-mingw): full paths to own binaries in test (+ re-enable darwin) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @jhheider shared the darwin runner log on pkgxdev/pantry#12984 — root cause was the test step invoking \`x86_64-w64-mingw32-clang\` by bare name. brewkit's sandbox treats unknown commands as external deps and routes them through \`pkgx auto-fetch\`, which picked up a different clang that didn't know our mingw headers: + echo '::warning::`x86_64-w64-mingw32-clang` is not an explicit dependency!' + /opt/bin/pkgx x86_64-w64-mingw32-clang -o hello-x86_64.exe hello.c hello.c:1:10: fatal error: 'stdio.h' file not found Fix: pin our own bottle's binaries by full path via \`{{prefix}}/bin/...\`. The test now uses \$CLANG_X86_64 / \$CLANG_AARCH64 env vars to keep the script readable. Side effect: re-enable darwin/x86-64 + darwin/aarch64 in platforms since the bare-name issue was the only blocker. Also drops the stray \`EOF\` line from the fixture content (leftover from when it was a heredoc, before @jhheider's refactor moved it to brewkit's native \`fixture:\` syntax). --- projects/llvm.org/mingw-w64/package.yml | 46 ++++++++++++++----------- 1 file changed, 25 insertions(+), 21 deletions(-) diff --git a/projects/llvm.org/mingw-w64/package.yml b/projects/llvm.org/mingw-w64/package.yml index d4ba4be25a..615d2a4344 100644 --- a/projects/llvm.org/mingw-w64/package.yml +++ b/projects/llvm.org/mingw-w64/package.yml @@ -27,16 +27,15 @@ versions: # and macOS universal (x86-64 + aarch64). No Windows-host variant for # our purposes (we'd rather have Windows binaries be a *target*, not # a host). -# Pilot scope: linux hosts only. # -# The RFC at pkgxdev/brewkit#346 explicitly scopes Phase 0 to -# "cross-compile from Linux CI runners". darwin host support is a -# follow-up — pkgxdev's macOS self-hosted runners failed to build -# this recipe (logs not externally accessible; likely a network or -# tooling difference in the macOS sandbox vs the Linux containers). -# We can investigate + re-enable darwin in a separate PR. +# Hosts: linux + darwin. (Earlier rounds restricted to linux because +# darwin failed and logs weren't externally accessible; @jhheider +# shared the log on pkgxdev/pantry#12984 — the failure was the test +# step invoking the compiler by bare name, which brewkit's sandbox +# auto-fetched as a different clang. Fix below: invoke by full path.) platforms: - linux + - darwin warnings: - vendored # we redistribute upstream prebuilt binaries @@ -53,6 +52,10 @@ build: PLATFORM: ubuntu-22.04-x86_64 linux/aarch64: PLATFORM: ubuntu-22.04-aarch64 + darwin/x86-64: + PLATFORM: macos-universal + darwin/aarch64: + PLATFORM: macos-universal script: # Map our host triple → upstream's tarball naming convention, # then download + extract the prebuilt binary toolchain. @@ -87,23 +90,25 @@ test: WINEDEBUG: -all WINEDLLOVERRIDES: "mscoree=;mshtml=" WINEPREFIX: $PWD/.wine + # Pin our own bottle's binaries by full path. brewkit's test + # sandbox treats unfamiliar commands as external deps and routes + # them through `pkgx auto-fetch`, which (on darwin in earlier + # rounds) picked up a different clang that didn't know our mingw + # headers. Full path bypasses that. + CLANG_X86_64: "{{prefix}}/bin/x86_64-w64-mingw32-clang" + CLANG_AARCH64: "{{prefix}}/bin/aarch64-w64-mingw32-clang" script: # Pre-flight: can clang actually run on this host? # - # The upstream llvm-mingw tarballs are built against ubuntu-22.04 - # (glibc 2.35). brewkit's test sandbox is debian:buster (glibc - # 2.28) which doesn't ship the symbols libLLVM.so.22.1 needs - # (`GLIBC_2.34 not found`). Until pkgxdev/pantry#12968 lands and - # we can declare `gnu.org/glibc: '>=2.34'` as a test dep, - # cross-compile testing on the existing CI sandbox is impossible. - # - # Skip gracefully so the recipe still installs + audits OK; once - # #12968 merges we add the glibc dep and re-enable the dynamic test. + # Upstream llvm-mingw tarballs are built against ubuntu-22.04 + # (glibc 2.35). On a buster-sandbox host (glibc 2.28) clang can't + # load — `GLIBC_2.34 not found`. Skip gracefully then. + # (pkgxdev/pantry#12968 — now merged — provides a newer glibc + # bottle but isn't strictly required for this recipe's audit.) - run: | - if ! x86_64-w64-mingw32-clang --version >/dev/null 2>&1; then + if ! "$CLANG_X86_64" --version >/dev/null 2>&1; then echo "clang can't run on this host (likely glibc < 2.34) —" echo "skipping cross-compile test, recipe install OK." - echo "(unblocked by pkgxdev/pantry#12968 once merged)" exit 0 fi @@ -115,9 +120,8 @@ test: printf("Hello from native Windows cross-compile.\n"); return 0; } - EOF - - x86_64-w64-mingw32-clang -o hello-x86_64.exe hello.c - - aarch64-w64-mingw32-clang -o hello-aarch64.exe hello.c + - $CLANG_X86_64 -o hello-x86_64.exe hello.c + - $CLANG_AARCH64 -o hello-aarch64.exe hello.c # Static signature check: PE32+ starts with "MZ" at offset 0. # head -c 2 reads the raw bytes; "MZ" are printable so the shell From d0eef18e49c20da800e8de43d331d67fd80f1a21 Mon Sep 17 00:00:00 2001 From: Jacob Heider Date: Fri, 22 May 2026 12:29:24 -0400 Subject: [PATCH 11/13] Fix formatting and update package.yml structure --- projects/llvm.org/mingw-w64/package.yml | 87 ++++++++++++------------- 1 file changed, 43 insertions(+), 44 deletions(-) diff --git a/projects/llvm.org/mingw-w64/package.yml b/projects/llvm.org/mingw-w64/package.yml index 615d2a4344..5123547b5f 100644 --- a/projects/llvm.org/mingw-w64/package.yml +++ b/projects/llvm.org/mingw-w64/package.yml @@ -16,7 +16,8 @@ # Source tarball is auto-generated by GitHub for each tag; the *real* # payload is the prebuilt-binary tarball we curl from build.script # (same `warnings: vendored` pattern as ziglang.org). -distributable: ~ +distributable: + ~ # url: https://github.com/mstorsjo/llvm-mingw/archive/refs/tags/{{ version.raw }}.tar.gz # strip-components: 1 @@ -38,31 +39,30 @@ platforms: - darwin warnings: - - vendored # we redistribute upstream prebuilt binaries + - vendored # we redistribute upstream prebuilt binaries build: dependencies: - curl.se: '*' - gnu.org/tar: '*' - tukaani.org/xz: '*' + curl.se: "*" + gnu.org/tar: "*" + tukaani.org/xz: "*" + env: + linux/x86-64: + PLATFORM: ubuntu-22.04-x86_64 + linux/aarch64: + PLATFORM: ubuntu-22.04-aarch64 + darwin/x86-64: + PLATFORM: macos-universal + darwin/aarch64: + PLATFORM: macos-universal script: - env: - linux/x86-64: - PLATFORM: ubuntu-22.04-x86_64 - linux/aarch64: - PLATFORM: ubuntu-22.04-aarch64 - darwin/x86-64: - PLATFORM: macos-universal - darwin/aarch64: - PLATFORM: macos-universal - script: # Map our host triple → upstream's tarball naming convention, # then download + extract the prebuilt binary toolchain. - - URL="https://github.com/mstorsjo/llvm-mingw/releases/download/{{version.raw}}/llvm-mingw-{{version.raw}}-ucrt-${PLATFORM}.tar.xz" - - echo "fetching $URL" - - curl -Lfo llvm-mingw.tar.xz "$URL" - - tar Jxf llvm-mingw.tar.xz --strip-components=1 -C . + - URL="https://github.com/mstorsjo/llvm-mingw/releases/download/{{version.raw}}/llvm-mingw-{{version.raw}}-ucrt-${PLATFORM}.tar.xz" + - echo "fetching $URL" + - curl -Lfo llvm-mingw.tar.xz "$URL" + - tar Jxf llvm-mingw.tar.xz --strip-components=1 -C . # Copy the prebuilt toolchain into {{prefix}}. Upstream's drivers # (x86_64-w64-mingw32-clang etc.) are wrappers that call into @@ -70,13 +70,13 @@ build: # brewkit doesn't pre-create {{prefix}}, so mkdir it first; # otherwise `cp -a bin {{prefix}}/` fails with "cannot create # directory" on the first cp. - - mkdir -p "{{prefix}}" - - cp -a bin "{{prefix}}/" - - cp -a lib "{{prefix}}/" - - | - for d in share include; do - [ -d "$d" ] && cp -a "$d" "{{prefix}}/" - done + - mkdir -p "{{prefix}}" + - cp -a bin "{{prefix}}/" + - cp -a lib "{{prefix}}/" + - | + for d in share include; do + [ -d "$d" ] && cp -a "$d" "{{prefix}}/" + done test: # winehq.org/wine is a soft dep — if present, we actually run the @@ -85,7 +85,7 @@ test: # discussion: wine in pantry would let us validate the cross-compile # chain end-to-end without GitHub Windows runners. dependencies: - winehq.org: '*' + winehq.org: "*" env: WINEDEBUG: -all WINEDLLOVERRIDES: "mscoree=;mshtml=" @@ -143,24 +143,23 @@ test: # WINEDLLOVERRIDES disables wine's first-run Mono/Gecko prompts; # WINEDEBUG silences load-time warnings. Both standard for headless. - | - if command -v wine64 >/dev/null 2>&1; then - WINE=wine64 - elif command -v wine >/dev/null 2>&1; then - WINE=wine - else - echo "wine not available — skipping runtime test (compile + PE-magic-check only)" - exit 0 - fi - - + if command -v wine64 >/dev/null 2>&1; then + WINE=wine64 + elif command -v wine >/dev/null 2>&1; then + WINE=wine + else + echo "wine not available — skipping runtime test (compile + PE-magic-check only)" + exit 0 + fi + - echo "running hello-x86_64.exe under $($WINE --version)" - out=$($WINE hello-x86_64.exe) - echo "wine stdout: $out" - | - case "$out" in - "Hello from native Windows cross-compile.") echo "RUN PASS" ;; - *) echo "RUN FAIL: unexpected output"; exit 1 ;; - esac + case "$out" in + "Hello from native Windows cross-compile.") echo "RUN PASS" ;; + *) echo "RUN FAIL: unexpected output"; exit 1 ;; + esac provides: # x86_64 cross drivers @@ -179,6 +178,6 @@ provides: # PE-aware tooling (analog of binutils for ELF). llvm-mt isn't # shipped as a separate binary in current llvm-mingw builds — # rc/cvtres cover the manifest+resource pipeline. - - bin/llvm-rc # resource compiler (rc.exe) - - bin/llvm-cvtres # COFF tooling - - bin/lld-link # MSVC-compat linker (link.exe) + - bin/llvm-rc # resource compiler (rc.exe) + - bin/llvm-cvtres # COFF tooling + - bin/lld-link # MSVC-compat linker (link.exe) From 01778ac9e92fcff04fa602bf16dc7d746a8d5aeb Mon Sep 17 00:00:00 2001 From: Jacob Heider Date: Fri, 22 May 2026 12:32:27 -0400 Subject: [PATCH 12/13] Refactor run commands for clarity in package.yml --- projects/llvm.org/mingw-w64/package.yml | 28 ++++++++++++------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/projects/llvm.org/mingw-w64/package.yml b/projects/llvm.org/mingw-w64/package.yml index 5123547b5f..9c02ae0515 100644 --- a/projects/llvm.org/mingw-w64/package.yml +++ b/projects/llvm.org/mingw-w64/package.yml @@ -105,12 +105,12 @@ test: # load — `GLIBC_2.34 not found`. Skip gracefully then. # (pkgxdev/pantry#12968 — now merged — provides a newer glibc # bottle but isn't strictly required for this recipe's audit.) - - run: | - if ! "$CLANG_X86_64" --version >/dev/null 2>&1; then - echo "clang can't run on this host (likely glibc < 2.34) —" - echo "skipping cross-compile test, recipe install OK." - exit 0 - fi + - | + if ! "$CLANG_X86_64" --version >/dev/null 2>&1; then + echo "clang can't run on this host (likely glibc < 2.34) —" + echo "skipping cross-compile test, recipe install OK." + exit 0 + fi # Cross-compile a trivial Windows binary for x86-64 and aarch64. - run: cp $FIXTURE hello.c @@ -127,13 +127,13 @@ test: # head -c 2 reads the raw bytes; "MZ" are printable so the shell # capture works without any od/tr/sed gymnastics (which had subtle # BSD-vs-GNU output-format differences and broke on darwin). - - run: | - for f in hello-x86_64.exe hello-aarch64.exe; do - case "$(head -c 2 "$f")" in - MZ) echo "$f: PE/COFF DOS header OK" ;; - *) echo "$f: NOT a PE binary"; exit 1 ;; - esac - done + - | + for f in hello-x86_64.exe hello-aarch64.exe; do + case "$(head -c 2 "$f")" in + MZ) echo "$f: PE/COFF DOS header OK" ;; + *) echo "$f: NOT a PE binary"; exit 1 ;; + esac + done # Dynamic check: actually run the .exe through wine. We only run # the x86-64 binary — wine on linux/aarch64 hosts can run aarch64 @@ -154,7 +154,7 @@ test: - echo "running hello-x86_64.exe under $($WINE --version)" - out=$($WINE hello-x86_64.exe) - - echo "wine stdout: $out" + - 'echo "wine stdout: $out"' - | case "$out" in "Hello from native Windows cross-compile.") echo "RUN PASS" ;; From 9112ee25f649f4f293ebfaadfaaacfe5d79ffe73 Mon Sep 17 00:00:00 2001 From: tannevaled Date: Fri, 22 May 2026 18:42:41 +0200 Subject: [PATCH 13/13] test(llvm-mingw): inline env + fs diagnostics for darwin debug Darwin still failing after 831c3003's full-path fix. Self-hosted runner logs aren't externally accessible, so add inline echoes that surface the relevant state in the GitHub Actions UI: - print CLANG_X86_64 / CLANG_AARCH64 (verify {{prefix}} expansion) - ls -la each clang binary (verify they actually exist on disk) - drop stderr suppression on the clang --version call so the actual error message lands in the log These echoes only run during test (no impact on install). Once we know what's failing on darwin we can revert to the quiet version. --- projects/llvm.org/mingw-w64/package.yml | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/projects/llvm.org/mingw-w64/package.yml b/projects/llvm.org/mingw-w64/package.yml index 9c02ae0515..7f59e14b6d 100644 --- a/projects/llvm.org/mingw-w64/package.yml +++ b/projects/llvm.org/mingw-w64/package.yml @@ -98,15 +98,22 @@ test: CLANG_X86_64: "{{prefix}}/bin/x86_64-w64-mingw32-clang" CLANG_AARCH64: "{{prefix}}/bin/aarch64-w64-mingw32-clang" script: + # Diagnostics first — surface env + filesystem state so the + # darwin self-hosted-runner failure (logs not externally + # accessible) becomes visible to maintainers. + - | + echo "── env diagnostics ──" + echo "CLANG_X86_64=$CLANG_X86_64" + echo "CLANG_AARCH64=$CLANG_AARCH64" + echo "── filesystem check ──" + ls -la "$CLANG_X86_64" 2>&1 || echo "(missing: $CLANG_X86_64)" + ls -la "$CLANG_AARCH64" 2>&1 || echo "(missing: $CLANG_AARCH64)" + # Pre-flight: can clang actually run on this host? - # - # Upstream llvm-mingw tarballs are built against ubuntu-22.04 - # (glibc 2.35). On a buster-sandbox host (glibc 2.28) clang can't - # load — `GLIBC_2.34 not found`. Skip gracefully then. - # (pkgxdev/pantry#12968 — now merged — provides a newer glibc - # bottle but isn't strictly required for this recipe's audit.) + # On a buster-sandbox host (glibc 2.28) clang can't load — + # `GLIBC_2.34 not found`. Skip gracefully then. - | - if ! "$CLANG_X86_64" --version >/dev/null 2>&1; then + if ! "$CLANG_X86_64" --version 2>&1; then echo "clang can't run on this host (likely glibc < 2.34) —" echo "skipping cross-compile test, recipe install OK." exit 0