Skip to content

Commit 24ba6a0

Browse files
authored
docs: fork 规范形态、fontconfig 实况、沙箱盲点(v1.3) (#309)
§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。
1 parent 7741d10 commit 24ba6a0

1 file changed

Lines changed: 110 additions & 1 deletion

File tree

‎.agents/docs/2026-08-30-graphics-stack-coverage-design.md‎

Lines changed: 110 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# mcpp 图形栈:从「能跑通」到「能开发」的覆盖面设计
22

3-
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 仍缺的部分)**
3+
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 沙箱盲点)**
44

55
## 0. 这份文档解决什么
66

@@ -1164,3 +1164,112 @@ Wayland **没有服务端光标**:客户端要指针,就得自己加载主题、
11641164

11651165
第 3 条只有 llvm 那条腿抓得到 —— 它没有 sysroot 且用 lld,而这正是
11661166
`validate.yml` 注释里说的「gcc 腿结构上看不见这一类 bug」。
1167+
1168+
---
1169+
1170+
## 14. fork 的规范形态(2026-08-30 修订)
1171+
1172+
本轮前半段的 fork 用了 `sh` + `python` 预生成、把产物签进仓。**那是错的**,正确
1173+
形态是:
1174+
1175+
> **上游目录与适配目录分开;能支持模块的直接支持模块;生成走
1176+
> `mcpp` + `build.mcpp` + `feature`;尽量不依赖其他工具、sh 或 python。**
1177+
1178+
### 14.1 `build.mcpp` 是 C++ 程序,不是配置
1179+
1180+
这是我一开始判断错的地方,而它决定一切:`build.mcpp` 由 mcpp **编译并运行**,
1181+
`import mcpp;` 提供指令 API(`generated` / `include_dir` / `define` / `action` /
1182+
`dep_dir` / `dep_bin` / `out_dir` / `manifest_dir` / `rerun_if_changed` /
1183+
`target_os`)。所以任何"读文件、变换文本、写文件"的生成器都能在里面做,不需要
1184+
外部解释器。
1185+
1186+
`freedesktop.libdisplay-info` 是按这个形态重做的样板(#308):
1187+
1188+
| 产物 | 由谁产 |
1189+
|---|---|
1190+
| `pnp-id-table.c`(2583 行) | `build.mcpp` → out dir |
1191+
| `src/libdisplay-info.cppm`(206 个名字) | `build.mcpp` → src/ |
1192+
1193+
**没有签进仓的生成物,所以也没有「重生成再 diff」的 CI 步骤** —— "数据与代码
1194+
不一致"这个状态不存在。这是构建期生成与签生成物的本质区别。
1195+
1196+
模块写进 `src/` 而非 out dir,因为 `[lib] path` 是**静态**声明的;`build.mcpp`
1197+
在编译前跑,所以到用的时候文件已经在。
1198+
1199+
### 14.2 模块能顺手消掉一类上游缺陷
1200+
1201+
libdisplay-info 的七个公共头**一个 `extern "C"` 都没有**,C++ 消费者 `#include`
1202+
会 mangle 到链接失败(`undefined reference to di_info_get_make(di_info const*)`)。
1203+
原来的处理是"让消费者自己包,并写进文档";有了模块,包装做在模块 purview 里:
1204+
1205+
```cpp
1206+
import freedesktop.displayinfo; // 消费者不用管
1207+
```
1208+
1209+
`compat.libseat` 有同样的上游问题而没有模块,所以那里消费者仍要自己包 —— 两者
1210+
对照说明模块层不只是风格。
1211+
1212+
### 14.3 生成器可以比上游更正确
1213+
1214+
`build.mcpp` 的 PNP 表与上游 python 生成器**逐行 diff 过**:2583 行,除几个
1215+
非 ASCII 名字外完全一致,而那几个**这边是对的**。
1216+
1217+
`pnp.ids` 里 `DemoPad<U+00A0>Software<U+00A0>Ltd`,U+00A0 编码是 `c2 a0` 两字节。
1218+
上游按**文本**读、按码点转义成 `\240` —— 单字节,不是 UTF-8,消费者打印会得到
1219+
替换字符。`build.mcpp` 按**字节**转义成 `\302\240`。
1220+
1221+
---
1222+
1223+
## 15. fontconfig:我的估算错了,以及它真正的形态
1224+
1225+
### 15.1 更正
1226+
1227+
| | 我先前说的 | 实测 |
1228+
|---|---|---|
1229+
| 规模 | 「中,和 libinput 同量级」 | 26k 行源码,**7 个生成物** |
1230+
| 生成器 | 「一个 python 脚本读一个文本文件」 | `makealias.py` 71 行 + `cutout.py` + gperf + `fc-case.py` **240 行** + `fc-lang.py` **387 行,吃 281 个 `.orth` 数据文件** |
1231+
1232+
`fc-lang` 把 281 个正字法文件编译成 FcCharSet 的 leaf/number 位图 —— 复刻它
1233+
约等于重写一个小编译器。**这不是「工作量不大」**,而我基于错误估算说过它是。
1234+
1235+
### 15.2 已经做通的部分(全部在 `build.mcpp` 里,零外部工具)
1236+
1237+
- `fcstdint.h`
1238+
- `fcalias.h` / `fcaliastail.h` —— 复刻 `makealias.py`,**含它的分组顺序**:
1239+
tail 按"哪个 `.c` 定义了这个符号"分组,`#ifdef` 块必须按首见顺序嵌套
1240+
- `fcftalias.h` / `fcftaliastail.h`
1241+
- **`fcobjshash.h` —— 用二分查找替掉 gperf 的完美哈希**。这是一处**判断**而非
1242+
转写:唯一消费者是 `fcobjs.c`,它调 `FcObjectTypeLookup(str, strlen(str))` 并
1243+
只读 `->id`,72 个条目。语义等价,而少一个工具和一遍 C 预处理。条目来自
1244+
`fcobjs.h` 的 `FC_OBJECT(...)` 列表 + `fontconfig.h` 的 `#define FC_<NAME>`,
1245+
两个文本扫描,不需要 cpp
1246+
- 模块包装
1247+
- `config.h` —— **不是**生成物:它是探测**答案**,属于适配目录里可读可争的文件,
1248+
不属于生成器。四条运行期路径按既定立场留空
1249+
(`FONTCONFIG_FILE` / `FONTCONFIG_PATH` / `FONTCONFIG_SYSROOT` 是出口)
1250+
1251+
### 15.3 仍缺的两个,以及形态建议
1252+
1253+
`fc-case`(240 行,吃 `CaseFolding.txt`)和 `fc-lang`(387 行,吃 281 个
1254+
`.orth`)。前者可复刻;后者是本轮单个最大的一块。
1255+
1256+
**建议的混合形态**:能 `build.mcpp` 的全做,`fclang.h` 作为**唯一例外**签进适配
1257+
目录并在文件头写明理由。这违反"不签生成物",但避开重写位图编译器 —— 而把例外
1258+
写在文件里、只此一处,比为了纯粹性再花一天更划算。
1259+
1260+
---
1261+
1262+
## 16. 沙箱验证的一个盲点(2026-08-30)
1263+
1264+
补跑新增三个包的沙箱验证时,脚本把一个**已发布一小时**的包报成「找不到」。原因:
1265+
1266+
```
1267+
index: local index af79fd2 (never refreshed)
1268+
```
1269+
1270+
沙箱的 home 是合成的,mcpp 带的是镜像里那份索引快照,**早于被测的包**。而
1271+
"刷新索引"正是新用户会做的第一件事。
1272+
1273+
**所以任何在 `--sandbox` 里做的验证,第一步必须是 `mcpp index update`** ——
1274+
否则测的是镜像打包那天的生态,而不是今天的。这与
1275+
「本地旧索引快照掩盖描述符错误」那条 是同一类,只是发生在沙箱侧。

0 commit comments

Comments
 (0)