From 81497c65640480ca3047a709bb586b2970354baa Mon Sep 17 00:00:00 2001 From: sunrisepeak Date: Mon, 24 Aug 2026 23:16:26 +0800 Subject: [PATCH 1/4] declare the compiler runtime, which was always the larger half of this package MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 本包 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,且这些包尚无存量用户。 --- .github/workflows/ci.yml | 2 +- mcpp.toml | 67 +++++++++++++++++++++------------------- 2 files changed, 36 insertions(+), 33 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a90581ea..375a1518 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -17,7 +17,7 @@ on: workflow_dispatch: env: - MCPP_VERSION: 2026.8.19.4 + MCPP_VERSION: 2026.8.24.3 XLINGS_VERSION: v2026.8.17.2 XLINGS_NON_INTERACTIVE: '1' diff --git a/mcpp.toml b/mcpp.toml index 51417bdb..614770e6 100644 --- a/mcpp.toml +++ b/mcpp.toml @@ -18,39 +18,42 @@ repo = "https://github.com/mcpplibs/openkal-llvm-runtime" # The older spelling is kept beside the current one so that an engine # predating the layer vocabulary still recognises this package. Both name the # same layer; a newer engine reads the second and ignores the first. -provides = ["hosted-standard-library", "mcpp:c++-abi=libc++"] +provides = [ + "hosted-standard-library", + "mcpp:c++-abi=libc++", + # ⚠️ THE LARGER HALF OF THIS PACKAGE, AND IT IS NOT A C++ THING. + # + # Of the 729 objects built here, 498 are compiler-rt's builtins and 21 are + # libunwind's. Those are what a C PROGRAM needs — `__udivti3` and its + # relatives have nothing to do with C++ — so declaring them under the C++ + # layer would say this package supplies something it does not and conceal + # something it does. + "mcpp:compiler-runtime=compiler-rt", +] -# ⚠️ THE COMPILER RUNTIME IS THE LARGER HALF OF THIS PACKAGE AND IS NOT YET -# DECLARED, BECAUSE DECLARING IT WOULD MAKE THIS MANIFEST UNREADABLE TO EVERY -# RELEASED BUILD TOOL. -# -# Measured: of the 729 objects built here, 498 are compiler-rt's builtins and 21 -# are libunwind's. Those are what a C PROGRAM needs — `__udivti3` and its -# relatives have nothing to do with C++ — so declaring them under the C++ layer -# says this package supplies something it does not and conceals something it -# does. -# -# The layer is named `mcpp:compiler-runtime` from mcpp 2026.8.24.2, and a build -# tool released before that reports: -# -# error: `provides = ["mcpp:compiler-runtime=compiler-rt"]` names no -# capability mcpp knows. -# -# ⚠️ That refusal is itself fixed in 2026.8.24.2 — an unknown layer name in a -# DEPENDENCY's manifest is now ignored with a warning rather than refused — but -# the fix cannot apply retroactively to tools already released. -# -# ⚠️ AND THE CRITERION IS NOT THIS PACKAGE'S FLOOR. It is what the index serves, -# because that is what a reader of this file actually has. Measured 2026-08-24 -# against the two keys, with a dependency declaring each and a build tool taken -# from the version the index named `latest`: -# -# requires = ["mcpp:compiler=llvm"] 2026.8.24.1 exit 0, ignored -# provides = ["mcpp:compiler-runtime=…"] 2026.8.24.1 exit 2, refused -# -# So `requires` is safe to publish today and the layer declaration is not. The -# gate on adding it is that the index's `latest` be at 2026.8.24.2 or above — -# not that a newer mcpp exists, and not that this package's floor was raised. +# ── The floor this declaration puts under the package ─────────────────────── +# +# `mcpp:compiler-runtime` is a layer name mcpp learned in 2026.8.24.2. Measured +# 2026-08-24, one dependency declaring one key, each build tool taken from a +# published release: +# +# requires = ["mcpp:compiler=llvm"] 2026.8.19.4 exit 0 not validated +# 2026.8.24.1 exit 0 not validated +# provides = ["mcpp:compiler-runtime=…"] 2026.8.19.4 exit 0 not validated +# 2026.8.24.1 exit 2 REFUSED +# 2026.8.24.3 exit 0 resolved +# +# ⚠️ THE TWO ZEROES AT 2026.8.19.4 ARE NOT THE SAME KIND OF SUCCESS AS THE ONE +# AT 2026.8.24.3. That tool predates the layer vocabulary and ignores the whole +# array, so it neither refuses the declaration nor reads it. A CI pinned there +# would report green over a manifest whose central claim was never examined, +# which is why this package's `MCPP_VERSION` moves to 2026.8.24.3 in the same +# change that adds the line. +# +# The window that REFUSES is 2026.8.24.1 alone — between the release that began +# validating the `mcpp:` prefix and the one that learned this layer. Publishing +# into it was deferred until the index served a tool past it; the index reached +# 2026.8.24.3 on 2026-08-24 and these packages have no installed base behind it. # What this package needs of the layer it does not supply. # From e7723563644d12c1aacd1bc699d5e064e6925e68 Mon Sep 17 00:00:00 2001 From: sunrisepeak Date: Mon, 24 Aug 2026 23:25:41 +0800 Subject: [PATCH 2/4] ci: drop the branch-built tool, and make the bare-metal step reach bare metal MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 删掉的那个步骤自己写着退出条件:「⇒ 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 横幅出现,四行输出与宿主一致。 --- .github/workflows/ci.yml | 87 ++++++---------------------------------- 1 file changed, 12 insertions(+), 75 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 375a1518..884cf43e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -107,61 +107,6 @@ jobs: xlings install xim:qemu-riscv -y XLINGS_HOME="$HOME/.mcpp/registry" xlings install xim:qemu-riscv -y - # ⚠️ THE BUILD TOOL IS BUILT FROM A BRANCH, AND THAT IS TEMPORARY. - # - # This step needs four decisions that no released mcpp makes yet, each of - # which belongs to the tool rather than to this package: - # - # `import std` is gated on whether a package PROVIDES a standard - # library for the target rather than on whether the target is - # freestanding; a package may carry its own std module source; - # `-fno-exceptions` / `-fno-rtti` / `-ffreestanding` come off when the - # graph supplies a C++ runtime built for the target; and unwind tables - # go on, because the compiler turns them off for this kind of target - # and a partial set of tables stops the walk rather than degrading it. - # - # They are on mcpp-community/mcpp#486. Until that is released this job - # builds the tool the same way every other dependency here is taken — - # from the branch — so the criterion below is actually enforced instead - # of being a comment saying it was verified once on a laptop. - # - # ⇒ When #486 ships, delete this step and raise MCPP_VERSION. - - name: The build tool, from the branch that has what this needs - if: matrix.toolchain == 'llvm@22.1.8' - run: | - set -euo pipefail - git clone --depth 1 -b feat/import-std-capability \ - https://github.com/mcpp-community/mcpp "$RUNNER_TEMP/mcpp-src" - cd "$RUNNER_TEMP/mcpp-src" - # ⚠️ THE CLONE CARRIES A WORKSPACE PIN, AND IT NAMES A VERSION THE - # INDEX NO LONGER HAS. - # - # xlings: version '2026.8.17.1' not found for 'mcpp' - # available: 2026.8.19.4 - # - # `.xlings.json` at a repository root says which mcpp a build in that - # tree uses, and mcpp's own bootstrap pin does not move when mcpp is - # released — it is the version that was current when the pin was last - # touched. Cloning the branch therefore imports a pin that is only - # valid inside that repository's own CI, where the same file selects - # what gets installed. - # - # Rewriting it to the version this job already installed is what makes - # the two agree. It changes nothing about what is being tested: the - # pin selects the tool that BUILDS mcpp, and what is under test is the - # mcpp that comes out. - printf '{\n "workspace": {\n "mcpp": "%s"\n }\n}\n' "$MCPP_VERSION" > .xlings.json - # ⚠️ `--dev` AND NOT `--release`. What is under test is a set of - # decisions the tool makes about compile flags; an optimisation level - # changes none of them. Measured: the release self-build took over - # half an hour of a sixty-minute job on a two-core runner, which is - # most of the budget spent on something the test does not observe. - mcpp build --dev - BUILT=$(find target -type f -name mcpp -perm -u+x | head -1) - [ -n "$BUILT" ] || { echo "::error::mcpp did not build"; exit 1; } - echo "$(cd "$(dirname "$BUILT")" && pwd)" >> "$GITHUB_PATH" - "$BUILT" --version - - name: The same source on bare metal, with exceptions if: matrix.toolchain == 'llvm@22.1.8' run: | @@ -175,7 +120,18 @@ jobs: grep -q '"qemu-system-riscv64"' mcpp.toml \ || { echo "::error::the manifest no longer carries the bare emulator name"; exit 1; } sed -i "s|\"qemu-system-riscv64\"|\"$Q\"|" mcpp.toml - mcpp run 2>&1 | tee out.log + # ⚠️ `--target riscv64-none-elf`, AND THE FLAG IS THE WHOLE STEP. + # + # This manifest carries no `[build] target`, so a bare `mcpp run` + # builds for the HOST and passes — the four lines below appear either + # way, which is the manifest's own claim and not an accident. A step + # named "on bare metal" that omits the flag therefore reports green + # over a host build and has never once reached OpenSBI. Measured + # 2026-08-24: the artefact was `target/x86_64-linux-gnu/…`. + mcpp run --target riscv64-none-elf 2>&1 | tee out.log + # The emulator's own banner, so a run that never left the host cannot + # satisfy this step by printing the four application lines. + grep -q 'Boot HART' out.log # firmware ran; this is OpenSBI grep -q 'sorted: 2 4 7' out.log # containers + algorithms + the allocator grep -q 'caught: 42' out.log # the unwinder found the handler grep -q 'unwound: true' out.log # ⭐ and ran a destructor on the way @@ -398,25 +354,6 @@ jobs: mcpp toolchain install llvm 22.1.8 mcpp toolchain default 'llvm@22.1.8' - # ⚠️ Same temporary step as the Linux job: the decisions this exercises are - # on mcpp#486 and not in any release. When that ships, this goes and - # MCPP_VERSION rises. See the long note in the `runtime` job. - - name: The build tool, from the branch that has what this needs - run: | - set -euo pipefail - git clone --depth 1 -b feat/import-std-capability \ - https://github.com/mcpp-community/mcpp "$RUNNER_TEMP/mcpp-src" - cd "$RUNNER_TEMP/mcpp-src" - printf '{\n "workspace": {\n "mcpp": "%s"\n }\n}\n' "$MCPP_VERSION" > .xlings.json - mcpp build --dev - # ⚠️ Named exactly, and `-perm` is not used. On Windows every file - # reads as executable, so a permission test selects nothing useful; - # `mcpp.exe` is the name there and `mcpp` everywhere else. - BUILT=$(find target -type f \( -name 'mcpp' -o -name 'mcpp.exe' \) | head -1) - [ -n "$BUILT" ] || { echo "::error::mcpp did not build"; exit 1; } - echo "$(cd "$(dirname "$BUILT")" && pwd)" >> "$GITHUB_PATH" - "$BUILT" --version - - name: Every target, from this host run: | set -euo pipefail From 747085e3cef6df7fa8ff298eae73087475b3c094 Mon Sep 17 00:00:00 2001 From: sunrisepeak Date: Tue, 25 Aug 2026 00:18:08 +0800 Subject: [PATCH 3/4] ci: pin 2026.8.24.4, which is the release that survives the bare-metal step MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 把 pin 移到 24.3 让裸机那一步第一次真正到达 OpenSBI,而**它之后的那一步** 随即失败:`mcpp run --target X` 一直把 X 的构建记在宿主的缓存槽里, 于是下一条裸的 `mcpp run` 直接 exec 了交叉产物。 那个缺陷早于本包,只因为一个自称测裸机的步骤开始真的测裸机才现形。 mcpp-community/mcpp#498 修复,随 2026.8.24.4 发布。 --- .github/workflows/ci.yml | 2 +- mcpp.toml | 9 +++++++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 884cf43e..7dffbdaf 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -17,7 +17,7 @@ on: workflow_dispatch: env: - MCPP_VERSION: 2026.8.24.3 + MCPP_VERSION: 2026.8.24.4 XLINGS_VERSION: v2026.8.17.2 XLINGS_NON_INTERACTIVE: '1' diff --git a/mcpp.toml b/mcpp.toml index 614770e6..3aaa7b76 100644 --- a/mcpp.toml +++ b/mcpp.toml @@ -47,8 +47,13 @@ provides = [ # AT 2026.8.24.3. That tool predates the layer vocabulary and ignores the whole # array, so it neither refuses the declaration nor reads it. A CI pinned there # would report green over a manifest whose central claim was never examined, -# which is why this package's `MCPP_VERSION` moves to 2026.8.24.3 in the same -# change that adds the line. +# which is why this package's `MCPP_VERSION` moves in the same change that adds +# the line. It moves to 2026.8.24.4 rather than .3: raising the pin made the +# bare-metal step below reach OpenSBI for the first time, and the step AFTER it +# then failed — `mcpp run --target X` had been recording X's build under the +# host's cache key, so the next bare `mcpp run` exec'd the cross artefact. The +# defect predates this package and was found only because a step that claimed to +# test bare metal started doing so. Fixed in mcpp-community/mcpp#498. # # The window that REFUSES is 2026.8.24.1 alone — between the release that began # validating the `mcpp:` prefix and the one that learned this layer. Publishing From 3e68059b38b8ed075cc6fca9be91b9b4ec0c313d Mon Sep 17 00:00:00 2001 From: sunrisepeak Date: Tue, 25 Aug 2026 00:47:15 +0800 Subject: [PATCH 4/4] ci: the emulated serial console ends lines with CRLF MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 裸机那一步的四行与宿主的四行**内容完全一致**,而 `diff` 报四行全不同: 1,4c1,4 < sorted: 2 4 7 --- > sorted: 2 4 7 不可见字符。裸机运行经由模拟的 16550 UART 到达控制台,而串口控制台 以 CRLF 结束一行;宿主运行不是。 ⭐ 这种失败读起来像是**被测的主张不成立**,而不像承载它的传输层不同 —— 两侧各加一个 `tr -d '\r'`。断言的是程序打印了什么,不是字节怎么到达的。 同样是把那一步从裸的 `mcpp run`(宿主)改成真的 `--target riscv64-none-elf` 之后才暴露的。 --- .github/workflows/ci.yml | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7dffbdaf..9de5c28e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -151,8 +151,16 @@ jobs: cd examples/same-source && mcpp run 2>&1 | tee host.log grep -q 'import std over openkal: ok' host.log # The four lines are the same four lines. - diff <(grep -E '^(sorted|caught|unwound|import std over openkal):' out.log) \ - <(grep -E '^(sorted|caught|unwound|import std over openkal):' host.log) + # + # ⚠️ `tr -d '\r'` ON BOTH SIDES, AND IT IS NOT COSMETIC. The bare-metal + # run reaches the console through an emulated 16550 UART, and a serial + # console terminates lines with CRLF; the native run does not. Without + # this the diff reports four differing lines whose visible text is + # identical, which reads as a failure of the claim being tested rather + # than of the transport carrying it. The assertion is about what the + # program printed, not about how the bytes arrived. + diff <(grep -E '^(sorted|caught|unwound|import std over openkal):' out.log | tr -d '\r') \ + <(grep -E '^(sorted|caught|unwound|import std over openkal):' host.log | tr -d '\r') # ⭐⭐ AND THE SAME SOURCE FOR TWO MACHINES THIS ONE IS NOT. #