Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
231 changes: 89 additions & 142 deletions projects/llvm.org/mingw-w64/package.yml
Original file line number Diff line number Diff line change
@@ -1,181 +1,128 @@
# 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.
# llvm.org/mingw-w64 — from-source LLVM mingw-w64 cross-compiler toolchain.
#
# 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.
# Builds the COMPLETE llvm-mingw toolchain from source via upstream
# mstorsjo/llvm-mingw's own build orchestration (`build-all.sh`):
# - clang + lld + the LLVM binutils-equivalents
# - the mingw-w64 runtime (headers + CRT + winpthreads)
# - the LLVM runtimes for the Windows targets: compiler-rt builtins,
# libunwind, libc++abi, libc++
# - the per-target driver wrappers (install-wrappers.sh)
# No vendored binaries — everything is compiled here.
#
# 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.
# Why inline (clang and all) rather than composing pantry's llvm.org: the
# Windows-target runtimes must match the exact clang that builds them, and
# pkgx dependency constraints can't "drift" to track that. Building the whole
# toolchain from one source tree makes it internally consistent by
# construction, and versioning to mstorsjo's releases (which pin the matching
# llvm-project) means there's no LLVM-version dance to get wrong.
#
# Compiled on the builder at pkgx's glibc floor, so the host-side driver
# binaries run on old hosts with NO bklibcvenv seal. (Replaces the previous
# approach of vendoring mstorsjo's prebuilt tarball; pantry policy is
# from-source over vendored.)
#
# NOTE: this is a full LLVM build — long, by design. "Build time isn't the
# end of the world to get it right."

# 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
url: https://github.com/mstorsjo/llvm-mingw/archive/refs/tags/{{version.tag}}.tar.gz
strip-components: 1

versions:
github: mstorsjo/llvm-mingw

warnings:
- vendored # we redistribute upstream prebuilt binaries

# Runtime libs the LLVM toolchain itself links (host-side, not the
# Windows target). On a modern host these resolve from the system, but
# once we bundle our own glibc (below) so the toolchain runs on old CI
# hosts, the host's copies are bypassed — so pkgx must supply these via
# its runtime env. These are pkgx-built, so they're guaranteed under
# pkgx's default GLIBC_2.28 symbol floor (and are — libstdc++ 2.26, the
# rest 2.14). It's the *vendored* upstream binaries that break that floor:
# clang/libLLVM need GLIBC_2.34, which is the whole reason this bundle is
# necessary. linux-only: darwin links libSystem/libc++ from the OS.
# Runtime libs the host-side clang/lld link. Built at the 2.28 floor, so these
# pkgx-built deps (all <= 2.28) satisfy it — pkgx supplies them via its runtime
# env, no seal needed. linux-only (darwin links libSystem/libc++ from the OS).
dependencies:
linux:
gnu.org/gcc/libstdcxx: ^14 # libstdc++.so.6 + libgcc_s.so.1
zlib.net: "*" # libz.so.1
facebook.com/zstd: "*" # libzstd.so.1
zlib.net: "*"
facebook.com/zstd: "*"
gnome.org/libxml2: ~2.13 # 2.14 changes the API

build:
# We bundle our own ld.so + libc.so.6 (see the seal step) and patch the
# toolchain's PT_INTERP to it. brewkit's fix-patchelf would force-rpath
# *every* ELF under lib/ — including the bundled loader — and a loader
# that parses its own RPATH at startup SIGSEGVs (pkgxdev/brewkit#345,
# reproduced on x86-64 glibc 2.43). So skip it: the upstream binaries
# already carry relative $ORIGIN rpaths, bklibcvenv prepends the bundled
# libc dir as DT_RPATH, and cross-package deps resolve via pkgx's runtime
# env (same approach as the gnu.org/glibc recipe).
skip: fix-patchelf
dependencies:
curl.se: "*"
gnu.org/tar: "*"
tukaani.org/xz: "*"
cmake.org: "*"
ninja-build.org: "*"
git-scm.org: "*" # build-llvm.sh / build-mingw-w64.sh clone the sources
python.org: "~3.11" # LLVM's build tooling
zlib.net: "*"
facebook.com/zstd: "*"
linux:
# The libc to bundle. ~2.34 is the *oldest* glibc that still satisfies
# the vendored toolchain's symbol versions (clang/libLLVM reference up
# to GLIBC_2.34, above pkgx's default 2.28 floor; older won't load —
# see the test's glibc<2.34 guard). Bundling replaces the host libc
# entirely, so host range is set by glibc's --enable-kernel floor
# (CentOS 7), not this version.
gnu.org/glibc: ~2.34
gnu.org/gcc: ^14
# no compiler dep declared on purpose: brewkit's default toolchain is
# llvm, so the host bootstrap compiler is clang (cc/c++ shims → clang).
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
linux:
GLIBC_DIR: $(basename "$(echo {{deps.gnu.org/glibc.prefix}}/lib/glibc-*)")
URL: https://github.com/mstorsjo/llvm-mingw/releases/download/{{version.tag}}/llvm-mingw-{{version.tag}}-ucrt
working-directory: ${{prefix}}
# llvm-mingw builds per-target; we ship the x86_64 + aarch64 Windows
# cross-compilers (the two brewkit CI cares about).
TOOLCHAIN_ARCHS:
- x86_64
- aarch64
# mstorsjo's orchestrator builds clang/lld, native compiler-rt, installs
# the driver wrappers, builds the mingw-w64 runtime, then the Windows-target
# compiler-rt + libunwind/libc++. Trim lldb + clang-tools-extra to the
# cross-compiler essentials (still a full clang/lld build).
script:
- curl -Lf "$URL-${PLATFORM}.tar.xz" | tar Jxpf - --strip-components=1
# architecture register reservation weirdness
- run: sed -i -f $PROP build-mingw-w64-tools.sh
if: linux/aarch64
prop: |
1a export CFLAGS="\${CFLAGS:-} -O2 -ffixed-x18"

