Skip to content

Latest commit

 

History

History
230 lines (145 loc) · 11.6 KB

File metadata and controls

230 lines (145 loc) · 11.6 KB

SPEC-006:工具链管理

规范编号 SPEC-006
标题 工具链管理:身份、来源、选择与载荷契约
状态 草案 v0.2
最后修改 2026-09-24
对应实现 逐条标注;标为「已实现」的条款对应 mcpp >= 2026.9.24.1。标为「未实现」的条款计划与下一批 LLVM 工具链一同落地,届时按实测修订本规范
相关设计文档 .agents/docs/2026-09-24-toolchain-selection-and-payload-trust-design.md.agents/docs/2026-09-24-685-687-msvc-stl-and-toolchain-payloads.md
相关 issue mcpp#685、mcpp#687
使用文档 docs/20 - 工具链docs/32 - 编写载荷docs/91 - 工具链内部

本规范定义 mcpp 对工具链的命名、选择和使用方式,以及一个工具链载荷在发布前必须满足的条件。 目标侧的层模型见 SPEC-002;清单的平面划分与解析轴见 SPEC-004

用语按 RFC 2119:必须 / 禁止(强制)、应当(强烈建议)、可以(可选)。


1. 术语

术语 含义
工具链 执行编译的程序及其随附部分:编译器驱动、编译器运行时(builtins 与展开器)、随编译器发布的 C++ 标准库、汇编器、链接器与归档工具
载荷 由 xlings 从索引安装的预构建目录树,身份为命名空间、名字与版本
来源 工具链或 sysroot 的出处:managed(生态包)或 system(在本机定位)
sysroot 编译时所针对的目标环境。Linux 目标上是 C 库载荷;MSVC ABI 目标上是 MSVC toolset(STL、vcruntime、CRT)及其 Windows SDK
构建环境 产出一个载荷的机器或容器,以及其中的 C 库

2. 身份与写法

2.1 基本写法 已实现

工具链必须写作 <族>@<版本>,族为 gccllvmmsvcemsdkandroid-ndk。 部分版本必须解析为匹配的最高版本。

2.2 系统来源 已实现

只有 msvc 有系统来源,写作 msvc@system。其他族写 @system,必须在读取处被拒绝。 不带族的 system(PATH 上的编译器)必须被拒绝,拒绝信息给出可用的写法。

2.3 生态包前缀 已实现

xim:<族>@<版本> 表示只取生态包。对没有系统来源的族,它与不带前缀的写法等价,规范写法去掉前缀; 对 msvc,前缀改变含义,规范写法保留前缀。xim:msvc@systemxim: 之外的命名空间必须被拒绝。

2.4 带版本的 msvc 写法 已实现

msvc@<版本> 必须先在本机已安装的 toolset 中匹配,匹配不到再取生态包;规则见 §3.4。 mcpp toolchain default msvc@<版本> 在本机已有该 toolset 时必须直接接受,不要求先安装生态包。

2.5 版本匹配 部分实现

前缀必须按版本分量匹配:14.4 匹配 14.4.x,不匹配 14.44。「最高」必须按数字元组比较。

当前:本机 MSVC toolset 的匹配与比较按本条实现;其他族的前缀匹配方式未逐一核对。


3. 来源与选择

3.1 一次选择 已实现

一次构建中,工具链及其 sysroot 必须只解析一次;编译、依赖扫描、标准库模块、链接与缓存键必须读取同一个结果。 clang 以 MSVC ABI 为目标时,所选 toolset 与 SDK 以 -Xmicrosoft-visualc-tools-root-Xmicrosoft-windows-sdk-root-Xmicrosoft-windows-sdk-version 显式交给编译器驱动,std.ixx 取自同一个 toolset。

3.2 声明优先于探测 部分实现

项目写明的版本必须优先于环境变量与本机扫描;被忽略的环境变量必须以一行说明报告。

条目 状态
受管 MSVC 忽略 WindowsSdkDir 并报告 已实现
VSINSTALLDIR 优先于 vswhere 已实现
写明版本时忽略 VCToolsInstallDirVSINSTALLDIR,并报告 已实现

