From 39cca3ec888ca512b876d7f3af86a877128123dc Mon Sep 17 00:00:00 2001 From: sunrisepeak Date: Fri, 11 Sep 2026 02:33:50 +0800 Subject: [PATCH 01/10] feat(huxerui): the descriptor, and the two reasons it cannot land yet MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Form A entry for the HuxerUI SDK plus its workspace member. The descriptor is finished and `mcpp xpkg parse` accepts it -- "form A, no mcpp segment". What is NOT finished is the thing the index actually promises, that a consumer can build the package, so this is committed as the record of where it stops rather than opened as a PR. WHAT THE DESCRIPTOR DECIDES `xpm.linux.deps` carries the 36-entry GTK closure by hand. Upstream declares it on the target axis, which is the form mcpp recommends and which a descriptor structurally cannot carry: three platform blocks, and a cfg selector is not a platform. Consumer edges therefore come from this file, at PLATFORM level -- a per-version `deps` is inert, the same finding compat.eui-neo records. Omitting them would let a consumer resolve, build, and die at link on the GTK sonames. `licenses` and `repo` deliberately disagree with `mcpp emit xpkg`, which emits Apache-2.0 and Sunrisepeak/HuxerUI. The v0.3.0 tree's LICENSE is MIT verbatim and the canonical repo is HuxerUI/HuxerUI; upstream's mcpp.toml is wrong on both and is being corrected separately. No `mcpp` segment: pasting emit's table form makes the parser read this as an inline Form B and refuse it for missing `sources`. WHY IT CANNOT LAND 1. VERSION FLOOR. v0.3.0's mcpp/huxerui-build-rules calls `mcpp::package_name()` and `mcpp::package_namespace()`, added in mcpp #587 (2026-09-08) and first released in v2026.9.7.1. validate.yml pins MCPP_VERSION 2026.9.6.3, one release short, so the host module fails to compile: `'package_name' is not a member of 'mcpp'`. 2. ACTION BUFFER OVERFLOW, and this one survives a newer mcpp. On 2026.9.10.2 the build gets past (1) and dies in build.mcpp: build.mcpp declared an action whose arguments did not fit payload: {"id":"hrc:builtin", … "overflow":true} `mcpp::action` uses fixed buffers -- `inputs_[8192]` -- and the hrc:builtin action enumerates all 44 files under resources/. Measured: as a dependency those paths total 8131 bytes, plus ~106 for the hrc binary, against a 8192-byte cap. In-tree the same list is 1531 bytes, and the same source builds clean in 21.45s. So the trigger is the 149-character dependency unpack prefix, not the file count, and it overflows by roughly 45 bytes. That is worse than a clean failure: whether a consumer builds depends on how deep their project sits on disk. mcpp's own error names the fix -- declare the resources DIRECTORY as one input instead of enumerating it -- and that belongs in huxerui-build-rules, not here. No CN mirror yet: mirroring a version that cannot be consumed would publish a promise this index cannot keep. --- mcpp.toml | 1 + pkgs/h/huxerui.huxerui.lua | 154 ++++++++++++++++++ tests/examples/huxerui-module/mcpp.toml | 11 ++ .../examples/huxerui-module/tests/runtime.cpp | 30 ++++ 4 files changed, 196 insertions(+) create mode 100644 pkgs/h/huxerui.huxerui.lua create mode 100644 tests/examples/huxerui-module/mcpp.toml create mode 100644 tests/examples/huxerui-module/tests/runtime.cpp diff --git a/mcpp.toml b/mcpp.toml index ce33498..afc37cd 100644 --- a/mcpp.toml +++ b/mcpp.toml @@ -56,6 +56,7 @@ members = [ "tests/examples/ftxui-module", "tests/examples/gmp", "tests/examples/gzip-hpp", + "tests/examples/huxerui-module", "tests/examples/gmp-gmpxx", "tests/examples/godot-cpp", "tests/examples/godot-cpp-module", diff --git a/pkgs/h/huxerui.huxerui.lua b/pkgs/h/huxerui.huxerui.lua new file mode 100644 index 0000000..556377a --- /dev/null +++ b/pkgs/h/huxerui.huxerui.lua @@ -0,0 +1,154 @@ +-- huxerui.huxerui — the HuxerUI SDK as a native mcpp module package. +-- +-- Form A: upstream carries its own `mcpp.toml`, so this descriptor declares +-- metadata and a download address and nothing else about the build. mcpp's +-- default lookup finds `/*/mcpp.toml` inside the GitHub tag archive's +-- `HuxerUI-0.3.0/` wrap. `import huxerui;` is upstream's own module interface +-- (`modules/huxerui.cppm`), not one authored here. +-- +-- ── Two fields deliberately DISAGREE with `mcpp emit xpkg` ──────────────── +-- +-- Running `mcpp emit xpkg` against the v0.3.0 tag emits `Apache-2.0` and +-- `github.com/Sunrisepeak/HuxerUI`. Both are wrong at the source and are +-- corrected here rather than copied: +-- +-- * LICENSE in the v0.3.0 tree is the MIT License, verbatim, and the +-- xim-pkgindex entry for the same SDK has always said MIT. The +-- `license = "Apache-2.0"` line in upstream's mcpp.toml is a typo that +-- seven manifests in that repo share; it is being fixed upstream +-- separately. An index must not restate a licence its own artifact +-- contradicts, so this says MIT. +-- * `Sunrisepeak/HuxerUI` is the author's personal remote. The canonical +-- repository -- the one that publishes the releases this descriptor +-- downloads, and the one the README's installer URLs point at -- is +-- `HuxerUI/HuxerUI`. +-- +-- Re-emitting over this file would reintroduce both, which is why the +-- "AUTO-GENERATED / do not edit by hand" banner is NOT carried here: this +-- descriptor is hand-maintained on purpose. +-- +-- ── Why `xpm.linux.deps` is written out by hand ─────────────────────────── +-- +-- Upstream declares the GTK4 stack on the TARGET axis +-- (`[target.'cfg(linux)'.xlings.workspace]`), which is the form mcpp +-- recommends for anything the produced code is compiled or linked against -- +-- and `mcpp emit xpkg` says, correctly, that it can carry no edge for it: +-- +-- [target.'cfg(linux)'] declares tools (xim:cairo@1.18.4, …) and the +-- descriptor carries no edge for them: its blocks are per platform, and +-- a selector is not a platform. +-- +-- A descriptor has three platform blocks; a target selector is a cfg +-- expression and does not fit in one. Consumer dependencies therefore come +-- from this file, and if they were simply omitted a consumer would resolve +-- huxerui, build it, and die at link with the GTK sonames missing. +-- +-- So the closure is transcribed here, at PLATFORM level (a per-version +-- `deps` does not take effect -- the same finding compat.eui-neo and +-- compat.glx-runtime record). The 36 entries and their pins are copied +-- verbatim from the v0.3.0 tag's own mcpp.toml, which documents them as the +-- transitive .pc closure of gtk4 + epoxy + libsoup. They are what the +-- package's build compiles against AND what its consumer must have, so no +-- `runtime = { … }` split applies. +-- +-- Keeping this list in step with upstream's is manual until mcpp can derive +-- consumer dependencies from the target axis. A missing entry surfaces as +-- `Package was not found in the pkg-config search path`, which names it. +-- +-- macOS needs no payloads: upstream's platform layer binds AppKit/Metal and +-- friends through `[runtime] frameworks`, which the system SDK provides. +-- windows carries `xim:wix` because upstream declares it on the HOST axis +-- (top-level `[xlings.workspace]`) -- wix.exe runs on the build machine -- +-- and that IS emitted, so it is kept as emitted. +package = { + spec = "1", + namespace = "huxerui", + -- FULLY-QUALIFIED, per mcpp#278 (INV-NAME). `namespace` plus a bare + -- `name` is the split form, which parses but can never be installed. + name = "huxerui.huxerui", + description = "HuxerUI — declarative cross-platform UI framework in C++20 (GTK4 on Linux, Win32/Direct2D, AppKit/Metal)", + licenses = {"MIT"}, + repo = "https://github.com/HuxerUI/HuxerUI", + type = "package", + + xpm = { + linux = { + -- The transitive .pc closure of gtk4 + epoxy + libsoup, pinned, + -- copied from the v0.3.0 tag's [target.'cfg(linux)'.xlings.workspace]. + deps = { + "xim:cairo@1.18.4", + "xim:expat@2.6.2", + "xim:fontconfig@2.15.0.1", + "xim:freetype@2.13.2", + "xim:fribidi@1.0.13", + "xim:gdk-pixbuf@2.44.8", + "xim:glib@2.88.3", + "xim:graphene@1.10.8", + "xim:gtk4@4.16.13", + "xim:harfbuzz@14.4.0", + "xim:libX11@1.8.10", + "xim:libXau@1.0.11", + "xim:libXdmcp@1.1.5", + "xim:libXext@1.3.6", + "xim:libXft@2.3.9", + "xim:libXrender@0.9.11", + "xim:libdatrie@0.2.14", + "xim:libepoxy@1.5.10", + "xim:libffi@3.4.4", + "xim:libglvnd@1.7.0.1", + "xim:libjpeg-turbo@3.2.0", + "xim:libpng@1.6.43", + "xim:libpsl@0.23.3", + "xim:libselinux@3.11", + "xim:libsoup@3.6.6", + "xim:libthai@0.1.30", + "xim:libtiff@4.7.2", + "xim:libxcb@1.17.0", + "xim:nghttp2@1.70.0", + "xim:pango@1.52.1", + "xim:pcre2@10.42", + "xim:pixman@0.42.2", + "xim:sqlite@3.53.4", + "xim:util-linux@2.40.2", + "xim:xorgproto@2024.1", + "xim:zlib@1.3.1", + }, + ["0.3.0"] = { + url = { + GLOBAL = "https://github.com/HuxerUI/HuxerUI/archive/refs/tags/v0.3.0.tar.gz", + CN = "https://gitcode.com/mcpp-res/huxerui/releases/download/0.3.0/huxerui-0.3.0.tar.gz", + }, + sha256 = "8b326d95015e92925229fdc1ababe4fdf32515e75764472591645622c1cfbb08", + }, + }, + macosx = { + ["0.3.0"] = { + url = { + GLOBAL = "https://github.com/HuxerUI/HuxerUI/archive/refs/tags/v0.3.0.tar.gz", + CN = "https://gitcode.com/mcpp-res/huxerui/releases/download/0.3.0/huxerui-0.3.0.tar.gz", + }, + sha256 = "8b326d95015e92925229fdc1ababe4fdf32515e75764472591645622c1cfbb08", + }, + }, + windows = { + -- HOST axis, and emitted as such: wix.exe runs on the build + -- machine. Only a project that builds an MSI reaches it. + deps = { "xim:wix@5.0.2" }, + ["0.3.0"] = { + url = { + GLOBAL = "https://github.com/HuxerUI/HuxerUI/archive/refs/tags/v0.3.0.tar.gz", + CN = "https://gitcode.com/mcpp-res/huxerui/releases/download/0.3.0/huxerui-0.3.0.tar.gz", + }, + sha256 = "8b326d95015e92925229fdc1ababe4fdf32515e75764472591645622c1cfbb08", + }, + }, + }, + + -- NO `mcpp` SEGMENT, deliberately. This is shape D (external Form-A module + -- repo): the tag archive carries `HuxerUI-0.3.0/mcpp.toml`, and mcpp's + -- default lookup finds `/*/mcpp.toml` there. `mcpp emit xpkg` + -- prints a table-form segment aimed at the publish flow; pasting it here + -- makes the parser read this as an INLINE (Form B) descriptor and refuse + -- it -- `synthesised manifest missing sources (mcpp segment must declare + -- \`sources = { ... }\`)`. imgui.lua carries the same note. +} diff --git a/tests/examples/huxerui-module/mcpp.toml b/tests/examples/huxerui-module/mcpp.toml new file mode 100644 index 0000000..23f6f8e --- /dev/null +++ b/tests/examples/huxerui-module/mcpp.toml @@ -0,0 +1,11 @@ +# A member-level redirect replaces the workspace root's compat redirect, so +# this test resolves huxerui.huxerui from the current checkout. +[indices] +huxerui = { path = "../../.." } + +[package] +name = "huxerui-module-tests" +version = "0.1.0" + +[dependencies.huxerui] +huxerui = "0.3.0" diff --git a/tests/examples/huxerui-module/tests/runtime.cpp b/tests/examples/huxerui-module/tests/runtime.cpp new file mode 100644 index 0000000..baa6044 --- /dev/null +++ b/tests/examples/huxerui-module/tests/runtime.cpp @@ -0,0 +1,30 @@ +// HuxerUI is a GUI framework, and this test opens no window: a CI runner has +// no display, and the point here is that the PACKAGE resolves, builds and +// links, not that GTK can paint. +// +// The last assertion is the one that carries that weight. Rect/Color are +// header-attached entities that `import huxerui;` re-exports, so on their own +// they would still compile if libhuxerui had never been built. +// FlatLightThemeSpec/FlatDarkThemeSpec are out-of-line definitions living in +// the library itself, so reaching them is what proves the link. +import std; +import huxerui; + +using huxerui::Color; +using huxerui::Point; +using huxerui::Rect; + +int main() { + const Rect bounds{10.0F, 20.0F, 100.0F, 50.0F}; + const bool inside = bounds.Contains(Point{60.0F, 40.0F}); + const bool outside = !bounds.Contains(Point{5.0F, 40.0F}); + + // Rgba32 decodes 0xRRGGBBAA, so this is opaque orange. + const Color orange = Color::Rgba32(0xFF8000FFU); + const bool decoded = orange == Color::Rgb(255, 128, 0); + + const bool themes_differ = + !(huxerui::FlatLightThemeSpec() == huxerui::FlatDarkThemeSpec()); + + return (inside && outside && decoded && themes_differ) ? 0 : 1; +} From 7f28bd99e40587e3da4f1b2d5ff352cc656340cd Mon Sep 17 00:00:00 2001 From: sunrisepeak Date: Fri, 11 Sep 2026 02:44:47 +0800 Subject: [PATCH 02/10] feat(huxerui): 0.3.0, and a CI pin that follows the engine MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The descriptor and its member landed in the previous commit as a record of two blockers. One turned out not to be a blocker at all and the other is fixed here, so this completes the addition. THE OVERFLOW WAS THE MEASUREMENT, NOT THE PACKAGE The `hrc:builtin` action was reported as overflowing mcpp's fixed `inputs_[8192]`. It does -- at a 149-character unpack prefix. Measured across three path lengths, the same source and the same engine: 149 chars (deep local checkout) 8131 B + ~106 B overflows 109 chars (ordinary path) 6371 B builds in-tree, relative 1531 B builds, 21.45s So the trigger is the prefix, not the file count, and it clears at any ordinary checkout depth. It is still a real trap -- roughly 45 bytes of margin, decided by how deep a consumer's project sits -- and mcpp's own error names the fix (declare the resources DIRECTORY as one input rather than enumerating 44 files). That belongs in huxerui-build-rules and is filed there; working around it in this index would be the wrong place. THE PIN, WHICH IS A REAL BLOCKER AND MOVES HERE `mcpp/huxerui-build-rules` calls `mcpp::package_name()` and `mcpp::package_namespace()` -- mcpp#587, first released in v2026.9.7.1 -- so under the old 2026.9.6.3 pin the host module does not compile: rules.cppm:274:61: error: 'package_name' is not a member of 'mcpp' #361 established the pattern for exactly this, down to the reasoning: a package whose build program uses a current engine API is not a defect, a CI that cannot run current engines is. MCPP_VERSION moves to 2026.9.10.2. `index.toml` min_mcpp does NOT move, and that is verified rather than assumed: `mcpp xpkg parse` accepts this descriptor under 2026.8.27.2 (the floor), 2026.9.6.3 and 2026.9.10.2 alike. The floor is about descriptor grammar; only BUILDING this package needs the newer engine, so a client on the floor keeps resolving the whole index. VERIFIED mcpp test -p huxerui-module → test result ok. 1 passed same, on 2026.9.6.3 → 'package_name' is not a member assertion inverted → FAILED. 0 passed; 1 failed The last one matters: the test opens no window, and Rect/Color alone would compile even if libhuxerui had never been built. FlatLightThemeSpec and FlatDarkThemeSpec are out-of-line definitions inside the library, so reaching them is what proves the link -- and inverting the check proves the assertion is live. CN mirror mcpp-res/huxerui@0.3.0 is up and byte-identical to GLOBAL (http 200, 9946045 bytes, sha 8b326d95…). All five lint checks pass on the new descriptor, and the three repo-wide ones pass across pkgs/*/*.lua. The pin move pays the cold-cache cost the workflow comment warns about, so any other descriptor waiting on a newer engine should ride along. --- .agents/docs/2026-09-11-add-huxerui-plan.md | 202 ++++++++++++++++++++ .github/workflows/validate.yml | 26 ++- README.md | 3 +- README.zh-CN.md | 2 +- 4 files changed, 230 insertions(+), 3 deletions(-) create mode 100644 .agents/docs/2026-09-11-add-huxerui-plan.md diff --git a/.agents/docs/2026-09-11-add-huxerui-plan.md b/.agents/docs/2026-09-11-add-huxerui-plan.md new file mode 100644 index 0000000..f1581d0 --- /dev/null +++ b/.agents/docs/2026-09-11-add-huxerui-plan.md @@ -0,0 +1,202 @@ +# Adding `huxerui.huxerui` 0.3.0 to mcpp-index + +> 2026-09-11 · Form A (shape D, external Form-A module repo) · PR: add HuxerUI + a CI pin that follows the engine + +## 1. Shape + +Source category (b) — a library developed **on** mcpp. Upstream carries its own +`mcpp.toml` (`[lib] path = "modules/huxerui.cppm"`, `[build-dependencies]` for +two code generators and a rule module, `build.mcpp` driving them), so this is +**Form A**: the descriptor declares metadata plus a download address, and every +build fact comes from the source's own manifest. + +No `mcpp` segment. `mcpp emit xpkg` prints a table-form one aimed at the publish +flow; pasting it here makes the parser read the descriptor as an **inline +Form B** and refuse it: + +``` +error: synthesised manifest missing sources (mcpp segment must declare `sources = { ... }`) +``` + +Omitting it lets mcpp's default lookup find `/*/mcpp.toml`, which the +tag archive provides at `HuxerUI-0.3.0/mcpp.toml`. `imgui.lua` carries the same +note. `mcpp xpkg parse` then reports `form A — no mcpp segment`. + +## 2. Source and hash + +v0.3.0's release publishes SDK **binaries** only — no source asset — so the +url is GitHub's tag archive, the same form `imgui-m` uses: + +``` +https://github.com/HuxerUI/HuxerUI/archive/refs/tags/v0.3.0.tar.gz +sha256 8b326d95015e92925229fdc1ababe4fdf32515e75764472591645622c1cfbb08 +``` + +Downloaded twice, sha identical both times (9 946 045 bytes). Wrap layer is +`HuxerUI-0.3.0/`, absorbed by the default lookup. + +## 3. Two fields that deliberately disagree with `emit xpkg` + +Emit produces `licenses = {"Apache-2.0"}` and +`repo = "https://github.com/Sunrisepeak/HuxerUI"`. Both are wrong at the source: + +* The v0.3.0 tree's `LICENSE` is the **MIT** License verbatim, and + xim-pkgindex's entry for the same SDK has always said MIT. Upstream's + `license = "Apache-2.0"` is a typo shared by seven manifests in that repo and + is being corrected separately. An index must not restate a licence its own + artifact contradicts. +* `Sunrisepeak/HuxerUI` is the author's personal remote; the canonical + repository — the one publishing the releases this descriptor downloads — is + `HuxerUI/HuxerUI`. + +The descriptor is therefore hand-maintained and does **not** carry emit's +"AUTO-GENERATED / do not edit by hand" banner. Re-emitting over it would +reintroduce both. (`aimol.tensorvia-cpu` is the cautionary case: it still +carries that banner while having been hand-edited.) + +Naming follows mcpp#278 (INV-NAME): `namespace = "huxerui"` **and** the +fully-qualified `name = "huxerui.huxerui"`. The split form — namespace plus a +bare name — parses but can never be installed. + +## 4. `xpm.linux.deps`, and why it is written out by hand + +Upstream declares the GTK4 stack on the **target axis**: + +```toml +[target.'cfg(linux)'.xlings.workspace] +"xim:gtk4" = "4.16.13" # …36 entries, the transitive .pc closure +``` + +which is the form mcpp recommends for anything the produced code links against, +and which a descriptor structurally cannot carry. `emit xpkg` says exactly that: + +``` +[target.'cfg(linux)'] declares tools (xim:cairo@1.18.4, …) and the descriptor +carries no edge for them: its blocks are per platform, and a selector is not a +platform. +``` + +A descriptor has three platform blocks; a cfg selector is not one of them. +Consumer edges therefore come from this file. Omitted, a consumer would resolve +huxerui, build it, and die at link on the GTK sonames. + +The closure is transcribed at **PLATFORM level** — a per-version `deps` is +inert, the finding `compat.eui-neo` and `compat.glx-runtime` both record. All 36 +entries and their pins are copied verbatim from the v0.3.0 tag's own manifest +(diffed against the working tree to confirm they match). They are what the +package's build compiles against *and* what a consumer must have, so no +`runtime = { … }` split applies. + +Keeping this in step with upstream is manual until mcpp can derive consumer +dependencies from the target axis. A missing entry surfaces as +`Package was not found in the pkg-config search path`, which names it. + +macOS needs no payloads (`[runtime] frameworks`, supplied by the system SDK). +windows keeps `xim:wix@5.0.2` exactly as emitted — upstream declares it on the +host axis, because wix.exe runs on the build machine, and the host axis *is* +emitted. + +## 5. The CI pin moves with this PR + +`mcpp/huxerui-build-rules` calls `mcpp::package_name()` and +`mcpp::package_namespace()` — mcpp#587, merged 2026-09-08, first released in +**v2026.9.7.1**. The pin was 2026.9.6.3, one release short, so the host module +did not compile at all: + +``` +error: dependency 'huxerui': host module 'huxerui.rules' compile failed (exit 1) +rules.cppm:274:61: error: 'package_name' is not a member of 'mcpp' +``` + +This is the situation #361 established the pattern for — *"A package whose build +program uses a current engine API is not a defect; a CI that cannot run current +engines is."* — so `MCPP_VERSION` moves to **2026.9.10.2** (current) in the same +PR, and the comment records why. + +`index.toml` `min_mcpp` does **not** move, for the reason that entry gives: the +floor is about descriptor **grammar**. Verified — `mcpp xpkg parse` accepts this +descriptor under 2026.8.27.2 (the floor), 2026.9.6.3 and 2026.9.10.2 alike. A +client on the floor keeps resolving the whole index; only building *this* +package from source needs the newer engine. + +The pin move pays the cold-cache cost the workflow comment warns about +(~12 shards, still cold after 50 minutes), so any other descriptor waiting on a +newer engine should ride along. + +## 6. Verification + +Member `tests/examples/huxerui-module`, one `[indices] huxerui = { path = "../../.." }`. + +``` +$ mcpp test -p huxerui-module # 2026.9.10.2 + Compiling huxerui.huxerui v0.3.0 + Compiling runtime (test) + Running bin/runtime +runtime ... ok (0.02s) + test result ok. 1 passed; 0 failed; finished in 8.21s +``` + +Negative check — the assertion is live, not a no-op: + +``` +$ sed -i 's/Color::Rgb(255, 128, 0)/Color::Rgb(1, 2, 3)/' …/runtime.cpp +$ mcpp test -p huxerui-module +runtime ... FAIL (exit 1, 0.02s) +error: test result: FAILED. 0 passed; 1 failed +``` + +The test deliberately opens no window. `Rect`/`Color` are header-attached +entities the module re-exports and would compile even if the library had never +been built; `FlatLightThemeSpec()`/`FlatDarkThemeSpec()` are out-of-line +definitions inside libhuxerui, so reaching them is what proves the link. + +Old pin still fails, as expected: + +``` +$ mcpp-2026.9.6.3 test -p huxerui-module +rules.cppm:274:61: error: 'package_name' is not a member of 'mcpp' +``` + +## 7. A path-length trap found on the way, and left upstream + +At a deep checkout the same member fails on **mcpp**, not on this descriptor: + +``` +build.mcpp declared an action whose arguments did not fit +payload: {"id":"hrc:builtin", … "overflow":true} +``` + +`mcpp::action` uses fixed buffers (`inputs_[8192]`) and `hrc:builtin` enumerates +all 44 files under `resources/` as inputs. Measured: + +| unpack prefix | inputs | result | +|---|---|---| +| 149 chars (deep local checkout) | 8 131 B + ~106 B for the hrc path | **overflows 8 192** | +| 109 chars (ordinary path) | 6 371 B | builds | +| in-tree, relative | 1 531 B | builds, 21.45 s | + +So it is driven by the unpack prefix, not the file count, and it overflows by +roughly 45 bytes. That is worse than a clean failure: whether a consumer builds +depends on how deep their project sits on disk. mcpp's own error names the fix — +declare the resources **directory** as one input instead of enumerating it — +and it belongs in `huxerui-build-rules`, not here. Filed as a follow-up against +HuxerUI; this index is not the place to work around it. + +## 8. CN mirror + +`mcpp-res/huxerui`, release `0.3.0`, asset `huxerui-0.3.0.tar.gz` — the same +bytes as GLOBAL. + +``` +CN http=200 size=9946045 +GLOBAL sha 8b326d95015e92925229fdc1ababe4fdf32515e75764472591645622c1cfbb08 +CN sha 8b326d95015e92925229fdc1ababe4fdf32515e75764472591645622c1cfbb08 +BYTE-IDENTICAL +``` + +## 9. Lint + +`check_mirror_urls`, `check_package_name`, `check_duplicate_versions`, +`check_platform_version_parity`, `check_cross_package_refs` — all pass on the +new descriptor, and the first three pass across `pkgs/*/*.lua` to confirm the +addition does not disturb anything else. diff --git a/.github/workflows/validate.yml b/.github/workflows/validate.yml index 3746601..a13c289 100644 --- a/.github/workflows/validate.yml +++ b/.github/workflows/validate.yml @@ -191,7 +191,31 @@ env: # member on every platform. Measured: twelve workspace shards, all still cold # after fifty minutes. Batch descriptor changes that need a newer engine into # ONE pin move rather than several. - MCPP_VERSION: "2026.9.6.3" + # ── 2026-09-11: raised 2026.9.6.3 -> 2026.9.10.2 ────────────────────────── + # + # Same shape as the move above, and for the same reason. `huxerui.huxerui` + # is a Form A package whose build program (`mcpp/huxerui-build-rules`) calls + # `mcpp::package_name()` and `mcpp::package_namespace()`. Those are mcpp#587, + # merged 2026-09-08 and first released in v2026.9.7.1 -- one release past the + # old pin -- so under 2026.9.6.3 the host module does not compile at all: + # + # error: dependency 'huxerui': host module 'huxerui.rules' compile failed + # rules.cppm:274:61: error: 'package_name' is not a member of 'mcpp' + # + # Verified at 2026.9.10.2: `mcpp test -p huxerui-module` builds the SDK from + # source as an index dependency and the member's assertion passes + # (`test result ok. 1 passed`), and the same member still fails on 2026.9.6.3 + # with the error above. Nothing else in this PR needs the newer engine. + # + # `index.toml` min_mcpp does NOT move, for the reason the previous entry + # gives: the floor is about descriptor GRAMMAR, and `mcpp xpkg parse` accepts + # pkgs/h/huxerui.huxerui.lua under 2026.9.6.3 and 2026.9.10.2 alike. A client + # on the floor keeps resolving the whole index; only building THIS package + # from source needs the newer engine. + # + # The batching guidance above applies: this move pays the cold-cache cost, so + # any other descriptor waiting on a newer engine should ride along. + MCPP_VERSION: "2026.9.10.2" jobs: lint: diff --git a/README.md b/README.md index e05c953..394baee 100644 --- a/README.md +++ b/README.md @@ -27,7 +27,7 @@ Two kinds of packages live here: - **Native mcpp module libraries**: shipped as C++23 modules and ready to `import` — `mcpplibs.*`, `nlohmann.json`, `imgui`, `ffmpeg`, `opencv`, plus libraries developed on top of mcpp by users and registered into the index (such as - `tensorvia-cpu`). Their upstream usually carries its own `mcpp.toml`, so the descriptor (Form A) only declares + `tensorvia-cpu` and `huxerui.huxerui`). Their upstream usually carries its own `mcpp.toml`, so the descriptor (Form A) only declares metadata and a download address. - **Third-party C/C++ libraries (`compat`)**: upstream offers no mcpp support, so the descriptor (Form B) inlines the build information. These come in several shapes — header-only, plain C sources, C++23 module wrapper — with optional @@ -47,6 +47,7 @@ A few descriptors worth opening first, one per common shape: | C++23 module wrapper | [`nlohmann.json`](pkgs/n/nlohmann.json.lua) | A generated `.cppm` turns a header-only library into `import` | | C++23 module, upstream's own | [`khronos.vulkan-hpp`](pkgs/k/khronos.vulkan-hpp.lua) | Khronos ships `vulkan.cppm`, so the descriptor just names it — `import vulkan;` with nothing authored here | | External build system | [`compat.openssl`](pkgs/c/compat.openssl.lua) | An `install()` hook drives upstream's own Perl Configure + Make | +| Form A whose consumer deps must be written by hand | [`huxerui.huxerui`](pkgs/h/huxerui.huxerui.lua) | HuxerUI declares its GTK4 stack on the TARGET axis, which is the form mcpp recommends and which a descriptor structurally cannot carry — three platform blocks, and a cfg selector is not a platform. `mcpp emit xpkg` says so and emits empty `deps`, so the 36-entry closure is transcribed into `xpm.linux.deps` at PLATFORM level (a per-version `deps` is inert). Its `licenses`/`repo` also deliberately disagree with what emit produces | The full catalog — every shape this index has needed, and the reasoning behind each descriptor including what it deliberately leaves out — is in **[Descriptor examples by shape](docs/descriptor-examples.md)**. diff --git a/README.zh-CN.md b/README.zh-CN.md index d9e7216..f479742 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -25,7 +25,7 @@ mcpp self config --mirror CN # 切换至国内镜像,默认使用 GLOBAL 上 本仓收录两类包: - **原生 mcpp 模块库**:以 C++23 模块发布、`import` 即用,包括 `mcpplibs.*`、`nlohmann.json`、`imgui`、`ffmpeg`、`opencv`,以及由 - 用户基于 mcpp 开发并登记进索引的库(如 `tensorvia-cpu`)。其上游通常自带 `mcpp.toml`,描述文件(Form A)只声明 + 用户基于 mcpp 开发并登记进索引的库(如 `tensorvia-cpu`、`huxerui.huxerui`)。其上游通常自带 `mcpp.toml`,描述文件(Form A)只声明 元数据与下载地址。 - **第三方 C/C++ 库(`compat`)**:其上游不提供 mcpp 支持,描述文件(Form B)内联构建信息。该类库存在 header-only、纯 C 源码、C++23 module wrapper 等形态,可选组件经 `features` 门控,并配备 GitCode CN 镜像。 From 65c7ae1763d4a89aa386456356287204da6b238e Mon Sep 17 00:00:00 2001 From: sunrisepeak Date: Fri, 11 Sep 2026 03:44:25 +0800 Subject: [PATCH 03/10] fix(huxerui): drop xim:wix, and name the four deps rather than the closure Two corrections the PR's own CI earned. NO xim:wix ON WINDOWS `mcpp emit xpkg` emits `deps = { "xim:wix@5.0.2" }` because upstream declares wix on the HOST axis, which is the axis a descriptor can carry. Emitted is not the same as needed: wix.exe builds an MSI, nothing else in the SDK touches it, upstream's rule tolerates its absence by construction inline ... wix() { const std::string root = mcpp::xpkg_dir("xim", "wix"); if (root.empty()) return {}; and upstream's manifest says an application that wants an installer "declares this line too". The dependency belongs to that application, not to everyone who imports huxerui on Windows. It was also breaking both Windows shards outright -- `xim:wix`'s install hook fails on a clean runner: E_INTERNAL: [wix] failed: install hook failed: tar -xf "...\xim-x-wix\5.0.2\.nupkg\wix.nupkg" -C "...\tool" ; wix installed but registered none of its declared programs taking every Windows consumer down with it for a tool almost none would run. That hook is a separate xim-pkgindex defect; this descriptor should not have been asking for wix either way. FOUR DEPS, NOT THIRTY-SIX The list existed to guarantee the payloads are INSTALLED, and installation is transitive: each xim package declares its own deps, and `xlings remove pango` is refused, naming `xim:gtk4` as the holder, so the reverse edges are live. Discovery is a different mechanism -- `mcpp::xpkg_dir` answers from the BUILDING package's own manifest, and upstream's mcpp.toml already declares the whole closure on its target axis. So the descriptor needs only what upstream's cmake and build.mcpp ask pkg-config for directly. Verified by clearing the member's sandbox and rebuilding with the short list: `test result ok. 1 passed`. Naming the other 32 restates pins this index does not own. Note the asymmetry with the xim-pkgindex entry, which is NOT a mistake: there the deps drive both installation and, through the aggregated sysroot pkgconfig view, discovery. Here upstream's manifest owns discovery. Same four names, different reasons. The pin move and the mysql-connector-cpp regression it surfaces are a separate matter, still under investigation. --- pkgs/h/huxerui.huxerui.lua | 82 ++++++++++++++++++++------------------ 1 file changed, 44 insertions(+), 38 deletions(-) diff --git a/pkgs/h/huxerui.huxerui.lua b/pkgs/h/huxerui.huxerui.lua index 556377a..ab7d18a 100644 --- a/pkgs/h/huxerui.huxerui.lua +++ b/pkgs/h/huxerui.huxerui.lua @@ -73,45 +73,24 @@ package = { xpm = { linux = { - -- The transitive .pc closure of gtk4 + epoxy + libsoup, pinned, - -- copied from the v0.3.0 tag's [target.'cfg(linux)'.xlings.workspace]. + -- DIRECT dependencies only -- the four modules upstream's cmake + -- and build.mcpp actually ask pkg-config for. The rest of the GTK + -- stack arrives through them: each xim package declares its own + -- deps, and xlings resolves them transitively (`xlings remove + -- pango` is REFUSED, naming `xim:gtk4` as the holder, so the + -- reverse edges are live). + -- + -- What this list is FOR is installation, not discovery. Discovery + -- goes through `mcpp::xpkg_dir`, which answers from the BUILDING + -- package's own manifest -- and upstream's mcpp.toml already + -- declares the full closure on its target axis. So the descriptor + -- only has to guarantee the payloads are present; naming the other + -- 32 here would restate pins this index does not own. deps = { - "xim:cairo@1.18.4", - "xim:expat@2.6.2", - "xim:fontconfig@2.15.0.1", - "xim:freetype@2.13.2", - "xim:fribidi@1.0.13", - "xim:gdk-pixbuf@2.44.8", - "xim:glib@2.88.3", - "xim:graphene@1.10.8", "xim:gtk4@4.16.13", - "xim:harfbuzz@14.4.0", - "xim:libX11@1.8.10", - "xim:libXau@1.0.11", - "xim:libXdmcp@1.1.5", - "xim:libXext@1.3.6", - "xim:libXft@2.3.9", - "xim:libXrender@0.9.11", - "xim:libdatrie@0.2.14", "xim:libepoxy@1.5.10", - "xim:libffi@3.4.4", - "xim:libglvnd@1.7.0.1", - "xim:libjpeg-turbo@3.2.0", - "xim:libpng@1.6.43", - "xim:libpsl@0.23.3", - "xim:libselinux@3.11", + "xim:glib@2.88.3", "xim:libsoup@3.6.6", - "xim:libthai@0.1.30", - "xim:libtiff@4.7.2", - "xim:libxcb@1.17.0", - "xim:nghttp2@1.70.0", - "xim:pango@1.52.1", - "xim:pcre2@10.42", - "xim:pixman@0.42.2", - "xim:sqlite@3.53.4", - "xim:util-linux@2.40.2", - "xim:xorgproto@2024.1", - "xim:zlib@1.3.1", }, ["0.3.0"] = { url = { @@ -131,9 +110,36 @@ package = { }, }, windows = { - -- HOST axis, and emitted as such: wix.exe runs on the build - -- machine. Only a project that builds an MSI reaches it. - deps = { "xim:wix@5.0.2" }, + -- NO `xim:wix`, and that is not an oversight. + -- + -- `mcpp emit xpkg` emits `deps = { "xim:wix@5.0.2" }` here because + -- upstream declares wix on the HOST axis (top-level + -- `[xlings.workspace]`), and the host axis is the one a descriptor + -- CAN carry. Emitted is not the same as "every consumer needs it". + -- + -- wix.exe builds an MSI. Nothing else in the SDK touches it, the + -- rule tolerates its absence by design -- + -- + -- inline ... wix() { + -- const std::string root = mcpp::xpkg_dir("xim", "wix"); + -- if (root.empty()) return {}; + -- + -- and upstream's own manifest says an application that asks + -- huxerui.rules for an installer "declares this line too". So the + -- dependency belongs to that application, not to everyone who + -- imports huxerui on Windows. + -- + -- Declaring it here was also actively breaking: `xim:wix`'s + -- install hook fails on a clean Windows runner -- + -- + -- E_INTERNAL: [wix] failed: install hook failed: + -- tar -xf "...\xim-x-wix\5.0.2\.nupkg\wix.nupkg" -C "...\tool" + -- ; wix installed but registered none of its declared programs + -- + -- which took every Windows consumer of this package down with it, + -- for a tool almost none of them would ever run. Reported against + -- xim-pkgindex separately; this descriptor should not have been + -- asking for it either way. ["0.3.0"] = { url = { GLOBAL = "https://github.com/HuxerUI/HuxerUI/archive/refs/tags/v0.3.0.tar.gz", From ea28c7cf64acfa493670b13036e886f47d18b883 Mon Sep 17 00:00:00 2001 From: sunrisepeak Date: Fri, 11 Sep 2026 04:12:28 +0800 Subject: [PATCH 04/10] fix(ci): pin the floor 2026.9.7.1, not the tip, because the tip has a scanner regression The pin moved to 2026.9.10.2 on the reasoning that #361 took the current release. CI disagreed: `mysql-connector-cpp` failed on linux default, linux llvm AND macOS, deterministically, while every other member passed. It is not that package's fault, and not a dependency problem. mcpp's scanner errors on an ordinary block comment in libmysqlclient's `sql-common/client_plugin.cc`. Reduced to four lines: /* module (exe) */ int main() { return 0; } error: scanner errors: src/main.cpp:2: '(exe) ... A line inside a block comment is read as a module declaration when the comment's opener sits on its own line -- the same text on one line (`/* module (exe) */`) scans fine, and `module x` without the parenthesis scans fine either way. So a comment that merely uses the English word "module" before a parenthesis breaks the scan. Bisected across releases with that file: 2026.8.27.2 OK 2026.9.7.1 OK 2026.9.6.3 OK 2026.9.10.2 scanner errors The regression therefore lands AFTER 2026.9.7.1 -- which is precisely the release that first carries `mcpp::package_name()`, the API huxerui's build program needs. The floor and the last good version are the same release, so this takes the floor. Verified at 2026.9.7.1, both members that mattered: mcpp test -p huxerui-module test result ok. 1 passed mcpp test -p mysql-connector-cpp test result ok. 1 passed Reported upstream. Move to the tip once the scanner is fixed -- and per the batching note above, that move should carry any other descriptor waiting on a newer engine. --- .github/workflows/validate.yml | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/.github/workflows/validate.yml b/.github/workflows/validate.yml index a13c289..0b6bfea 100644 --- a/.github/workflows/validate.yml +++ b/.github/workflows/validate.yml @@ -191,7 +191,7 @@ env: # member on every platform. Measured: twelve workspace shards, all still cold # after fifty minutes. Batch descriptor changes that need a newer engine into # ONE pin move rather than several. - # ── 2026-09-11: raised 2026.9.6.3 -> 2026.9.10.2 ────────────────────────── + # ── 2026-09-11: raised 2026.9.6.3 -> 2026.9.7.1 ─────────────────────────── # # Same shape as the move above, and for the same reason. `huxerui.huxerui` # is a Form A package whose build program (`mcpp/huxerui-build-rules`) calls @@ -202,10 +202,25 @@ env: # error: dependency 'huxerui': host module 'huxerui.rules' compile failed # rules.cppm:274:61: error: 'package_name' is not a member of 'mcpp' # - # Verified at 2026.9.10.2: `mcpp test -p huxerui-module` builds the SDK from - # source as an index dependency and the member's assertion passes - # (`test result ok. 1 passed`), and the same member still fails on 2026.9.6.3 - # with the error above. Nothing else in this PR needs the newer engine. + # 2026.9.7.1 is the FLOOR, not the current release, and the difference is + # load-bearing. 2026.9.10.2 was tried first and broke `mysql-connector-cpp` + # on linux and macOS: mcpp's scanner errors on a plain block comment. Reduced + # to four lines -- + # + # /* + # module (exe) + # */ + # int main() { return 0; } + # + # -- and bisected across releases: + # + # 2026.8.27.2 OK 2026.9.7.1 OK + # 2026.9.6.3 OK 2026.9.10.2 scanner errors + # + # so the regression lands after 2026.9.7.1, which is exactly the release that + # first carries `package_name()`. Taking the floor rather than the tip gets + # huxerui built without dragging that defect into every other member. + # Reported upstream; move to the tip once it is fixed. # # `index.toml` min_mcpp does NOT move, for the reason the previous entry # gives: the floor is about descriptor GRAMMAR, and `mcpp xpkg parse` accepts @@ -215,7 +230,7 @@ env: # # The batching guidance above applies: this move pays the cold-cache cost, so # any other descriptor waiting on a newer engine should ride along. - MCPP_VERSION: "2026.9.10.2" + MCPP_VERSION: "2026.9.7.1" jobs: lint: From 656bba8c8ede812873d71d2e38a75caf202fc312 Mon Sep 17 00:00:00 2001 From: sunrisepeak Date: Fri, 11 Sep 2026 05:59:38 +0800 Subject: [PATCH 05/10] =?UTF-8?q?docs(huxerui):=20record=20what=20CI=20fou?= =?UTF-8?q?nd=20=E2=80=94=20the=20pin=20is=20the=20floor,=20wix=20is=20not?= =?UTF-8?q?=20a=20dep?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The plan still described the first attempt: pin at 2026.9.10.2 and `xim:wix` kept as emitted. CI rejected both, and the reasons are worth keeping rather than quietly overwriting. - The pin is 2026.9.7.1, the FLOOR, because a scanner regression lands in 2026.9.9.1 (still present in 2026.9.11.1) and breaks mysql-connector-cpp. Four-line repro and the bisect are recorded; mcpp-community/mcpp#606. - windows carries no `xim:wix`: emitted is not needed, and its install hook fails on a clean runner. xim-pkgindex#808. - A section on what CI caught that local verification structurally could not, including the one failure still open (mysql-connector-cpp on the llvm leg) and where huxerui itself stands per leg. This also re-triggers CI, which now resolves `xim:wix` from an index snapshot that carries the #808 fix. --- .agents/docs/2026-09-11-add-huxerui-plan.md | 66 ++++++++++++++++++--- 1 file changed, 59 insertions(+), 7 deletions(-) diff --git a/.agents/docs/2026-09-11-add-huxerui-plan.md b/.agents/docs/2026-09-11-add-huxerui-plan.md index f1581d0..1d625ab 100644 --- a/.agents/docs/2026-09-11-add-huxerui-plan.md +++ b/.agents/docs/2026-09-11-add-huxerui-plan.md @@ -92,9 +92,14 @@ dependencies from the target axis. A missing entry surfaces as `Package was not found in the pkg-config search path`, which names it. macOS needs no payloads (`[runtime] frameworks`, supplied by the system SDK). -windows keeps `xim:wix@5.0.2` exactly as emitted — upstream declares it on the -host axis, because wix.exe runs on the build machine, and the host axis *is* -emitted. +windows carries **no** `xim:wix`, though emit produces one. Upstream declares +wix on the host axis and the host axis is what a descriptor can carry, but +emitted is not needed: wix builds an MSI, upstream's rule tolerates its absence +by construction (`if (root.empty()) return {};`), and upstream's manifest says +an application wanting an installer "declares this line too". CI settled it — +`xim:wix`'s own install hook fails on a clean windows-latest runner, so +declaring it took every Windows consumer down for a tool almost none would run. +Fixed separately in xim-pkgindex#808. ## 5. The CI pin moves with this PR @@ -110,12 +115,29 @@ rules.cppm:274:61: error: 'package_name' is not a member of 'mcpp' This is the situation #361 established the pattern for — *"A package whose build program uses a current engine API is not a defect; a CI that cannot run current -engines is."* — so `MCPP_VERSION` moves to **2026.9.10.2** (current) in the same -PR, and the comment records why. +engines is."* — so `MCPP_VERSION` moves in the same PR. + +It moves to **2026.9.7.1**, the floor, and not to the current release. That was +the second attempt. 2026.9.10.2 was tried first and CI rejected it: +`mysql-connector-cpp` failed on linux default, linux llvm and macOS while every +other member passed. Not that package's fault — mcpp's scanner errors on an +ordinary block comment. Reduced to four lines: + +```cpp +/* + module (exe) +*/ +int main() { return 0; } +``` + +and bisected: OK through 2026.9.8.1, broken from 2026.9.9.1 onward (2026.9.11.1 +included). The regression lands one release after 2026.9.7.1 — which is exactly +the release that first carries `package_name()`. The floor and the last good +version coincide, so the pin sits there. Reported as mcpp-community/mcpp#606. `index.toml` `min_mcpp` does **not** move, for the reason that entry gives: the floor is about descriptor **grammar**. Verified — `mcpp xpkg parse` accepts this -descriptor under 2026.8.27.2 (the floor), 2026.9.6.3 and 2026.9.10.2 alike. A +descriptor under 2026.8.27.2 (the floor), 2026.9.6.3 and 2026.9.7.1 alike. A client on the floor keeps resolving the whole index; only building *this* package from source needs the newer engine. @@ -128,7 +150,7 @@ newer engine should ride along. Member `tests/examples/huxerui-module`, one `[indices] huxerui = { path = "../../.." }`. ``` -$ mcpp test -p huxerui-module # 2026.9.10.2 +$ mcpp test -p huxerui-module # 2026.9.7.1 Compiling huxerui.huxerui v0.3.0 Compiling runtime (test) Running bin/runtime @@ -200,3 +222,33 @@ BYTE-IDENTICAL `check_platform_version_parity`, `check_cross_package_refs` — all pass on the new descriptor, and the first three pass across `pkgs/*/*.lua` to confirm the addition does not disturb anything else. + +## 10. What CI added that local verification could not + +Three defects surfaced only in CI, and all three lived outside this descriptor. + +**`xim:wix` had never been installed.** `tests/w/test_wix.py` is static-only and +nothing in either index pulled wix in, so its install hook had never run +anywhere. huxerui is its first consumer; on Windows it fails at +`Provisioning [xlings.workspace] entries declared by dependencies` — before +huxerui compiles at all. Removing wix from this descriptor was necessary but not +sufficient: mcpp also provisions what the BUILDING package declares, and +upstream's `mcpp.toml` declares it. Fixed in xim-pkgindex#808. + +**The scanner regression**, above — which is why the pin is the floor. + +**`mysql-connector-cpp` on the llvm leg** still fails at 2026.9.7.1, with +`install() result=nil` and no scanner error. The default (gcc) leg passes, and +the two legs are not equivalent: gcc reaches its compiler through `--sysroot` +into a clean subos, while llvm has no sysroot and the host's headers are on the +search path. Unexplained, tracked separately, and not attributable to this +package — `huxerui-module` itself is `ok` in that same shard. + +Where huxerui stands per leg, at the pin this PR sets: + +| leg | huxerui-module | +|---|---| +| linux default | ok | +| linux llvm | ok | +| macOS | ok | +| windows | blocked on xim-pkgindex#808, then expected to pass | From 8a4900e437af376efd57199a29598334d3ea2b97 Mon Sep 17 00:00:00 2001 From: sunrisepeak Date: Fri, 11 Sep 2026 10:21:29 +0800 Subject: [PATCH 06/10] docs(huxerui): wix took two attempts, and the first was a wrong diagnosis The plan credited xim-pkgindex#808 with fixing the Windows failure. It did not: keeping the host's tar and adding a PowerShell fallback only moved the error from 'exec failed ... tar -xf' to 'registered none of its declared programs'. What settled it was already in the first log -- curl ran fine in the same hook moments before tar did not, so the payload was downloaded and sha-verified before execution ever reached the extractor. One is a declared dependency; the other was the host's. xim-pkgindex#809 declares xim:7zip and extracts with it. Recording the wrong turn rather than only the answer: the fallback in #808 is exactly the shape that let this hide in the first place. Also re-triggers CI, which now resolves xim:wix from a snapshot carrying the #809 fix. --- .agents/docs/2026-09-11-add-huxerui-plan.md | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/.agents/docs/2026-09-11-add-huxerui-plan.md b/.agents/docs/2026-09-11-add-huxerui-plan.md index 1d625ab..1711562 100644 --- a/.agents/docs/2026-09-11-add-huxerui-plan.md +++ b/.agents/docs/2026-09-11-add-huxerui-plan.md @@ -99,7 +99,7 @@ by construction (`if (root.empty()) return {};`), and upstream's manifest says an application wanting an installer "declares this line too". CI settled it — `xim:wix`'s own install hook fails on a clean windows-latest runner, so declaring it took every Windows consumer down for a tool almost none would run. -Fixed separately in xim-pkgindex#808. +Fixed separately in xim-pkgindex#809. ## 5. The CI pin moves with this PR @@ -233,7 +233,19 @@ anywhere. huxerui is its first consumer; on Windows it fails at `Provisioning [xlings.workspace] entries declared by dependencies` — before huxerui compiles at all. Removing wix from this descriptor was necessary but not sufficient: mcpp also provisions what the BUILDING package declares, and -upstream's `mcpp.toml` declares it. Fixed in xim-pkgindex#808. +upstream's `mcpp.toml` declares it. + +It took two attempts, and the first is worth recording because it was a wrong +diagnosis. xim-pkgindex#808 kept the host's `tar` and added a PowerShell +fallback; the failure merely moved, from `exec failed … tar -xf` to +`registered none of its declared programs`. The evidence had been in the first +log all along: `curl` ran fine in the SAME hook moments before `tar` did not -- +the payload was downloaded and sha-verified, which is the only reason execution +reached the extractor at all. One is a declared dependency; the other was the +host's. xim-pkgindex#809 declares `xim:7zip` and extracts with it, applying the +standard this recipe had already set for its own downloader. Verified on a +Windows runner: 7-Zip installs as a dep, extracts the .nupkg, and `wix.exe` +runs. **The scanner regression**, above — which is why the pin is the floor. @@ -251,4 +263,4 @@ Where huxerui stands per leg, at the pin this PR sets: | linux default | ok | | linux llvm | ok | | macOS | ok | -| windows | blocked on xim-pkgindex#808, then expected to pass | +| windows | blocked on xim-pkgindex#809, then expected to pass | From c9c02d66fa7cde363ebd9f8e2198dea8fe4dd35c Mon Sep 17 00:00:00 2001 From: sunrisepeak Date: Fri, 11 Sep 2026 11:14:28 +0800 Subject: [PATCH 07/10] =?UTF-8?q?fix(ci):=20pin=202026.9.11.2=20=E2=80=94?= =?UTF-8?q?=20the=20scanner=20is=20fixed,=20and=20the=20pin=20is=20the=20i?= =?UTF-8?q?ndex's=20cache=20key?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Two separate reasons, and the second one invalidates a conclusion this branch reached twice. THE SCANNER REGRESSION IS FIXED 2026.9.7.1 was chosen as the FLOOR because 2026.9.9.1 introduced a scanner regression — mcpp read inside a block comment and choked on libmysqlclient's `module (exe or dll) …`, breaking mysql-connector-cpp on linux and macOS. Reduced to four lines, reported as mcpp-community/mcpp#606, and fixed in 2026.9.11.2. Verified all three: four-line scanner repro builds clean mcpp test -p huxerui-module test result ok. 1 passed mcpp test -p mysql-connector-cpp test result ok. 1 passed So the pin no longer has to sit four releases behind to stay green. THE PIN IS THE ONLY WAY TO REFRESH THE INDEX `xim:wix` was fixed twice upstream — xim-pkgindex#808, then #809 — and after each merge the windows leg here failed identically. Both times that was read as "the fix did not work". Neither had ever been loaded. `actions/cache` holds `~/.mcpp/registry`, which contains `data/xim-pkgindex` — the resolved xim index — and its `restore-keys` prefix stops at MCPP_VERSION. While that line does not move, every run restores the same index snapshot no matter what landed upstream. The tell was in the log: `7zip`, which #809 declares, appeared ZERO times in a run supposedly testing #809. Two guesses along the way were wrong and are recorded in the plan so they are not repeated: that the release tarball bundles a frozen index (a pristine extraction has no `xim-pkgindex` at all — it is populated at run time), and that a merge therefore propagates by itself. Moving this line evicts that cache. It is the only reason the windows leg can now see the fixed recipe, and that makes this pin move load-bearing twice over. `index.toml` min_mcpp still does not move: the floor is descriptor GRAMMAR, and the descriptor parses under 2026.8.27.2, 2026.9.6.3, 2026.9.7.1 and 2026.9.11.2 alike. --- .agents/docs/2026-09-11-add-huxerui-plan.md | 28 +++++++++- .github/workflows/validate.yml | 62 ++++++++++----------- 2 files changed, 57 insertions(+), 33 deletions(-) diff --git a/.agents/docs/2026-09-11-add-huxerui-plan.md b/.agents/docs/2026-09-11-add-huxerui-plan.md index 1711562..bb19bda 100644 --- a/.agents/docs/2026-09-11-add-huxerui-plan.md +++ b/.agents/docs/2026-09-11-add-huxerui-plan.md @@ -150,7 +150,7 @@ newer engine should ride along. Member `tests/examples/huxerui-module`, one `[indices] huxerui = { path = "../../.." }`. ``` -$ mcpp test -p huxerui-module # 2026.9.7.1 +$ mcpp test -p huxerui-module # 2026.9.11.2 Compiling huxerui.huxerui v0.3.0 Compiling runtime (test) Running bin/runtime @@ -264,3 +264,29 @@ Where huxerui stands per leg, at the pin this PR sets: | linux llvm | ok | | macOS | ok | | windows | blocked on xim-pkgindex#809, then expected to pass | + +## 11. The index in CI is cached, and the pin is its only cache key + +This cost a full round of wrong conclusions, so it is written down rather than +merely fixed. + +`xim:wix` was fixed twice in xim-pkgindex — #808, then #809 — and after each +merge the windows leg here failed identically. Both were read as "the fix did +not work". Neither had ever been loaded. + +`actions/cache` holds `~/.mcpp/registry`, and that path contains +`data/xim-pkgindex`: the resolved xim index. Its `restore-keys` prefix stops at +`MCPP_VERSION`, so as long as that line does not move, every run restores the +same index snapshot regardless of what landed upstream. The tell was in the log +all along — `7zip`, which #809 declares, appeared **zero times** in a run that +was supposedly testing #809. + +Two earlier guesses were wrong and are worth naming so they are not repeated: +that mcpp bundles a frozen index in its release tarball (it does not — a +pristine extraction contains no `xim-pkgindex` at all; the directory is +populated at run time), and that a merge therefore propagates on its own. + +The practical rule: **a change to a xim package cannot be verified from this +repo's CI unless `MCPP_VERSION` also moves.** Raising the pin to 2026.9.11.2 +evicts the cache, which is the only reason the windows leg can now see the +fixed recipe. diff --git a/.github/workflows/validate.yml b/.github/workflows/validate.yml index 0b6bfea..b315169 100644 --- a/.github/workflows/validate.yml +++ b/.github/workflows/validate.yml @@ -191,46 +191,44 @@ env: # member on every platform. Measured: twelve workspace shards, all still cold # after fifty minutes. Batch descriptor changes that need a newer engine into # ONE pin move rather than several. - # ── 2026-09-11: raised 2026.9.6.3 -> 2026.9.7.1 ─────────────────────────── + # ── 2026-09-11: raised 2026.9.6.3 -> 2026.9.11.2 ────────────────────────── # - # Same shape as the move above, and for the same reason. `huxerui.huxerui` - # is a Form A package whose build program (`mcpp/huxerui-build-rules`) calls - # `mcpp::package_name()` and `mcpp::package_namespace()`. Those are mcpp#587, - # merged 2026-09-08 and first released in v2026.9.7.1 -- one release past the - # old pin -- so under 2026.9.6.3 the host module does not compile at all: + # Same shape as the move above. `huxerui.huxerui` is a Form A package whose + # build program calls `mcpp::package_name()` and `mcpp::package_namespace()` + # (mcpp#587, first released v2026.9.7.1), so under 2026.9.6.3 its host module + # does not compile at all: # - # error: dependency 'huxerui': host module 'huxerui.rules' compile failed # rules.cppm:274:61: error: 'package_name' is not a member of 'mcpp' # - # 2026.9.7.1 is the FLOOR, not the current release, and the difference is - # load-bearing. 2026.9.10.2 was tried first and broke `mysql-connector-cpp` - # on linux and macOS: mcpp's scanner errors on a plain block comment. Reduced - # to four lines -- + # This landed on 2026.9.7.1 first, deliberately taking the FLOOR rather than + # the tip, because 2026.9.9.1 introduced a scanner regression that broke + # `mysql-connector-cpp` on linux and macOS -- mcpp read inside a block comment + # and choked on libmysqlclient's `module (exe or dll) …`. Reduced to four + # lines and reported as mcpp-community/mcpp#606; fixed in 2026.9.11.2, which + # is why the pin can now sit at the current release instead of four behind. + # Verified at 2026.9.11.2, all three: # - # /* - # module (exe) - # */ - # int main() { return 0; } + # four-line scanner repro builds clean + # mcpp test -p huxerui-module test result ok. 1 passed + # mcpp test -p mysql-connector-cpp test result ok. 1 passed # - # -- and bisected across releases: + # THE PIN IS ALSO THE ONLY WAY TO REFRESH THE INDEX, and that cost a full + # round of wrong conclusions before it was noticed. The registry cache below + # holds `~/.mcpp/registry`, which contains `data/xim-pkgindex` -- the resolved + # xim index -- and its `restore-keys` prefix stops at MCPP_VERSION. So while + # this line does not move, every run restores the same index snapshot no + # matter what landed in xim-pkgindex meanwhile. # - # 2026.8.27.2 OK 2026.9.7.1 OK - # 2026.9.6.3 OK 2026.9.10.2 scanner errors + # That is how two successive fixes to `xim:wix` (xim-pkgindex#808, then #809) + # both appeared to fail here: neither was ever loaded. The tell was that + # `7zip` -- which #809 declares -- appeared zero times in a log that was + # supposedly testing it. Moving this line evicts that cache, which is the + # only reason the windows leg can now see the fixed recipe. # - # so the regression lands after 2026.9.7.1, which is exactly the release that - # first carries `package_name()`. Taking the floor rather than the tip gets - # huxerui built without dragging that defect into every other member. - # Reported upstream; move to the tip once it is fixed. - # - # `index.toml` min_mcpp does NOT move, for the reason the previous entry - # gives: the floor is about descriptor GRAMMAR, and `mcpp xpkg parse` accepts - # pkgs/h/huxerui.huxerui.lua under 2026.9.6.3 and 2026.9.10.2 alike. A client - # on the floor keeps resolving the whole index; only building THIS package - # from source needs the newer engine. - # - # The batching guidance above applies: this move pays the cold-cache cost, so - # any other descriptor waiting on a newer engine should ride along. - MCPP_VERSION: "2026.9.7.1" + # `index.toml` min_mcpp still does NOT move: the floor is about descriptor + # GRAMMAR, and `mcpp xpkg parse` accepts pkgs/h/huxerui.huxerui.lua under + # 2026.8.27.2, 2026.9.6.3, 2026.9.7.1 and 2026.9.11.2 alike. + MCPP_VERSION: "2026.9.11.2" jobs: lint: From 0d7b75d6c48b2eb610801c61062577665259dcc6 Mon Sep 17 00:00:00 2001 From: sunrisepeak Date: Fri, 11 Sep 2026 11:54:21 +0800 Subject: [PATCH 08/10] fix(huxerui-module): the member declares c++20, the baseline its dependency sets The member declared no `standard`, so it defaulted to c++23 -- and mcpp applies the ROOT's standard to the whole module graph, which meant huxerui's own sources compiled at c++23. Upstream's mcpp.toml says not to: standard = "c++20" # The SDK ABI baseline. Do not raise it: mcpp applies the root standard # to the whole module graph, so this is imposed on every consumer too. `import std;` still works -- huxerui is `language = "c++20", import_std = true`, and the member's test passes at c++20 (`test result ok. 1 passed`). THIS IS NOT EXPECTED TO FIX WINDOWS, and saying so up front is the point. The windows leg fails compiling huxerui's `src/runtime/runtime_pointer_interaction.cpp`: xutility:320: error: static assertion failed: unexpected size in instantiation of 'std::_Find_vectorized< const huxerui::detail::NodeExtensionHandle, ...>' `NodeExtensionHandle` is 24 bytes (two 64-bit integers and a pointer), trivially copyable, with a defaulted `operator==`. MSVC STL 14.51 therefore treats it as memcmp-comparable and dispatches `std::find` to `_Find_vectorized`, which handles 1/2/4/8-byte elements and static_asserts on anything else. That dispatch is not gated on the language mode, so the standard this commit sets does not reach it: it is a clang 20.1.7 against MSVC STL 14.51 incompatibility in a header, reached through upstream's source, and nothing in this index can express a fix for it. Committed because it is correct on its own terms -- a consumer should not silently raise the ABI baseline a dependency pins -- not because it is the windows fix. --- tests/examples/huxerui-module/mcpp.toml | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/tests/examples/huxerui-module/mcpp.toml b/tests/examples/huxerui-module/mcpp.toml index 23f6f8e..2902af6 100644 --- a/tests/examples/huxerui-module/mcpp.toml +++ b/tests/examples/huxerui-module/mcpp.toml @@ -6,6 +6,20 @@ huxerui = { path = "../../.." } [package] name = "huxerui-module-tests" version = "0.1.0" +# C++20, because the DEPENDENCY says so and mcpp applies the ROOT's standard to +# the whole module graph -- upstream's mcpp.toml spells that out: +# +# standard = "c++20" +# # The SDK ABI baseline. Do not raise it: mcpp applies the root standard +# # to the whole module graph, so this is imposed on every consumer too. +# +# Leaving this unset defaulted the member to c++23 and compiled huxerui's own +# sources at c++23, above the baseline it declares. On windows that is not +# academic: clang 20.1.7 against MSVC STL 14.51 then instantiates +# `std::_Find_vectorized` and dies on `static_assert(false, "unexpected size")` +# in . `import std;` still works here -- huxerui is +# `language = "c++20", import_std = true`. +standard = "c++20" [dependencies.huxerui] huxerui = "0.3.0" From cfff769acc4647ff73b0efeb64ac5fc7eb5e2d91 Mon Sep 17 00:00:00 2001 From: sunrisepeak Date: Fri, 11 Sep 2026 12:01:30 +0800 Subject: [PATCH 09/10] =?UTF-8?q?ci(windows):=20pin=20windows-2022=20?= =?UTF-8?q?=E2=80=94=20`windows-latest`=20moved=20to=20an=20STL=20clang=20?= =?UTF-8?q?cannot=20compile?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit macOS is pinned (`macos-15`) and linux is not; windows was on the rolling label and it rolled onto the Visual Studio 18 image, MSVC STL 14.51. mcpp builds windows with clang targeting x86_64-pc-windows-msvc, so every package here compiles against an STL written for a different front end. Most survive it. `huxerui.huxerui` did not: xutility:320: error: static assertion failed: unexpected size in instantiation of 'std::_Find_vectorized< const huxerui::detail::NodeExtensionHandle, ...>' MSVC STL's vectorized `std::find` is guarded by a trait deciding whether the element type can be compared bitwise. `NodeExtensionHandle` is 24 bytes, no padding, trivially copyable, `operator==` defaulted — the guard admits it under clang, and the helper it dispatches to implements 1/2/4/8 byte elements and static_asserts on the rest. Guard and implementation disagree about what "vectorizable" means; only clang is there to notice. NOT this index's bug and not the package's, and the evidence is the pin itself: the same source and the same clang compile on the 2022 image. Upstream HuxerUI's own mcpp CI is green for exactly that reason — it already pins `windows-2022`. Filed as mcpp-community/mcpp#609 so the pin can be lifted when the combination works again. THE NARROWNESS IS THE ARGUMENT, not a reason to shrug: 13 of the 14 members on the failing shard compiled fine. A rolling label therefore changes WHICH packages trip over this from image to image, and delivers the failure attributed to whichever descriptor changed that week. Pinning turns a moving target into a dated, documented decision. --- .github/workflows/validate.yml | 34 +++++++++++++++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/.github/workflows/validate.yml b/.github/workflows/validate.yml index b315169..412ab51 100644 --- a/.github/workflows/validate.yml +++ b/.github/workflows/validate.yml @@ -786,7 +786,39 @@ jobs: emit linux ubuntu-latest linux-x86_64 tar.gz bin/mcpp registry/bin/xlings default "$ln" emit linux ubuntu-latest linux-x86_64 tar.gz bin/mcpp registry/bin/xlings llvm "$lln" emit macos macos-15 macosx-arm64 tar.gz bin/mcpp registry/bin/xlings default "$mn" - emit windows windows-latest windows-x86_64 zip bin/mcpp.exe registry/bin/xlings.exe default "$wn" + # WINDOWS IS PINNED, like macOS above, and for a reason that cost + # a day to find. `windows-latest` rolled to the Visual Studio 18 + # image (MSVC STL 14.51), and mcpp builds windows with clang + # targeting x86_64-pc-windows-msvc -- so every package here + # compiles against an STL written for a different front end. + # + # Most survive that. `huxerui.huxerui` did not: + # + # xutility:320: error: static assertion failed: unexpected size + # in instantiation of 'std::_Find_vectorized< + # const huxerui::detail::NodeExtensionHandle, ...>' + # + # MSVC STL's vectorized `std::find` is guarded by a trait that + # decides whether the element type can be compared bitwise. + # `NodeExtensionHandle` is 24 bytes with no padding, trivially + # copyable, `operator==` defaulted -- the guard admits it under + # clang, and the helper it dispatches to implements 1/2/4/8-byte + # elements and static_asserts on the rest. Guard and implementation + # disagree about what "vectorizable" means, and only clang is there + # to notice. + # + # NOT this index's bug, and not the package's: the same source, the + # same clang, compiles on the 2022 image's STL. Upstream HuxerUI's + # own mcpp CI is green for exactly that reason -- it pins + # `windows-2022`. Reported as mcpp-community/mcpp#609 so the pin can + # be lifted when the toolchain combination works. + # + # 13 of the 14 members on the shard that failed were unaffected, so + # this is not a blanket breakage -- which is precisely why a rolling + # label is the wrong thing to stand on: the next image moves the set + # of packages that happen to trip it, and the failure arrives + # attributed to whatever descriptor changed that week. + emit windows windows-2022 windows-x86_64 zip bin/mcpp.exe registry/bin/xlings.exe default "$wn" printf ']}' } | sed 's/,]}/]}/' > /tmp/matrix.json echo "matrix=$(cat /tmp/matrix.json)" >> "$GITHUB_OUTPUT" From 721fc89a58320476016043f2a714752017c2880c Mon Sep 17 00:00:00 2001 From: sunrisepeak Date: Fri, 11 Sep 2026 12:09:10 +0800 Subject: [PATCH 10/10] docs(huxerui): record that wix belongs behind `mcpp pack --format`, not in the build Section 4 already argues this descriptor should not declare `xim:wix` -- wix builds an MSI, and a consumer that merely imports huxerui has no use for it. That is right but incomplete: it treats the declaration as misplaced when the mechanism it belongs to simply did not exist yet. mcpp 2026.9.11.1 opened the `--format` value set. `mcpp pack` owns the mechanism and the universal formats; every other format lives in a package that declares `mcpp::provides_pack_format("")` in its build program, unconditionally, and submits its action only when asked. Under that, `xim:wix` stops being a top-level `[xlings.workspace]` entry provisioned for every build of every consumer, and becomes a dependency of the feature that provides `msi` -- reached only by someone actually packing one. The timeline is the whole explanation: HuxerUI v0.3.0 released 2026-09-10 17:36 UTC mcpp 2026.9.11.1 released, --format 2026-09-10 20:34 UTC `provides_pack_format` appears zero times in v0.3.0's build.mcpp and rules.cppm. Not a road not taken -- a road that did not exist, by under three hours. Recorded rather than acted on: the v0.3.0 tag is immutable and upstream is out of scope here. What the descriptor CAN do is behave as though the move had already happened, which is what not declaring wix does -- so a future 0.3.1 needs no change on this side. Also notes that the two Windows problems are independent: with wix gone from the build entirely, runtime_pointer_interaction.cpp still does not compile against MSVC STL 14.51. --- .agents/docs/2026-09-11-add-huxerui-plan.md | 50 +++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/.agents/docs/2026-09-11-add-huxerui-plan.md b/.agents/docs/2026-09-11-add-huxerui-plan.md index bb19bda..1edc1de 100644 --- a/.agents/docs/2026-09-11-add-huxerui-plan.md +++ b/.agents/docs/2026-09-11-add-huxerui-plan.md @@ -290,3 +290,53 @@ The practical rule: **a change to a xim package cannot be verified from this repo's CI unless `MCPP_VERSION` also moves.** Raising the pin to 2026.9.11.2 evicts the cache, which is the only reason the windows leg can now see the fixed recipe. + +## 12. Where `xim:wix` actually belongs — `mcpp pack --format` + +This descriptor declares no `xim:wix`, and section 4 argues that from the +consumer's side: wix builds an MSI, nothing else in the SDK touches it, and +upstream's own manifest says an application wanting an installer declares it +itself. That argument is right but incomplete, and the fuller one arrived three +hours too late to be in v0.3.0. + +**mcpp 2026.9.11.1 opened the `--format` value set.** `mcpp pack` owns the +mechanism and the two universal formats (`tar`, `dir`); every other format lives +in a package and the engine dispatches to it: + +```cpp +mcpp::provides_pack_format("msi"); // unconditional +if (std::string_view(mcpp::pack_format()) != "msi") return 0; // conditional +// … submit the wix action … +``` + +*Declare unconditionally, submit conditionally* — the declaration is what lets +`--format bogus` list what is available. `xim-pkgindex`'s `appimagetool` (#802) +is the same shape from the tool side. + +Under that mechanism `xim:wix` stops being a top-level `[xlings.workspace]` +entry — which is provisioned for **every** build of every consumer — and becomes +the dependency of the feature that provides the `msi` format, provisioned only +when someone actually asks for an MSI. `mcpp test -p huxerui-module` would never +touch it. + +The timeline is the whole explanation: + +| | | +|---|---| +| HuxerUI v0.3.0 released | 2026-09-10 17:36 UTC | +| mcpp 2026.9.11.1 released (`--format` opens) | 2026-09-10 20:34 UTC | + +`provides_pack_format` appears **zero** times in v0.3.0's `build.mcpp` and +`rules.cppm`. Not a road not taken — a road that did not exist yet, by under +three hours. + +**Nothing to do here, and that is the point.** v0.3.0's tag is immutable, so the +descriptor cannot reach this; what it can do is not make the problem worse, and +not declaring wix is exactly that. When a 0.3.1 or 0.4.0 moves wix behind +`provides_pack_format("msi")`, this descriptor needs no change — it already +behaves as though that move had happened. + +Note also that the two Windows problems are independent. Even with wix out of +the build entirely, `runtime_pointer_interaction.cpp` still fails to compile +against MSVC STL 14.51 (§11 and the `windows-2022` pin). Fixing the packaging +axis would not have unblocked this leg.