Skip to content

Commit 378ad36

Browse files
authored
Add X11-backed compat runtime packages
Add Linux X11/XCB/X extension compat runtime packages and smoke coverage. Also align hook tool dependencies with mcpp 0.0.40 project-index support and isolate compat smoke tests from stale local package/index caches.
1 parent 2fd70f5 commit 378ad36

29 files changed

Lines changed: 2365 additions & 49 deletions

.github/workflows/validate.yml

Lines changed: 34 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ name: validate
22

33
on:
44
pull_request:
5-
paths: ["pkgs/**/*.lua", ".github/workflows/validate.yml"]
5+
paths: ["pkgs/**/*.lua", "tests/**", "README.md", ".github/workflows/validate.yml"]
66
push:
77
branches: [main]
88

@@ -17,18 +17,13 @@ jobs:
1717
run: |
1818
fail=0
1919
for f in pkgs/*/*.lua; do
20-
# 1. Forbidden install hook (security: descriptors must not run code)
21-
if grep -q "^function install" "$f"; then
22-
echo "::error file=$f::install hook is forbidden"
23-
fail=1
24-
fi
25-
# 2. Lua syntax check — load (= compile) without executing.
20+
# 1. Lua syntax check — load (= compile) without executing.
2621
# `loadfile(name, 't')` rejects bytecode and parses text only.
2722
if ! lua5.4 -e "assert(loadfile('$f', 't'))" >/dev/null 2>&1; then
2823
echo "::error file=$f::lua syntax error"
2924
fail=1
3025
fi
31-
# 3. xpkg V1 baseline: the file has to populate `package = { ... }`
26+
# 2. xpkg V1 baseline: the file has to populate `package = { ... }`
3227
# with at least `spec`, `name`, and an `xpm` table. Form A vs
3328
# Form B (mcpp = "<path>" / mcpp = { ... }) is descriptor-author
3429
# choice and not enforced here.
@@ -38,6 +33,37 @@ jobs:
3833
fail=1
3934
fi
4035
done
36+
# 3. Package version identifiers and dependency versions should be
37+
# bare versions ("1.2.3"), not upstream tag names ("v1.2.3").
38+
# Download URLs may still contain refs/tags/v* when upstream
39+
# uses that tag spelling.
40+
if grep -nE '\["v[0-9]+|\["[^"]+"\][[:space:]]*=[[:space:]]*"v[0-9]+' "$f"; then
41+
echo "::error file=$f::version identifiers must not use a leading v"
42+
fail=1
43+
fi
4144
done
4245
[ $fail -eq 0 ] && echo "All package files valid."
4346
exit $fail
47+
48+
smoke-linux:
49+
runs-on: ubuntu-latest
50+
steps:
51+
- uses: actions/checkout@v4
52+
- name: Download mcpp
53+
env:
54+
MCPP_VERSION: "0.0.40"
55+
run: |
56+
curl -L -fsS -o mcpp.tar.gz \
57+
"https://github.com/mcpp-community/mcpp/releases/download/v${MCPP_VERSION}/mcpp-${MCPP_VERSION}-linux-x86_64.tar.gz"
58+
tar -xzf mcpp.tar.gz
59+
root="$PWD/mcpp-${MCPP_VERSION}-linux-x86_64"
60+
echo "MCPP=$root/bin/mcpp" >> "$GITHUB_ENV"
61+
echo "MCPP_VENDORED_XLINGS=$root/registry/bin/xlings" >> "$GITHUB_ENV"
62+
echo "$root/bin" >> "$GITHUB_PATH"
63+
- name: Run compat smoke tests
64+
run: |
65+
"$MCPP" --version
66+
timeout 1800 bash tests/smoke_compat_core.sh
67+
timeout 1800 bash tests/smoke_compat_imgui.sh
68+
timeout 1800 bash tests/smoke_compat_archive.sh
69+
timeout 1800 bash tests/smoke_compat_imgui_window.sh

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
.xlings-index-cache.json

README.md

Lines changed: 78 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -29,16 +29,31 @@ mcpp build # 自动拉取源码 + 构建
2929
| 包名 | 版本 | 简介 |
3030
|------|------|------|
3131
| `ftxui` | 6.1.9 | C++ 函数式终端 UI 库(screen + dom + component) |
32-
| `glfw` | 3.4 | GLFW 窗口与输入库(null platform 后端源码构建) |
32+
| `glfw` | 3.4 | GLFW 窗口与输入库(X11/null 后端源码构建) |
3333
| `gtest` | 1.15.2 | Google Test 测试框架 |
34-
| `imgui` | v1.92.8 | Dear ImGui immediate-mode GUI 核心源码 |
34+
| `imgui` | 1.92.8 | Dear ImGui immediate-mode GUI 核心源码 |
3535
| `opengl` | 2026.05.31 | Khronos OpenGL API 头文件 |
36+
| `khrplatform` | 2026.05.31 | Khronos KHR platform 头文件 |
37+
| `xorgproto` | 2025.1 | X.Org protocol 头文件 |
38+
| `xtrans` | 1.6.0 | X.Org transport support headers/source snippets |
39+
| `xau` | 1.0.12 | X authorization runtime library(`libXau.so`) |
40+
| `xdmcp` | 1.1.5 | X Display Manager Control Protocol runtime library(`libXdmcp.so`) |
41+
| `xcb-proto` | 1.17.0 | XCB protocol XML definitions and generator metadata |
42+
| `xcb` | 1.17.0 | X C Binding runtime library(`libxcb.so`) |
43+
| `x11` | 1.8.13 | Xlib runtime library(`libX11.so`) and public headers |
44+
| `xcursor` | 1.2.3 | Xcursor runtime library(`libXcursor.so`) and public headers |
45+
| `xext` | 1.3.7 | Xext runtime library(`libXext.so`) and public headers |
46+
| `xfixes` | 6.0.2 | Xfixes runtime library(`libXfixes.so`) and public headers |
47+
| `xi` | 1.8.3 | XInput runtime library(`libXi.so`) and public headers |
48+
| `xinerama` | 1.1.6 | Xinerama runtime library(`libXinerama.so`) and public headers |
49+
| `xrandr` | 1.5.5 | Xrandr runtime library(`libXrandr.so`) and public headers |
50+
| `xrender` | 0.9.12 | Xrender runtime library(`libXrender.so`) and public headers |
3651
| `mbedtls` | 3.6.1 | TLS/加密库(纯 C) |
3752
| `lua` | 5.4.7 | Lua 脚本语言(纯 C 嵌入式库) |
38-
| `zlib` | v1.3.2 | DEFLATE 压缩库 |
53+
| `zlib` | 1.3.2 | DEFLATE 压缩库 |
3954
| `bzip2` | 1.0.8 | bzip2 压缩库 |
40-
| `lz4` | v1.10.0 | LZ4 压缩库 |
41-
| `zstd` | v1.5.7 | Zstandard 压缩库 |
55+
| `lz4` | 1.10.0 | LZ4 压缩库 |
56+
| `zstd` | 1.5.7 | Zstandard 压缩库 |
4257
| `xz` | 5.8.3 | XZ Utils liblzma 压缩库 |
4358
| `libarchive` | 3.8.7 | 多格式归档与压缩库 |
4459

@@ -61,11 +76,68 @@ libarchive
6176
└── xz ← 压缩后端自动传递
6277
6378
glfw
64-
└── opengl ← GLFW/glfw3.h 所需 OpenGL 头文件
79+
├── opengl
80+
│ └── khrplatform ← GLFW/glfw3.h 所需 OpenGL/KHR 头文件
81+
└── x11 / xcursor / xext / xfixes / xi
82+
/ xinerama / xorgproto / xrandr / xrender
83+
← GLFW Linux X11 后端所需 runtime/header 闭包
84+
85+
xau / xdmcp
86+
└── xorgproto ← X11 底层 runtime 库的协议头文件
87+
88+
xcb
89+
├── xcb-proto ← hook 内生成 xcb 协议源文件
90+
├── xau
91+
└── xdmcp
92+
93+
x11
94+
├── xcb
95+
├── xorgproto
96+
└── xtrans ← Xlib/XIM transport 源码片段
6597
```
6698

6799
mcpp 0.0.3+ 的 transitive walker 自动沿链路传播头文件和依赖,消费者只需声明直接依赖。
68100

101+
> 当前 X11/XCB/Xau/Xdmcp 以及 GLFW 需要的 Xcursor/Xext/Xfixes/Xi/Xinerama/
102+
> Xrandr/Xrender 都已按上游源码提供 runtime `.so``compat.glfw` 仍沿用
103+
> GLFW 上游的 GLX/OpenGL 动态加载行为,窗口运行时需要宿主环境提供可用的
104+
> X server/GLX/OpenGL 驱动。
105+
106+
### 本地 smoke 验证
107+
108+
```bash
109+
MCPP=/path/to/mcpp tests/smoke_compat_core.sh
110+
MCPP=/path/to/mcpp tests/smoke_compat_imgui.sh
111+
MCPP=/path/to/mcpp tests/smoke_compat_archive.sh
112+
```
113+
114+
该脚本会通过当前 checkout 作为本地 path index 创建临时 mcpp 项目,验证:
115+
116+
- `compat.gtest`/`compat.ftxui`/`compat.lua`/`compat.mbedtls` 能用上游
117+
`#include <...>` API 构建并运行最小用例
118+
- `compat.opengl`/`compat.khrplatform` 能提供 GLFW/OpenGL 常见头文件闭包
119+
- `compat.imgui@1.92.8` core 能构建并运行一个 headless ImGui frame
120+
- `compat.glfw@3.4` 能构建、运行 `glfwInit()` smoke,并链接 X11 扩展 runtime `.so`
121+
- `compat.xau@1.0.12`/`compat.xdmcp@1.1.5` 能构建、运行并链接 runtime `.so`
122+
- `compat.xcb@1.17.0` 能构建、运行并链接 `libxcb.so`
123+
- `compat.x11@1.8.13` 能构建、运行并链接 `libX11.so``libxcb.so`
124+
- `compat.xcursor`/`compat.xext`/`compat.xfixes`/`compat.xi`/`compat.xinerama`/
125+
`compat.xrandr`/`compat.xrender` 能构建、运行并链接对应 `libX*.so`
126+
- `compat.libarchive` 能连同 `zlib`/`bzip2`/`lz4`/`zstd`/`xz` 压缩后端构建并运行
127+
128+
有窗口的 ImGui + GLFW + OpenGL demo 单独放在可选 smoke 中:
129+
130+
```bash
131+
MCPP=/path/to/mcpp tests/smoke_compat_imgui_window.sh
132+
MCPP=/path/to/mcpp MCPP_INDEX_RUN_WINDOW_SMOKE=1 tests/smoke_compat_imgui_window.sh
133+
```
134+
135+
默认只验证 demo 构建和 X11 runtime 链接闭包。显式设置
136+
`MCPP_INDEX_RUN_WINDOW_SMOKE=1` 后才会运行隐藏窗口帧渲染,此时需要当前
137+
`DISPLAY` 可用,并且宿主机提供 GLVND/GLX/OpenGL 驱动 runtime。脚本会把
138+
宿主 GL runtime 和 compat X11 runtime 组装到临时 `LD_LIBRARY_PATH` 中,
139+
避免系统 X11 库覆盖 mcpp 构建出的 `libX11.so`/`libxcb.so`
140+
69141
## 包描述文件
70142

71143
每个包对应一个 `pkgs/<首字母>/<包名>.lua` 文件,遵循 [xpkg V1 规范](https://github.com/d2learn/xim-pkgindex/blob/main/docs/V1/xpackage-spec.md)

pkgs/c/compat.glfw.lua

Lines changed: 118 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ package = {
22
spec = "1",
33
namespace = "compat",
44
name = "compat.glfw",
5-
description = "GLFW windowing and input library built from source with the null platform backend",
5+
description = "GLFW windowing and input library built from upstream sources",
66
licenses = {"Zlib"},
77
repo = "https://github.com/glfw/glfw",
88
type = "package",
@@ -14,35 +14,134 @@ package = {
1414
sha256 = "c038d34200234d071fae9345bc455e4a8f2f544ab60150765d7704e08f3dac01",
1515
},
1616
},
17+
macosx = {
18+
["3.4"] = {
19+
url = "https://github.com/glfw/glfw/archive/refs/tags/3.4.tar.gz",
20+
sha256 = "c038d34200234d071fae9345bc455e4a8f2f544ab60150765d7704e08f3dac01",
21+
},
22+
},
23+
windows = {
24+
["3.4"] = {
25+
url = "https://github.com/glfw/glfw/archive/refs/tags/3.4.tar.gz",
26+
sha256 = "c038d34200234d071fae9345bc455e4a8f2f544ab60150765d7704e08f3dac01",
27+
},
28+
},
1729
},
1830

1931
mcpp = {
2032
language = "c++23",
2133
import_std = false,
2234
c_standard = "c11",
23-
cflags = { "-D_DEFAULT_SOURCE" },
24-
include_dirs = {"*/include", "*/src"},
35+
include_dirs = {"include", "src"},
2536
sources = {
26-
"*/src/context.c",
27-
"*/src/init.c",
28-
"*/src/input.c",
29-
"*/src/monitor.c",
30-
"*/src/platform.c",
31-
"*/src/vulkan.c",
32-
"*/src/window.c",
33-
"*/src/egl_context.c",
34-
"*/src/osmesa_context.c",
35-
"*/src/null_init.c",
36-
"*/src/null_monitor.c",
37-
"*/src/null_window.c",
38-
"*/src/null_joystick.c",
39-
"*/src/posix_time.c",
40-
"*/src/posix_thread.c",
41-
"*/src/posix_module.c",
37+
"src/context.c",
38+
"src/init.c",
39+
"src/input.c",
40+
"src/monitor.c",
41+
"src/platform.c",
42+
"src/vulkan.c",
43+
"src/window.c",
44+
"src/egl_context.c",
45+
"src/osmesa_context.c",
46+
"src/null_init.c",
47+
"src/null_monitor.c",
48+
"src/null_window.c",
49+
"src/null_joystick.c",
4250
},
4351
targets = { ["glfw"] = { kind = "lib" } },
4452
deps = {
4553
["compat.opengl"] = "2026.05.31",
4654
},
55+
linux = {
56+
cflags = { "-D_DEFAULT_SOURCE", "-D_GLFW_X11" },
57+
sources = {
58+
"src/x11_init.c",
59+
"src/x11_monitor.c",
60+
"src/x11_window.c",
61+
"src/xkb_unicode.c",
62+
"src/glx_context.c",
63+
"src/linux_joystick.c",
64+
"src/posix_poll.c",
65+
"src/posix_time.c",
66+
"src/posix_thread.c",
67+
"src/posix_module.c",
68+
},
69+
deps = {
70+
["compat.x11"] = "1.8.13",
71+
["compat.xcursor"] = "1.2.3",
72+
["compat.xext"] = "1.3.7",
73+
["compat.xfixes"] = "6.0.2",
74+
["compat.xi"] = "1.8.3",
75+
["compat.xinerama"] = "1.1.6",
76+
["compat.xorgproto"] = "2025.1",
77+
["compat.xrandr"] = "1.5.5",
78+
["compat.xrender"] = "0.9.12",
79+
},
80+
},
81+
macosx = {
82+
cflags = { "-D_GLFW_COCOA" },
83+
sources = {
84+
"src/cocoa_time.c",
85+
"src/posix_thread.c",
86+
"src/posix_module.c",
87+
"src/cocoa_init.m",
88+
"src/cocoa_joystick.m",
89+
"src/cocoa_monitor.m",
90+
"src/cocoa_window.m",
91+
"src/nsgl_context.m",
92+
},
93+
ldflags = {
94+
"-framework", "Cocoa",
95+
"-framework", "IOKit",
96+
"-framework", "CoreFoundation",
97+
},
98+
},
99+
windows = {
100+
cflags = { "-D_GLFW_WIN32", "-DUNICODE", "-D_UNICODE" },
101+
sources = {
102+
"src/win32_time.c",
103+
"src/win32_thread.c",
104+
"src/win32_module.c",
105+
"src/win32_init.c",
106+
"src/win32_joystick.c",
107+
"src/win32_monitor.c",
108+
"src/win32_window.c",
109+
"src/wgl_context.c",
110+
},
111+
ldflags = { "-lgdi32" },
112+
},
47113
},
48114
}
115+
116+
import("xim.libxpkg.pkginfo")
117+
118+
local function patch_x11_loader_names(root)
119+
local file = path.join(root, "src", "x11_init.c")
120+
local data = io.readfile(file)
121+
local replacements = {
122+
['"libX11.so.6"'] = '"libX11.so"',
123+
['"libXi.so.6"'] = '"libXi.so"',
124+
['"libXrandr.so.2"'] = '"libXrandr.so"',
125+
['"libXcursor.so.1"'] = '"libXcursor.so"',
126+
['"libXinerama.so.1"'] = '"libXinerama.so"',
127+
['"libX11-xcb.so.1"'] = '"libX11-xcb.so"',
128+
['"libXrender.so.1"'] = '"libXrender.so"',
129+
['"libXext.so.6"'] = '"libXext.so"',
130+
}
131+
for from, to in pairs(replacements) do
132+
data = data:gsub(from, to)
133+
end
134+
io.writefile(file, data)
135+
end
136+
137+
function install()
138+
local srcdir = pkginfo.install_file():replace(".tar.gz", "")
139+
if not os.isdir(srcdir) then
140+
srcdir = "glfw-" .. pkginfo.version()
141+
end
142+
143+
os.tryrm(pkginfo.install_dir())
144+
os.mv(srcdir, pkginfo.install_dir())
145+
patch_x11_loader_names(pkginfo.install_dir())
146+
return true
147+
end

pkgs/c/compat.imgui.lua

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,19 +9,19 @@ package = {
99

1010
xpm = {
1111
linux = {
12-
["v1.92.8"] = {
12+
["1.92.8"] = {
1313
url = "https://github.com/ocornut/imgui/archive/refs/tags/v1.92.8.tar.gz",
1414
sha256 = "fecb33d33930e12ff53a34064e9d3a06c8f7c3e04408f14cd36c80e3faac863b",
1515
},
1616
},
1717
macosx = {
18-
["v1.92.8"] = {
18+
["1.92.8"] = {
1919
url = "https://github.com/ocornut/imgui/archive/refs/tags/v1.92.8.tar.gz",
2020
sha256 = "fecb33d33930e12ff53a34064e9d3a06c8f7c3e04408f14cd36c80e3faac863b",
2121
},
2222
},
2323
windows = {
24-
["v1.92.8"] = {
24+
["1.92.8"] = {
2525
url = "https://github.com/ocornut/imgui/archive/refs/tags/v1.92.8.tar.gz",
2626
sha256 = "fecb33d33930e12ff53a34064e9d3a06c8f7c3e04408f14cd36c80e3faac863b",
2727
},

0 commit comments

Comments
 (0)