probe: xmake baseline on unmodified master (do not merge) - #4
Open
Sunrisepeak wants to merge 1 commit into
Open
Conversation
Sunrisepeak
pushed a commit
that referenced
this pull request
Aug 12, 2026
…an MSVC nothing used
TWO SEPARATE THINGS, BOTH FOUND BY READING THE FAILING RUN.
1. src/font/typesetting.rich_text.argument.ixx uses math::vec2 without
importing the module that declares it.
Following its entire import closure:
mo_yanxi.font.manager -> export import mo_yanxi.font -> nothing
mo_yanxi.static_string -> nothing
mo_yanxi.typesetting.util-> nothing
mo_yanxi.heterogeneous -> nothing
mo_yanxi.graphic.color -> export import mo_yanxi.math.vector4
-> vector4 only plain-imports mo_yanxi.math
Nothing re-exports mo_yanxi.math.vector2, which is where vec2 lives. The
file compiled on older MSVC because names leaked across the module boundary;
14.52 does not leak them, and it fails with
error C2039: 'vec2': is not a member of 'mo_yanxi::math'
This is not environment drift -- a probe branch carrying unmodified upstream
master (#4) fails identically, on the same commit whose
upstream run went green in June. The drift only exposed it.
(I had seen this same error under GCC earlier and written it off as a stale
BMI. That was wrong: GCC was reporting the same real defect.)
2. The workflow no longer installs VS 2026 Insider, and pins the runner.
It spent roughly half an hour per run installing MSVC 14.52 preview and
exporting its vcvars -- and then every cl invocation used the preinstalled
14.51:
exported by vcvars : VCToolsVersion 14.52.36629 (VS2026Insider)
used by every cl : .../Visual Studio/18/Enterprise/.../14.51.36231
mcpp's `msvc@system` discovers Visual Studio itself and does not read the
exported environment. Installing a toolchain nothing reads is not a pin, it
is latency. The runner image (windows-2025-vs2026) already ships VS 2026
Enterprise, so `runs-on: windows-2025` -- pinned rather than `latest` -- is
what actually holds MSVC still.
19 steps at the start, 11 now.
Sunrisepeak
pushed a commit
that referenced
this pull request
Aug 12, 2026
This workflow installed VS 2026 Insider from aka.ms/vs/18/insiders on every run and asked vcvars for 14.52. That URL always serves the newest build, so the toolchain moved underneath the build: the same commit that went green upstream on 2026-06-24 (run 28114032617) fails today under 14.52.36629, and a probe branch carrying unmodified upstream master fails the same way (#4). A floating preview is not a pin. The runner image (windows-2025-vs2026) already ships VS 2026 Enterprise with MSVC 14.51.36231, so: - the Insider install step is gone, and with it ~30 minutes per run - vswhere no longer passes -prerelease, which is what selected the Insider instance over the preinstalled one - MSVC_VER is 14.51, which --vs_toolset already interpolates - runs-on is windows-2025 rather than windows-latest: the label is the pin, and `latest` would move the toolchain again Also adds a concurrency group. Each run installs the Vulkan SDK and compiles the whole tree, so leaving superseded runs alive costs a long slot for an answer nobody reads.
Sunrisepeak
force-pushed
the
probe/xmake-baseline
branch
from
August 15, 2026 07:00
c8ee343 to
8d24742
Compare
Sunrisepeak
added a commit
that referenced
this pull request
Aug 16, 2026
* build: add a Windows/MSVC mcpp build alongside xmake
Describes this project for mcpp on Windows only. xmake stays the reference: its
MSVC CI is green, so mcpp.toml is a transcription of xmake.lua rather than a
second opinion, and the new workflow runs both build systems in the same job so
a failure can only mean the transcription is wrong.
WHAT IS DESCRIBED, NOT CHANGED
mcpp.toml the xrgui target: sources, include dirs,
defines, the three bin targets, and the
add_requires() list as pinned packages
mcpp/mo_yanxi_utility/ one manifest per submodule, transcribed from
mcpp/mo_yanxi_vulkan_wrapper/ each repo's own xmake.lua. They live here
mcpp/mo_yanxi_react_flow/ rather than inside the submodules because those
are separate upstream repositories; the globs
reach back out of tree so upstreaming later is
just a move
build.mcpp the counterpart of xmake's media.svg_to_bin
rule and its before_build hook: bin2c per SVG
plus the aggregated assets_summary.h
THE FOUR SOURCE CHANGES, AND WHY EACH IS UNAVOIDABLE
1. XRGUI_FUCK_MSVC_INCLUDE_CPP_HEADER_IN_MODULE is gone (16 files, all
deletions). The macro selected between `#include <plf_hive.h>` and
`import <plf_hive.h>;`. mcpp's M1 scanner rejects an import inside a
conditional preprocessor block even when the branch is inactive, and it
cannot build header units at all -- so the include branch had to become
unconditional. xmake.lua's own comment already said the macro was probably
obsolete on current MSVC ("msvc 新版好像没这问题了,哪天删了"), so the define
is dropped there too. Nothing else changes for xmake: the same include is
what its build was already taking.
2. src.backends/miniaudio/audio.cpp guards its MINIAUDIO_IMPLEMENTATION behind
XRGUI_MINIAUDIO_IMPL_PROVIDED. compat.miniaudio compiles upstream's own
miniaudio.c, so instantiating the implementation again would define every
ma_* symbol twice. xmake does not define the guard macro, so its build is
byte-for-byte what it was.
3. magic_enum comes from the index package rather than the submodule's
module/magic_enum.cppm, because that file also wraps `import std;` in an
#ifdef. The package carries a scan_override for exactly this, which is
cheaper than patching upstream.
4. mcpp/patches/mo_yanxi_vulkan_wrapper.patch hoists one import above an
`#if defined(__cpp_lib_stacktrace)` in stack_trace.cpp -- same scanner rule
as (1), and the only site in a submodule. Six lines, applied by CI.
TWO INTERFACE DETAILS
nanosvg: this repo writes <nanosvg/nanosvg.h> because xrepo installs the headers
one directory deeper than upstream keeps them. compat.nanosvg follows upstream,
so [generated_files] emits two forwarding headers instead of touching every call
site.
VMA: taken from the checked-out submodule, not compat.vulkan-memory-allocator,
because vk_wrap/util/vma.cpp already defines VMA_IMPLEMENTATION.
CI
.github/workflows/mcpp-windows.yml reuses the upstream workflow's environment
verbatim -- VS 2026 Insider with MSVC 14.52 preview, Vulkan SDK, slang, and the
same asset-generation tasks -- then builds with xmake first and mcpp second, and
runs xrgui_tests.
* build(mcpp): drop the vestigial external/stb include dir, name VMA's explicitly
xmake.lua lists ./external/stb and ./external/VulkanMemoryAllocator/include at
the repo root; neither directory exists there. The stb headers actually live in
external/include, and VMA's are inside the vulkan_wrapper submodule -- which is
where <vk_mem_alloc.h> resolves from today, through that target's public
includedir. Naming VMA's real path here as well keeps the root build independent
of how a path dependency propagates include dirs.
* build(mcpp): spell the Windows syslinks the way the index packages do
compat.mimalloc and friends declare their Windows link libraries as -lpsapi
rather than psapi.lib, and those descriptors pass mcpp-index's Windows CI. Use
the proven spelling instead of assuming ldflags reach link.exe verbatim.
* ci: cancel superseded mcpp-windows runs
Every run installs VS 2026 Insider and the Vulkan SDK before it compiles
anything, so a stale run left alive after a new push burns a long slot for a
result that is already obsolete.
* docs: record the Windows/mcpp adaptation and why each source change exists
* ci: make the mcpp workflow only build with mcpp
build_and_dispatch.yml already builds this PR with xmake, on the same runner
image and the same MSVC. Repeating that here cost another VS 2026 Insider
install per run and told us nothing the other workflow was not already saying.
xmake is not installed at all now. Its xrgui.gen_slang / xrgui.gen_icon tasks
are thin wrappers around properties/build_util/slang_builder.py and
properties/assets_raw/svg_normalize.py, so the job calls those directly and the
generated assets are identical.
* ci: install node, python, slang and mcpp with xlings
All four are in xim-pkgindex, and mcpp already reads that registry to resolve
its own toolchains and packages -- so the CI was hand-rolling downloads for
tools the ecosystem already publishes. One `xlings install` replaces two
setup-* actions and two Invoke-WebRequest blocks, and the versions now come from
the same index the build itself uses.
The asset scripts are invoked with `python` rather than `py`: the Windows
launcher comes with actions/setup-python, not with the xlings package. The
install step checks each tool resolves on PATH so a miss fails there instead of
three steps later.
Vulkan SDK and MSVC stay as they were -- neither is in the index.
* ci: put xlings on PATH inside the step that installs it
The installer edits the user profile and prints 'restart terminal to refresh
PATH'. Appending to GITHUB_PATH only reaches later steps, so calling xlings in
the same step failed with 'The term xlings is not recognized'. Set $env:PATH
too, and locate the directory by finding xlings.exe rather than guessing --
~/.xlings has both bin/ and subos/default/bin/.
* ci: stop the mcpp workflow starting twice per push
With the feature branch listed under `push` and a PR open, each push started
two runs -- one for refs/heads/feat/mcpp-windows and one for refs/pull/N/merge.
They did not cancel each other because the concurrency group keyed on
github.ref, which differs between the two.
Now push only covers master and everything else arrives through pull_request,
and the group keys on head_ref when there is a PR.
* build: run the asset generators from build.mcpp
xmake's xrgui.gen_icon and xrgui.gen_slang are thin wrappers around
properties/assets_raw/svg_normalize.py and properties/build_util/slang_builder.py.
build.mcpp now calls both, so `mcpp build` is self-contained and a local
checkout gets the same assets CI does instead of needing a separate step.
Both are skipped, with a message, when their tools are missing -- python for the
icons, python and slangc for the shaders. That is deliberate: the tree still has
to build without them, which is what the empty assets_summary.h is for.
FAILURE IS A WARNING, NOT AN ABORT
Their exit status cannot be trusted. svg_normalize.py returns 0 even when the
npx child crashes -- observed locally, where Node fails with ERR_DLOPEN_FAILED
and the script still exits 0. Aborting on a non-zero status would therefore be
both useless (it does not fire) and harmful (a machine with a broken Node could
not build at all). So build.mcpp warns and continues, and CI gains an
"Assert generated assets exist" step that checks the OUTPUTS -- the only signal
here that means anything.
CI DROPS TWO STEPS
The separate asset-generation step is gone, and so is `pip install tomli`:
slang_builder.py uses Python 3.11+'s built-in tomllib and only falls back to
tomli on older interpreters. xlings installs 3.13. That line was inherited from
the upstream workflow, whose own comment says it was an assumption to adjust.
For the record, since it is easy to assume otherwise: mcpp itself needs neither
Python nor Node. It is a self-contained binary and the C++ build needs only the
toolchain. Both are purely for asset generation, and Node's single use is the
oslllo-svg-fixer npm package, which runs a browser engine to flatten SVG strokes
into fills so msdfgen can consume them.
* build: stage runtime assets next to the binaries, as xmake's after_build does
xmake copies properties/assets and properties/vk_layer_settings.txt into the
target dir once the build finishes, so the image can find its data. Without it
the CI artifact is an executable with nothing to load.
build.mcpp cannot do this itself. It runs during prepare, and the binary
directory is not in the environment contract -- ${mcpp.bin_dir} exists only as
an action interpolation. So this declares two `role = "artifact"` actions, whose
inputs are link outputs and which therefore run after the link.
One command copies the whole tree, but every output has to be named: mcpp fixes
the file set during prepare. That is workable here because the set is five files
and because the generated shaders are already on disk by this point -- the
generators run earlier in the same build.mcpp.
Verified on Linux: both edges appear in build.ninja as ARTIFACT nodes, all five
outputs register as default targets, and running them puts assets/ and
vk_layer_settings.txt in bin/.
Two more lines from the same xmake block:
add_syslinks(...) already in [target.windows.build] ldflags
set_policy("build.optimization.lto") [profile.release] lto = true, NOT enabled
lto is supported -- confirmed by watching it reach the compiler -- but a preview
MSVC plus C++ modules plus LTO is three variables at once on a build that has
not gone green yet. It goes on after, where a regression can be attributed.
* build: stage the runtime data with one action, and correct what artifact means
Two actions were one too many. A single copy command takes several sources, so
there is no reason to split a directory and a plain file across two edges. On
POSIX that is `cp -r <assets> <vk_layer_settings.txt> <bin>/`; on Windows it is
Copy-Item, which handles a directory and a file in the same call -- `copy` and
`xcopy` each only manage half of that, which is what led to the split.
Also corrects the comment. `role = "artifact"` does NOT by itself order the edge
after the link; the docs' "runs after the link" holds because such an action's
inputs are typically link outputs. These inputs are source files, and checking
build.ninja confirms the edge depends on no link output at all, so ninja may run
the copy whenever it likes. That is fine -- runtime data does not depend on the
binaries -- but the comment claimed an ordering the graph does not provide.
Forcing the ordering would mean naming a specific target as an input, and which
targets exist depends on the active features, so it would be brittle for no
gain.
Verified on Linux: one ARTIFACT edge, five declared outputs, and running it
puts assets/ and vk_layer_settings.txt in bin/.
* build(mcpp): use the dynamic CRT, as xmake does
xmake.lua has set_runtimes(is_mode("debug") and "MDd" or "MD"). I missed it,
so the build ran on mcpp's default cxx_runtime -- self-contained, which is /MT
on MSVC.
That is not just a difference from xmake; it was internally inconsistent. The
std module interface came out built for the static CRT while the project's own
TUs compiled against the dynamic one:
warning C5050: Possible incompatible environment while importing module
'std': _MSVC_MT is defined in module command line and not
in current command line
corecrt_malloc.h(89): error C2375: 'free': redefinition; different linkage
cxx_runtime = "host-coupled" is the /MD side of that contract, which puts
std.ifc and every TU on the same runtime and matches what xmake ships.
* ci: drop the loose cache restore-keys
~/.mcpp holds compiled artifacts whose validity depends on the compile flags,
and `restore-keys: mcpp-win-` let a changed manifest still hit an older entry.
That is how the cxx_runtime fix appeared not to work: the run restored a std.ifc
built for the static CRT, so cl still reported
warning C5050: _MSVC_MT is defined in module command line and not in
current command line
against TUs that were now /MD, and failed in corecrt_malloc.h exactly as before.
The key now covers build.mcpp as well, and a miss is a cold cache rather than a
near-miss.
* fix: import the module that declares math::vec2, and stop installing an MSVC nothing used
TWO SEPARATE THINGS, BOTH FOUND BY READING THE FAILING RUN.
1. src/font/typesetting.rich_text.argument.ixx uses math::vec2 without
importing the module that declares it.
Following its entire import closure:
mo_yanxi.font.manager -> export import mo_yanxi.font -> nothing
mo_yanxi.static_string -> nothing
mo_yanxi.typesetting.util-> nothing
mo_yanxi.heterogeneous -> nothing
mo_yanxi.graphic.color -> export import mo_yanxi.math.vector4
-> vector4 only plain-imports mo_yanxi.math
Nothing re-exports mo_yanxi.math.vector2, which is where vec2 lives. The
file compiled on older MSVC because names leaked across the module boundary;
14.52 does not leak them, and it fails with
error C2039: 'vec2': is not a member of 'mo_yanxi::math'
This is not environment drift -- a probe branch carrying unmodified upstream
master (#4) fails identically, on the same commit whose
upstream run went green in June. The drift only exposed it.
(I had seen this same error under GCC earlier and written it off as a stale
BMI. That was wrong: GCC was reporting the same real defect.)
2. The workflow no longer installs VS 2026 Insider, and pins the runner.
It spent roughly half an hour per run installing MSVC 14.52 preview and
exporting its vcvars -- and then every cl invocation used the preinstalled
14.51:
exported by vcvars : VCToolsVersion 14.52.36629 (VS2026Insider)
used by every cl : .../Visual Studio/18/Enterprise/.../14.51.36231
mcpp's `msvc@system` discovers Visual Studio itself and does not read the
exported environment. Installing a toolchain nothing reads is not a pin, it
is latency. The runner image (windows-2025-vs2026) already ships VS 2026
Enterprise, so `runs-on: windows-2025` -- pinned rather than `latest` -- is
what actually holds MSVC still.
19 steps at the start, 11 now.
* build(mcpp): match the runtime the std module is actually built with
cxx_runtime = "host-coupled" (/MD, what xmake uses) does not work: mcpp builds
the std module interface with the static runtime whatever this is set to, so the
project TUs came out /MD against a /MT std.ifc and cl failed in corecrt_malloc.h
with C2375 'free': redefinition; different linkage.
Verified against a cold cache -- the previous attempt restored a stale artifact,
this one did not, and the log carries no command building std.ifc at all. It
comes from mcpp's global std cache, built /MT.
So follow std rather than fight it. self-contained is /MT and is mcpp's own
default, which puts the packages, the std module and this project on one
runtime. The difference from xmake is what the artifact promises about the
machine that runs it, not semantics.
Worth reporting upstream: cxx_runtime should reach the std module build.
* ci: pin the xmake build to the toolset the runner ships
This workflow installed VS 2026 Insider from aka.ms/vs/18/insiders on every run
and asked vcvars for 14.52. That URL always serves the newest build, so the
toolchain moved underneath the build: the same commit that went green upstream
on 2026-06-24 (run 28114032617) fails today under 14.52.36629, and a probe
branch carrying unmodified upstream master fails the same way
(#4). A floating preview is not a pin.
The runner image (windows-2025-vs2026) already ships VS 2026 Enterprise with
MSVC 14.51.36231, so:
- the Insider install step is gone, and with it ~30 minutes per run
- vswhere no longer passes -prerelease, which is what selected the Insider
instance over the preinstalled one
- MSVC_VER is 14.51, which --vs_toolset already interpolates
- runs-on is windows-2025 rather than windows-latest: the label is the pin,
and `latest` would move the toolchain again
Also adds a concurrency group. Each run installs the Vulkan SDK and compiles the
whole tree, so leaving superseded runs alive costs a long slot for an answer
nobody reads.
* fix: give segmented_layout the small_vector header, and pin MSVC by exact toolset
TWO THINGS, THE SECOND CORRECTING MY PREVIOUS COMMIT.
1. src/font/typesetting.segmented_layout.ixx now includes gch/small_vector.hpp
itself.
It instantiates algorithms over gch::small_vector_iterator but never named
the header -- it inherited the declarations from mo_yanxi.typesetting.rich_text.
That worked while rich_text reached the header through `import <...>;`,
because a header unit exports what it declares. Moving that to a global
module fragment include (which mcpp requires, since it supports neither
header units nor imports inside conditional blocks) changed the rule: a GMF
declaration the purview never names is discarded rather than written into
the BMI, and operator-(it, it) is a namespace-scope template found only by
ADL at instantiation time. So the importer stopped finding it:
xutility(1865): error C2679: binary '-': no operator found which takes a
right-hand operand of type '_InIt'
[_InIt=gch::small_vector_iterator<const hb_feature_t*, __int64>]
This is a regression from my header-unit removal, not drift. Including the
header where the types are used is what modules ask for anyway.
2. The MSVC pin is by exact toolset, and 14.51 is not usable.
My previous commit pinned to the runner's preinstalled 14.51 to stop chasing
a floating preview. That was wrong: 14.51 does not compile this codebase at
all --
font.manager.ixx
vector2.ixx(67): fatal error C1001: Internal compiler error.
(compiler file '...\Compiler\CxxFE\sl\p1\c\template.cpp', line 26415)
note: IFC import detected.
-- which is presumably why the workflow reached for a preview to begin with.
So the Insider install is back, and the pin is what it can actually be: the
job asks vcvars for 14.52, then checks VCToolsVersion is exactly 14.52.36629
and fails with a clear message if it is not. aka.ms/vs/18/insiders will keep
moving; this makes it move visibly instead of silently changing the compiler
under a green checkmark.
runs-on stays pinned at windows-2025, and a concurrency group cancels
superseded runs -- each one installs VS 2026 Insider and the Vulkan SDK
before compiling anything.
* build: give the mcpp job the same MSVC the xmake job builds with
The two legs were not comparing the same thing. mcpp resolves `msvc@system`
by searching vswhere, then VSINSTALLDIR / VS*COMNTOOLS, then the standard
Program Files paths -- so with no vcvars exported it found the runner image's
preinstalled VS 2026 Enterprise and built with 14.51.36231, while xmake built
with the 14.52 preview. A previous revision removed the Insider install from
this job on the belief that nothing read it; the upstream green run disproves
that plainly, every cl in it being
C:\VS2026Insider\VC\Tools\MSVC\14.52.36510\bin\HostX64\x64\cl.exe
and 14.51 does not survive this codebase anyway (C1001 at vector2.ixx:67).
So install and export it, exactly as build_and_dispatch.yml does, and fail the
job if mcpp still reports 14.51. VCToolsVersion joins the cache key for the
same reason: ~/.mcpp holds .ifc files, and an .ifc and its consumer must come
from one compiler -- restoring a std module built by another cl is what
produced the C5050/C2375 pair this job kept dying on.
cxx_runtime follows from that. "self-contained" was chosen to match a std
module cl reported as /MT, but mcpp does not implement it for the MSVC runtime
and says so, silently using host-coupled; the setting was a no-op and the
mismatch was the cross-compiler cache. Written out as host-coupled now, which
is /MD -- what xmake's set_runtimes("MD") asks for.
Both legs now assert the 14.52 line rather than an exact build number.
aka.ms/vs/18/insiders always serves the newest Insider, so pinning the build
number turns Microsoft's release schedule into a red CI on commits that
changed nothing; the drift is worth a warning, not a failure.
Also: text_edit.ixx compares two layout_configs, whose defaulted operator==
reaches rich_text_fallback_style::features, a gch::small_vector. gch declares
that container's operator== as a free function template rather than a hidden
friend, so it is not decl-reachable from the exported class and its module
discards it along with the rest of the global module fragment. Overload
resolution then reached for small_vector's private allocator base, which 14.52
reports as C2243 against ui.util.ixx, where the template is defined. Same
shape, and same fix, as typesetting.segmented_layout.ixx.
* docs: separate what mcpp needs from what the MSVC drift forced
Four source changes are for mcpp's scanner and one duplicate symbol; three more
are neither, and would be needed by the xmake leg alone -- unmodified master no
longer compiles on the Insider toolset that has replaced the one its last green
run used. Recording which is which, and the toolchain findings that cost the
most to establish: how mcpp resolves msvc@system, why VCToolsVersion has to be
in the cache key, and that cxx_runtime has exactly one reachable value on MSVC.
* build: pin mcpp to the version that fixes the std module runtime, fix the comparison at its source
Two separate things, both diagnosed from mcpp's own source rather than guessed
at from the outside.
mcpp version. The C5050/C2375 pair this job kept dying on was not a stale
cache: mcpp compiled the std module with no runtime flag at all, so cl defaulted
it to /MT while the project TUs got /MD (mcpp#422, fixed in 2026.8.15.1 by
msvc_crt_flag in src/toolchain/dialect.cppm). `xlings install mcpp` served
2026.8.11.3, one release short, and reproduced it on a provably cold cache. So
ask for the version by name, make it active, and check what ended up on PATH --
mcpp is the thing under test here and should not be whatever the index served
that hour.
MSVC. The previous commit added a VS 2026 Insider install and a vcvars export to
this job so it would compile with the same toolset as the xmake leg. It does
not work, and cannot: mcpp's discovery asks vswhere without -prerelease, so an
Insider instance is invisible to it, and the VSINSTALLDIR fallback that a
developer command prompt would set is only consulted when vswhere finds nothing
(src/toolchain/msvc.cppm). The build log named Enterprise 14.51.36231 either
way -- the install was seven minutes a run for no change in what compiled. It is
gone again, this time with the measurement written down, and the divergence
between the two legs recorded where someone will find it rather than papered
over. Closing it is a one-line change in mcpp, not here.
The cache key now carries the *detected* toolset instead of a literal, so a
runner image that moves MSVC gets a cold cache rather than a std module built by
a compiler that is no longer installed.
Source: rich_text_fallback_style::operator== is written out instead of
defaulted. A defaulted comparison is synthesized wherever it is odr-used, which
is every importer that compares two layout_configs -- text_edit.ixx, label.ixx,
and one more each time somebody adds a setter. None of them can see gch's
operator== for small_vector (a free function template, so not decl-reachable
from the class that holds one), and each resolves the comparison to
small_vector's private allocator base instead: C2243, reported against
ui.util.ixx where try_modify is defined rather than against the file that would
have to change. Spelling the body binds those names once, in the module whose
global module fragment includes the header. The include added to text_edit.ixx
in the previous commit is reverted -- it fixed one instantiation site out of N.
* ci(mcpp): make mcpp build with the preview toolset, since 14.51 cannot build this at all
The previous commit settled for the toolset mcpp picks on its own, on the
grounds that nothing here could change it. The first half of that was wrong in
a way only a run could show: the image's 14.51.36231 does not merely differ from
the xmake leg's compiler, it cannot compile this codebase.
mo_yanxi_utility/src/utility/math/basic/vector2.ixx(67):
fatal error C1001: Internal compiler error.
(compiler file '...\CxxFE\sl\p1\c\template.cpp', line 26415)
note: IFC import detected.
instantiating math::vector2<float>::ceil. That is the same ICE the xmake
workflow's comments claimed without a citation; it now has one.
The second half was right: mcpp cannot be told which MSVC to use. It probes
vswhere with no -prerelease, so an Insider instance is invisible to it, and the
VSINSTALLDIR fallback -- the only lever a caller has -- is reached only when
that probe comes up empty. So this installs the preview to a path of our
choosing, exports vcvars straight from it, and moves vswhere.exe aside so the
fallback runs. It is a workaround for mcpp and is labelled as one: a one-line
change there (pass -prerelease, or let an explicit VSINSTALLDIR win) deletes the
whole step.
The toolchain check that follows is now an assertion rather than a note, because
the job can finally decide the answer. Resolving 14.51 does not produce a
slightly worse build, it produces C1001 some minutes later, and this says so at
the point where it is still cheap to read.
Same run confirmed the other half of the previous commit: with mcpp 2026.8.15.3
the only C5050 left is _UTF8 (the std module is not built with this project's
/utf-8, which is harmless). _MSVC_MT, _MSVC_MD and _DLL are all gone, and with
them C2375 in corecrt_malloc.h.
* fix: compare rich_text_fallback_style::features through its data pointer
Writing the operator out was necessary but not sufficient. `lhs.features ==
rhs.features` calls gch::operator==, which is itself a function template and so
instantiates where it is called -- in the importer -- carrying std::equal and
its need for gch's operator-(a, b) along with it. That operator is another free
function template, equally absent from the BMI, so the failure came back wearing
a different hat: a wall of C2794 / C3376 / C2062 inside <xutility> instead of
one C2243.
const hb_feature_t* has none of this: no BMI lookup, no gch templates, same
meaning. Both legs reached the identical error before this, which at least
confirms they are now compiling the same code with the same compiler.
* fix: fill feature_stack_ from the container's data pointer, not its iterators
Second site of the rule the previous commit established, and the last error left
on either leg. layout_context_impl::reset builds its std::vector<hb_feature_t>
from a pair of gch::small_vector iterators; vector's range constructor needs
operator-(a, b) to size the allocation, and that is a free function template in
gch, discarded from the BMI along with the rest of the global module fragment.
The member belongs to a class template, so it instantiates in whichever module
imports it -- label.ixx and segmented_layout.ixx here -- and none of them can see
gch's header.
The rule, for whoever hits this next: a gch iterator is fine inside the TU that
includes the header, and breaks anywhere that instantiates in another module.
Everything else in this tree holds its small_vectors as private members of
non-template classes or as locals in .cpp files, which is why only these two
turned up.
* build(mcpp): declare the Windows libraries with link_lib, not ldflags
Everything compiled; nothing linked. 235 unresolved externals, and the reason
was one line above them in the log:
LNK4044: unrecognized option '/luser32'; ignored
mcpp's ldflags reach the linker verbatim -- plan.cppm calls it "a flat string in
the link command" -- so a GNU spelling arrives at MSVC's link.exe unchanged, and
link.exe warns and carries on rather than failing. Every link flag in the
command was dropped that way. link_lib and link_search go through the toolchain
dialect instead (Transform::LibFlag / LibSearchPath), which spells `user32` as
user32.lib here and -luser32 under a GNU linker, so build.mcpp is where this
belongs.
Not all of it is ours. compat.glfw declares `-lgdi32`, compat.mimalloc
`-lpsapi -lshell32 -luser32 -ladvapi32 -lbcrypt`, and compat.vulkan
`-Llib -lvulkan-1` -- all as ldflags, all dropped for the same reason, which is
why the missing symbols ran from __imp_DestroyIcon through vkCreateDevice. Until
those packages say it in a form both linkers can consume, this repeats them,
with compat.vulkan's import library located through dep_dir rather than a
guessed path. That block is compensating for package metadata and is marked as
such.
* build(mcpp): link vulkan-1, and let compat.msdfgen decide about C++11
Down to two causes from 116 unresolved externals.
vulkan-1 was never named: dep_dir("compat.vulkan") came back empty, and the
branch that handled that only printed a warning -- to a stdout mcpp reads as
directives and does not echo, so it said nothing at all. Now the search dir is
whichever of the package's lib/ or $VULKAN_SDK/{Lib,lib} actually holds
vulkan-1.lib (the SDK being what mo_yanxi_vulkan_wrapper's xmake.lua links
against), and link_lib is called either way. Naming a library that cannot be
found fails with "cannot open input file 'vulkan-1.lib'", which points at the
problem; the silent path produced a hundred vk* symbols that did not.
msdfgen was one symbol, Contour::addEdge(EdgeHolder&&). src/graphic/msdf.{cpp,ixx}
`#define MSDFGEN_USE_CPP11` before including the headers, but compat.msdfgen is
built with it off and publishes that through the msdfgen-config.h every public
header includes -- which is precisely the mechanism that package uses to keep
both sides agreeing on which declarations exist. Defining it ourselves broke the
agreement in one direction: declared for our TUs, absent from the library.
XRGUI_MSDFGEN_NO_CPP11 lets the package's answer stand under mcpp. xrepo's
msdfgen does build with it, so the xmake build keeps the define and is unchanged.
* build(mcpp): probe for slangc by name, not by asking it its version
The library and xrgui_hello link now. What failed was the assertion after them:
40 normalized icons, 0 compiled shaders. build.mcpp gates the shader generator
on `have_tool("slangc")`, which ran `slangc --version` and took a non-zero exit
to mean "not installed" -- while the workflow's own `Get-Command slangc` had
succeeded two steps earlier. Whether slangc spells that flag differently or
exits non-zero after printing it, the two questions are not the same one, and
only the second is what the gate wants to ask. `where` / `command -v` asks it.
The workflow now records both answers next to each other at install time, so if
this is not the whole story the next run says so in one line instead of in a
missing directory.
Diagnostics move to stderr, since stdout is the directive stream. That does not
make them visible -- mcpp captures both, merged, and echoes them only when the
program fails -- and the comment says so rather than implying otherwise. The
real gate stays where it was: CI asserting on the outputs, which is exactly what
caught this.
* docs: record what the slangc probe actually answered
Both legs are green. Replacing the guess in build.mcpp's comment with the
measurement that settled it: slangc has no --version at all, so probing with
one called an installed compiler missing and skipped the shader generator --
"normalized icons: 40 compiled shaders: 0". Now 40 and 17.
Also notes, where the next reader will look for it, that build.mcpp's output is
captured and echoed only on failure, so a diagnostic there is not a substitute
for CI asserting on the outputs.
* ci(mcpp): strip UTF-8 BOMs from submodule module interfaces
The intermittent failure was not intermittent. mcpp reads module declarations
line by line and nothing in its source touches a byte-order mark, so a file
opening with EF BB BF immediately followed by `export module X;` provides no
module as far as the scanner is concerned. Its compile edge then gets no
$bmi_out while the MSVC rule still emits `/ifcOutput $bmi_out`, and cl reads the
next token as the filename:
array_queue.ixx(191): error C3474: could not open output file '/interface'
Eight files under external/ carry a BOM, but only two open with the module
declaration -- array_queue.ixx and array_stack.ixx. The rest open with `module;`
and put `export module` on a later line, where the BOM cannot reach it. Those
two land in different feature builds, which is why consecutive runs failed at
different steps and one run passed outright.
Stripped rather than patched: a patch whose entire content is three invisible
bytes is not reviewable. Safe, because /utf-8 is on the compile line and nothing
is inferring the encoding from a mark.
* ci(mcpp): delete the vswhere workaround -- mcpp no longer needs it
The step that moved `vswhere.exe` aside is gone. It was always described here
as a patch for mcpp rather than something this repo should own, and mcpp
2026.8.16.1 (mcpp#432/#434) removed the reason for it: an explicitly-set
VSINSTALLDIR now outranks the vswhere probe, because a guess should not
override an answer.
What makes this worth doing rather than merely tidy: **the toolset assertion
gets STRONGER by deleting it.** vswhere.exe is left in place, and so is the
preinstalled Enterprise 14.51 that it ranks first -- nothing removes the
wrong answer, it just has to lose. While the workaround was there,
"VSINSTALLDIR was honoured" and "vswhere found nothing" produced identical
observations, so the job could not distinguish a fixed mcpp from a hidden
one.
If mcpp ever regresses to preferring the probe, this job now goes red naming
14.51 rather than silently building with a compiler that ICEs on this
codebase forty minutes later.
MCPP_VER floor moves to 2026.8.16.1 for the same reason.
---------
Co-authored-by: Sunrisepeak <x.d2learn.org@gmail.com>
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.
Upstream master 6d63715 plus one markdown file. Establishes whether the xmake MSVC failure seen on #3 is a regression from that PR or environment drift: the same commit went green upstream on 2026-06-24 (run 28114032617). Do not merge.