Skip to content

Commit c4e1fc1

Browse files
committed
ci: 在 Linux 上构建,在真机上跑 —— 而那两个 job 什么都不装
原先 CI 证明的是「同一份源码不知道自己在哪台机器上」(裸机 + 本机,四行输出 diff 相等)。现在加证「构建也不必在那台机器上」:一台 Linux 宿主产出 PE 和 Mach-O,两个 job 把它们下载下来在真的 Windows 和真的 macOS 上跑。 ⭐⭐ 那两个 job 故意没有任何工具链步骤 —— 不装 mcpp、不装编译器、不装 C 运行时。 程序自带 C 库、C++ 运行时和展开器,剩下的只有它被构建给的那个操作系统。如果哪 天有人因为「程序需要」而往里加一步安装,那一步就是发现,不是修复。 ⚠️ 交叉构建产出一个格式正确的文件,只证明编译器被告知了正确的目标。它不证明程 序能跑 —— 而这套生态在这两个平台上找到的每一处差异(加载器 bootstrap 的 thread-local、展开器找自己的表、人格例程)都是**链接成功、运行时失败**。 判据是 unwound: true —— 析构函数在展开中跑到了,链接骗不出这一行。 两处断言写在运行之前,因为它们的修法不同: · 格式(PE32+ / Mach-O arm64)在构建 job 里断言 —— 失败意味着目标选错了; · ad-hoc 签名在 macOS job 里断言 —— arm64 macOS 拒绝未签名镜像,失败意味着 链接器没签,而不是程序崩了。 ⚠️ 产物上传会丢执行位,所以 chmod 在前。 ── 本机已验(⚠️ wine 不等于 Windows,所以才要上面那个 job)────── x86_64-linux-gnu ELF 跑通 x86_64-windows-gnu PE 跑通(wine) riscv64-none-elf ELF 跑通(qemu + OpenSBI) aarch64-macos Mach-O 产出,LC_CODE_SIGNATURE 在
1 parent 814b3ab commit c4e1fc1

1 file changed

Lines changed: 97 additions & 0 deletions

File tree

.github/workflows/ci.yml

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,3 +197,100 @@ jobs:
197197
# The four lines are the same four lines.
198198
diff <(grep -E '^(sorted|caught|unwound|import std over openkal):' out.log) \
199199
<(grep -E '^(sorted|caught|unwound|import std over openkal):' host.log)
200+
201+
# ⭐⭐ AND THE SAME SOURCE FOR TWO MACHINES THIS ONE IS NOT.
202+
#
203+
# The two steps above prove the source does not know which machine it is
204+
# for. These prove the BUILD does not need to be on it: one Linux host
205+
# produces a PE and a Mach-O, and the jobs below run them on the real
206+
# thing with nothing installed.
207+
#
208+
# ⚠️ THE ARTEFACT IS THE ARGUMENT, WHICH IS WHY THOSE JOBS INSTALL NOTHING.
209+
# Not mcpp, not a compiler, not a C runtime — the program carries its C
210+
# library, its C++ runtime and its unwinder, and what remains is the
211+
# operating system it was built for. A run that needed a redistributable
212+
# installed first would be demonstrating something weaker.
213+
- name: The same source, built here for Windows and for macOS
214+
if: matrix.toolchain == 'llvm@22.1.8'
215+
run: |
216+
set -euo pipefail
217+
cd examples/same-source
218+
mkdir -p "$RUNNER_TEMP/cross"
219+
for t in x86_64-windows-gnu aarch64-macos; do
220+
rm -rf target
221+
mcpp build --target "$t"
222+
a=$(find target -type f \( -name 'openkal-same-source' -o -name '*.exe' \) | head -1)
223+
[ -n "$a" ] || { echo "::error::$t produced no artefact"; exit 1; }
224+
echo "$t → $(file -b "$a")"
225+
cp "$a" "$RUNNER_TEMP/cross/"
226+
done
227+
# ⚠️ The format is asserted here rather than left to the run jobs. A
228+
# run that fails tells you the program did not work; this tells you
229+
# what was produced, and the two failures need different fixes.
230+
file "$RUNNER_TEMP/cross/openkal-same-source.exe" | grep -q 'PE32+ executable'
231+
file "$RUNNER_TEMP/cross/openkal-same-source" | grep -q 'Mach-O 64-bit arm64'
232+
233+
- uses: actions/upload-artifact@v4
234+
if: matrix.toolchain == 'llvm@22.1.8'
235+
with:
236+
name: cross-artifacts
237+
path: ${{ runner.temp }}/cross/
238+
if-no-files-found: error
239+
240+
# ---------------------------------------------------------------------------
241+
# ⭐⭐ THE ACCEPTANCE CRITERION FOR PORTABILITY OF THE ARTEFACT.
242+
#
243+
# A cross build that produces a well-formed file proves the compiler was told
244+
# the right target. It does not prove the program runs, and every difference
245+
# this ecosystem has had to find on these two platforms — the loader-bootstrapped
246+
# thread-local, the unwinder's search for its own tables, the personality
247+
# routine — links successfully and fails at run time.
248+
#
249+
# ⚠️ These jobs deliberately have NO toolchain steps. If one is ever added
250+
# because "the program needs it", that is the finding, not the fix.
251+
run-on-windows:
252+
name: the artefact built on Linux runs on Windows
253+
needs: runtime
254+
runs-on: windows-2022
255+
timeout-minutes: 10
256+
defaults:
257+
run:
258+
shell: bash
259+
steps:
260+
- uses: actions/download-artifact@v4
261+
with: { name: cross-artifacts, path: art }
262+
- name: It runs, and it unwinds
263+
run: |
264+
set -euo pipefail
265+
./art/openkal-same-source.exe 2>&1 | tee out.log
266+
grep -q 'sorted: 2 4 7' out.log
267+
grep -q 'caught: 42' out.log
268+
# ⭐ The line a link cannot fake: a destructor ran during the unwind,
269+
# so libunwind found `.eh_frame` by reading the image rather than by
270+
# asking the operating system to enumerate modules.
271+
grep -q 'unwound: true' out.log
272+
grep -q 'import std over openkal: ok' out.log
273+
274+
run-on-macos:
275+
name: the artefact built on Linux runs on macOS
276+
needs: runtime
277+
runs-on: macos-14
278+
timeout-minutes: 10
279+
steps:
280+
- uses: actions/download-artifact@v4
281+
with: { name: cross-artifacts, path: art }
282+
- name: It runs, and it unwinds
283+
run: |
284+
set -euo pipefail
285+
# ⚠️ The executable bit does not survive an artefact upload.
286+
chmod +x art/openkal-same-source
287+
# ⚠️ AND THE SIGNATURE DOES. arm64 macOS refuses an unsigned image, so
288+
# this is asserted before the run: a failure here is "the linker did
289+
# not ad-hoc sign it", which is a different repair from "the program
290+
# crashed".
291+
codesign -dv art/openkal-same-source 2>&1 | grep -q 'adhoc\|Signature'
292+
./art/openkal-same-source 2>&1 | tee out.log
293+
grep -q 'sorted: 2 4 7' out.log
294+
grep -q 'caught: 42' out.log
295+
grep -q 'unwound: true' out.log
296+
grep -q 'import std over openkal: ok' out.log

0 commit comments

Comments
 (0)