Skip to content

Commit 58cf8b7

Browse files
committed
fix(模块): 托管方不是负责方 —— 改名 cairo/displayinfo,并补齐两个不完备的包装体
改名:freedesktop.cairo -> cairo,freedesktop.displayinfo -> displayinfo。 索引 namespace 是货架标签,从不进模块名。cairo 是它自己的项目,freedesktop.org 托管 git 但不拥有那套接口;libdisplay-info 解析的是 VESA 的 EDID/DisplayID。同 一条规则下 freedesktop.egl 导出的是 khronos.egl。 ⭐ 而且两个包装体都不完备: cairo 470 -> 697 缺 cairo_t,以及全部 192 个枚举量 displayinfo 206 -> 501 缺全部 295 个枚举量 cairo_t 的原因很具体:正则 cairo_[a-z0-9_]+_t 要求 cairo_ 与 _t 之间至少一个 字符,于是 `typedef struct _cairo cairo_t;` —— 这个库里用得最多的类型 —— 恰好 是它唯一匹配不到的名字。 为什么一直没人发现,这才是要记的: - cairo:唯一 import 那个模块的测试同时写了 #include <cairo.h>,头文件把模块 缺的都补上了。一个从没被要求独立站住的 import,不是被测试了,是被装饰了。 - displayinfo:没有任何测试点过一个枚举量。而且只在 GCC 上加一个也发现不了 —— 导出 enum 会让枚举量在 GCC 可见,clang 拒绝同一个文件。 它是从外面被发现的:gnome.pangocairo 不能混用两条消费路线,只能问模块要 cairo_t,结果什么都没拿到。pango 那一版因此自己扫了 cairo.h;现在 cairo 修好, 那个变通已经删掉,普通的 export import cairo; 就够了。 发布形态:这两个包用 release 资产而不是 tag 归档,所以走 -mcpp3 新资产,tag 不 动、零窗口。pango 重切 tag(sha 0882a260…,CN 容器 tag 1.56.1-5)。 ⚠️ 验证时撞上了本地 store 按 (name, version) 索引的固定代价:已解开过 1.18.2 的 机器拿不到新资产,报 `failed to read compiled module`,清掉 store 条目才对。已 写进 §23.4。 cairo 的测试拆成两个文件,一条路线一个,module.cpp 一个头都不包;displayinfo 的 测试比较两个枚举量 —— 导出清单再塌陷就是编译错误。 五个示例 × 两条工具链全绿。
1 parent 3a4ab31 commit 58cf8b7

9 files changed

Lines changed: 295 additions & 27 deletions

File tree

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

Lines changed: 70 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.9,§11 总账 / §14 fork 规范 / §18 八角度复核 / §19 合成器闸门与 GObject 栈,含沙箱实测 · §20 gio 与一次被推翻的判断 · §21 namespace 是契约 · §22 pango:文本排版接上了)**
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 · **状态:已实现并闭环验证(v2.0,§11 总账 / §14 fork 规范 / §18 八角度复核 / §19 合成器闸门与 GObject 栈,含沙箱实测 · §20 gio 与一次被推翻的判断 · §21 namespace 是契约 · §22 pango:文本排版接上了 · §23 模块名与包装体完备性)**
44

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

@@ -2174,3 +2174,72 @@ error: dependency 'gnome.gobject' is requested as both a version dep
21742174
| 端到端 | 1,492 个像素 |
21752175

