Skip to content

Commit 93e59b5

Browse files
committed
0.19.0: one resolver for where a member's tool comes from, payloads installed on request, and a toolchain a build program states
A member that runs a program answers one question before it can plan anything: which program. Each member answered it its own way -- an option here, a variable there, a silent PATH fallback in two members and a refusal of PATH in two others -- and a tool named in build.mcpp did not stop the declared payload from being downloaded. On the engine of mcpp#755 this release answers it once. - `mcpp.plugins.tool` (in `plugins-core`) resolves a member's tool in one order: the build program's choice, the member's legacy variable, the engine's override, then the declared payload. 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>` can answer, and one refusal text lists every way to name the tool. - Every member that runs a payload tool takes its option as a `tool::choice`, which a string constructs, so `o.cmake = "/usr/bin/cmake"` keeps working and the line that wrote it is what the build reports. `rules-cuda`, `rules-hip`, `rules-ascendc` and `dist-apk` gain the options they had none of. - `deps-cmake`, `deps-archive`, `deps-vcpkg`, `dist-appimage` and `dist-apk`'s `bundletool` declare their payloads `provision = "on-request"`: a build that names its own tool, or never reaches the tool, downloads nothing. - `rules-spirv` and `rules-slang` keep their PATH fallback behind a warning that names the choice to write instead, until 2027-04-01 (SPEC-007 R6.2). - `mcpp.plugins.toolchain` (feature `plugins-toolchain`) builds the statement a root build program makes in its toolchain phase: `layout`, `prefixed`, `compose`, `from_env_script`, `with_launcher`, `managed`, `env`, `configure` and `use`. - `mcpp.plugins.testing` states a payload's source, its program and the phase, so a case can describe an override or a pending payload. The engine floor is 2026.10.1.3, the release whose protocol 15 states where each tool and payload comes from. Closes #41 Test plan - `tests/plugin-logic`: 27 cases pass, including five for the resolver (a choice asks for no payload, an override answers, a pending payload is requested, the payload answers last, and the refusal lists every way to name the tool). - 11 consumer fixtures build against the engine branch, `all-rules-compile` compiles every rule and dist member, and the default build's output is unchanged. - New CI criterion `tool-sources` on all three platforms: with nothing named the member asks for the payload; with the build program naming a cmake the payload is not asked for and the source is reported; an override says the same; and `--managed-only` refuses both. The criterion reads `resolution.json`, so it holds on a runner that already has the payload.
1 parent 6dc3490 commit 93e59b5

30 files changed

