Skip to content

Commit 700f7de

Browse files
Sunrisepeakspeak-agentclaude
authored
openkal c-environment: withdraw the _WIN32 adaptations, add posix/platform labels (draft, blocked on two releases) (#439)
* openkal-emscripten 0.2.0, std-freestanding-alloc-kal 0.1.6, and CI builds against mcpp 2026.9.17.3 The two packages resolve openkal 0.13.0 from this index, so their releases follow #437. mcpp 2026.9.17.3 carries #662: a dependency graph that supplies the C library is no longer mixed with the host's own headers. validate.yml and the openkal compatibility measurement both move to it, and the measurement takes openkal-llvm-runtime 0.10.0 (openkal-musl 0.14.0, openkal 0.13). * compat.libarchive: macOS with musl builds without the Apple SDK (#434) libarchive reads __APPLE__ as the Apple SDK being present (TargetConditionals.h, copyfile, quarantine) in four private units and in the generated configuration; in an openkal graph for macOS the SDK is not there. __APPLE__ is removed from libarchive's own units under cfg(all(macos, c-abi = "musl")); archive.h and archive_entry.h do not test it. Measured with mcpp 2026.9.17.3: the archive member cross-builds for aarch64-macos above openkal-macos 0.10.0. Windows with musl is not adapted, and the reason is recorded here rather than worked around: libarchive writes wide string literals, which the Windows target makes sixteen bits while musl's wchar_t is thirty-two, and openkal-musl refuses that mixture on purpose (musl/PATCHES.md). The measurement reports it. * compat.libarchive on Linux with musl, and the tinyhttps member at 0.3.1 The measurement against mcpp 2026.9.17.3 showed the archive member failing on Linux above openkal: the Linux host configuration names linux/fs.h and its neighbours, which belong to the kernel's interface and were reached only because the compiler searched the host before mcpp#662. Under cfg(all(linux, c-abi = "musl")) the generated configuration removes them as it does on every other system; the member runs again. The tinyhttps member names 0.3.1, which selects POSIX sockets on Windows with musl; the measurement had been taken against 0.3.0. * openkal-compat: a measurement requested on another branch proposes nothing * compat.py: a measured copy resolves compat from this checkout A copy of a member is not a member of the workspace and did not inherit its [indices], so compat resolved from the published index and a descriptor changed in a pull request was not the one measured (the archive member measured libarchive's published descriptor). The copy now names this checkout when the member declares no [indices] of its own. * openkal compatibility: the measurement of 2026-09-17 Measured by openkal-compat run 35222831479 with mcpp 2026.9.17.3, openkal-llvm-runtime 0.10.0 and llvm@22.1.8, the host's mingw headers installed. x86_64-linux-gnu: 27 members run, 3 fail (cmp-module and curl name Linux kernel headers or epoll, which openkal does not provide; expat calls arc4random_buf, which musl does not declare). x86_64-windows-gnu, run through Wine: 15 run, 15 fail, each on a Windows or MinGW header its package includes on _WIN32. * compat.zlib, compat.mbedtls: withdraw the _WIN32 workarounds the c-abi declaration replaces Both descriptors carried a target_cfg scoped to cfg(all(windows, c-abi = "musl")) that hand-corrected what the windows-gnu triple implied for the library's own translation units: zlib's -U_WIN32 -include unistd.h, and mbedtls's -U_WIN32 -D__unix__. Neither was wrong when it was written -- openkal-musl had no way yet to say what environment it presents, so the descriptor said it instead, one package at a time. openkal-musl now declares `[c-abi] presents = "posix"` (design: openkal/.agents/docs/2026-09-18-openkal-c-environment-and-personalities- design.md §3.2), and mcpp realises that declaration for the whole target rather than per package. _WIN32 is simply absent and __unix__ is simply present on openkal-Windows to begin with, so these two hand-rolled predecessors of the mechanism are withdrawn rather than reproduced. mbedtls's target_cfg block is removed outright: both of its flags were purely about environment identity, exactly what presents = "posix" now states once for the whole target. zlib's case also needed something presents = "posix" does not itself provide: mcpp_zlib_config.h (which defines Z_HAVE_UNISTD_H, and so pulls in <unistd.h> for the read/write/close/lseek declarations gzlib.c and friends call directly) was previously wired into the linux/macosx blocks only, so windows-musl's target_cfg additionally hand-included <unistd.h>. Since the header's own guard is `#if !defined(_WIN32)`, the same platform test the cflags scoping used to perform by hand, hoisting the -include to a single unconditional cflags entry reaches openkal-Windows exactly as it already reaches Linux and macOS, and does nothing on native (non-openkal) Windows where _WIN32 stays true -- no target_cfg needed to say so. z_off_t now resolves to off_t rather than a forced `long long` wherever the header's guard is open, but both are 8 bytes under the LP64 data model presents = "posix" also declares, and tests/examples/zlib asserts that width dynamically via zlibCompileFlags(), not a fixed type. Checked the rest of pkgs/c/*.lua for the same shape (a target_cfg cflags entry undoing a platform macro for windows+musl): no other instance. compat.libarchive's two target_cfg entries (linux+musl dropping kernel UAPI headers, macos+musl dropping __APPLE__) are a different concern -- kernel/SDK header reachability, not C-environment identity -- and are untouched. Verified: mcpp xpkg parse and the repo's lua lints on both files; `mcpp test` for the zlib and core (mbedtls) members on this host still pass (native Linux effective cflags are unchanged by this refactor, so both came back from the build cache). The windows+musl path itself cannot be built or measured here: it needs the mcpp release and openkal-musl 0.15.0 this same wave's index.toml and pkgs/o/openkal-musl.lua changes mark as pending. * openkal compat: a second, orthogonal kind label -- posix or platform tests/openkal/compat.py already records, per member and target, whether the build ran, built, or failed. This adds a second axis beside it, answering a different question: not whether it worked, but what it needed in order to. posix built and ran using only the C environment the graph's C library presents platform needs the platform's own interfaces Both are derived, never hand-assigned: `kind_of()` reuses the one signal already computed for this purpose, `platform_bound()` (a member declaring a per-target dependencies table -- the same fact the site already showed as "selects platform dependencies of its own"), together with the measured `status`. platform_bound is "declares a platform dependency"; docs/openkal-compat.md rule 1 already describes a feature's `feature-deps` reaching a platform SDK shim as the way a descriptor expresses "this adaptation reaches platform headers", so the one signal covers both halves of the definition rather than needing a second, separate heuristic that would have to guess at a package's internals. `kind` is omitted, not guessed, when status is "fails". A third label, `native` (built in a reduced ISO C form with no POSIX-shaped package anywhere in the graph), is deliberately deferred: that form does not exist yet (design: openkal/.agents/docs/2026-09-18-openkal-c-environment-and-personalities- design.md §7, §12 decision 5). It is not implemented here beyond the one sentence saying so, in each of the three places this documents the mechanism (compat.py's docstring, docs/openkal-compat.md, and the plugin's OPENKAL_KINDS comment) -- no dict entry, no branch, no stub. Wired into the site the same way the existing `openkal` tag and facet are: `.xpkgindex/plugins/mcpp.py` gains OPENKAL_KINDS (paralleling OPENKAL_LEVELS), an `_openkal_kind()` package-level reducer (paralleling `_openkal_level()`), a `pkg.facets["openkal_kind"]` facet value, a matching badge, and an `environment` column in the existing per-target openkal table -- so the derivation is stated in the same place the status is, both in the results file (same target dict) and on the site (same table, same row). Verified: `xpkgindex generate . --output ... --offline --strict` (the same command .github/workflows/site-check.yml runs) builds clean, no warnings, all landing pages present. Confirmed the new facet, badge and table column actually render by patching a throwaway copy of .xpkgindex/openkal-compat.json with synthetic `kind` values and rebuilding -- not committed here, since inventing measurement data is exactly what this mechanism is designed not to do. The checked-in .xpkgindex/openkal-compat.json is unchanged; it was measured by the previous mechanism and will pick up `kind` on the next real tests/openkal/compat.py run. * Prepare, and mark blocked, the descriptors and floor the c-abi wave still needs openkal-musl 0.15.0 and openkal-llvm-runtime 0.11.0 -- the versions that declare and consume `[c-abi] presents = "posix"` -- are not published yet, and neither is the mcpp release that understands the `[c-abi]` table. This adds no version entry and no min_mcpp bump for any of that, because there is no sha256 and no version number to put in one: per index.toml's own rule, min_mcpp and the CI MCPP_VERSION pin move together, only once, to a real mcpp release, and raising the floor early is precisely the "advertising support nobody tested" failure the 2026-08-30 entry in this same file already describes. What this does add is the structure and a marker of exactly what is missing, next to where each value will eventually go: a dated note in index.toml describing the landing order (mcpp releases and enters xim-pkgindex, then the two packages, then min_mcpp/MCPP_VERSION move together in the same PR that adds the two versions), and a comment in each of pkgs/o/openkal-musl.lua and pkgs/o/openkal-llvm-runtime.lua, next to their version tables, naming the pending version and what it changes -- without adding that version's xpm entry, since its url would have no matching sha256 to check it against. This PR cannot merge before openkal-musl 0.15.0 and openkal-llvm-runtime 0.11.0 are published; this commit is the placeholder for the work that follows that, not a substitute for it. * compat.zlib: record which channel the config header rides, and why it is safe Follow-up to 8fc4b63, from review: hoisting -include mcpp_zlib_config.h changes what z_off_t resolves to (off_t instead of a forced long long), and that flag is package-private -- it does not reach a consumer compiling zlib.h. Confirmed against tests/examples/zlib's compile_commands.json: gzlib.c/zutil.c carry -include mcpp_zlib_config.h, tests/zlib.cpp does not. So the library and an openkal-Windows consumer compute z_off_t two different ways (Z_HAVE_UNISTD_H set vs. zconf.h's own unconditional fallback), and the two only agree because every target this index measures is LP64, where off_t and long long are both 8 bytes. tests/openkal/pins.toml and the platforms in this descriptor's own xpm table confirm there is no ILP32 target measured anywhere today. Recorded this in the descriptor rather than leaving it implicit, so the next person who adds an ILP32 target finds the note -- and the existing rule 3/4 machinery in docs/openkal-compat.md this situation already matches (a public-header macro that cannot reach the consumer, asserted at run time via zlibCompileFlags() against sizeof(z_off_t) in tests/examples/zlib) -- rather than the silent mismatch rule 3 warns about. Re-verified: mcpp xpkg parse, lua syntax, and mcpp test for the zlib member all still pass. * openkal_kind: say plainly that the package-level badge is a summary Follow-up to 6382334, from review: the package-level reducer takes `platform` if any measured target shows it, which is correct behaviour (a package genuinely posix on Linux and platform-bound only on Windows does need the platform somewhere) but was not said anywhere a reader of the badge, rather than the code, would see it. Made the per-target table the stated authority: the detail-page caption now adds one sentence, shown only when there is a kind badge for it to qualify, saying the badge above summarises the strictest measured target and the table's own `environment` column is what to read for one target's actual answer. Docs/openkal-compat.md says the same, with the glfw/tinyhttps example from the plugin's own comment. The plugin's OPENKAL_KINDS comment and _openkal_kind's docstring say it too, next to the code that does the reducing. Verified: py_compile; rebuilt a throwaway copy with synthetic per-target kind values (posix on both zlib targets, platform on expat's Windows target only) through the real `xpkgindex generate --offline --strict` and confirmed the new sentence renders correctly on a mixed package's detail page, then discarded the copy -- nothing here touches the checked-in .xpkgindex/openkal-compat.json. * compat.zlib: note the LP64-only agreement is preserved, not introduced Follow-up to 1844867, from review: the withdrawn `-include unistd.h` was package-private in exactly the same way the hoisted `-include mcpp_zlib_config.h` is, so the library and the consumer already computed z_off_t by two different routes before this change, and already agreed only because every measured target is LP64. Added one clause saying so, so the comment does not read as if this PR introduced the asymmetry it documents. Re-verified: mcpp xpkg parse, lua syntax, and mcpp test for the zlib member. * Raise min_mcpp and both CI MCPP_VERSION pins to 2026.9.18.1 The gate is open: mcpp 2026.9.18.1 (the release that understands `[c-abi]`) is published and has entered xim-pkgindex. Per index.toml's own rule, min_mcpp moves together with the CI pin that lints descriptors against it -- validate.yml's MCPP_VERSION, in this commit. This also updates a second, separate pin: tests/openkal/pins.toml's `mcpp` and openkal-compat.yml's own MCPP_VERSION. That pin exists because tests/openkal/compat.py's `prepare()` opens this repository as a live index (`[indices] compat = { path = ... }`) to measure against uncommitted descriptor changes -- so index.toml's min_mcpp gates the openkal measurement exactly as it gates every other client. Left at 2026.9.17.3 after this raise, every member would fail immediately with "index requires mcpp >= 2026.9.18.1 but this is mcpp 2026.9.17.3 [E0006]", before a single line of source is read. Confirmed this failure mode locally before fixing it, rather than reasoning about it. openkal-musl 0.15.0 and openkal-llvm-runtime 0.11.0 -- the two packages that will actually declare and consume `[c-abi] presents = "posix"" -- are still not registered anywhere by this commit: no version, no sha256, nothing invented. tests/openkal/pins.toml's `runtime` field stays at 0.10.0 for the same reason. This raise is deliberately separate from that landing step; the two are independent per the plan's own ordering (mcpp release/xim-pkgindex entry is step 1-2, the two package releases are step 3, registering them here is step 4). Verified, not merely asserted, that this raise changes nothing observable today: - every descriptor in pkgs/*/*.lua still parses under mcpp 2026.9.18.1 (`mcpp xpkg parse`, all 231, plus the repo's lua lints) - a full run of tests/openkal/compat.py against every listed member on x86_64-linux-gnu, under 2026.9.18.1, reproduces the checked-in baseline exactly: 27 runs / 3 fails, the same three members (expat, curl, cmp-module), the same diagnostics character-for-character past the local path prefix Windows was not re-run here: without openkal-musl 0.15.0/ openkal-llvm-runtime 0.11.0, no package declares `[c-abi]` yet, so a Windows re-run now would only reproduce the existing 15/15 baseline -- no new information, and the expensive (Wine) leg. That baseline's two members failing inside clang's own headers -- eigen at mm_malloc.h:43:22 (`__mingw_aligned_malloc` undeclared) and fmtlib.fmt at intrin.h:12:15 (`'intrin.h' file not found`, clang's own `#include_next <intrin.h>`) -- are on record here as exactly what `builtins = "iso"` needs to turn, once openkal-musl 0.15.0 exists to declare it and the real re-measurement runs. * Raise min_mcpp and both CI MCPP_VERSION pins to 2026.9.18.2 2026.9.18.2 is the release whose refusals match [c-abi]: an empty realisation is accepted under GCC, and presents = "posix" is realised on macOS and on freestanding targets instead of refused. The two packages that declare the block pin this release in their own CI; the floor must not leave them refused at 2026.9.18.1. * Raise min_mcpp and both CI MCPP_VERSION pins to 2026.9.18.3 * README: pin the engine floor at mcpp 2026.9.18.3 `openkal-musl 0.15.0` and any future `[c-abi]` package require the engine that ships with `mcpp 2026.9.18.3` or later. The host-macro strip on Windows hosts and the freestanding wchar realisation are what let the c-abi probe verify a declaration without host contamination. The `min_mcpp` floor on `[indices]`, `MCPP_VERSION`, and the per-package pins under `tests/openkal/pins.toml` all gate this together (raising only the index floor would still let 30 members E0006 before reading any source line). State the floor here so a reader landing on the README from a search knows the upgrade is required and not a suggestion, and why raising the floor is one of three coordinated moves rather than a single `min_mcpp` bump. Co-Authored-By: Claude Code <noreply@anthropic.com> --------- Co-authored-by: sunrisepeak <x.d2learn.org@gmail.com> Co-authored-by: Claude Code <noreply@anthropic.com>
1 parent 41ad30a commit 700f7de

12 files changed

Lines changed: 350 additions & 54 deletions

File tree

‎.github/workflows/openkal-compat.yml‎

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,12 @@ permissions:
2828
contents: read
2929

3030
env:
31-
MCPP_VERSION: "2026.9.17.3"
31+
# Moves together with index.toml's `min_mcpp` and tests/openkal/pins.toml's
32+
# `mcpp` -- the "The pins agree with this workflow" step below fails the
33+
# run if this drifts from pins.toml. See the comment beside `mcpp` in
34+
# pins.toml for why this pin, not just validate.yml's, is gated by the
35+
# index floor.
36+
MCPP_VERSION: "2026.9.18.3"
3237
XLINGS_NON_INTERACTIVE: "1"
3338

3439
jobs:

‎.github/workflows/validate.yml‎

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -282,7 +282,26 @@ env:
282282
# tests/openkal measures it with the host's mingw headers installed.
283283
#
284284
# `index.toml` min_mcpp does not move: no descriptor grammar changed.
285-
MCPP_VERSION: "2026.9.17.3"
285+
# ── 2026-09-18: raised 2026.9.17.3 -> 2026.9.18.1, WITH index.toml's floor ─
286+
#
287+
# This is the mcpp release that understands `[c-abi]` (design:
288+
# openkal/.agents/docs/2026-09-18-openkal-c-environment-and-personalities-
289+
# design.md §3.2; landing order: the sibling
290+
# 2026-09-18-c-environment-execution-plan.md §5, step 1). It is the reason
291+
# `index.toml`'s min_mcpp moves in the SAME commit as this line, unlike the
292+
# two raises above it: this one is a grammar the index is about to gain a
293+
# user of. openkal-musl 0.15.0 and openkal-llvm-runtime 0.11.0, the two
294+
# packages that will declare and consume `[c-abi] presents = "posix"`, are
295+
# not registered yet (no version, no sha256 exist) — see the versions in
296+
# pkgs/o/openkal-musl.lua and pkgs/o/openkal-llvm-runtime.lua and the note
297+
# beside them — so this raise alone changes nothing observable: no
298+
# descriptor in this index writes `[c-abi]` today, and mcpp's own release
299+
# notes state that a package which does not declare the block gets the same
300+
# command line, byte for byte, as before. The first build after this bump
301+
# is a cold one (mcpp's build-cache epoch moved from 2 to 3 in this same
302+
# release, because the old cache key did not cover the realised [c-abi]
303+
# environment).
304+
MCPP_VERSION: "2026.9.18.3"
286305

287306
jobs:
288307
lint:

‎.xpkgindex/plugins/mcpp.py‎

Lines changed: 82 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,37 @@ def _t(en: str, zh: str, hant: str) -> Dict[str, str]:
5858
("n/a", _t("not applicable", "不适用", "不適用"), "neutral"),
5959
]
6060
_OPENKAL_RANK = {"fails": 0, "builds": 1, "runs": 2}
61+
62+
# How a package's best-measured target relates to the platform, orthogonal to
63+
# OPENKAL_LEVELS above: whether the graph worked is one axis, what it needed
64+
# to work is another. Measured by the same tool and recorded beside `status`
65+
# in the same file -- see the `posix`/`platform` table in
66+
# tests/openkal/compat.py's module docstring, which is the derivation this
67+
# reads. `native` (the reduced ISO C form, no POSIX package in the graph) is
68+
# deliberately deferred there and has no entry here to match: a form that
69+
# cannot be measured gets no facet value to claim it.
70+
OPENKAL_KINDS = [
71+
("posix", _t("posix on openkal", "posix 环境", "posix 環境"), "module"),
72+
("platform", _t("uses platform interfaces", "使用平台接口", "使用平台介面"), "header"),
73+
]
74+
# Not ordered strongest-to-weakest like _OPENKAL_RANK: `platform` is not a
75+
# worse outcome than `posix`, it is a different fact about the same package,
76+
# and a package can be genuinely one on one target and the other on another
77+
# (glfw needs a window-system SDK everywhere; tinyhttps needs one only where
78+
# it falls back from epoll to Winsock). The package-level facet below still
79+
# has to pick one value, so it takes `platform` if the package is that on ANY
80+
# measured target -- the fact that it needs the platform somewhere does not
81+
# stop being true because another target does not need it.
82+
#
83+
# This makes the package-level value a SUMMARY, specifically the strictest
84+
# target's answer, not a per-target fact -- a package that is `posix` on
85+
# Linux and `platform` only on Windows is filed under `platform` here, the
86+
# same way it would be if every target needed the platform. A reader who
87+
# wants to know about one target, rather than the worst case across all of
88+
# them, wants `_openkal_blocks`'s per-target table (the `environment`
89+
# column), not this facet or the badge it drives -- both say so.
90+
_OPENKAL_KIND_PRIORITY = ("platform", "posix")
91+
6192
# The packages that make up openkal: the specification, its implementations, and
6293
# the layers built directly on it. Named once, here.
6394
OPENKAL_FAMILY = {
@@ -402,6 +433,25 @@ def _openkal_level(self, slug: str) -> str:
402433
best = max(_OPENKAL_RANK.get(r.get("status"), 0) for r in rec["targets"].values())
403434
return {2: "runs", 1: "builds", 0: "fails"}[best]
404435

436+
def _openkal_kind(self, slug: str) -> str:
437+
"""The package-level `kind` facet value -- a SUMMARY that takes the
438+
strictest measured target, not a claim about every target: `platform`
439+
if any measured target recorded it, else `posix` if any did, else
440+
empty (openkal's own packages, and any package with no `kind` on any
441+
target, carry none). See OPENKAL_KINDS above for why `platform` wins
442+
ties, and `_openkal_blocks`'s per-target table for the authoritative,
443+
target-by-target picture this reduces."""
444+
if slug in OPENKAL_FAMILY:
445+
return ""
446+
rec = self.openkal_by_package.get(slug)
447+
if not rec:
448+
return ""
449+
present = {r.get("kind") for r in rec["targets"].values() if r.get("kind")}
450+
for kind in _OPENKAL_KIND_PRIORITY:
451+
if kind in present:
452+
return kind
453+
return ""
454+
405455
# --------------------------------------------------------- identity --
406456
def identity(self, raw: Dict[str, Any], path: str) -> Optional[Identity]:
407457
"""mcpp resolves `namespace.name`, so the namespace IS the identity.
@@ -471,6 +521,16 @@ def on_package(self, pkg, raw: Dict[str, Any]) -> None:
471521
label = {k: lbl for k, lbl, _ in OPENKAL_LEVELS}[level]
472522
pkg.extensions.setdefault("_badges", []).append(label)
473523

524+
# Wired the same way as `level` just above: a measurement, not a
525+
# declaration, turned into a facet and a badge on the package it
526+
# was measured on -- see OPENKAL_KINDS.
527+
kind = self._openkal_kind(pkg.identity.slug)
528+
if kind:
529+
pkg.facets["openkal_kind"] = kind
530+
ext["openkal"]["kind"] = kind
531+
label = {k: lbl for k, lbl, _ in OPENKAL_KINDS}[kind]
532+
pkg.extensions.setdefault("_badges", []).append(label)
533+
474534
pkg.extensions["mcpp"] = ext
475535
# After the examples are attached: the surfaces depend on which
476536
# interface lines the examples can actually produce.
@@ -644,6 +704,10 @@ def facets(self) -> List[Facet]:
644704
Facet(key="openkal", label=_t("openkal", "openkal", "openkal"), weight=20, values=[
645705
FacetValue(key=key, label=label, tone=tone) for key, label, tone in OPENKAL_LEVELS
646706
]),
707+
Facet(key="openkal_kind", label=_t("openkal environment", "openkal 环境",
708+
"openkal 環境"), weight=21, values=[
709+
FacetValue(key=key, label=label, tone=tone) for key, label, tone in OPENKAL_KINDS
710+
]),
647711
]
648712

649713
# -------------------------------------------------------------- row --
@@ -818,29 +882,42 @@ def _openkal_blocks(self, pkg, ext: Dict[str, Any]) -> List[Block]:
818882
return []
819883
rows = []
820884
for target, rec in sorted((info.get("targets") or {}).items()):
821-
rows.append([target, rec.get("status", ""), rec.get("member", ""),
822-
rec.get("diagnostic", "")])
885+
rows.append([target, rec.get("status", ""), rec.get("kind", ""),
886+
rec.get("member", ""), rec.get("diagnostic", "")])
823887
pins = self.openkal.get("pins") or {}
888+
# Shown only when there is a package-level `kind` badge for it to
889+
# qualify: that badge is the strictest measured target's answer, not
890+
# every target's, and the table above it is the one that is.
891+
kind_note = (" The badge above is a summary of the strictest "
892+
"measured target -- the table above states each "
893+
"target's own environment.",
894+
" 上方徽章是所有已测目标里最严格那个的结果 —— 上表列出每个目标各自的环境。",
895+
" 上方徽章是所有已測目標裡最嚴格那個的結果 —— 上表列出每個目標各自的環境。") \
896+
if info.get("kind") else ("", "", "")
824897
caption = _t(
825898
f"Measured {self.openkal.get('measured', '')} by tests/openkal/compat.py with "
826899
f"openkal-llvm-runtime {pins.get('runtime', '')}, {pins.get('toolchain', '')}, "
827900
f"mcpp {pins.get('mcpp', '')}. "
828901
+ ("The test project selects no platform dependency of its own."
829902
if info.get("portable", True) else
830-
"The test project selects platform dependencies of its own."),
903+
"The test project selects platform dependencies of its own.")
904+
+ kind_note[0],
831905
f"{self.openkal.get('measured', '')} 由 tests/openkal/compat.py 测得,使用 "
832906
f"openkal-llvm-runtime {pins.get('runtime', '')}、{pins.get('toolchain', '')}、"
833907
f"mcpp {pins.get('mcpp', '')}。"
834908
+ ("测试项目没有自行选择平台依赖。" if info.get("portable", True)
835-
else "测试项目自行选择了平台依赖。"),
909+
else "测试项目自行选择了平台依赖。")
910+
+ kind_note[1],
836911
f"{self.openkal.get('measured', '')} 由 tests/openkal/compat.py 測得,使用 "
837912
f"openkal-llvm-runtime {pins.get('runtime', '')}、{pins.get('toolchain', '')}、"
838913
f"mcpp {pins.get('mcpp', '')}。"
839914
+ ("測試專案沒有自行選擇平台相依。" if info.get("portable", True)
840-
else "測試專案自行選擇了平台相依。"))
915+
else "測試專案自行選擇了平台相依。")
916+
+ kind_note[2])
841917
return [
842918
Block(kind="table", title=_t("openkal", "openkal", "openkal"), weight=25,
843919
data={"head": [_t("target", "目标", "目標"), _t("result", "结果", "結果"),
920+
_t("environment", "环境", "環境"),
844921
_t("test project", "测试项目", "測試專案"),
845922
_t("first diagnostic", "首条诊断", "首條診斷")],
846923
"rows": rows}),

‎README.md‎

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,18 @@ This repository hosts the C++23 packages that `mcpp` can `add` directly — both
99
`import`, and third-party C/C++ libraries built from upstream sources or headers in `compat` form. Every package maps
1010
to one `pkgs/<initial>/<name>.lua` descriptor file.
1111

12+
> **Engine floor (mcpp 2026.9.18.3):** `openkal-musl 0.15.0` and any future
13+
> `[c-abi]` package require the engine that ships with `mcpp 2026.9.18.3`
14+
> or later — the host-macro strip on Windows hosts and the freestanding
15+
> wchar realisation are what let the c-abi probe verify a declaration
16+
> without host contamination. The `min_mcpp` floor on `[indices]`,
17+
> `MCPP_VERSION`, and the per-package pins under `tests/openkal/pins.toml`
18+
> all gate this together (raising only the index floor would still let
19+
> 30 members E0006 before reading any source line). Older engines
20+
> silently misbuild `[c-abi]` packages: the build succeeds, the probe
21+
> fails, the program compiles against the wrong environment. Upgrade:
22+
> `xlings install mcpp --force`.
23+
1224
## Usage
1325

1426
```bash

‎docs/openkal-compat.md‎

Lines changed: 38 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -36,16 +36,47 @@ recorded per target:
3636
| `builds` | the member built, and its tests were not run or did not pass; the first diagnostic is kept |
3737
| `fails` | the member did not build; the first diagnostic is kept |
3838

39+
Beside `status`, and derived from the same measurement, `compat.py` records a
40+
second, orthogonal `kind`: not whether the member worked, but what it needed
41+
in order to:
42+
43+
| Kind | Meaning | Derived from |
44+
| --- | --- | --- |
45+
| `posix` | built and ran using only the C environment the graph's C library presents | `status == "runs"` and the member declares no platform dependency of its own |
46+
| `platform` | needs the platform's own interfaces | the member declares a platform dependency of its own (a per-target `dependencies` table — see rule 1 below), and `status` is `runs` or `builds` |
47+
48+
`kind` is omitted for `status == "fails"`: an unmeasured member states nothing
49+
about its relation to the platform. A third kind, `native` — built in a reduced
50+
ISO C form with no POSIX-shaped package anywhere in the graph — is deliberately
51+
deferred, because that form does not exist yet; it is not computed or shown
52+
anywhere in this pipeline.
53+
54+
Selecting a platform dependency is permitted: a package on openkal may use a
55+
platform's system interfaces, provided they come from the dependency graph.
56+
The distinction is shown and does not lower the `status` label — it only
57+
decides `kind`. See `tests/openkal/compat.py`'s module docstring for the exact
58+
derivation, stated next to the code that computes it.
59+
3960
The results are written to `.xpkgindex/openkal-compat.json` together with the
4061
pins and the date. The site gives every package a test project covers the best
4162
result any covering project recorded for each target, and files the package
42-
under the `openkal` facet by its best target. The packages of openkal itself are
43-
filed as `openkal itself`.
44-
45-
A member is also recorded as selecting platform dependencies of its own or not.
46-
Selecting them is permitted: a package on openkal may use a platform's system
47-
interfaces, provided they come from the dependency graph. The distinction is
48-
shown and does not lower the label.
63+
under the `openkal` facet by its best target and under the `openkal_kind`
64+
facet by `platform` if any measured target recorded it, else `posix` if any
65+
did. The packages of openkal itself are filed as `openkal itself` and carry
66+
neither `kind` nor `openkal_kind`: they answer what openkal is, not what a
67+
package built on it needs.
68+
69+
The `openkal_kind` facet and the badge it drives are a package-level
70+
**summary**: they take the strictest target, the way `platform` above is
71+
chosen over `posix` whenever both were measured. A package can genuinely be
72+
`posix` on one target and `platform` on another — glfw needs a
73+
window-system SDK everywhere it is measured, tinyhttps needs one only where
74+
it falls back from epoll to Winsock — and the summary does not distinguish
75+
those two shapes; it says `platform` either way, because that is true of at
76+
least one target. The package's detail page's per-target `openkal` table (the
77+
`environment` column, beside `result`) is the authority for what one
78+
particular target actually needed; read that, not the badge, when the
79+
question is about a target rather than the package as a whole.
4980

5081
`tests/openkal/members.toml` lists what is measured. `[excluded]` lists members
5182
that cannot be built in any openkal graph, each with its reason; a member that

‎index.toml‎

Lines changed: 43 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,48 @@
3838
# refusal at the index-open choke point instead of an undefined reference or a
3939
# missing payload three layers down. 2026.8.27.2 is the version this index is
4040
# actually tested against, and now the contract says so.
41+
#
42+
# ── 2026-09-18: raised 2026.8.27.2 -> 2026.9.18.1, with the CI pin ─────────
43+
#
44+
# 2026.9.18.1 is the mcpp release that understands `[c-abi]` (design:
45+
# openkal/.agents/docs/2026-09-18-openkal-c-environment-and-personalities-
46+
# design.md §3.2; plan: the sibling 2026-09-18-c-environment-execution-plan.md
47+
# §5, step 1) and has entered xim-pkgindex (step 2). Per the rule at the top
48+
# of this file, this moves together with `.github/workflows/validate.yml`'s
49+
# `MCPP_VERSION`, in this same commit.
50+
#
51+
# This raise on its own changes nothing observable: no descriptor in this
52+
# index declares `[c-abi]` yet, and mcpp's own release notes state that a
53+
# package which does not declare the block gets the same command line, byte
54+
# for byte, as before. Verified here, not merely asserted: every descriptor
55+
# in pkgs/*/*.lua still parses with `mcpp xpkg parse` under 2026.9.18.1.
56+
#
57+
# ── 2026-09-18: raised 2026.9.18.2 -> 2026.9.18.3, with both CI pins ────────
58+
#
59+
# 2026.9.18.3 is the release whose c-abi probe on a Windows host × freestanding
60+
# target stops mismatching on _WIN32 (host strip) and __SIZEOF_WCHAR_T__
61+
# (realisation always emits -fno-short-wchar on freestanding). The probe's
62+
# measurement contract is unchanged (design §3.2: a declaration is checked,
63+
# never trusted); the realisation's previous "freestanding skips the wchar
64+
# flag" rule was the actual bug, the wave's measurement is what caught it.
65+
# A floor at 2026.9.18.2 would let a 2026.9.18.2 user be refused builds the
66+
# next release accepts. Per the rule at the top of this file, this moves in
67+
# the same commit as validate.yml's `MCPP_VERSION`; openkal-compat.yml's
68+
# `MCPP_VERSION` moves with tests/openkal/pins.toml's `mcpp`, which that
69+
# workflow checks for agreement.
70+
#
71+
# openkal-musl 0.15.0 and openkal-llvm-runtime 0.11.0 (plan step 3) -- the two
72+
# packages that will actually declare and consume `[c-abi] presents =
73+
# "posix"` -- are NOT registered by this raise. Neither has a version number
74+
# or a sha256 yet; `pkgs/o/openkal-musl.lua` and
75+
# `pkgs/o/openkal-llvm-runtime.lua` carry a note beside their version tables
76+
# marking exactly that, and this index has no data to put in an xpm entry for
77+
# either until the other agent handling their release reports the tag and
78+
# hash. Registering them is plan step 4, a separate change from this one:
79+
# raising the floor was gated on the engine, not on those two packages, and
80+
# gating on both at once would have held this raise hostage to something it
81+
# does not need.
4182
[index]
4283
spec = "1"
43-
min_mcpp = "2026.8.27.2"
44-
latest_mcpp = "2026.8.27.2"
84+
min_mcpp = "2026.9.18.3"
85+
latest_mcpp = "2026.9.18.3"

‎pkgs/c/compat.mbedtls.lua‎

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -56,21 +56,22 @@ package = {
5656
c_standard = "c11",
5757
targets = { ["mbedtls"] = { kind = "lib" } },
5858
deps = { },
59+
-- Windows with musl as the C library (an openkal graph) used to carry a
60+
-- `target_cfg` here (`-U_WIN32 -D__unix__`): mbedtls selects its
61+
-- entropy, timing and socket code by asking whether the environment is
62+
-- Windows (_WIN32) or Unix (__unix__), the triple answered Windows, and
63+
-- the C library these units actually compile against is POSIX-shaped
64+
-- (openkal-musl: getrandom, clock_gettime, BSD sockets), so the flags
65+
-- corrected what the triple implied for mbedtls's own translation
66+
-- units. openkal-musl now declares `[c-abi] presents = "posix"`
67+
-- (design:
68+
-- openkal/.agents/docs/2026-09-18-openkal-c-environment-and-personalities-design.md
69+
-- §3.2), and mcpp realises that declaration for the whole target
70+
-- rather than one package at a time, so _WIN32 is simply absent and
71+
-- __unix__ is simply present there to begin with; the `target_cfg` is
72+
-- withdrawn rather than reproduced.
5973
windows = {
6074
ldflags = { "-lbcrypt" },
6175
},
62-
target_cfg = {
63-
-- Windows with musl as the C library. mbedtls selects its entropy,
64-
-- timing and socket code by asking whether the environment is
65-
-- Windows (_WIN32) or Unix (__unix__); the triple answers Windows,
66-
-- and the C library these units compile against is POSIX-shaped
67-
-- (openkal-musl: getrandom, clock_gettime, BSD sockets). Both
68-
-- flags are confined to mbedtls's own translation units, and no
69-
-- public header of mbedtls tests either macro, so its consumers
70-
-- read the same declarations.
71-
["cfg(all(windows, c-abi = \"musl\"))"] = {
72-
cflags = { "-U_WIN32", "-D__unix__" },
73-
},
74-
},
7576
},
7677
}

0 commit comments

Comments
 (0)