Skip to content

Commit 2d9890d

Browse files
committed
0.8.1 — the backend existed and the one-line usage could not reach it
⚠️⚠️ 0.8.0 SHIPPED `openarch-cortex-m`, DECLARED ITS CAPABILITIES, AND EXERCISED IT — FROM AN EXAMPLE THAT NAMES IT BY PATH. The documented one-line usage is `openarch = "<version>"`, which goes through the `backend-auto` feature: a table in the ROOT manifest that binds a target's arch to a backend. That table was never extended. Measured from a fresh project against the published 0.8.0: error: no package provides capability 'openarch-backend' required by 'openarch' The package was in the tarball and unreachable through the only usage a consumer is told about. ⭐ The lesson is the one a new capability always carries: it has more readers than the site that introduced it, and the file that BINDS it is not the file that DECLARES it. `examples/preempt` could not have caught this — it names the backend by path, which is precisely the door a consumer does not have. ## Five rows, because `cfg(arch = ...)` compares exactly There is no glob, and "Cortex-M" is not an instruction set: mcpp spells each M-profile row's arch differently (`thumbv6m`, `thumbv7m`, `thumbv7em`, `thumbv8m.base`, `thumbv8m.main`) because objects built for them are not interchangeable. `backend-cortex-m` is added beside the other three named features for a consumer that wants the choice written down. ## The check is the usage, not the backend CI builds five fresh projects — one per arch spelling — whose whole manifest is `openarch = { path = … }`, and requires each to compile the backend. A/B on this tree: 0 backend compile lines before, 14 after, on every one of the five.
1 parent edec008 commit 2d9890d

3 files changed

Lines changed: 83 additions & 4 deletions

File tree

‎.github/workflows/ci.yml‎

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -488,6 +488,44 @@ jobs:
488488
[ "$rc" = "0" ] \
489489
|| { echo "the scheduler reported success and exited $rc — check the semihosting exit call"; exit 1; }
490490
491+
# ⭐⭐ THE ONE-LINE USAGE REACHES THIS BACKEND, WHICH IS A DIFFERENT CLAIM
492+
# FROM "THE BACKEND WORKS".
493+
#
494+
# `examples/preempt` names `openarch-cortex-m` by PATH, so it exercises
495+
# the backend and says nothing about whether a CONSUMER can get it. The
496+
# documented one-line usage is `openarch = "<version>"`, and that goes
497+
# through `backend-auto` — a table in the ROOT manifest that is a
498+
# different file from the one declaring the backend.
499+
#
500+
# Measured on 0.8.0 as first written: a fresh project against the
501+
# published package got
502+
#
503+
# error: no package provides capability 'openarch-backend'
504+
#
505+
# The backend was in the tarball and unreachable. `cfg(arch = ...)`
506+
# compares exactly and there is no glob, so M-profile needs one row per
507+
# arch spelling; this step is what keeps all five bound.
508+
- name: The one-line usage reaches the Cortex-M backend
509+
run: |
510+
set -euo pipefail
511+
n=0
512+
for t in thumbv6m-none-eabi thumbv7m-none-eabi thumbv7em-none-eabi \
513+
thumbv8m.base-none-eabi thumbv8m.main-none-eabi; do
514+
D=$(mktemp -d); mkdir -p "$D/src"
515+
printf '[package]\nname="oap"\nversion="0.1.0"\n[build]\ntarget="%s"\nsources=["src/main.cpp"]\n[target.%s]\nsysroot=""\n[dependencies]\nopenarch = { path = "%s" }\n' \
516+
"$t" "$t" "$PWD" > "$D/mcpp.toml"
517+
printf 'int main(){return 0;}\n' > "$D/src/main.cpp"
518+
( cd "$D" && mcpp build --verbose > v.log 2>&1 ) || true
519+
c=$(grep -c 'openarch-cortex-m' "$D/v.log" || true)
520+
[ "$c" -gt 0 ] || {
521+
echo "::error::$t resolved no Cortex-M backend through backend-auto"
522+
tail -20 "$D/v.log"; exit 1; }
523+
echo " ok $t binds the backend ($c compile lines)"
524+
n=$((n+1)); rm -rf "$D"
525+
done
526+
# A count, because a loop that ran zero times also reaches this line.
527+
[ "$n" = "5" ] || { echo "::error::checked $n arch spellings, expected 5"; exit 1; }
528+
491529
# ⭐ THE EXAMPLE CONTAINS NO ASSEMBLY, AND THAT IS AN ASSERTION RATHER
492530
# THAN A REMARK. Its first version hand-wrote thirty lines of PendSV,
493531
# because the layer had no primitive for "switch the context this trap