# Linux: bundle our own libc + seal the toolchain so it runs on hosts
# whose system glibc is older than the toolchain needs (the CI-runner
# case behind pkgxdev/brewkit#346). darwin uses dyld/libSystem — n/a.
- run:
# The glibc dep installs its loader + libc into lib/glibc-<X.Y>/;
# copy that whole dir in so the bottle ships its own loader.
- cp -a "{{deps.gnu.org/glibc.prefix}}/lib/$GLIBC_DIR" "{{prefix}}/lib/$GLIBC_DIR"

# Force compiler-rt. After the seal moves clang to libexec/, clang's
# MinGW runtime auto-detection (which keys off its bin/ siblings)
# falls back to libgcc and emits -lgcc/-lgcc_eh, which this toolchain
# doesn't ship. llvm-mingw is always compiler-rt + libunwind, so make
# it explicit — also fixes a latent location-sensitivity bug.
- sed -i 's|FLAGS="$FLAGS -target $TARGET"|FLAGS="$FLAGS -rtlib=compiler-rt -unwindlib=libunwind -target $TARGET"|' bin/clang-target-wrapper.sh

# Seal: patch each toolchain binary's PT_INTERP to the bundled loader
# via a load-time fixup stub, keeping /proc/self/exe pointing at the
# real binary (so clang -> cc1 works) while staying relocatable.
- bklibcvenv seal "{{prefix}}" "$GLIBC_DIR"
if: linux
- ./build-all.sh "{{prefix}}"
--disable-lldb
--disable-lldb-mi
--disable-clang-tools-extra || (find . -name config.log -exec echo {} \; -exec cat {} \; ; false)

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.

# TODO: enable after #12986 is merged
# dependencies:
# winehq.org: "*"
env:
WINEDEBUG: -all
WINEDLLOVERRIDES: "mscoree=;mshtml="
WINEPREFIX: $PWD/.wine
# env:
# WINEDEBUG: -all
# WINEDLLOVERRIDES: "mscoree=;mshtml="
# WINEPREFIX: $PWD/.wine
script:
# Diagnostics first — surface env + filesystem state so the
# darwin self-hosted-runner failure (logs not externally
# accessible) becomes visible to maintainers.
- command -v aarch64-w64-mingw32-clang
- command -v x86_64-w64-mingw32-clang

# Cross-compile a trivial Windows binary for x86-64 and aarch64.
- x86_64-w64-mingw32-clang --version
- run: cp $FIXTURE hello.c
fixture: |
#include <stdio.h>
int main(void) {
printf("Hello from native Windows cross-compile.\n");
return 0;
}
- x86_64-w64-mingw32-clang -o hello-x86_64.exe hello.c
int main(void) { printf("Hello from native Windows cross-compile.\n"); return 0; }
- x86_64-w64-mingw32-clang -o hello-x86_64.exe hello.c
- 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).
- test "$(head -c 2 hello-x86_64.exe)" = "MZ"
- test "$(head -c 2 hello-aarch64.exe)" = "MZ"

# 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.

# TODO: enable after #12986 is merged
- exit 0
- if command -v wine64 >/dev/null 2>&1; then
- WINE=wine64
- else
- WINE=wine
- fi

- test "$($WINE hello-x86_64.exe)" = "Hello from native Windows cross-compile."
- test "$($WINE hello-aarch64.exe)" = "Hello from native Windows cross-compile."
- if ! command -v wine64 >/dev/null 2>&1; then exit 0; fi
- test "$(wine64 hello-x86_64.exe | tr -d '\r')" = "Hello from native Windows cross-compile."

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/x86_64-w64-mingw32-ar
- bin/x86_64-w64-mingw32-ranlib
- bin/x86_64-w64-mingw32-strip
- bin/x86_64-w64-mingw32-nm
- bin/x86_64-w64-mingw32-objdump
- bin/x86_64-w64-mingw32-objcopy
- bin/x86_64-w64-mingw32-windres
- bin/x86_64-w64-mingw32-dlltool
- 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)
- bin/aarch64-w64-mingw32-ar
- bin/aarch64-w64-mingw32-ranlib
- bin/aarch64-w64-mingw32-strip
- bin/aarch64-w64-mingw32-nm
- bin/aarch64-w64-mingw32-objdump
- bin/aarch64-w64-mingw32-objcopy
- bin/aarch64-w64-mingw32-windres
- bin/aarch64-w64-mingw32-dlltool
# don't want to grab these.
# - bin/clang
# - bin/clang++
- bin/lld-link
- bin/llvm-rc
- bin/llvm-cvtres
Loading