Skip to content

Commit 7f5f0ed

Browse files
authored
0.19.0: one resolver for a member's tool, payloads installed on request, and a toolchain a build program states (#41)
Every member answers one question the same way: where does the tool it runs come from. `mcpp.plugins.tool` answers in one order -- the build program's choice, the member's legacy variable, the engine's override, then the declared payload, asked for there when it is declared `provision = "on-request"`. A choice never asks for the payload, which is what makes "the build program names its own tool" mean "the payload is not downloaded". Every answer is recorded with `mcpp::decision`, so a build reports the source and `mcpp why tool <name>` answers from the same record; `describe_missing` is the one refusal text. Thirteen members use it: deps-vcpkg, deps-cmake, deps-archive, rules-cuda, rules-hip, rules-sycl, rules-ascendc, rules-slang, rules-spirv, rules-qt, dist-apk, dist-appimage, dist-wix. Five entries are installed on request: `xim:vcpkg`, `xim:cmake` (twice), `xim:appimagetool`, `xim:bundletool`. `mcpp.plugins.toolchain` (feature `plugins-toolchain`) builds the statement a root build program makes in a toolchain phase. `mcpp.plugins.testing` gained `xpkg_source`, `xpkg_program` and `phase`, and clears the real build's `MCPP_XPKG_*`. `docs/tool-sources.md` is the reference for both audiences, written as scenarios, with a chapter on replacing the default tool from `build.mcpp`. Engine floor: mcpp 2026.10.1.3 (protocol 15, mcpp-community/mcpp#755). Closes #41
1 parent 34b7af4 commit 7f5f0ed

32 files changed

Lines changed: 2323 additions & 255 deletions

‎.agents/docs/2026-10-01-ecosystem-build-plugin-framework-plan.md‎

Lines changed: 314 additions & 0 deletions
Large diffs are not rendered by default.

‎.github/scripts/check-deps-and-qt.sh‎

Lines changed: 91 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -576,7 +576,97 @@ vcpkg_make_port() {
576576
echo "ok: a make-based port builds with the managed toolset first on the kept PATH"
577577
}
578578

579+
# 0.19.0 (mcpp#755): a tool the build program names is used, and the payload the
580+
# member declares `provision = "on-request"` is NOT asked for.
581+
#
582+
# THE CRITERION IS THE ENGINE'S OWN RECORD, NOT THE STORE. A runner may already
583+
# hold `xim:cmake` -- every other case here installs it -- so "nothing was
584+
# downloaded" cannot be read from the store, and a clean `MCPP_HOME` would cost
585+
# a download per case. `resolution.json` states what each payload's source was
586+
# and whether this build asked for it, which is the decision itself. The pair is
587+
# the criterion: the same project asks for the payload when nothing names a
588+
# tool, and does not when the build program names one.
589+
tool_sources() {
590+
cd "$ROOT/tests/cmake-consumer"
591+
local cmake; cmake=$(command -v cmake || true)
592+
[ -n "$cmake" ] || { echo "SKIP: no cmake on this host to name"; return 0; }
593+
594+
# `considered` of the payload entry, and the class of each subject.
595+
record() {
596+
python3 - <<'PYEOF'
597+
import glob, json, sys
598+
paths = glob.glob("target/*/*/resolution.json")
599+
if not paths:
600+
print("NO-RECORD"); raise SystemExit(0)
601+
doc = json.load(open(sorted(paths)[0]))
602+
for d in doc.get("sources", []):
603+
print(d["subject"], d["class"], "|", "; ".join(d.get("considered", [])), sep="\t")
604+
PYEOF
605+
}
606+
607+
cp build.mcpp build.mcpp.bak
608+
restore() { mv -f build.mcpp.bak build.mcpp 2>/dev/null || true; }
609+
trap restore EXIT
610+
611+
# The control: nothing names a tool, so the member asks for the payload.
612+
rm -rf target
613+
NO_COLOR=1 "$MCPP" build >/dev/null 2>&1 || fail "the control build failed"
614+
record | grep -q "payload:xim:cmake.*installed on request" \
615+
|| fail "the control did not ask for xim:cmake: $(record)"
616+
617+
# The build program names the host's cmake, through the member's option.
618+
python3 - "$cmake" <<'PYEOF'
619+
import pathlib, sys
620+
p = pathlib.Path("build.mcpp")
621+
t = p.read_text()
622+
marker = " o.shared = true;"
623+
assert marker in t, t
624+
p.write_text(t.replace(marker, marker + '\n o.cmake = "%s";' % sys.argv[1].replace("\\", "/"), 1))
625+
PYEOF
626+
rm -rf target
627+
local out
628+
out=$(MCPP_NO_AUTO_INSTALL=1 NO_COLOR=1 "$MCPP" build 2>&1) \
629+
|| fail "a named cmake still needed the payload: $out"
630+
case "$out" in
631+
*"Using cmake (mcpp.deps.cmake)"*"[program · build.mcpp:"*) ;;
632+
*) fail "the build did not report the tool's source: $out" ;;
633+
esac
634+
case "$out" in
635+
*"program: cmake (mcpp.deps.cmake)"*) ;;
636+
*) fail "the Finished line did not summarise the source: $out" ;;
637+
esac
638+
record | grep -q "payload:xim:cmake.*not requested by this build" \
639+
|| fail "the payload was asked for although the program named a cmake: $(record)"
640+
MCPP_NO_AUTO_INSTALL=1 "$MCPP" run | grep -q '^cmake-consumer: greet says 42$' \
641+
|| fail "the program built with the named cmake does not run"
642+
643+
# The same statement as an engine override, with the payload untouched.
644+
restore
645+
rm -rf target
646+
out=$(MCPP_XLINGS_OVERRIDE_XIM_CMAKE="$cmake" MCPP_NO_AUTO_INSTALL=1 NO_COLOR=1 "$MCPP" build 2>&1) \
647+
|| fail "an override still needed the payload: $out"
648+
case "$out" in
649+
*"Using xim:cmake"*"[custom · env MCPP_XLINGS_OVERRIDE_XIM_CMAKE]"*) ;;
650+
*) fail "the build did not report the override: $out" ;;
651+
esac
652+
record | grep -q "payload:xim:cmake.*custom.*overridden" \
653+
|| fail "the record does not state the override: $(record)"
654+
655+
# `--managed-only` refuses the same build, naming the payload.
656+
rm -rf target
657+
out=$(MCPP_XLINGS_OVERRIDE_XIM_CMAKE="$cmake" MCPP_NO_AUTO_INSTALL=1 NO_COLOR=1 \
658+
"$MCPP" build --managed-only 2>&1 || true)
659+
case "$out" in
660+
*managed-only*xim:cmake*) ;;
661+
*) fail "--managed-only did not refuse the override: $out" ;;
662+
esac
663+
trap - EXIT
664+
rm -rf target
665+
echo "OK: a named tool is used, the payload is not asked for, and both are reported"
666+
}
667+
579668
case "${1:-}" in
669+
tool-sources) tool_sources ;;
580670
vcpkg-consumer) vcpkg_consumer ;;
581671
vcpkg-libcxx) vcpkg_libcxx ;;
582672
archive-consumer) archive_consumer ;;
@@ -592,5 +682,5 @@ case "${1:-}" in
592682
vcpkg-managed) vcpkg_managed ;;
593683
vcpkg-msbuild-refused) vcpkg_msbuild_refused ;;
594684
vcpkg-make-port) vcpkg_make_port ;;
595-
*) echo "usage: $0 vcpkg-consumer|vcpkg-libcxx|archive-consumer|vcpkg-workspace|cmake-consumer|cmake-cache|qt-consumer|qt-widgets-consumer|qt-sdk-consumer|qt-import-only|plugin-logic|vcpkg-crt|vcpkg-managed|vcpkg-msbuild-refused|vcpkg-make-port"; exit 2 ;;
685+
*) echo "usage: $0 vcpkg-consumer|vcpkg-libcxx|archive-consumer|vcpkg-workspace|cmake-consumer|cmake-cache|qt-consumer|qt-widgets-consumer|qt-sdk-consumer|qt-import-only|plugin-logic|tool-sources|vcpkg-crt|vcpkg-managed|vcpkg-msbuild-refused|vcpkg-make-port"; exit 2 ;;
596686
esac

