Skip to content

test(grpc): 新增 grpc-codegen 成员 —— 一条依赖经已发布索引拿到整条工具链 - #174

Open
Sunrisepeak wants to merge 13 commits into
mainfrom
feat/grpc-codegen-member
Open

test(grpc): 新增 grpc-codegen 成员 —— 一条依赖经已发布索引拿到整条工具链#174
Sunrisepeak wants to merge 13 commits into
mainfrom
feat/grpc-codegen-member

Conversation

@Sunrisepeak

Copy link
Copy Markdown
Member

补上 #172 里说明过要单独提的那个成员。当时提不了,是因为它要证明的正是「reexport 经由已发布索引到达消费者」,而那时 mcpplibs.grpcgen 还解析到线上的 -2-3 现已发布并传播。

它是唯一能证明这件事的地方

mcpp 自己的 e2e(193)用 path 依赖;grpc-m 的 examples/greeter 也用 path 依赖(它要测工作树)。两者都不经过索引。

这个成员只声明一条:

[target.'cfg(linux)'.dependencies.grpc]
grpc = { version = "1.83.0", features = ["codegen"] }

build.mcpp 一行 grpcgen::generate_all(),proto/ 里一个 echo.proto。protoc、grpc_cpp_plugin、grpcgen 规则模块全部由 grpc 包交过来,manifest 里一个字都没提。

断言选的是 service,不是 message

const std::string method = echotest::Echo::service_full_name();
if (method != "echotest.Echo") return 1;

只跑 protoc 而没跑 grpc 插件的话,Echo::service_full_name() 根本不存在 —— 半配置的 codegen 编译期就过不去。同时它覆盖 rerun_if_changed_glob:文件清单没有写在任何地方。

本机已跑通:

service = echotest.Echo
grpc-codegen: OK
 test result ok. 1 passed; 0 failed

顺带两处过时陈述

  • tests/examples/grpc-module/mcpp.toml:「gRPC's codegen needs host tools mcpp cannot hand a consumer」—— 自 mcpp 2026.8.6.2 起不成立,reexport = true 正是把它们交出去的机制;
  • pkgs/g/grpc.lua 头部仍写着「归档换成 v1.83.0-2」,现已是 -3

这是唯一能证明 `reexport = true` 真的经由已发布索引到达消费者的地方:mcpp 自己的
e2e 用的都是 path 依赖,grpc-m 的 examples/greeter 也是(它要测工作树)。

成员只声明:

    [target.'cfg(linux)'.dependencies.grpc]
    grpc = { version = "1.83.0", features = ["codegen"] }

build.mcpp 一行 `grpcgen::generate_all()`,proto/ 里放一个 echo.proto,断言生成的
**service** stub 能用(`echotest.Echo`)—— 只跑 protoc 而没跑 grpc 插件的话,
`Echo::service_full_name()` 根本不存在,所以半配置的 codegen 过不了这条。

它同时覆盖 `rerun_if_changed_glob`:文件清单没有写在任何地方。

顺带改掉两处已被本次推翻的陈述:
* grpc-module 里「gRPC's codegen needs host tools mcpp cannot hand a consumer」
  —— 自 mcpp 2026.8.6.2 起不再成立,reexport 正是把它们交出去的机制;
* grpc.lua 头部还写着「归档换成 v1.83.0-2」,现已是 -3。

本机已跑通:service = echotest.Echo / grpc-codegen: OK。
CI:`build.mcpp:8:8: fatal error: module 'grpcgen' not found`。

成员照抄 grpc-module 把 grpc 依赖放在 cfg(linux)/cfg(macos) 下(compat.openssl
没有 windows 条目),但 grpc-module **没有 build.mcpp**;本成员有,而
`import grpcgen;` 是**编译期**依赖 —— docs/01 §4.2 明令不得用 #if 包裹 import,
所以运行期的守卫救不了它。

grpcgen 是纯 C++23 规则包,自身没有平台受限的依赖,索引里**有 windows 条目**。
因此 windows 上单独声明它:import 成立,守在**调用**上早退。与
tests/examples/protobuf-protoc 的处理完全同形(`if target_os == windows return 0`),
成员照常构建,测试编译成一次可见的跳过。

Linux 本机复验:service = echotest.Echo / grpc-codegen: OK。
openssl 的 `assert.h: No such file or directory` 根因是 gcc alias 把安装机的
subos sysroot 写死了;#463 已合入并进入已发布索引(artifact xim-index-5f383b5
里可见 XLINGS_DYNAMIC_SUBOS_DIR)。此前那轮 job 起于修复传播之前。
    Failed to resolve action download info. Error: Service Unavailable

与改动无关;`gh run rerun` 对该 run 不可用,故以空提交触发。
官方状态页确认 Actions partial_outage;上一轮 select 死于
`Failed to resolve action download info: Service Unavailable`,lint 被连带取消,
workspace 因此全部 skip。与改动无关。
grpc-codegen 在 linux 上死于 compat.openssl 的 install():
`stdlib.h: No such file or directory`。同一个成员在 macOS(那里
openssl 用 /usr/bin/cc)和 windows 上都过,而它的姊妹 grpc-module
排在第二、工具链已就位,构建同一个 openssl 毫无问题。

差别只有一个:它是本 shard 第一个成员,于是承担了 mcpp 的一次性
工具链自举 —— 并且是在**它自己的**环境里承担的。带自定义
`[indices]` 的成员用的是项目局部 xlings home
(<member>/.mcpp/.xlings),而 openssl 走自己的 Makefile、用裸 gcc,
头文件搜索完全来自 xvm shim 的 --sysroot;那个 sysroot 指到项目局部
subos,它的 usr/include 是空的。

于是 job 的成败取决于成员**顺序**。这一步用一个没有 [indices] 的
最小工程把工具链装进共享 home,一次,单独一个进程,在任何成员开始
之前。这本身也更诚实:job 该显式准备自己的环境,而不是继承上一个
测试留下的副作用。
grpcgen 从「两个旋钮 + 断崖」变成四层,每层是下一层的默认值:
generate_all(opt) ≡ submit(plan_all(opt)),.grpc=true ≡ .plugins={cpp()}。
新增 extra_dirs(既生成又搜索)/imports(只搜索)/mock/protoc_args,
plan_entries((root,name)) 公开,description 自述用了哪些旋钮。

sha256 991e9928…(GitCode 镜像已回探核验,与 GitHub 源码包逐字节一致)。
linux 上 CC 一直留给 PATH,理由写在注释里:「on linux the xim gcc
carries its own payload and is the right compiler to use」。二进制
是对的,「它自足」这半不对。

PATH 上的 gcc 是 xvm shim,shim 会注入
`--sysroot=<调用进程解析到的 subos>`(xim-pkgindex pkgs/g/gcc.lua)
—— 而同一段注释写着契约的另一半:

    Consumers that bypass the shim supply their own header flags.

OpenSSL 的 Makefile 调裸 `cc`,正是那一类。

这个 hook 的 cwd 在**消费方项目**的 xlings home 里
(<proj>/.mcpp/.xlings/data/runtimedir/openssl-<v>),于是 subos 解析
到项目那个 —— 它只装了该项目自己的东西,没有 usr/include,通常连
usr/ 都没有。而 `--sysroot` 指向空树不会回落,它会**关掉**默认搜索:

    include/internal/common.h:14:11: fatal error: stdlib.h: No such file
    .../xim-x-gcc/16.1.0/lib/gcc/.../limits.h:210:15: fatal error: limits.h

