Skip to content

Commit 0a9f83e

Browse files
tannevaledjhheider
andauthored
new(llvm.org/mingw-w64): from-source LLVM-mingw cross-toolchain (#13048)
Co-authored-by: Jacob Heider <jacob@pkgx.dev>
1 parent d52988e commit 0a9f83e

1 file changed

Lines changed: 89 additions & 142 deletions

File tree

Lines changed: 89 additions & 142 deletions
Original file line numberDiff line numberDiff line change
@@ -1,181 +1,128 @@
1-
# llvm-mingw: LLVM-based mingw-w64 toolchain.
2-
# Cross-compiler that runs on Linux / macOS hosts and produces native
3-
# Windows binaries (PE/COFF) for x86-64, i686, aarch64, armv7.
1+
# llvm.org/mingw-w64 — from-source LLVM mingw-w64 cross-compiler toolchain.
42
#
5-
# This is the toolchain bottle behind pkgxdev/brewkit#346 — the
6-
# "produce native Windows packages from Linux CI runners" RFC. Once
7-
# this lands, individual pantry recipes can add `platforms:
8-
# windows/x86-64` and depend on `llvm.org/mingw-w64` to cross-compile.
3+
# Builds the COMPLETE llvm-mingw toolchain from source via upstream
4+
# mstorsjo/llvm-mingw's own build orchestration (`build-all.sh`):
5+
# - clang + lld + the LLVM binutils-equivalents
6+
# - the mingw-w64 runtime (headers + CRT + winpthreads)
7+
# - the LLVM runtimes for the Windows targets: compiler-rt builtins,
8+
# libunwind, libc++abi, libc++
9+
# - the per-target driver wrappers (install-wrappers.sh)
10+
# No vendored binaries — everything is compiled here.
911
#
10-
# We re-distribute the upstream prebuilt tarballs (vendored binaries
11-
# from mstorsjo/llvm-mingw releases) rather than building llvm-mingw
12-
# from source — that'd require building LLVM itself plus the
13-
# mingw-w64 runtime, multi-hour and not differentiated. Upstream
14-
# tarballs are reproducibly-built and signed via GitHub releases.
12+
# Why inline (clang and all) rather than composing pantry's llvm.org: the
13+
# Windows-target runtimes must match the exact clang that builds them, and
14+
# pkgx dependency constraints can't "drift" to track that. Building the whole
15+
# toolchain from one source tree makes it internally consistent by
16+
# construction, and versioning to mstorsjo's releases (which pin the matching
17+
# llvm-project) means there's no LLVM-version dance to get wrong.
18+
#
19+
# Compiled on the builder at pkgx's glibc floor, so the host-side driver
20+
# binaries run on old hosts with NO bklibcvenv seal. (Replaces the previous
21+
# approach of vendoring mstorsjo's prebuilt tarball; pantry policy is
22+
# from-source over vendored.)
23+
#
24+
# NOTE: this is a full LLVM build — long, by design. "Build time isn't the
25+
# end of the world to get it right."
1526

16-
# Source tarball is auto-generated by GitHub for each tag; the *real*
17-
# payload is the prebuilt-binary tarball we curl from build.script
18-
# (same `warnings: vendored` pattern as ziglang.org).
1927
distributable:
20-
~
21-
# url: https://github.com/mstorsjo/llvm-mingw/archive/refs/tags/{{ version.raw }}.tar.gz
22-
# strip-components: 1
28+
url: https://github.com/mstorsjo/llvm-mingw/archive/refs/tags/{{version.tag}}.tar.gz
29+
strip-components: 1
2330

2431
versions:
2532
github: mstorsjo/llvm-mingw
2633

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

4544
build:
46-
# We bundle our own ld.so + libc.so.6 (see the seal step) and patch the
47-
# toolchain's PT_INTERP to it. brewkit's fix-patchelf would force-rpath
48-
# *every* ELF under lib/ — including the bundled loader — and a loader
49-
# that parses its own RPATH at startup SIGSEGVs (pkgxdev/brewkit#345,
50-
# reproduced on x86-64 glibc 2.43). So skip it: the upstream binaries
51-
# already carry relative $ORIGIN rpaths, bklibcvenv prepends the bundled
52-
# libc dir as DT_RPATH, and cross-package deps resolve via pkgx's runtime
53-
# env (same approach as the gnu.org/glibc recipe).
54-
skip: fix-patchelf
5545
dependencies:
56-
curl.se: "*"
57-
gnu.org/tar: "*"
58-
tukaani.org/xz: "*"
46+
cmake.org: "*"
47+
ninja-build.org: "*"
48+
git-scm.org: "*" # build-llvm.sh / build-mingw-w64.sh clone the sources
49+
python.org: "~3.11" # LLVM's build tooling
50+
zlib.net: "*"
51+
facebook.com/zstd: "*"
5952
linux:
60-
# The libc to bundle. ~2.34 is the *oldest* glibc that still satisfies
61-
# the vendored toolchain's symbol versions (clang/libLLVM reference up
62-
# to GLIBC_2.34, above pkgx's default 2.28 floor; older won't load —
63-
# see the test's glibc<2.34 guard). Bundling replaces the host libc
64-
# entirely, so host range is set by glibc's --enable-kernel floor
65-
# (CentOS 7), not this version.
66-
gnu.org/glibc: ~2.34
53+
gnu.org/gcc: ^14
54+
# no compiler dep declared on purpose: brewkit's default toolchain is
55+
# llvm, so the host bootstrap compiler is clang (cc/c++ shims → clang).
6756
env:
68-
linux/x86-64:
69-
PLATFORM: ubuntu-22.04-x86_64
70-
linux/aarch64:
71-
PLATFORM: ubuntu-22.04-aarch64
72-
darwin/x86-64:
73-
PLATFORM: macos-universal
74-
darwin/aarch64:
75-
PLATFORM: macos-universal
76-
linux:
77-
GLIBC_DIR: $(basename "$(echo {{deps.gnu.org/glibc.prefix}}/lib/glibc-*)")
78-
URL: https://github.com/mstorsjo/llvm-mingw/releases/download/{{version.tag}}/llvm-mingw-{{version.tag}}-ucrt
79-
working-directory: ${{prefix}}
57+
# llvm-mingw builds per-target; we ship the x86_64 + aarch64 Windows
58+
# cross-compilers (the two brewkit CI cares about).
59+
TOOLCHAIN_ARCHS:
60+
- x86_64
61+
- aarch64
62+
# mstorsjo's orchestrator builds clang/lld, native compiler-rt, installs
63+
# the driver wrappers, builds the mingw-w64 runtime, then the Windows-target
64+
# compiler-rt + libunwind/libc++. Trim lldb + clang-tools-extra to the
65+
# cross-compiler essentials (still a full clang/lld build).
8066
script:
81-
- curl -Lf "$URL-${PLATFORM}.tar.xz" | tar Jxpf - --strip-components=1
67+
# architecture register reservation weirdness
68+
- run: sed -i -f $PROP build-mingw-w64-tools.sh
69+
if: linux/aarch64
70+
prop: |
71+
1a export CFLAGS="\${CFLAGS:-} -O2 -ffixed-x18"
8272
83-
# Linux: bundle our own libc + seal the toolchain so it runs on hosts
84-
# whose system glibc is older than the toolchain needs (the CI-runner
85-
# case behind pkgxdev/brewkit#346). darwin uses dyld/libSystem — n/a.
86-
- run:
87-
# The glibc dep installs its loader + libc into lib/glibc-<X.Y>/;
88-
# copy that whole dir in so the bottle ships its own loader.
89-
- cp -a "{{deps.gnu.org/glibc.prefix}}/lib/$GLIBC_DIR" "{{prefix}}/lib/$GLIBC_DIR"
90-
91-
# Force compiler-rt. After the seal moves clang to libexec/, clang's
92-
# MinGW runtime auto-detection (which keys off its bin/ siblings)
93-
# falls back to libgcc and emits -lgcc/-lgcc_eh, which this toolchain
94-
# doesn't ship. llvm-mingw is always compiler-rt + libunwind, so make
95-
# it explicit — also fixes a latent location-sensitivity bug.
96-
- sed -i 's|FLAGS="$FLAGS -target $TARGET"|FLAGS="$FLAGS -rtlib=compiler-rt -unwindlib=libunwind -target $TARGET"|' bin/clang-target-wrapper.sh
97-
98-
# Seal: patch each toolchain binary's PT_INTERP to the bundled loader
99-
# via a load-time fixup stub, keeping /proc/self/exe pointing at the
100-
# real binary (so clang -> cc1 works) while staying relocatable.
101-
- bklibcvenv seal "{{prefix}}" "$GLIBC_DIR"
102-
if: linux
73+
- ./build-all.sh "{{prefix}}"
74+
--disable-lldb
75+
--disable-lldb-mi
76+
--disable-clang-tools-extra || (find . -name config.log -exec echo {} \; -exec cat {} \; ; false)
10377

10478
test:
105-
# winehq.org/wine is a soft dep — if present, we actually run the
106-
# cross-compiled .exe through wine and verify the output. If not,
107-
# we fall back to a PE magic-byte check. See pkgxdev/brewkit#346
108-
# discussion: wine in pantry would let us validate the cross-compile
109-
# chain end-to-end without GitHub Windows runners.
110-
111-
# TODO: enable after #12986 is merged
11279
# dependencies:
11380
# winehq.org: "*"
114-
env:
115-
WINEDEBUG: -all
116-
WINEDLLOVERRIDES: "mscoree=;mshtml="
117-
WINEPREFIX: $PWD/.wine
81+
# env:
82+
# WINEDEBUG: -all
83+
# WINEDLLOVERRIDES: "mscoree=;mshtml="
84+
# WINEPREFIX: $PWD/.wine
11885
script:
119-
# Diagnostics first — surface env + filesystem state so the
120-
# darwin self-hosted-runner failure (logs not externally
121-
# accessible) becomes visible to maintainers.
122-
- command -v aarch64-w64-mingw32-clang
123-
- command -v x86_64-w64-mingw32-clang
124-
125-
# Cross-compile a trivial Windows binary for x86-64 and aarch64.
86+
- x86_64-w64-mingw32-clang --version
12687
- run: cp $FIXTURE hello.c
12788
fixture: |
12889
#include <stdio.h>
129-
int main(void) {
130-
printf("Hello from native Windows cross-compile.\n");
131-
return 0;
132-
}
133-
- x86_64-w64-mingw32-clang -o hello-x86_64.exe hello.c
90+
int main(void) { printf("Hello from native Windows cross-compile.\n"); return 0; }
91+
- x86_64-w64-mingw32-clang -o hello-x86_64.exe hello.c
13492
- aarch64-w64-mingw32-clang -o hello-aarch64.exe hello.c
135-
136-
# Static signature check: PE32+ starts with "MZ" at offset 0.
137-
# head -c 2 reads the raw bytes; "MZ" are printable so the shell
138-
# capture works without any od/tr/sed gymnastics (which had subtle
139-
# BSD-vs-GNU output-format differences and broke on darwin).
14093
- test "$(head -c 2 hello-x86_64.exe)" = "MZ"
14194
- test "$(head -c 2 hello-aarch64.exe)" = "MZ"
142-
143-
# Dynamic check: actually run the .exe through wine. We only run
144-
# the x86-64 binary — wine on linux/aarch64 hosts can run aarch64
145-
# Windows but it's flakier; static check above is enough to prove
146-
# the aarch64 cross-compile worked.
147-
#
148-
# WINEDLLOVERRIDES disables wine's first-run Mono/Gecko prompts;
149-
# WINEDEBUG silences load-time warnings. Both standard for headless.
150-
151-
# TODO: enable after #12986 is merged
152-
- exit 0
153-
- if command -v wine64 >/dev/null 2>&1; then
154-
- WINE=wine64
155-
- else
156-
- WINE=wine
157-
- fi
158-
159-
- test "$($WINE hello-x86_64.exe)" = "Hello from native Windows cross-compile."
160-
- test "$($WINE hello-aarch64.exe)" = "Hello from native Windows cross-compile."
95+
- if ! command -v wine64 >/dev/null 2>&1; then exit 0; fi
96+
- test "$(wine64 hello-x86_64.exe | tr -d '\r')" = "Hello from native Windows cross-compile."
16197

16298
provides:
163-
# x86_64 cross drivers
16499
- bin/x86_64-w64-mingw32-clang
165100
- bin/x86_64-w64-mingw32-clang++
166101
- bin/x86_64-w64-mingw32-gcc
167102
- bin/x86_64-w64-mingw32-g++
168-
# aarch64 cross drivers
103+
- bin/x86_64-w64-mingw32-ar
104+
- bin/x86_64-w64-mingw32-ranlib
105+
- bin/x86_64-w64-mingw32-strip
106+
- bin/x86_64-w64-mingw32-nm
107+
- bin/x86_64-w64-mingw32-objdump
108+
- bin/x86_64-w64-mingw32-objcopy
109+
- bin/x86_64-w64-mingw32-windres
110+
- bin/x86_64-w64-mingw32-dlltool
169111
- bin/aarch64-w64-mingw32-clang
170112
- bin/aarch64-w64-mingw32-clang++
171113
- bin/aarch64-w64-mingw32-gcc
172114
- bin/aarch64-w64-mingw32-g++
173-
# i686 cross drivers
174-
- bin/i686-w64-mingw32-clang
175-
- bin/i686-w64-mingw32-clang++
176-
# PE-aware tooling (analog of binutils for ELF). llvm-mt isn't
177-
# shipped as a separate binary in current llvm-mingw builds —
178-
# rc/cvtres cover the manifest+resource pipeline.
179-
- bin/llvm-rc # resource compiler (rc.exe)
180-
- bin/llvm-cvtres # COFF tooling
181-
- bin/lld-link # MSVC-compat linker (link.exe)
115+
- bin/aarch64-w64-mingw32-ar
116+
- bin/aarch64-w64-mingw32-ranlib
117+
- bin/aarch64-w64-mingw32-strip
118+
- bin/aarch64-w64-mingw32-nm
119+
- bin/aarch64-w64-mingw32-objdump
120+
- bin/aarch64-w64-mingw32-objcopy
121+
- bin/aarch64-w64-mingw32-windres
122+
- bin/aarch64-w64-mingw32-dlltool
123+
# don't want to grab these.
124+
# - bin/clang
125+
# - bin/clang++
126+
- bin/lld-link
127+
- bin/llvm-rc
128+
- bin/llvm-cvtres

0 commit comments

Comments
 (0)