‎.github/workflows/ci.yml‎

Lines changed: 50 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ on:
77
workflow_dispatch:
88
inputs:
99
mcpp_source_ref:
10-
description: "A branch or tag of mcpp-community/mcpp to build and run in place of the release MCPP_VERSION names"
10+
description: "A branch or tag of mcpp-community/mcpp to build and run in place of the release MCPP_BOOTSTRAP names"
1111
required: false
1212
default: ""
1313

@@ -60,7 +60,25 @@ env:
6060
# 2026.9.28.3 IS WHAT 0.17.0 NEEDS, and the package floor states it: the
6161
# build information `mcpp.plugins.toolset` reads, `mcpp::report`, and one
6262
# placement edge for many files (mcpp#734).
63-
MCPP_VERSION: 2026.9.28.3
63+
#
64+
# 2026.10.1.3 IS WHAT 0.19.0 NEEDS (mcpp#755): protocol 15 states where each
65+
# tool and payload comes from -- `xpkg_source`, `xpkg_program`,
66+
# `xpkg_request`, `mcpp::decision`, `mcpp::toolchain`, `mcpp::phase` -- and
67+
# it is the release that honours the `provision = "on-request"` entries this
68+
# collection now declares, so a consumer that names its own tool downloads
69+
# nothing. An older engine refuses the manifest at the package floor.
70+
MCPP_VERSION: 2026.10.1.3
71+
# THE RELEASE EVERY JOB FETCHES, WHICH IS NOT ALWAYS THE ONE UNDER TEST.
72+
#
73+
# `MCPP_VERSION` states the engine this collection needs -- the package floor
74+
# (`[package] mcpp`) is the same statement -- and a release of it may not exist
75+
# yet: 0.19.0 was written against mcpp#755 and pinned 2026.10.1.3 before that
76+
# release was published. Every fetch therefore names this variable instead, and
77+
# the dispatch input `mcpp_source_ref` builds the engine under review with it.
78+
#
79+
# It moves to `MCPP_VERSION` once that release exists, so the ordinary path
80+
# runs the engine this collection states.
81+
MCPP_BOOTSTRAP: 2026.10.1.3
6482
# AN ENGINE BUILT FROM SOURCE, WHEN A DISPATCH NAMES ONE.
6583
#
6684
# Empty on every push and pull request, so the steps run the release above.
@@ -107,16 +125,16 @@ jobs:
107125
uses: actions/cache@v4
108126
with:
109127
path: ~/.mcpp
110-
key: mcpp-sandbox-v2-${{ runner.os }}-${{ runner.arch }}-${{ env.MCPP_VERSION }}-${{ hashFiles('tests/*/mcpp.toml') }}
128+
key: mcpp-sandbox-v2-${{ runner.os }}-${{ runner.arch }}-${{ env.MCPP_BOOTSTRAP }}-${{ hashFiles('tests/*/mcpp.toml') }}
111129
restore-keys: |
112-
mcpp-sandbox-v2-${{ runner.os }}-${{ runner.arch }}-${{ env.MCPP_VERSION }}-
130+
mcpp-sandbox-v2-${{ runner.os }}-${{ runner.arch }}-${{ env.MCPP_BOOTSTRAP }}-
113131
114132
- name: Fetch the released mcpp
115133
run: |
116134
curl -L -fsS --retry 3 --retry-all-errors -o mcpp.tar.gz \
117-
"https://github.com/mcpp-community/mcpp/releases/download/v${MCPP_VERSION}/mcpp-${MCPP_VERSION}-linux-x86_64.tar.gz"
135+
"https://github.com/mcpp-community/mcpp/releases/download/v${MCPP_BOOTSTRAP}/mcpp-${MCPP_BOOTSTRAP}-linux-x86_64.tar.gz"
118136
tar -xzf mcpp.tar.gz
119-
MCPP="$PWD/mcpp-${MCPP_VERSION}-linux-x86_64/bin/mcpp"
137+
MCPP="$PWD/mcpp-${MCPP_BOOTSTRAP}-linux-x86_64/bin/mcpp"
120138
"$MCPP" --version
121139
# THE BUNDLED xlings, NAMED EXPLICITLY BECAUSE `MCPP_HOME` IS PINNED.
122140
#
@@ -126,7 +144,7 @@ jobs:
126144
# with `xlings binary not found` -- measured. The override is needed
127145
# only for that first call: mcpp copies the binary into the pinned
128146
# home and answers from there afterwards.
129-
export MCPP_VENDORED_XLINGS="$PWD/mcpp-${MCPP_VERSION}-linux-x86_64/registry/bin/xlings"
147+
export MCPP_VENDORED_XLINGS="$PWD/mcpp-${MCPP_BOOTSTRAP}-linux-x86_64/registry/bin/xlings"
130148
"$MCPP" self config --mirror GLOBAL
131149
echo "MCPP=$MCPP" >> "$GITHUB_ENV"
132150
echo "MCPP_VENDORED_XLINGS=$MCPP_VENDORED_XLINGS" >> "$GITHUB_ENV"
@@ -728,7 +746,11 @@ jobs:
728746
grep -v '^[[:space:]]*#' mcpp.toml | grep -n 'host-module'
729747
exit 1
730748
fi
731-
"$MCPP" build | tee build.log
749+
# `2>&1`, BECAUSE THE LINE THIS ASSERTS ON IS NARRATION. mcpp writes
750+
# every status line to standard error from 2026.10.1.1 (the output
751+
# streams design), so a step that captures stdout alone reads an empty
752+
# log and reports that the rule did not run while it did.
753+
"$MCPP" build 2>&1 | tee build.log
732754
grep -q 'Rules mcpp.rules.spirv' build.log \
733755
|| { echo "FAIL: the build did not report which rule it ran"; exit 1; }
734756
"$MCPP" run | tee run.log
@@ -1690,6 +1712,12 @@ jobs:
16901712
- name: deps-cmake builds a CMake subproject as an action and links it
16911713
run: bash .github/scripts/check-deps-and-qt.sh cmake-consumer
16921714

