diff --git a/projects/llvm.org/mingw-w64/package.yml b/projects/llvm.org/mingw-w64/package.yml new file mode 100644 index 0000000000..7f59e14b6d --- /dev/null +++ b/projects/llvm.org/mingw-w64/package.yml @@ -0,0 +1,190 @@ +# 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. + +# 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 + +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). +# +# 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 + +build: + dependencies: + 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: + # 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 . + + # 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. + # 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 + +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: "*" + env: + 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: + # 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? + # 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 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 + fixture: | + #include + int main(void) { + printf("Hello from native Windows cross-compile.\n"); + return 0; + } + - $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 + # capture works without any od/tr/sed gymnastics (which had subtle + # BSD-vs-GNU output-format differences and broke on darwin). + - | + 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 + # 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. + - | + 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 + +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). 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)