…s package (#4)
* declare the compiler runtime, which was always the larger half of this package
本包 729 个对象里,**498 个是 compiler-rt 的 builtins、21 个是 libunwind 的**。
那些是一个 **C 程序**需要的东西 —— `__udivti3` 和它的亲戚与 C++ 无关 ——
而清单此前只声明 `mcpp:c++-abi=libc++`,于是它说自己供给了不供给的东西,
同时隐瞒了真正供给的那一半。
provides = [
"hosted-standard-library",
"mcpp:c++-abi=libc++",
"mcpp:compiler-runtime=compiler-rt", ← 新增
]
实测(本机,mcpp 2026.8.24.3):
compiler llvm (22.1.8, payload)
compiler-runtime compiler-rt (openkal-llvm-runtime@0.1.2, graph) ← 原为 payload
kernel-abi openkal (openkal-linux@0.5.3, graph)
c-abi musl (openkal-musl@0.3.3, graph)
c++-abi libc++ (openkal-llvm-runtime@0.1.2, graph)
五层里四层来自图,只剩编译器本身来自载荷。
── ⚠️ 同一改动里必须上移 MCPP_VERSION,原因不是兼容性 ────────
一个键有三种结局,而其中两种都是 exit 0:
provides = ["mcpp:compiler-runtime=…"] 2026.8.19.4 exit 0 **没有被校验**
2026.8.24.1 exit 2 拒绝
2026.8.24.3 exit 0 解析成功
⭐ 19.4 那个零和 24.3 那个零**不是同一种成功**。前者早于层词表,
整个数组被当作不认识的键忽略 —— 它既不拒绝这条声明,也不读它。
CI 停在那里会在一份**中心主张从未被检查过**的清单上报绿。
因此 `MCPP_VERSION` 2026.8.19.4 → 2026.8.24.3 与本行同时改。
拒绝窗口只有 2026.8.24.1 一个版本(开始校验 `mcpp:` 前缀之后、
学会这一层之前)。索引已于今日到达 2026.8.24.3,且这些包尚无存量用户。
* ci: drop the branch-built tool, and make the bare-metal step reach bare metal
删掉的那个步骤自己写着退出条件:「⇒ When #486 ships, delete this step and
raise MCPP_VERSION」。#486 已于 2026-08-23 合入并随 2026.8.24.1 起发布,
而这个步骤还在从 `feat/import-std-capability` 分支构建 mcpp 并盖掉刚装好的那个。
后果不是「多跑一次构建」。日志里两行并排:
Install mcpp mcpp 2026.8.24.3
The build tool, from the branch… mcpp 2026.8.21.3 ← 实际跑的是它
于是 `MCPP_VERSION` 这个变量对**被测的行为**不起作用,本 PR 把它移到 24.3
之后 CI 仍然用 21.3 跑,报出三层版的错误信息。两个 job 各一处,一并删除。
── ⚠️ 并且那一步在测宿主,而它的名字说的是裸机 ──────────────
`The same source on bare metal, with exceptions` 跑的是裸的 `mcpp run`。
这个清单**刻意没有 `[build] target`**(注释就写在第 5 行),所以裸的
`mcpp run` 构建的是**宿主**。四行断言两种跑法都会打印 —— 那是清单自己的
主张,不是巧合 —— 于是这一步在宿主构建上报绿,**一次都没有到过 OpenSBI**。
实测 2026-08-24:产物是 `target/x86_64-linux-gnu/…`。
改法两处:
· `mcpp run --target riscv64-none-elf`
· 加一条 `grep -q 'Boot HART'`,即固件自己的横幅 —— 这样一次没离开宿主
的运行**无法**靠打印那四行应用输出来满足本步骤
本机实测改后:OpenSBI 横幅出现,四行输出与宿主一致。
* ci: pin 2026.8.24.4, which is the release that survives the bare-metal step
把 pin 移到 24.3 让裸机那一步第一次真正到达 OpenSBI,而**它之后的那一步**
随即失败:`mcpp run --target X` 一直把 X 的构建记在宿主的缓存槽里,
于是下一条裸的 `mcpp run` 直接 exec 了交叉产物。
那个缺陷早于本包,只因为一个自称测裸机的步骤开始真的测裸机才现形。
mcpp-community/mcpp#498 修复,随 2026.8.24.4 发布。
* ci: the emulated serial console ends lines with CRLF
裸机那一步的四行与宿主的四行**内容完全一致**,而 `diff` 报四行全不同:
1,4c1,4
< sorted: 2 4 7
---
> sorted: 2 4 7
不可见字符。裸机运行经由模拟的 16550 UART 到达控制台,而串口控制台
以 CRLF 结束一行;宿主运行不是。
⭐ 这种失败读起来像是**被测的主张不成立**,而不像承载它的传输层不同 ——
两侧各加一个 `tr -d '\r'`。断言的是程序打印了什么,不是字节怎么到达的。
同样是把那一步从裸的 `mcpp run`(宿主)改成真的
`--target riscv64-none-elf` 之后才暴露的。
mcpp run --target X 正确地为 X 交叉构建,然后把结果记在了宿主的槽里。损害不在这条命令,而在下一条:
$ mcpp run --target riscv64-none-elf # 正确,经 qemu 跑起来 $ mcpp run Running `target/riscv64-none-elf/…/bin/openkal-same-source` exit=1缓存文件里逐字可见:一次 riscv 交叉构建写下的是 [target=]。空键的含义是「为这台机器构建」,而这正是 try_fast_run 允许自己直接 exec 缓存产物的唯一依据。裸的 mcpp run 命中它,跳过整个 prepare_build(既没构建宿主目标,也没解析 runner),在本机执行了另一个目标的二进制。
真因是一个丢掉的实参:
最后那个形参就是缓存条目的 [target=] 键。cmd_build 两个调用点都传了,只有 run 这条没传。
⚠️ try_fast_run 的注释里记着同一个缺陷的另一条到达路径(目标写在清单的 [build] target 里),并且只守了那一扇门。这是另一扇门:flag。
回归测试的判据是路径,不是退出码
⭐ 异架构产物 exec 会失败,所以只看退出码的测试在那里因错误的理由通过,而在同架构上完全测不到——后者更危险:用户不会看到崩溃,只会拿到一个 musl 产物冒充宿主产物。测试因此用 x86_64-linux-musl(同架构、本机能跑),断言 Running 那行的路径。
修复前实测为红:
FAIL: a bare `mcpp run` exec'd the x86_64-linux-musl artifact target/x86_64-linux-musl/50af2973556be3d7/bin/runslot修复后转绿;单元测试 93 通过 / 0 失败。
发现路径:openkal-llvm-runtime 的 CI 有一步名为「on bare metal」却跑裸的 mcpp run(即宿主)。改成真的 --target riscv64-none-elf 之后,下一步炸了——缺陷一直都在,只是没有任何东西走到那条顺序上。