Skip to content

compat.expat 改为静态:host tool 链接它才能真的跑起来 - #291

Merged
Sunrisepeak merged 1 commit into
mainfrom
fix/expat-static-for-host-tools
Aug 30, 2026
Merged

compat.expat 改为静态:host tool 链接它才能真的跑起来#291
Sunrisepeak merged 1 commit into
mainfrom
fix/expat-static-for-host-tools

Conversation

@Sunrisepeak

@Sunrisepeak Sunrisepeak commented Aug 30, 2026

Copy link
Copy Markdown
Member

compat.expat 当初照搬 compat.libdrm 做成了 kind = "shared"。这个类比不成立,而且 shared 形态对它唯一的消费者是坏的。

libdrm 为什么必须 shared,而 expat 不必

libdrm 必须是进程里唯一一份映射:Mesa 的 payload 对 libdrm.so.2 有 DT_NEEDED,而 libdrm 保有可变的 file-static 状态(drmHashTablenr_fdsconnection)横跨同一批 fd —— 两份就是两套账。

expat 没有对应物:解析状态全挂在调用方持有的 XML_Parser 上,所以消费者并入这些对象、同时 Mesa 加载 payload 那份 libexpat.so.1,并不共享任何会被写坏的东西。

shared 在这里是坏的

expat 在本索引里唯一的消费者是 freedesktop.wayland-scanner(#290)—— 一个 kind = "bin"host tool,mcpp 在子构建里把它建出来,然后在别的包的 build.mcpp 期间运行它。

host tool 链接 shared 依赖,产出的二进制带着无人满足的 DT_NEEDED:mcpp 不会把那个 .so 放到工具旁边,子构建的 bin/ 里只有可执行文件:

    Building host tool wayland-scanner:wayland-scanner from wayland-scanner v1.26.0
error: dependency 'wayland': build.mcpp exited with 1 (build aborted):
  .../bin/wayland-scanner: error while loading shared libraries:
  libexpat.so.1: cannot open shared object file: No such file or directory

已上报:mcpp-community/mcpp#535

为什么本地没测出来 —— 这一条比失败本身更值得记

这个失败只在没有图形栈的机器上复现。工具 RPATH 的最后一项是 <registry>/subos/default/lib,而装了 Mesa 的机器上那里正好有一个 libexpat.so.1 —— 是 xim:expat 2.6.2 的那一份。于是工具照常启动,只不过链的是另一个库的另一个版本:

libexpat.so.1 => <registry>/subos/default/lib/libexpat.so.1    # xim:expat 2.6.2,不是 compat.expat 2.7.1

开发机绿、干净 runner 红,而且开发机上那次"成功"用的根本不是声明的那个依赖。改静态就没有这个问题。

测试

dladdr 那条断言含义不变:对象并入消费者后它报告的是可执行文件本身,而它断言的东西还是同一件 —— 刚才完成解析的代码不来自生态那份 xim:expat

本地 expat 成员全绿:XML_NS 前缀展开、DTD 实体展开、错误拒绝、来源断言。

Refs #290, #289

compat.expat was shared by analogy with compat.libdrm. The analogy does not
hold, and the shared form is actively broken for its only consumer.

WHY LIBDRM IS SHARED AND EXPAT NEED NOT BE. libdrm must be one mapping because
Mesa's payload has DT_NEEDED on libdrm.so.2 and the library keeps mutable
file-static state — drmHashTable, nr_fds, connection — over a shared set of
fds, so a second copy is a split ledger. Expat has no equivalent: parser state
hangs off the XML_Parser the caller owns.

WHY SHARED IS BROKEN HERE. The only consumer is freedesktop.wayland-scanner, a
 HOST TOOL that mcpp builds in a sub-build and then runs during
another package's build.mcpp. A host tool linking a shared dependency comes out
with a DT_NEEDED nothing satisfies — mcpp does not stage the .so beside the
tool, and the sub-build's bin/ holds the executable alone:

    wayland-scanner: error while loading shared libraries:
    libexpat.so.1: cannot open shared object file

Reported as mcpp-community/mcpp#535.

The failure only reproduces without a graphics stack, which is why it reached
CI rather than being caught here: with Mesa installed the tool's RPATH reaches
<registry>/subos/default/lib and binds to xim:expat's copy instead — a
DIFFERENT library, silently succeeding. Static removes the question.

The test's dladdr check keeps its meaning: with objects merged it reports the
executable, and what it asserts is unchanged — that the code which just parsed
did not come from the ecosystem's copy.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants