Skip to content

feat(glx-runtime): GL 来自生态而非 /usr/lib,这次带上缺失的那个测试 - #181

Merged
Sunrisepeak merged 5 commits into
mainfrom
fix/graphics-relanding-with-side-effect-test
Aug 8, 2026
Merged

feat(glx-runtime): GL 来自生态而非 /usr/lib,这次带上缺失的那个测试#181
Sunrisepeak merged 5 commits into
mainfrom
fix/graphics-relanding-with-side-effect-test

Conversation

@Sunrisepeak

Copy link
Copy Markdown
Member

重新应用 f44e896(#179),它在 #180 被整体 revert —— 这次带上当时缺失的那个测试。

改动本身是对的

compat.glx-runtime 之前从 /usr/lib* 符号链接宿主的 libGL/libEGL。mcpp#352 正是这么来的:宿主 Mesa 需要 GLIBC_2.43,mcpp 的 payload glibc 是 2.39,程序链接干净、退出 255、一行输出都没有。它也是 xlings hermetic 政策禁止清单上的第一条。

被 revert 的原因不在这两个文件里

mesa 声明 xim:glibc@>=2.38。下限被任何更高版本满足,于是 xim 在 2.39 旁边装了 2.44;而当时的 mcpp 用 readdir 的第一项来解析「那个 glibc payload」,编译侧取了 2.44,产物的 interpreter 却仍是 2.39。二进制开始引用 GLIBC_2.42 符号,报错落在 asio-modulecore 上 —— 两个不用图形、不依赖 mesa、这次改动根本没碰的成员。

引擎侧已在 mcpp 2026.8.8.2 修好(runtime binding 由权威决定,不再猜)。

真正缺的是这里的一个测试

这个仓库的每个测试都在测「它自己那个包」,所以没有任何一个问出唯一重要的那个问题:装了这个,对其他所有人有没有影响?

tests/check_graphics_install_side_effects.sh 只问这一个:装图形栈前后,各构建一次与图形无关的成员,断言产物的 PT_INTERP 与 glibc 符号上界逐字不变

写这个脚本时踩到的坑,每一个都被写进了脚本本身 —— 它们全是「测试因错误的理由而通过」的变体:

现在怎么处理
调用了不存在的 mcpp toolchain install-deps,fallback 失败还 exit 0 走用户真实路径(构建 imgui-windowcompat.glfwcompat.glx-runtime),失败即硬失败
找不到 readelf 就跳过 硬失败。一个不能查看就悄悄放行的检查,正是本文件反对的东西
图形栈已装时,基线就是装后状态,两半比的是同一个东西 —— 任何 mcpp 都过(实测:修复前的版本在我机器上打印 PASS) 先检查前置条件,不满足报 INCONCLUSIVE 并退 1。评估不了的门不能是绿的
设了 MCPP_HOME 不等于构建真的用了它 —— 曾经往一个 home 装图形栈、却测另一个 home 的产物 产物的 interpreter 判定是哪个 home 服务了构建;不一致则 INCONCLUSIVE
home_real 为空时 case "$interp_path" in ""/*) 变成 /*,匹配任何绝对路径 空值单独拦截。空变量拼进 glob 会静默放行一切
失败日志 cat 到 stdout,而调用方用 $(...) 捕获 ⇒ 日志进变量后被丢弃,失败时只有一行空白 诊断一律走 stderr
mcpp build 取产物 —— 但这些是测试型成员,只产出 obj/BMI;之前能找到产物是因为 target/ 里有上次 mcpp test 的残留 改用 mcpp test;显式说明为何不看它的退出码

这个测试有多强,它自己会说

事故需要的条件是装完之后存在两个及以上 glibc payload —— 有得选,才可能选错。所以它在结论里区分:

  • strong:装完 ≥2 个 payload,构建有得选而没有选错
  • weak:只有 1 个,没有选择可言,本次运行证明了无漂移但没有触发缺陷

今天全新 home 装 gcc 直接拿到 2.44,所以 CI 上多半会是 weak —— 如实标注,不冒充。双 payload 场景由两处覆盖:一台真实开发机(2.39 + 2.44 并存,用 2026.8.8.2 跑过,逐字不变),以及 mcpp 侧的单测(两个 payload 时沉默、记录指向仍存在的那个则采信,红绿验证过)。

它在任何早于 2026.8.8.2 的 mcpp 上都该失败,这是有意的 —— 图形栈不该落在一个仍会犯这个错的工具链上。

重新应用 f44e896(#179),它在 #180 被整体 revert。改动本身是对的:
compat.glx-runtime 之前从 /usr/lib* 符号链接**宿主的** libGL/libEGL,而
mcpp#352 正是这么来的 —— 宿主 Mesa 需要 GLIBC_2.43,mcpp 的 payload glibc 是
2.39,程序链接干净、退出 255、一行输出都没有。它也是 xlings hermetic 政策
禁止清单上的第一条。

被 revert 的原因不在这两个文件里。mesa 声明 `xim:glibc@>=2.38`,下限被任何
更高版本满足,于是 xim 在 2.39 旁边装了 2.44;而当时的 mcpp 用 readdir 的第一项
来解析「那个 glibc payload」,编译侧取了 2.44,产物的 interpreter 却仍是 2.39。
二进制开始引用 GLIBC_2.42 符号,而报错落在 asio-module 和 core 上 —— 两个不用
图形、不依赖 mesa、这次改动根本没碰的成员。

引擎侧已在 mcpp 2026.8.8.2 修好(runtime binding 从 subos 读,不再猜)。

真正缺的是**这里**的一个测试。这个仓库的每个测试都在测「它自己那个包」,所以
没有任何一个问出唯一重要的那个问题:装了这个,对**其他所有人**有没有影响?
tests/check_graphics_install_side_effects.sh 就问这一个:装图形栈前后,各构建
一次与图形无关的成员,断言产物的 PT_INTERP 与 glibc 符号上界**逐字不变**。

它在任何早于 2026.8.8.2 的 mcpp 上都会失败,这是有意的 —— 图形栈不该落在一个
仍会犯这个错的工具链上。
两件事,都是评审提问逼出来的。

一、`MCPP_VERSION` 2026.8.6.2 → 2026.8.8.2。不是顺手升级。

`compat.glx-runtime` 依赖 mesa,mesa 声明 `xim:glibc@>=2.38`;下限被任何更高版本
满足,于是安装图形栈会在既有 glibc 旁边再装一个。2026.8.8.2 之前的 mcpp 用
`readdir` 的第一项解析「那个 glibc payload」,编译侧与产物 interpreter 因此可以
指向不同版本 —— 这正是 #179 落地后 asio-module 和 core 变红、整份改动被 #180
revert 的原因。用更旧的 mcpp 重新落地,就是在仍会犯这个错的引擎上复现事故条件。

二、`tests/check_graphics_install_side_effects.sh` 不被任何 workflow 引用。

它是一个永远不会运行的检查 —— 与它自己反对的东西同一形状。现在有专属作业,
Linux,装 pin 住的 mcpp 后执行。

顺带回答「为什么触发了全量 CI」:选择规则里 `tests/*.sh` 一律 full。这条规则是为
共享测试骨架写的,而新文件匹配了它。就本 PR 而言全量恰恰是想要的 —— 上次坏掉的
正是与图形无关的成员,只跑图形相关的那几个看不见任何东西。

注意:动 `MCPP_VERSION` 会改变 registry 缓存键(它进 key 也进 restore-keys),
所以这一轮所有 workspace 作业都从冷缓存起步。潜伏的缺陷可能因此「突然出现」——
那是暴露,不是新增。
The side-effect check reported INCONCLUSIVE on its first CI run, correctly: a
released mcpp is self-contained and resolves its registry from beside its own
executable, so copying the payload tree into ~/.mcpp and pointing MCPP_HOME
there watched one home while the build used another.

MCPP_HOME is now the tarball root. The check was right; the job was wrong.
三件事,起因是 #181 的 CI 太长。

一、registry 缓存一直是摆设。

Download 步骤把 release 的 registry 拷进 ~/.mcpp/registry,而缓存也覆盖那里 ——
但发布版 mcpp 是 **self-contained**,从自己可执行文件旁边解析 registry。所以每次
构建用的是 <tarball>/registry,缓存恢复和保存的那份从没被读过。

证据取自加入 grpc-codegen 的那次 run:abseil 的源码编译自
`<tarball>/registry/data/xpkgs/compat-x-abseil/...`,而同一个 job 在报告 registry
缓存 **命中** 的情况下重新下载了 xim:glibc@2.44 和 xim:python@3.13.12。

修法是一行 `MCPP_HOME=$HOME/.mcpp`。payload 从此跨 run 复用。

二、host tool store 从不缓存。

同一次 run 实测:建 protoc 636s、建 grpc_cpp_plugin 660s —— 3363s 的成员里占
1296s,而且每个 job 每次 run 都重来。`protobuf-protoc`(945s)和 `grpc-module`
(1724s)建的是同一个 protoc。

store 在 `$MCPP_HOME/build-cache/v1/tool`,本机实测 116MB —— 缓存得起。粗粒度滚动
键是安全的:store 按 `<包>@<版本>/<hash>` 内容寻址,且 mcpp 逐字段比对
entry.json(epoch、target、host triple、编译器身份、profile、features、传递依赖
闭包),对不上就重建而不是误用。

刻意不缓存 `build-cache/v1/pkg`:本机 6.0GB,而 Actions 每仓库 10GB —— 塞进去会把
更需要的 registry 缓存挤掉。

三、cmdline 和 llmapi 有描述符却没有成员。

两个都补上,并且是**消费型**测试而不是「能链上就算过」:

- cmdline 用 `parse_from` 解析真实命令行,断言 positional、长选项、`--opt=value`;
  再断言**缺少必填参数会被拒绝** —— 没有这一条,前面几条对一个「什么都接受」的
  解析器同样成立。
- llmapi 全部断言离线。它是 HTTP 客户端,真打端点需要 CI 没有的 key、要花钱、且
  会因与包无关的原因失败。测的是依赖边:`:url` 的端点常量、`:types` 的 variant
  内容模型、`:errors` 的异常层次 —— 三者都是纯数据/纯逻辑。

两个成员都在本机跑通,并各自验证过把断言改错会变红。
LPT 装箱按降序考虑成员,所以每片交给 run_members.sh 的顺序也是降序 —— 贵的先跑。
反过来。

理由不是「更快发现失败」,而是让维护者能在跑完之前就**做决定**。少数时候,一个
改动在核心已被证明覆盖之后就值得合入,不必等尾巴跑完。

一次全量 linux run 是 13427s 成员墙钟,前四名占 52%(grpc-codegen 3363s、
grpc-module 1724s、opencv-module-dnn 1017s、protobuf-protoc 945s)。按这个顺序,
约 55 个成员在第一个重量级启动前就已报完 —— 于是「除了那四个已知的贵成员之外
全绿」是一个**存在的、早早出现的、可以判断的状态**。贵的先跑则没有这种中间状态:
一小时内什么都说明不了,然后一次性全部结束。

超时的后果按同一逻辑读:分片现在丢的是贵成员而不是便宜成员 —— 那正是维护者本来
就会选择跳过的那一半,数量少,且在 tests/member-timings.tsv 里逐个有名有姓。

装箱与顺序是两个问题,这里只动后者:LPT 仍按降序装箱(否则箱子会不均)。三平台
七个分片逐一比对过成员集合 —— 完全一致。单片路径(`--shard 0/1`)同样升序,所以
本地与 CI 的顺序是同一个。
@Sunrisepeak
Sunrisepeak force-pushed the fix/graphics-relanding-with-side-effect-test branch from 04c7322 to 7b04083 Compare August 8, 2026 05:46
@Sunrisepeak
Sunrisepeak merged commit 1ba4161 into main Aug 8, 2026
5 checks passed
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