Skip to content

tmp(ci): probe the three windows images — do NOT merge - #387

Closed
Sunrisepeak wants to merge 2 commits into
mainfrom
tmp/windows-image-probe
Closed

tmp(ci): probe the three windows images — do NOT merge#387
Sunrisepeak wants to merge 2 commits into
mainfrom
tmp/windows-image-probe

Conversation

@Sunrisepeak

Copy link
Copy Markdown
Member

Temporary. Not for merge. Delete the branch once the question below is answered.

The question

#385 pinned the windows leg to windows-2022 because windows-latest (= windows-2025-vs2026, MSVC STL 14.51) cannot compile huxerui.huxerui — clang instantiates MSVC STL's vectorized std::find for a 24-byte trivially-comparable type and hits static_assert(false, "unexpected size"). Filed as mcpp-community/mcpp#609.

The pin worked, and it cost three members. vulkan, eui-neo-vulkan and vulkan-hpp-module now fail at run time with 0xC0000135 (STATUS_DLL_NOT_FOUND); they compile fine. The Vulkan loader is not a Windows component — it ships with a GPU driver or the SDK — so whether an image carries vulkan-1.dll is a property of the image, and windows-2022 does not have it.

So the pin is a trade, not a win:

image huxerui-module vulkan ×3
windows-latest (VS2026 / STL 14.51) FAIL — compile ok
windows-2022 (VS2022 / STL 14.3x) ok FAIL — no loader
windows-2025 never tried never tried

windows-2025 is the obvious candidate: old enough to miss 14.51's vectorized find, new enough to plausibly carry the loader.

What this runs

Both questions, on all three images, in one run:

  1. Inventory firstvulkan-1.dll present or absent (both System32 and SysWOW64, with file version), and every MSVC toolset directory on the box. Printed before any build, so the answer survives a build behaving unexpectedly.
  2. mcpp test -p huxerui-module — the compile question
  3. mcpp test -p vulkan — the loader question

Both are continue-on-error, so every image reports a complete row rather than stopping at its first red, and a Row step prints the pair.

Why a separate file

validate.yml's paths: names only itself, so adding a new workflow file selects no members. This run is two members on three images — minutes, not the ~50 the full matrix costs. Changing validate.yml to ask the same question would have selected everything.

After

Whatever it says, the follow-up is a one-line change to validate.yml's emit windows … and deleting this file. If windows-2025 clears both, that is the pin. If it clears neither, the trade is real and the choice has to be argued rather than discovered.

…ogether

TEMPORARY — delete once the windows image question is settled.