1715+
# 0.19.0 (mcpp#755): a tool the build program names is used and the
1716+
# payload is not asked for; an override says the same and is reported;
1717+
# `--managed-only` refuses both.
1718+
- name: a tool the build program names is used, and its payload is not asked for
1719+
run: bash .github/scripts/check-deps-and-qt.sh tool-sources
1720+
16931721
# 0.18.0: an installation is kept under a key with no path of the
16941722
# machine, and taken by a build without target/, by a checkout at another
16951723
# path; an edit, other CFLAGS and an installation that names its own
@@ -1783,20 +1811,20 @@ jobs:
17831811
uses: actions/cache@v4
17841812
with:
17851813
path: ~/.mcpp
1786-
key: mcpp-sandbox-v2-${{ runner.os }}-${{ runner.arch }}-${{ env.MCPP_VERSION }}-${{ hashFiles('tests/spirv-consumer/mcpp.toml') }}
1814+
key: mcpp-sandbox-v2-${{ runner.os }}-${{ runner.arch }}-${{ env.MCPP_BOOTSTRAP }}-${{ hashFiles('tests/spirv-consumer/mcpp.toml') }}
17871815
restore-keys: |
1788-
mcpp-sandbox-v2-${{ runner.os }}-${{ runner.arch }}-${{ env.MCPP_VERSION }}-
1816+
mcpp-sandbox-v2-${{ runner.os }}-${{ runner.arch }}-${{ env.MCPP_BOOTSTRAP }}-
17891817
17901818
- name: Fetch the released mcpp
17911819
run: |
17921820
set -e
17931821
curl -L -fsS --retry 3 --retry-all-errors -o mcpp.pkg \
1794-
"https://github.com/mcpp-community/mcpp/releases/download/v${MCPP_VERSION}/mcpp-${MCPP_VERSION}-${{ matrix.asset }}"
1822+
"https://github.com/mcpp-community/mcpp/releases/download/v${MCPP_BOOTSTRAP}/mcpp-${MCPP_BOOTSTRAP}-${{ matrix.asset }}"
17951823
case "${{ matrix.asset }}" in
17961824
*.zip) unzip -q mcpp.pkg ;;
17971825
*) tar -xzf mcpp.pkg ;;
17981826
esac
1799-
dir="mcpp-${MCPP_VERSION}-${{ matrix.dir-suffix }}"
1827+
dir="mcpp-${MCPP_BOOTSTRAP}-${{ matrix.dir-suffix }}"
18001828
MCPP="$PWD/$dir/bin/mcpp"
18011829
"$MCPP" --version
18021830
# The bundled xlings, named explicitly because MCPP_HOME is pinned
@@ -2388,6 +2416,12 @@ jobs:
23882416
- name: deps-cmake builds a CMake subproject as an action and links it
23892417
run: bash .github/scripts/check-deps-and-qt.sh cmake-consumer
23902418

