Skip to content

Commit 89cfee7

Browse files
compat.expat 改为静态:host tool 链接它才能真的跑起来 (#291)
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. Co-authored-by: Sunrisepeak <x.d2learn.org@gmail.com>
1 parent 11555ab commit 89cfee7

2 files changed

Lines changed: 35 additions & 4 deletions

File tree

pkgs/c/compat.expat.lua

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,33 @@ package = {
8686
"lib/xmlrole.c",
8787
},
8888

89-
targets = { ["expat"] = { kind = "shared", soname = "libexpat.so.1" } },
89+
-- STATIC, unlike compat.libdrm's shared build, and the difference is
90+
-- not an oversight.
91+
--
92+
-- libdrm is shared because Mesa's payload has DT_NEEDED on
93+
-- `libdrm.so.2` and the two must be ONE mapping — libdrm keeps mutable
94+
-- file-static state (`drmHashTable`, `nr_fds`, `connection`) over a
95+
-- shared set of fds, so a second copy is a split ledger. Expat has no
96+
-- equivalent: every bit of parser state hangs off the XML_Parser the
97+
-- caller owns, so a consumer that merges these objects while Mesa loads
98+
-- the payload's libexpat.so.1 is not sharing anything to corrupt.
99+
--
100+
-- And there is a concrete reason to prefer static here. Expat's only
101+
-- consumer in this index is `freedesktop.wayland-scanner`, a
102+
-- `kind = "bin"` HOST TOOL that mcpp builds in a sub-build and then
103+
-- RUNS during another package's build.mcpp. A host tool linking a
104+
-- shared dependency comes out with a DT_NEEDED nothing satisfies —
105+
-- mcpp does not stage the .so beside the tool, and the sub-build's
106+
-- bin/ holds the executable alone:
107+
--
108+
-- wayland-scanner: error while loading shared libraries:
109+
-- libexpat.so.1: cannot open shared object file
110+
--
111+
-- That reproduces only on a machine without a graphics stack: with
112+
-- Mesa installed the tool's RPATH reaches `<registry>/subos/default/lib`
113+
-- and silently binds to `xim:expat`'s copy instead — the WRONG library,
114+
-- succeeding. Static removes the question.
115+
targets = { ["expat"] = { kind = "lib" } },
90116
deps = {},
91117

92118
generated_files = {

tests/examples/expat/tests/xml.cpp

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -97,17 +97,22 @@ int main()
9797
}
9898

9999
// ── 4. It is THIS build that ran ─────────────────────────────────────
100+
// The package is `kind = "lib"`, so these objects are merged into the
101+
// consumer and dladdr reports the EXECUTABLE. The check that matters is
102+
// the same either way: the code that just parsed must not have come from
103+
// the ecosystem's `xim:expat`, which is present whenever Mesa is and would
104+
// otherwise answer silently.
100105
{
101106
Dl_info info{};
102107
const bool located =
103108
::dladdr(reinterpret_cast<void *>(&XML_ParserCreate), &info) != 0
104109
&& info.dli_fname != nullptr;
105-
check(located, "dladdr locates the loaded libexpat");
110+
check(located, "dladdr locates the code that parsed");
106111
if (located) {
107112
const std::string from = info.dli_fname;
108-
std::printf(" loaded from: %s\n", from.c_str());
113+
std::printf(" resolved from: %s\n", from.c_str());
109114
check(from.find("xim-x-expat") == std::string::npos,
110-
"the loaded libexpat is not the ecosystem payload's copy");
115+
"it is not the ecosystem payload's libexpat");
111116
}
112117
}
113118

0 commit comments

Comments
 (0)