From 456596b54e283d1fbd5c79efa9699d5711fc26e7 Mon Sep 17 00:00:00 2001 From: sunrisepeak Date: Sun, 30 Aug 2026 23:39:36 +0800 Subject: [PATCH 1/2] =?UTF-8?q?docs:=20=C2=A718=20=E5=85=AB=E4=B8=AA?= =?UTF-8?q?=E8=A7=92=E5=BA=A6=E7=9A=84=E5=AE=9E=E7=8E=B0=E5=90=8E=E5=A4=8D?= =?UTF-8?q?=E6=A0=B8(v1.5)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit §6 那张表是设计时写的,实现之后没回头修订。逐条回看,八条里有四条被推翻或需要 重述——把它们留在原样比不写更糟,下一个人会照着一张已经不成立的表做决定。 推翻两条: 架构 「新增仓数量 = 0」→ 实际新建五个。错在把「进已有 fork」当成可选的组织 方式;它不是,一个 fork 仓对应一个上游一个版本。 兼容性 「全部新增,不动任何已发布包」→ 动了三个。错在把「新增」等同于「无风 险」:DISCOVERY 加一行会让现有提供方自动继承它;新增一个消费者会暴露 compat.freetype 的源码列表缺口。 重述四条: 稳定性 风险不在难写的代码里,在写完之后没人检查的断言里。实现期代价最高的 三类失败都不在设计时的风险清单上。 跨平台 真正咬人的不是 CPU 架构,是编译器与标准库(static inline 实例化、 传递包含),两个都只有 llvm 腿抓得到。 一致性 「生成物签进仓」被推翻——改由 build.mcpp 构建期产出,由此消掉了 「数据与代码不一致」这个状态本身。 无感升级 同版本重发换了三种形态出现,结论是 tag 指向历史、资产承载分发。 成立两条:优雅(feature 机制把「替消费者选」变成「让消费者选」)、用户体验 (模块层不只是换写法,它是放置适配代码的位置)。 只改 .agents/docs/。 --- ...26-08-30-graphics-stack-coverage-design.md | 118 +++++++++++++++++- 1 file changed, 117 insertions(+), 1 deletion(-) diff --git a/.agents/docs/2026-08-30-graphics-stack-coverage-design.md b/.agents/docs/2026-08-30-graphics-stack-coverage-design.md index 776ac74..e007e65 100644 --- a/.agents/docs/2026-08-30-graphics-stack-coverage-design.md +++ b/.agents/docs/2026-08-30-graphics-stack-coverage-design.md @@ -1,6 +1,6 @@ # mcpp 图形栈:从「能跑通」到「能开发」的覆盖面设计 -Date: 2026-08-30 · 前置:[`2026-08-30-gbm-cross-repo-closed-loop-plan.md`](2026-08-30-gbm-cross-repo-closed-loop-plan.md) §19/§20 · **状态:已实现并闭环验证(v1.4,§11 总账 / §12 客户端侧 / §14 fork 规范 / §17 桌面栈补齐与判据修正)** +Date: 2026-08-30 · 前置:[`2026-08-30-gbm-cross-repo-closed-loop-plan.md`](2026-08-30-gbm-cross-repo-closed-loop-plan.md) §19/§20 · **状态:已实现并闭环验证(v1.5,§11 总账 / §14 fork 规范 / §17 桌面栈补齐 / §18 八角度实现后复核)** ## 0. 这份文档解决什么 @@ -1429,3 +1429,119 @@ RESULT: PASS **pango 是唯一量准后仍需决策的**:57k 行本身不大,但硬依赖 glib,而 glib 是 `glib/` + `gobject/` + `gio/` 三大块 300k+ 行,自己还缺 `pcre2` 和 `libmount`。 按 §17.1 的新判据,它的难点也不在行数——需要先数它的生成器再定。 + +--- + +## 18. 八个角度的实现后复核 + +§6 的表是**设计时**写的。实现之后逐条回看,**八条里有四条被推翻或需要重述**—— +把它们留在原样比不写更糟,因为下一个人会照着一张已经不成立的表做决定。 + +### 18.1 架构 —— ❌ 推翻 + +> 设计时:「不新建仓,**新增仓数量 = 0**」 + +实际新建 **五个** fork 仓:`wayland-protocols`、`libevdev`、`libxkbcommon` +(前三个见 §10.2)、`libdisplay-info`、`fontconfig`、`cairo`。 + +**错在哪**:当时以为「进已有 fork」是可选的组织方式。它不是——**一个 fork 仓对应 +一个上游、一个版本**。wayland-protocols 有自己的版本号和发布周期,塞进 +mcpplibs/wayland 就等于让两个上游共用一个 tag,那才是真正的架构错误。 + +**留下的规则**:fork 仓的数量由**上游的数量**决定,不由「想少建几个仓」决定。 + +### 18.2 稳定性 —— ⚠ 重述 + +设计时说「风险集中在模块导出与体积,两者都可先验」。体积确实可先验(cairo 47.8MB +→ 1.8MB,§17.4)。模块导出也确实是风险,但**真正咬人的不是它**。 + +实现期的失败按代价排序,前三名都不在当时的风险清单上: + +1. **探测答案错**(§17.5、§17.6)——编过、链过、报 SUCCESS,行为错。三次。 +2. **环境陈旧**(§17.7)——沙箱/CI/store 各一次,报错全部指向别处。 +3. **上游自己的 `.gitignore`**(§17.6)——fork 少了 5 个发布物文件。 + +**留下的规则**:风险不在「难写的代码」里,在「写完之后没人检查的断言」里。所以 +每个 fork 的 CI 都要有一条**拿产物和上游对照**的检查,而不只是「能编过」。 + +### 18.3 优雅/简洁 —— ✅ 成立,而且被 feature 机制加强 + +设计时的「只做三个无 X11 的 GL 库」成立。cairo 把同一个想法做到了更好的形态: +**不是替消费者选,而是让消费者选**——`default = ["ft","fc","png"]`,X11 是 +feature(§17.4)。 + +差别是真实的:「只做无 X11 的库」意味着要 X11 的人没得用;feature 意味着他写一行 +就有。 + +### 18.4 用户体验 —— ✅ 成立,且比预期多一层 + +`import khronos.glesv2;` 那条成立。多出来的一层是**模块消掉了上游的缺陷**: +libdisplay-info 七个公共头一个 `extern "C"` 都没有,C++ 消费者 `#include` 会 +mangle 到链接失败;`import freedesktop.displayinfo;` 把包装做在模块内(§14.2)。 + +**留下的规则**:模块层不只是「换个写法」,它是**放置适配代码的位置**。 + +### 18.5 兼容性 —— ❌ 推翻 + +> 设计时:「全部是新增条目,**不动任何已发布包**」 + +实际动了三个已发布包: + +- `compat.freetype` 补 `ftsynth.c`(#311)——cairo 无条件调它 +- `xim:mesa` 改成只声明自己填的路径(xim#733)——加一行 DISCOVERY 造成的回归 +- `graphics.consumer_envs` 跳过标量行(xim#735)——同一行造成的第二处回归 + +**错在哪**:当时把「新增」等同于「无风险」。**新增一个条目会改变现有条目的行为** +——DISCOVERY 表加一行,`declare_subos_env(tag)` 不传 `only` 的调用点就自动继承了 +它;新增一个消费者,`compat.freetype` 的源码列表缺口就暴露了。 + +**留下的规则**:见 §14 的三项检查清单,以及「一个 compat 包的源码列表就是它的 +ABI 承诺」(§17.6)。 + +### 18.6 跨平台 —— ⚠ 重述 + +设计时只考虑了 CPU 架构(aarch64/ppc64)。实现期真正咬人的跨平台维度是 +**编译器与标准库**: + +- `wl_shm_create_pool` 是 `static inline`,取地址强制实例化 → GNU ld 经传递 + DT_NEEDED 解析,**lld 不会**(#301) +- `` 被 libstdc++ 经 `` 传递包含,**libc++ 不会**(#310) + +两个都只有 mcpp-index 的 **llvm 腿**抓得到——它没有 sysroot 且用 lld。 + +**留下的规则**:fork 里任何 `build.mcpp` 或模块包装的改动,推之前先 +`mcpp toolchain default llvm` 跑一遍。cairo 的 fork CI 已经把这一步固化。 + +### 18.7 一致性 —— ⚠ 重述 + +三条规则(模块命名、生成物签进仓、path 依赖)里,**第二条被推翻**:生成物不再 +签进仓,改由 `build.mcpp` 在构建期产出(§14.1)。 + +这不是风格变更,是消掉了一整类状态:**没有签进仓的生成物,就没有「数据与代码不 +一致」这个状态**,也就不需要「重生成再 diff」的 CI 步骤。 + +另外两条原样成立,并新增一条:**feature 的 `sources` 逐条列,不用 glob** +(§17.4)。 + +### 18.8 无感升级 —— ⚠ 重述 + +> 设计时:「全是新增包,无同版本重切 tag 的问题」 + +同版本重发的问题**换了三种形态出现**: + +| 形态 | 后果 | +|---|---| +| tag archive 做 URL | 重切直接打断已发布描述符的 sha256 | +| store 按 `(name, version)` 缓存 | 同版本重发**不重新解压** | +| 删 tag 再建 | release 掉成**草稿**,资产 404 | + +三个都指向同一条,已成为本轮的操作规则:**tag 指向历史,资产承载分发,不要动 +tag**——把新内容作为 release 资产发布,旧资产原样保留,零窗口(§12.2)。 + +### 18.9 一句话 + +八条里**两条推翻**(架构、兼容性)、**四条重述**(稳定性、跨平台、一致性、无感 +升级)、**两条成立且被加强**(优雅、用户体验)。 + +设计时的判断有一半没扛过实现——而这正是「验证要更新到文档」的意义:留下的应该是 +**被证伪之后的那一版**。 From 2378f98bc2479c19c285ef7d8b7fe789d722f186 Mon Sep 17 00:00:00 2001 From: sunrisepeak Date: Sun, 30 Aug 2026 23:43:10 +0800 Subject: [PATCH 2/2] =?UTF-8?q?docs:=20=C2=A76=20=E6=AF=8F=E8=A1=8C?= =?UTF-8?q?=E6=A0=87=E6=B3=A8=E7=BB=93=E8=AE=BA=E5=B9=B6=E6=8C=87=E5=90=91?= =?UTF-8?q?=20=C2=A718?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit §18 的整个理由是「下一个人会照着 §6 那张表做决定」——那 §6 自己就必须说它 已经被推翻,否则读者根本走不到 §18。加一列结论标记(❌/⚠/✅)+ 小节号, 以及一句「不要单独引用本节」。 --- ...26-08-30-graphics-stack-coverage-design.md | 23 +++++++++++-------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/.agents/docs/2026-08-30-graphics-stack-coverage-design.md b/.agents/docs/2026-08-30-graphics-stack-coverage-design.md index e007e65..1109950 100644 --- a/.agents/docs/2026-08-30-graphics-stack-coverage-design.md +++ b/.agents/docs/2026-08-30-graphics-stack-coverage-design.md @@ -349,16 +349,19 @@ G6 libudev 路线决策 → libseat ← 最后,单独评估 ## 6. 多角度评估 -| 角度 | 评估 | -|---|---| -| **架构** | G1 不新建仓,复用 mcpplibs/libglvnd 已有的 `mcpp/generated/` 与 path 依赖机制;G3 复用 mcpplibs/wayland 的 scanner。**新增仓数量 = 0** | -| **稳定性** | 四张生成表已实跑;CI 的 diff 守卫扩四行即可。风险集中在 G1b(模块导出)与 G3(体积),两者都可先验 | -| **优雅/简洁** | 只做三个无 X11 的 GL 库,不碰 GLX/GL —— 覆盖合成器的全部需要,且不把 X11 拖进任何消费者 | -| **用户体验** | 合成器作者的 `mcpp.toml` 从「缺渲染链」变成可写;`import khronos.glesv2;` 与既有命名一致 | -| **兼容性** | 全部是新增条目,不动任何已发布包。唯一的行为变更是 G2a,而它修的是「静默落到软件渲染」 | -| **跨平台** | GL 家族的 per-arch entry stub 沿用 `build.mcpp` 里已有的 `target_arch()` 选择,aarch64/ppc64 由构造成立;pixman 的 SIMD 自门控,不需要额外机制 | -| **一致性** | 模块命名(khronos.*)、生成物签进仓、path 依赖三条规则原样复用,不引入新范式 | -| **无感升级** | 全是新增包,无同版本重切 tag 的问题(那正是上一轮的教训) | +> ⚠ **这张表是设计时写的,八条里有四条已被实现推翻或需要重述。** +> 每行末尾的标记给出结论,逐条的证据在 **§18**。不要单独引用本节。 + +| 角度 | 评估(设计时) | | +|---|---|---| +| **架构** | G1 不新建仓,复用 mcpplibs/libglvnd 已有的 `mcpp/generated/` 与 path 依赖机制;G3 复用 mcpplibs/wayland 的 scanner。**新增仓数量 = 0** | ❌ 实际五个仓,§18.1 | +| **稳定性** | 四张生成表已实跑;CI 的 diff 守卫扩四行即可。风险集中在 G1b(模块导出)与 G3(体积),两者都可先验 | ⚠ 真正的风险不在此,§18.2 | +| **优雅/简洁** | 只做三个无 X11 的 GL 库,不碰 GLX/GL —— 覆盖合成器的全部需要,且不把 X11 拖进任何消费者 | ✅ 且被 feature 加强,§18.3 | +| **用户体验** | 合成器作者的 `mcpp.toml` 从「缺渲染链」变成可写;`import khronos.glesv2;` 与既有命名一致 | ✅ 且多一层,§18.4 | +| **兼容性** | 全部是新增条目,不动任何已发布包。唯一的行为变更是 G2a,而它修的是「静默落到软件渲染」 | ❌ 动了三个,§18.5 | +| **跨平台** | GL 家族的 per-arch entry stub 沿用 `build.mcpp` 里已有的 `target_arch()` 选择,aarch64/ppc64 由构造成立;pixman 的 SIMD 自门控,不需要额外机制 | ⚠ 咬人的是编译器不是架构,§18.6 | +| **一致性** | 模块命名(khronos.*)、生成物签进仓、path 依赖三条规则原样复用,不引入新范式 | ⚠ 第二条已推翻,§18.7 | +| **无感升级** | 全是新增包,无同版本重切 tag 的问题(那正是上一轮的教训) | ⚠ 换三种形态出现,§18.8 | ---