Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
101 changes: 23 additions & 78 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ on:
workflow_dispatch:

env:
MCPP_VERSION: 2026.8.19.4
MCPP_VERSION: 2026.8.24.4
XLINGS_VERSION: v2026.8.17.2
XLINGS_NON_INTERACTIVE: '1'

Expand Down Expand Up @@ -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: |
Expand All @@ -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
Expand All @@ -195,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.
#
Expand Down Expand Up @@ -398,25 +362,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
Expand Down
72 changes: 40 additions & 32 deletions mcpp.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,39 +18,47 @@ 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 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
# 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.
#
Expand Down
Loading