diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 9aad5a1..86c9bfc 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -282,6 +282,24 @@ jobs: test -n "$objs" || { echo "no objects were found" >&2; exit 1; } bash .spec/tools/check-surface.sh --complete .spec/SURFACE.txt $objs + # The array in mcpp.toml is a declaration, and a declaration is + # checked rather than trusted. The check is the comparison above + # stopped one step earlier: the walk that decides whether each group + # is exported whole already answers which interfaces this + # implementation provides, so regenerating and diffing is the same + # derivation rather than a second one. The same step openkal-linux + # and openkal-windows carry, so that the three implementations answer + # the question the same way. + bash .spec/tools/check-surface.sh --toml .spec/SURFACE.txt $objs > /tmp/derived.toml + echo " derived from the artefact:" + sed 's/^/ /' /tmp/derived.toml + awk '/^provides-interfaces = \[/{p=1} p{print} /^\]/{if(p)exit}' mcpp.toml > /tmp/declared.toml + if ! diff -u /tmp/declared.toml /tmp/derived.toml; then + echo "::error::mcpp.toml's provides-interfaces disagrees with the artefact" + exit 1 + fi + echo " ok the declaration is the artefact's own answer" + # The property version 0.3 exists for. The assertion is made against the # objects rather than against the source, because a source can reach a C # library through a macro. diff --git a/README.md b/README.md index 2c83fda..2c88c11 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ written on the kernel's own calls. openkal = "0.14.0" [target.'cfg(os = "macos")'.dependencies] -openkal-macos = "0.11.0" +openkal-macos = "0.12.0" ``` Its purpose is as much to test the specification as to be used. A specification diff --git a/mcpp.toml b/mcpp.toml index fa95e2e..3e2b55a 100644 --- a/mcpp.toml +++ b/mcpp.toml @@ -1,7 +1,7 @@ [package] namespace = "mcpplibs" name = "openkal-macos" -version = "0.11.0" +version = "0.12.0" description = "An implementation of openkal for macOS, written on the kernel's own calls. Its purpose is as much to test the specification as to be used." license = "Apache-2.0" @@ -17,6 +17,45 @@ provides = ["mcpp:kernel-abi=openkal"] authors = ["mcpplibs"] repo = "https://github.com/mcpplibs/openkal-macos" +# WHICH INTERFACES OF THAT LAYER THIS PACKAGE PROVIDES (mcpp 2026.9.20.1). +# The engine compares this set against a consumer's `requires-interfaces` at +# dependency resolution and refuses before anything is compiled; it learns no +# interface name from it --- both lists are opaque strings and the only +# operation is a set difference, so the specification may add an interface +# without a release of the engine. +# +# NOT WRITTEN BY HAND. The step "The exported surface is complete and contains +# nothing else" regenerates this array from the objects this package builds and +# fails the run if the two disagree. It is clause 9's surface comparison +# stopped one step earlier: the walk that decides whether each group is +# exported whole already answers which interfaces this implementation provides, +# so regenerating is the same derivation rather than a second one. A +# declaration derived from the thing it describes cannot disagree with it, and +# an implementation that gains an interface cannot forget to say so. +# +# BACKWARD COMPATIBLE. An engine that predates the key reads `[kernel-abi]` as +# an unknown top-level table and ignores it, so this manifest loads unchanged +# everywhere it loaded before; the absence of the check is the behaviour that +# release already had. Measured against the published 2026.9.18.3 archive. +[kernel-abi] +provides-interfaces = [ + "openkal.abort", + "openkal.stream", + "openkal.memory", + "openkal.env", + "openkal.time", + "openkal.random", + "openkal.fs", + "openkal.process", + "openkal.task", + "openkal.exec", + "openkal.terminal", + "openkal.net", + "openkal.datagram", + "openkal.space", + "openkal.timeout", +] + [dependencies] openkal = "0.14.0"