@@ -51,64 +51,31 @@ jobs:
5151 echo "$HOME/.xlings/subos/current/bin" >> "$GITHUB_PATH"
5252
5353 - name : Install mcpp
54+ run : bash tools/install-mcpp.sh
55+
56+ # ⭐ THE ENGINE EVERY STEP BELOW WILL USE, COMPARED AGAINST THE ONE BUILT.
57+ #
58+ # The step above appends a directory to GITHUB_PATH, which governs the
59+ # steps that follow it, so that step cannot observe its own effect. Whether
60+ # the appended spelling is one the runner accepts is a property of the
61+ # runner and differs between hosts. Left unasserted, a cross-validation run
62+ # on a host that ignores it builds this ecosystem with the released engine
63+ # and reports the result as though the change under review had been tested.
64+ - name : The engine on PATH is the one under review
5465 run : |
55- # THE PIN MAY NAME A RELEASE THIS RUN IS VALIDATING, which does not
56- # exist yet --- that is what MCPP_SOURCE_REF is for. Bootstrap from
57- # whatever the index has; the block below replaces it with the build
58- # under review, and the pin is what an ordinary run tests.
59- if [ -n "${MCPP_SOURCE_REF:-}" ]; then
60- xlings update > /dev/null 2>&1 || true
61- xlings install mcpp -y -g
62- else
63- for attempt in 1 2 3 4 5 6; do
64- xlings update > /dev/null 2>&1 || true
65- if xlings install "mcpp@$MCPP_VERSION" -y -g; then break; fi
66- if [ "$attempt" = 6 ]; then
67- echo "::error::mcpp@$MCPP_VERSION never appeared in the index"; exit 1
68- fi
69- sleep 60
70- done
66+ set -euo pipefail
67+ if [ -z "${MCPP_UNDER_REVIEW:-}" ]; then
68+ echo " no source reference: this run tests $(mcpp --version)"
69+ exit 0
7170 fi
72- mcpp --version
73- mcpp self config --mirror GLOBAL
74-
75- # CROSS-VALIDATION: BUILD THE mcpp UNDER REVIEW AND USE THAT ONE.
76- #
77- # Empty in the ordinary run, so this job keeps testing the released
78- # mcpp the pin above names. Set it --- through the workflow_dispatch
79- # input or the repository variable --- and the same job runs against
80- # that source.
81- #
82- # THIS REPOSITORY HAD NO SUCH MECHANISM WHILE EVERY OTHER ONE IN THE
83- # ECOSYSTEM DID, so an engine change could be validated against seven
84- # repositories and not against the one that carries a C++ standard
85- # library. That is the repository where a change to how a target side
86- # is assembled shows first, because a standard library is configured
87- # for one C library and compiled against its headers.
88- #
89- # The released mcpp installed above is the bootstrap that compiles it;
90- # mcpp builds itself and there is no other compiler for it here.
91- if [ -n "${MCPP_SOURCE_REF:-}" ]; then
92- src="$RUNNER_TEMP/mcpp-src"
93- [ -d "$src" ] || git clone --quiet --depth 1 \
94- --branch "$MCPP_SOURCE_REF" \
95- https://github.com/mcpp-community/mcpp.git "$src"
96- # The clone's own workspace pin must not decide which mcpp builds it.
97- # `.xlings.json` at mcpp's root pins the mcpp that compiles mcpp and
98- # does not move when mcpp is released, so a build inside the checkout
99- # obeys it and tries to install a version the index may no longer
100- # carry. What is wanted is the source compiled by the mcpp installed
101- # above, which is what removing the file leaves.
102- rm -f "$src/.xlings.json"
103- ( cd "$src" && mcpp build --release )
104- built=$(find "$src/target" -type f \
105- \( -name mcpp -o -name mcpp.exe \) | head -1)
106- [ -n "$built" ] || { echo "::error::mcpp did not build from $MCPP_SOURCE_REF"; exit 1; }
107- echo "$(cd "$(dirname "$built")" && pwd)" >> "$GITHUB_PATH"
108- # Reported, because a PATH entry that does not win looks exactly like
109- # one that does until something is built with the wrong engine.
110- echo "under review: $("$built" --version) (from $MCPP_SOURCE_REF)"
71+ on_path=$(mcpp --version | awk '{print $2}')
72+ if [ "$on_path" != "$MCPP_UNDER_REVIEW" ]; then
73+ echo "::error::PATH resolves mcpp $on_path, and the build under review is $MCPP_UNDER_REVIEW"
74+ echo " the directory appended to GITHUB_PATH did not take effect on this host"
75+ command -v mcpp
76+ exit 1
11177 fi
78+ echo " every step below runs $on_path, built from $MCPP_SOURCE_REF"
11279
11380 - name : Select the toolchain
11481 run : |
@@ -117,91 +84,9 @@ jobs:
11784 mcpp toolchain default "$spec"
11885
11986 # THE C LIBRARY THIS RUNTIME IS CONFIGURED FOR, AS WRITTEN ON THE BRANCH
120- # UNDER TEST RATHER THAN AS PUBLISHED.
121- #
122- # This package declares openkal-musl by version, which is what a published
123- # manifest must say. A change that spans the two repositories cannot be
124- # tested that way: the version named here does not exist in the index until
125- # the other half is released, and the run fails with
126- #
127- # E_NOT_FOUND: package 'openkal-musl@<version>' not found in the
128- # synced index
129- #
130- # --- which reads as a mistake in this manifest and is nothing of the kind.
131- #
132- # The other repositories in this ecosystem solve it by substituting a
133- # working tree, and this one now does the same. The substitution is
134- # asserted rather than assumed: one that matched nothing would leave the
135- # manifest naming a version, the resolver would fetch a published C
136- # library, and the run would report on that one while appearing to report
137- # on this branch.
138- - name : The C library, as written on this branch
139- run : |
140- set -euo pipefail
141- branch='${{ github.head_ref || github.ref_name }}'
142- git clone --quiet https://github.com/mcpplibs/openkal-musl.git .musl
143- if git -C .musl rev-parse --verify --quiet "origin/$branch" > /dev/null; then
144- git -C .musl checkout --quiet "origin/$branch"
145- echo "openkal-musl is at $branch $(git -C .musl rev-parse --short HEAD)"
146- else
147- echo "openkal-musl has no $branch; its default branch is used" \
148- "($(git -C .musl rev-parse --short HEAD))"
149- fi
150-
151- # openkal-musl reaches the specification by whatever its own manifest
152- # says. That becomes the same working tree, so that the whole stack
153- # under test is the one written on this branch.
154- git clone --quiet https://github.com/mcpplibs/openkal.git .spec
155- if git -C .spec rev-parse --verify --quiet "origin/$branch" > /dev/null; then
156- git -C .spec checkout --quiet "origin/$branch"
157- fi
158-
159- # ⚠️ EVERY BACKEND THE C LIBRARY NAMES, DISCOVERED RATHER THAN LISTED.
160- #
161- # openkal-musl names a backend per target: linux, macos, windows and
162- # opensbi, each conditional. Their versions all move with a change that
163- # spans these repositories, so each one left unsubstituted fails the
164- # same way, one link further down:
165- #
166- # E_NOT_FOUND: package 'openkal-linux@0.6.0' (the host build)
167- # E_NOT_FOUND: package 'openkal-opensbi@0.2.0' (the bare-metal one)
168- #
169- # I fixed the first by naming it, and the second appeared. A list
170- # written by hand is a list that is one entry short, so the set is read
171- # out of the manifest instead.
172- for backend in $(grep -oE '^openkal-[a-z]+ = \{ version' .musl/mcpp.toml | cut -d' ' -f1); do
173- git clone --quiet "https://github.com/mcpplibs/$backend.git" ".$backend"
174- if git -C ".$backend" rev-parse --verify --quiet "origin/$branch" > /dev/null; then
175- git -C ".$backend" checkout --quiet "origin/$branch"
176- fi
177- here="$(cd ".$backend" && pwd)"
178- # The backend reaches the specification too, and by whatever form its
179- # own manifest uses.
180- sed -i -E "s|^openkal = .*$|openkal = { path = \"$(cd .spec && pwd)\" }|" ".$backend/mcpp.toml"
181- sed -i -E "s|^$backend = \\{ version = \"[^\"]*\"(.*)$|$backend = { path = \"$here\"\\1|" \
182- .musl/mcpp.toml
183- grep -q "path = \"$here\"" .musl/mcpp.toml \
184- || { echo "::error::$backend was not substituted"; exit 1; }
185- echo " $backend -> working tree"
186- done
187-
188- spec="$(cd .spec && pwd)"
189- musl="$(cd .musl && pwd)"
190- sed -i -E "s|^openkal = .*$|openkal = { path = \"$spec\" }|" .musl/mcpp.toml
191- sed -i -E "s|^openkal-musl = .*$|openkal-musl = { path = \"$musl\" }|" mcpp.toml
192-
193- grep -q "path = \"$musl\"" mcpp.toml \
194- || { echo "::error::the C library substitution matched nothing"; exit 1; }
195- grep -q "path = \"$spec\"" .musl/mcpp.toml \
196- || { echo "::error::the specification substitution matched nothing"; exit 1; }
197-
198- # ⚠️ THE LAST CHECK IS THE ONE THAT WOULD HAVE CAUGHT BOTH FAILURES:
199- # nothing anywhere in the substituted graph still names a version.
200- if grep -nE '^openkal[a-z-]* = (\"|\{ version)' .musl/mcpp.toml mcpp.toml; then
201- echo "::error::something in the graph still names a version rather than a tree"
202- exit 1
203- fi
204- echo "the whole stack names working trees, and nothing in it names a version"
87+ # UNDER TEST RATHER THAN AS PUBLISHED. The reasoning is in the script.
88+ - name : The stack, as written on this branch
89+ run : bash tools/branch-graph.sh '${{ github.head_ref || github.ref_name }}'
20590
20691 - name : The runtime builds
20792 run : mcpp build
@@ -581,23 +466,49 @@ jobs:
581466 "$env:USERPROFILE\.xlings\subos\current\bin" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append
582467
583468 - name : Install mcpp
469+ run : bash tools/install-mcpp.sh
470+
471+ # ⭐ THE ENGINE EVERY STEP BELOW WILL USE, COMPARED AGAINST THE ONE BUILT.
472+ #
473+ # The step above appends a directory to GITHUB_PATH, which governs the
474+ # steps that follow it, so that step cannot observe its own effect. Whether
475+ # the appended spelling is one the runner accepts is a property of the
476+ # runner and differs between hosts. Left unasserted, a cross-validation run
477+ # on a host that ignores it builds this ecosystem with the released engine
478+ # and reports the result as though the change under review had been tested.
479+ - name : The engine on PATH is the one under review
584480 run : |
585- for attempt in 1 2 3 4 5 6; do
586- xlings update > /dev/null 2>&1 || true
587- if xlings install "mcpp@$MCPP_VERSION" -y -g; then break; fi
588- if [ "$attempt" = 6 ]; then
589- echo "::error::mcpp@$MCPP_VERSION never appeared in the index"
590- exit 1
591- fi
592- sleep 60
593- done
594- mcpp self config --mirror GLOBAL
481+ set -euo pipefail
482+ if [ -z "${MCPP_UNDER_REVIEW:-}" ]; then
483+ echo " no source reference: this run tests $(mcpp --version)"
484+ exit 0
485+ fi
486+ on_path=$(mcpp --version | awk '{print $2}')
487+ if [ "$on_path" != "$MCPP_UNDER_REVIEW" ]; then
488+ echo "::error::PATH resolves mcpp $on_path, and the build under review is $MCPP_UNDER_REVIEW"
489+ echo " the directory appended to GITHUB_PATH did not take effect on this host"
490+ command -v mcpp
491+ exit 1
492+ fi
493+ echo " every step below runs $on_path, built from $MCPP_SOURCE_REF"
494+
495+ # ⭐ THE SAME ENGINE AND THE SAME STACK AS THE LINUX JOB, FROM A DIFFERENT
496+ # HOST. This job had neither: it installed the released engine and
497+ # resolved this ecosystem from the index, so a change spanning these
498+ # repositories was validated on one host of three and reported as
499+ # validated everywhere.
500+ - name : Select the toolchain
501+ run : |
502+ set -euo pipefail
595503 # ⚠️ INSTALL, THEN SELECT. `toolchain default` names a toolchain and
596504 # does not fetch one, so selecting an absent payload fails with
597505 # `llvm@22.1.8 is not installed` — measured on both rows of this job.
598506 mcpp toolchain install llvm 22.1.8
599507 mcpp toolchain default 'llvm@22.1.8'
600508
509+ - name : The stack, as written on this branch
510+ run : bash tools/branch-graph.sh '${{ github.head_ref || github.ref_name }}'
511+
601512 - name : Every target, from this host
602513 run : |
603514 set -euo pipefail
0 commit comments