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
72 changes: 51 additions & 21 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -169,17 +169,25 @@ jobs:
# unresolvable here — this version is not published yet, and a check that
# silently fell back to the previous one would be testing the wrong tree.
#
# ⚠️ IN THE `gate` JOB'S riscv64 ROW, AND THE PLACEMENT IS THE FIX FOR A
# MISTAKE. 0.4.0 put this in `host-encoders`, which installs no emulator —
# ⚠️ IN THE `gate` JOB, AND THE PLACEMENT IS THE FIX FOR A MISTAKE MADE
# TWICE. 0.4.0 put this in `host-encoders`, which installs no emulator —
# so the check could only ever assert `mcpp build`, and a generated project
# that ran on nothing passed it. The emulator lives here.
#
# One row rather than all three: the template's CONTENT is
# ⚠️ AND 0.5.0 MADE THE SAME MISTAKE ONE SIZE SMALLER. This step ran only
# in the riscv64 row, which installs only the RISC-V emulator, so the
# claim it could support was "the template runs on riscv64" while the
# template's README had begun to claim all three. It did not: the
# template's own `build.mcpp.in` was left with x86_64's old early return,
# and nothing here could see that. The RUN half is per-row from 0.5.1 —
# each row asserts the machine whose emulator it installed.
#
# The BUILD half stays on one row: the template's CONTENT is
# host-independent, and the rewrite below puts `$PWD` into a manifest,
# which on a Windows runner is `/d/a/openarch/openarch` under Git Bash
# while mcpp wants a native path — a mismatch this repository has been
# bitten by before.
- name: The template generates a project that builds for all three machines and runs
- name: The template generates a project that builds for all three machines
if: matrix.arch == 'riscv64'
run: |
set -euo pipefail
Expand All @@ -202,25 +210,47 @@ jobs:
done
echo "the template builds for riscv64, aarch64 and x86_64"

