From 89bb51388c6a3d16cc8b00be49a0e2e32fbd0f7c Mon Sep 17 00:00:00 2001 From: sunrisepeak Date: Sun, 30 Aug 2026 22:18:31 +0800 Subject: [PATCH] =?UTF-8?q?docs:=20fork=20=E8=A7=84=E8=8C=83=E5=BD=A2?= =?UTF-8?q?=E6=80=81=E3=80=81fontconfig=20=E5=AE=9E=E5=86=B5=E3=80=81?= =?UTF-8?q?=E6=B2=99=E7=AE=B1=E7=9B=B2=E7=82=B9(v1.3)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit §14 fork 的规范形态。本轮前半段用 sh + python 预生成、把产物签进仓——那是错的。 关键是我一开始判断错了 build.mcpp 是什么:它是 mcpp 编译并运行的 C++ 程序, import mcpp; 给指令 API,所以任何「读文件、变换文本、写文件」的生成器都能在 里面做,不需要外部解释器。libdisplay-info(#308)是按新形态重做的样板。 没有签进仓的生成物,所以也没有「重生成再 diff」的 CI 步骤——「数据与代码 不一致」这个状态不存在。 §14.2 模块能顺手消掉一类上游缺陷:libdisplay-info 七个公共头一个 extern "C" 都没有,有了模块消费者就不用自己包。compat.libseat 有同样问题而没有模块,两者 对照说明模块层不只是风格。 §14.3 生成器可以比上游更正确:PNP 表逐行 diff 过,2583 行除几个非 ASCII 名字 外一致,而那几个这边是对的(上游按码点转义 U+00A0 成单字节 \240,不是 UTF-8)。 §15 fontconfig:我的估算错了。说过它「中,和 libinput 同量级」,实测 7 个生成物, 其中 fc-lang.py 387 行吃 281 个 .orth 文件编译成 FcCharSet 位图。已在 build.mcpp 里做通 5 个(含用二分查找替掉 gperf 完美哈希——唯一消费者只读一个字段,72 条目, 语义等价而少一个工具和一遍预处理)。剩下两个及建议的混合形态写在 §15.3。 §16 沙箱验证的盲点:合成 home 带的索引快照早于被测的包,脚本因此把一个已发布 一小时的包报成「找不到」。任何 --sandbox 里的验证第一步必须是 mcpp index update, 否则测的是镜像打包那天的生态。 只改 .agents/docs/,不触发任何 CI。 --- ...26-08-30-graphics-stack-coverage-design.md | 111 +++++++++++++++++- 1 file changed, 110 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 464f889..a16bf14 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.2,见 §11 交付总账 / §12 客户端侧 / §13 仍缺的部分)** +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.3,§11 总账 / §12 客户端侧 / §13 仍缺 / §14 fork 规范 / §15 fontconfig / §16 沙箱盲点)** ## 0. 这份文档解决什么 @@ -1164,3 +1164,112 @@ Wayland **没有服务端光标**:客户端要指针,就得自己加载主题、 第 3 条只有 llvm 那条腿抓得到 —— 它没有 sysroot 且用 lld,而这正是 `validate.yml` 注释里说的「gcc 腿结构上看不见这一类 bug」。 + +--- + +## 14. fork 的规范形态(2026-08-30 修订) + +本轮前半段的 fork 用了 `sh` + `python` 预生成、把产物签进仓。**那是错的**,正确 +形态是: + +> **上游目录与适配目录分开;能支持模块的直接支持模块;生成走 +> `mcpp` + `build.mcpp` + `feature`;尽量不依赖其他工具、sh 或 python。** + +### 14.1 `build.mcpp` 是 C++ 程序,不是配置 + +这是我一开始判断错的地方,而它决定一切:`build.mcpp` 由 mcpp **编译并运行**, +`import mcpp;` 提供指令 API(`generated` / `include_dir` / `define` / `action` / +`dep_dir` / `dep_bin` / `out_dir` / `manifest_dir` / `rerun_if_changed` / +`target_os`)。所以任何"读文件、变换文本、写文件"的生成器都能在里面做,不需要 +外部解释器。 + +`freedesktop.libdisplay-info` 是按这个形态重做的样板(#308): + +| 产物 | 由谁产 | +|---|---| +| `pnp-id-table.c`(2583 行) | `build.mcpp` → out dir | +| `src/libdisplay-info.cppm`(206 个名字) | `build.mcpp` → src/ | + +**没有签进仓的生成物,所以也没有「重生成再 diff」的 CI 步骤** —— "数据与代码 +不一致"这个状态不存在。这是构建期生成与签生成物的本质区别。 + +模块写进 `src/` 而非 out dir,因为 `[lib] path` 是**静态**声明的;`build.mcpp` +在编译前跑,所以到用的时候文件已经在。 + +### 14.2 模块能顺手消掉一类上游缺陷 + +libdisplay-info 的七个公共头**一个 `extern "C"` 都没有**,C++ 消费者 `#include` +会 mangle 到链接失败(`undefined reference to di_info_get_make(di_info const*)`)。 +原来的处理是"让消费者自己包,并写进文档";有了模块,包装做在模块 purview 里: + +```cpp +import freedesktop.displayinfo; // 消费者不用管 +``` + +`compat.libseat` 有同样的上游问题而没有模块,所以那里消费者仍要自己包 —— 两者 +对照说明模块层不只是风格。 + +### 14.3 生成器可以比上游更正确 + +`build.mcpp` 的 PNP 表与上游 python 生成器**逐行 diff 过**:2583 行,除几个 +非 ASCII 名字外完全一致,而那几个**这边是对的**。 + +`pnp.ids` 里 `DemoPadSoftwareLtd`,U+00A0 编码是 `c2 a0` 两字节。 +上游按**文本**读、按码点转义成 `\240` —— 单字节,不是 UTF-8,消费者打印会得到 +替换字符。`build.mcpp` 按**字节**转义成 `\302\240`。 + +--- + +## 15. fontconfig:我的估算错了,以及它真正的形态 + +### 15.1 更正 + +| | 我先前说的 | 实测 | +|---|---|---| +| 规模 | 「中,和 libinput 同量级」 | 26k 行源码,**7 个生成物** | +| 生成器 | 「一个 python 脚本读一个文本文件」 | `makealias.py` 71 行 + `cutout.py` + gperf + `fc-case.py` **240 行** + `fc-lang.py` **387 行,吃 281 个 `.orth` 数据文件** | + +`fc-lang` 把 281 个正字法文件编译成 FcCharSet 的 leaf/number 位图 —— 复刻它 +约等于重写一个小编译器。**这不是「工作量不大」**,而我基于错误估算说过它是。 + +### 15.2 已经做通的部分(全部在 `build.mcpp` 里,零外部工具) + +- `fcstdint.h` +- `fcalias.h` / `fcaliastail.h` —— 复刻 `makealias.py`,**含它的分组顺序**: + tail 按"哪个 `.c` 定义了这个符号"分组,`#ifdef` 块必须按首见顺序嵌套 +- `fcftalias.h` / `fcftaliastail.h` +- **`fcobjshash.h` —— 用二分查找替掉 gperf 的完美哈希**。这是一处**判断**而非 + 转写:唯一消费者是 `fcobjs.c`,它调 `FcObjectTypeLookup(str, strlen(str))` 并 + 只读 `->id`,72 个条目。语义等价,而少一个工具和一遍 C 预处理。条目来自 + `fcobjs.h` 的 `FC_OBJECT(...)` 列表 + `fontconfig.h` 的 `#define FC_`, + 两个文本扫描,不需要 cpp +- 模块包装 +- `config.h` —— **不是**生成物:它是探测**答案**,属于适配目录里可读可争的文件, + 不属于生成器。四条运行期路径按既定立场留空 + (`FONTCONFIG_FILE` / `FONTCONFIG_PATH` / `FONTCONFIG_SYSROOT` 是出口) + +### 15.3 仍缺的两个,以及形态建议 + +`fc-case`(240 行,吃 `CaseFolding.txt`)和 `fc-lang`(387 行,吃 281 个 +`.orth`)。前者可复刻;后者是本轮单个最大的一块。 + +**建议的混合形态**:能 `build.mcpp` 的全做,`fclang.h` 作为**唯一例外**签进适配 +目录并在文件头写明理由。这违反"不签生成物",但避开重写位图编译器 —— 而把例外 +写在文件里、只此一处,比为了纯粹性再花一天更划算。 + +--- + +## 16. 沙箱验证的一个盲点(2026-08-30) + +补跑新增三个包的沙箱验证时,脚本把一个**已发布一小时**的包报成「找不到」。原因: + +``` +index: local index af79fd2 (never refreshed) +``` + +沙箱的 home 是合成的,mcpp 带的是镜像里那份索引快照,**早于被测的包**。而 +"刷新索引"正是新用户会做的第一件事。 + +**所以任何在 `--sandbox` 里做的验证,第一步必须是 `mcpp index update`** —— +否则测的是镜像打包那天的生态,而不是今天的。这与 +「本地旧索引快照掩盖描述符错误」那条 是同一类,只是发生在沙箱侧。