概述
xpkg store 的目录是带命名空间的(<ns>-x-<name>/<version>/),但判断「这个包装过没有」的那层查找不比对 namespace,只看 (name, version)。于是不同命名空间下同短名同版本的两个包会互相顶替 —— 而且失败是静默的,最终报出来的错误和真正的原因毫无关系。
实测环境:mcpp 2026.8.29.1,xlings 2026.8.27.4。
复现
compat.libdrm 是一个源码构建包,install() 里建两个 include 根(libdrm 的公开头在根、uapi 头在 libdrm/ 子目录)。把它的版本定为上游版本 2.4.123:
-- pkgs/c/compat.libdrm.lua
["2.4.123"] = {
url = { GLOBAL = "https://dri.freedesktop.org/libdrm/libdrm-2.4.123.tar.xz" },
sha256 = "a2b98567a149a74b0f50e91e825f9c0315d86e7be9b74394dae8b298caadb79e",
},
在任何装了 Mesa 的机器上构建都会失败,因为 xim:mesa 的依赖里有 xim:libdrm@>=2.4,所以 store 里一定有 xim-x-libdrm/2.4.123。
发生了什么
$ mcpp test
Compiling compat.libdrm v2.4.123 <- 看起来解析成功
error: build failed
failed: bin/libdrm.so
-shared @bin/libdrm.so.rsp -o bin/libdrm.so ... -Wl,-soname,libdrm.so.2
/bin/sh: 1: -shared: not found
/bin/sh: 1: -shared: not found 与真正的原因隔了三层:
- store 认为
libdrm@2.4.123 已安装(它看到的是 xim-x-libdrm/2.4.123),于是跳过 install();
- 但版本目录照样被建出来并标记为装好了:
$ ls -a <store>/compat-x-libdrm/2.4.123/
. .. .mcpp_ok .xpkg-install.json mcpp_generated/
.mcpp_ok、.xpkg-install.json 都在,mcpp_generated/ 是 mcpp 自己的 generated_files 写的 —— 只有描述符 install() 该建的那棵树不存在;
- 于是
sources 一个都没匹配上,mcpp 生成了一条零输入的 c_shared 边:
build bin/libdrm.so : c_shared # 对照正常情况:c_shared obj/a.o obj/b.o ...
- 因为没有对象要编,
cc 变量根本没被写进 build.ninja(只有 cxx),$cc -shared ... 展开成 -shared ...,shell 去执行 -shared。
关键点:与是否声明该依赖无关
这一点值得强调 —— 我最初以为是「本包声明了 xim:libdrm 才会撞」,不是。上面这个 compat.libdrm 完全没有 xim:* 依赖(纯源码构建,deps = {}),撞的是 store 里碰巧存在的任何同名同版本包。
判定方法
把版本号临时改成一个不可能撞的值:
-["2.4.123"] = {
+["2.4.123-probe"] = {
install() 立刻被调用,而且里面的错误会大声报出来:
error: xlings install_packages failed (exit 1) for 'compat.libdrm@2.4.123-probe'
xlings reported: E_INTERNAL: [libdrm] failed: install hook failed:
compat.libdrm.lua:219: attempt to call a nil value (field 'tmpdir')
同一份描述符,只差版本号:一个静默跳过、报无关错误,一个正常执行、错误可见。
影响
这条规则实际上是在说:索引里任何 compat 包的 <短名>@<版本> 都不能与生态里某个 xim:* 包相同,而包作者无从知道生态里有什么、将来会加什么。
具体到这次的图形栈,四个包全部被迫改版本号:
| 包 |
想用 |
实际只能用 |
撞的是 |
compat.libdrm |
2.4.123 |
2.4.123.1 |
xim:libdrm@2.4.123 |
compat.wayland |
1.23.1 |
1.23.1.1 |
xim:wayland@1.23.1 |
freedesktop.wayland(模块层) |
1.23.1 |
1.23.1.2 |
上面两个 |
compat.libffi |
3.4.4(与生态同版) |
3.4.8 |
xim:libffi@3.4.4 |
compat.expat 同理只能取 2.7.1 而不是生态的 2.6.2。
也就是说:一个包想和生态用同一个上游版本,是表达不出来的 —— 而这恰恰是最常见、最应该被鼓励的情形(消费者和 Mesa 用同一份 libdrm)。
建议
store 的已安装查找按 (namespace, name, version) 匹配,与目录布局 <ns>-x-<name>/<version>/ 一致。
这是 xlings#381(index 侧按 (namespace, name) 建键)在 store 侧的同一个缺口。
在修好之前,至少让它不要静默:如果查找命中了一个 namespace 不同的包,要么报错,要么在跳过 install() 时打印出「命中的是 <ns>-x-<name>/<version>」。现在的表现是把一个包管理器的身份问题伪装成了一条链接器命令行错误。
相关
- 索引侧的四个包与形态讨论:mcpplibs/mcpp-index(源码构建的图形栈)
- 顺带一个小的:Form A 的纯 C 库包(
[targets.x] kind = "shared",没有任何 .cppm)会稳定报
warning: src/<name>.cppm: lib target without conventional lib root。C 库没有 lib root 可言,这个告警会传染给每个消费者。
概述
xpkg store 的目录是带命名空间的(
<ns>-x-<name>/<version>/),但判断「这个包装过没有」的那层查找不比对 namespace,只看(name, version)。于是不同命名空间下同短名同版本的两个包会互相顶替 —— 而且失败是静默的,最终报出来的错误和真正的原因毫无关系。实测环境:mcpp
2026.8.29.1,xlings2026.8.27.4。复现
compat.libdrm是一个源码构建包,install()里建两个 include 根(libdrm 的公开头在根、uapi 头在libdrm/子目录)。把它的版本定为上游版本2.4.123:在任何装了 Mesa 的机器上构建都会失败,因为
xim:mesa的依赖里有xim:libdrm@>=2.4,所以 store 里一定有xim-x-libdrm/2.4.123。发生了什么
/bin/sh: 1: -shared: not found与真正的原因隔了三层:libdrm@2.4.123已安装(它看到的是xim-x-libdrm/2.4.123),于是跳过install();.mcpp_ok、.xpkg-install.json都在,mcpp_generated/是 mcpp 自己的generated_files写的 —— 只有描述符install()该建的那棵树不存在;sources一个都没匹配上,mcpp 生成了一条零输入的c_shared边:cc变量根本没被写进build.ninja(只有cxx),$cc -shared ...展开成-shared ...,shell 去执行-shared。关键点:与是否声明该依赖无关
这一点值得强调 —— 我最初以为是「本包声明了
xim:libdrm才会撞」,不是。上面这个compat.libdrm完全没有xim:*依赖(纯源码构建,deps = {}),撞的是 store 里碰巧存在的任何同名同版本包。判定方法
把版本号临时改成一个不可能撞的值:
install()立刻被调用,而且里面的错误会大声报出来:同一份描述符,只差版本号:一个静默跳过、报无关错误,一个正常执行、错误可见。
影响
这条规则实际上是在说:索引里任何 compat 包的
<短名>@<版本>都不能与生态里某个xim:*包相同,而包作者无从知道生态里有什么、将来会加什么。具体到这次的图形栈,四个包全部被迫改版本号:
compat.libdrm2.4.1232.4.123.1xim:libdrm@2.4.123compat.wayland1.23.11.23.1.1xim:wayland@1.23.1freedesktop.wayland(模块层)1.23.11.23.1.2compat.libffi3.4.4(与生态同版)3.4.8xim:libffi@3.4.4compat.expat同理只能取2.7.1而不是生态的2.6.2。也就是说:一个包想和生态用同一个上游版本,是表达不出来的 —— 而这恰恰是最常见、最应该被鼓励的情形(消费者和 Mesa 用同一份 libdrm)。
建议
store 的已安装查找按
(namespace, name, version)匹配,与目录布局<ns>-x-<name>/<version>/一致。这是 xlings#381(index 侧按
(namespace, name)建键)在 store 侧的同一个缺口。在修好之前,至少让它不要静默:如果查找命中了一个 namespace 不同的包,要么报错,要么在跳过
install()时打印出「命中的是<ns>-x-<name>/<version>」。现在的表现是把一个包管理器的身份问题伪装成了一条链接器命令行错误。相关
[targets.x] kind = "shared",没有任何.cppm)会稳定报warning: src/<name>.cppm: lib target without conventional lib root。C 库没有 lib root 可言,这个告警会传染给每个消费者。