Lines changed: 1414 additions & 230 deletions
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
# mcpp 构建插件框架:实施计划与任务依赖
2+
3+
日期:2026-10-01。状态:执行中。
4+
5+
依据:`2026-10-01-ecosystem-build-plugin-framework-design.md` v3(下称“设计”)及其 §0 的已定事项。本记录覆盖 2026-10-01 /goal 的要求:
6+
- D6 一步到位,不分期交付;
7+
- 每个仓库单 PR,标题带版本号;
8+
- CI 全绿;
9+
- 自我 review,包括生态级 review;
10+
- 发布:GitHub 加 GitCode(本地 gtc),mcpp-index 与 xim-pkgindex 登记;
11+
- 在 xlings subos 沙箱中以 CN 镜像做真实验证;
12+
- 关闭已完成的 issue;
13+
- 文档与代码注释不含表情符号。
14+
15+
## 1. 交付物与版本
16+
17+
| 仓库 | PR | 版本 | 内容 |
18+
|---|---|---|---|
19+
| mcpp-community/mcpp | 1 个 | 发布当日的 `YYYY.M.D.N` | 核心:决策记录与输出语义、E1、E2、决策指令、自定义工具链(路径与 toolchain 阶段)、规范与文档(中英)、测试 |
20+
| mcpp-community/mcpp-plugins | 1 个 | 0.19.0 | `mcpp.plugins.tool`、`mcpp.plugins.toolchain`、成员迁移、按需条目、文档、fixture、CI |
21+
| speak-agent/llvm-macos27-lab | 1 个以上 | — | LLVM `arm64e.x1` 修复在 macOS 27 / Xcode 27 上的可用性;裁剪后的工具链资产 |
22+
| speak-agent/mcpp-framework-lab | 1 个以上 | — | 工具来源、输出、可观察性的验收 |
23+
| speak-agent/mcpp-toolchain-lab | 1 个以上 | — | 自定义工具链的验收(含 macOS 27) |
24+
| mcpplibs/mcpp-index | 1 个 | — | 登记 plugins 0.19.0 |
25+
| openxlings/xim-pkgindex | release 自动开出的 bump PR | — | 登记 mcpp 新版本 |
26+
27+
设计 §10 中的 S4(xim `llvm` 23.1.3 打包)取决于上游发布。它不在本 goal 的关键路径上:若上游在收尾前发布了 23.1.3,就按设计执行;否则在 mcpp#669 中记录 lab 的结果,并留作后续。
28+
29+
## 2. 任务与依赖
30+
31+
```
32+
T0 issues(mcpp、plugins)与 lab 仓库
33+
T1 核心:来源类、决策记录、渲染(status 行、标签、Finished 汇总)、resolution.json、
34+
mcpp why tool/payload、--managed-only
35+
T2 E1 覆盖(清单、target cfg、全局配置、环境变量;供给过滤;统一校验;
36+
fillXpkgDirs 的 DIR/PROGRAM/SOURCE;xpkg_program、xpkg_source) ← T1
37+
T3 E2 按需(provision 键;xpkg_request/xpkg_pending;xpkg-request 指令;
38+
批量供给与选择性重跑;离线拒绝;plan_only note) ← T1, T2
39+
T4 decision 指令(插件把工具决定写进记录) ← T1
40+
T5 自定义工具链按路径([toolchain] 表、MCPP_TOOLCHAIN=path:、bootstrap 键;
41+
探测;不做 post-install;指纹含内容 hash;lock 记为 local) ← T1
42+
T6 toolchain 阶段(configure = "build.mcpp";mcpp:toolchain 指令;mcpp::phase) ← T4, T5
43+
T7 mcpp 规范与文档(中英)、CHANGELOG、设计记录 ← T1–T6 的语义
44+
T8 mcpp 单测与 e2e ← 各项随实现
45+
T9 plugins 0.19.0(tool、toolchain、成员迁移、on-request、文档、fixture、CI)
46+
← T2, T3, T4, T6 的宿主接口
47+
T10 llvm-macos27-lab (独立,最早开始)
48+
T11 framework-lab、toolchain-lab ← T9(以及 T10 的资产)
49+
T12 两个 PR 的 CI 全绿;以 mcpp_source_ref 指向 mcpp 分支做 plugins 预验证
50+
T13 自我 review(含生态级)
51+
T14 发布 mcpp → xim-pkgindex bump PR 合入 → bootstrap pin
52+
T15 发布 plugins 0.19.0 → gtc → mcpp-index
53+
T16 沙箱验证(xlings subos,CN 镜像);lab 改指已发布版本复跑
54+
T17 issue 评论与关闭;设计记录追加状态行
55+
```
56+
57+
**并行**:
58+
- T10 不依赖任何实现,最早开始;
59+
- T1 完成后,T2/T4/T5 可以并行;
60+
- T7 与 T9 的文档部分在接口冻结后与实现并行;
61+
- 后台 agent 同时最多 3 个。
62+
63+
## 3. 质量门(每个视角在哪里被检查)
64+
65+
| 视角 | 检查 |
66+
|---|---|
67+
| 架构 | 核心只承担语义与接口;具体工具的知识留在 L2 与成员中(设计 §3 原则 4);新模块的 import 指向类型的提供者 |
68+
| 稳定性 | 默认构建的输出与行为逐字节不变(framework-lab `default` case 与 e2e);已有 e2e 全部通过 |
69+
| 简洁 | 两个入口共用一个描述 schema;一份决策记录驱动全部输出 |
70+
| 用户体验 | 显式选择一行 `Using`;错误首行写明来源;报错给出四种指定方式 |
71+
| 兼容性 | 旧插件不改代码即可从 E1 受益;`tool::choice` 可由字符串隐式构造;新键在旧引擎上会被拒或忽略,提 floor |
72+
| 跨平台 | 单测与 e2e 覆盖 Linux、macOS、Windows;Windows 路径与 `.exe`;macOS 27 由 lab 覆盖 |
73+
| 一致性 | 优先级只写一份(核心一份、L2 一份);文档中英结构一一对应 |
74+
| 无感升级 | 不写任何新键的项目在新版本上行为不变;插件 0.19.0 的成员在默认路径上下载与输出不变 |
75+
| 测试覆盖 | 每个新清单键、指令、查询函数与命令都有单测或 e2e;每条拒绝都有一个反例用例 |
76+
77+
## 4. 执行记录
78+
79+
(随执行追加:PR、run、发布与验证结果。)

‎.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: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,14 @@ 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
6471
# AN ENGINE BUILT FROM SOURCE, WHEN A DISPATCH NAMES ONE.
6572
#
6673
# Empty on every push and pull request, so the steps run the release above.
@@ -1690,6 +1697,12 @@ jobs:
16901697
- name: deps-cmake builds a CMake subproject as an action and links it
16911698
run: bash .github/scripts/check-deps-and-qt.sh cmake-consumer
16921699

1700+
# 0.19.0 (mcpp#755): a tool the build program names is used and the
1701+
# payload is not asked for; an override says the same and is reported;
1702+
# `--managed-only` refuses both.
1703+
- name: a tool the build program names is used, and its payload is not asked for
1704+
run: bash .github/scripts/check-deps-and-qt.sh tool-sources
1705+
16931706
# 0.18.0: an installation is kept under a key with no path of the
16941707
# machine, and taken by a build without target/, by a checkout at another
16951708
# path; an edit, other CFLAGS and an installation that names its own
@@ -2388,6 +2401,12 @@ jobs:
23882401
- name: deps-cmake builds a CMake subproject as an action and links it
23892402
run: bash .github/scripts/check-deps-and-qt.sh cmake-consumer
23902403

2404+
# 0.19.0 (mcpp#755): a tool the build program names is used and the
2405+
# payload is not asked for; an override says the same and is reported;
2406+
# `--managed-only` refuses both.
2407+
- name: a tool the build program names is used, and its payload is not asked for
2408+
run: bash .github/scripts/check-deps-and-qt.sh tool-sources
2409+
23912410
# 0.18.0: an installation is kept under a key with no path of the
23922411
# machine, and taken by a build without target/, by a checkout at another
23932412
# path; an edit, other CFLAGS and an installation that names its own

0 commit comments

Comments
 (0)