From 4a4be206e177a009e22fad9b90358ac7fbcb6ef8 Mon Sep 17 00:00:00 2001 From: sunrisepeak Date: Mon, 1 Jun 2026 05:45:50 +0800 Subject: [PATCH 1/4] feat: add X11-backed compat runtime packages --- .github/workflows/validate.yml | 39 +- README.md | 84 +++- pkgs/c/compat.glfw.lua | 109 ++++- pkgs/c/compat.imgui.lua | 6 +- pkgs/c/compat.khrplatform.lua | 43 ++ pkgs/c/compat.libarchive.lua | 6 +- pkgs/c/compat.lz4.lua | 6 +- pkgs/c/compat.opengl.lua | 4 +- pkgs/c/compat.x11.lua | 684 +++++++++++++++++++++++++++++ pkgs/c/compat.xau.lua | 40 ++ pkgs/c/compat.xcb-proto.lua | 43 ++ pkgs/c/compat.xcb.lua | 155 +++++++ pkgs/c/compat.xcursor.lua | 34 ++ pkgs/c/compat.xdmcp.lua | 40 ++ pkgs/c/compat.xext.lua | 32 ++ pkgs/c/compat.xfixes.lua | 33 ++ pkgs/c/compat.xi.lua | 37 ++ pkgs/c/compat.xinerama.lua | 33 ++ pkgs/c/compat.xorgproto.lua | 32 ++ pkgs/c/compat.xrandr.lua | 34 ++ pkgs/c/compat.xrender.lua | 32 ++ pkgs/c/compat.xtrans.lua | 62 +++ pkgs/c/compat.zlib.lua | 6 +- pkgs/c/compat.zstd.lua | 6 +- tests/smoke_compat_archive.sh | 105 +++++ tests/smoke_compat_core.sh | 150 +++++++ tests/smoke_compat_imgui.sh | 260 +++++++++++ tests/smoke_compat_imgui_window.sh | 258 +++++++++++ 28 files changed, 2338 insertions(+), 35 deletions(-) create mode 100644 pkgs/c/compat.khrplatform.lua create mode 100644 pkgs/c/compat.x11.lua create mode 100644 pkgs/c/compat.xau.lua create mode 100644 pkgs/c/compat.xcb-proto.lua create mode 100644 pkgs/c/compat.xcb.lua create mode 100644 pkgs/c/compat.xcursor.lua create mode 100644 pkgs/c/compat.xdmcp.lua create mode 100644 pkgs/c/compat.xext.lua create mode 100644 pkgs/c/compat.xfixes.lua create mode 100644 pkgs/c/compat.xi.lua create mode 100644 pkgs/c/compat.xinerama.lua create mode 100644 pkgs/c/compat.xorgproto.lua create mode 100644 pkgs/c/compat.xrandr.lua create mode 100644 pkgs/c/compat.xrender.lua create mode 100644 pkgs/c/compat.xtrans.lua create mode 100755 tests/smoke_compat_archive.sh create mode 100755 tests/smoke_compat_core.sh create mode 100755 tests/smoke_compat_imgui.sh create mode 100755 tests/smoke_compat_imgui_window.sh diff --git a/.github/workflows/validate.yml b/.github/workflows/validate.yml index 0378b9f..7d4d9da 100644 --- a/.github/workflows/validate.yml +++ b/.github/workflows/validate.yml @@ -2,7 +2,7 @@ name: validate on: pull_request: - paths: ["pkgs/**/*.lua", ".github/workflows/validate.yml"] + paths: ["pkgs/**/*.lua", "tests/**", "README.md", ".github/workflows/validate.yml"] push: branches: [main] @@ -17,18 +17,13 @@ jobs: run: | fail=0 for f in pkgs/*/*.lua; do - # 1. Forbidden install hook (security: descriptors must not run code) - if grep -q "^function install" "$f"; then - echo "::error file=$f::install hook is forbidden" - fail=1 - fi - # 2. Lua syntax check — load (= compile) without executing. + # 1. Lua syntax check — load (= compile) without executing. # `loadfile(name, 't')` rejects bytecode and parses text only. if ! lua5.4 -e "assert(loadfile('$f', 't'))" >/dev/null 2>&1; then echo "::error file=$f::lua syntax error" fail=1 fi - # 3. xpkg V1 baseline: the file has to populate `package = { ... }` + # 2. xpkg V1 baseline: the file has to populate `package = { ... }` # with at least `spec`, `name`, and an `xpm` table. Form A vs # Form B (mcpp = "" / mcpp = { ... }) is descriptor-author # choice and not enforced here. @@ -38,6 +33,34 @@ jobs: fail=1 fi done + # 3. Package version identifiers and dependency versions should be + # bare versions ("1.2.3"), not upstream tag names ("v1.2.3"). + # Download URLs may still contain refs/tags/v* when upstream + # uses that tag spelling. + if grep -nE '\["v[0-9]+|\["[^"]+"\][[:space:]]*=[[:space:]]*"v[0-9]+' "$f"; then + echo "::error file=$f::version identifiers must not use a leading v" + fail=1 + fi done [ $fail -eq 0 ] && echo "All package files valid." exit $fail + + smoke-linux: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Download mcpp + env: + MCPP_VERSION: "0.0.38" + run: | + curl -L -fsS -o mcpp.tar.gz \ + "https://github.com/mcpp-community/mcpp/releases/download/v${MCPP_VERSION}/mcpp-${MCPP_VERSION}-linux-x86_64.tar.gz" + tar -xzf mcpp.tar.gz + echo "$PWD/mcpp-${MCPP_VERSION}-linux-x86_64/bin" >> "$GITHUB_PATH" + - name: Run compat smoke tests + run: | + mcpp --version + timeout 1800 bash tests/smoke_compat_core.sh + timeout 1800 bash tests/smoke_compat_imgui.sh + timeout 1800 bash tests/smoke_compat_archive.sh + timeout 1800 bash tests/smoke_compat_imgui_window.sh diff --git a/README.md b/README.md index 0a65a90..034bd63 100644 --- a/README.md +++ b/README.md @@ -29,16 +29,31 @@ mcpp build # 自动拉取源码 + 构建 | 包名 | 版本 | 简介 | |------|------|------| | `ftxui` | 6.1.9 | C++ 函数式终端 UI 库(screen + dom + component) | -| `glfw` | 3.4 | GLFW 窗口与输入库(null platform 后端源码构建) | +| `glfw` | 3.4 | GLFW 窗口与输入库(X11/null 后端源码构建) | | `gtest` | 1.15.2 | Google Test 测试框架 | -| `imgui` | v1.92.8 | Dear ImGui immediate-mode GUI 核心源码 | +| `imgui` | 1.92.8 | Dear ImGui immediate-mode GUI 核心源码 | | `opengl` | 2026.05.31 | Khronos OpenGL API 头文件 | +| `khrplatform` | 2026.05.31 | Khronos KHR platform 头文件 | +| `xorgproto` | 2025.1 | X.Org protocol 头文件 | +| `xtrans` | 1.6.0 | X.Org transport support headers/source snippets | +| `xau` | 1.0.12 | X authorization runtime library(`libXau.so`) | +| `xdmcp` | 1.1.5 | X Display Manager Control Protocol runtime library(`libXdmcp.so`) | +| `xcb-proto` | 1.17.0 | XCB protocol XML definitions and generator metadata | +| `xcb` | 1.17.0 | X C Binding runtime library(`libxcb.so`) | +| `x11` | 1.8.13 | Xlib runtime library(`libX11.so`) and public headers | +| `xcursor` | 1.2.3 | Xcursor runtime library(`libXcursor.so`) and public headers | +| `xext` | 1.3.7 | Xext runtime library(`libXext.so`) and public headers | +| `xfixes` | 6.0.2 | Xfixes runtime library(`libXfixes.so`) and public headers | +| `xi` | 1.8.3 | XInput runtime library(`libXi.so`) and public headers | +| `xinerama` | 1.1.6 | Xinerama runtime library(`libXinerama.so`) and public headers | +| `xrandr` | 1.5.5 | Xrandr runtime library(`libXrandr.so`) and public headers | +| `xrender` | 0.9.12 | Xrender runtime library(`libXrender.so`) and public headers | | `mbedtls` | 3.6.1 | TLS/加密库(纯 C) | | `lua` | 5.4.7 | Lua 脚本语言(纯 C 嵌入式库) | -| `zlib` | v1.3.2 | DEFLATE 压缩库 | +| `zlib` | 1.3.2 | DEFLATE 压缩库 | | `bzip2` | 1.0.8 | bzip2 压缩库 | -| `lz4` | v1.10.0 | LZ4 压缩库 | -| `zstd` | v1.5.7 | Zstandard 压缩库 | +| `lz4` | 1.10.0 | LZ4 压缩库 | +| `zstd` | 1.5.7 | Zstandard 压缩库 | | `xz` | 5.8.3 | XZ Utils liblzma 压缩库 | | `libarchive` | 3.8.7 | 多格式归档与压缩库 | @@ -61,11 +76,68 @@ libarchive └── xz ← 压缩后端自动传递 glfw - └── opengl ← GLFW/glfw3.h 所需 OpenGL 头文件 + ├── opengl + │ └── khrplatform ← GLFW/glfw3.h 所需 OpenGL/KHR 头文件 + └── x11 / xcursor / xext / xfixes / xi + / xinerama / xorgproto / xrandr / xrender + ← GLFW Linux X11 后端所需 runtime/header 闭包 + +xau / xdmcp + └── xorgproto ← X11 底层 runtime 库的协议头文件 + +xcb + ├── xcb-proto ← hook 内生成 xcb 协议源文件 + ├── xau + └── xdmcp + +x11 + ├── xcb + ├── xorgproto + └── xtrans ← Xlib/XIM transport 源码片段 ``` mcpp 0.0.3+ 的 transitive walker 自动沿链路传播头文件和依赖,消费者只需声明直接依赖。 +> 当前 X11/XCB/Xau/Xdmcp 以及 GLFW 需要的 Xcursor/Xext/Xfixes/Xi/Xinerama/ +> Xrandr/Xrender 都已按上游源码提供 runtime `.so`。`compat.glfw` 仍沿用 +> GLFW 上游的 GLX/OpenGL 动态加载行为,窗口运行时需要宿主环境提供可用的 +> X server/GLX/OpenGL 驱动。 + +### 本地 smoke 验证 + +```bash +MCPP=/path/to/mcpp tests/smoke_compat_core.sh +MCPP=/path/to/mcpp tests/smoke_compat_imgui.sh +MCPP=/path/to/mcpp tests/smoke_compat_archive.sh +``` + +该脚本会通过当前 checkout 作为本地 path index 创建临时 mcpp 项目,验证: + +- `compat.gtest`/`compat.ftxui`/`compat.lua`/`compat.mbedtls` 能用上游 + `#include <...>` API 构建并运行最小用例 +- `compat.opengl`/`compat.khrplatform` 能提供 GLFW/OpenGL 常见头文件闭包 +- `compat.imgui@1.92.8` core 能构建并运行一个 headless ImGui frame +- `compat.glfw@3.4` 能构建、运行 `glfwInit()` smoke,并链接 X11 扩展 runtime `.so` +- `compat.xau@1.0.12`/`compat.xdmcp@1.1.5` 能构建、运行并链接 runtime `.so` +- `compat.xcb@1.17.0` 能构建、运行并链接 `libxcb.so` +- `compat.x11@1.8.13` 能构建、运行并链接 `libX11.so` → `libxcb.so` +- `compat.xcursor`/`compat.xext`/`compat.xfixes`/`compat.xi`/`compat.xinerama`/ + `compat.xrandr`/`compat.xrender` 能构建、运行并链接对应 `libX*.so` +- `compat.libarchive` 能连同 `zlib`/`bzip2`/`lz4`/`zstd`/`xz` 压缩后端构建并运行 + +有窗口的 ImGui + GLFW + OpenGL demo 单独放在可选 smoke 中: + +```bash +MCPP=/path/to/mcpp tests/smoke_compat_imgui_window.sh +MCPP=/path/to/mcpp MCPP_INDEX_RUN_WINDOW_SMOKE=1 tests/smoke_compat_imgui_window.sh +``` + +默认只验证 demo 构建和 X11 runtime 链接闭包。显式设置 +`MCPP_INDEX_RUN_WINDOW_SMOKE=1` 后才会运行隐藏窗口帧渲染,此时需要当前 +`DISPLAY` 可用,并且宿主机提供 GLVND/GLX/OpenGL 驱动 runtime。脚本会把 +宿主 GL runtime 和 compat X11 runtime 组装到临时 `LD_LIBRARY_PATH` 中, +避免系统 X11 库覆盖 mcpp 构建出的 `libX11.so`/`libxcb.so`。 + ## 包描述文件 每个包对应一个 `pkgs/<首字母>/<包名>.lua` 文件,遵循 [xpkg V1 规范](https://github.com/d2learn/xim-pkgindex/blob/main/docs/V1/xpackage-spec.md)。 diff --git a/pkgs/c/compat.glfw.lua b/pkgs/c/compat.glfw.lua index 132fd63..e9271a3 100644 --- a/pkgs/c/compat.glfw.lua +++ b/pkgs/c/compat.glfw.lua @@ -2,7 +2,7 @@ package = { spec = "1", namespace = "compat", name = "compat.glfw", - description = "GLFW windowing and input library built from source with the null platform backend", + description = "GLFW windowing and input library built from upstream sources", licenses = {"Zlib"}, repo = "https://github.com/glfw/glfw", type = "package", @@ -14,13 +14,24 @@ package = { sha256 = "c038d34200234d071fae9345bc455e4a8f2f544ab60150765d7704e08f3dac01", }, }, + macosx = { + ["3.4"] = { + url = "https://github.com/glfw/glfw/archive/refs/tags/3.4.tar.gz", + sha256 = "c038d34200234d071fae9345bc455e4a8f2f544ab60150765d7704e08f3dac01", + }, + }, + windows = { + ["3.4"] = { + url = "https://github.com/glfw/glfw/archive/refs/tags/3.4.tar.gz", + sha256 = "c038d34200234d071fae9345bc455e4a8f2f544ab60150765d7704e08f3dac01", + }, + }, }, mcpp = { language = "c++23", import_std = false, c_standard = "c11", - cflags = { "-D_DEFAULT_SOURCE" }, include_dirs = {"*/include", "*/src"}, sources = { "*/src/context.c", @@ -36,13 +47,101 @@ package = { "*/src/null_monitor.c", "*/src/null_window.c", "*/src/null_joystick.c", - "*/src/posix_time.c", - "*/src/posix_thread.c", - "*/src/posix_module.c", }, targets = { ["glfw"] = { kind = "lib" } }, deps = { ["compat.opengl"] = "2026.05.31", }, + linux = { + cflags = { "-D_DEFAULT_SOURCE", "-D_GLFW_X11" }, + sources = { + "*/src/x11_init.c", + "*/src/x11_monitor.c", + "*/src/x11_window.c", + "*/src/xkb_unicode.c", + "*/src/glx_context.c", + "*/src/linux_joystick.c", + "*/src/posix_poll.c", + "*/src/posix_time.c", + "*/src/posix_thread.c", + "*/src/posix_module.c", + }, + deps = { + ["compat.x11"] = "1.8.13", + ["compat.xcursor"] = "1.2.3", + ["compat.xext"] = "1.3.7", + ["compat.xfixes"] = "6.0.2", + ["compat.xi"] = "1.8.3", + ["compat.xinerama"] = "1.1.6", + ["compat.xorgproto"] = "2025.1", + ["compat.xrandr"] = "1.5.5", + ["compat.xrender"] = "0.9.12", + }, + }, + macosx = { + cflags = { "-D_GLFW_COCOA" }, + sources = { + "*/src/cocoa_time.c", + "*/src/posix_thread.c", + "*/src/posix_module.c", + "*/src/cocoa_init.m", + "*/src/cocoa_joystick.m", + "*/src/cocoa_monitor.m", + "*/src/cocoa_window.m", + "*/src/nsgl_context.m", + }, + ldflags = { + "-framework", "Cocoa", + "-framework", "IOKit", + "-framework", "CoreFoundation", + }, + }, + windows = { + cflags = { "-D_GLFW_WIN32", "-DUNICODE", "-D_UNICODE" }, + sources = { + "*/src/win32_time.c", + "*/src/win32_thread.c", + "*/src/win32_module.c", + "*/src/win32_init.c", + "*/src/win32_joystick.c", + "*/src/win32_monitor.c", + "*/src/win32_window.c", + "*/src/wgl_context.c", + }, + ldflags = { "-lgdi32" }, + }, }, } + +import("xim.libxpkg.pkginfo") + +local function patch_x11_loader_names(root) + local file = path.join(root, "src", "x11_init.c") + local data = io.readfile(file) + local replacements = { + ['"libX11.so.6"'] = '"libX11.so"', + ['"libXi.so.6"'] = '"libXi.so"', + ['"libXrandr.so.2"'] = '"libXrandr.so"', + ['"libXcursor.so.1"'] = '"libXcursor.so"', + ['"libXinerama.so.1"'] = '"libXinerama.so"', + ['"libX11-xcb.so.1"'] = '"libX11-xcb.so"', + ['"libXrender.so.1"'] = '"libXrender.so"', + ['"libXext.so.6"'] = '"libXext.so"', + } + for from, to in pairs(replacements) do + data = data:gsub(from, to) + end + io.writefile(file, data) +end + +function install() + local srcdir = pkginfo.install_file():replace(".tar.gz", "") + if not os.isdir(srcdir) then + srcdir = "glfw-" .. pkginfo.version() + end + + os.tryrm(pkginfo.install_dir()) + os.mv(srcdir, pkginfo.install_dir()) + patch_x11_loader_names(pkginfo.install_dir()) + return true +end diff --git a/pkgs/c/compat.imgui.lua b/pkgs/c/compat.imgui.lua index b64ad81..7efc54f 100644 --- a/pkgs/c/compat.imgui.lua +++ b/pkgs/c/compat.imgui.lua @@ -9,19 +9,19 @@ package = { xpm = { linux = { - ["v1.92.8"] = { + ["1.92.8"] = { url = "https://github.com/ocornut/imgui/archive/refs/tags/v1.92.8.tar.gz", sha256 = "fecb33d33930e12ff53a34064e9d3a06c8f7c3e04408f14cd36c80e3faac863b", }, }, macosx = { - ["v1.92.8"] = { + ["1.92.8"] = { url = "https://github.com/ocornut/imgui/archive/refs/tags/v1.92.8.tar.gz", sha256 = "fecb33d33930e12ff53a34064e9d3a06c8f7c3e04408f14cd36c80e3faac863b", }, }, windows = { - ["v1.92.8"] = { + ["1.92.8"] = { url = "https://github.com/ocornut/imgui/archive/refs/tags/v1.92.8.tar.gz", sha256 = "fecb33d33930e12ff53a34064e9d3a06c8f7c3e04408f14cd36c80e3faac863b", }, diff --git a/pkgs/c/compat.khrplatform.lua b/pkgs/c/compat.khrplatform.lua new file mode 100644 index 0000000..cb58baa --- /dev/null +++ b/pkgs/c/compat.khrplatform.lua @@ -0,0 +1,43 @@ +package = { + spec = "1", + namespace = "compat", + name = "compat.khrplatform", + description = "Khronos KHR platform header for OpenGL/EGL compat packages", + licenses = {"MIT"}, + repo = "https://github.com/KhronosGroup/EGL-Registry", + type = "package", + + xpm = { + linux = { + ["2026.05.31"] = { + url = "https://github.com/KhronosGroup/EGL-Registry/archive/3d7796b3721d93976b6bfe536aa97bbc4bce8667.tar.gz", + sha256 = "f303c6a9248081e73c20a41fe9cc5b97c428bc0716286c5bb33551e65306015e", + }, + }, + macosx = { + ["2026.05.31"] = { + url = "https://github.com/KhronosGroup/EGL-Registry/archive/3d7796b3721d93976b6bfe536aa97bbc4bce8667.tar.gz", + sha256 = "f303c6a9248081e73c20a41fe9cc5b97c428bc0716286c5bb33551e65306015e", + }, + }, + windows = { + ["2026.05.31"] = { + url = "https://github.com/KhronosGroup/EGL-Registry/archive/3d7796b3721d93976b6bfe536aa97bbc4bce8667.tar.gz", + sha256 = "f303c6a9248081e73c20a41fe9cc5b97c428bc0716286c5bb33551e65306015e", + }, + }, + }, + + mcpp = { + language = "c++23", + import_std = false, + c_standard = "c11", + include_dirs = {"*/api"}, + generated_files = { + ["mcpp_generated/khrplatform_empty.c"] = "int mcpp_compat_khrplatform_headers_anchor(void) { return 0; }\n", + }, + sources = {"mcpp_generated/khrplatform_empty.c"}, + targets = { ["khrplatform"] = { kind = "lib" } }, + deps = {}, + }, +} diff --git a/pkgs/c/compat.libarchive.lua b/pkgs/c/compat.libarchive.lua index 92e29d0..780297c 100644 --- a/pkgs/c/compat.libarchive.lua +++ b/pkgs/c/compat.libarchive.lua @@ -173,10 +173,10 @@ package = { }, targets = { ["libarchive"] = { kind = "lib" } }, deps = { - ["compat.zlib"] = "v1.3.2", + ["compat.zlib"] = "1.3.2", ["compat.bzip2"] = "1.0.8", - ["compat.lz4"] = "v1.10.0", - ["compat.zstd"] = "v1.5.7", + ["compat.lz4"] = "1.10.0", + ["compat.zstd"] = "1.5.7", ["compat.xz"] = "5.8.3", }, }, diff --git a/pkgs/c/compat.lz4.lua b/pkgs/c/compat.lz4.lua index c0b0a06..007cd41 100644 --- a/pkgs/c/compat.lz4.lua +++ b/pkgs/c/compat.lz4.lua @@ -9,19 +9,19 @@ package = { xpm = { linux = { - ["v1.10.0"] = { + ["1.10.0"] = { url = "https://github.com/lz4/lz4/archive/refs/tags/v1.10.0.tar.gz", sha256 = "537512904744b35e232912055ccf8ec66d768639ff3abe5788d90d792ec5f48b", }, }, macosx = { - ["v1.10.0"] = { + ["1.10.0"] = { url = "https://github.com/lz4/lz4/archive/refs/tags/v1.10.0.tar.gz", sha256 = "537512904744b35e232912055ccf8ec66d768639ff3abe5788d90d792ec5f48b", }, }, windows = { - ["v1.10.0"] = { + ["1.10.0"] = { url = "https://github.com/lz4/lz4/archive/refs/tags/v1.10.0.tar.gz", sha256 = "537512904744b35e232912055ccf8ec66d768639ff3abe5788d90d792ec5f48b", }, diff --git a/pkgs/c/compat.opengl.lua b/pkgs/c/compat.opengl.lua index bbfcadd..64d68da 100644 --- a/pkgs/c/compat.opengl.lua +++ b/pkgs/c/compat.opengl.lua @@ -39,6 +39,8 @@ package = { }, sources = {"mcpp_generated/opengl_empty.c"}, targets = { ["opengl"] = { kind = "lib" } }, - deps = {}, + deps = { + ["compat.khrplatform"] = "2026.05.31", + }, }, } diff --git a/pkgs/c/compat.x11.lua b/pkgs/c/compat.x11.lua new file mode 100644 index 0000000..b83d71e --- /dev/null +++ b/pkgs/c/compat.x11.lua @@ -0,0 +1,684 @@ +package = { + spec = "1", + namespace = "compat", + name = "compat.x11", + description = "Xlib runtime library and public headers built from upstream sources", + licenses = {"MIT"}, + repo = "https://gitlab.freedesktop.org/xorg/lib/libx11", + type = "package", + + xpm = { + linux = { + deps = { + "compat:compat.xorgproto@2025.1", + }, + ["1.8.13"] = { + url = "https://xorg.freedesktop.org/releases/individual/lib/libX11-1.8.13.tar.gz", + sha256 = "acf0e7cd7541110e6330ecb539441a2d53061f386ec7be6906dfde0de2598470", + }, + }, + }, + + mcpp = { + language = "c++23", + import_std = false, + c_standard = "c11", + include_dirs = { + ".", + "include", + "include/X11", + "src", + "src/xcms", + "src/xkb", + "src/xlibi18n", + "modules/im/ximcp", + "modules/lc/def", + "modules/lc/gen", + "modules/lc/Utf8", + "modules/om/generic", + }, + cflags = { + "-D_GNU_SOURCE", + "-D_DEFAULT_SOURCE", + "-D_BSD_SOURCE", + "-DXIM_t=1", + "-DTRANS_CLIENT=1", + "-DHAVE_CONFIG_H", + }, + sources = { + "src/*.c", + "src/xcms/*.c", + "src/xkb/*.c", + "src/xlibi18n/*.c", + "!src/xlibi18n/XlcDL.c", + "!src/xlibi18n/XlcSL.c", + "modules/im/ximcp/*.c", + "modules/lc/def/*.c", + "modules/lc/gen/*.c", + "modules/lc/Utf8/*.c", + "modules/om/generic/*.c", + }, + targets = { ["X11"] = { kind = "shared" } }, + deps = { + ["compat.xcb"] = "1.17.0", + ["compat.xorgproto"] = "2025.1", + ["compat.xtrans"] = "1.6.0", + }, + }, +} + +import("xim.libxpkg.pkginfo") +import("xim.libxpkg.log") + +local makekeys_py = [=[ +import re +import sys + +KTNUM = 4000 +MIN_REHASH = 15 +MATCHES = 10 +XK_VOID_SYMBOL = 0xFFFFFF + +defs = [] + +def parse_line(line): + m = re.match(r"#define\s+(\S+)\s+0x([0-9a-fA-F]+)", line) + if m and "XK_" in m.group(1): + key = m.group(1) + i = key.find("XK_") + return key[:i] + key[i + 3:], int(m.group(2), 16) + + m = re.match(r"#define\s+(\S+)\s+_EVDEVK\(0x([0-9a-fA-F]+)\)", line) + if m and "XK_" in m.group(1): + key = m.group(1) + i = key.find("XK_") + return key[:i] + key[i + 3:], int(m.group(2), 16) + 0x10081000 + + m = re.match(r"#define\s+(\S+)\s+(\S+)", line) + if m and "XK_" in m.group(1) and "XK_" in m.group(2): + key = m.group(1) + alias = m.group(2) + i = key.find("XK_") + ai = alias.find("XK_") + name = key[:i] + key[i + 3:] + alias_name = alias[:ai] + alias[ai + 3:] + for old_name, old_value in reversed(defs): + if old_name == alias_name: + return name, old_value + return None + +for filename in sys.argv[1:]: + with open(filename, "r", encoding="utf-8", errors="ignore") as f: + for line in f: + parsed = parse_line(line) + if not parsed: + continue + name, value = parsed + if value == XK_VOID_SYMBOL: + value = 0 + if value > 0x1FFFFFFF: + continue + defs.append((name, value)) + +def signature(name): + sig = 0 + for ch in name: + sig = ((sig << 1) + ord(ch)) & 0xFFFFFFFF + return sig + +def find_hash_by_name(): + best_max = len(defs) + best_z = 0 + found = 0 + for z in range(len(defs), KTNUM): + used = [False] * z + max_rehash = 0 + ok = True + for name, _ in defs: + sig = signature(name) + first = j = sig % z + k = 0 + while used[j]: + k += 1 + j += first + 1 + if j >= z: + j -= z + if j == first: + ok = False + break + if not ok: + break + used[j] = True + max_rehash = max(max_rehash, k) + if ok and max_rehash < MIN_REHASH: + if max_rehash < best_max: + best_max = max_rehash + best_z = z + found += 1 + if found >= MATCHES: + break + return best_z, best_max + +def find_hash_by_value(): + best_max = len(defs) + best_z = 0 + found = 0 + for z in range(len(defs), KTNUM): + used = [False] * z + values = [None] * z + max_rehash = 0 + ok = True + for _, value in defs: + first = j = value % z + k = 0 + while used[j]: + if values[j] == value: + break + k += 1 + j += first + 1 + if j >= z: + j -= z + if j == first: + ok = False + break + if not ok: + break + used[j] = True + values[j] = value + max_rehash = max(max_rehash, k) + if ok and max_rehash < MIN_REHASH: + if max_rehash < best_max: + best_max = max_rehash + best_z = z + found += 1 + if found >= MATCHES: + break + return best_z, best_max + +def c_char(ch): + if ch == "'": + return "'\\''" + if ch == "\\": + return "'\\\\'" + return "'" + ch + "'" + +z, max_rehash = find_hash_by_name() +if not z: + raise SystemExit("makekeys: failed to find string hash") + +offsets = [0] * z +indexes = [0] * len(defs) +rows = [] +k = 1 +for i, (name, value) in enumerate(defs): + sig = signature(name) + first = j = sig % z + while offsets[j]: + j += first + 1 + if j >= z: + j -= z + offsets[j] = k + indexes[i] = k + row = [ + "0x%.2x" % ((sig >> 8) & 0xff), + "0x%.2x" % (sig & 0xff), + "0x%.2x" % ((value >> 24) & 0xff), + "0x%.2x" % ((value >> 16) & 0xff), + "0x%.2x" % ((value >> 8) & 0xff), + "0x%.2x" % (value & 0xff), + ] + row.extend(c_char(ch) for ch in name) + row.append("0") + rows.append(row) + k += 7 + len(name) + +print("/* This file is generated from keysymdef.h. */") +print("/* Do not edit. */") +print() +print("#ifdef NEEDKTABLE") +print("const unsigned char _XkeyTable[] = {") +print("0,") +for i, row in enumerate(rows): + end = "" if i == len(rows) - 1 else "," + print(", ".join(row) + end) +print("};") +print() +print("#define KTABLESIZE %d" % z) +print("#define KMAXHASH %d" % (max_rehash + 1)) +print() +print("static const unsigned short hashString[KTABLESIZE] = {") +for i in range(0, z, 8): + chunk = offsets[i:i + 8] + line = ", ".join("0x%.4x" % x for x in chunk) + if i + 8 < z: + line += "," + print(line) +print() +print("};") +print("#endif /* NEEDKTABLE */") + +z, max_rehash = find_hash_by_value() +if not z: + raise SystemExit("makekeys: failed to find value hash") + +offsets = [0] * z +values = [None] * z +for i, (_, value) in enumerate(defs): + first = j = value % z + while offsets[j]: + if values[j] == value: + break + j += first + 1 + if j >= z: + j -= z + if not offsets[j]: + offsets[j] = indexes[i] + 2 + values[j] = value + +print() +print("#ifdef NEEDVTABLE") +print("#define VTABLESIZE %d" % z) +print("#define VMAXHASH %d" % (max_rehash + 1)) +print() +print("static const unsigned short hashKeysym[VTABLESIZE] = {") +for i in range(0, z, 8): + chunk = offsets[i:i + 8] + line = ", ".join("0x%.4x" % x for x in chunk) + if i + 8 < z: + line += "," + print(line) +print() +print("};") +print("#endif /* NEEDVTABLE */") +]=] + +local function first_existing(paths) + for _, candidate in ipairs(paths) do + if os.isfile(candidate) then + return candidate + end + end + return nil +end + +local function xorgproto_header(root, name) + return first_existing({ + path.join(root, "include", "X11", name), + path.join(root, "xorgproto-2025.1", "include", "X11", name), + }) +end + +local function c_string(value) + return '"' .. tostring(value):gsub("\\", "\\\\"):gsub('"', '\\"') .. '"' +end + +local function strip_xk_prefix(symbol) + local pos = symbol:find("XK_", 1, true) + if not pos then + return nil + end + return symbol:sub(1, pos - 1) .. symbol:sub(pos + 3) +end + +local function parse_keysym_headers(headers) + local defs = {} + for _, filename in ipairs(headers) do + local content = io.readfile(filename) + for line in content:gmatch("[^\r\n]+") do + local key, hex = line:match("^%s*#define%s+(%S+)%s+0x([0-9a-fA-F]+)") + if key and key:find("XK_", 1, true) then + local name = strip_xk_prefix(key) + local value = tonumber(hex, 16) + if value == 0xFFFFFF then + value = 0 + end + if value <= 0x1FFFFFFF then + table.insert(defs, { name = name, value = value }) + end + else + key, hex = line:match("^%s*#define%s+(%S+)%s+_EVDEVK%(0x([0-9a-fA-F]+)%)") + if key and key:find("XK_", 1, true) then + local name = strip_xk_prefix(key) + table.insert(defs, { name = name, value = tonumber(hex, 16) + 0x10081000 }) + else + local alias + key, alias = line:match("^%s*#define%s+(%S+)%s+(%S+)") + if key and alias and key:find("XK_", 1, true) and alias:find("XK_", 1, true) then + local name = strip_xk_prefix(key) + local alias_name = strip_xk_prefix(alias) + for i = #defs, 1, -1 do + if defs[i].name == alias_name then + table.insert(defs, { name = name, value = defs[i].value }) + break + end + end + end + end + end + end + end + return defs +end + +local function signature(name) + local sig = 0 + for i = 1, #name do + sig = (sig * 2 + name:byte(i)) % 0x100000000 + end + return sig +end + +local function find_hash_by_name(defs) + local best_max = #defs + local best_z = 0 + local found = 0 + for z = #defs, 3999 do + local used = {} + local max_rehash = 0 + local ok = true + for _, def in ipairs(defs) do + local sig = signature(def.name) + local first = sig % z + local j = first + local k = 0 + while used[j] do + k = k + 1 + j = j + first + 1 + if j >= z then + j = j - z + end + if j == first then + ok = false + break + end + end + if not ok then + break + end + used[j] = true + if k > max_rehash then + max_rehash = k + end + end + if ok and max_rehash < 15 then + if max_rehash < best_max then + best_max = max_rehash + best_z = z + end + found = found + 1 + if found >= 10 then + break + end + end + end + return best_z, best_max +end + +local function find_hash_by_value(defs) + local best_max = #defs + local best_z = 0 + local found = 0 + for z = #defs, 3999 do + local used = {} + local values = {} + local max_rehash = 0 + local ok = true + for _, def in ipairs(defs) do + local first = def.value % z + local j = first + local k = 0 + while used[j] do + if values[j] == def.value then + break + end + k = k + 1 + j = j + first + 1 + if j >= z then + j = j - z + end + if j == first then + ok = false + break + end + end + if not ok then + break + end + used[j] = true + values[j] = def.value + if k > max_rehash then + max_rehash = k + end + end + if ok and max_rehash < 15 then + if max_rehash < best_max then + best_max = max_rehash + best_z = z + end + found = found + 1 + if found >= 10 then + break + end + end + end + return best_z, best_max +end + +local function c_char(ch) + if ch == "'" then + return "'\\''" + end + if ch == "\\" then + return "'\\\\'" + end + return "'" .. ch .. "'" +end + +local function hex2(value) + return string.format("0x%.2x", value % 0x100) +end + +local function hex4(value) + return string.format("0x%.4x", value % 0x10000) +end + +local function write_ks_tables(headers, out) + local defs = parse_keysym_headers(headers) + local z, max_rehash = find_hash_by_name(defs) + if z == 0 then + log.error("makekeys: failed to find string hash") + return false + end + + local lines = { + "/* This file is generated from keysymdef.h. */", + "/* Do not edit. */", + "", + "#ifdef NEEDKTABLE", + "const unsigned char _XkeyTable[] = {", + "0,", + } + local offsets = {} + local indexes = {} + local rows = {} + local k = 1 + for i, def in ipairs(defs) do + local sig = signature(def.name) + local first = sig % z + local j = first + while offsets[j] do + j = j + first + 1 + if j >= z then + j = j - z + end + end + offsets[j] = k + indexes[i] = k + + local row = { + hex2(math.floor(sig / 0x100)), + hex2(sig), + hex2(math.floor(def.value / 0x1000000)), + hex2(math.floor(def.value / 0x10000)), + hex2(math.floor(def.value / 0x100)), + hex2(def.value), + } + for pos = 1, #def.name do + table.insert(row, c_char(def.name:sub(pos, pos))) + end + table.insert(row, "0") + table.insert(rows, row) + k = k + 7 + #def.name + end + + for i, row in ipairs(rows) do + local suffix = i == #rows and "" or "," + table.insert(lines, table.concat(row, ", ") .. suffix) + end + + table.insert(lines, "};") + table.insert(lines, "") + table.insert(lines, "#define KTABLESIZE " .. tostring(z)) + table.insert(lines, "#define KMAXHASH " .. tostring(max_rehash + 1)) + table.insert(lines, "") + table.insert(lines, "static const unsigned short hashString[KTABLESIZE] = {") + for i = 0, z - 1, 8 do + local chunk = {} + for j = i, math.min(i + 7, z - 1) do + table.insert(chunk, hex4(offsets[j] or 0)) + end + local suffix = i + 8 < z and "," or "" + table.insert(lines, table.concat(chunk, ", ") .. suffix) + end + table.insert(lines, "") + table.insert(lines, "};") + table.insert(lines, "#endif /* NEEDKTABLE */") + + z, max_rehash = find_hash_by_value(defs) + if z == 0 then + log.error("makekeys: failed to find value hash") + return false + end + + offsets = {} + local values = {} + for i, def in ipairs(defs) do + local first = def.value % z + local j = first + while offsets[j] do + if values[j] == def.value then + break + end + j = j + first + 1 + if j >= z then + j = j - z + end + end + if not offsets[j] then + offsets[j] = indexes[i] + 2 + values[j] = def.value + end + end + + table.insert(lines, "") + table.insert(lines, "#ifdef NEEDVTABLE") + table.insert(lines, "#define VTABLESIZE " .. tostring(z)) + table.insert(lines, "#define VMAXHASH " .. tostring(max_rehash + 1)) + table.insert(lines, "") + table.insert(lines, "static const unsigned short hashKeysym[VTABLESIZE] = {") + for i = 0, z - 1, 8 do + local chunk = {} + for j = i, math.min(i + 7, z - 1) do + table.insert(chunk, hex4(offsets[j] or 0)) + end + local suffix = i + 8 < z and "," or "" + table.insert(lines, table.concat(chunk, ", ") .. suffix) + end + table.insert(lines, "") + table.insert(lines, "};") + table.insert(lines, "#endif /* NEEDVTABLE */") + + io.writefile(out, table.concat(lines, "\n") .. "\n") + return true +end + +local function write_config(installdir) + local x11datadir = path.join(installdir, "share", "X11") + io.writefile(path.join(installdir, "config.h"), [[#ifndef MCPP_COMPAT_X11_CONFIG_H +#define MCPP_COMPAT_X11_CONFIG_H + +#define HAVE_UNISTD_H 1 +#define HAVE_SYS_IOCTL_H 1 +#define HAVE_SYS_SELECT_H 1 +#define HAVE_SYS_SOCKET_H 1 +#define HAVE_STRCASECMP 1 +#define HAVE_STRNCASECMP 1 +#define HAVE_STRDUP 1 +#define HAVE_POLL 1 +#define USE_POLL 1 +#define HAS_SHM 1 +#define XTHREADS 1 +#define XUSE_MTSAFE_API 1 +#define XKB 1 +#define XCMS 1 +#define XLOCALE 1 +#define XCMSDIR ]] .. c_string(x11datadir) .. "\n" .. [[ +#define XLOCALEDIR ]] .. c_string(path.join(x11datadir, "locale")) .. "\n" .. [[ +#define XLOCALELIBDIR ]] .. c_string(path.join(x11datadir, "locale")) .. "\n" .. [[ +#define XLOCALEDATADIR ]] .. c_string(path.join(x11datadir, "locale")) .. "\n" .. [[ +#define XERRORDB ]] .. c_string(path.join(x11datadir, "XErrorDB")) .. [[ + +#endif +]]) + + io.writefile(path.join(installdir, "include", "X11", "XlibConf.h"), [[#ifndef _XLIBCONF_H_ +#define _XLIBCONF_H_ +#define XTHREADS 1 +#define XUSE_MTSAFE_API 1 +#endif +]]) +end + +local function generate_ks_tables(installdir) + local proto_dir = pkginfo.install_dir("compat:compat.xorgproto", "2025.1") + or pkginfo.install_dir("compat.xorgproto", "2025.1") + if not proto_dir then + log.error("compat.xorgproto@2025.1 install dir not found") + return false + end + + local headers = { + xorgproto_header(proto_dir, "keysymdef.h"), + xorgproto_header(proto_dir, "XF86keysym.h"), + xorgproto_header(proto_dir, "Sunkeysym.h"), + xorgproto_header(proto_dir, "DECkeysym.h"), + xorgproto_header(proto_dir, "HPkeysym.h"), + } + for _, header in ipairs(headers) do + if not header then + log.error("missing xorgproto keysym header") + return false + end + end + + local out = path.join(installdir, "src", "ks_tables.h") + return write_ks_tables(headers, out) and os.isfile(out) +end + +function install() + local srcdir = pkginfo.install_file():replace(".tar.gz", "") + if not os.isdir(srcdir) then + srcdir = "libX11-" .. pkginfo.version() + end + + os.tryrm(pkginfo.install_dir()) + os.mv(srcdir, pkginfo.install_dir()) + + local datadir = path.join(pkginfo.install_dir(), "share", "X11") + os.mkdir(datadir) + os.cp(path.join(pkginfo.install_dir(), "src", "XErrorDB"), path.join(datadir, "XErrorDB")) + os.cp(path.join(pkginfo.install_dir(), "src", "xcms", "Xcms.txt"), path.join(datadir, "Xcms.txt")) + + write_config(pkginfo.install_dir()) + return generate_ks_tables(pkginfo.install_dir()) +end diff --git a/pkgs/c/compat.xau.lua b/pkgs/c/compat.xau.lua new file mode 100644 index 0000000..b3ee793 --- /dev/null +++ b/pkgs/c/compat.xau.lua @@ -0,0 +1,40 @@ +package = { + spec = "1", + namespace = "compat", + name = "compat.xau", + description = "X authorization file management library", + licenses = {"MIT"}, + repo = "https://gitlab.freedesktop.org/xorg/lib/libxau", + type = "package", + + xpm = { + linux = { + ["1.0.12"] = { + url = "https://xorg.freedesktop.org/releases/individual/lib/libXau-1.0.12.tar.gz", + sha256 = "2402dd938da4d0a332349ab3d3586606175e19cb32cb9fe013c19f1dc922dcee", + }, + }, + }, + + mcpp = { + language = "c++23", + import_std = false, + c_standard = "c11", + cflags = {"-D_GNU_SOURCE", "-D_DEFAULT_SOURCE"}, + include_dirs = {"*/include"}, + sources = { + "*/AuDispose.c", + "*/AuFileName.c", + "*/AuGetAddr.c", + "*/AuGetBest.c", + "*/AuLock.c", + "*/AuRead.c", + "*/AuUnlock.c", + "*/AuWrite.c", + }, + targets = { ["Xau"] = { kind = "shared" } }, + deps = { + ["compat.xorgproto"] = "2025.1", + }, + }, +} diff --git a/pkgs/c/compat.xcb-proto.lua b/pkgs/c/compat.xcb-proto.lua new file mode 100644 index 0000000..e9d8a7f --- /dev/null +++ b/pkgs/c/compat.xcb-proto.lua @@ -0,0 +1,43 @@ +package = { + spec = "1", + namespace = "compat", + name = "compat.xcb-proto", + description = "XCB protocol XML descriptions and xcbgen generator", + licenses = {"MIT"}, + repo = "https://gitlab.freedesktop.org/xorg/proto/xcbproto", + type = "package", + + xpm = { + linux = { + ["1.17.0"] = { + url = "https://xorg.freedesktop.org/releases/individual/proto/xcb-proto-1.17.0.tar.xz", + sha256 = "2c1bacd2110f4799f74de6ebb714b94cf6f80fb112316b1219480fd22562148c", + }, + }, + }, + + mcpp = { + language = "c++23", + import_std = false, + c_standard = "c11", + include_dirs = {}, + generated_files = { + ["mcpp_generated/xcb_proto_empty.c"] = "int mcpp_compat_xcb_proto_anchor(void) { return 0; }\n", + }, + sources = {"mcpp_generated/xcb_proto_empty.c"}, + targets = { ["xcb_proto"] = { kind = "lib" } }, + deps = {}, + }, +} + +import("xim.libxpkg.pkginfo") + +function install() + local srcdir = pkginfo.install_file():replace(".tar.xz", "") + if not os.isdir(srcdir) then + srcdir = "xcb-proto-" .. pkginfo.version() + end + os.tryrm(pkginfo.install_dir()) + os.mv(srcdir, pkginfo.install_dir()) + return true +end diff --git a/pkgs/c/compat.xcb.lua b/pkgs/c/compat.xcb.lua new file mode 100644 index 0000000..572eda5 --- /dev/null +++ b/pkgs/c/compat.xcb.lua @@ -0,0 +1,155 @@ +package = { + spec = "1", + namespace = "compat", + name = "compat.xcb", + description = "X C Binding core library built from upstream sources", + licenses = {"MIT"}, + repo = "https://gitlab.freedesktop.org/xorg/lib/libxcb", + type = "package", + + xpm = { + linux = { + deps = { + "compat:compat.xcb-proto@1.17.0", + "python@latest", + }, + ["1.17.0"] = { + url = "https://xorg.freedesktop.org/releases/individual/lib/libxcb-1.17.0.tar.xz", + sha256 = "599ebf9996710fea71622e6e184f3a8ad5b43d0e5fa8c4e407123c88a59a6d55", + }, + }, + }, + + mcpp = { + language = "c++23", + import_std = false, + c_standard = "c11", + include_dirs = {"src", "include"}, + cflags = { + "-D_GNU_SOURCE", + "-D_DEFAULT_SOURCE", + "-DHAVE_CONFIG_H", + }, + sources = { + "src/xcb_conn.c", + "src/xcb_out.c", + "src/xcb_in.c", + "src/xcb_ext.c", + "src/xcb_xid.c", + "src/xcb_list.c", + "src/xcb_util.c", + "src/xcb_auth.c", + "src/xproto.c", + "src/bigreq.c", + "src/xc_misc.c", + }, + targets = { ["xcb"] = { kind = "shared" } }, + deps = { + ["compat.xau"] = "1.0.12", + ["compat.xdmcp"] = "1.1.5", + }, + }, +} + +import("xim.libxpkg.pkginfo") +import("xim.libxpkg.log") + +local generated_headers = { + "xcb.h", + "xcbext.h", + "xcb_windefs.h", + "xproto.h", + "bigreq.h", + "xc_misc.h", +} + +local function write_config_header(srcdir) + io.writefile(path.join(srcdir, "config.h"), [[#ifndef MCPP_COMPAT_XCB_CONFIG_H +#define MCPP_COMPAT_XCB_CONFIG_H + +#define HAVE_SENDMSG 1 +#define HAVE_ABSTRACT_SOCKETS 1 +#define HAVE_GETADDRINFO 1 +#define XCB_QUEUE_BUFFER_SIZE 16384 + +#endif +]]) +end + +local function copy_public_headers(srcdir, installdir) + local incdir = path.join(installdir, "include", "xcb") + os.mkdir(path.join(installdir, "include")) + os.mkdir(incdir) + for _, header in ipairs(generated_headers) do + os.cp(path.join(srcdir, header), path.join(incdir, header)) + end +end + +local function sh_quote(value) + return "'" .. tostring(value):gsub("'", "'\\''") .. "'" +end + +local function resolve_python() + local python = pkginfo.build_dep("xim:python") or pkginfo.build_dep("python") + if not python or not python.bin or not os.isdir(python.bin) then + log.error("python build dependency not found") + return nil + end + + for _, name in ipairs({ "python3", "python" }) do + local candidate = path.join(python.bin, name) + if os.isfile(candidate) then + return candidate + end + end + + local matches = os.files(path.join(python.bin, "python3.*")) or {} + table.sort(matches) + if #matches > 0 then + return matches[#matches] + end + + log.error("python executable not found under %s", python.bin) + return nil +end + +function install() + local srcroot = pkginfo.install_file():replace(".tar.xz", "") + if not os.isdir(srcroot) then + srcroot = "libxcb-" .. pkginfo.version() + end + + os.tryrm(pkginfo.install_dir()) + os.mv(srcroot, pkginfo.install_dir()) + + local proto_dir = pkginfo.install_dir("compat:compat.xcb-proto", "1.17.0") + or pkginfo.install_dir("compat.xcb-proto", "1.17.0") + if not proto_dir or not os.isdir(proto_dir) then + log.error("compat.xcb-proto@1.17.0 install dir not found") + return false + end + + local srcdir = path.join(pkginfo.install_dir(), "src") + write_config_header(srcdir) + + local python = resolve_python() + if not python then + return false + end + + os.cd(srcdir) + for _, name in ipairs({ "xproto", "bigreq", "xc_misc" }) do + local cmd = string.format( + "%s c_client.py -c %s -l %s -s 3 -p %s %s", + sh_quote(python), + sh_quote("libxcb " .. pkginfo.version()), + sh_quote("X Version 11"), + sh_quote(proto_dir), + sh_quote(path.join(proto_dir, "src", name .. ".xml")) + ) + os.exec(cmd) + end + + copy_public_headers(srcdir, pkginfo.install_dir()) + return true +end diff --git a/pkgs/c/compat.xcursor.lua b/pkgs/c/compat.xcursor.lua new file mode 100644 index 0000000..12f914d --- /dev/null +++ b/pkgs/c/compat.xcursor.lua @@ -0,0 +1,34 @@ +package = { + spec = "1", + namespace = "compat", + name = "compat.xcursor", + description = "X cursor management runtime library and public headers", + licenses = {"MIT"}, + repo = "https://gitlab.freedesktop.org/xorg/lib/libxcursor", + type = "package", + + xpm = { + linux = { + ["1.2.3"] = { + url = "https://xorg.freedesktop.org/releases/individual/lib/libXcursor-1.2.3.tar.gz", + sha256 = "74e72da27e61cc2cfd2e267c14f500ea47775850048ee0b00362a55c9b60ee9b", + }, + }, + }, + + mcpp = { + language = "c++23", + import_std = false, + c_standard = "c11", + cflags = {"-D_GNU_SOURCE", "-D_DEFAULT_SOURCE", "-DHAVE_XFIXES=1"}, + include_dirs = {"*/include", "*/include/X11/Xcursor", "*/include/X11/extensions", "*/src"}, + sources = {"*/src/*.c"}, + targets = { ["Xcursor"] = { kind = "shared" } }, + deps = { + ["compat.x11"] = "1.8.13", + ["compat.xfixes"] = "6.0.2", + ["compat.xrender"] = "0.9.12", + ["compat.xorgproto"] = "2025.1", + }, + }, +} diff --git a/pkgs/c/compat.xdmcp.lua b/pkgs/c/compat.xdmcp.lua new file mode 100644 index 0000000..70fe5a2 --- /dev/null +++ b/pkgs/c/compat.xdmcp.lua @@ -0,0 +1,40 @@ +package = { + spec = "1", + namespace = "compat", + name = "compat.xdmcp", + description = "X Display Manager Control Protocol library", + licenses = {"MIT"}, + repo = "https://gitlab.freedesktop.org/xorg/lib/libxdmcp", + type = "package", + + xpm = { + linux = { + ["1.1.5"] = { + url = "https://xorg.freedesktop.org/releases/individual/lib/libXdmcp-1.1.5.tar.gz", + sha256 = "31a7abc4f129dcf6f27ae912c3eedcb94d25ad2e8f317f69df6eda0bc4e4f2f3", + }, + }, + }, + + mcpp = { + language = "c++23", + import_std = false, + c_standard = "c11", + cflags = {"-D_GNU_SOURCE", "-D_DEFAULT_SOURCE", "-DHAVE_ARC4RANDOM_BUF=1"}, + include_dirs = {"*/include", "*"}, + sources = { + "*/Array.c", + "*/Fill.c", + "*/Flush.c", + "*/Key.c", + "*/Read.c", + "*/Unwrap.c", + "*/Wrap.c", + "*/Write.c", + }, + targets = { ["Xdmcp"] = { kind = "shared" } }, + deps = { + ["compat.xorgproto"] = "2025.1", + }, + }, +} diff --git a/pkgs/c/compat.xext.lua b/pkgs/c/compat.xext.lua new file mode 100644 index 0000000..f50bf93 --- /dev/null +++ b/pkgs/c/compat.xext.lua @@ -0,0 +1,32 @@ +package = { + spec = "1", + namespace = "compat", + name = "compat.xext", + description = "X11 miscellaneous extensions runtime library and public headers", + licenses = {"MIT"}, + repo = "https://gitlab.freedesktop.org/xorg/lib/libxext", + type = "package", + + xpm = { + linux = { + ["1.3.7"] = { + url = "https://xorg.freedesktop.org/releases/individual/lib/libXext-1.3.7.tar.gz", + sha256 = "6564608dc3b816b0cfddf0c7ddc62bc579055dd70b2f28113a618df2acb64189", + }, + }, + }, + + mcpp = { + language = "c++23", + import_std = false, + c_standard = "c11", + cflags = {"-D_GNU_SOURCE", "-D_DEFAULT_SOURCE"}, + include_dirs = {"*/include", "*/include/X11/extensions", "*/src"}, + sources = {"*/src/*.c"}, + targets = { ["Xext"] = { kind = "shared" } }, + deps = { + ["compat.x11"] = "1.8.13", + ["compat.xorgproto"] = "2025.1", + }, + }, +} diff --git a/pkgs/c/compat.xfixes.lua b/pkgs/c/compat.xfixes.lua new file mode 100644 index 0000000..eb3e23b --- /dev/null +++ b/pkgs/c/compat.xfixes.lua @@ -0,0 +1,33 @@ +package = { + spec = "1", + namespace = "compat", + name = "compat.xfixes", + description = "X Fixes extension runtime library and public headers", + licenses = {"MIT"}, + repo = "https://gitlab.freedesktop.org/xorg/lib/libxfixes", + type = "package", + + xpm = { + linux = { + ["6.0.2"] = { + url = "https://xorg.freedesktop.org/releases/individual/lib/libXfixes-6.0.2.tar.gz", + sha256 = "041331b8e6e36038b3bf836785b6b175ec8515f964c9e4e3316b3bfed0f53ac7", + }, + }, + }, + + mcpp = { + language = "c++23", + import_std = false, + c_standard = "c11", + cflags = {"-D_GNU_SOURCE", "-D_DEFAULT_SOURCE"}, + include_dirs = {"*/include", "*/include/X11/extensions", "*/src"}, + sources = {"*/src/*.c"}, + targets = { ["Xfixes"] = { kind = "shared" } }, + deps = { + ["compat.x11"] = "1.8.13", + ["compat.xext"] = "1.3.7", + ["compat.xorgproto"] = "2025.1", + }, + }, +} diff --git a/pkgs/c/compat.xi.lua b/pkgs/c/compat.xi.lua new file mode 100644 index 0000000..1c15140 --- /dev/null +++ b/pkgs/c/compat.xi.lua @@ -0,0 +1,37 @@ +package = { + spec = "1", + namespace = "compat", + name = "compat.xi", + description = "X Input extension runtime library and public headers", + licenses = {"MIT"}, + repo = "https://gitlab.freedesktop.org/xorg/lib/libxi", + type = "package", + + xpm = { + linux = { + ["1.8.3"] = { + url = "https://xorg.freedesktop.org/releases/individual/lib/libXi-1.8.3.tar.gz", + sha256 = "6648c44127e4585f4e7842c0802d265008fa6f9741df0ea6ee7934a5267adf63", + }, + }, + }, + + mcpp = { + language = "c++23", + import_std = false, + c_standard = "c11", + cflags = {"-D_GNU_SOURCE", "-D_DEFAULT_SOURCE"}, + include_dirs = {"*/include", "*/include/X11/extensions", "*/src"}, + sources = { + "*/src/*.c", + "!*/src/XFreeLst.c", + }, + targets = { ["Xi"] = { kind = "shared" } }, + deps = { + ["compat.x11"] = "1.8.13", + ["compat.xext"] = "1.3.7", + ["compat.xfixes"] = "6.0.2", + ["compat.xorgproto"] = "2025.1", + }, + }, +} diff --git a/pkgs/c/compat.xinerama.lua b/pkgs/c/compat.xinerama.lua new file mode 100644 index 0000000..08a146f --- /dev/null +++ b/pkgs/c/compat.xinerama.lua @@ -0,0 +1,33 @@ +package = { + spec = "1", + namespace = "compat", + name = "compat.xinerama", + description = "Xinerama extension runtime library and public headers", + licenses = {"MIT"}, + repo = "https://gitlab.freedesktop.org/xorg/lib/libxinerama", + type = "package", + + xpm = { + linux = { + ["1.1.6"] = { + url = "https://xorg.freedesktop.org/releases/individual/lib/libXinerama-1.1.6.tar.gz", + sha256 = "c74ee3d05e473671bf86285e2dece345485200bb042bea1540b1e30ff3f74bae", + }, + }, + }, + + mcpp = { + language = "c++23", + import_std = false, + c_standard = "c11", + cflags = {"-D_GNU_SOURCE", "-D_DEFAULT_SOURCE"}, + include_dirs = {"*/include", "*/include/X11/extensions", "*/src"}, + sources = {"*/src/*.c"}, + targets = { ["Xinerama"] = { kind = "shared" } }, + deps = { + ["compat.x11"] = "1.8.13", + ["compat.xext"] = "1.3.7", + ["compat.xorgproto"] = "2025.1", + }, + }, +} diff --git a/pkgs/c/compat.xorgproto.lua b/pkgs/c/compat.xorgproto.lua new file mode 100644 index 0000000..b692f29 --- /dev/null +++ b/pkgs/c/compat.xorgproto.lua @@ -0,0 +1,32 @@ +package = { + spec = "1", + namespace = "compat", + name = "compat.xorgproto", + description = "X.Org protocol headers for X11-based compat packages", + licenses = {"MIT"}, + repo = "https://gitlab.freedesktop.org/xorg/proto/xorgproto", + type = "package", + + xpm = { + linux = { + ["2025.1"] = { + url = "https://xorg.freedesktop.org/releases/individual/proto/xorgproto-2025.1.tar.gz", + sha256 = "d6f89f65bafb8c9b735e0515882b8a1511e8e864dde5e9513e191629369f2256", + }, + }, + }, + + mcpp = { + language = "c++23", + import_std = false, + c_standard = "c11", + include_dirs = {"*/include", "mcpp_generated/include"}, + generated_files = { + ["mcpp_generated/include/X11/Xpoll.h"] = "#ifndef _XPOLL_H_\n#define _XPOLL_H_\n#if !defined(WIN32) || defined(__CYGWIN__)\n#include \n#include \n#define Select(n,r,w,e,t) select(n,(fd_set*)r,(fd_set*)w,(fd_set*)e,(struct timeval*)t)\n#else\n#include \n#endif\n#endif\n", + ["mcpp_generated/xorgproto_empty.c"] = "int mcpp_compat_xorgproto_headers_anchor(void) { return 0; }\n", + }, + sources = {"mcpp_generated/xorgproto_empty.c"}, + targets = { ["xorgproto"] = { kind = "lib" } }, + deps = {}, + }, +} diff --git a/pkgs/c/compat.xrandr.lua b/pkgs/c/compat.xrandr.lua new file mode 100644 index 0000000..ccf29df --- /dev/null +++ b/pkgs/c/compat.xrandr.lua @@ -0,0 +1,34 @@ +package = { + spec = "1", + namespace = "compat", + name = "compat.xrandr", + description = "X Resize, Rotate and Reflect extension runtime library and public headers", + licenses = {"MIT"}, + repo = "https://gitlab.freedesktop.org/xorg/lib/libxrandr", + type = "package", + + xpm = { + linux = { + ["1.5.5"] = { + url = "https://xorg.freedesktop.org/releases/individual/lib/libXrandr-1.5.5.tar.gz", + sha256 = "23faedab4675890ba579b8103399132a139527306b18b500c6fe28e090e2a056", + }, + }, + }, + + mcpp = { + language = "c++23", + import_std = false, + c_standard = "c11", + cflags = {"-D_GNU_SOURCE", "-D_DEFAULT_SOURCE"}, + include_dirs = {"*/include", "*/include/X11/extensions", "*/src"}, + sources = {"*/src/*.c"}, + targets = { ["Xrandr"] = { kind = "shared" } }, + deps = { + ["compat.x11"] = "1.8.13", + ["compat.xext"] = "1.3.7", + ["compat.xrender"] = "0.9.12", + ["compat.xorgproto"] = "2025.1", + }, + }, +} diff --git a/pkgs/c/compat.xrender.lua b/pkgs/c/compat.xrender.lua new file mode 100644 index 0000000..d91255a --- /dev/null +++ b/pkgs/c/compat.xrender.lua @@ -0,0 +1,32 @@ +package = { + spec = "1", + namespace = "compat", + name = "compat.xrender", + description = "X Rendering extension runtime library and public headers", + licenses = {"MIT"}, + repo = "https://gitlab.freedesktop.org/xorg/lib/libxrender", + type = "package", + + xpm = { + linux = { + ["0.9.12"] = { + url = "https://xorg.freedesktop.org/releases/individual/lib/libXrender-0.9.12.tar.gz", + sha256 = "0fff64125819c02d1102b6236f3d7d861a07b5216d8eea336c3811d31494ecf7", + }, + }, + }, + + mcpp = { + language = "c++23", + import_std = false, + c_standard = "c11", + cflags = {"-D_GNU_SOURCE", "-D_DEFAULT_SOURCE"}, + include_dirs = {"*/include", "*/include/X11/extensions", "*/src"}, + sources = {"*/src/*.c"}, + targets = { ["Xrender"] = { kind = "shared" } }, + deps = { + ["compat.x11"] = "1.8.13", + ["compat.xorgproto"] = "2025.1", + }, + }, +} diff --git a/pkgs/c/compat.xtrans.lua b/pkgs/c/compat.xtrans.lua new file mode 100644 index 0000000..1264a5a --- /dev/null +++ b/pkgs/c/compat.xtrans.lua @@ -0,0 +1,62 @@ +package = { + spec = "1", + namespace = "compat", + name = "compat.xtrans", + description = "X.Org transport layer support headers used by Xlib", + licenses = {"MIT"}, + repo = "https://gitlab.freedesktop.org/xorg/lib/libxtrans", + type = "package", + + xpm = { + linux = { + ["1.6.0"] = { + url = "https://xorg.freedesktop.org/releases/individual/lib/xtrans-1.6.0.tar.xz", + sha256 = "faafea166bf2451a173d9d593352940ec6404145c5d1da5c213423ce4d359e92", + }, + }, + }, + + mcpp = { + language = "c++23", + import_std = false, + c_standard = "c11", + include_dirs = {"include"}, + generated_files = { + ["mcpp_generated/xtrans_empty.c"] = "int mcpp_compat_xtrans_headers_anchor(void) { return 0; }\n", + }, + sources = {"mcpp_generated/xtrans_empty.c"}, + targets = { ["xtrans"] = { kind = "lib" } }, + deps = {}, + }, +} + +import("xim.libxpkg.pkginfo") + +local xtrans_headers = { + "Xtrans.h", + "Xtrans.c", + "Xtransint.h", + "Xtranslcl.c", + "Xtranssock.c", + "Xtransutil.c", + "transport.c", +} + +function install() + local srcdir = pkginfo.install_file():replace(".tar.xz", "") + if not os.isdir(srcdir) then + srcdir = "xtrans-" .. pkginfo.version() + end + + os.tryrm(pkginfo.install_dir()) + os.mv(srcdir, pkginfo.install_dir()) + + local xtransdir = path.join(pkginfo.install_dir(), "include", "X11", "Xtrans") + os.mkdir(path.join(pkginfo.install_dir(), "include")) + os.mkdir(path.join(pkginfo.install_dir(), "include", "X11")) + os.mkdir(xtransdir) + for _, header in ipairs(xtrans_headers) do + os.cp(path.join(pkginfo.install_dir(), header), path.join(xtransdir, header)) + end + return true +end diff --git a/pkgs/c/compat.zlib.lua b/pkgs/c/compat.zlib.lua index 1849c17..87eda33 100644 --- a/pkgs/c/compat.zlib.lua +++ b/pkgs/c/compat.zlib.lua @@ -9,19 +9,19 @@ package = { xpm = { linux = { - ["v1.3.2"] = { + ["1.3.2"] = { url = "https://github.com/madler/zlib/archive/refs/tags/v1.3.2.tar.gz", sha256 = "b99a0b86c0ba9360ec7e78c4f1e43b1cbdf1e6936c8fa0f6835c0cd694a495a1", }, }, macosx = { - ["v1.3.2"] = { + ["1.3.2"] = { url = "https://github.com/madler/zlib/archive/refs/tags/v1.3.2.tar.gz", sha256 = "b99a0b86c0ba9360ec7e78c4f1e43b1cbdf1e6936c8fa0f6835c0cd694a495a1", }, }, windows = { - ["v1.3.2"] = { + ["1.3.2"] = { url = "https://github.com/madler/zlib/archive/refs/tags/v1.3.2.tar.gz", sha256 = "b99a0b86c0ba9360ec7e78c4f1e43b1cbdf1e6936c8fa0f6835c0cd694a495a1", }, diff --git a/pkgs/c/compat.zstd.lua b/pkgs/c/compat.zstd.lua index f2f4290..76b6f64 100644 --- a/pkgs/c/compat.zstd.lua +++ b/pkgs/c/compat.zstd.lua @@ -9,19 +9,19 @@ package = { xpm = { linux = { - ["v1.5.7"] = { + ["1.5.7"] = { url = "https://github.com/facebook/zstd/archive/refs/tags/v1.5.7.tar.gz", sha256 = "37d7284556b20954e56e1ca85b80226768902e2edabd3b649e9e72c0c9012ee3", }, }, macosx = { - ["v1.5.7"] = { + ["1.5.7"] = { url = "https://github.com/facebook/zstd/archive/refs/tags/v1.5.7.tar.gz", sha256 = "37d7284556b20954e56e1ca85b80226768902e2edabd3b649e9e72c0c9012ee3", }, }, windows = { - ["v1.5.7"] = { + ["1.5.7"] = { url = "https://github.com/facebook/zstd/archive/refs/tags/v1.5.7.tar.gz", sha256 = "37d7284556b20954e56e1ca85b80226768902e2edabd3b649e9e72c0c9012ee3", }, diff --git a/tests/smoke_compat_archive.sh b/tests/smoke_compat_archive.sh new file mode 100755 index 0000000..8ab8bec --- /dev/null +++ b/tests/smoke_compat_archive.sh @@ -0,0 +1,105 @@ +#!/usr/bin/env bash +# Smoke-test archive/compression compat packages through this checkout as a +# local mcpp path index. +set -euo pipefail + +ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +MCPP_BIN="${MCPP:-}" +if [[ -z "$MCPP_BIN" ]]; then + MCPP_BIN="$(command -v mcpp || true)" +fi +if [[ -z "$MCPP_BIN" || ! -x "$MCPP_BIN" ]]; then + echo "FATAL: set MCPP=/path/to/mcpp or put mcpp on PATH" >&2 + exit 1 +fi + +TMP="$(mktemp -d)" +trap 'rm -rf "$TMP"' EXIT +SMOKE_CACHE_DIR="${MCPP_INDEX_SMOKE_CACHE_DIR:-}" +SMOKE_XPKGS_DIR="${MCPP_INDEX_SMOKE_XPKGS_DIR:-}" + +export MCPP_HOME="$TMP/mcpp-home" +mkdir -p "$MCPP_HOME" + +USER_MCPP="${HOME}/.mcpp" +mkdir -p "$MCPP_HOME/registry/data/xpkgs" +link_xpkgs() { + local src="$1" + [[ -d "$src" ]] || return 0 + find "$src" -mindepth 1 -maxdepth 1 -type d | while read -r pkg; do + ln -s "$pkg" "$MCPP_HOME/registry/data/xpkgs/$(basename "$pkg")" 2>/dev/null || true + done +} +link_xpkgs "$SMOKE_XPKGS_DIR" +link_xpkgs "$USER_MCPP/registry/data/xpkgs" +if [[ -d "$USER_MCPP/registry/data/xim-pkgindex" ]]; then + mkdir -p "$MCPP_HOME/registry/data" + ln -s "$USER_MCPP/registry/data/xim-pkgindex" "$MCPP_HOME/registry/data/xim-pkgindex" 2>/dev/null || true +fi +if [[ -d "$USER_MCPP/registry/bin" ]]; then + mkdir -p "$MCPP_HOME/registry" + ln -s "$USER_MCPP/registry/bin" "$MCPP_HOME/registry/bin" 2>/dev/null || true +fi +if [[ -f "$USER_MCPP/config.toml" ]]; then + cp -f "$USER_MCPP/config.toml" "$MCPP_HOME/config.toml" 2>/dev/null || true +fi + +mkdir -p "$TMP/compat-archive-smoke/src" +cd "$TMP/compat-archive-smoke" +cat > mcpp.toml < src/main.cpp <<'EOF' +#include +#include +#include +#include +#include +#include +#include + +int main() { + archive* writer = archive_write_new(); + if (!writer) return 1; + archive_write_free(writer); + + archive_entry* entry = archive_entry_new(); + if (!entry) return 2; + archive_entry_free(entry); + + if (!archive_version_string()) return 3; + if (!zlibVersion()) return 4; + if (!BZ2_bzlibVersion()) return 5; + if (LZ4_versionNumber() <= 0) return 6; + if (ZSTD_versionNumber() == 0) return 7; + if (lzma_version_number() == 0) return 8; + return 0; +} +EOF + +"$MCPP_BIN" build +"$MCPP_BIN" run +echo "OK" diff --git a/tests/smoke_compat_core.sh b/tests/smoke_compat_core.sh new file mode 100755 index 0000000..0a6bdc1 --- /dev/null +++ b/tests/smoke_compat_core.sh @@ -0,0 +1,150 @@ +#!/usr/bin/env bash +# Smoke-test core third-party compat packages through this checkout as a local +# mcpp path index. The test intentionally uses upstream-style headers and APIs. +set -euo pipefail + +ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +MCPP_BIN="${MCPP:-}" +if [[ -z "$MCPP_BIN" ]]; then + MCPP_BIN="$(command -v mcpp || true)" +fi +if [[ -z "$MCPP_BIN" || ! -x "$MCPP_BIN" ]]; then + echo "FATAL: set MCPP=/path/to/mcpp or put mcpp on PATH" >&2 + exit 1 +fi + +TMP="$(mktemp -d)" +trap 'rm -rf "$TMP"' EXIT +SMOKE_CACHE_DIR="${MCPP_INDEX_SMOKE_CACHE_DIR:-}" +SMOKE_XPKGS_DIR="${MCPP_INDEX_SMOKE_XPKGS_DIR:-}" + +export MCPP_HOME="$TMP/mcpp-home" +mkdir -p "$MCPP_HOME/registry/data/xpkgs" + +USER_MCPP="${HOME}/.mcpp" +link_xpkgs() { + local src="$1" + [[ -d "$src" ]] || return 0 + find "$src" -mindepth 1 -maxdepth 1 -type d | while read -r pkg; do + ln -s "$pkg" "$MCPP_HOME/registry/data/xpkgs/$(basename "$pkg")" 2>/dev/null || true + done +} +link_xpkgs "$SMOKE_XPKGS_DIR" +link_xpkgs "$USER_MCPP/registry/data/xpkgs" +if [[ -d "$USER_MCPP/registry/data/xim-pkgindex" ]]; then + mkdir -p "$MCPP_HOME/registry/data" + ln -s "$USER_MCPP/registry/data/xim-pkgindex" "$MCPP_HOME/registry/data/xim-pkgindex" 2>/dev/null || true +fi +if [[ -d "$USER_MCPP/registry/bin" ]]; then + mkdir -p "$MCPP_HOME/registry" + ln -s "$USER_MCPP/registry/bin" "$MCPP_HOME/registry/bin" 2>/dev/null || true +fi +if [[ -f "$USER_MCPP/config.toml" ]]; then + cp -f "$USER_MCPP/config.toml" "$MCPP_HOME/config.toml" 2>/dev/null || true +fi + +mkdir -p "$TMP/compat-core-smoke/src" +cd "$TMP/compat-core-smoke" +cat > mcpp.toml < src/main.cpp <<'EOF' +#include +#include + +#include +#include +#include +#include +#include +#include + +extern "C" { +#include +#include +#include +} + +TEST(CompatGTest, BasicAssertion) { + EXPECT_EQ(2 + 2, 4); +} + +static bool check_ftxui() { + using namespace ftxui; + Element document = hbox({text("compat"), separator(), text("ftxui")}); + Screen screen = Screen::Create(Dimension::Fit(document), Dimension::Fit(document)); + Render(screen, document); + const std::string rendered = screen.ToString(); + return rendered.find("compat") != std::string::npos && + rendered.find("ftxui") != std::string::npos; +} + +static bool check_lua() { + lua_State* state = luaL_newstate(); + if (!state) { + return false; + } + luaL_openlibs(state); + const int rc = luaL_dostring(state, "return 20 + 22"); + const bool ok = rc == LUA_OK && lua_isinteger(state, -1) && + lua_tointeger(state, -1) == 42; + lua_close(state); + return ok; +} + +static bool check_mbedtls() { + const unsigned char input[] = "abc"; + std::array out{}; + mbedtls_sha256(input, 3, out.data(), 0); + return out[0] == 0xba && out[1] == 0x78 && + out[30] == 0x15 && out[31] == 0xad; +} + +static bool check_opengl_headers() { + const GLenum texture = GL_TEXTURE_2D; + const khronos_uint32_t one = 1; + return texture == 0x0DE1 && one == 1; +} + +TEST(CompatCore, UpstreamHeadersAndMinimalRuntime) { + EXPECT_TRUE(check_ftxui()); + EXPECT_TRUE(check_lua()); + EXPECT_TRUE(check_mbedtls()); + EXPECT_TRUE(check_opengl_headers()); +} +EOF + +"$MCPP_BIN" build +"$MCPP_BIN" run +echo "OK" diff --git a/tests/smoke_compat_imgui.sh b/tests/smoke_compat_imgui.sh new file mode 100755 index 0000000..a7261c7 --- /dev/null +++ b/tests/smoke_compat_imgui.sh @@ -0,0 +1,260 @@ +#!/usr/bin/env bash +# Smoke-test the ImGui-related compat packages through this checkout as a +# local mcpp path index. +set -euo pipefail + +ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +MCPP_BIN="${MCPP:-}" +if [[ -z "$MCPP_BIN" ]]; then + MCPP_BIN="$(command -v mcpp || true)" +fi +if [[ -z "$MCPP_BIN" || ! -x "$MCPP_BIN" ]]; then + echo "FATAL: set MCPP=/path/to/mcpp or put mcpp on PATH" >&2 + exit 1 +fi + +TMP="$(mktemp -d)" +trap 'rm -rf "$TMP"' EXIT +SMOKE_CACHE_DIR="${MCPP_INDEX_SMOKE_CACHE_DIR:-}" +SMOKE_XPKGS_DIR="${MCPP_INDEX_SMOKE_XPKGS_DIR:-}" + +export MCPP_HOME="$TMP/mcpp-home" +mkdir -p "$MCPP_HOME" + +USER_MCPP="${HOME}/.mcpp" +mkdir -p "$MCPP_HOME/registry/data/xpkgs" +link_xpkgs() { + local src="$1" + [[ -d "$src" ]] || return 0 + find "$src" -mindepth 1 -maxdepth 1 -type d | while read -r pkg; do + ln -s "$pkg" "$MCPP_HOME/registry/data/xpkgs/$(basename "$pkg")" 2>/dev/null || true + done +} +link_xpkgs "$SMOKE_XPKGS_DIR" +link_xpkgs "$USER_MCPP/registry/data/xpkgs" +if [[ -d "$USER_MCPP/registry/data/xim-pkgindex" ]]; then + mkdir -p "$MCPP_HOME/registry/data" + ln -s "$USER_MCPP/registry/data/xim-pkgindex" "$MCPP_HOME/registry/data/xim-pkgindex" 2>/dev/null || true +fi +if [[ -d "$USER_MCPP/registry/bin" ]]; then + mkdir -p "$MCPP_HOME/registry" + ln -s "$USER_MCPP/registry/bin" "$MCPP_HOME/registry/bin" 2>/dev/null || true +fi +if [[ -f "$USER_MCPP/config.toml" ]]; then + cp -f "$USER_MCPP/config.toml" "$MCPP_HOME/config.toml" 2>/dev/null || true +fi + +make_project() { + local name="$1" + mkdir -p "$TMP/$name/src" + cd "$TMP/$name" + cat > mcpp.toml <> mcpp.toml <<'EOF' + +[dependencies.compat] +imgui = "1.92.8" +EOF +cat > src/main.cpp <<'EOF' +#include + +int main() { + ImGui::CreateContext(); + ImGuiIO& io = ImGui::GetIO(); + io.DisplaySize = ImVec2(320.0f, 180.0f); + io.DeltaTime = 1.0f / 60.0f; + unsigned char* pixels = nullptr; + int tex_width = 0; + int tex_height = 0; + io.Fonts->GetTexDataAsRGBA32(&pixels, &tex_width, &tex_height); + io.Fonts->SetTexID(1); + + ImGui::NewFrame(); + ImGui::Begin("compat imgui smoke"); + ImGui::Text("ok"); + ImGui::End(); + ImGui::Render(); + + ImDrawData* draw_data = ImGui::GetDrawData(); + const bool ok = draw_data != nullptr && draw_data->Valid; + ImGui::DestroyContext(); + return ok ? 0 : 1; +} +EOF +"$MCPP_BIN" build +"$MCPP_BIN" run + +make_project "compat-xlibs-runtime-smoke" +cat >> mcpp.toml <<'EOF' + +[dependencies.compat] +xext = "1.3.7" +xrender = "0.9.12" +xfixes = "6.0.2" +xcursor = "1.2.3" +xinerama = "1.1.6" +xrandr = "1.5.5" +xi = "1.8.3" +EOF +cat > src/main.cpp <<'EOF' +#include +#include +#include +#include +#include +#include +#include +#include + +extern "C" int XextCreateExtension(void); + +int main() { + return XextCreateExtension != nullptr && + XRenderQueryExtension != nullptr && + XFixesQueryExtension != nullptr && + XcursorLibraryPath != nullptr && + XineramaQueryExtension != nullptr && + XRRQueryExtension != nullptr && + XIQueryVersion != nullptr ? 0 : 1; +} +EOF +"$MCPP_BIN" build +"$MCPP_BIN" run +if command -v readelf >/dev/null 2>&1; then + bin="$(find target -path '*/bin/compat-xlibs-runtime-smoke' -type f | head -1)" + for lib in libXext.so libXrender.so libXfixes.so libXcursor.so libXinerama.so libXrandr.so libXi.so; do + readelf -d "$bin" | grep -q "Shared library: \\[$lib\\]" + done +fi + +make_project "compat-glfw-runtime-smoke" +cat >> mcpp.toml <<'EOF' + +[dependencies.compat] +glfw = "3.4" +EOF +cat > src/main.cpp <<'EOF' +#include + +int main() { + glfwSetErrorCallback(nullptr); + const int ok = glfwInit(); + if (ok) { + glfwTerminate(); + } + return GLFW_VERSION_MAJOR == 3 ? 0 : 1; +} +EOF +"$MCPP_BIN" build +"$MCPP_BIN" run +if command -v readelf >/dev/null 2>&1; then + bin="$(find target -path '*/bin/compat-glfw-runtime-smoke' -type f | head -1)" + for lib in libX11.so libXcursor.so libXext.so libXfixes.so libXi.so libXinerama.so libXrandr.so libXrender.so; do + readelf -d "$bin" | grep -q "Shared library: \\[$lib\\]" + done +fi + +make_project "compat-xorg-runtime-smoke" +cat >> mcpp.toml <<'EOF' + +[dependencies.compat] +xau = "1.0.12" +xdmcp = "1.1.5" +EOF +cat > src/main.cpp <<'EOF' +#include +#include + +int main() { + ARRAY8 array{}; + const int allocated = XdmcpAllocARRAY8(&array, 1); + if (allocated) { + XdmcpDisposeARRAY8(&array); + } + + char* auth_file = XauFileName(); + return allocated && auth_file != nullptr ? 0 : 1; +} +EOF +"$MCPP_BIN" build +"$MCPP_BIN" run +if command -v readelf >/dev/null 2>&1; then + bin="$(find target -path '*/bin/compat-xorg-runtime-smoke' -type f | head -1)" + readelf -d "$bin" | grep -q 'Shared library: \[libXau.so\]' + readelf -d "$bin" | grep -q 'Shared library: \[libXdmcp.so\]' +fi + +make_project "compat-xcb-runtime-smoke" +cat >> mcpp.toml <<'EOF' + +[dependencies.compat] +xcb = "1.17.0" +EOF +cat > src/main.cpp <<'EOF' +#include +#include + +int main() { + char* host = nullptr; + int display = -1; + int screen = -1; + const int ok = xcb_parse_display(":0.1", &host, &display, &screen); + std::free(host); + return ok && display == 0 && screen == 1 ? 0 : 1; +} +EOF +"$MCPP_BIN" build +"$MCPP_BIN" run +if command -v readelf >/dev/null 2>&1; then + bin="$(find target -path '*/bin/compat-xcb-runtime-smoke' -type f | head -1)" + readelf -d "$bin" | grep -q 'Shared library: \[libxcb.so\]' +fi + +make_project "compat-x11-runtime-smoke" +cat >> mcpp.toml <<'EOF' + +[dependencies.compat] +x11 = "1.8.13" +EOF +cat > src/main.cpp <<'EOF' +#include +#include + +int main() { + const KeySym escape = XStringToKeysym("Escape"); + return X_PROTOCOL == 11 && escape == XK_Escape ? 0 : 1; +} +EOF +"$MCPP_BIN" build +"$MCPP_BIN" run +if command -v readelf >/dev/null 2>&1; then + bin="$(find target -path '*/bin/compat-x11-runtime-smoke' -type f | head -1)" + lib="$(find target -path '*/bin/libX11.so' -type f | head -1)" + readelf -d "$bin" | grep -q 'Shared library: \[libX11.so\]' + readelf -d "$lib" | grep -q 'Shared library: \[libxcb.so\]' +fi + +echo "OK" diff --git a/tests/smoke_compat_imgui_window.sh b/tests/smoke_compat_imgui_window.sh new file mode 100755 index 0000000..d280ac1 --- /dev/null +++ b/tests/smoke_compat_imgui_window.sh @@ -0,0 +1,258 @@ +#!/usr/bin/env bash +# Build a minimal Dear ImGui + GLFW + OpenGL window program through this +# checkout as a local mcpp path index. Runtime execution is optional because +# GLX/OpenGL driver libraries are host-specific. +set -euo pipefail + +ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +MCPP_BIN="${MCPP:-}" +if [[ -z "$MCPP_BIN" ]]; then + MCPP_BIN="$(command -v mcpp || true)" +fi +if [[ -z "$MCPP_BIN" || ! -x "$MCPP_BIN" ]]; then + echo "FATAL: set MCPP=/path/to/mcpp or put mcpp on PATH" >&2 + exit 1 +fi + +TMP="$(mktemp -d)" +if [[ "${MCPP_INDEX_KEEP_SMOKE_TMP:-0}" == "1" ]]; then + echo "KEEP: $TMP" +else + trap 'rm -rf "$TMP"' EXIT +fi +SMOKE_CACHE_DIR="${MCPP_INDEX_SMOKE_CACHE_DIR:-}" +SMOKE_XPKGS_DIR="${MCPP_INDEX_SMOKE_XPKGS_DIR:-}" + +export MCPP_HOME="$TMP/mcpp-home" +mkdir -p "$MCPP_HOME/registry/data/xpkgs" + +USER_MCPP="${HOME}/.mcpp" +link_xpkgs() { + local src="$1" + [[ -d "$src" ]] || return 0 + find "$src" -mindepth 1 -maxdepth 1 -type d | while read -r pkg; do + ln -s "$pkg" "$MCPP_HOME/registry/data/xpkgs/$(basename "$pkg")" 2>/dev/null || true + done +} +link_xpkgs "$SMOKE_XPKGS_DIR" +link_xpkgs "$USER_MCPP/registry/data/xpkgs" +if [[ -d "$USER_MCPP/registry/data/xim-pkgindex" ]]; then + mkdir -p "$MCPP_HOME/registry/data" + ln -s "$USER_MCPP/registry/data/xim-pkgindex" "$MCPP_HOME/registry/data/xim-pkgindex" 2>/dev/null || true +fi +if [[ -d "$USER_MCPP/registry/bin" ]]; then + mkdir -p "$MCPP_HOME/registry" + ln -s "$USER_MCPP/registry/bin" "$MCPP_HOME/registry/bin" 2>/dev/null || true +fi +if [[ -f "$USER_MCPP/config.toml" ]]; then + cp -f "$USER_MCPP/config.toml" "$MCPP_HOME/config.toml" 2>/dev/null || true +fi + +mkdir -p "$TMP/compat-imgui-window-smoke/src" +cd "$TMP/compat-imgui-window-smoke" +cat > mcpp.toml < src/main.cpp <<'EOF' +#include + +#include +#include +#include +#include + +#include "imgui_impl_glfw.cpp" +#include "imgui_impl_opengl3.cpp" + +int main() { + glfwSetErrorCallback([](int code, const char* message) { + std::fprintf(stderr, "GLFW error %d: %s\n", code, message ? message : ""); + }); + + if (!glfwInit()) { + return 10; + } + + glfwWindowHint(GLFW_VISIBLE, GLFW_FALSE); + glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 2); + glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0); + + GLFWwindow* window = glfwCreateWindow(320, 180, "mcpp compat imgui", nullptr, nullptr); + if (!window) { + glfwTerminate(); + return 11; + } + + glfwMakeContextCurrent(window); + + IMGUI_CHECKVERSION(); + ImGui::CreateContext(); + ImGuiIO& io = ImGui::GetIO(); + io.DisplaySize = ImVec2(320.0f, 180.0f); + io.DeltaTime = 1.0f / 60.0f; + + if (!ImGui_ImplGlfw_InitForOpenGL(window, true)) { + ImGui::DestroyContext(); + glfwDestroyWindow(window); + glfwTerminate(); + return 12; + } + if (!ImGui_ImplOpenGL3_Init("#version 110")) { + ImGui_ImplGlfw_Shutdown(); + ImGui::DestroyContext(); + glfwDestroyWindow(window); + glfwTerminate(); + return 13; + } + + ImGui_ImplOpenGL3_NewFrame(); + ImGui_ImplGlfw_NewFrame(); + ImGui::NewFrame(); + ImGui::Begin("compat imgui"); + ImGui::Text("hello from mcpp"); + ImGui::End(); + ImGui::Render(); + ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData()); + + ImGui_ImplOpenGL3_Shutdown(); + ImGui_ImplGlfw_Shutdown(); + ImGui::DestroyContext(); + glfwDestroyWindow(window); + glfwTerminate(); + return 0; +} +EOF + +"$MCPP_BIN" build + +bin="$(find target -path '*/bin/compat-imgui-window-smoke' -type f | head -1)" +if [[ -z "$bin" ]]; then + echo "FATAL: built binary not found" >&2 + exit 1 +fi + +if command -v readelf >/dev/null 2>&1; then + for lib in libX11.so libXcursor.so libXext.so libXfixes.so libXi.so libXinerama.so libXrandr.so libXrender.so; do + readelf -d "$bin" | grep -q "Shared library: \\[$lib\\]" + done +fi + +if [[ "${MCPP_INDEX_RUN_WINDOW_SMOKE:-0}" != "1" ]]; then + echo "SKIP: set MCPP_INDEX_RUN_WINDOW_SMOKE=1 to run the GLX/OpenGL window smoke" + echo "OK" + exit 0 +fi +if [[ -z "${DISPLAY:-}" ]]; then + echo "FATAL: DISPLAY is required for MCPP_INDEX_RUN_WINDOW_SMOKE=1" >&2 + exit 1 +fi + +bindir="$(dirname "$bin")" +shim="$TMP/gl-runtime-shim" +mkdir -p "$shim" + +HOST_GL_LIBDIR="${MCPP_INDEX_HOST_GL_LIBDIR:-/lib/x86_64-linux-gnu}" +if [[ ! -d "$HOST_GL_LIBDIR" ]]; then + echo "FATAL: host GL library directory not found: $HOST_GL_LIBDIR" >&2 + exit 1 +fi + +link_host_glob() { + local pattern="$1" + local matched=0 + for lib in "$HOST_GL_LIBDIR"/$pattern; do + [[ -e "$lib" ]] || continue + ln -sf "$lib" "$shim/$(basename "$lib")" + matched=1 + done + return $matched +} + +link_host_glob 'libGL*.so*' || true +link_host_glob 'libEGL*.so*' || true +link_host_glob 'libnvidia*.so*' || true +link_host_glob 'libglapi.so*' || true +link_host_glob 'libdrm.so*' || true +link_host_glob 'libxcb*.so*' || true +link_host_glob 'libX11-xcb.so*' || true +link_host_glob 'libX11.so*' || true +link_host_glob 'libXau.so*' || true +link_host_glob 'libXdmcp.so*' || true +link_host_glob 'libXext.so*' || true +link_host_glob 'libXfixes.so*' || true +link_host_glob 'libXrender.so*' || true +link_host_glob 'libXcursor.so*' || true +link_host_glob 'libXinerama.so*' || true +link_host_glob 'libXrandr.so*' || true +link_host_glob 'libXi.so*' || true +link_host_glob 'libXxf86vm.so*' || true +link_host_glob 'libexpat.so*' || true +link_host_glob 'libxshmfence.so*' || true +link_host_glob 'libbsd.so*' || true +link_host_glob 'libmd.so*' || true + +runpath="$(readelf -d "$bin" | sed -n 's/.*RUNPATH.*\[\(.*\)\].*/\1/p' | head -1)" +IFS=':' read -r -a runpath_dirs <<< "$runpath" +for dir in "${runpath_dirs[@]}"; do + for lib in libdl.so.2 libpthread.so.0 librt.so.1; do + [[ -e "$dir/$lib" ]] && ln -sf "$dir/$lib" "$shim/$lib" + done +done + +find_target_lib() { + local name="$1" + find target -path "*/bin/$name" -type f | head -1 +} + +link_compat_lib() { + local file="$1" + shift + local src + src="$(find_target_lib "$file")" + [[ -n "$src" ]] || return 0 + for soname in "$@"; do + ln -sf "$(cd "$(dirname "$src")" && pwd)/$(basename "$src")" "$shim/$soname" + done +} + +link_compat_lib libX11.so libX11.so libX11.so.6 +link_compat_lib libxcb.so libxcb.so libxcb.so.1 +link_compat_lib libXau.so libXau.so libXau.so.6 +link_compat_lib libXdmcp.so libXdmcp.so libXdmcp.so.6 +link_compat_lib libXext.so libXext.so libXext.so.6 +link_compat_lib libXfixes.so libXfixes.so libXfixes.so.3 +link_compat_lib libXrender.so libXrender.so libXrender.so.1 +link_compat_lib libXcursor.so libXcursor.so libXcursor.so.1 +link_compat_lib libXinerama.so libXinerama.so libXinerama.so.1 +link_compat_lib libXrandr.so libXrandr.so libXrandr.so.2 +link_compat_lib libXi.so libXi.so libXi.so.6 + +LD_LIBRARY_PATH="$shim${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}" "$bin" +echo "OK" From fa2bdfaac4c29ca49572aa53112a2173a86db0ea Mon Sep 17 00:00:00 2001 From: sunrisepeak Date: Mon, 1 Jun 2026 05:51:19 +0800 Subject: [PATCH 2/4] ci: wire vendored xlings for compat smoke --- .github/workflows/validate.yml | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/.github/workflows/validate.yml b/.github/workflows/validate.yml index 7d4d9da..a76f438 100644 --- a/.github/workflows/validate.yml +++ b/.github/workflows/validate.yml @@ -56,10 +56,13 @@ jobs: curl -L -fsS -o mcpp.tar.gz \ "https://github.com/mcpp-community/mcpp/releases/download/v${MCPP_VERSION}/mcpp-${MCPP_VERSION}-linux-x86_64.tar.gz" tar -xzf mcpp.tar.gz - echo "$PWD/mcpp-${MCPP_VERSION}-linux-x86_64/bin" >> "$GITHUB_PATH" + root="$PWD/mcpp-${MCPP_VERSION}-linux-x86_64" + echo "MCPP=$root/bin/mcpp" >> "$GITHUB_ENV" + echo "MCPP_VENDORED_XLINGS=$root/registry/bin/xlings" >> "$GITHUB_ENV" + echo "$root/bin" >> "$GITHUB_PATH" - name: Run compat smoke tests run: | - mcpp --version + "$MCPP" --version timeout 1800 bash tests/smoke_compat_core.sh timeout 1800 bash tests/smoke_compat_imgui.sh timeout 1800 bash tests/smoke_compat_archive.sh From c2a1e896e03a62f7871a0d4faaf6b271931aace6 Mon Sep 17 00:00:00 2001 From: sunrisepeak Date: Mon, 1 Jun 2026 06:07:30 +0800 Subject: [PATCH 3/4] fix: align compat hook deps with mcpp deps --- pkgs/c/compat.glfw.lua | 80 +++++++++++++++++++++--------------------- pkgs/c/compat.x11.lua | 3 -- pkgs/c/compat.xcb.lua | 6 ++-- 3 files changed, 43 insertions(+), 46 deletions(-) diff --git a/pkgs/c/compat.glfw.lua b/pkgs/c/compat.glfw.lua index e9271a3..df076d4 100644 --- a/pkgs/c/compat.glfw.lua +++ b/pkgs/c/compat.glfw.lua @@ -32,21 +32,21 @@ package = { language = "c++23", import_std = false, c_standard = "c11", - include_dirs = {"*/include", "*/src"}, + include_dirs = {"include", "src"}, sources = { - "*/src/context.c", - "*/src/init.c", - "*/src/input.c", - "*/src/monitor.c", - "*/src/platform.c", - "*/src/vulkan.c", - "*/src/window.c", - "*/src/egl_context.c", - "*/src/osmesa_context.c", - "*/src/null_init.c", - "*/src/null_monitor.c", - "*/src/null_window.c", - "*/src/null_joystick.c", + "src/context.c", + "src/init.c", + "src/input.c", + "src/monitor.c", + "src/platform.c", + "src/vulkan.c", + "src/window.c", + "src/egl_context.c", + "src/osmesa_context.c", + "src/null_init.c", + "src/null_monitor.c", + "src/null_window.c", + "src/null_joystick.c", }, targets = { ["glfw"] = { kind = "lib" } }, deps = { @@ -55,16 +55,16 @@ package = { linux = { cflags = { "-D_DEFAULT_SOURCE", "-D_GLFW_X11" }, sources = { - "*/src/x11_init.c", - "*/src/x11_monitor.c", - "*/src/x11_window.c", - "*/src/xkb_unicode.c", - "*/src/glx_context.c", - "*/src/linux_joystick.c", - "*/src/posix_poll.c", - "*/src/posix_time.c", - "*/src/posix_thread.c", - "*/src/posix_module.c", + "src/x11_init.c", + "src/x11_monitor.c", + "src/x11_window.c", + "src/xkb_unicode.c", + "src/glx_context.c", + "src/linux_joystick.c", + "src/posix_poll.c", + "src/posix_time.c", + "src/posix_thread.c", + "src/posix_module.c", }, deps = { ["compat.x11"] = "1.8.13", @@ -81,14 +81,14 @@ package = { macosx = { cflags = { "-D_GLFW_COCOA" }, sources = { - "*/src/cocoa_time.c", - "*/src/posix_thread.c", - "*/src/posix_module.c", - "*/src/cocoa_init.m", - "*/src/cocoa_joystick.m", - "*/src/cocoa_monitor.m", - "*/src/cocoa_window.m", - "*/src/nsgl_context.m", + "src/cocoa_time.c", + "src/posix_thread.c", + "src/posix_module.c", + "src/cocoa_init.m", + "src/cocoa_joystick.m", + "src/cocoa_monitor.m", + "src/cocoa_window.m", + "src/nsgl_context.m", }, ldflags = { "-framework", "Cocoa", @@ -99,14 +99,14 @@ package = { windows = { cflags = { "-D_GLFW_WIN32", "-DUNICODE", "-D_UNICODE" }, sources = { - "*/src/win32_time.c", - "*/src/win32_thread.c", - "*/src/win32_module.c", - "*/src/win32_init.c", - "*/src/win32_joystick.c", - "*/src/win32_monitor.c", - "*/src/win32_window.c", - "*/src/wgl_context.c", + "src/win32_time.c", + "src/win32_thread.c", + "src/win32_module.c", + "src/win32_init.c", + "src/win32_joystick.c", + "src/win32_monitor.c", + "src/win32_window.c", + "src/wgl_context.c", }, ldflags = { "-lgdi32" }, }, diff --git a/pkgs/c/compat.x11.lua b/pkgs/c/compat.x11.lua index b83d71e..c6cee3c 100644 --- a/pkgs/c/compat.x11.lua +++ b/pkgs/c/compat.x11.lua @@ -9,9 +9,6 @@ package = { xpm = { linux = { - deps = { - "compat:compat.xorgproto@2025.1", - }, ["1.8.13"] = { url = "https://xorg.freedesktop.org/releases/individual/lib/libX11-1.8.13.tar.gz", sha256 = "acf0e7cd7541110e6330ecb539441a2d53061f386ec7be6906dfde0de2598470", diff --git a/pkgs/c/compat.xcb.lua b/pkgs/c/compat.xcb.lua index 572eda5..00c426a 100644 --- a/pkgs/c/compat.xcb.lua +++ b/pkgs/c/compat.xcb.lua @@ -10,7 +10,6 @@ package = { xpm = { linux = { deps = { - "compat:compat.xcb-proto@1.17.0", "python@latest", }, ["1.17.0"] = { @@ -45,8 +44,9 @@ package = { }, targets = { ["xcb"] = { kind = "shared" } }, deps = { - ["compat.xau"] = "1.0.12", - ["compat.xdmcp"] = "1.1.5", + ["compat.xau"] = "1.0.12", + ["compat.xcb-proto"] = "1.17.0", + ["compat.xdmcp"] = "1.1.5", }, }, } From 2ce2721ee6d60c7653764f63c71be51914474b3f Mon Sep 17 00:00:00 2001 From: sunrisepeak Date: Mon, 1 Jun 2026 08:33:50 +0800 Subject: [PATCH 4/4] fix: isolate compat smoke dependencies --- .github/workflows/validate.yml | 2 +- .gitignore | 1 + pkgs/c/compat.xcb.lua | 2 +- tests/smoke_compat_archive.sh | 6 ++++-- tests/smoke_compat_core.sh | 6 ++++-- tests/smoke_compat_imgui.sh | 12 +++++++++--- tests/smoke_compat_imgui_window.sh | 6 ++++-- 7 files changed, 24 insertions(+), 11 deletions(-) create mode 100644 .gitignore diff --git a/.github/workflows/validate.yml b/.github/workflows/validate.yml index a76f438..333d96b 100644 --- a/.github/workflows/validate.yml +++ b/.github/workflows/validate.yml @@ -51,7 +51,7 @@ jobs: - uses: actions/checkout@v4 - name: Download mcpp env: - MCPP_VERSION: "0.0.38" + MCPP_VERSION: "0.0.40" run: | curl -L -fsS -o mcpp.tar.gz \ "https://github.com/mcpp-community/mcpp/releases/download/v${MCPP_VERSION}/mcpp-${MCPP_VERSION}-linux-x86_64.tar.gz" diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..af16046 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +.xlings-index-cache.json diff --git a/pkgs/c/compat.xcb.lua b/pkgs/c/compat.xcb.lua index 00c426a..4342e5e 100644 --- a/pkgs/c/compat.xcb.lua +++ b/pkgs/c/compat.xcb.lua @@ -10,7 +10,7 @@ package = { xpm = { linux = { deps = { - "python@latest", + "xim:python@latest", }, ["1.17.0"] = { url = "https://xorg.freedesktop.org/releases/individual/lib/libxcb-1.17.0.tar.xz", diff --git a/tests/smoke_compat_archive.sh b/tests/smoke_compat_archive.sh index 8ab8bec..94d3a41 100755 --- a/tests/smoke_compat_archive.sh +++ b/tests/smoke_compat_archive.sh @@ -27,14 +27,16 @@ link_xpkgs() { local src="$1" [[ -d "$src" ]] || return 0 find "$src" -mindepth 1 -maxdepth 1 -type d | while read -r pkg; do + [[ "$(basename "$pkg")" == compat-x-* ]] && continue ln -s "$pkg" "$MCPP_HOME/registry/data/xpkgs/$(basename "$pkg")" 2>/dev/null || true done } link_xpkgs "$SMOKE_XPKGS_DIR" link_xpkgs "$USER_MCPP/registry/data/xpkgs" if [[ -d "$USER_MCPP/registry/data/xim-pkgindex" ]]; then - mkdir -p "$MCPP_HOME/registry/data" - ln -s "$USER_MCPP/registry/data/xim-pkgindex" "$MCPP_HOME/registry/data/xim-pkgindex" 2>/dev/null || true + mkdir -p "$MCPP_HOME/registry/data/xim-pkgindex" + cp -a "$USER_MCPP/registry/data/xim-pkgindex/." "$MCPP_HOME/registry/data/xim-pkgindex/" 2>/dev/null || true + rm -f "$MCPP_HOME/registry/data/xim-pkgindex/.xlings-index-cache.json" fi if [[ -d "$USER_MCPP/registry/bin" ]]; then mkdir -p "$MCPP_HOME/registry" diff --git a/tests/smoke_compat_core.sh b/tests/smoke_compat_core.sh index 0a6bdc1..ce26dcc 100755 --- a/tests/smoke_compat_core.sh +++ b/tests/smoke_compat_core.sh @@ -26,14 +26,16 @@ link_xpkgs() { local src="$1" [[ -d "$src" ]] || return 0 find "$src" -mindepth 1 -maxdepth 1 -type d | while read -r pkg; do + [[ "$(basename "$pkg")" == compat-x-* ]] && continue ln -s "$pkg" "$MCPP_HOME/registry/data/xpkgs/$(basename "$pkg")" 2>/dev/null || true done } link_xpkgs "$SMOKE_XPKGS_DIR" link_xpkgs "$USER_MCPP/registry/data/xpkgs" if [[ -d "$USER_MCPP/registry/data/xim-pkgindex" ]]; then - mkdir -p "$MCPP_HOME/registry/data" - ln -s "$USER_MCPP/registry/data/xim-pkgindex" "$MCPP_HOME/registry/data/xim-pkgindex" 2>/dev/null || true + mkdir -p "$MCPP_HOME/registry/data/xim-pkgindex" + cp -a "$USER_MCPP/registry/data/xim-pkgindex/." "$MCPP_HOME/registry/data/xim-pkgindex/" 2>/dev/null || true + rm -f "$MCPP_HOME/registry/data/xim-pkgindex/.xlings-index-cache.json" fi if [[ -d "$USER_MCPP/registry/bin" ]]; then mkdir -p "$MCPP_HOME/registry" diff --git a/tests/smoke_compat_imgui.sh b/tests/smoke_compat_imgui.sh index a7261c7..0b4eb50 100755 --- a/tests/smoke_compat_imgui.sh +++ b/tests/smoke_compat_imgui.sh @@ -14,7 +14,11 @@ if [[ -z "$MCPP_BIN" || ! -x "$MCPP_BIN" ]]; then fi TMP="$(mktemp -d)" -trap 'rm -rf "$TMP"' EXIT +if [[ "${MCPP_INDEX_KEEP_SMOKE_TMP:-0}" == "1" ]]; then + echo "KEEP: $TMP" +else + trap 'rm -rf "$TMP"' EXIT +fi SMOKE_CACHE_DIR="${MCPP_INDEX_SMOKE_CACHE_DIR:-}" SMOKE_XPKGS_DIR="${MCPP_INDEX_SMOKE_XPKGS_DIR:-}" @@ -27,14 +31,16 @@ link_xpkgs() { local src="$1" [[ -d "$src" ]] || return 0 find "$src" -mindepth 1 -maxdepth 1 -type d | while read -r pkg; do + [[ "$(basename "$pkg")" == compat-x-* ]] && continue ln -s "$pkg" "$MCPP_HOME/registry/data/xpkgs/$(basename "$pkg")" 2>/dev/null || true done } link_xpkgs "$SMOKE_XPKGS_DIR" link_xpkgs "$USER_MCPP/registry/data/xpkgs" if [[ -d "$USER_MCPP/registry/data/xim-pkgindex" ]]; then - mkdir -p "$MCPP_HOME/registry/data" - ln -s "$USER_MCPP/registry/data/xim-pkgindex" "$MCPP_HOME/registry/data/xim-pkgindex" 2>/dev/null || true + mkdir -p "$MCPP_HOME/registry/data/xim-pkgindex" + cp -a "$USER_MCPP/registry/data/xim-pkgindex/." "$MCPP_HOME/registry/data/xim-pkgindex/" 2>/dev/null || true + rm -f "$MCPP_HOME/registry/data/xim-pkgindex/.xlings-index-cache.json" fi if [[ -d "$USER_MCPP/registry/bin" ]]; then mkdir -p "$MCPP_HOME/registry" diff --git a/tests/smoke_compat_imgui_window.sh b/tests/smoke_compat_imgui_window.sh index d280ac1..f0c7e5a 100755 --- a/tests/smoke_compat_imgui_window.sh +++ b/tests/smoke_compat_imgui_window.sh @@ -31,14 +31,16 @@ link_xpkgs() { local src="$1" [[ -d "$src" ]] || return 0 find "$src" -mindepth 1 -maxdepth 1 -type d | while read -r pkg; do + [[ "$(basename "$pkg")" == compat-x-* ]] && continue ln -s "$pkg" "$MCPP_HOME/registry/data/xpkgs/$(basename "$pkg")" 2>/dev/null || true done } link_xpkgs "$SMOKE_XPKGS_DIR" link_xpkgs "$USER_MCPP/registry/data/xpkgs" if [[ -d "$USER_MCPP/registry/data/xim-pkgindex" ]]; then - mkdir -p "$MCPP_HOME/registry/data" - ln -s "$USER_MCPP/registry/data/xim-pkgindex" "$MCPP_HOME/registry/data/xim-pkgindex" 2>/dev/null || true + mkdir -p "$MCPP_HOME/registry/data/xim-pkgindex" + cp -a "$USER_MCPP/registry/data/xim-pkgindex/." "$MCPP_HOME/registry/data/xim-pkgindex/" 2>/dev/null || true + rm -f "$MCPP_HOME/registry/data/xim-pkgindex/.xlings-index-cache.json" fi if [[ -d "$USER_MCPP/registry/bin" ]]; then mkdir -p "$MCPP_HOME/registry"