2419+
# 0.19.0 (mcpp#755): a tool the build program names is used and the
2420+
# payload is not asked for; an override says the same and is reported;
2421+
# `--managed-only` refuses both.
2422+
- name: a tool the build program names is used, and its payload is not asked for
2423+
run: bash .github/scripts/check-deps-and-qt.sh tool-sources
2424+
23912425
# 0.18.0: an installation is kept under a key with no path of the
23922426
# machine, and taken by a build without target/, by a checkout at another
23932427
# path; an edit, other CFLAGS and an installation that names its own
@@ -2454,20 +2488,20 @@ jobs:
24542488
uses: actions/cache@v4
24552489
with:
24562490
path: ~/.mcpp
2457-
key: mcpp-sandbox-v2-${{ runner.os }}-${{ runner.arch }}-${{ env.MCPP_VERSION }}-${{ hashFiles('tests/vcpkg-consumer/mcpp.toml') }}
2491+
key: mcpp-sandbox-v2-${{ runner.os }}-${{ runner.arch }}-${{ env.MCPP_BOOTSTRAP }}-${{ hashFiles('tests/vcpkg-consumer/mcpp.toml') }}
24582492
restore-keys: |
2459-
mcpp-sandbox-v2-${{ runner.os }}-${{ runner.arch }}-${{ env.MCPP_VERSION }}-
2493+
mcpp-sandbox-v2-${{ runner.os }}-${{ runner.arch }}-${{ env.MCPP_BOOTSTRAP }}-
24602494
24612495
- name: Fetch the released mcpp
24622496
run: |
24632497
set -e
24642498
curl -L -fsS --retry 3 --retry-all-errors -o mcpp.pkg \
2465-
"https://github.com/mcpp-community/mcpp/releases/download/v${MCPP_VERSION}/mcpp-${MCPP_VERSION}-windows-x86_64.zip"
2499+
"https://github.com/mcpp-community/mcpp/releases/download/v${MCPP_BOOTSTRAP}/mcpp-${MCPP_BOOTSTRAP}-windows-x86_64.zip"
24662500
case "windows-x86_64.zip" in
24672501
*.zip) unzip -q mcpp.pkg ;;
24682502
*) tar -xzf mcpp.pkg ;;
24692503
esac
2470-
dir="mcpp-${MCPP_VERSION}-windows-x86_64"
2504+
dir="mcpp-${MCPP_BOOTSTRAP}-windows-x86_64"
24712505
MCPP="$PWD/$dir/bin/mcpp"
24722506
"$MCPP" --version
24732507
# The bundled xlings, named explicitly because MCPP_HOME is pinned

0 commit comments

Comments
 (0)