‎README.md‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,7 @@ answer as `MAIR_EL1`, arrived at for a different reason.
161161
| The switch reaches, returns and preserves; traps classify; per-CPU round-trips; four barriers are accepted | One probe source, three emulators, in CI |
162162
| A trap resumes a **different** context | The same probe, on all three; the assertion is a counter the *other* context advanced, not that both printed |
163163
| The partial backend preempts | `examples/preempt` on `mps2-an385`, in its own job: two tasks that never yield, each proving it was interrupted |
164+
| The one-line usage REACHES that backend | Five fresh projects, one per M-profile arch spelling: `openarch = "<version>"` and nothing else must pull the backend in |
164165
| The entry encodings | A host unit test that holds **all three** encoders at once |
165166
| The two faces declare one library | A host test of `static_assert`s, on a machine with no backend at all |
166167
| The ABI's frozen layout | `tests/abi_shape.cpp`, in byte offsets rather than in `sizeof` of another member |

‎mcpp.toml‎

Lines changed: 44 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@
3333
[package]
3434
namespace = "mcpplibs"
3535
name = "openarch"
36-
version = "0.8.0"
36+
version = "0.8.1"
3737
description = "openarch: the architecture-mechanism layer — execution contexts, traps, per-CPU state and address spaces, as one interface over several instruction sets"
3838
license = "Apache-2.0"
3939
authors = ["mcpplibs"]
@@ -142,9 +142,10 @@ default = ["backend-auto"]
142142
backend-auto = []
143143
backend-external = { requires = ["openarch-backend"] }
144144

145-
backend-riscv64 = []
146-
backend-aarch64 = []
147-
backend-x86-64 = []
145+
backend-riscv64 = []
146+
backend-aarch64 = []
147+
backend-x86-64 = []
148+
backend-cortex-m = []
148149

149150
[target.'cfg(all(arch = "riscv64", os = "none"))'.feature-deps.backend-auto]
150151
openarch-riscv64 = { path = "backends/riscv64" }
@@ -155,6 +156,42 @@ openarch-aarch64 = { path = "backends/aarch64" }
155156
[target.'cfg(all(arch = "x86_64", os = "none"))'.feature-deps.backend-auto]
156157
openarch-x86-64 = { path = "backends/x86_64" }
157158

159+
# ⚠️⚠️ SEVEN ROWS FOR ONE BACKEND, AND THAT IS THE MACHINE RATHER THAN A CHOICE.
160+
#
161+
# `cfg(arch = ...)` compares exactly — there is no glob — and "Cortex-M" is not
162+
# an instruction set: mcpp spells each M-profile row's arch differently
163+
# (`thumbv6m`, `thumbv7m`, `thumbv7em`, `thumbv8m.base`, `thumbv8m.main`)
164+
# because objects built for them are not interchangeable.
165+
#
166+
# ⚠️ THE BACKEND EXISTED BEFORE THIS TABLE KNEW ABOUT IT, WHICH IS THE WORST
167+
# SHAPE THIS ARRANGEMENT CAN HAVE. 0.8.0 shipped `openarch-cortex-m`, declared
168+
# its capabilities, and exercised it from `examples/preempt` — which names the
169+
# backend by PATH. A consumer of the published package writes
170+
# `openarch = "0.8.0"` and got no backend at all: the package was present in the
171+
# tarball and unreachable through the documented one-line usage. Measured from a
172+
# fresh project against the published index:
173+
#
174+
# error: no package provides capability 'openarch-backend' required by
175+
# 'openarch'
176+
#
177+
# ⭐ The lesson is the one a new capability always carries: it has more readers
178+
# than the site that introduced it, and the table that BINDS it is a different
179+
# file from the one that DECLARES it.
180+
[target.'cfg(all(arch = "thumbv6m", os = "none"))'.feature-deps.backend-auto]
181+
openarch-cortex-m = { path = "backends/cortex-m" }
182+
183+
[target.'cfg(all(arch = "thumbv7m", os = "none"))'.feature-deps.backend-auto]
184+
openarch-cortex-m = { path = "backends/cortex-m" }
185+
186+
[target.'cfg(all(arch = "thumbv7em", os = "none"))'.feature-deps.backend-auto]
187+
openarch-cortex-m = { path = "backends/cortex-m" }
188+
189+
[target.'cfg(all(arch = "thumbv8m.base", os = "none"))'.feature-deps.backend-auto]
190+
openarch-cortex-m = { path = "backends/cortex-m" }
191+
192+
[target.'cfg(all(arch = "thumbv8m.main", os = "none"))'.feature-deps.backend-auto]
193+
openarch-cortex-m = { path = "backends/cortex-m" }
194+
158195
# Named explicitly, so unconditional: asking for a backend by name on a target
159196
# it does not serve should fail while assembling it, not resolve to nothing.
160197
[feature-deps.backend-riscv64]
@@ -165,3 +202,6 @@ openarch-aarch64 = { path = "backends/aarch64" }
165202

166203
[feature-deps.backend-x86-64]
167204
openarch-x86-64 = { path = "backends/x86_64" }
205+
206+
[feature-deps.backend-cortex-m]
207+
openarch-cortex-m = { path = "backends/cortex-m" }

0 commit comments

Comments
 (0)