3.3 结果可见 已实现

凡由探测得到的选择,其来源、版本与 SDK 必须打印在构建输出中,写入 resolution.json,并进入缓存键。 MSVC ABI 目标上:SDK 以 ucrt@<版本> 进入运行时身份;clang 行的 toolset 与 SDK 写入 resolution.jsonmsvc_toolsetwindows_sdk,toolset 目录与 SDK 版本进入缓存键,stdlibVersion 记为 toolset 的版本。

3.4 MSVC 的候选与顺序 已实现

本机候选必须覆盖全部 VS 实例(含预发布版)及每个实例下的全部 toolset。

msvc@system 必须按以下顺序取第一个完整的候选:

  1. VCToolsInstallDir 所指的 toolset;
  2. VSINSTALLDIRVCINSTALLDIR 所指实例的默认 toolset;
  3. PATHcl.exe 所在的 toolset;
  4. 带 C++ 组件、且安装版本最高的实例的默认 toolset;
  5. 没有 vswhere 时,扫描固定路径得到的候选。

带版本的写法必须依次尝试本机候选、已安装的生态包、索引;三者都没有时,必须报错并列出三类候选。

「完整」指本次构建所需的文件都在:库目录;需要 import std 时的 modules/std.ixx;cl.exe 行的 cl.exe。 不完整的候选必须被跳过,并报告。

cl.exe 行与 clang 行使用同一个选择。

3.5 MSVC ABI 目标的 sysroot 已实现

*-windows-msvc 目标上,编译器是工具链,MSVC toolset 是 sysroot。

  • [target.<三元组>].sysroot 在这些行上可以写作 msvc@systemmsvc@<版本>xim:msvc@<版本>,含义同 §2。
  • 未写时必须等同于 msvc@system
  • 编译器为 cl.exe 时,sysroot 必须是该编译器所属的 toolset;另写一个不同的 sysroot,必须被拒绝。
  • SDK 必须跟随 toolset 的来源:生态包 toolset 用随其安装的 windows-sdk 载荷,本机 toolset 用本机扫描的结果。
  • 目标侧报告(SPEC-002)中,c-abi 与 c++ 两层记为预制来源;具体的 toolset 与 SDK 记入 resolution.json(§3.3)。
  • 该值禁止作为 C 库包进入项目环境的安装集合。

3.6 目标属性按目标判定 已实现

描述产物的属性(最低系统版本、三元组中的版本段)必须按目标判定,与宿主无关; 只有在宿主上执行的编译(build.mcpp)按宿主判定。macOS 的 deployment target 在任何宿主上都按目标解析与施加。


4. 载荷契约

4.1 可重定位 部分实现

载荷在使用时禁止依赖构建环境中的路径。以下文件含构建环境的路径,但不参与编译与链接,可以豁免: libtool 的 .la;gcc 的 plugin/include/configargs.hinstall-tools/mkheaders.conf

4.2 不含构建环境的 C 库内容 部分实现

gcc 载荷的 lib/gcc/<三元组>/<版本>/include-fixed/ 禁止含带 fixincludes 横幅(auto-edited by fixincludes)的头文件。 这类头文件是构建环境 C 库的冻结副本,在搜索顺序上排在构建所用的 C 库之前。gcc 自己生成、不带横幅的头文件不受此限。

当前:gcc 13.3.0、15.1.0 与 11.5.0 的 x86_64-linux-gnu 发布归档含这类文件(mcpp#687)。索引中的 gcc 配方在安装时删除它们(openxlings/xim-pkgindex#870 之后生效); 在此之前安装的载荷由 mcpp self doctor 报告(§6.4)。故标为部分实现:安装后的载荷满足本条,发布归档不满足。

4.3 安装时的改写 部分实现

要求 状态
安装后的改写必须限于一张列出的清单:ELF 的 PT_INTERPRUNPATH、clang 的 .cfg 部分实现:改写集中在单一入口,清单未写成规范
改写必须由标记文件 .mcpp-fixup.json 记录 已实现
改写必须经副本与原子重命名完成 部分实现:mcpp 的安装后修正管线如此;xlings 安装时所做的改写未核对
清单之外的文件必须与发布归档一致 未实现:没有检查
gcc 的 specs 禁止在安装时改写 已实现

4.4 完整性 部分实现

载荷必须包含其声明的能力所需的全部文件,例如 llvm 载荷的 share/libc++/v1/std.cppm,以及 libc++ 运行期依赖的 libatomic.so.1

当前:准入脚本检查 llvm 载荷的这几项,但它不在 CI 中运行。

4.5 描述文件 部分实现

载荷根目录的 .mcpp-toolchain.json 已支持 schemafrontendplatform_floorstd_module_definesrunner(已实现)。

应当另外记录来源(未实现):配方所在仓库与提交、编译器的配置行、上游源码的 sha256、构建所用的 C 库及其版本。

4.6 修订与资产名 已实现

一个版本在索引中的内容由 sha256 固定。内容有任何变化,必须使用新的资产名,因为 GitCode 上的发布资产既不能替换,也不能删除。


5. 构建

5.1 配方入库 部分实现

每个发布的载荷必须能由一份检入仓库的配方重新构建。

当前:llvm 子包、musl、glibc 等由 xim-pkgindex 中的构建脚本产出;gcc 由 fromsource 配方产出。已发布的三个 gcc 载荷出自两个不同的构建环境,载荷本身不记录构建环境。配方与构建 CI 所在的仓库待定。

5.2 构建环境 未实现

构建必须在固定的容器中进行;构建 sysroot 必须取自索引发布的 C 库载荷,禁止取自某台机器的 subos。

5.3 可复现等级 部分实现

等级 含义 要求
可重建 由配方与固定输入重新得到功能等价的载荷 必须
可验收 由第 6 节的程序判定合格与否 必须
逐字节可复现 固定时间戳、路径前缀映射与归档顺序 可以

6. 验收

6.1 载荷 lint 未实现

必须有一个程序对一个载荷目录执行 §4.1 至 §4.4 的全部检查,并在发布前运行。 每一项检查必须有反向测试:把对应的缺陷放回载荷,该项检查必须失败。

6.2 兼容矩阵 部分实现

载荷发布或 C 库绑定变化时,必须编译一个矩阵:一维是该目标行在索引中可解析的全部编译器版本,另一维是全部 C 库版本。 格子必须由索引枚举得到,禁止使用手写清单。 每格至少编译一个使用 <memory><mutex><thread> 的程序,以及一个 import std 的程序。 在 MSVC ABI 目标上,矩阵的另一维是 toolset 版本。

当前:描述符变化时,CI 只安装不带版本号时解析出的那一个版本(即 latest),并编译一个 import std 程序。gcc 描述符的改动因此只在 16.1.0 上验证过,13.3.0 与 15.1.0 未被覆盖。

6.3 准入门 部分实现

xim-pkgindex 的准入脚本 verify-toolchain.sh 对一个载荷归档做一次真实的编译、链接与运行,并对 llvm 载荷检查完整性与 CRT 的解析位置(已实现)。

必须在 CI 中运行(未实现),并必须覆盖 §6.2 的程序(未实现)。当前它默认使用 glibc 2.39,测试程序不含线程头文件。

6.4 已安装载荷的诊断 部分实现

mcpp self doctor 必须对已安装的载荷执行 §6.1 中不依赖归档的检查;发现问题时,必须给出重装命令。

当前:doctor 执行 §4.2 的检查(gcc 载荷 include-fixed/ 中带 fixincludes 横幅的文件);§4.1、§4.3、§4.4 的检查未实现。


7. 发布顺序 未实现

移动 C 库绑定或某个载荷的 latest 之前,§6.2 的矩阵必须在新版本上全部通过。


变更记录

版本 日期 变更
v0.1 2026-09-24 初版草案:身份与写法、来源与选择(含 MSVC ABI 目标的 sysroot)、载荷契约、构建、验收、发布顺序
v0.2 2026-09-24 随 mcpp 2026.9.24.1 更新实现状态:§2.3、§2.4、§3.1 至 §3.6 已实现;§4.2、§6.4 部分实现;§2.2 更正:不带族的 system 被拒绝