# ⚠️ AND IT MUST RUN, NOT ONLY BUILD — THIS ASSERTION IS HERE BECAUSE
# ITS ABSENCE SHIPPED A BROKEN QUICK START.
#
# 0.4.0's check stopped at `mcpp build`, so a generated project that
# compiled for all three machines and ran on none of them passed. What
# was missing is not in the sources: `mcpp.toml` declares the emulator
# packages under `[xlings] deps`, which is not an install trigger, so
# on a machine that has not installed them `build.mcpp` finds nothing
# and configures no runner. Measured against a freshly unpacked mcpp.
#
# This job installs the emulator in an earlier step, so the run below
# exercises the path a user gets AFTER the README's one-time install.
# What it cannot cover is the before — see the note in the README, and
# the comment in build.mcpp on why a build program cannot warn.
( cd "$D" && mcpp run --target riscv64-none-elf 2>&1 | tee run.log ) \
|| { cat "$D/run.log"; echo "the generated project does not run"; exit 1; }
# ⚠️ AND IT MUST RUN, NOT ONLY BUILD — THIS ASSERTION EXISTS BECAUSE ITS
# ABSENCE SHIPPED A BROKEN QUICK START, AND IT IS PER-ROW BECAUSE ITS
# BEING ON ONE ROW SHIPPED A SECOND ONE.
#
# 0.4.0's check stopped at `mcpp build`, so a generated project that
# compiled for all three machines and ran on none of them passed. What was
# missing is not in the sources: `mcpp.toml` declares the emulator packages
# under `[xlings] deps`, which is not an install trigger, so on a machine
# that has not installed them `build.mcpp` finds nothing and configures no
# runner.
#
# Each row installs one emulator, so each row asserts one machine. A row
# cannot assert a machine whose emulator it does not have — which is the
# whole reason the previous arrangement could not see that the template's
# `build.mcpp.in` still had x86_64's early return in it.
#
# This job installs the emulator in an earlier step, so the run below
# exercises the path a user gets AFTER the README's one-time install. What
# it cannot cover is the before — see the note in the README, and the
# comment in build.mcpp on why a build program cannot warn.
- name: The template's project runs on ${{ matrix.arch }}, not only builds
run: |
set -euo pipefail
T=templates/three-machines
V=$(grep -m1 '^version' mcpp.toml | cut -d'"' -f2)
D=$(mktemp -d); mkdir -p "$D/src"
for f in mcpp.toml README.md build.mcpp; do
sed -e "s/{{project\.name}}/k/g" -e "s/{{self\.version}}/$V/g" \
"$T/$f.in" > "$D/$f"
done
cp "$T"/*.ld "$D/"
cp "$T"/src/* "$D/src/"
sed -i.bak "s|openarch = \"$V\"|openarch = { path = \"$PWD\" }|" "$D/mcpp.toml"
rm -f "$D/mcpp.toml.bak"
grep -q "path = " "$D/mcpp.toml" || { cat "$D/mcpp.toml"; echo "the dependency rewrite did not apply"; exit 1; }
( cd "$D" && mcpp build --target ${{ matrix.triple }} > /dev/null 2>&1 ) || true
( cd "$D" && mcpp run --target ${{ matrix.triple }} 2>&1 | tee run.log ) \
|| { cat "$D/run.log"; echo "the generated project does not run on ${{ matrix.arch }}"; exit 1; }
grep -q "switch ok" "$D/run.log" \
|| { cat "$D/run.log"; echo "the generated project ran without reaching the end"; exit 1; }
echo "the template's project runs, not only builds"
echo "the template's project runs on ${{ matrix.arch }}"

# The same source produced that output. Asserted rather than trusted: a
# probe that had quietly grown a per-architecture branch would still pass
Expand Down
2 changes: 1 addition & 1 deletion abi/mcpp.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
[package]
namespace = "mcpplibs"
name = "openarch-abi"
version = "0.5.0"
version = "0.5.1"
description = "openarch's C ABI: the contract between the interface and an instruction set's backend"
license = "Apache-2.0"
authors = ["mcpplibs"]
Expand Down
2 changes: 1 addition & 1 deletion backends/aarch64/mcpp.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
[package]
namespace = "mcpplibs"
name = "openarch-aarch64"
version = "0.5.0"
version = "0.5.1"
description = "openarch's aarch64 backend: the instructions behind the ABI"
license = "Apache-2.0"
authors = ["mcpplibs"]
Expand Down
2 changes: 1 addition & 1 deletion backends/riscv64/mcpp.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
[package]
namespace = "mcpplibs"
name = "openarch-riscv64"
version = "0.5.0"
version = "0.5.1"
description = "openarch's riscv64 backend: the instructions behind the ABI"
license = "Apache-2.0"
authors = ["mcpplibs"]
Expand Down
2 changes: 1 addition & 1 deletion backends/x86_64/mcpp.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
[package]
namespace = "mcpplibs"
name = "openarch-x86-64"
version = "0.5.0"
version = "0.5.1"
description = "openarch's x86_64 backend: the instructions behind the ABI"
license = "Apache-2.0"
authors = ["mcpplibs"]
Expand Down
2 changes: 1 addition & 1 deletion mcpp.toml
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
[package]
namespace = "mcpplibs"
name = "openarch"
version = "0.5.0"
version = "0.5.1"
description = "openarch: the architecture-mechanism layer — execution contexts, traps, per-CPU state and address spaces, as one interface over several instruction sets"
license = "Apache-2.0"
authors = ["mcpplibs"]
Expand Down
47 changes: 27 additions & 20 deletions templates/three-machines/build.mcpp.in
Original file line number Diff line number Diff line change
Expand Up @@ -30,25 +30,25 @@ int main() {
// against whichever home owns it, which is not necessarily the home this
// build is using.
//
// The two packages are different — xPack builds QEMU per target family, so
// `qemu-riscv` carries only the two RISC-V emulators and `qemu-arm` only
// the two Arm ones. There is no single package that runs both machines.
// ⚠️ x86_64 IS ABSENT FROM THIS TABLE, AND THE ABSENCE IS THE ECOSYSTEM'S
// RATHER THAN THIS PROBE'S. xPack publishes QEMU per target family, and the
// index carries `qemu-riscv` and `qemu-arm` because those are the families
// it publishes. There is no `xim:qemu-x86`, so on that target this build
// program configures no runner and `mcpp build` is the whole of what CI can
// do — which is stated here rather than worked around, because a runner
// silently pointing at a host `qemu-system-x86_64` would make the build
// depend on what happens to be installed.
if (arch == "x86_64") {
mcpp::rerun_if_env_changed("MCPP_TARGET_ARCH");
mcpp::rerun_if_changed("x86_64.ld");
return 0;
}

const char* pkg = (arch == "riscv64") ? "qemu-riscv" : "qemu-arm";
const char* sys = (arch == "riscv64") ? "riscv64" : "aarch64";
// ⭐ THREE PACKAGES, ONE PER MACHINE, AND THAT IS THE ECOSYSTEM'S SHAPE
// RATHER THAN THIS PROBE'S. QEMU is published per target family, so
// `qemu-riscv` carries the RISC-V emulators, `qemu-arm` the Arm ones and
// `qemu-x86` the x86_64 one. No single package runs all three machines,
// which is why this table exists at all.
//
// ⚠️ x86_64 WAS AN EXCEPTION HERE UNTIL 0.5.0, and the exception was the
// absence of a package rather than a property of the machine: with no
// `xim:qemu-x86` this program configured no runner, CI could assert only
// `mcpp build`, and the third machine was the one machine whose findings
// could not be reproduced by running it. `mcpplibs/qemu-x86` builds that
// emulator from source for five hosts and the exception is gone — the row
// below is now the same shape as the other two.
const char* pkg = (arch == "riscv64") ? "qemu-riscv"
: (arch == "aarch64") ? "qemu-arm"
: "qemu-x86";
const char* sys = (arch == "riscv64") ? "riscv64"
: (arch == "aarch64") ? "aarch64"
: "x86_64";
// ⚠️ DECLARED IS NOT INSTALLED, AND THE DIFFERENCE IS INVISIBLE UNTIL
// SOMEBODY BUILDS THIS ON A MACHINE THAT HAS NOT ALREADY GOT THE EMULATOR.
//
Expand Down Expand Up @@ -79,8 +79,14 @@ int main() {
// So the README carries it, and this comment records why it has to.
if (const char* dir = mcpp::xpkg_dir("xim", pkg); dir && *dir) {
mcpp::runner(std::format("{}/bin/qemu-system-{}", dir, sys).c_str());
// ⚠️ THE MACHINE TYPE IS NOT UNIVERSAL. `virt` is the para-virtual
// board the two RISC machines use; x86_64 has no such board and boots
// `q35`, a model of real PC chipset hardware. The image reaches it
// through multiboot rather than through `-kernel`'s raw-image path,
// which is why the linker script for that machine carries an a.out
// kludge the other two do not need.
mcpp::runner("-machine");
mcpp::runner("virt");
mcpp::runner(arch == "x86_64" ? "q35" : "virt");
// ⚠️ aarch64's `virt` has no default CPU that implements the features
// this image needs; riscv's does. Naming one on the machine that
// requires it rather than on both, so that the argument list says which
Expand All @@ -98,5 +104,6 @@ int main() {
mcpp::rerun_if_env_changed("MCPP_TARGET_ARCH");
mcpp::rerun_if_changed("riscv64.ld");
mcpp::rerun_if_changed("aarch64.ld");
mcpp::rerun_if_changed("x86_64.ld");
return 0;
}
Loading