21762176
**文本排版那条线接上了。**
2177+
2178+
---
2179+
2180+
## 23. 模块名与包装体完备性:两个已发布包的修正(2026-08-31)
2181+
2182+
### 23.1 托管方不是负责方 —— 模块名改了两个
2183+
2184+
| 包(索引键) | 旧模块名 | 新模块名 |
2185+
|---|---|---|
2186+
| `freedesktop.cairo` | `freedesktop.cairo` | **`cairo`** |
2187+
| `freedesktop.libdisplay-info` | `freedesktop.displayinfo` | **`displayinfo`** |
2188+
2189+
**索引 namespace 是货架标签,从不进模块名。** cairo 是它自己的项目,
2190+
freedesktop.org 托管 git 但不拥有那套接口;libdisplay-info 解析的是 **VESA** 的
2191+
EDID/DisplayID,`freedesktop.*` 这个模块前缀留给 freedesktop 自己的规范(像
2192+
`freedesktop.wayland.client`)。同一条规则下 `freedesktop.egl` 导出的是
2193+
`khronos.egl`。
2194+
2195+
改名会让老消费者**编译报错并点名模块** —— 这是最该发现问题的地方。
2196+
2197+
### 23.2 ⭐ 两个包装体都不完备,而且都是「没人问过」
2198+
2199+
| | 导出 | 缺了什么 |
2200+
|---|---|---|
2201+
| `cairo` | 470 → **697** | `cairo_t`,以及**全部 192 个枚举量** |
2202+
| `displayinfo` | 206 → **501** | **全部 295 个枚举量** |
2203+
2204+
`cairo_t` 的原因很具体:正则是 `cairo_[a-z0-9_]+_t`,要求 `cairo_` 与 `_t` 之间
2205+
至少有一个字符 —— 于是
2206+
```c
2207+
typedef struct _cairo cairo_t; /* cairo.h:135 */
2208+
```
2209+
**这个库里用得最多的类型,恰好是它唯一匹配不到的名字。**
2210+
2211+
**为什么一直没人发现,这才是要记的:**
2212+
2213+
- cairo:唯一 import 那个模块的测试**同时**写了 `#include <cairo.h>`,头文件把
2214+
模块缺的都补上了。**一个从没被要求独立站住的 import,不是被测试了,是被装饰了。**
2215+
- displayinfo:**没有任何测试点过一个枚举量**。而且只在 GCC 上加一个也发现不了 ——
2216+
导出 enum 会让枚举量在 GCC 可见,clang 拒绝同一个文件(§21.5)。
2217+
2218+
### 23.3 它是从**外面**被发现的
2219+
2220+
`gnome.pangocairo` **不能混用两条消费路线**(`pangocairo.h` 经 glib 到
2221+
`<stdio.h>`),所以它只能问模块要 `cairo_t` —— 结果什么都没拿到。
2222+
2223+
于是 pango 那一版带了个变通:**自己扫 `cairo.h`**。现在 cairo 修好了,
2224+
**那个变通已经删掉**,普通的 `export import cairo;` 就够了 —— 本来就该够。
2225+
2226+
> 一个包的包装体缺不缺,自己的测试可能永远问不出来;**是别的包在用它的时候问出来的。**
2227+
2228+
### 23.4 发布形态:发资产,不重切 tag
2229+
2230+
这两个包用的是 **release 资产**(`cairo-1.18.2-mcpp2.tar.gz`)而不是 tag 归档,
2231+
所以修正走 `-mcpp3` 新资产:**tag 不动,零窗口**,而且资产名自带修订号。
2232+
(对比 glib/pango 用 tag 归档,只能原地重切 + 换 sha。)
2233+
2234+
⚠️ 本地 store 按 `(name, version)` 索引,所以已经解开过 `1.18.2` 的机器**拿不到
2235+
新资产** —— 本次验证时就撞上了(`failed to read compiled module`),清掉 store
2236+
条目才对。这是「包版本与上游对齐」这条约定的固定代价,值得写在这里。
2237+
2238+
### 23.5 结果
2239+
2240+
| | |
2241+
|---|---|
2242+
| `cairo` | 697 个导出;测试拆成两个文件,一条路线一个,module.cpp **一个头都不包** |
2243+
| `displayinfo` | 501 个导出;测试比较两个枚举量,导出清单再塌陷就是编译错误 |
2244+
| `gnome.pangocairo` | 变通删除,`export import cairo;` |
2245+
| 验证 | 五个示例 × 两条工具链全绿 |

‎pkgs/f/freedesktop.cairo.lua‎

Lines changed: 33 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,36 @@
4747
-- `cairo_paint` working, and gives every PATH garbage fixed-point coordinates:
4848
-- `cairo_rectangle(4,4,16,16)` came out with extents -8.03e+06 … 4.37e+06 and
4949
-- `cairo_fill` changed zero pixels. Measured.
50+
--
51+
-- ─────────────────────────────────────────────────────────────────────────
52+
-- ⚠️ THE MODULE IS `cairo`, NOT `freedesktop.cairo`
53+
--
54+
-- import cairo;
55+
--
56+
-- cairo is its own project; freedesktop.org hosts the git and does not own the
57+
-- interface. **The index namespace is a shelf label and never enters the module
58+
-- name** — the same reason `freedesktop.egl` exports `khronos.egl`.
59+
--
60+
-- This changed in the mcpp3 asset. A consumer on the old name gets a compile
61+
-- error naming the module, which is the right place to find out.
62+
--
63+
-- ⭐ AND THE WRAPPER WAS INCOMPLETE: 470 names, missing `cairo_t` and all 192
64+
-- enumerators. It was found from OUTSIDE, by `gnome.pangocairo`, which cannot
65+
-- mix the two consumption routes and therefore had to ask the module for
66+
-- `cairo_t` and got nothing.
67+
--
68+
-- cairo_t `typedef struct _cairo cairo_t;` — the typedef regex
69+
-- needed a character between `cairo_` and `_t`, so the
70+
-- most-used type in the library was the one it could not
71+
-- match.
72+
-- 192 enumerators every CAIRO_FORMAT_*, CAIRO_STATUS_*, CAIRO_OPERATOR_*.
73+
-- The scan never entered a `typedef enum` body.
74+
--
75+
-- ⚠️ WHY NOBODY NOTICED, and the lesson worth keeping: the only test that
76+
-- imported the module ALSO wrote `#include <cairo.h>`, so the header supplied
77+
-- whatever the module lacked. **An import that is never asked to stand on its
78+
-- own is not tested, it is decorated.** The fork now has two test files, one
79+
-- per route, and exports 697 names.
5080
package = {
5181
spec = "1",
5282
namespace = "freedesktop",
@@ -60,10 +90,10 @@ package = {
6090
linux = {
6191
["1.18.2"] = {
6292
url = {
63-
GLOBAL = "https://github.com/mcpplibs/cairo/releases/download/v1.18.2/cairo-1.18.2-mcpp2.tar.gz",
64-
CN = "https://gitcode.com/mcpp-res/cairo/releases/download/1.18.2/cairo-1.18.2-mcpp2.tar.gz",
93+
GLOBAL = "https://github.com/mcpplibs/cairo/releases/download/v1.18.2/cairo-1.18.2-mcpp3.tar.gz",
94+
CN = "https://gitcode.com/mcpp-res/cairo/releases/download/1.18.2/cairo-1.18.2-mcpp3.tar.gz",
6595
},
66-
sha256 = "202352a38d0847628c55cd0f9c67e85ac78667ad76bc88691ab47606d1104ef7",
96+
sha256 = "5a82cfb52365f40b7ecc679d7d67c3c34459aef4a69b4b75c2c0c964d74ec6e1",
6797
},
6898
},
6999
},

‎pkgs/f/freedesktop.libdisplay-info.lua‎

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -45,14 +45,35 @@
4545
-- THE MODULE IS GENERATED, not hand-written: 206 names read out of the public
4646
-- headers, so a version bump cannot silently drop one.
4747
--
48-
-- import freedesktop.displayinfo;
48+
-- import displayinfo;
4949
--
5050
-- and that also removes a real burden — not one of the seven public headers has
5151
-- an `extern "C"` block, so a C++ TU that #includes them mangles every
5252
-- declaration and fails to link with `undefined reference to
5353
-- di_info_get_make(di_info const*)`. The module does that wrapping once, inside
5454
-- the module purview, so a consumer does not. (compat.libseat has the same
5555
-- upstream problem and no module, so there the consumer still wraps.)
56+
--
57+
-- ─────────────────────────────────────────────────────────────────────────
58+
-- ⚠️ THE MODULE IS `displayinfo`, NOT `freedesktop.displayinfo`
59+
--
60+
-- import displayinfo;
61+
--
62+
-- freedesktop.org HOSTS this library; the interfaces it parses are **VESA's**
63+
-- (EDID, DisplayID). `freedesktop.*` in a module name is for freedesktop's own
64+
-- specifications, the way `freedesktop.wayland.client` is. The index namespace
65+
-- is a shelf label and never enters the module name.
66+
--
67+
-- This changed in the mcpp3 asset; a consumer on the old name gets a compile
68+
-- error naming the module.
69+
--
70+
-- ⭐ AND THE WRAPPER EXPORTED 206 NAMES AND NOT ONE ENUMERATOR — the module
71+
-- carried `enum di_edid_…` but nothing inside it. 295 of them.
72+
--
73+
-- ⚠️ It went unnoticed because no test named an enumerator, and adding one on
74+
-- GCC alone would not have noticed either: exporting an enum makes its
75+
-- enumerators visible there, and clang rejects the same file. The same gap was
76+
-- in `freedesktop.cairo`. 501 names now, and the test compares two enumerators.
5677
package = {
5778
spec = "1",
5879
namespace = "freedesktop",
@@ -66,10 +87,10 @@ package = {
6687
linux = {
6788
["0.2.0"] = {
6889
url = {
69-
GLOBAL = "https://github.com/mcpplibs/libdisplay-info/releases/download/v0.2.0/libdisplay-info-0.2.0-mcpp2.tar.gz",
70-
CN = "https://gitcode.com/mcpp-res/libdisplay-info/releases/download/0.2.0/libdisplay-info-0.2.0-mcpp2.tar.gz",
90+
GLOBAL = "https://github.com/mcpplibs/libdisplay-info/releases/download/v0.2.0/libdisplay-info-0.2.0-mcpp3.tar.gz",
91+
CN = "https://gitcode.com/mcpp-res/libdisplay-info/releases/download/0.2.0/libdisplay-info-0.2.0-mcpp3.tar.gz",
7192
},
72-
sha256 = "8df9a8064146b2b38378bd8b146894d084ffda43b88b43c485b954da073a7617",
93+
sha256 = "8b2238a7b275e7da831d96c4f73b607a522d03620e6d5e0f12c605ef04659c8b",
7394
},
7495
},
7596
},

‎pkgs/p/gnome.pango.lua‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -84,14 +84,14 @@ package = {
8484
["1.56.1"] = {
8585
url = {
8686
GLOBAL = "https://github.com/mcpplibs/pango/archive/refs/tags/1.56.1.tar.gz",
87-
-- ⚠️ The container tag is `1.56.1-4`, not `1.56.1`. gitcode
87+
-- ⚠️ The container tag is `1.56.1-5`, not `1.56.1`. gitcode
8888
-- refuses to REPLACE an asset of the same name in an
8989
-- existing release, so each corrected tarball needs a new
9090
-- container tag while the PACKAGE version stays upstream's.
9191
-- Verified byte-identical to the GLOBAL tag archive.
92-
CN = "https://gitcode.com/mcpp-res/pango/releases/download/1.56.1-4/pango-1.56.1.tar.gz",
92+
CN = "https://gitcode.com/mcpp-res/pango/releases/download/1.56.1-5/pango-1.56.1.tar.gz",
9393
},
94-
sha256 = "b470a658e05ef0e14d779bc852371ce52dd11efa76d10782347be40f1d63476b",
94+
sha256 = "0882a260346cbdb6b553177269a8acc083a2985bbe929b458406af98e90a03ad",
9595
},
9696
},
9797
},

‎pkgs/p/gnome.pangocairo.lua‎

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,20 @@
2222
-- then segfaulted. The fork's test now reads the font map's FONT TYPE and
2323
-- requires `CAIRO_FONT_TYPE_FT`, which catches it immediately.
2424
--
25-
-- ⚠️ AND freedesktop.cairo's MODULE IS NOT SUFFICIENT ON ITS OWN. Measured on
26-
-- 1.18.2: 470 names, ZERO enumerators (no `CAIRO_FORMAT_ARGB32`, no
27-
-- `CAIRO_FONT_TYPE_FT`) and no `cairo_t`. The index's own cairo example does
28-
-- not notice, because it writes BOTH `#include <cairo.h>` and
29-
-- `import freedesktop.cairo;`. pangocairo cannot mix the routes, so its module
30-
-- scans cairo.h itself; that can go when cairo's wrapper is fixed.--
25+
-- ✅ AND THIS PACKAGE IS WHERE cairo's MODULE GAP WAS FOUND. On the
26+
-- `1.18.2-mcpp2` asset `freedesktop.cairo` exported 470 names, ZERO
27+
-- enumerators and no `cairo_t`. The index's own cairo example did not notice,
28+
-- because it wrote BOTH `#include <cairo.h>` and `import freedesktop.cairo;`
29+
-- — the header supplied what the module lacked, so that import had never been
30+
-- asked to stand on its own.
31+
--
32+
-- It surfaced here because pangocairo CANNOT mix the two routes
33+
-- (`pangocairo.h` reaches glib and therefore <stdio.h>), so it had to ask the
34+
-- module for `cairo_t` and got nothing. This package carried a workaround for
35+
-- one release — scanning cairo.h itself — and that workaround is GONE:
36+
-- `1.18.2-mcpp3` exports 697 names and the plain re-export is enough.
37+
--
38+
-- The module it re-exports is now `cairo`, not `freedesktop.cairo`.--
3139
-- ─────────────────────────────────────────────────────────────────────────
3240
-- ⭐ TWO WAYS TO CONSUME IT, AND YOU PICK ONE
3341
--
@@ -90,14 +98,14 @@ package = {
9098
["1.56.1"] = {
9199
url = {
92100
GLOBAL = "https://github.com/mcpplibs/pango/archive/refs/tags/1.56.1.tar.gz",
93-
-- ⚠️ The container tag is `1.56.1-4`, not `1.56.1`. gitcode
101+
-- ⚠️ The container tag is `1.56.1-5`, not `1.56.1`. gitcode
94102
-- refuses to REPLACE an asset of the same name in an
95103
-- existing release, so each corrected tarball needs a new
96104
-- container tag while the PACKAGE version stays upstream's.
97105
-- Verified byte-identical to the GLOBAL tag archive.
98-
CN = "https://gitcode.com/mcpp-res/pango/releases/download/1.56.1-4/pango-1.56.1.tar.gz",
106+
CN = "https://gitcode.com/mcpp-res/pango/releases/download/1.56.1-5/pango-1.56.1.tar.gz",
99107
},
100-
sha256 = "b470a658e05ef0e14d779bc852371ce52dd11efa76d10782347be40f1d63476b",
108+
sha256 = "0882a260346cbdb6b553177269a8acc083a2985bbe929b458406af98e90a03ad",
101109
},
102110
},
103111
},

‎pkgs/p/gnome.pangoft2.lua‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -68,14 +68,14 @@ package = {
6868
["1.56.1"] = {
6969
url = {
7070
GLOBAL = "https://github.com/mcpplibs/pango/archive/refs/tags/1.56.1.tar.gz",
71-
-- ⚠️ The container tag is `1.56.1-4`, not `1.56.1`. gitcode
71+
-- ⚠️ The container tag is `1.56.1-5`, not `1.56.1`. gitcode
7272
-- refuses to REPLACE an asset of the same name in an
7373
-- existing release, so each corrected tarball needs a new
7474
-- container tag while the PACKAGE version stays upstream's.
7575
-- Verified byte-identical to the GLOBAL tag archive.
76-
CN = "https://gitcode.com/mcpp-res/pango/releases/download/1.56.1-4/pango-1.56.1.tar.gz",
76+
CN = "https://gitcode.com/mcpp-res/pango/releases/download/1.56.1-5/pango-1.56.1.tar.gz",
7777
},
78-
sha256 = "b470a658e05ef0e14d779bc852371ce52dd11efa76d10782347be40f1d63476b",
78+
sha256 = "0882a260346cbdb6b553177269a8acc083a2985bbe929b458406af98e90a03ad",
7979
},
8080
},
8181
},

‎tests/examples/cairo/tests/cairo.cpp‎

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// freedesktop.cairo — draw something, read the pixels back, and check that the
1+
// cairo, via its HEADERS — draw something, read the pixels back, and check that the
22
// feature split actually took effect.
33
//
44
// Cairo needs no display and no fonts on disk to draw: an image surface is
@@ -14,11 +14,26 @@
1414
#ifdef __linux__
1515

1616
#include <cairo.h>
17+
// ⚠️ cairo.h does NOT reach the feature headers. This name used to arrive from
18+
// the module — which is precisely the confusion this split removes: on the
19+
// header route you include what you use.
20+
#include <cairo-ft.h>
1721

1822
#include <cstdio>
1923
#include <cstring>
2024

21-
import freedesktop.cairo;
25+
// ⚠️ THIS FILE IS THE HEADER ROUTE, AND IT NO LONGER IMPORTS.
26+
//
27+
// It used to do BOTH — `#include <cairo.h>` and `import freedesktop.cairo;` —
28+
// and that is why nobody noticed the module was incomplete: the header
29+
// supplied every name the module was missing, including `cairo_t` and all 192
30+
// enumerators. An import that is never asked to stand on its own is not
31+
// tested, it is decorated.
32+
//
33+
// `tests/module.cpp` next door takes the module route alone. Two files,
34+
// because on GCC the two routes cannot be combined in one TU anyway: reaching
35+
// a system header both textually and through a module's global fragment makes
36+
// the same type two entities.
2237

2338
namespace {
2439

0 commit comments

Comments
 (0)