-
Notifications
You must be signed in to change notification settings - Fork 9
feat(eui-neo): enable the linux SNI tray backend (EUI_TRAY_SNI) #245
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Closed
+0
−0
Closed
Changes from 3 commits
Commits
Show all changes
25 commits
Select commit
Hold shift + click to select a range
937df82
feat(eui-neo): enable the linux SNI tray backend (EUI_TRAY_SNI)
FarnaHerry 598562b
fix(eui-neo): make glib staging self-sufficient — store fallback, cop…
FarnaHerry 3851dd5
fix(eui-neo): explicit -L for the staged glib + pcre2 version coherence
FarnaHerry c155ce8
fix(eui-neo): remove host GLib closure reconstruction
FarnaHerry da0de4e
fix(eui-neo): resolve review merge cleanup
FarnaHerry 99f939b
fix(eui-neo): remove stale merge conflict markers
FarnaHerry 1bdd986
Merge remote-tracking branch 'upstream/main' into feat/eui-neo-linux-…
FarnaHerry cdacb42
fix(eui-neo): resolve generated platform source path
FarnaHerry a846ae8
fix(eui-neo): bridge platform header for generated TU
FarnaHerry 44bd72c
fix(eui-neo): expose archive root for platform includes
FarnaHerry ab9e382
fix(eui-neo): forward platform header from include root
FarnaHerry cb9f4c5
fix(eui-neo): expose GLib as Linux build dependency
FarnaHerry c0c1625
ci: retry validation after runner startup failure
FarnaHerry f167f78
fix(eui-neo): forward window backend header
FarnaHerry 41ed7b6
fix(eui-neo): restore native platform include layout
FarnaHerry 63f9bef
fix(eui-neo): expose archive root for platform includes
FarnaHerry 28b6afa
fix(eui-neo): restore native platform source include
FarnaHerry 1302c6c
fix(eui-neo): bridge nested platform includes
FarnaHerry ec30a51
fix(eui-neo): bridge tray platform include
FarnaHerry d646f54
fix(eui-neo): expose archive root includes
FarnaHerry 7ad565c
fix(eui-neo): revert to main source layout, drop generated wrappers
FarnaHerry 45797ce
fix(eui-neo): restore main include dirs, keep native platform source
FarnaHerry 87dc592
fix(eui-neo): expose archive core dir to consumer includes
FarnaHerry b81d461
fix(eui-neo): revert to main descriptor, keep pure unpack hook
FarnaHerry 1021627
fix(eui-neo): restore upstream package layout
FarnaHerry File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -27,15 +27,15 @@ | |
| -- descriptor names is byte-identical in upstream's CORE_SOURCES. | ||
| -- | ||
| -- 0.5.7: CORE_SOURCES is byte-identical to 0.5.6, so the lib's shape does not | ||
| -- change; the version's real moves are the linux tray default (SNI over GDBus | ||
| -- change; the version's real moves are the linux tray backend (SNI over GDBus | ||
| -- via glib/gio, replacing the dead GTK3+libappindicator path — tray_bridge.c | ||
| -- now speaks freedesktop SNI when EUI_TRAY_SNI is set, which `compat.tray` | ||
| -- never feeds) and SDL2-only input fixes (SDL_GetMouseFocus, pointer/button | ||
| -- mapping) plus X11 resource handling in the SDL2 window backend. None of that | ||
| -- touches the sources this descriptor compiles: `compat.tray` does not provide | ||
| -- GDBus, so the linux leg still builds the EUI_TRAY_HAS_BACKEND=0 stub exactly | ||
| -- as before, and the x11_*.cpp / tray-gio pieces are not in CORE_SOURCES. | ||
| -- The new `EUI_ENABLE_TRAY` option does not affect this package either. | ||
| -- speaks freedesktop StatusNotifierItem when EUI_TRAY_SNI is set, which this | ||
| -- descriptor now does on linux, wiring glib through `xim:glib` and the | ||
| -- staging install() hook below) and SDL2-only input fixes (SDL_GetMouseFocus, | ||
| -- pointer/button mapping) plus X11 resource handling in the SDL2 window | ||
| -- backend. The new `EUI_ENABLE_TRAY` option does not affect this package: | ||
| -- tray_bridge.c is in CORE_SOURCES unconditionally and the define selects | ||
| -- which backend its body compiles to. | ||
| -- | ||
| -- All `mcpp` paths are GLOBS relative to the verdir; the leading `*/` absorbs | ||
| -- the GitHub tarball's `EUI-NEO-0.5.7/` wrap layer. | ||
|
|
@@ -50,6 +50,13 @@ package = { | |
|
|
||
| xpm = { | ||
| linux = { | ||
| -- 0.5.7: tray_bridge.c (:207) speaks freedesktop StatusNotifierItem | ||
| -- over GDBus when EUI_TRAY_SNI is set — no GTK3, no libappindicator. | ||
| -- xim:glib publishes glib-2.0 / gio-2.0 / gobject-2.0 into the SubOS | ||
| -- view; the install() hook at the bottom of this file stages them | ||
| -- into the payload (headers for the compile, sonames for the link | ||
| -- and the runtime closure — the same mcpp#352 boundary as GL). | ||
| deps = { runtime = { "xim:glib@2.80.0" } }, | ||
| ["0.5.3"] = { | ||
| url = { GLOBAL = "https://github.com/sudoevolve/EUI-NEO/archive/refs/tags/v0.5.3.tar.gz", | ||
| CN = "https://gitcode.com/mcpp-res/eui-neo/releases/download/0.5.3/eui-neo-0.5.3.tar.gz" }, | ||
|
|
@@ -132,7 +139,9 @@ package = { | |
| -- `*/include` carries the umbrella `eui_neo.h` and `eui/*.h`; `*` is the | ||
| -- verdir root, which is what makes the `"components/…"`, `"core/…"` and | ||
| -- `"3rd/stb_image.h"` quoted includes resolve. Upstream marks both PUBLIC. | ||
| include_dirs = { "*/include", "*", "mcpp_generated" }, | ||
| -- `mcpp_generated/glib/include/glib-2.0` is the staged glib header tree | ||
| -- (linux SNI tray; see install()); off linux it is an empty directory. | ||
| include_dirs = { "*/include", "*", "mcpp_generated", "mcpp_generated/glib/include/glib-2.0" }, | ||
|
|
||
| -- mcpp#233/#240: every package in a link emits its objects into ONE | ||
| -- flat obj/ dir keyed by source basename. Upstream's | ||
|
|
@@ -458,13 +467,309 @@ package = { | |
| }, | ||
|
|
||
| linux = { | ||
| -- No tray define on purpose. Upstream only sets | ||
| -- EUI_TRAY_APPINDICATOR when pkg-config finds GTK3 AND | ||
| -- libappindicator; this index has neither, so tray_bridge.c | ||
| -- compiles its EUI_TRAY_HAS_BACKEND=0 stub — which is exactly | ||
| -- what upstream does on a machine without those dev packages. | ||
| -- `-ldl` is glad's CMAKE_DL_LIBS. | ||
| ldflags = { "-lpthread", "-ldl" }, | ||
| -- 0.5.7: tray_bridge.c (:207) speaks freedesktop StatusNotifierItem | ||
| -- over GDBus when EUI_TRAY_SNI is set — no GTK3, no libappindicator. | ||
| -- xim:glib (declared at the xpm→linux level) lands the libraries in | ||
| -- the SubOS view; the install() hook below stages them plus the | ||
| -- headers into mcpp_generated/glib/ so the compile and the runtime | ||
| -- closure both resolve inside the hermetic boundary (the same | ||
| -- mcpp#352 problem as GL on the host, the same staging shape as | ||
| -- compat.glx-runtime). | ||
| -- The -L is RELATIVE to the payload: mcpp resolves it against | ||
| -- the install dir (same convention as compat.openblas's | ||
| -- "-Llib"). It is load-bearing, not decorative: with only | ||
| -- runtime.library_dirs the staged dir reaches links as | ||
| -- -Wl,-rpath, which lld happens to search for -l but GNU ld | ||
| -- does not — on the GNU-ld toolchain -lglib then falls through | ||
| -- to the host's /lib64 (wrong glib, or none at all). | ||
| cflags = { "-DEUI_TRAY_SNI=1", "-pthread" }, | ||
| ldflags = { "-Lmcpp_generated/glib/lib", | ||
| "-lpthread", "-ldl", | ||
| "-lglib-2.0", "-lgio-2.0", "-lgobject-2.0" }, | ||
| runtime = { | ||
| library_dirs = { "mcpp_generated/glib/lib" }, | ||
| }, | ||
| }, | ||
| }, | ||
| } | ||
|
|
||
| import("xim.libxpkg.pkginfo") | ||
| import("xim.libxpkg.system") | ||
| import("xim.libxpkg.log") | ||
|
|
||
| -- Libraries the SNI tray backend needs at runtime, COPIED into the payload | ||
| -- so the link and the runtime closure both resolve inside one directory on | ||
| -- the consumer's RPATH. Copies, not symlinks: the subos view is | ||
| -- project-local while this payload is shared across projects, and a staged | ||
| -- symlink dangles the moment the project that provided the view is not the | ||
| -- one building (observed: `gio/gio.h file not found` off a shared payload | ||
| -- pointing into a wiped project .mcpp/). The payload dir is | ||
| -- version-immutable and already on the RPATH, so copies lose nothing. | ||
| -- Two origins, in preference order: | ||
| -- | ||
| -- * the glib sonames and the xim-provided transitives (libffi / pcre2 / | ||
| -- zlib — xim:glib's own deps) come from the subos view when published, | ||
| -- else straight from the xim store. The view alone is NOT enough at | ||
| -- hook time: a package already cached in the store skips the config() | ||
| -- run that publishes it, so on a fresh project view the transitives | ||
| -- can be missing even though the store holds them (observed). | ||
| -- * libmount / libselinux / libblkid have NO xim provider yet: the | ||
| -- xim:glib build links them, no xim package ships them. They are | ||
| -- staged from the HOST with a warning, the same host-plane fallback | ||
| -- compat.glx-runtime used before xim:graphics existed. The day xim | ||
| -- gains util-linux/libselinux packages this branch is dead code; | ||
| -- the day a host ships a glibc newer than the payload's, this is | ||
| -- the mcpp#352 configuration again and the warn below says so. | ||
| local subos_sonames = { | ||
| "libglib-2.0.so", "libglib-2.0.so.0", | ||
| "libgio-2.0.so", "libgio-2.0.so.0", | ||
| "libgobject-2.0.so", "libgobject-2.0.so.0", | ||
| "libgmodule-2.0.so", "libgmodule-2.0.so.0", | ||
| "libgthread-2.0.so", "libgthread-2.0.so.0", | ||
| "libffi.so.8", | ||
| "libpcre2-8.so", "libpcre2-8.so.0", | ||
| "libz.so", "libz.so.1", | ||
| } | ||
| local host_fallback_sonames = { | ||
| "libmount.so.1", | ||
| "libselinux.so.1", | ||
| "libblkid.so.1", | ||
| } | ||
| local host_lib_dirs = { | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
| "/usr/lib/x86_64-linux-gnu", "/lib/x86_64-linux-gnu", | ||
| "/usr/lib64", "/lib64", "/usr/lib", "/lib", | ||
| } | ||
|
|
||
| function install() | ||
| -- Default extraction, which this package previously got by having no | ||
| -- hook at all: move the unpacked tarball into place (same idiom as | ||
| -- compat.glfw). | ||
| local srcdir = pkginfo.install_file():replace(".tar.gz", "") | ||
| if not os.isdir(srcdir) then | ||
| srcdir = "EUI-NEO-" .. pkginfo.version() | ||
| end | ||
| local idir = pkginfo.install_dir() | ||
| os.tryrm(idir) | ||
| os.mv(srcdir, idir) | ||
|
|
||
| -- Normalize to the single wrap layer the descriptor's `*/` globs are | ||
| -- written against. Whether the tree arrives wrapped depends on the | ||
| -- fetch path: the GitHub tarball keeps its `EUI-NEO-<v>/` top level, | ||
| -- the CN mirror's does not — observed on one machine, one version, | ||
| -- one day apart. Without this, which layout a consumer compiles is a | ||
| -- function of their mirror, and the losing side fails with | ||
| -- `"core/…" file not found` on the quoted includes. | ||
| if os.isdir(path.join(idir, "core")) then | ||
| local tmp = idir .. ".wrap-tmp" | ||
| os.tryrm(tmp) | ||
| os.mv(idir, tmp) | ||
| os.mkdir(idir) | ||
| os.mv(tmp, path.join(idir, "EUI-NEO-" .. pkginfo.version())) | ||
| end | ||
|
|
||
| -- The staging dir exists on EVERY platform so the include_dirs entry | ||
| -- `mcpp_generated/glib/include/glib-2.0` never names a missing path; | ||
| -- only linux populates it. Off linux it stays an empty directory, | ||
| -- which as an -I is inert. | ||
| local gendir = path.join(pkginfo.install_dir(), "mcpp_generated", "glib") | ||
| local geninc = path.join(gendir, "include") | ||
| os.mkdir(path.join(geninc, "glib-2.0")) | ||
|
|
||
| if os.host() ~= "linux" then | ||
| return true | ||
| end | ||
|
|
||
| -- Resolver, in tier order. The subos VIEW (project-local) is consulted | ||
| -- first but is NOT reliable at hook time: entries appear there only | ||
| -- when the providing package's config() runs, and a package already | ||
| -- cached in the store skips that run — observed on a wiped .mcpp/ | ||
| -- where the view had the glib sonames but not pcre2/zlib/libffi yet. | ||
| -- The STORE (the xpkgs dir the payloads live in) is the stable source: | ||
| -- a package's files exist there from the moment it is fetched, which | ||
| -- for every xpm-level dep is strictly before this hook runs. | ||
| local subos = system.subos_sysrootdir() | ||
| local subos_lib = path.join(subos, "lib") | ||
|
|
||
| local store_roots = {} | ||
| local function add_root(root) | ||
| if root and root ~= "" and os.isdir(root) then | ||
| for _, r in ipairs(store_roots) do | ||
| if r == root then return end | ||
| end | ||
| table.insert(store_roots, root) | ||
| end | ||
| end | ||
| add_root(path.directory(path.directory(idir))) | ||
| local xlh = os.getenv("XLINGS_HOME") | ||
| if xlh and xlh ~= "" then | ||
| add_root(path.join(xlh, "data", "xpkgs")) | ||
| end | ||
|
|
||
| local from_store = {} | ||
| -- os.files/os.dirs are NOT in the xpm sandbox (install hook died on | ||
| -- exactly that); glob through the shell instead. One match per line, | ||
| -- no-match expands to an ls error that stderr's redirect swallows. | ||
| local function glob(pattern) | ||
| local out = {} | ||
| for line in os.iorun("sh -c 'ls -d " .. pattern .. " 2>/dev/null'"):gmatch("[^\n]+") do | ||
| table.insert(out, line) | ||
| end | ||
| return out | ||
| end | ||
| local function resolve(soname) | ||
| local in_view = path.join(subos_lib, soname) | ||
| if os.isfile(in_view) then | ||
| return in_view, false | ||
| end | ||
| for _, root in ipairs(store_roots) do | ||
| for _, hit in ipairs(glob(root .. "/*/*/lib/" .. soname)) do | ||
| if os.isfile(hit) then | ||
| return hit, true | ||
| end | ||
| end | ||
| end | ||
| return nil, false | ||
| end | ||
|
|
||
| -- Headers, view first then the store (same race as the sonames). | ||
| local subos_glib_inc = path.join(subos, "usr", "include", "glib-2.0") | ||
| local glib_inc = nil | ||
| if os.isdir(subos_glib_inc) then | ||
| glib_inc = subos_glib_inc | ||
| else | ||
| for _, root in ipairs(store_roots) do | ||
| local hits = glob(root .. "/xim-x-glib/*/include/glib-2.0") | ||
| if #hits > 0 then | ||
| glib_inc = hits[1] | ||
| break | ||
| end | ||
| end | ||
| end | ||
| if not glib_inc then | ||
| log.error("glib-2.0 headers found neither in this subos nor in the " | ||
| .. "xim store. They come from `xim:glib` (declared as a " | ||
| .. "runtime dep at the xpm level); if it is declared and " | ||
| .. "this still fires, the stack did not finish installing") | ||
| return false | ||
| end | ||
|
|
||
| -- COPY, not symlink. The subos view is project-local while this payload | ||
| -- is shared across projects: a symlink staged from the view dangles the | ||
| -- moment another project (or a wiped .mcpp/) is the one that builds — | ||
| -- observed as `gio/gio.h file not found` on a shared payload whose | ||
| -- staged link pointed into a deleted project view. The payload dir is | ||
| -- version-immutable and already on the consumer's RPATH, so copies are | ||
| -- also the stable indirection the glx-runtime note wants; a glib bump | ||
| -- simply rides the next eui-neo version. | ||
| os.tryrm(path.join(geninc, "glib-2.0")) | ||
| os.exec("cp -rL '" .. glib_inc .. "' '" .. geninc .. "'") | ||
|
|
||
| local genlib = path.join(gendir, "lib") | ||
| os.mkdir(genlib) | ||
| local function stage(soname, src) | ||
| os.exec("cp -L '" .. src .. "' '" .. path.join(genlib, soname) .. "'") | ||
| end | ||
|
|
||
| local missing = {} | ||
| for _, soname in ipairs(subos_sonames) do | ||
| local src, store_side = resolve(soname) | ||
| if src then | ||
| stage(soname, src) | ||
| if store_side then | ||
| table.insert(from_store, soname) | ||
| end | ||
| else | ||
| table.insert(missing, soname) | ||
| end | ||
| end | ||
| if #from_store > 0 then | ||
| log.warn("%s came from the xim store, bypassing a subos view that " | ||
| .. "had not published them yet (publish lists lag payloads — " | ||
| .. "libffi.so.8: openxlings/xim-pkgindex#676)", | ||
| table.concat(from_store, ", ")) | ||
| end | ||
| if #missing > 0 then | ||
| log.error("%s is in neither this subos nor the xim store — see the " | ||
| .. "header note about xim:glib", table.concat(missing, ", ")) | ||
| return false | ||
| end | ||
|
|
||
| -- The host-plane fallback. Prefer the view/store for these too (a future | ||
| -- xim provider lands there without a descriptor change); only when both | ||
| -- have nothing do the host dirs get searched, loudly. | ||
| local from_host = {} | ||
| for _, soname in ipairs(host_fallback_sonames) do | ||
| local src = resolve(soname) | ||
| if not src then | ||
| for _, dir in ipairs(host_lib_dirs) do | ||
| local cand = path.join(dir, soname) | ||
| if os.isfile(cand) then | ||
| src = cand | ||
| break | ||
| end | ||
| end | ||
| end | ||
| if src then | ||
| stage(soname, src) | ||
| local host_origin = false | ||
| for _, dir in ipairs(host_lib_dirs) do | ||
| if src:sub(1, #dir) == dir then | ||
| host_origin = true | ||
| break | ||
| end | ||
| end | ||
| if host_origin then | ||
| table.insert(from_host, soname) | ||
| end | ||
| else | ||
| table.insert(missing, soname) | ||
| end | ||
| end | ||
| if #from_host > 0 then | ||
| log.warn("%s staged from the HOST: no xim package provides them yet " | ||
| .. "(xim:glib links libmount/libselinux; util-linux and " | ||
| .. "libselinux are not packaged). Built against the host's " | ||
| .. "glibc, they are the mcpp#352 configuration the day that " | ||
| .. "glibc overtakes the payload's", table.concat(from_host, ", ")) | ||
| end | ||
|
|
||
| -- Versioned-symbol coherence: a HOST libselinux references pcre2 | ||
| -- symbols WITH version tags (PCRE2_10.xx), and a versioned reference | ||
| -- cannot bind to the xim pcre2's unversioned definitions — GNU ld | ||
| -- hard-errors at link time, lld lets it through to a runtime warning. | ||
| -- The reverse direction is fine (unversioned refs bind to versioned | ||
| -- defs), so when libselinux came from the host, pcre2 must too: | ||
| -- overwrite the xim-staged copy with the host's, which satisfies | ||
| -- both sides. Ubuntu and Fedora both ship libpcre2-8-0 by default. | ||
| local selinux_from_host = false | ||
| for _, soname in ipairs(from_host) do | ||
| if soname == "libselinux.so.1" then | ||
| selinux_from_host = true | ||
| break | ||
| end | ||
| end | ||
| if selinux_from_host then | ||
| local host_pcre = nil | ||
| for _, dir in ipairs(host_lib_dirs) do | ||
| local cand = path.join(dir, "libpcre2-8.so.0") | ||
| if os.isfile(cand) then | ||
| host_pcre = cand | ||
| break | ||
| end | ||
| end | ||
| if host_pcre then | ||
| stage("libpcre2-8.so.0", host_pcre) | ||
| else | ||
| log.warn("libselinux came from the host but libpcre2-8.so.0 did " | ||
| .. "not: the xim pcre2's unversioned symbols cannot " | ||
| .. "satisfy the host libselinux, and GNU ld will fail " | ||
| .. "the final link") | ||
| end | ||
| end | ||
| if #missing > 0 then | ||
| log.error("%s found neither in this subos, the xim store, nor on " | ||
| .. "the host", table.concat(missing, ", ")) | ||
| return false | ||
| end | ||
| return true | ||
| end | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
为什么要走二进制依赖呢?而不是走 compat.glib
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
因为 GLib 在这个项目中属于运行时系统库,不是普通的“把源码编进当前项目”的兼容库,所以选择 xim:glib 二进制依赖是有意的。
两种包的职责不同
compat.glib
如果走 compat.glib,它通常意味着:
这比较适合:
但 GLib 并不是这种形态。它包含多个相互关联的动
libglib-2.0.so
libgobject-2.0.so
libgmodule-2.0.so
libgio-2.0.so
libgthread-2.0.so
并且 GIO 还涉及运行时模块、GDBus、动态加载和系
xim:glib
xim:glib 是预构建运行时包,负责:
EUI-NEO 本身只是使用 GLib:
#include <gio/gio.h>
它不应该拥有或重新构建 GLib。它只需要:
deps = { runtime = { "xim:glib@2.80.0" } }
然后链接:
-lglib-2.0
-lgio-2.0
-lgobject-2.0
为什么不能简单把 GLib 源码做成 compat 包
主要有四个问题。
EUI 的六个测试成员都会各自触发 compat.glib 的 他包也可能各自带一份 GLib,浪费大量时间和空间。
GIO 依赖 GObject、GModule、GLib,并且还依赖外 码库会把“源码编译”问题变成:
GLib 构建配置
这已经是系统运行时打包问题,而不是 compat 源码
当前问题正是 GLib 的运行时 closure:
libgio-2.0.so
├── libglib-2.0.so
├── libgobject-2.0.so
├── libffi.so.8
├── libz.so.1
├── libmount.so.1
└── libselinux.so.1
这些库必须来自同一个可控的预构建依赖图。使用 决这些运行时库的版本一致性。
维护者给出的规则也是:
GLib 属于第二类,不属于 compat。
这次 CI 暴露的真正问题
不是“应该改成 compat.glib”,而是原来的 xim:glib 发布不完整:
-lglib-2.0
-lgio-2.0
-lgobject-2.0
所以正确路线仍是:
EUI-NEO
→ xim:glib
→ xim:glibc
→ xim:libffi
→ xim:zlib
→ xim:pcre2
而不是:
EUI-NEO
→ compat.glib
一句话总结:
▎ compat.glib 是“每个项目自己编译一份源码库” 可复用、可验证、带完整 ABI/runtime closure 的
▎ GLib”。EUI-NEO 应该使用后者。