一句话
包的身份是 (名字, 版本),而描述文件可以在版本不变的前提下改变这个包的产物和链接面。 于是 mcpp index update 换掉了描述文件、却不重装已安装的包,两者当场互相矛盾——而矛盾暴露出来时,报错指向的是毫不相干的目标。
CI 结构上看不见这一条:CI 每次都是干净环境,(名字, 版本) 在它眼里从来不会「内容变过」。判据只能在装过旧版的机器上取得。
实例
compat.eui-neo@0.5.7 在 mcpp-index#269 里从「不带 glib」变成「install() 暂存 glib + -Lmcpp_generated/glib/lib -lgio-2.0 …」,版本号没动。
一台在 #269 之前装过该包的机器上:
症状一:刷新之前 —— 构建全绿,功能静默损坏
拿到旧描述文件,编出来的程序里根本没有 glib,托盘不工作,没有任何报错:
$ mcpp build
Finished dev [unoptimized + debuginfo] in 3.02s
$ readelf -d ./mytray | grep -cE 'lib(gio|gobject|glib)'
0
$ ./mytray
no tray available
用户不会知道自己需要 mcpp index update。
症状二:刷新之后 —— 硬失败,且报错指向无关目标
$ mcpp index update && mcpp build
failed: bin/libXau.so
ld: cannot find -lgio-2.0: No such file or directory
ld: cannot find -lgobject-2.0: No such file or directory
ld: cannot find -lglib-2.0: No such file or directory
failed: bin/libXdmcp.so
(同上)
compat.xau / compat.xdmcp 与 eui-neo 毫无关系,它们只是恰好声明了 kind = "shared"。
原因是那几个 flag 进了全局 c_ldflags,而 rule c_shared 对项目里每一个共享库展开它:
rule c_shared
command = $cc -shared @$out.rsp -o $out $c_ldflags $soname_flag $implib_flag $def_flag $unit_ldflags
c_ldflags = … -L/home/…/xpkgs/compat-x-eui-neo/0.5.7/mcpp_generated/glib/lib -lgio-2.0 -lgobject-2.0 -lglib-2.0 …
而 -L 指向的目录只有新 install() 才会创建:
$ ls ~/.mcpp/registry/data/xpkgs/compat-x-eui-neo/0.5.7/
EUI-NEO-0.5.7 mcpp_generated v0.5.7.tar.gz # ← 旧布局:上游包装层,无 install() 归一化
$ ls ~/.mcpp/registry/data/xpkgs/compat-x-eui-neo/0.5.7/mcpp_generated/glib/lib
ls: 不存在 # ← flag 指向一个从未被创建的目录
复现
需要一台装过旧版的机器。关键是版本号不变:
- 用某版描述文件装上
<pkg>@<ver>
- 索引里改这个包的描述文件,令其新增由
install() 产出的链接输入(ldflags 里的 -L),不动版本号
mcpp index update
rm -rf target mcpp.lock && mcpp build
⚠️ 只删 target / mcpp.lock 不足以复现:那些共享库若在描述文件变更之前就已建好并缓存,就不会重新链接,构建照样是绿的。我自己前几次本地绿就是这么来的——绿是构建顺序的产物。要连已装包一起删才谈得上对照:
rm -rf ~/.mcpp/registry/data/xpkgs/<ns>-x-<name>/<ver>
用户侧规避
删掉已装包让它重装。验证过:libgio/libgobject/libglib 回到 NEEDED,功能正常。
两条独立的问题
写在一起是因为一条暴露了另一条,但它们可以分开修:
A. 已装包的身份里没有描述文件。 描述文件既决定怎么装(install() 的产出)、又决定怎么链(ldflags/include_dirs),却不参与「这个包是否需要重装」的判定。可能的方向:把描述文件内容摘要纳入已装包的指纹;或让 index update 把描述文件变过的包标记为失效。跟 [依赖的 [build] 输入没进指纹] 是同一类。
B. 一个包的链接输入是全局的。 c_ldflags 让 compat.eui-neo 的 -lgio-2.0 出现在 libXau.so 的链接行上。即使 A 修好,这一条仍然让任何包的 ldflags 有能力打断无关目标,并且错误信息指向错误的地方。这跟 #519 那条 carries_foreign_link_inputs()(ldflags 里有 -L 的包不能构建成动态库)是同一个根:ldflags 是不透明字符串,mcpp 只能整体搬运,没法按作用域安放。 一个结构化的「本包随附的链接输入」键(包内相对目录 + 库名)会同时改善这两处。
诊断质量
这次报错本身也值一提:用户看到的是 linking bin/libXau.so: cannot find -lgio-2.0。从这句话到真因(另一个包的描述文件变了而它没重装)之间隔着三层,没有任何一层是错误信息提到的。如果 A 短期内不好修,至少在 -L 指向的目录不存在时说清楚是哪个包贡献了这个 flag、以及它的安装目录看起来是旧版布局。
环境
- mcpp
2026.8.28.2(发布版)
- mcpp-index
9927799
- Linux x86_64,gcc 16.1.0
一句话
包的身份是
(名字, 版本),而描述文件可以在版本不变的前提下改变这个包的产物和链接面。 于是mcpp index update换掉了描述文件、却不重装已安装的包,两者当场互相矛盾——而矛盾暴露出来时,报错指向的是毫不相干的目标。CI 结构上看不见这一条:CI 每次都是干净环境,
(名字, 版本)在它眼里从来不会「内容变过」。判据只能在装过旧版的机器上取得。实例
compat.eui-neo@0.5.7在 mcpp-index#269 里从「不带 glib」变成「install()暂存 glib +-Lmcpp_generated/glib/lib -lgio-2.0 …」,版本号没动。一台在 #269 之前装过该包的机器上:
症状一:刷新之前 —— 构建全绿,功能静默损坏
拿到旧描述文件,编出来的程序里根本没有 glib,托盘不工作,没有任何报错:
用户不会知道自己需要
mcpp index update。症状二:刷新之后 —— 硬失败,且报错指向无关目标
compat.xau/compat.xdmcp与 eui-neo 毫无关系,它们只是恰好声明了kind = "shared"。原因是那几个 flag 进了全局
c_ldflags,而rule c_shared对项目里每一个共享库展开它:而
-L指向的目录只有新install()才会创建:复现
需要一台装过旧版的机器。关键是版本号不变:
<pkg>@<ver>install()产出的链接输入(ldflags里的-L),不动版本号mcpp index updaterm -rf target mcpp.lock && mcpp buildtarget/mcpp.lock不足以复现:那些共享库若在描述文件变更之前就已建好并缓存,就不会重新链接,构建照样是绿的。我自己前几次本地绿就是这么来的——绿是构建顺序的产物。要连已装包一起删才谈得上对照:rm -rf ~/.mcpp/registry/data/xpkgs/<ns>-x-<name>/<ver>用户侧规避
删掉已装包让它重装。验证过:
libgio/libgobject/libglib回到NEEDED,功能正常。两条独立的问题
写在一起是因为一条暴露了另一条,但它们可以分开修:
A. 已装包的身份里没有描述文件。 描述文件既决定怎么装(
install()的产出)、又决定怎么链(ldflags/include_dirs),却不参与「这个包是否需要重装」的判定。可能的方向:把描述文件内容摘要纳入已装包的指纹;或让index update把描述文件变过的包标记为失效。跟 [依赖的[build]输入没进指纹] 是同一类。B. 一个包的链接输入是全局的。
c_ldflags让compat.eui-neo的-lgio-2.0出现在libXau.so的链接行上。即使 A 修好,这一条仍然让任何包的ldflags有能力打断无关目标,并且错误信息指向错误的地方。这跟 #519 那条carries_foreign_link_inputs()(ldflags里有-L的包不能构建成动态库)是同一个根:ldflags是不透明字符串,mcpp 只能整体搬运,没法按作用域安放。 一个结构化的「本包随附的链接输入」键(包内相对目录 + 库名)会同时改善这两处。诊断质量
这次报错本身也值一提:用户看到的是
linking bin/libXau.so: cannot find -lgio-2.0。从这句话到真因(另一个包的描述文件变了而它没重装)之间隔着三层,没有任何一层是错误信息提到的。如果 A 短期内不好修,至少在-L指向的目录不存在时说清楚是哪个包贡献了这个 flag、以及它的安装目录看起来是旧版布局。环境
2026.8.28.2(发布版)9927799