(后一条是 gcc 自己的 #include_next,读起来像编译器坏了,并不是。)

所以按 make 和 perl 已有的做法办:从声明的 build dep 解析 C 库载荷,
把 payload gcc 需要的三样显式交给它 —— 头(-isystem)、crt(-B)、
-lc(-L)。--sysroot 重指到 glibc 载荷根,它不是 FHS 形状因而不贡献
任何搜索路径:既压掉 shim 注入的那个,又不给宿主 /usr/include 开门。

deps 用 xim:gcc 自己的区间(glibc@>=2.39 / linux-headers@5.11.1)而非
@latest:openssl 的产物要和该 gcc 链在一起,@latest 可能解析出比工具链
更新的 glibc。两边解析同一个节点,而且 gcc 在哪它们就已经在哪。

验证(本机 + xlings subos,非 docker):
  * 裸载荷 gcc 无 flag  → fatal error: stdlib.h: No such file(精确复现)
  * 加上本次这组 flag   → 编译+链接+运行通过
  * openssl 成员端到端  → configdata.pm / Makefile 均带上构造出的 CC,
                          test result ok. 1 passed
两个 grpc 成员各有一对逐字相同的 [target.'cfg(linux)'] 与
[target.'cfg(macos)'] 段。它们表达的是**一个**事实——compat.openssl
没有 windows xpm 条目,所以 gRPC 在 windows 之外都可解析——一个事实
写两遍,就是下一次只改一处的机会。

mcpp 的谓词语言本来就够用:any()/all()/not() 加 unix 别名
(family == "unix",见 src/build/prepare.cppm 的 match_alias)。

本机核验:cfg(unix) 下 grpc-codegen 照常解析出 c-ares/openssl/re2/zlib。
linux 分片在 1h30m17s 被取消——正好是 job 上限。没有任何东西坏掉:
一片里排了 grpc-codegen(3563s)与 grpc-module(1701s),装不下。

分片数原本是二元的(全量 linux 3 片,否则 1 片),那等于断言「非全量
就是小活」。并不是:改一个被广泛消费的描述符会选中所有消费者——本次
改 compat.openssl.lua 就选中了四个成员。

tests/member-timings.tsv 早就记着每个成员的实测耗时,plan_shards.lua
也早就按它做 LPT 装箱。所以扇出数就从同一张表来:把本次成员的 linux
耗时求和,每 ~45 分钟一片,上限 3(再多会被 runner 并发与每片固定开销
吃掉,见上方既有测量)。macOS 保持 1 片——它并发就是 1,多分只会串行。

同时把 grpc-codegen 的实测值补进表里(linux 3563 / macos 1715 /
windows 31)。新成员此前没有条目,按中位数估算,正是它被低估的原因。

本机核验:四成员求和 5313s → 2 片,LPT 切成
  shard 0: grpc-codegen              (59min)
  shard 1: grpc-module asio-ssl openssl (29min)
上一轮 linux 三片全过(1h17/1h09/44m),macOS 单片在 1h30m20s 撞顶。

原注释只从墙钟论证 macOS 不该分片(并发为 1,分了也串行),漏了另
一半:**每个分片是独立 job、各有各的 timeout-minutes**,所以分片同时
也是「让活装得下」的手段。串行不要紧,跑不完才要紧。

macOS 全量实测 6922s = 115 分钟,本来就超 90 上限;它此前能过,只是
因为总量刚好卡在线下,而 grpc-codegen(macOS 1715s)把它推了过去。

改为三平台同一条规则:从 tests/member-timings.tsv 求本次成员在该平台
的实测总和,每 ~70 分钟一片(在 90 上限下留 ~20 分钟冷缓存余量),
上限按各自 runner 并发定(linux 3 / macOS 2 / windows 2)。

本机核验:
  全量        linux 3 片 ~75min · macOS 2 片 ~57min · windows 2 片 ~67min
  本 PR 四成员 linux 2 片 ~44min · macOS 1 片 · windows 1 片
linux 全量是最紧的一档(实测最慢片 77/90),注释已写明后续两个杠杆。
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant