|
41 | 41 | # carries it, and the row is now the same shape as the other two. |
42 | 42 | - { arch: x86_64, triple: x86_64-none-elf, qemu: 'xim:qemu-x86' } |
43 | 43 | env: |
44 | | - MCPP_VERSION: 2026.8.21.1 |
| 44 | + MCPP_VERSION: 2026.8.21.2 |
45 | 45 | XLINGS_VERSION: v2026.8.17.2 |
46 | 46 | XLINGS_NON_INTERACTIVE: '1' |
47 | 47 | steps: |
@@ -110,6 +110,33 @@ jobs: |
110 | 110 | # The three packages are different builds, one per target family: |
111 | 111 | # `qemu-riscv` carries the RISC-V emulators, `qemu-arm` the Arm ones and |
112 | 112 | # `qemu-x86` the x86_64 one. Measured; no single package runs all three. |
| 113 | + # ⭐ BEFORE THE EMULATOR IS INSTALLED, AND THAT ORDER IS THE ASSERTION. |
| 114 | + # |
| 115 | + # `[xlings] deps` is a DECLARATION, not an install trigger, so on a clean |
| 116 | + # machine `xpkg_dir` answers empty and this project's build program |
| 117 | + # configures no runner. That is correct and it used to be SILENT: mcpp |
| 118 | + # prints a build program's output only on a non-zero exit, so a |
| 119 | + # `std::cerr` note printed nothing on exactly the builds that needed it. |
| 120 | + # |
| 121 | + # mcpp 2026.8.21.2's `mcpp::warning()` is the channel. This step is the |
| 122 | + # only place the ecosystem can observe it, because every later step has |
| 123 | + # the emulator — so it runs here, once, and asserts the sentence a first |
| 124 | + # -time user sees. |
| 125 | + - name: A clean machine is told what is missing |
| 126 | + working-directory: examples/switch |
| 127 | + run: | |
| 128 | + set -euo pipefail |
| 129 | + COLD=$(mktemp -d) |
| 130 | + MCPP_HOME="$COLD" mcpp build --target ${{ matrix.triple }} 2>&1 | tee cold.log |
| 131 | + grep -q "is not installed" cold.log \ |
| 132 | + || { cat cold.log; echo "the build program said nothing about the missing emulator"; exit 1; } |
| 133 | + grep -q "xlings install" cold.log \ |
| 134 | + || { cat cold.log; echo "the advisory does not name the command that fixes it"; exit 1; } |
| 135 | + # An advisory is not an error: the build still succeeded. |
| 136 | + grep -q "Finished" cold.log \ |
| 137 | + || { cat cold.log; echo "the build did not finish"; exit 1; } |
| 138 | + rm -rf "$COLD" target |
| 139 | +
|
113 | 140 | - name: Install the emulator |
114 | 141 | run: | |
115 | 142 | xlings install ${{ matrix.qemu }} -y |
@@ -188,7 +215,10 @@ jobs: |
188 | 215 | # while mcpp wants a native path — a mismatch this repository has been |
189 | 216 | # bitten by before. |
190 | 217 | - name: The template generates a project that builds for all three machines |
191 | | - if: matrix.arch == 'riscv64' |
| 218 | + # The claim here is host-independent — the template's CONTENT builds for |
| 219 | + # all three machines — so one row is the right place for it. The per-row |
| 220 | + # claim, that it RUNS, is the separate step below. |
| 221 | + if: matrix.arch == 'riscv64' # ci-lint: allow-r1: host-independent claim |
192 | 222 | run: | |
193 | 223 | set -euo pipefail |
194 | 224 | T=templates/three-machines |
@@ -255,6 +285,39 @@ jobs: |
255 | 285 | # The same source produced that output. Asserted rather than trusted: a |
256 | 286 | # probe that had quietly grown a per-architecture branch would still pass |
257 | 287 | # every line above, and the gate would be measuring two programs. |
| 288 | + # ⚠️ ONE PIECE OF LOGIC LIVING IN TWO FILES IS WHAT SHIPPED 0.5.0's DEFECT: |
| 289 | + # the example's build program was updated and the template's copy was not, |
| 290 | + # so the template's README claimed something its own program could not do. |
| 291 | + # |
| 292 | + # The fix is not "be more careful" — that had already been tried once. The |
| 293 | + # pairs are declared in `.ci-identical-files` and asserted here. |
| 294 | + - name: Files declared identical are identical |
| 295 | + run: | |
| 296 | + set -euo pipefail |
| 297 | + test -s .ci-identical-files |
| 298 | + n=0 |
| 299 | + while IFS=$'\t' read -r a b marker; do |
| 300 | + case "${a:-}" in ''|'#'*) continue ;; esac |
| 301 | + test -f "$a" && test -f "$b" || { echo "declared pair missing a side: $a / $b"; exit 1; } |
| 302 | + # ⚠️ `grep -F` + `tail`, NOT a sed address. The marker is a line of |
| 303 | + # C++ and contains `/`, which sed reads as the end of its pattern — |
| 304 | + # measured: `unknown command: '/'`, both sides empty, and the diff |
| 305 | + # would then have PASSED. That is the emptiness-as-success shape |
| 306 | + # this repository has already been bitten by once. |
| 307 | + la=$(grep -nF -m1 "$marker" "$a" | cut -d: -f1) |
| 308 | + lb=$(grep -nF -m1 "$marker" "$b" | cut -d: -f1) |
| 309 | + test -n "$la" && test -n "$lb" \ |
| 310 | + || { echo "marker '$marker' not found in $a or $b"; exit 1; } |
| 311 | + tail -n +"$la" "$a" > /tmp/ia |
| 312 | + tail -n +"$lb" "$b" > /tmp/ib |
| 313 | + test -s /tmp/ia && test -s /tmp/ib \ |
| 314 | + || { echo "marker '$marker' matched an empty tail in $a or $b"; exit 1; } |
| 315 | + diff -u /tmp/ia /tmp/ib || { echo "$a and $b diverge after '$marker'"; exit 1; } |
| 316 | + n=$((n+1)) |
| 317 | + done < .ci-identical-files |
| 318 | + test "$n" -ge 1 || { echo ".ci-identical-files declared no pairs"; exit 1; } |
| 319 | + echo "$n declared pair(s) identical" |
| 320 | +
|
258 | 321 | - name: The probe is one source, and the layering is a directory tree |
259 | 322 | run: | |
260 | 323 | set -euo pipefail |
@@ -347,7 +410,7 @@ jobs: |
347 | 410 | run: |
348 | 411 | shell: bash |
349 | 412 | env: |
350 | | - MCPP_VERSION: 2026.8.21.1 |
| 413 | + MCPP_VERSION: 2026.8.21.2 |
351 | 414 | XLINGS_VERSION: v2026.8.17.2 |
352 | 415 | XLINGS_NON_INTERACTIVE: '1' |
353 | 416 | steps: |
@@ -437,7 +500,7 @@ jobs: |
437 | 500 | run: |
438 | 501 | shell: bash |
439 | 502 | env: |
440 | | - MCPP_VERSION: 2026.8.21.1 |
| 503 | + MCPP_VERSION: 2026.8.21.2 |
441 | 504 | XLINGS_VERSION: v2026.8.17.2 |
442 | 505 | XLINGS_NON_INTERACTIVE: '1' |
443 | 506 | steps: |
|
0 commit comments