#385 pinned the windows leg to `windows-2022` because `windows-latest`
(= windows-2025-vs2026, MSVC STL 14.51) cannot compile `huxerui.huxerui`:
clang instantiates MSVC STL's vectorized `std::find` for a 24-byte type and
hits `static_assert(false, "unexpected size")` (mcpp-community/mcpp#609).

The pin worked and cost three members. `vulkan`, `eui-neo-vulkan` and
`vulkan-hpp-module` now fail at RUN time with 0xC0000135
(STATUS_DLL_NOT_FOUND) — they compile fine. The Vulkan loader is not a
Windows component; it arrives with a GPU driver or the SDK, so whether an
image carries `vulkan-1.dll` is a property of the image. So the pin is a
TRADE: one compile failure removed, three load failures created.

`windows-2025` was never tried, and it is the obvious candidate — old
enough to miss 14.51's vectorized find, new enough to plausibly carry the
loader. This asks all three images both questions at once:

  * does `vulkan-1.dll` exist (the vulkan members' failure), and
  * does `huxerui-module` compile (huxerui's failure)

`continue-on-error` on both so every image reports a full row instead of
stopping at its first red, and the image inventory is printed BEFORE any
build so the answer is visible even if the builds behave unexpectedly.

A separate FILE, not a change to validate.yml, and that is the point:
validate.yml's `paths:` names only itself, so adding this selects no
members and the run is two members on three images instead of the full
matrix. Nothing here is meant to merge.
…C 14.44

The inventory step already paid for itself. `windows-2025` carries THREE
toolsets:

    MSVC\14.29.30133
    MSVC\14.44.35207
    MSVC\14.51.36231     <- clang picks this one, and dies in it

So the trade this branch exists to resolve may not be a trade at all. The
loader question and the STL question were assumed to move together because
both were read off the image label; they do not. A new image carries the
Vulkan loader AND an older STL — the only thing choosing 14.51 is clang's
default of newest-wins.

Two ways to ask it otherwise, probed separately because they fail in
different places: `VCToolsInstallDir`, which is what a developer prompt
exports and what clang's MSVC detection reads, and clang's own
`/vctoolsdir`. If neither reaches the compile, toolset selection belongs to
mcpp and CI cannot fix it — which is itself the answer, just a different
one.

The last step prints which MSVC path the build actually touched, pass or
fail. Without it a pass proves nothing: "compiled against 14.44" and
"compiled against 14.51 and got lucky" look the same from the outcome.
@Sunrisepeak

Copy link
Copy Markdown
Member Author

Closing with #388. The probe did its job — the table it produced is what settled the question, including the part that sank #388:

image vulkan-1.dll huxerui-module vulkan
windows-latest (VS2026 / STL 14.51) present fail pass
windows-2025 present fail pass
windows-2022 absent pass fail

And the inventory step, which is the part worth remembering: windows-2025 ships three toolsets (14.29.30133, 14.44.35207, 14.51.36231) and clang takes the newest. That is the fact everything after it was built on — including the four rounds of #388 that established the newest is not steerable without breaking other consumers.

Deleting the branch: a scheduled-off, dispatch-only workflow left in the tree is a loaded gun with no owner.

@Sunrisepeak
Sunrisepeak deleted the tmp/windows-image-probe branch September 11, 2026 09:39
Sunrisepeak added a commit that referenced this pull request Sep 11, 2026
…ne else does

`vulkan-1.dll` is not part of Windows. It arrives with a GPU driver, with
LunarG's Vulkan Runtime redistributable, or bundled beside an application,
so a runner with no driver has no loader and anything linking
`vulkan-1.lib` dies at process start with 0xC0000135, before main.

MEASURED across the three images (#387 probe, run 34569282837):

    windows-2022    vulkan-1.dll absent    MSVC 14.29/14.44
                    huxerui PASS           vulkan FAIL 0xC0000135
    windows-2025    vulkan-1.dll PRESENT   MSVC +14.51
                    huxerui FAIL (STL)     vulkan PASS
    windows-latest  same as windows-2025

Neither image satisfies both. This leg is pinned to `windows-2022` to
dodge the MSVC STL 14.51 bug (mcpp-community/mcpp#609,
microsoft/STL#6294), and windows-2022 is the image without the loader.

THIS REPLACES THE PACKAGE-DEPENDENCY APPROACH, which did not work. The
first version of this PR had `compat.vulkan`'s windows branch declare
`xim:vulkan-loader@>=1.4.313`. Three runs:

  1. cold store -- loader installed, its config() hook failed
     (`subos.env` PATH declaration; fixed by openxlings/xim-pkgindex#819,
     asymmetry filed as mcpp-community/mcpp#614)
  2. warm store -- `compat.vulkan@1.4.357.0` already installed, so its
     dependency closure was never re-evaluated and the loader was not
     installed at all
  3. cold store again, after deleting the three registry caches -- still
     no loader, and no error saying why

The declaration sits in `xpm.windows` beside working precedents
(`compat.cuda-runtime`, `compat.cudart`), and range versions have
precedent too (`compat.openssl`, `compat.vulkan-runtime`), so the shape
is not obviously wrong -- but three runs produced no loader and no
diagnostic, and chasing it further is not worth it for a problem whose
actual shape is "the runner is missing a redistributable".

WHAT EVERYONE ELSE DOES, since this is a common Windows problem:

  * dynamic loading in the consumer -- volk, Vulkan-Hpp's
    VULKAN_HPP_DISPATCH_LOADER_DYNAMIC, glfwVulkanSupported(),
    SDL_Vulkan_LoadLibrary. The process starts and degrades gracefully
    instead of dying before main. This is the robust answer for
    applications.
  * rely on the GPU driver -- what most games do, and sound: a machine
    that can run Vulkan has a driver, and the driver brought the loader.
  * ship the loader -- Apache-2.0, which is what the LunarG Runtime
    redistributable is for.
  * on CI specifically -- install the Runtime/SDK, or register a software
    ICD (SwiftShader, lavapipe) when device-level coverage is wanted.

These members assert loader-level calls only (`vkEnumerateInstanceVersion`,
instance extension enumeration), deliberately: the loader advertises WSI
extensions only when an ICD supports them, so asserting on those would be
testing the runner's hardware. A loader with no ICD is exactly the right
amount here.

The payload is the one built for openxlings/xim-pkgindex#818 -- built on a
runner from Khronos' source, and the build loads the DLL and resolves
vkEnumerateInstanceVersion, vkCreateInstance and vkGetInstanceProcAddr
before publishing. Hash-pinned here, and the step is idempotent: if the
image ever grows the DLL, it leaves it alone.

The xim-pkgindex loader package stays. It is a real ecosystem capability
for a driverless Windows machine; it is simply not the layer that fixes a
missing redistributable on a CI runner.

Co-authored-by: sunrisepeak <x.d2learn.org@gmail.com>
Sunrisepeak added a commit that referenced this pull request Sep 11, 2026
* feat(compat.vulkan): 1.4.357.3 ships the Vulkan loader on Windows

A Windows program that links `vulkan-1.lib` needs `vulkan-1.dll` at process
start, and that DLL is not part of Windows. It arrives with a GPU driver, with
LunarG's Vulkan Runtime redistributable, or beside an application. A machine
without a driver has none, and the program dies before `main` with 0xC0000135
(STATUS_DLL_NOT_FOUND). Measured on GitHub's `windows-2022` image (#387 probe,
run 34569282837): `vulkan`, `eui-neo-vulkan` and `vulkan-hpp-module` all fail
that way, while images that happen to carry a driver pass.

WHAT CHANGES

  compat.vulkan 1.4.357.3   windows artifact adds bin/vulkan-1.dll and
                            LICENSE.txt; mcpp.windows.runtime gains
                            library_dirs = { "bin" }
  khronos.vulkan-hpp 1.4.357.1   same headers, pin -> compat.vulkan 1.4.357.3
  compat.eui-neo 0.5.9.1    upstream 0.5.9 unchanged, `vulkan` feature pin
                            -> compat.vulkan 1.4.357.3
  members                   vulkan 1.4.357.3, vulkan-hpp-module 1.4.357.1,
                            eui-neo-vulkan 0.5.9.1
  tests/examples/vulkan     on Windows, asserts the mapped vulkan-1.dll lives
                            in the executable's own directory

THE MECHANISM ALREADY EXISTS AND IS NOT NEW HERE. mcpp copies every *.dll under
a dependency's `runtime.library_dirs` beside the executable it builds (mcpp #185,
v0.0.73); `compat.openblas` has shipped `bin/libopenblas.dll` this way on
Windows CI since mcpp-index #55. Two properties this change leans on were
measured locally with mcpp 2026.9.11.2 rather than assumed:

  * transitive -- app -> mid -> dep(bin/vulkan-1.dll): the DLL lands beside
    `app`. `vulkan-hpp-module` and `eui-neo-vulkan` reach compat.vulkan only
    transitively.
  * test binaries -- `mcpp test` places it beside the test executable too.

`mcpp pack` needs nothing further: its PE closure always searches the
executable's own directory ("whatever the build staged beside it ... is by
definition part of what it runs with"), and `vulkan-1.dll` is not in its
system-DLL allow-list, so the deployed copy is what a packed program carries.

THE ARTIFACT (xlings-res/vulkan-import 1.4.357.3, sha256 8118f1bd...12f5)

  lib/vulkan-1.lib    byte-identical to 1.4.357.1's
  vulkan-1.def        upstream `loader/vulkan-1.def`, tag vulkan-sdk-1.4.357.0
  bin/vulkan-1.dll    built from vulkan-sdk-1.4.357.0 by
                      xlings-res/vulkan-loader's windows workflow, which loads
                      the DLL and resolves vkEnumerateInstanceVersion,
                      vkCreateInstance and vkGetInstanceProcAddr before
                      publishing (run 34608619850)
  LICENSE.txt         Vulkan-Loader's Apache-2.0 -- a redistributed binary
                      carries its license
  README.md           how each file was produced

Packed deterministically (sorted, fixed mtime, numeric owner, gzip -n); the
sha was computed twice, read back from GitHub, and the gitcode mirror
(mcpp-res/vulkan-import 1.4.357.3) is byte-identical.

COMPATIBILITY, MEASURED. The DLL exports exactly the 265 names in the .def --
no additions, no omissions -- so every import `vulkan-1.lib` can produce
resolves, and no consumer can hit "entry point not found". The loader version
the earlier xim payload carried (1.4.313) exports the same 265; the build is at
1.4.357 anyway so the loader matches the headers it is consumed with.

On a machine that ALREADY has a GPU driver nothing is lost: the copy beside
the executable is found first (the application directory precedes System32),
and the loader still reads HKLM\SOFTWARE\Khronos\Vulkan\Drivers, so the driver
the machine has is the ICD it uses. The ICD is deliberately not supplied -- a
software fallback would hide a missing driver behind a slow device.

WHY NEW VERSIONS INSTEAD OF MOVING PINS. An installed copy records the pins it
resolved with. Moving a pin inside a published version does not reach a warm
store, which is not hypothetical here: with #391's first approach, a warm CI
store kept `compat.vulkan@1.4.357.0`, never re-evaluated its closure, and the
loader never arrived. That is the same rule as compat.vulkan 1.4.357.1.
Versions before 1.4.357.3 have no bin/; mcpp skips a declared runtime
directory that does not exist, so `library_dirs` is inert for them.

WHY THE TEST ASSERTION IS A REAL CHECK. On Windows the test now requires the
mapped vulkan-1.dll to sit in the executable's directory. With an older
compat.vulkan that fails on a machine with a driver (the loader comes from
System32) and never runs on one without (the process dies first). The
`windows-2022` leg of this PR has no system loader at all, so it can only pass
if the deployment works. This is also why #391 -- which put the DLL in
System32 on the runner -- is superseded rather than merged: it would make that
leg pass whether or not the package works.

Co-authored-by: sunrisepeak <x.d2learn.org@gmail.com>

* fix(eui-neo): find upstream's directory under a re-released version; vulkan-hpp moves to a follow-up

TWO THINGS LOCAL VERIFICATION FOUND in the first push of this branch.

1. compat.eui-neo 0.5.9.1 could not install. The install hook looks for the
   unpacked archive by name, `EUI-NEO-<version>`, and took the version
   verbatim -- so it looked for `EUI-NEO-0.5.9.1/` in an archive that unpacks
   to `EUI-NEO-0.5.9/`:

       eui-neo: no CMakeLists.txt under .../compat-x-eui-neo/0.5.9.1/eui-neo-0.5.9.1
       after unpacking; the archive layout is neither wrapped nor flat

   A fourth version component is this index re-releasing the same upstream tag,
   so the lookup now drops it. Three-component versions are unchanged; checked
   directly: 0.5.9 -> 0.5.9, 0.5.9.1 -> 0.5.9, 0.5.10 -> 0.5.10,
   1.2.3.45 -> 1.2.3, 0.5.9-rc1 -> 0.5.9-rc1. The `layer` directory keeps the
   package's own version; the sources are `*/` globs, so its name never
   mattered.

   After the fix, locally with mcpp 2026.9.11.2:
       compat.eui-neo[vulkan]: ok (backend=vulkan, loader api 1.4.357)
   i.e. eui-neo 0.5.9.1 resolved compat.vulkan 1.4.357.3 through the feature.

   This is the same class of bug as openxlings/xim-pkgindex#821 fixed in
   vulkan-loader: a hook deriving a path from the version works exactly until a
   second version shares an archive.

2. khronos.vulkan-hpp 1.4.357.1 cannot be verified in the same change that
   introduces compat.vulkan 1.4.357.3. `vulkan-hpp-module` redirects only the
   `khronos` namespace to this checkout, so `compat` comes from the PUBLISHED
   index, which does not have 1.4.357.3 until this merges:

       xlings install_packages failed (exit 1) for 'compat.vulkan@1.4.357.3'
       with 1 index repo configured [mcpplibs -> https://github.com/mcpplibs/mcpp-index.git]

   Redirecting `compat` as well was tried and is still refused -- mcpp reports
   "≥2 project-level index repos is a known xlings resolution gap (mcpp #238;
   root cause openxlings/xlings#374)" even though #238 is closed. So the
   khronos.vulkan-hpp bump and its member pin are reverted here and follow
   once this is merged and the index republished -- the same order
   openxlings/xim-pkgindex#818 and mcpp-index#391 needed.

   Consequence for this PR's CI, stated in advance: `vulkan-hpp-module` is
   still selected (its manifest names vulkan) and still resolves
   compat.vulkan 1.4.357.0, so on the windows leg it fails exactly as it does
   on main today. `vulkan` and `eui-neo-vulkan` are the members this change is
   judged by.

Co-authored-by: sunrisepeak <x.d2learn.org@gmail.com>

---------

Co-authored-by: sunrisepeak <x.d2learn.org@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant