Skip to content

Commit 3a6f1c2

Browse files
authored
0.13.0: deps-vcpkg, deps-cmake and rules-qt, written against mcpp's SPEC-007 (#29)
1 parent dea1f09 commit 3a6f1c2

44 files changed

Lines changed: 3375 additions & 27 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎.agents/docs/2026-09-26-deps-vcpkg-rules-qt-design.md‎

Lines changed: 636 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
# 实施计划:`deps-vcpkg`、`rules-qt`、`deps-cmake` 的跨仓库交付
2+
3+
状态:执行中 · 2026-09-26(引擎下界 2026.9.26.2) · 设计见 `2026-09-26-deps-vcpkg-rules-qt-design.md`(第 4 版)。
4+
5+
## 1. 第 3 轮决定(设计第 4 版据此修改)
6+
7+
| # | 决定 | 对设计的影响 |
8+
|---|---|---|
9+
| D6 | 附加模块合为一个包 | 确认 `xim:qt-addons`;按 xim 的载荷私有规则,它有**自己的前缀**,不写入 `xim:qt` 的目录 |
10+
| D8 | 先做 mcpp / xlings 生态的通用能力;GalTranslPP 的 D 阶段只在 fork 上做初步验证 | 引擎需求 2 在 mcpp 中实现:构建程序声明运行时库目录 |
11+
| D9 | 免装 VS 不是目标 | 删除 `toolchain::msvc_xim`;`xim:msvc` 由 mcpp 自动匹配,插件不声明 |
12+
13+
另有一项由实测带来的简化:vcpkg-tool 每个发布附带 `vcpkg-standalone-bundle.tar.gz`(3.4 MB,脚本与该工具
14+
版本严格对应,`vcpkg-bundle.json` 含 `"usegitregistry": true`)。以它为 `VCPKG_ROOT` 时,`builtin-baseline`
15+
清单经 git registry 解析,registry 落在 vcpkg 的每用户 registries 缓存。已在本机实测:对 GalTranslPP 的
16+
baseline `ea1a7396` 执行 `vcpkg install --dry-run` 解析出 `fmt 12.2.0`,缓存 137 MB。因此设计第 3 版 §3.6 的托管克隆、
17+
按工具检出与文件锁全部取消。
18+
19+
## 2. 仓库与交付物
20+
21+
| 仓库 | 单个 PR 的内容 | 发布 |
22+
|---|---|---|
23+
| mcpp-community/mcpp | SPEC-007 与 #702 的合规设计(`runtime_search_dir`、`prepare`、stamp 规则、Windows DLL 放置),由 mcpp 侧实现 | 下一个 mcpp 发布;插件 PR 等待它 |
24+
| openxlings/xim-pkgindex | `xim:vcpkg` 2026.7.27(工具 + standalone bundle)、`xim:qt` 6.11.1、`xim:qt-addons` 6.11.1;`xim:7zip` 说明 `7z.dll` 位置;测试 | 合入即发布索引;`xlings-res/vcpkg` 资源用 `gh` 与 `gtc` 双端上传 |
25+
| mcpp-community/mcpp-plugins | `0.13.0`:`deps-vcpkg` + `mcpp-vcpkg`、`rules-qt` + `rules-qt-xim` + `rules-qt-xim-addons`、`deps-cmake` + `mcpp-cmake`;fixtures;CI 引擎版本;README | tag `v0.13.0`,GitHub release,`gtc` 上传 `mcpp-res/mcpp-plugins` |
26+
| mcpp-community/mcpp-index | 登记 `mcpp:plugins 0.13.0` | 合入即发布 |
27+
| Sunrisepeak/GalTranslPP(fork) | 临时 PR 2:迁移 A–C,D 阶段初步验证 | 不合入 |
28+
29+
## 3. 依赖关系
30+
31+
```
32+
T2 xim 包(vcpkg/qt/qt-addons)──► T2r 索引合入(xim-pkgindex#878,已合入)
33+
T3 插件按 SPEC-007 实现(PR 已开,等待)──┐
34+
T1 mcpp#702 实现并发布(mcpp 侧)─────────┴──► T3c 插件 CI 全绿 ──► T3r 插件发布 0.13.0 ──► T4 mcpp-index ──► T5 GalTranslPP PR 2
35+
```
36+
37+
- T1、T2、T3 并行:T3 在本机用 T1 的源码构建验证 Linux 路径;Windows 与 macOS 路径只能由 CI 验证。
38+
- T3 的 CI 依赖 T1r(`MCPP_VERSION` 指向新引擎)与 T2r(索引里有 `xim:vcpkg`、`xim:qt`)。
39+
- T5 用索引中的 `mcpp:plugins 0.13.0`,不用路径依赖,以验证用户实际得到的东西。
40+
41+
## 4. 多角度检查项(实施与 review 共用)
42+
43+
| 角度 | 检查项 |
44+
|---|---|
45+
| 架构 | `deps-*` 家族只描述、重活在 action;插件拥有它驱动的 xim 包;运行时目录经引擎通道而非逐文件复制 |
46+
| 稳定性 | emit 在未安装依赖时返回 0;安装边只在输入变化时重跑;各项目的 buildtrees/packages 隔离;vcpkg 自身对安装目录加锁 |
47+
| 优雅简洁 | 零配置可用;registry 管理交给 vcpkg;一个选项结构 + 一个入口函数 |
48+
| 用户体验 | 所有拒绝都给出下一步;缺依赖时 warning 写明 `mcpp build` 会安装它 |
49+
| 兼容性 | 旧引擎给出明确的版本下界提示;已有 `vcpkg_installed/` 布局不变;自定义 triplet 与 overlay 照常 |
50+
| 跨平台 | Windows x86_64 / Linux x86_64 / macOS:`deps-vcpkg` 三平台 fixture;`rules-qt` Windows + Linux(macOS 视 Qt 框架布局而定) |
51+
| 一致性 | 选项、警告格式、`mcpp::fact` 版本记录与既有成员一致;README 成员表同格式 |
52+
| 无感升级 | 插件次版本号前移;不改变已有成员的行为;引擎新增指令,旧程序不受影响 |
53+
| 测试覆盖 | 每个功能一个正向 fixture + 一个拒绝/边界断言;`all-rules-compile` 覆盖新模块在三平台编译 |
54+
55+
## 5. 进度
56+
57+
| 任务 | 状态 |
58+
|---|---|
59+
| T0 设计第 4 版、本计划 | 完成 |
60+
| T1 引擎 | mcpp#702 由 mcpp 侧合入,随 2026.9.26.2 发布 |
61+
| T2 xim 包 | xim-pkgindex#878、#879 已合入;`xlings-res/vcpkg` 双端资源已校验 |
62+
| T3 插件 | PR #29;Linux 各 fixture 在 2026.9.26.2 上通过;Windows、macOS 由 CI 验证 |
63+
| T3r / T4 / T5 | 等待 T3c |
64+
65+
实测发现两项引擎缺口,均已报告:
66+
67+
- 主机构建不读取主机三元组的 `[target.<triple>]` 段(mcpp#704),因此 Qt fixture 在 `[build]` 中声明
68+
`cxx_runtime = "toolchain-coupled"`。
69+
- `path` 包的宿主工具以整棵目录树的 stamp 为键,嵌套其中的消费方写出的文件改变该键(mcpp#705)。fixture
70+
位于插件仓库之内,因此其安装位于 `target/` 之下,检查脚本的日志写入 `target/ci/`,第二次构建以
71+
`--profile dev` 绕过快路径,使 Linux 与 Windows、macOS 走同一条规划路径。从索引取得插件的项目不受影响。
Lines changed: 174 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,174 @@
1+
#!/usr/bin/env bash
2+
# The criteria for `deps-vcpkg`, `deps-cmake` and `rules-qt`, one function per
3+
# fixture, the same on every host. A CI step names the fixture:
4+
#
5+
# bash .github/scripts/check-deps-and-qt.sh vcpkg-consumer
6+
#
7+
# Each function fails with the reason it failed. Host differences are the
8+
# host's: a DLL is looked for on Windows, where a triplet builds fmt as one, and
9+
# nowhere else.
10+
set -euo pipefail
11+
12+
: "${MCPP:?MCPP names the mcpp under test}"
13+
ROOT=$(cd "$(dirname "$0")/../.." && pwd)
14+
15+
fail() { echo "FAIL: $*"; exit 1; }
16+
17+
is_windows() { case "$(uname -s)" in MINGW*|MSYS*|CYGWIN*) return 0 ;; *) return 1 ;; esac; }
18+
is_macos() { [ "$(uname -s)" = Darwin ]; }
19+
20+
# The stamp an installation action leaves: the file mcpp writes when a `prepare`
21+
# action's command succeeds. Its modification time is the criterion for "the
22+
# installation did not run again".
23+
stamp_of() { find target -path "*$1*" -name '*.stamp' | head -1; }
24+
25+
# The program as the build left it, started without `mcpp run`: on Windows the
26+
# engine has placed the DLLs it imports beside it (SPEC-007 R4.3), so it starts
27+
# from the build directory as it does from the packed tree.
28+
run_directly() {
29+
local exe; exe=$(find target -path '*/bin/*' -name "$1.exe" | head -1)
30+
[ -n "$exe" ] || fail "no $1.exe under target/"
31+
"$exe"
32+
}
33+
34+
# A second build with nothing changed must not run the installation again.
35+
assert_not_rerun() {
36+
local stamp="$1"
37+
[ -n "$stamp" ] && [ -f "$stamp" ] || fail "no installation stamp under target/"
38+
mkdir -p target/ci
39+
touch -r "$stamp" target/ci/before-second-build
40+
sleep 1
41+
# `--profile dev` names the default profile and declines mcpp's fast path,
42+
# so the second build is planned on every host, as it is on Windows and
43+
# macOS without the flag, and a host tool whose key moved is rebuilt.
44+
"$MCPP" build --profile dev > target/ci/second-build.log 2>&1 ||
45+
{ cat target/ci/second-build.log; fail "the second build failed"; }
46+
[ -z "$(find "$stamp" -newer target/ci/before-second-build)" ] ||
47+
fail "the second build re-ran the installation ($stamp is newer)"
48+
echo "ok: a second build with nothing changed did not re-run the installation"
49+
}
50+
51+
vcpkg_consumer() {
52+
cd "$ROOT/tests/vcpkg-consumer"
53+
rm -rf target vcpkg_installed
54+
# PLANNING NEVER INSTALLS, AND STILL STATES THE PATHS. An editor asks for
55+
# the build database on machines that never built; the build program must
56+
# succeed there and name the include directory the build will fill.
57+
mkdir -p target/ci
58+
"$MCPP" emit build-database --format json > target/ci/db.json 2> target/ci/emit.log ||
59+
{ cat target/ci/emit.log; fail "emit build-database failed before any installation"; }
60+
grep -q 'vcpkg_installed' target/ci/db.json || fail "the database names no vcpkg_installed include directory"
61+
[ ! -d target/vcpkg_installed ] || fail "emit build-database installed something"
62+
echo "ok: emit succeeded before the installation and named its include directory"
63+
64+
"$MCPP" build 2>&1 | tee target/ci/build.log
65+
"$MCPP" run | tee target/ci/run.log
66+
grep -qE '^vcpkg-consumer: fmt [0-9]+ says 42$' target/ci/run.log || fail "the program did not print through fmt"
67+
assert_not_rerun "$(stamp_of deps-vcpkg)"
68+
69+
if is_windows; then
70+
# The pack collects it from the runtime search directory.
71+
ls target/vcpkg_installed/x64-windows/bin/fmt.dll > /dev/null || fail "x64-windows built no fmt.dll"
72+
run_directly vcpkg-consumer | tee target/ci/direct.log
73+
grep -qE '^vcpkg-consumer: fmt [0-9]+ says 42$' target/ci/direct.log ||
74+
fail "started from the build directory, the program did not find fmt.dll"
75+
"$MCPP" pack --format dir | tee target/ci/pack.log
76+
find target/dist -iname 'fmt.dll' | grep -q . || fail "the packed tree carries no fmt.dll"
77+
echo "ok: the packed tree carries fmt.dll"
78+
fi
79+
}
80+
81+
vcpkg_workspace() {
82+
cd "$ROOT/tests/vcpkg-workspace"
83+
rm -rf target app-a/target app-b/target vcpkg_installed
84+
mkdir -p target/ci
85+
"$MCPP" build 2>&1 | tee target/ci/build.log
86+
"$MCPP" run -p app-a | tee target/ci/run-a.log
87+
"$MCPP" run -p app-b | tee target/ci/run-b.log
88+
grep -qE '^app-a: fmt [0-9]+$' target/ci/run-a.log || fail "app-a did not run"
89+
grep -qE '^app-b: fmt [0-9]+$' target/ci/run-b.log || fail "app-b did not run"
90+
# Each member builds into its own target/ and declares its own installation.
91+
[ "$(find . -path '*/target/*' -path '*deps-vcpkg*' -name '*.stamp' | wc -l)" -ge 2 ] ||
92+
fail "each member did not declare its own installation"
93+
echo "ok: two members that share no dependency both installed and linked one prefix"
94+
}
95+
96+
cmake_consumer() {
97+
cd "$ROOT/tests/cmake-consumer"
98+
rm -rf target
99+
mkdir -p target/ci
100+
"$MCPP" build 2>&1 | tee target/ci/build.log
101+
"$MCPP" run | tee target/ci/run.log
102+
grep -q '^cmake-consumer: greet says 42$' target/ci/run.log || fail "the program did not call the subproject's library"
103+
assert_not_rerun "$(stamp_of deps-cmake)"
104+
# The builds after an edit are planned as well. The subproject lies inside
105+
# this repository, the tree mcpp stamps for the plugins' host tool
106+
# (mcpp#705), so an edit also rebuilds `mcpp-deps`; the build that is
107+
# expected to re-run the installation absorbs that rebuild.
108+
touch greet/greet.c
109+
"$MCPP" build --profile dev > target/ci/third-build.log 2>&1 || { cat target/ci/third-build.log; fail "the rebuild failed"; }
110+
# The installed library is the product of the rebuild, whatever the engine
111+
# does with the action's stamp.
112+
[ -n "$(find target -path '*deps-cmake*/install/*' -name '*greet*' -newer target/ci/before-second-build)" ] ||
113+
fail "an edited subproject source did not rebuild the subproject"
114+
echo "ok: an edited subproject source rebuilt the subproject"
115+
# And not again: the engine moves the stamp past the input that changed
116+
# (mcpp's SPEC-007 R3.5).
117+
assert_not_rerun "$(stamp_of deps-cmake)"
118+
119+
# A file ADDED to the subproject is an input too: the build program watches
120+
# the tree, so the next plan names it and the installation runs again.
121+
trap 'rm -f "$ROOT/tests/cmake-consumer/greet/added.txt"' RETURN
122+
touch -r "$(stamp_of deps-cmake)" target/ci/before-added-file
123+
sleep 1
124+
echo added > greet/added.txt
125+
"$MCPP" build --profile dev > target/ci/added-build.log 2>&1 || { cat target/ci/added-build.log; fail "the build after adding a file failed"; }
126+
[ -n "$(find "$(stamp_of deps-cmake)" -newer target/ci/before-added-file)" ] ||
127+
fail "a file added to the subproject did not re-run its installation"
128+
echo "ok: a file added to the subproject re-ran its installation"
129+
}
130+
131+
qt_consumer() {
132+
cd "$ROOT/tests/qt-consumer"
133+
rm -rf target
134+
mkdir -p target/ci
135+
"$MCPP" build 2>&1 | tee target/ci/build.log
136+
"$MCPP" run | tee target/ci/run.log
137+
grep -qE "^qt-consumer: signal 42, resource 'greetings from rcc', translation 'hallo', Qt 6\." target/ci/run.log ||
138+
fail "moc, rcc or lrelease did not reach the program"
139+
find target -name 'qt_consumer_de.qm' | grep -q . || fail "no .qm was produced"
140+
echo "ok: moc (header and inline), rcc and lrelease reached the program"
141+
}
142+
143+
qt_widgets_consumer() {
144+
cd "$ROOT/tests/qt-widgets-consumer"
145+
rm -rf target
146+
mkdir -p target/ci
147+
"$MCPP" build 2>&1 | tee target/ci/build.log
148+
QT_QPA_PLATFORM=offscreen "$MCPP" run | tee target/ci/run.log
149+
grep -q "^qt-widgets-consumer: platform offscreen, label 'made by uic'$" target/ci/run.log ||
150+
fail "the platform plugin or the uic form did not reach the program"
151+
if is_macos; then
152+
find target -path '*/bin/platforms/libqoffscreen.dylib' | grep -q . ||
153+
fail "no platforms/libqoffscreen.dylib was deployed beside the program"
154+
fi
155+
if is_windows; then
156+
QT_QPA_PLATFORM=offscreen run_directly qt-widgets-consumer | tee target/ci/direct.log
157+
grep -q "^qt-widgets-consumer: platform offscreen" target/ci/direct.log ||
158+
fail "started from the build directory, the program did not find the Qt DLLs"
159+
"$MCPP" pack --format dir | tee target/ci/pack.log
160+
find target/dist -iname 'Qt6Widgets.dll' | grep -q . || fail "the packed tree carries no Qt6Widgets.dll"
161+
find target/dist -ipath '*platforms/qoffscreen.dll' | grep -q . ||
162+
fail "the packed tree carries no platforms/qoffscreen.dll"
163+
echo "ok: the packed tree carries the Qt modules and the platform plugins"
164+
fi
165+
}
166+
167+
case "${1:-}" in
168+
vcpkg-consumer) vcpkg_consumer ;;
169+
vcpkg-workspace) vcpkg_workspace ;;
170+
cmake-consumer) cmake_consumer ;;
171+
qt-consumer) qt_consumer ;;
172+
qt-widgets-consumer) qt_widgets_consumer ;;
173+
*) echo "usage: $0 vcpkg-consumer|vcpkg-workspace|cmake-consumer|qt-consumer|qt-widgets-consumer"; exit 2 ;;
174+
esac

0 commit comments

Comments
 (0)