Skip to content

Latest commit

 

History

History
185 lines (153 loc) · 13.1 KB

File metadata and controls

185 lines (153 loc) · 13.1 KB

SPEC-007:构建插件:配置、施工与校验的分工,运行时与规划期的义务

项 值
规范编号 SPEC-007
标题 构建插件:配置、施工与校验的分工,运行时与规划期的义务
状态 草案 v0.2
版本 0.2
最后修改 2026-09-26
对应实现 逐条标注。未注明版本的「已实现」条款对应 mcpp >= 2026.9.26.1;注明 mcpp#702 的条款对应 mcpp >= 2026.9.26.2
相关设计文档 .agents/docs/2026-09-26-compile-database-and-issue-699-design.md(§5)
相关 issue mcpp#699、mcpp#701、mcpp#702、mcpp#703
使用文档 docs/30 - build.mcpp、docs/31 - 编写规则包

本规范规定构建插件对引擎和对消费方承担的义务,以及引擎为此提供的机制。docs/31 说明怎样编写 插件,本规范规定插件必须满足什么。

规范用语与实现状态标记见 规范索引。只约束插件作者、引擎不做检查的条款标注 「作者义务」。

0. 适用范围

构建插件是为其他包的构建贡献工作的包,以及它导入消费方构建程序的模块(rule_module、 host-module)。

类别 例 贡献
规则包 rules-qt、rules-spirv、rules-cuda 代码生成,设备语言的编译
依赖适配包 deps-vcpkg、deps-cmake 把外部包管理器或外部构建系统的产物接入构建
分发成员 dist-wix、dist-apk 由链接产物生成可安装的分发物

项目自己的 build.mcpp 中的同类代码同样适用本规范。

分工。 mcpp 只提供通用机制:指令、action 的角色、stamp、运行时库的搜索与放置。某一个 工具(vcpkg、CMake、Qt)的知识只属于它的插件。插件遇到的缺口若是通用的,由 mcpp 以通用机制 补上(第 3.3 节的 prepare、第 4.1 节的 runtime_search_dir、第 4.3 节的 DLL 放置),而不 由插件绕过。

1. 三类工作

插件所做的每一件事属于且只属于下表的一类。

