-
Notifications
You must be signed in to change notification settings - Fork 6
165 lines (153 loc) · 8.07 KB
/
Copy pathcross-build-test.yml
File metadata and controls
165 lines (153 loc) · 8.07 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
name: cross-build-test
# mcpp cross-build test — the single source of truth for "which CROSS-build
# target combinations mcpp supports", verified end-to-end.
#
# Cross = host arch ≠ target arch. Verification targets are mcpp ITSELF and
# xlings (real, self-hosting C++23 module projects), cross-built from source for
# each target triple, arch-checked, and smoke-run under qemu-user.
#
# ── Supported cross matrix (built + verified below) ────────────────────────
# target | toolchain | host→target | run
# ----------------------|---------------------------------|---------------|-----
# aarch64-linux-musl | aarch64-linux-musl-gcc@15.1.0 | x86_64→arm64 | qemu
#
# mcpp resolves a cross `--target <triple>-musl` build to the triple-named cross
# gcc musl toolchain from the xlings ecosystem (xim:<triple>-gcc, see
# src/build/prepare.cppm). Output is a fully static musl ELF (no PT_INTERP),
# which also makes the aarch64 artefact runnable natively in Termux/Android —
# qemu-aarch64 is the CI proxy for "does this cross artefact actually execute".
#
# ── NOT here ───────────────────────────────────────────────────────────────
# * Same-arch builds (host arch == target arch) are NOT cross. The native musl
# static build `--target x86_64-linux-musl` (x86_64 host) is exercised by
# ci-linux.yml's "Toolchain: musl-gcc" step, and release.yml for the static
# release artefact. Keep them there; this file is cross-arch only.
#
# ── Planned cross rows (documented; NOT yet wired in mcpp — keep as comments) ─
# * llvm/clang cross : clang is inherently a cross-compiler, but mcpp does not
# yet inject `-target <triple>` + a cross sysroot for a
# clang toolchain; cross `--target` resolves to gcc musl
# only. Wire the clang cross path first, then add a row.
# * riscv64-linux-musl: add once xim:riscv64-linux-musl-gcc ships to
# xlings-res + xim-pkgindex.
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
workflow_dispatch:
concurrency:
group: ci-${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
cross-build:
name: cross-build ${{ matrix.target }} (mcpp + xlings)
runs-on: ubuntu-24.04
timeout-minutes: 60
strategy:
fail-fast: false
matrix:
include:
- target: aarch64-linux-musl
file_arch: "ARM aarch64"
qemu_bin: qemu-aarch64-static
env:
MCPP_HOME: /home/runner/.mcpp
# Verbose every mcpp invocation for richer CI diagnostics (src/cli.cppm).
MCPP_VERBOSE: "1"
steps:
- uses: actions/checkout@v4
- name: Cache mcpp sandbox
uses: actions/cache@v4
with:
path: ~/.mcpp
key: mcpp-sandbox-${{ runner.os }}-cross-${{ matrix.target }}-${{ hashFiles('mcpp.toml', '.xlings.json') }}
restore-keys: |
mcpp-sandbox-${{ runner.os }}-cross-${{ matrix.target }}-
- name: Cache xlings
uses: actions/cache@v4
with:
path: ~/.xlings
key: xlings-${{ runner.os }}-v2-${{ hashFiles('.xlings.json') }}
restore-keys: |
xlings-${{ runner.os }}-v2-
- name: Install qemu-user-static
run: |
sudo apt-get update -qq
sudo apt-get install -y qemu-user-static
${{ matrix.qemu_bin }} --version | head -1
- name: Bootstrap mcpp via xlings
env:
XLINGS_NON_INTERACTIVE: '1'
# 0.4.62 (current) — kept in lock-step with the xlings the release
# is built/bundled against (release.yml). A past 0.4.61 "download 404
# for mcpp@<pin>" was NOT a version bug — the xlings-res/mcpp GitHub
# release assets were uploaded in a broken state (records present,
# blobs missing → 404 on GET); re-uploaded clean. The stale-INDEX
# half is handled by the marker-clear below.
XLINGS_VERSION: '0.4.62'
run: |
tarball="xlings-${XLINGS_VERSION}-linux-x86_64.tar.gz"
curl -fsSL -o "/tmp/${tarball}" \
"https://github.com/d2learn/xlings/releases/download/v${XLINGS_VERSION}/${tarball}"
tar -xzf "/tmp/${tarball}" -C /tmp
"/tmp/xlings-${XLINGS_VERSION}-linux-x86_64/subos/default/bin/xlings" self install
export PATH="$HOME/.xlings/subos/default/bin:$PATH"
xlings --version
# Force a real index re-sync even on a warm cache: drop the TTL refresh
# markers so `xlings update` actually pulls the latest index (sees the
# current bootstrap pin) while the toolchain payloads stay cached.
find "$HOME/.xlings" -name '.xlings-index-cache.json' -delete 2>/dev/null || true
xlings config --mirror GLOBAL 2>/dev/null || true
xlings update -y 2>/dev/null || xlings update 2>/dev/null || true
xlings install mcpp -y
echo "XLINGS_BIN=$HOME/.xlings/subos/default/bin/xlings" >> "$GITHUB_ENV"
echo "MCPP_BOOT=$HOME/.xlings/subos/default/bin/mcpp" >> "$GITHUB_ENV"
- name: Self-host build (bootstrap mcpp -> fresh host mcpp)
run: |
export MCPP_VENDORED_XLINGS="$XLINGS_BIN"
"$XLINGS_BIN" config --mirror GLOBAL 2>/dev/null || true
"$MCPP_BOOT" self config --mirror GLOBAL 2>/dev/null || true
"$MCPP_BOOT" build
MCPP=$(realpath "$(find target -type f -name mcpp -printf '%T@ %p\n' | sort -rn | head -1 | cut -d' ' -f2)")
test -x "$MCPP"
"$MCPP" self config --mirror GLOBAL
echo "MCPP=$MCPP" >> "$GITHUB_ENV"
- name: "Cross-build mcpp -> ${{ matrix.target }}"
run: |
export MCPP_VENDORED_XLINGS="$XLINGS_BIN"
"$MCPP" build --target ${{ matrix.target }}
bin=$(find target/${{ matrix.target }} -type f -name mcpp | head -1)
[ -n "$bin" ] || { echo "no mcpp artefact for ${{ matrix.target }}"; exit 1; }
echo "== file =="; file "$bin"
file "$bin" | grep -q "${{ matrix.file_arch }}" || { echo "expected ${{ matrix.file_arch }}"; exit 1; }
file "$bin" | grep -q "statically linked" || { echo "expected static"; exit 1; }
echo "MCPP_XBIN=$bin" >> "$GITHUB_ENV"
- name: "Cross-build xlings -> ${{ matrix.target }}"
run: |
export MCPP_VENDORED_XLINGS="$XLINGS_BIN"
git clone --depth 1 https://github.com/openxlings/xlings /tmp/xlings-src
cd /tmp/xlings-src
"$MCPP" self config --mirror GLOBAL 2>/dev/null || true
"$MCPP" build --target ${{ matrix.target }}
xbin=$(find target/${{ matrix.target }} -type f -name xlings | head -1)
[ -n "$xbin" ] || { echo "no xlings artefact for ${{ matrix.target }}"; exit 1; }
echo "== file =="; file "$xbin"
file "$xbin" | grep -q "${{ matrix.file_arch }}" || { echo "expected ${{ matrix.file_arch }}"; exit 1; }
file "$xbin" | grep -q "statically linked" || { echo "expected static"; exit 1; }
echo "XLINGS_XBIN=$xbin" >> "$GITHUB_ENV"
- name: "Smoke-run cross artefacts under qemu"
run: |
RUN="${{ matrix.qemu_bin }}"
# mcpp is self-contained, so --version runs cleanly under bare qemu —
# this is the hard execution proof for the cross artefact.
echo "== mcpp --version =="
mver=$($RUN "$MCPP_XBIN" --version)
echo "$mver"; echo "$mver" | grep -q "mcpp" || { echo "mcpp --version failed"; exit 1; }
# xlings expects a real runtime environment (sandbox/config) and may
# exit non-zero on a bare `--version` under qemu; its ELF arch + static
# linkage were already asserted in the build step, so treat execution
# here as best-effort rather than gating.
echo "== xlings --version (best-effort under qemu) =="
xver=$($RUN "$XLINGS_XBIN" --version 2>&1 || true)
echo "$xver"