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 00000000..1edc1deb --- /dev/null +++ b/.agents/docs/2026-09-11-add-huxerui-plan.md @@ -0,0 +1,342 @@ +# 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 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#809. + +## 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 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.7.1 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.11.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. + +## 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. + +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. + +**`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#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. + +## 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. diff --git a/.github/workflows/validate.yml b/.github/workflows/validate.yml index 37466010..412ab511 100644 --- a/.github/workflows/validate.yml +++ b/.github/workflows/validate.yml @@ -191,7 +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. - MCPP_VERSION: "2026.9.6.3" + # ── 2026-09-11: raised 2026.9.6.3 -> 2026.9.11.2 ────────────────────────── + # + # 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: + # + # rules.cppm:274:61: error: 'package_name' is not a member of 'mcpp' + # + # 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: + # + # 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 + # + # 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. + # + # 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. + # + # `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: @@ -749,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" diff --git a/README.md b/README.md index e05c9534..394baeef 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 d9e7216f..f4797425 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 镜像。 diff --git a/mcpp.toml b/mcpp.toml index ce33498b..afc37cdf 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 00000000..ab7d18a6 --- /dev/null +++ b/pkgs/h/huxerui.huxerui.lua @@ -0,0 +1,160 @@ +-- 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 = { + -- 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:gtk4@4.16.13", + "xim:libepoxy@1.5.10", + "xim:glib@2.88.3", + "xim:libsoup@3.6.6", + }, + ["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 = { + -- 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", + 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 00000000..2902af6a --- /dev/null +++ b/tests/examples/huxerui-module/mcpp.toml @@ -0,0 +1,25 @@ +# 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" +# 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" diff --git a/tests/examples/huxerui-module/tests/runtime.cpp b/tests/examples/huxerui-module/tests/runtime.cpp new file mode 100644 index 00000000..baa60446 --- /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; +}