fix(build.mcpp): 规则包能用 import std; 与 import mcpp; (2026.8.5.2) - #357
Merged
Conversation
`host-module = true` 是 2026.8.5.1 加的:一条构建规则以普通 mcpp 包分发,消费者
在 build.mcpp 里 `import` 它。机制本身成立,但两个缺陷叠在一起,使它**只能承载
手工 printf 指令的玩具规则** —— 规则一旦去用它本该用的那套 API 就编不过。
第一个真实使用者(grpc-m 的 protoc/gRPC codegen 规则)在第一分钟同时撞上两个。
e2e 189 之所以一直是绿的,是因为它的规则只 `#include <cstdio>` 再 printf,恰好
把两个缺陷都绕开了。
── 1. 规则里的 `import std;` ────────────────────────────────────────────────
`build_program.cppm` 先编 host module、后建 std 模块,规则拿到的 `stdFlags` 是
空的,报 `module 'std' not found`。而且「是否需要 std」只扫 build.mcpp 的源码,
所以一条**只有规则**用 `import std;` 的构建根本不会去建 std 模块。
两处都修:扫描把规则接口一并计入(usesStd / usesStdCompat / usesModule 三者都
是并集),std 那一段整体挪到编译 host module **之前**,并把 stdFlags 传进
build_host_module 的 extraUseFlags。顺序是承重的,不是风格:BMI 必须先存在、
stdFlags 必须先指向它,规则才可能 import 它。
── 2. 规则里的 `import mcpp;` ───────────────────────────────────────────────
`host-module = true` 只做了「注册这个模块」。`prepare.cppm` 从头到尾只**读**
`spec.hostModule`,从没把这个包移出消费者的**普通依赖图** —— 于是同一个 `.cppm`
又被当成消费者的一个普通库编了一遍,而那次编译里内置 `mcpp` 模块并不存在:
failed: obj/grpcgen/src/grpcgen.m.o
fatal error: module 'mcpp' not found
一条构建规则是纯构建期的东西,本来就不该进消费者的二进制 —— Cargo 用
`[build-dependencies]` 划的是同一条界线。现在只经由 root 的 host-module 边到达
的包会被清空源码集(与 feature-gated sources 的丢弃用同一套机制),不再参与编译
与链接;解析不动,因为 lib 根要从磁盘上读。
**有护栏**:同一个包完全可以既是规则、又是别处(或 root 另一种拼法)的普通库。
只在「指向它的边全部来自 root」时才清空,否则会变成一个离现场很远的 undefined
reference。
── 测试 ─────────────────────────────────────────────────────────────────────
e2e 189 扩了两条断言,并且**先验证过它们在 2026.8.5.1 上是红的**:
- 一条同时 `import std;` 和 `import mcpp;` 的规则必须能建、指令必须落地;
- `obj/rules/**.o` 必须不存在 —— 规则包被当普通库编译过就会留下它。
本地 e2e 全量:除 03/07/09 三条既有的环境性失败外全绿(已对released 2026.8.4.1
核对过,与本改动无关)。
── 文档 ─────────────────────────────────────────────────────────────────────
`docs/05-mcpp-toml.md` 的示例写的是 `import mcpp.rules.protobuf;`,**做不到**:
mcpp 用依赖的裸 `package.name` 注册 host 模块,而 SPEC-001 要求 `name` 是单一
原子段。顺带写明一条会咬人的约束:规则包的名字必须是合法 C++ 模块名(`grpcgen`
可以,`grpc-rules` 不行),否则报的是 `module 'grpc_rules' not found`,不会提示
你名字有问题。中英文档同步。
bootstrap pin 不动(仍 2026.8.4.1):它是自举起点,不随发布走。
aarch64 fresh-install job 在 clone 出 mcpp 源码后直接死在:
[error] xlings: version '2026.8.4.1' not found for 'mcpp'
[error] available: 2026.8.5.1
`.xlings.json` 的 bootstrap pin 停在 2026.8.4.1,而 **xim-pkgindex 只保留一个
mcpp 版本**。2026.8.5.1 一发布,2026.8.4.1 就不再可安装 —— 于是「从已发布的
mcpp 自举」这条路当场断掉。
pin 挪到 2026.8.5.1(= 当前最新已发布版本)。
顺带把这条不变式写进 check_version_pins.sh:此前那段注释只讲了**上界**
(「绝不能跑在被构建版本前面」,那是它自己踩过的坑),没讲**下界**。两边合起来
才是完整规则:**发布 N 之后,发布收尾的那个 commit 把 pin 设成 N** —— 不能超前
(check (c) 机器校验),也不能落后超过一个版本(校验不了,它需要索引,所以只会以
上面那条错误现身;注释里写清楚了下次去哪儿看)。
「Self-host — build mcpp + xlings from source」这一步固定克隆上游 main。于是 这道关卡从来没有验证过 PR 本身:一个会破坏「从源码自举」的改动能顺利通过它, 只在合入之后才炸。 这次是以最刺眼的方式暴露的 —— 上一个 commit 修的正是本仓库的 bootstrap pin, 而那个修复**无法被验证**:修复在分支上,克隆的却是 main,于是 job 继续报 `version '2026.8.4.1' not found`。 PR 上改为自举**被评审的那份代码**;非 PR 场景没有 head ref,main 本来就是对的。 用 fetch-by-sha 而不是 `clone --depth 1`(后者不接受 sha)。
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
问题
host-module = true是 2026.8.5.1 加的:一条构建规则以普通 mcpp 包分发,消费者在build.mcpp里import它。机制成立,但两个缺陷叠在一起,使它只能承载「手工 printf 指令」的玩具规则 —— 规则一旦去用它本该用的那套 API 就编不过。第一个真实使用者(grpc-m 的 protoc/gRPC codegen 规则)在第一分钟同时撞上了两个。
1. 规则里的
import std;build_program.cppm先编 host module、后建 std 模块,规则拿到的stdFlags是空的:而且「是否需要 std」只扫
build.mcpp的源码 —— 一条只有规则用import std;的构建根本不会去建 std 模块。修法:扫描把规则接口一并计入(
usesStd/usesStdCompat/usesModule三者取并集),std 那一段整体挪到编译 host module 之前,stdFlags传进build_host_module的extraUseFlags。顺序是承重的,不是风格问题:BMI 必须先存在、
stdFlags必须先指向它,规则才可能 import 它。2. 规则里的
import mcpp;host-module = true只做了「注册这个模块」。prepare.cppm从头到尾只读spec.hostModule,从没把这个包移出消费者的普通依赖图 —— 同一个.cppm又被当成消费者的一个普通库编了一遍,而那次编译里内置mcpp模块并不存在:修法:一条构建规则是纯构建期的东西,本来就不该进消费者的二进制 —— Cargo 用
[build-dependencies]划的是同一条界线。只经由 root 的 host-module 边到达的包会被清空源码集(与 feature-gated sources 的丢弃用同一套机制),不再参与编译与链接。解析不动,因为 lib 根要从磁盘上读。有护栏:同一个包完全可以既是规则、又是别处(或 root 另一种拼法)的普通库。只在「指向它的边全部来自 root」时才清空 —— 否则会变成一个离现场很远的 undefined reference。
效果
消费者的
build.mcpp从约 60 行降到 3 行,而那 60 行搬进了一个有版本、能测试、能发布的包:验证
import std;和import mcpp;的规则必须能建,指令必须落地;obj/rules/**.o必须不存在 —— 规则包被当普通库编译过就会留下它。03_multi_module/07_static_library/09_path_dependency三条既有的环境性失败外全绿(已对 released 2026.8.4.1 核对过,与本改动无关)。grpcgen规则包在打了本 PR 的二进制上跑通,生成→编译→链接→真实 RPC 全链路。文档
docs/05-mcpp-toml.md的示例写的是import mcpp.rules.protobuf;,做不到:mcpp 用依赖的裸package.name注册 host 模块,而 SPEC-001 要求name是单一原子段。顺带写明一条会咬人的约束:规则包的名字必须是合法 C++ 模块名(grpcgen可以,grpc-rules不行),否则报的是module 'grpc_rules' not found,不会提示你名字有问题。中英文档同步。版本
2026.8.5.2。bootstrap pin 不动(仍2026.8.4.1)—— 它是自举起点,不随发布走。