类 定义 发生在 机制
配置 决定构建的形状:编译哪些源、用哪些选项、链接什么、运行时在哪里找库 构建程序运行时,即规划期 指令(第 2 节)
施工 产生构建读取的文件:生成源码、编译设备代码、安装依赖前缀、打包 构建期 mcpp::action(第 3 节)
校验 判断环境或产物是否满足要求,不产生构建读取的文件 构建期 role = "check" 的 action
  • R1.1 施工必须声明为 action,禁止在构建程序运行期间进行。构建程序可以运行工具 来查询配置所需的答案(版本、选项、路径),禁止借此产生构建读取的文件。(作者义务; action 自 2026.8.5.1 已实现)
  • R1.2 校验必须是 check action。构建程序发现环境不完整(缺少一个 SDK 模块、缺少 一个库)时,必须用 mcpp::warning 报告,并输出它能确定的全部配置;禁止因环境不完整 以非零状态退出。编译或链接会在缺失处失败,位于该警告之后。(作者义务)
  • R1.3 配置必须只取决于构建程序声明的输入:包的清单、声明的载荷,以及 rerun_if_changed、rerun_if_changed_glob、rerun_if_env_changed 列出的文件、glob 与 环境变量。配置禁止依赖施工的结果,例如枚举一个安装前缀中由 action 产生的文件:规划 (mcpp emit build-database)与第一次构建都发生在施工之前,依赖施工结果的配置在第一次与 第二次构建之间不同。(作者义务;构建程序的重新运行依据落在一个 prepare action 声明的目录内 时,引擎给出一条警告并点名两者,已实现,mcpp#702)
  • R1.4 构建程序在规划与构建中必须行为相同。引擎不提供「正在规划」的信号,因为规划 所描述的计划与 mcpp build --configure-only 计算的计划相同(SPEC-005 R1.2)。(已实现)

2. 配置:指令

  • R2.1 下表中的配置必须用对应的指令表达;禁止用 link_flag、cxxflag 拼写表中 已有指令所表达的内容(例如以 -Wl,-rpath, 代替运行时搜索目录,以 -I 代替头文件目录)。 指令由引擎按平台渲染、去重,并进入缓存与构建数据库。(作者义务)

    配置 C++ 接口 线格式 自
    头文件目录 include_dir、include_dir_after include-dir、include-dir-after 协议 1
    编译选项 cxxflag、cflag cxxflag、cflag 协议 1
    宏 define cfg 协议 1
    链接库与库目录 link_lib、link_search link-lib、link-search 协议 1
    其他链接选项(含库的完整路径) link_flag link-flag 协议 8
    运行时搜索目录 runtime_search_dir runtime-search-dir 协议 12(mcpp#702)
    放到程序旁的文件 deploy deploy 协议 11
    生成的源 generated、source 与 role = "source" 的 action generated、source、action 协议 1
    重新运行构建程序的依据 rerun_if_changed、rerun_if_changed_glob、rerun_if_env_changed 同名 协议 1、2
    报告与探测 warning;fact、floor 同名 协议 5、7
  • R2.2 相对路径按声明它的包的根目录解析。插件禁止把宿主系统目录(/usr/include、 /usr/lib、/lib、C:\Windows\System32 及同类)声明为头文件、链接或运行时搜索目录;SDK 与工具的路径取自声明的载荷(mcpp::xpkg_dir)或依赖边(mcpp::dep_dir、mcpp::dep_bin)。 (作者义务;对图目标的链接,引擎检查 -L,mcpp#696 已实现)

  • R2.3 插件必须使用现行字段的指令,禁止依赖只为兼容而保留的字段 ([runtime] library_dirs,docs/04 §2.11)。(作者义务)

  • R2.4 链接选项的一个元素按 SPEC-004 §8 读成词,每个词原样到达链接器。插件禁止依赖 引擎内部的转义拼写(例如 '$$ORIGIN')。(已实现,mcpp#703;此前 ldflags 与 link_flag 中的 $ 会被宿主 shell 展开)

3. 施工:action

  • R3.1 action 的命令是 argv,禁止假定 shell。命令调用的工具必须列为输入;命令 自己发现的输入用 depfile 报告。(argv 与 depfile 已实现;工具作为输入是作者义务)

  • R3.2 action 必须在提交时命名它的输出文件,因为引擎在规划期确定源集合、指纹与模块 图。输出文件名在施工前无法得知的工作(安装一个前缀、解开一个 SDK)使用 prepare 角色。 (已实现;prepare 随 mcpp#702)

  • R3.3 角色:

    role 输出 顺序
    source 可编译的输出加入声明包的编译集 声明包的每条编译边等待它
    object 加入链接集 链接边消费它
    artifact 新文件,输入是链接产物 链接之后
    check 引擎写的 stamp 与编译并行;blocking = true 时声明包的编译边等待它
    prepare 引擎写的 stamp;命令填充它用 output_dir 声明的目录,构建按目录引用其内容 声明包的每条编译边与计划中的每条链接边(静态库归档除外)等待它

    prepare(已实现,mcpp#702)是施工,不是校验,任何只针对校验的策略都不作用于它;构建 输出以 PREPARE 标注它。它的产物由配置以目录为单位引用(include_dir、link_search、 runtime_search_dir),或以 link_flag 中的完整路径引用;这些名字在配置时确定,内容在施工 时到达。一个 prepare action 必须用 output_dir 声明它填充的目录(缺少时引擎拒绝该 action);命令成功而该目录不存在,或除该 action 的 stamp 之外不含任何文件时,引擎不写 stamp,并以指出该目录的消息使这条边失败。链接边等待所有 prepare,因为每个包的链接全局 指令并入整个计划共用的一份链接意图。

  • R3.4 check 只用于校验,禁止用来表示施工。(作者义务)

  • R3.5 check 与 prepare 的命令成功后,引擎创建或更新它们的 stamp,使 stamp 新于该 action 的每个输入;命令失败时不写 stamp。命令无需自己写 stamp。(创建自 2026.8.29.1 已实现;更新 已实现,mcpp#702;此前一个已存在的 stamp 不被更新,输入改变一次后该 action 在此后每次构建中都会重新运行)

  • R3.6 角色应当以常量书写(mcpp::roles::source、check、object、artifact、 prepare),使不认识该角色的旧引擎在编译构建程序时拒绝它;引擎拒绝未知的角色字符串,并列出 五个角色。(已实现,mcpp#702;此前引擎把未知的角色字符串当作 source)

  • R3.7 构建期不应访问网络:下载属于安装期(载荷的安装、依赖的解析)。一个必须在构建期 下载的 action(例如由包管理器取得源码)必须在其说明中写明,并在离线构建中 (--offline 或 MCPP_OFFLINE=1;前者在进程环境中设置后者,action 继承之)不访问网络: 从缓存完成,或以指出缺失内容的消息失败。(作者义务;环境传递 已实现)

4. 运行时:程序依赖的共享库的查找

  • R4.1 一个目录中的共享库由施工产生(prepare)或文件名不定时,插件必须用 runtime_search_dir 声明该目录。引擎把它用于 ELF 与 Mach-O 的运行路径(RUNPATH/rpath, 从不作为 -L)、mcpp run 的加载路径、mcpp pack 的闭包搜索与运行时校验,并把依赖包的 声明传到消费方的可执行文件。(已实现,mcpp#702)
  • R4.2 一个在配置时已知的文件需要位于程序旁的某个相对位置时(Qt 的平台插件、Vulkan 的 ICD 清单),插件用 deploy。(已实现,协议 11)
  • R4.3 Windows 的可执行文件没有运行路径。mcpp run 通过 PATH 使用运行时搜索目录, mcpp pack 把闭包需要的 DLL 放到程序旁(已实现)。链接之后,引擎把程序直接或间接导入的、 位于其运行时搜索目录中的非系统 DLL 放到程序旁,使从构建目录直接启动的程序同样能找到它们; 闭包的求解与 mcpp pack 相同,DLL 在其目录中被替换后下一次构建再次放置。(已实现, mcpp#702)
  • R4.4 插件禁止在 link_flag 中写运行路径(-Wl,-rpath,...),必须使用 R4.1。 (作者义务)

5. 规划期的义务(mcpp emit build-database)

  • R5.1 规划运行构建程序,不运行任何 action(SPEC-005 R2.2)。插件遵守 R1.3 时,规划得出 的配置与构建相同。(已实现)
  • R5.2 一个包的构建程序在规划中失败时,该包只按其清单描述,并得到一条错误诊断;成员的 其余部分照常描述。插件遵守 R1.2 时,环境不完整不会使构建程序失败。(已实现,mcpp#702)
  • R5.3 插件所需的宿主工具在规划中构建失败时,规划继续,构建程序收到该工具将被发布的路径, 并产生一条警告。插件应当在 action 中运行宿主工具,而不是在构建程序中运行,使规划不依赖 工具能否构建。(引擎部分 已实现,mcpp#702;「应当」为作者义务)

6. 环境与载荷

  • R6.1 插件驱动的工具与 SDK 必须声明为载荷([xlings] 或 [feature-xlings]),需要 时以目标轴选择器门控,并在构建程序中用 mcpp::xpkg_dir 取得路径。声明必须放在查询发生 的包上:xpkg_dir 为正在构建的包回答;host-module 的声明对编入它的每个构建程序可见 (docs/31)。(已实现)
  • R6.2 插件禁止探测宿主路径来寻找工具或 SDK;未声明的依赖不可复现。(作者义务)

7. 版本与兼容

  • R7.1 使用协议 N 的指令或角色的插件,必须在其文档中写明第一个支持协议 N 的 mcpp 版本。索引测量该插件时,CI 所用的 mcpp 版本移到该版本;索引的 min_mcpp 不因此改变。旧引擎 编译该构建程序时因缺少函数或常量而失败,并指出其名称。(编译期失败 已实现)
  • R7.2 插件禁止依赖引擎内部的拼写与未写入文档的行为(R2.3、R2.4)。(作者义务)

8. 判据

  • R8.1 插件必须在它声明支持的每个平台上有一个在该平台运行的判据。# requires: gcc 只在 Linux 成立,不能作为 Windows 或 macOS 的判据。(作者义务)
  • R8.2 每个判据必须在它所验证的改动之前失败。(作者义务)
  • R8.3 插件应当有一个规划判据:它的一个消费方工程,在没有安装其载荷的机器上运行 mcpp emit build-database,得到一份文档,其中该插件只贡献警告,或只使声明它的包缺少 构建程序的指令(R5.2),而不是整次失败。(作者义务)

9. 变更记录

版本 日期 变更
0.1 2026-09-26 首版草案(mcpp#699、#701、#702、#703)。
0.2 2026-09-26 随 mcpp 2026.9.26.2 落地:R1.3 的警告、R2.1 的 runtime_search_dir、R2.4、R3.3 的 prepare(目录须含文件;链接边等待所有 prepare)、R3.5、R3.6、R4.1、R4.3、R5.2、R5.3 标为已实现。