Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
d66232f
openkal-emscripten 0.2.0, std-freestanding-alloc-kal 0.1.6, and CI bu…
Sunrisepeak Sep 17, 2026
180b25c
compat.libarchive: macOS with musl builds without the Apple SDK (#434)
Sunrisepeak Sep 17, 2026
3acfce2
compat.libarchive on Linux with musl, and the tinyhttps member at 0.3.1
Sunrisepeak Sep 17, 2026
333d5bb
openkal-compat: a measurement requested on another branch proposes no…
Sunrisepeak Sep 17, 2026
1de1172
compat.py: a measured copy resolves compat from this checkout
Sunrisepeak Sep 17, 2026
e05856b
openkal compatibility: the measurement of 2026-09-17
Sunrisepeak Sep 17, 2026
8fc4b63
compat.zlib, compat.mbedtls: withdraw the _WIN32 workarounds the c-ab…
Sunrisepeak Sep 18, 2026
6382334
openkal compat: a second, orthogonal kind label -- posix or platform
Sunrisepeak Sep 18, 2026
4807a5f
Prepare, and mark blocked, the descriptors and floor the c-abi wave s…
Sunrisepeak Sep 18, 2026
1844867
compat.zlib: record which channel the config header rides, and why it…
Sunrisepeak Sep 18, 2026
cc4402c
openkal_kind: say plainly that the package-level badge is a summary
Sunrisepeak Sep 18, 2026
163f6a8
compat.zlib: note the LP64-only agreement is preserved, not introduced
Sunrisepeak Sep 18, 2026
468da5d
Raise min_mcpp and both CI MCPP_VERSION pins to 2026.9.18.1
Sunrisepeak Sep 18, 2026
a6c94f2
Merge origin/main into openkal-c-environment
Sunrisepeak Sep 18, 2026
3a04408
Raise min_mcpp and both CI MCPP_VERSION pins to 2026.9.18.2
Sunrisepeak Sep 18, 2026
851f09b
Raise min_mcpp and both CI MCPP_VERSION pins to 2026.9.18.3
speak-agent Sep 18, 2026
d25937f
README: pin the engine floor at mcpp 2026.9.18.3
Sunrisepeak Sep 18, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion .github/workflows/openkal-compat.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
21 changes: 20 additions & 1 deletion .github/workflows/validate.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
87 changes: 82 additions & 5 deletions .xpkgindex/plugins/mcpp.py
Original file line number Diff line number Diff line change
Expand Up @@ -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 = {
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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 --
Expand Down Expand Up @@ -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}),
Expand Down
12 changes: 12 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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/<initial>/<name>.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
Expand Down
45 changes: 38 additions & 7 deletions docs/openkal-compat.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
45 changes: 43 additions & 2 deletions index.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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"
27 changes: 14 additions & 13 deletions pkgs/c/compat.mbedtls.lua
Original file line number Diff line number Diff line change
Expand Up @@ -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__" },
},
},
},
}
Loading
Loading