diff --git a/.github/workflows/openkal-compat.yml b/.github/workflows/openkal-compat.yml index 7b51a71e..aedc6d1c 100644 --- a/.github/workflows/openkal-compat.yml +++ b/.github/workflows/openkal-compat.yml @@ -28,7 +28,12 @@ permissions: contents: read env: - MCPP_VERSION: "2026.9.17.3" + # Moves together with index.toml's `min_mcpp` and tests/openkal/pins.toml's + # `mcpp` -- the "The pins agree with this workflow" step below fails the + # run if this drifts from pins.toml. See the comment beside `mcpp` in + # pins.toml for why this pin, not just validate.yml's, is gated by the + # index floor. + MCPP_VERSION: "2026.9.18.3" XLINGS_NON_INTERACTIVE: "1" jobs: diff --git a/.github/workflows/validate.yml b/.github/workflows/validate.yml index a873683b..d4a332f3 100644 --- a/.github/workflows/validate.yml +++ b/.github/workflows/validate.yml @@ -282,7 +282,26 @@ env: # tests/openkal measures it with the host's mingw headers installed. # # `index.toml` min_mcpp does not move: no descriptor grammar changed. - MCPP_VERSION: "2026.9.17.3" + # ── 2026-09-18: raised 2026.9.17.3 -> 2026.9.18.1, WITH index.toml's floor ─ + # + # This is the mcpp release that understands `[c-abi]` (design: + # openkal/.agents/docs/2026-09-18-openkal-c-environment-and-personalities- + # design.md §3.2; landing order: the sibling + # 2026-09-18-c-environment-execution-plan.md §5, step 1). It is the reason + # `index.toml`'s min_mcpp moves in the SAME commit as this line, unlike the + # two raises above it: this one is a grammar the index is about to gain a + # user of. openkal-musl 0.15.0 and openkal-llvm-runtime 0.11.0, the two + # packages that will declare and consume `[c-abi] presents = "posix"`, are + # not registered yet (no version, no sha256 exist) — see the versions in + # pkgs/o/openkal-musl.lua and pkgs/o/openkal-llvm-runtime.lua and the note + # beside them — so this raise alone changes nothing observable: no + # descriptor in this index writes `[c-abi]` today, and mcpp's own release + # notes state that a package which does not declare the block gets the same + # command line, byte for byte, as before. The first build after this bump + # is a cold one (mcpp's build-cache epoch moved from 2 to 3 in this same + # release, because the old cache key did not cover the realised [c-abi] + # environment). + MCPP_VERSION: "2026.9.18.3" jobs: lint: diff --git a/.xpkgindex/plugins/mcpp.py b/.xpkgindex/plugins/mcpp.py index fb227d6f..69a90c54 100644 --- a/.xpkgindex/plugins/mcpp.py +++ b/.xpkgindex/plugins/mcpp.py @@ -58,6 +58,37 @@ def _t(en: str, zh: str, hant: str) -> Dict[str, str]: ("n/a", _t("not applicable", "不适用", "不適用"), "neutral"), ] _OPENKAL_RANK = {"fails": 0, "builds": 1, "runs": 2} + +# How a package's best-measured target relates to the platform, orthogonal to +# OPENKAL_LEVELS above: whether the graph worked is one axis, what it needed +# to work is another. Measured by the same tool and recorded beside `status` +# in the same file -- see the `posix`/`platform` table in +# tests/openkal/compat.py's module docstring, which is the derivation this +# reads. `native` (the reduced ISO C form, no POSIX package in the graph) is +# deliberately deferred there and has no entry here to match: a form that +# cannot be measured gets no facet value to claim it. +OPENKAL_KINDS = [ + ("posix", _t("posix on openkal", "posix 环境", "posix 環境"), "module"), + ("platform", _t("uses platform interfaces", "使用平台接口", "使用平台介面"), "header"), +] +# Not ordered strongest-to-weakest like _OPENKAL_RANK: `platform` is not a +# worse outcome than `posix`, it is a different fact about the same package, +# and a package can be genuinely one on one target and the other on another +# (glfw needs a window-system SDK everywhere; tinyhttps needs one only where +# it falls back from epoll to Winsock). The package-level facet below still +# has to pick one value, so it takes `platform` if the package is that on ANY +# measured target -- the fact that it needs the platform somewhere does not +# stop being true because another target does not need it. +# +# This makes the package-level value a SUMMARY, specifically the strictest +# target's answer, not a per-target fact -- a package that is `posix` on +# Linux and `platform` only on Windows is filed under `platform` here, the +# same way it would be if every target needed the platform. A reader who +# wants to know about one target, rather than the worst case across all of +# them, wants `_openkal_blocks`'s per-target table (the `environment` +# column), not this facet or the badge it drives -- both say so. +_OPENKAL_KIND_PRIORITY = ("platform", "posix") + # The packages that make up openkal: the specification, its implementations, and # the layers built directly on it. Named once, here. OPENKAL_FAMILY = { @@ -402,6 +433,25 @@ def _openkal_level(self, slug: str) -> str: best = max(_OPENKAL_RANK.get(r.get("status"), 0) for r in rec["targets"].values()) return {2: "runs", 1: "builds", 0: "fails"}[best] + def _openkal_kind(self, slug: str) -> str: + """The package-level `kind` facet value -- a SUMMARY that takes the + strictest measured target, not a claim about every target: `platform` + if any measured target recorded it, else `posix` if any did, else + empty (openkal's own packages, and any package with no `kind` on any + target, carry none). See OPENKAL_KINDS above for why `platform` wins + ties, and `_openkal_blocks`'s per-target table for the authoritative, + target-by-target picture this reduces.""" + if slug in OPENKAL_FAMILY: + return "" + rec = self.openkal_by_package.get(slug) + if not rec: + return "" + present = {r.get("kind") for r in rec["targets"].values() if r.get("kind")} + for kind in _OPENKAL_KIND_PRIORITY: + if kind in present: + return kind + return "" + # --------------------------------------------------------- identity -- def identity(self, raw: Dict[str, Any], path: str) -> Optional[Identity]: """mcpp resolves `namespace.name`, so the namespace IS the identity. @@ -471,6 +521,16 @@ def on_package(self, pkg, raw: Dict[str, Any]) -> None: label = {k: lbl for k, lbl, _ in OPENKAL_LEVELS}[level] pkg.extensions.setdefault("_badges", []).append(label) + # Wired the same way as `level` just above: a measurement, not a + # declaration, turned into a facet and a badge on the package it + # was measured on -- see OPENKAL_KINDS. + kind = self._openkal_kind(pkg.identity.slug) + if kind: + pkg.facets["openkal_kind"] = kind + ext["openkal"]["kind"] = kind + label = {k: lbl for k, lbl, _ in OPENKAL_KINDS}[kind] + pkg.extensions.setdefault("_badges", []).append(label) + pkg.extensions["mcpp"] = ext # After the examples are attached: the surfaces depend on which # interface lines the examples can actually produce. @@ -644,6 +704,10 @@ def facets(self) -> List[Facet]: Facet(key="openkal", label=_t("openkal", "openkal", "openkal"), weight=20, values=[ FacetValue(key=key, label=label, tone=tone) for key, label, tone in OPENKAL_LEVELS ]), + Facet(key="openkal_kind", label=_t("openkal environment", "openkal 环境", + "openkal 環境"), weight=21, values=[ + FacetValue(key=key, label=label, tone=tone) for key, label, tone in OPENKAL_KINDS + ]), ] # -------------------------------------------------------------- row -- @@ -818,29 +882,42 @@ def _openkal_blocks(self, pkg, ext: Dict[str, Any]) -> List[Block]: return [] rows = [] for target, rec in sorted((info.get("targets") or {}).items()): - rows.append([target, rec.get("status", ""), rec.get("member", ""), - rec.get("diagnostic", "")]) + rows.append([target, rec.get("status", ""), rec.get("kind", ""), + rec.get("member", ""), rec.get("diagnostic", "")]) pins = self.openkal.get("pins") or {} + # Shown only when there is a package-level `kind` badge for it to + # qualify: that badge is the strictest measured target's answer, not + # every target's, and the table above it is the one that is. + kind_note = (" The badge above is a summary of the strictest " + "measured target -- the table above states each " + "target's own environment.", + " 上方徽章是所有已测目标里最严格那个的结果 —— 上表列出每个目标各自的环境。", + " 上方徽章是所有已測目標裡最嚴格那個的結果 —— 上表列出每個目標各自的環境。") \ + if info.get("kind") else ("", "", "") caption = _t( f"Measured {self.openkal.get('measured', '')} by tests/openkal/compat.py with " f"openkal-llvm-runtime {pins.get('runtime', '')}, {pins.get('toolchain', '')}, " f"mcpp {pins.get('mcpp', '')}. " + ("The test project selects no platform dependency of its own." if info.get("portable", True) else - "The test project selects platform dependencies of its own."), + "The test project selects platform dependencies of its own.") + + kind_note[0], f"{self.openkal.get('measured', '')} 由 tests/openkal/compat.py 测得,使用 " f"openkal-llvm-runtime {pins.get('runtime', '')}、{pins.get('toolchain', '')}、" f"mcpp {pins.get('mcpp', '')}。" + ("测试项目没有自行选择平台依赖。" if info.get("portable", True) - else "测试项目自行选择了平台依赖。"), + else "测试项目自行选择了平台依赖。") + + kind_note[1], f"{self.openkal.get('measured', '')} 由 tests/openkal/compat.py 測得,使用 " f"openkal-llvm-runtime {pins.get('runtime', '')}、{pins.get('toolchain', '')}、" f"mcpp {pins.get('mcpp', '')}。" + ("測試專案沒有自行選擇平台相依。" if info.get("portable", True) - else "測試專案自行選擇了平台相依。")) + else "測試專案自行選擇了平台相依。") + + kind_note[2]) return [ Block(kind="table", title=_t("openkal", "openkal", "openkal"), weight=25, data={"head": [_t("target", "目标", "目標"), _t("result", "结果", "結果"), + _t("environment", "环境", "環境"), _t("test project", "测试项目", "測試專案"), _t("first diagnostic", "首条诊断", "首條診斷")], "rows": rows}), diff --git a/README.md b/README.md index 48d53b27..5d27fed7 100644 --- a/README.md +++ b/README.md @@ -9,6 +9,18 @@ This repository hosts the C++23 packages that `mcpp` can `add` directly — both `import`, and third-party C/C++ libraries built from upstream sources or headers in `compat` form. Every package maps to one `pkgs//.lua` descriptor file. +> **Engine floor (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). Older engines +> silently misbuild `[c-abi]` packages: the build succeeds, the probe +> fails, the program compiles against the wrong environment. Upgrade: +> `xlings install mcpp --force`. + ## Usage ```bash diff --git a/docs/openkal-compat.md b/docs/openkal-compat.md index 54dcd4d3..9abca406 100644 --- a/docs/openkal-compat.md +++ b/docs/openkal-compat.md @@ -36,16 +36,47 @@ recorded per target: | `builds` | the member built, and its tests were not run or did not pass; the first diagnostic is kept | | `fails` | the member did not build; the first diagnostic is kept | +Beside `status`, and derived from the same measurement, `compat.py` records a +second, orthogonal `kind`: not whether the member worked, but what it needed +in order to: + +| Kind | Meaning | Derived from | +| --- | --- | --- | +| `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 | +| `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` | + +`kind` is omitted for `status == "fails"`: an unmeasured member states nothing +about its relation to the platform. A third kind, `native` — built in a reduced +ISO C form with no POSIX-shaped package anywhere in the graph — is deliberately +deferred, because that form does not exist yet; it is not computed or shown +anywhere in this pipeline. + +Selecting a platform dependency is permitted: a package on openkal may use a +platform's system interfaces, provided they come from the dependency graph. +The distinction is shown and does not lower the `status` label — it only +decides `kind`. See `tests/openkal/compat.py`'s module docstring for the exact +derivation, stated next to the code that computes it. + The results are written to `.xpkgindex/openkal-compat.json` together with the pins and the date. The site gives every package a test project covers the best result any covering project recorded for each target, and files the package -under the `openkal` facet by its best target. The packages of openkal itself are -filed as `openkal itself`. - -A member is also recorded as selecting platform dependencies of its own or not. -Selecting them is permitted: a package on openkal may use a platform's system -interfaces, provided they come from the dependency graph. The distinction is -shown and does not lower the label. +under the `openkal` facet by its best target and under the `openkal_kind` +facet by `platform` if any measured target recorded it, else `posix` if any +did. The packages of openkal itself are filed as `openkal itself` and carry +neither `kind` nor `openkal_kind`: they answer what openkal is, not what a +package built on it needs. + +The `openkal_kind` facet and the badge it drives are a package-level +**summary**: they take the strictest target, the way `platform` above is +chosen over `posix` whenever both were measured. A package can genuinely be +`posix` on one target and `platform` on another — glfw needs a +window-system SDK everywhere it is measured, tinyhttps needs one only where +it falls back from epoll to Winsock — and the summary does not distinguish +those two shapes; it says `platform` either way, because that is true of at +least one target. The package's detail page's per-target `openkal` table (the +`environment` column, beside `result`) is the authority for what one +particular target actually needed; read that, not the badge, when the +question is about a target rather than the package as a whole. `tests/openkal/members.toml` lists what is measured. `[excluded]` lists members that cannot be built in any openkal graph, each with its reason; a member that diff --git a/index.toml b/index.toml index 2a1fc559..6182e10a 100644 --- a/index.toml +++ b/index.toml @@ -38,7 +38,48 @@ # refusal at the index-open choke point instead of an undefined reference or a # missing payload three layers down. 2026.8.27.2 is the version this index is # actually tested against, and now the contract says so. +# +# ── 2026-09-18: raised 2026.8.27.2 -> 2026.9.18.1, with the CI pin ───────── +# +# 2026.9.18.1 is the mcpp release that understands `[c-abi]` (design: +# openkal/.agents/docs/2026-09-18-openkal-c-environment-and-personalities- +# design.md §3.2; plan: the sibling 2026-09-18-c-environment-execution-plan.md +# §5, step 1) and has entered xim-pkgindex (step 2). Per the rule at the top +# of this file, this moves together with `.github/workflows/validate.yml`'s +# `MCPP_VERSION`, in this same commit. +# +# This raise on its own changes nothing observable: no descriptor in this +# index declares `[c-abi]` yet, and mcpp's own release notes state that a +# package which does not declare the block gets the same command line, byte +# for byte, as before. Verified here, not merely asserted: every descriptor +# in pkgs/*/*.lua still parses with `mcpp xpkg parse` under 2026.9.18.1. +# +# ── 2026-09-18: raised 2026.9.18.2 -> 2026.9.18.3, with both CI pins ──────── +# +# 2026.9.18.3 is the release whose c-abi probe on a Windows host × freestanding +# target stops mismatching on _WIN32 (host strip) and __SIZEOF_WCHAR_T__ +# (realisation always emits -fno-short-wchar on freestanding). The probe's +# measurement contract is unchanged (design §3.2: a declaration is checked, +# never trusted); the realisation's previous "freestanding skips the wchar +# flag" rule was the actual bug, the wave's measurement is what caught it. +# A floor at 2026.9.18.2 would let a 2026.9.18.2 user be refused builds the +# next release accepts. Per the rule at the top of this file, this moves in +# the same commit as validate.yml's `MCPP_VERSION`; openkal-compat.yml's +# `MCPP_VERSION` moves with tests/openkal/pins.toml's `mcpp`, which that +# workflow checks for agreement. +# +# openkal-musl 0.15.0 and openkal-llvm-runtime 0.11.0 (plan step 3) -- the two +# packages that will actually declare and consume `[c-abi] presents = +# "posix"` -- are NOT registered by this raise. Neither has a version number +# or a sha256 yet; `pkgs/o/openkal-musl.lua` and +# `pkgs/o/openkal-llvm-runtime.lua` carry a note beside their version tables +# marking exactly that, and this index has no data to put in an xpm entry for +# either until the other agent handling their release reports the tag and +# hash. Registering them is plan step 4, a separate change from this one: +# raising the floor was gated on the engine, not on those two packages, and +# gating on both at once would have held this raise hostage to something it +# does not need. [index] spec = "1" -min_mcpp = "2026.8.27.2" -latest_mcpp = "2026.8.27.2" +min_mcpp = "2026.9.18.3" +latest_mcpp = "2026.9.18.3" diff --git a/pkgs/c/compat.mbedtls.lua b/pkgs/c/compat.mbedtls.lua index 55d79a12..a27dbafb 100644 --- a/pkgs/c/compat.mbedtls.lua +++ b/pkgs/c/compat.mbedtls.lua @@ -56,21 +56,22 @@ package = { c_standard = "c11", targets = { ["mbedtls"] = { kind = "lib" } }, deps = { }, + -- Windows with musl as the C library (an openkal graph) used to carry a + -- `target_cfg` here (`-U_WIN32 -D__unix__`): mbedtls selects its + -- entropy, timing and socket code by asking whether the environment is + -- Windows (_WIN32) or Unix (__unix__), the triple answered Windows, and + -- the C library these units actually compile against is POSIX-shaped + -- (openkal-musl: getrandom, clock_gettime, BSD sockets), so the flags + -- corrected what the triple implied for mbedtls's own translation + -- units. 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 one package at a time, so _WIN32 is simply absent and + -- __unix__ is simply present there to begin with; the `target_cfg` is + -- withdrawn rather than reproduced. windows = { ldflags = { "-lbcrypt" }, }, - target_cfg = { - -- Windows with musl as the C library. mbedtls selects its entropy, - -- timing and socket code by asking whether the environment is - -- Windows (_WIN32) or Unix (__unix__); the triple answers Windows, - -- and the C library these units compile against is POSIX-shaped - -- (openkal-musl: getrandom, clock_gettime, BSD sockets). Both - -- flags are confined to mbedtls's own translation units, and no - -- public header of mbedtls tests either macro, so its consumers - -- read the same declarations. - ["cfg(all(windows, c-abi = \"musl\"))"] = { - cflags = { "-U_WIN32", "-D__unix__" }, - }, - }, }, } diff --git a/pkgs/c/compat.zlib.lua b/pkgs/c/compat.zlib.lua index 3fe29b38..6a126727 100644 --- a/pkgs/c/compat.zlib.lua +++ b/pkgs/c/compat.zlib.lua @@ -42,31 +42,58 @@ package = { import_std = false, c_standard = "c11", include_dirs = {"*", "mcpp_generated/include"}, - -- Both of these are GCC/Clang-only and used to be unconditional. - -- `-include` is the worse of the two on MSVC: cl does not reject it, it - -- warns (`D9002 ignoring unknown option`) and carries on, so the config - -- header was silently never included. The header only defines anything - -- when _WIN32 is absent, so Windows needs neither. + -- GCC/Clang-only, safe unconditionally: the header's own guard + -- (`#if !defined(_WIN32)`) is the real platform test, this placement + -- is not. It used to sit only in the linux/macosx blocks below, + -- because on native Windows _WIN32 is always true and the header + -- defines nothing there -- and on Windows with musl as the C library + -- (an openkal graph) _WIN32 used to be true too, so a `target_cfg` + -- carried a hand-written `-U_WIN32 -include unistd.h` to reach the + -- same POSIX-shaped compile that Linux and macOS already got from + -- this same header. 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, so + -- _WIN32 is simply absent there to begin with; this one line, applied + -- everywhere, now reaches openkal-Windows exactly as it already + -- reaches Linux and macOS, and the `target_cfg` is withdrawn rather + -- than reproduced. zconf.h computes z_off_t and z_off64_t as `off_t` + -- wherever this header's guard is open, `long long` where it is not. + -- + -- This `cflags` is package-private: it reaches zlib's own + -- translation units (gzlib.c, zutil.c, ...) but not a consumer + -- compiling zlib.h (verified against tests/examples/zlib's + -- compile_commands.json -- the flag is absent from tests/zlib.cpp's + -- own command line). So the library computes z_off_t with + -- Z_HAVE_UNISTD_H set (= off_t) while an openkal-Windows consumer, + -- which never sees this header, computes it with Z_HAVE_UNISTD_H + -- unset (= long long, zconf.h's own unconditional fallback). off_t + -- and long long agree in size on every target this index measures -- + -- all of them LP64 (x86_64-linux-gnu, x86_64-windows-gnu; see + -- tests/openkal/pins.toml and the platforms xpm above) -- which is + -- why this is safe today rather than merely untested. This is not a + -- new asymmetry introduced by hoisting the `-include`: the withdrawn + -- `-include unistd.h` it replaced was package-private in exactly the + -- same way, so the library and the consumer already reached z_off_t + -- by two different routes before this change, and already agreed + -- only because every measured target is LP64. This comment preserves + -- that property, and the note about it, rather than introducing + -- either. On an ILP32 target without _LARGEFILE64_SOURCE, off_t is + -- 4 bytes and long long + -- is 8: the two sides of this same split would disagree, silently, + -- in the type gzseek/gztell pass across the package boundary. Rule 3 + -- of docs/openkal-compat.md is exactly this situation (a macro that + -- changes a public header's declaration and cannot reach the + -- consumer), and rule 4 is why tests/examples/zlib already asserts + -- the agreement at run time via zlibCompileFlags() against the + -- consumer's own sizeof(z_off_t) -- add an ILP32 target to this + -- descriptor only once that assertion has actually been run there, + -- not on the strength of this comment. gzopen_w stays declared for a + -- consumer and is not defined: a call to it fails at the link rather + -- than at run time. + cflags = { "-include", "mcpp_zlib_config.h" }, linux = { - cflags = { "-D_GNU_SOURCE", "-include", "mcpp_zlib_config.h" }, - }, - macosx = { - cflags = { "-include", "mcpp_zlib_config.h" }, - }, - -- Windows with musl as the C library (an openkal graph). The triple - -- defines _WIN32, and zlib reads _WIN32 as "the Windows C runtime is - -- present" (, _lseeki64, _wopen), which is false here. The flag is - -- confined to zlib's own translation units and reaches no public - -- header in a way that changes a declaration: zconf.h computes z_off_t - -- and z_off64_t as `long long` on both sides, because Z_HAVE_UNISTD_H - -- is deliberately not defined (unistd.h is included directly instead). - -- tests/examples/zlib asserts that agreement with zlibCompileFlags(). - -- gzopen_w stays declared for a consumer and is not defined: a call to - -- it fails at the link rather than at run time. - target_cfg = { - ["cfg(all(windows, c-abi = \"musl\"))"] = { - cflags = { "-U_WIN32", "-include", "unistd.h" }, - }, + cflags = { "-D_GNU_SOURCE" }, }, generated_files = { ["mcpp_generated/include/mcpp_zlib_config.h"] = "#ifndef MCPP_ZLIB_CONFIG_H\n#define MCPP_ZLIB_CONFIG_H\n#if !defined(_WIN32)\n#define Z_HAVE_UNISTD_H 1\n#endif\n#endif\n", diff --git a/pkgs/o/openkal-llvm-runtime.lua b/pkgs/o/openkal-llvm-runtime.lua index 540532c1..d27a39d4 100644 --- a/pkgs/o/openkal-llvm-runtime.lua +++ b/pkgs/o/openkal-llvm-runtime.lua @@ -15,6 +15,18 @@ -- does NOT carry is a prebuilt binary for any target: the runtime is compiled -- for the target being built, by whichever compiler is running, which is the -- property that makes one source reach four object formats. +-- +-- 0.11.0 is pending, not listed below. It is the recompile that follows +-- openkal-musl 0.15.0's `[c-abi] presents = "posix"` declaration (design: +-- openkal/.agents/docs/2026-09-18-openkal-c-environment-and-personalities- +-- design.md §10) and drops the `_WIN32`-selected libunwind patches +-- (RWMutex.hpp, UnwindCursor.hpp, AddressSpace.hpp) and the +-- `_WIN64`-vs-SysV register-save mismatch in UnwindRegistersSave.S / +-- UnwindRegistersRestore.S / __libunwind_config.h that the same design's +-- plan document records (2026-09-18-c-environment-execution-plan.md §4) in +-- favour of definitions the package's own manifest now gives per target +-- (design §3.4). Neither the release nor its sha256 exist yet -- this +-- comment marks the entry as prepared and blocked, not as data to invent. package = { spec = "1", namespace = "mcpplibs", diff --git a/pkgs/o/openkal-musl.lua b/pkgs/o/openkal-musl.lua index 84d0cb62..49c60998 100644 --- a/pkgs/o/openkal-musl.lua +++ b/pkgs/o/openkal-musl.lua @@ -13,6 +13,15 @@ -- implementation's `standalone' feature. -- -- The consequence for a program is that it names this package and nothing else. +-- +-- 0.15.0 is pending, not listed below. It declares `[c-abi] presents = "posix"` +-- (design: openkal/.agents/docs/2026-09-18-openkal-c-environment-and- +-- personalities-design.md §3.2) and removes the LLP64/16-bit-wchar_t patches +-- to musl's generated Windows headers, in favour of the Cygwin-shaped LP64 +-- target that declaration realises (same design, §4); this repository's +-- `index.toml` carries a matching note about the `min_mcpp` this needs. +-- Neither the release nor its sha256 exist yet -- this comment marks the +-- entry as prepared and blocked, not as data to invent. package = { spec = "1", namespace = "mcpplibs", diff --git a/tests/openkal/compat.py b/tests/openkal/compat.py index ee93e33c..3601c7bb 100644 --- a/tests/openkal/compat.py +++ b/tests/openkal/compat.py @@ -19,6 +19,26 @@ builds the member built; its tests were not run on this host fails the build or the tests failed; the first diagnostic is kept +and, alongside `status`, a second and orthogonal `kind` records how the +member relates to the platform rather than whether it worked: + + 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 (see `platform_bound` below) + platform needs the platform's own interfaces -- the member declares a + platform dependency of its own (a per-target `dependencies` + table, the same fact `platform_bound` already reports as + "not portable" -- see docs/openkal-compat.md #4 rule 1, where a + feature's `feature-deps` reaches a platform SDK shim) -- and + `status` is "runs" or "builds" + +`kind` is omitted, not guessed, when `status == "fails"`: an unmeasured member +states nothing about its relation to the platform. A third label, `native` +(built in the 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) -- and is not computed here. + `select` reads changed file paths and prints the members to measure: every listed member when the openkal family or this directory changed, otherwise the members whose test projects depend on a changed descriptor. @@ -101,6 +121,23 @@ def platform_bound(manifest: dict) -> bool: return False +def kind_of(manifest: dict, status: str) -> str | None: + """The platform-relation label for one (member, target) result -- see the + `posix` / `platform` table in this module's docstring, which this + function is the whole of the implementation of. `platform_bound` is the + one signal used for "declares a platform dependency"; there is + deliberately no second, separate heuristic guessing at a package's + internals -- a label not backed by a declared or measured fact is worse + than no label, so an ambiguous case returns None rather than a guess.""" + if status == "fails": + return None + if platform_bound(manifest): + return "platform" + if status == "runs": + return "posix" + return None + + def prepare(member: str, pins: dict) -> str: """Copies a member and states the openkal graph in its manifest. @@ -194,7 +231,11 @@ def cmd_run(args: argparse.Namespace) -> int: entry["targets"][target] = measure(member, target, pins) except subprocess.TimeoutExpired: entry["targets"][target] = {"status": "fails", "diagnostic": "timed out"} + kind = kind_of(manifest, entry["targets"][target]["status"]) + if kind: + entry["targets"][target]["kind"] = kind print(f" {entry['targets'][target]['status']}" + + (f" ({kind})" if kind else "") + (f": {entry['targets'][target].get('diagnostic', '')}" if entry['targets'][target]['status'] == 'fails' else ""), flush=True) results["members"][member] = entry diff --git a/tests/openkal/pins.toml b/tests/openkal/pins.toml index 05fdafdb..61ead6df 100644 --- a/tests/openkal/pins.toml +++ b/tests/openkal/pins.toml @@ -6,7 +6,28 @@ # version names the whole graph. runtime = "0.10.0" toolchain = "llvm@22.1.8" -mcpp = "2026.9.17.3" +# `mcpp` here moves together with index.toml's `min_mcpp` and +# .github/workflows/openkal-compat.yml's own MCPP_VERSION (that workflow +# checks the two agree, and fails loudly if they do not) -- not because this +# is the same pin as validate.yml's, but because 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 this measurement exactly as it gates every other client. +# Confirmed: with this pin left at 2026.9.17.3 after index.toml's min_mcpp +# moved to 2026.9.18.1, every member here fails immediately with "error: +# index requires mcpp >= 2026.9.18.1 but this is mcpp 2026.9.17.3 [E0006]" +# before a single line of the member's own source is read. +# +# `runtime` does NOT move here: openkal-llvm-runtime 0.11.0 (the version that +# actually declares/consumes `[c-abi]`) is not published yet -- see the note +# in pkgs/o/openkal-llvm-runtime.lua. Bumping `mcpp` alone, ahead of it, +# changes nothing observable today: no package this pin resolves declares +# `[c-abi]`. Verified locally (not merely asserted): a full run of every +# member listed below against x86_64-linux-gnu, under 2026.9.18.1, reproduces +# the checked-in baseline exactly -- same 27 runs / 3 fails, same three +# members (expat, curl, cmp-module), same diagnostics character-for-character +# past the local path prefix. +mcpp = "2026.9.18.3" targets = ["x86_64-linux-gnu", "x86_64-windows-gnu"]