Skip to content

Commit b482469

Browse files
authored
2026.9.24.1 — the MSVC toolset is the sysroot, the deployment target follows the target, and frozen gcc headers are named (#688)
Closes #685. Closes #687. SPEC-006 (toolchain management, draft v0.2). See the PR description for the measurements.
1 parent b30e70c commit b482469

55 files changed

Lines changed: 3966 additions & 252 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-24-685-687-msvc-stl-and-toolchain-payloads.md‎

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

‎.agents/docs/2026-09-24-toolchain-selection-and-payload-trust-design.md‎

Lines changed: 408 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
---
2+
subject: plan
3+
status: active
4+
---
5+
6+
# 工具链选择与载荷可信度:实施计划
7+
8+
- 日期:2026-09-24
9+
- 设计:`2026-09-24-toolchain-selection-and-payload-trust-design.md`(v2)
10+
- 规范:`docs/specs/toolchain-management.md`(SPEC-006)
11+
- 维护者对设计 §10 的答复:
12+
- `sysroot` 语义接受;
13+
- `xim:` 前缀对所有工具链族都接受;
14+
- SPEC-006 保持一份,不拆分。
15+
16+
## 1. 约束
17+
18+
| 角度 | 约束 |
19+
|---|---|
20+
| 架构 | MSVC 的选择只在 prepare 里做一次,结果存进 `Toolchain`,所有读者都读它。选择逻辑是纯函数,只有枚举候选依赖 Windows。deployment target 的解析函数以目标三元组为参数,调用方无法再按宿主判定 |
21+
| 稳定性 | 不写版本时,默认结果与今天一致,例外只有设计 §3.9 列出的几种(每一种都更好)。任何回落都打印一行说明 |
22+
| 简洁 | 不新增清单键;clang 行复用 `[target.<triple>].sysroot`。三组 `-Xmicrosoft-*` 参数由 `LinkModel` 这一个地方产生 |
23+
| 用户体验 | 构建开头打印一行,说明用的是哪个 toolset、来自哪里、SDK 版本。找不到时列出三类候选。写了版本而环境变量被忽略时,打印说明 |
24+
| 兼容性 | `msvc@system`、`msvc@<版本>`、`gcc@…`、`llvm@…` 这些写法都继续有效。`msvc@<版本>` 在机器上有同版本时改用系统的那一份,这一点写进 CHANGELOG。缓存键的变化只影响 Windows clang 行 |
25+
| 跨平台 | 选择逻辑、写法解析、清单解析的单测都在 Linux 上运行;Windows 行为由 Windows CI 的 e2e 覆盖。#685 的修正对 macOS 宿主保持原有输出 |
26+
| 一致性 | `cl.exe` 行与 clang 行共用同一个选择函数。「最高」统一按数字元组比较 |
27+
| 无感升级 | 已有项目不需要改清单。新写法在旧引擎上是响亮的失败,不会被静默忽略;文档写明所需的最低版本 |
28+
| 测试覆盖 | 每个判据都配反向用例(撤回修复就变红)。纯函数单测覆盖边界情形;e2e 覆盖真实二进制 |
29+
30+
## 2. 任务
31+
32+
| 编号 | 仓库 | 内容 | 主要文件 | 依赖 |
33+
|---|---|---|---|---|
34+
| T1 | mcpp | #685:deployment target 与宿主无关,是否适用按目标判定 | `modules/platform/src/macos/macos.cppm`、`src/build/prepare.cppm`(deployment target 相关位置)、`src/build/prepare_inputs.cppm`、`src/toolchain/hostflags.cppm`(`-mmacosx-version-min`)、`src/toolchain/stdmod.cppm`、`src/build/flags.cppm`、`src/build/build_program.cppm`、对应单测 | 无 |
35+
| T2 | mcpp | #687 的 doctor 诊断:已安装 gcc 的 `include-fixed` 里带横幅的文件 | `src/doctor.cppm`、单测 | 无 |
36+
| T3 | mcpp | 工具链写法的 `xim:` 前缀(所有族) | `src/toolchain/registry.cppm`、`src/toolchain/compat.cppm`、单测 | 无 |
37+
| T4 | mcpp | MSVC 候选枚举与纯函数 `select_toolset()`;`cl.exe` 行的 `msvc@system` 与带版本的写法改用它 | `src/toolchain/msvc.cppm`、`src/build/prepare.cppm`(工具链解析段)、单测 | T3 |
38+
| T5 | mcpp | clang 行的 MSVC sysroot:清单解析、在 prepare 中解析、`Toolchain` 字段、`-Xmicrosoft-*` token、`std.ixx`、`stdlibVersion`、链接环境、`resolution.json`、构建开头那一行 | `modules/manifest/src/toml.cppm`、`modules/toolchain-model/src/model.cppm`、`linkmodel.cppm`、`src/toolchain/hostflags.cppm`(链接 token)、`src/toolchain/clang.cppm`、`src/build/flags.cppm`(链接一侧与含空格路径的转义)、`src/build/cache_key.cppm`、`src/build/prepare.cppm` | T4 |
39+
| T6 | mcpp | `mcpp toolchain list` 在 Windows 上列出机器上的 toolset | `src/toolchain/lifecycle.cppm` | T4 |
40+
| T7 | mcpp | Windows e2e:多版本、`xim:`、环境变量被忽略、`std.ixx` 与头文件同源 | `tests/e2e/`、`.github/workflows/ci-windows*.yml` | T5 |
41+
| T8 | mcpp | 文档:`docs/20`、`docs/22`、`docs/04` 及 `docs/zh/` 对应译文;SPEC-006 的实现状态;CHANGELOG;版本号 | 文档与版本文件 | T1 到 T7 |
42+
| T9 | xim-pkgindex | `gcc.lua` 清理代码的引号修正与日志;`tests/g/test_gcc.py` 断言 | `pkgs/g/gcc.lua`、`tests/g/test_gcc.py` | 无 |
43+
| T10 | — | 两个 PR 的 CI 全绿后合入:xim-pkgindex 先合,mcpp 后合 | — | T1 到 T9 |
44+
| T11 | mcpp、xlings-res、xim-pkgindex | 发布:打 tag、四平台构建、本地 gtc 补 GitCode、核验镜像、合入 bot 的索引 PR、在 PR 里前移 bootstrap pin | — | T10 |
45+
| T12 | — | 生态验证:在 xlings subos 沙箱里(mcpp 与 xlings 都配 CN 镜像)装已发布的 mcpp,逐项验证 #685、#687 以及 mcpp-index 的若干包 | — | T11 |
46+
47+
并行方式:
48+
49+
- T1 与 T2 交给一个子代理,在 worktree `mcpp-685` 里做;
50+
- T9 交给另一个子代理,在 xim-pkgindex 的 worktree 里做;
51+
- T3 到 T8 由主线在 `mcpp-tcsel` 里做;
52+
- T1、T2 做完后合入主线分支,形成一个 PR。
53+
54+
文件归属按上表划分。`src/build/prepare.cppm` 由两边在互不重叠的区段修改:T1 只动 deployment target 相关的函数与调用处,T4、T5 只动工具链解析段与 `resolution.json`。
55+
56+
## 3. 判据
57+
58+
| 编号 | 判据 | 反向 |
59+
|---|---|---|
60+
| T1 | 在 Linux 宿主上,`aarch64-macos` 目标的 `build.ninja` 带有 manifest 里写的版本;改值后指纹变化;env 优先于 manifest | macOS 宿主构建非 Apple 目标时不出现 `-mmacosx-version-min` |
61+
| T2 | 15.1.0 载荷副本触发诊断 | 16.1.0 不触发 |
62+
| T3 | `xim:gcc@16.1.0` 与 `gcc@16.1.0` 解析结果相同;`xim:msvc@system` 被拒绝 | — |
63+
| T4 | 纯函数单测覆盖设计 §3.10 列出的全部用例 | 去掉「先匹配系统」后,对应用例变红 |
64+
| T5 | 单测:MSVC 目标的 link model 产出三组 token,并进入缓存键;Windows CI 构建一个 `import std` 程序 | MinGW 目标的 token 为空 |
65+
| T7 | Windows e2e 的五条 | — |
66+
| T9 | 安装后 `include-fixed` 里没有带横幅的文件 | 撤回修正后断言变红 |
67+
| T12 | 沙箱里所有检查通过,并把没有运行的检查单独列出 | — |

‎.agents/docs/2026-09-24-toolchain-selection-verify.sh‎

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

‎.agents/docs/README.md‎

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ superseded_by: 2026-09-07-....md # when status is superseded
1818
---
1919
```
2020

21-
303 records.
21+
306 records.
2222

2323
## By subject
2424

@@ -30,6 +30,7 @@ Records that declare one. Everything else is listed by date below.
3030

3131
### design
3232

33+
- [MSVC toolset 的选择、#685、#687 与工具链管理规范:总体设计](2026-09-24-toolchain-selection-and-payload-trust-design.md) — active
3334
- [openkal 生态:能力的时刻模型,以及 C 环境方案空间的划分](2026-09-20-openkal-c-environment-ecosystem-design.md) — active
3435
- [#674:`presents = "posix"` 在 Windows 上兑现契约的下半段](2026-09-19-issue-674-cenv-posix-preinclude-design.md) — superseded
3536
- [The build database of #636, and two defects on the way to the latest xlings](2026-09-14-636-build-database-and-the-latest-xlings.md) — active
@@ -52,6 +53,7 @@ Records that declare one. Everything else is listed by date below.
5253

5354
### plan
5455

56+
- [工具链选择与载荷可信度:实施计划](2026-09-24-toolchain-selection-implementation-plan.md) — active
5557
- [openkal 生态:完整性收尾与验收方案](2026-09-21-openkal-ecosystem-completion-and-acceptance.md) — active
5658
- [C 环境生态方案:执行计划](2026-09-20-ecosystem-execution-plan.md) — active
5759

@@ -75,6 +77,7 @@ Records that declare one. Everything else is listed by date below.
7577

7678
### triage
7779

80+
- [#685、#687 与 Windows clang 的 MSVC STL:三个问题的归属,以及工具链载荷的规范化](2026-09-24-685-687-msvc-stl-and-toolchain-payloads.md) — active
7881
- [运行时绑定方案 v3:让 mcpp 真正安装它所声明的运行时](2026-09-17-runtime-binding-multi-repo-plan.md) — landed
7982
- [#662:目标侧由依赖图提供时,编译器的隐式头文件搜索仍指向宿主](2026-09-17-issue-662-graph-target-header-isolation-plan.md) — active
8083
- [Issue #660 分析:`glibc@2.44` 绑定在 2.44.3 发布后解析失败](2026-09-17-issue-660-glibc-line-binding-analysis.md) — landed
@@ -94,6 +97,9 @@ Records that declare one. Everything else is listed by date below.
9497

9598
### 2026-09
9699

100+
- [工具链选择与载荷可信度:实施计划](2026-09-24-toolchain-selection-implementation-plan.md) — active
101+
- [MSVC toolset 的选择、#685、#687 与工具链管理规范:总体设计](2026-09-24-toolchain-selection-and-payload-trust-design.md) — active
102+
- [#685、#687 与 Windows clang 的 MSVC STL:三个问题的归属,以及工具链载荷的规范化](2026-09-24-685-687-msvc-stl-and-toolchain-payloads.md) — active
97103
- [openkal 生态:完整性收尾与验收方案](2026-09-21-openkal-ecosystem-completion-and-acceptance.md) — active
98104
- [本轮生态级自审](2026-09-20-wave-self-review.md) — active
99105
- [openkal 生态:能力的时刻模型,以及 C 环境方案空间的划分](2026-09-20-openkal-c-environment-ecosystem-design.md) — active

‎CHANGELOG.md‎

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,90 @@
33
> 本文件追踪 `mcpp-community/mcpp` 公开仓的版本演进。
44
> 格式参考 [Keep a Changelog](https://keepachangelog.com/zh-CN/1.1.0/)。
55

6+
## [2026.9.24.1] - 2026-09-24
7+
8+
### MSVC ABI 上的 toolset:只选一次,可以指定,记录在案
9+
10+
clang 以 `*-windows-msvc` 为目标时,编译所针对的 MSVC 环境(STL、CRT、Windows SDK)由两个互不相关的
11+
选择器决定:clang 驱动自己探测头文件与库(`VCToolsInstallDir`、`PATH`、最新实例的默认 toolset,
12+
`%INCLUDE%` 存在时整体采用它),mcpp 另行按 `VSINSTALLDIR`、`vswhere -latest`、目录名最大者定位
13+
`std.ixx`。机器上装有多个 toolset 时,两者可能指向不同的 toolset;项目无法指定用哪一个;选择结果
14+
既不进缓存键,也不出现在任何记录里。
15+
16+
现在 MSVC toolset 是这一行的 sysroot,由 `[target.<triple>].sysroot` 指定,prepare 解析一次:
17+
18+
```toml
19+
[toolchain]
20+
windows = "llvm@22.1.8"
21+
22+
[target.x86_64-windows-msvc]
23+
sysroot = "msvc@14.44.35207" # 或 "msvc@system"(默认),或 "xim:msvc@14.44.35207"
24+
```
25+
26+
结果以 `-Xmicrosoft-visualc-tools-root`、`-Xmicrosoft-windows-sdk-root`、
27+
`-Xmicrosoft-windows-sdk-version` 传给编译、链接与 `std` 模块预编译(这几个是 clang-cl
28+
`/vctoolsdir` 等选项的别名;带上它们后,clang 不再读 `VCToolsInstallDir` 与 `%INCLUDE%`),
29+
`std.ixx` 取自同一个 toolset。构建打印一行 `Resolved sysroot msvc@system → MSVC <版本> (...)`,
30+
`resolution.json` 新增 `msvc_toolset` 与 `windows_sdk`,toolset 目录与 SDK 版本进入缓存键,
31+
SDK 版本也成为这一行的运行时身份 `ucrt@<版本>`。
32+
33+
写法在 cl.exe 行与 clang 行上相同:
34+
35+
| 写法 | 含义 |
36+
|---|---|
37+
| `msvc@system` | 本机默认:`VCToolsInstallDir` → `VSINSTALLDIR` 实例的默认 toolset → `PATH` 上的 `cl.exe` → 带 C++ 组件的最新实例的默认 toolset |
38+
| `msvc@<toolset>` | 本机已装的同版本 toolset 优先(所有实例中查找),没有时安装载荷;环境变量不参与,被忽略时打印说明 |
39+
| `xim:msvc@<toolset>` | 只用载荷,SDK 随载荷固定 |
40+
41+
`xim:` 是唯一的工具链命名空间。gcc、llvm 的工具链总来自载荷,`xim:gcc@16.1.0` 与 `gcc@16.1.0` 等价,
42+
这一点与过去相同;过去任何 `<ns>:` 前缀都被静默剥掉,现在其他命名空间在读取处被拒绝。`xim:msvc@system`
43+
不是一种写法,同样在读取处被拒绝(过去它在更晚的阶段失败,Linux 上报的是「只在 Windows 宿主可用」)。
44+
45+
**行为变化。** `msvc@<toolset>` 过去一律使用载荷;现在机器上有同版本时直接用机器的那一份,SDK
46+
随之取机器上的。需要载荷(连同它的 SDK)的项目改写为 `xim:msvc@<toolset>`。cl.exe 行的
47+
`msvc@system` 改为取实例的默认 toolset(`Microsoft.VCToolsVersion.default.txt`)而不是目录名最大者,
48+
并开始读取 `VCToolsInstallDir`;某个 toolset 缺少 `std.ixx` 时,不再借用另一个 toolset 的。
49+
cl.exe 行上指向另一个 toolset 的 `sysroot` 被拒绝。`mcpp toolchain list` 在 Windows 上列出
50+
本机已装的 toolset。
51+
52+
**旧引擎读新写法。** 在 Windows runner 上用 2026.9.21.3 实测:MSVC 行上的 `sysroot = "msvc@system"`
53+
与 `"msvc@<toolset>"` 让整份清单被拒(「is not an xpkg reference」);`"xim:msvc@<toolset>"` 被接受
54+
而不生效:不安装任何东西,clang 针对机器上的 toolset 编译,构建输出却把这个值列为 c-abi 层。
55+
依赖所写 toolset 的项目应把 mcpp 固定在 2026.9.24.1 或更高。
56+
57+
### `macos_deployment_target` 按目标生效,不再按宿主(#685)
58+
59+
在 Linux 或 Windows 宿主上 `mcpp build --target aarch64-macos`,产物的 `LC_BUILD_VERSION minos` 恒为
60+
14.0:`[build] macos_deployment_target` 与 `MACOSX_DEPLOYMENT_TARGET` 都被忽略,改了值也不重建。
61+
解析函数只在 `#if defined(__APPLE__)` 下读这两个输入,其他宿主上返回空,三元组于是回落到内置的
62+
`14.0`;指纹也只在宿主是 macOS 时折入这个值;平台事实 `macos.deployment-target` 同样为空,包里
63+
针对它的版本要求在这种构建里不被检查。反方向同理:macOS 宿主交叉到非 Apple 目标时,编译命令里
64+
仍带 `-mmacosx-version-min`。
65+
66+
现在解析(env > manifest > 14.0)与宿主无关,是否适用由构建的目标决定:三元组、指纹、平台事实、
67+
`-mmacosx-version-min` 与 std 模块预编译都按目标判定;build.mcpp 的宿主编译按它自己的目标(即宿主)
68+
判定。macOS 宿主构建 macOS 目标时输出不变。判据是 `tests/e2e/746_…`:在 Linux 宿主上用
69+
`[target.aarch64-macos] toolchain = "llvm@…"` 走 `--configure-only`,不需要 macOS SDK,断言
70+
`--target=arm64-apple-macos11.0`、改值后指纹变化、env 优先于 manifest;把修复撤回,三条全红。
71+
72+
### `mcpp self doctor` 报告 gcc 载荷里冻结的 fixincludes 头(#687)
73+
74+
gcc 13.3.0、15.1.0(以及 11.5.0)的 x86_64-linux-gnu 载荷在 `include-fixed/` 里带着构建机上 glibc
75+
头的 fixincludes 副本(`pthread.h` 等)。它们在搜索顺序上排在构建所用的 glibc 2.44 之前,于是
76+
`<mutex>`、`<memory>` 编译失败。索引里本有一段安装时删除它们的清理代码,但单引号嵌套让 grep 搜索的是
77+
当前目录而不是载荷,从未生效;配方的修正在 openxlings/xim-pkgindex#870,新安装会被清理。
78+
79+
已安装的载荷不会因为索引更新而重新清理。doctor 新增一项检查:列出每个 gcc 载荷里带
80+
`auto-edited by fixincludes` 横幅的文件、横幅里的源路径,以及重装命令
81+
(`mcpp index update`,然后 `mcpp toolchain remove gcc@<v>` 与 `mcpp toolchain install gcc@<v>`)。
82+
这是警告,不是失败。
83+
84+
### SPEC-006:工具链管理(草案)
85+
86+
`docs/specs/toolchain-management.md`:身份与写法、来源与选择、载荷契约、构建、验收与发布顺序,
87+
每条标注实现状态。载荷契约与验收(载荷 lint、编译器 × C 库兼容矩阵、准入门进 CI)计划与下一批
88+
LLVM 工具链一同实现。
89+
690
## [2026.9.21.3] - 2026-09-21
791

892
### `mcpp test --no-run`:为一个跑不了的目标构建测试,并把这当成答案

‎docs/04-mcpp-toml.md‎

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -708,7 +708,10 @@ cargo/rustc, cc, etc.) > this field (the project default, similar to SwiftPM's
708708
`platforms:`) > the **built-in default `14.0`** (rustc-style — every target has a
709709
baseline, and 14.0 is the floor of LLVM's official static libraries themselves).
710710
This value enters the BMI fingerprint, so switching targets automatically rebuilds
711-
the module cache.
711+
the module cache. Resolution and application both follow the TARGET, not the
712+
machine running mcpp: `mcpp build --target aarch64-macos` honors this field
713+
(and the environment variable) the same way on Linux or Windows as it does on
714+
a Mac, and a non-macOS target never sees it.
712715

713716
### Build concurrency (`jobs`) and module scheduling (`bmi_schedule`)
714717

‎docs/09-commands-by-scenario.md‎

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -224,8 +224,9 @@ $ mcpp xpkg parse mcpp.plugins.lua --json
224224
## Environment diagnosis
225225

226226
`mcpp self doctor` checks the toolchain, the `std` module, the registry, cache
227-
health and the last runtime-closure verdict, and reports what it found rather
228-
than only what failed:
227+
health, the last runtime-closure verdict, and installed GCC payloads for
228+
fixincludes-frozen headers left over from the build machine that produced
229+
them, and reports what it found rather than only what failed:
229230

230231
```
231232
$ mcpp self doctor

0 commit comments

Comments
 (0)