feat: 新增 compat.harfbuzz / compat.msdfgen / compat.mimalloc - #206
Merged
Conversation
These three are the only compiled dependencies still missing from the index for XRGUI (Sunrisepeak/xrgui#1), whose root build stops at exactly three lines -- hb.h, msdfgen/msdfgen-ext.h, mimalloc.h -- and nothing else. All three are general-purpose libraries in their own right: text shaping, SDF generation, and an allocator. SHAPES compat.mimalloc A 18 TUs, upstream's own mi_sources compat.harfbuzz A one TU, upstream's own amalgamation compat.msdfgen A + E C++ sources + a generated config header TWO OPPOSITE LESSONS ABOUT AMALGAMATIONS harfbuzz ships src/harfbuzz.cc as its supported "compile one file" path, so `sources` is a single line that cannot drift from a release -- reproducing meson here would mean tracking ~137 .cc files plus a generated config. The backends it also #includes (CoreText/DirectWrite/GDI/GLib/Graphite2) each sit behind their own HAVE_* gate, so naming only HAVE_FREETYPE selects the FreeType bridge and compiles the rest to nothing. mimalloc ships one too, and using it would be wrong. `src/*.c` is wrong three ways and each is a LINK error rather than a compile error: static.c duplicates every symbol, and free.c / alloc-override.c are #included BY alloc.c rather than being TUs. The list is upstream's mi_sources. msdfgen: THE CONFIG IS NOT OPTIONAL core/base.h opens with `#include <msdfgen/msdfgen-config.h>`, which CMake generates -- without it nothing compiles, not even core/. Generating it rather than passing -D flags is also what makes the library and its consumers agree BY CONSTRUCTION: base.h is reached from every public header, so that file is the single place saying which of SVG/PNG/Skia exist. A package's own cxxflags are private and a consumer including <msdfgen/msdfgen-ext.h> would disagree about which declarations exist. THREE KNOBS DELIBERATELY LEFT OFF, EACH FOR THE SAME REASON HB_NO_MT removes HarfBuzz's atomics -- sound only under a single-threading promise a shared package cannot make on its consumers' behalf MI_MALLOC_OVERRIDE a dependency silently taking over the process allocator is not a package's call MSDFGEN_USE_CPP11 adds move constructors to Bitmap, so it changes the layout of a type that crosses the library boundary; a package cannot guarantee every consumer defines it identically CN MIRRORS All three mirrored under gitcode mcpp-res with byte-identical tarballs; sha256 computed twice and the GLOBAL/CN round trip verified (200 + equal digest) for each. VERIFICATION Cold `mcpp test -p <member>` with the CI-pinned mcpp 2026.8.10.3: mimalloc test result ok. 1 passed; 0 failed harfbuzz test result ok. 1 passed; 0 failed msdfgen test result ok. 1 passed; 0 failed Every test asserts behavior, not linkage: mimalloc checks that usable_size reflects mimalloc's own bookkeeping and that zalloc really zeroes; harfbuzz shapes a real buffer and asserts one glyph per input codepoint with clusters tracking offsets; msdfgen generates an MSDF and asserts the field is signed (inside > 0.5, outside < 0.5 -- a blank bitmap fails both) and that the three channels actually differ, which a plain SDF would not. Local lint: check_mirror_urls, check_package_name, check_platform_version_parity, check_cross_package_refs and `mcpp xpkg parse` all pass.
Sunrisepeak
pushed a commit
to Sunrisepeak/xrgui
that referenced
this pull request
Aug 11, 2026
mcpplibs/mcpp-index#206 landed compat.harfbuzz, compat.msdfgen and compat.mimalloc, so the root package no longer stops at three missing headers. Getting past them exposed a whole layer those headers had been hiding: 13 more source issues, all now fixed. mcpp build -> 1332 objects, 626 BMIs only react_flow's :endpoint and :modifier still fail Source conformance is CLEARED except for react_flow, which is a GCC 16 modules bug rather than a defect in this tree. DEPENDENCIES ARE ONE TABLE NOW [dependencies.compat] / [dependencies.neargye] / [dependencies.marzer] are folded into a single [dependencies] using dotted `ns.name` selectors. The sub-table form scattered 12 dependencies across 4 sections whose only difference was the namespace -- not the role -- so nothing showed you what this project actually depends on. `compat.glfw = "3.4"` resolves to the same exact identity `(compat, glfw)`. compat.gtest stays under [feature-deps.tests]: that IS a role difference -- it is not resolved at all unless the feature is on. WHAT THE 13 FIXES WERE Same character as the first round -- portability fixes MSVC accepts identically, not mcpp-only patches: - export on std::hash / std::formatter specializations (color.ixx) - `struct ::std::hash<X>{...}` -- GCC rejects the global qualification - friend function templates defined inside a class template, redefined by every instantiation (gui.alloc.ixx, both allocators) - a `using` naming the injected-class-name instead of the base - std::exception(const char*) and std::ifstream(const wchar_t*), both MSVC extensions - `msdf::` qualification used INSIDE namespace mo_yanxi::graphic::msdf - a dependent name missing `typename` - an import reaching a module purview through a #include (allocator2d -- the two imports move into the .ixx, and the header gains a gate so a caller can say it already did them) Two deserve their own note: quad_group's scalar constructor was constrained on `!std::convertible_to<const Ty&, quad_group>` -- deciding whether something converts to quad_group has to consider that very constructor, so the constraint referred to itself. GCC rejects it outright. The replacement is non-recursive; what is genuinely lost is a Ty carrying its own `operator quad_group<T>()`, which nothing here does, and there is no way to ask that question without asking it of this constructor. Noted in the source. -Wchanges-meaning went from per-site fixes to a flag. Naming a member after its type (`vk::fence fence;`, `interp interp{};`) is pervasive in this codebase; it is ill-formed NDR that MSVC allows. Five sites were qualified by hand in the first round and stay that way, but the reachable surface is now dozens, all in someone else's style. GCC ships an opt-out for exactly this legacy shape. Qualifying every site remains the right fix -- upstream's. The extreme case of the same family is Yuria-Shikibe#11: a constructor parameter sharing the name of a member made GCC fail to PARSE `vk::allocator&` at all. LINUX CI .github/workflows/mcpp-linux.yml, alongside build_and_dispatch.yml (Windows/MSVC via xmake) -- the two build systems stay independent. utility and vulkan_wrapper are required jobs. react_flow and the root build are continue-on-error, which is a statement about one known blocker rather than a way to ignore failures: the steps still run and still print what failed, so new breakage stays visible in the log; it just cannot gate the branch on a compiler bug. They become required the day react_flow builds. Also caches ~/.mcpp (the GCC 16 toolchain plus compat.* sources are ~500 MB and only move when a pin does) and installs libfontconfig1-dev for src/platform/font.ixx's Linux backend.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
补齐 XRGUI 适配 mcpp 时索引里仅剩的三个编译型依赖。该项目的源码符合性问题已全部清零,根包构建恰好停在且仅停在这三行:
三者本身也都是通用库(分配器 / 文本整形 / SDF 生成),不是为单个下游定制的。适配记录见 Sunrisepeak/xrgui#1。
设计文档:
.agents/docs/2026-08-12-add-harfbuzz-msdfgen-mimalloc-plan.md形态
compat.mimallocmi_sourcescompat.harfbuzzcompat.msdfgen关于 amalgamation 的两个相反教训
harfbuzz 该用。 上游是 meson,在此复刻意味着跟踪 ~137 个
.cc加一份生成 config。src/harfbuzz.cc是上游自己支持的「只编一个文件」路径,于是sources只有一行且不会与 release 脱节。它同时#include的 CoreText / DirectWrite / GDI / GLib / Graphite2 各在自己的HAVE_*门后,所以只声明HAVE_FREETYPE就能精确选中 FreeType 桥接,其余编译为空。mimalloc 不该用。 它也带 amalgamation(
src/static.c),但src/*.c会在三处出错,且每处都是链接期而非编译期报错:static.c让每个符号重复;free.c与alloc-override.c是被alloc.c#include的、并非独立 TU。故源列表取上游mi_sources(CMakeLists.txt:75-93)。msdfgen:config 不是可选项
core/base.h第 7 行就是#include <msdfgen/msdfgen-config.h>,由 CMake 生成 —— 不生成它连core/都编不了。选择生成它而非传
-D,还有更重要的一层:它让库与消费者天然一致。base.h被每个公开头间接包含,所以这份文件是「SVG / PNG / Skia 哪些存在」的唯一出处。包自己的cxxflags是私有的,消费者#include <msdfgen/msdfgen-ext.h>时看不到,两边会对「有哪些声明」产生分歧。ext/四个单元只编import-font.cpp,其余三个各需一个本索引没有的库(Skia / TinyXML2 / libpng-或-LodePNG),其声明经同一份生成 config 一并消失。另外补了
mcpp_generated/msdfgen/*.h把约定的msdfgen/前缀装回来 —— 上游把两个根头放在仓库根,但所有打包方式(vcpkg / xmake-repo / 发行版)都装到include/msdfgen/,消费者源码写的也是这个。三个刻意不开的开关
理由是同一条:包不能替消费者做它无法保证的承诺。
HB_NO_MTMI_MALLOC_OVERRIDEMSDFGEN_USE_CPP11Bitmap加移动构造,改变跨库边界类型的布局,而直接#include <msdfgen.h>的消费者看不到任何 shim 里的定义CN 镜像
三个都已在 gitcode
mcpp-res建仓发 release,上传与 GLOBAL 字节一致的 tarball:mimalloc19a43af0645c57d348e729d5b31e23e912582911bb1047f795790834d3416221harfbuzz566e996a1b40486954fb7110ffe6eb88a0f7958bb466cdb023b0302618acea4amsdfgen93cd1ad8918c1a78c5c96e82d4f4c77f0eb86c2e7e8579a0967e54196c4b7167sha256 按 SOP 算两遍确认稳定;闭环校验(CN 返回 200 且与 GLOBAL 字节一致)三个全过。
feature
三个都没有实现 feature,各有其因:
sources,按 SKILL 的判定准则不可门控。ext/三个单元形式上符合定义,但每个都需要本索引尚无的库,且开关还要同时写进生成的 config 才能让消费者看见。等这些依赖进索引后可再评估。验证
冷验证(先删
target/与.mcpp/),用validate.yml里钉的 mcpp2026.8.10.3:每个测试都断言行为而非链接:
mi_usable_size必须 ≥ 请求大小(证明指针来自 mimalloc 自己的簿记而非 fallback)、mi_zalloc必须真的清零、对齐必须生效、私有 heap 必须mi_heap_contains自己发出的块。glyph_count必须等于输入长度(若hb-ot-shape.cc没编进 amalgamation 这里会是 0)、cluster必须跟踪输入偏移;再取hb_ft_face_create_referenced的地址,证明 FreeType 后端确实编进来了而不只是被声明。initializeFreetype证明ext/import-font在位、传递依赖到达链接行。测试用msdfgen/前缀 include,让生成的 shim 也被 CI 覆盖。本地 lint 全过:
check_mirror_urls、check_package_name、check_platform_version_parity、check_cross_package_refs、mcpp xpkg parse。已知事项