Skip to content

Commit 029cad6

Browse files
The suite can be given flags of its own, and the portable example builds again (#29)
THE PORTABLE EXAMPLE BUILT NOWHERE, AND THE PINS ARE WHY. `src/main.cpp` was updated for 0.11's `kal_spawn` -- one struct where there had been three declarations -- and `examples/portable/mcpp.toml` still pinned openkal 0.10.0: src/main.cpp:256:19: error: 'kal_spawn' does not name a type identically for the host and for every cross target. A version pin in an example is a claim about what that example builds against, and nothing was checking it: the program is not in any package's build, so no repository's continuous integration compiled it. The four pins now name the published versions, and the example runs -- 0 observations that did not hold on the host. AND IT GAINS THE THREE PLATFORMS, WHICH IS TWO LINES AND NOT THREE. Android NO LINE. `aarch64-linux-android` has `os = "linux"` because the kernel IS Linux; bionic is a C library above it, and an implementation written on the kernel's own interface does not know which C library sits above it. `cfg(os = "linux")` already selects `openkal-linux` for both ABIs, and an Android line would be a second name for one answer. iOS ONE LINE, no package. Darwin is Darwin -- the same traps, the same call numbers, the same calling convention -- and what differs between macOS and iOS is the SDK and the deployment-target flag, which belong to the build tool. `cfg(os = "ios")` matches all three iOS rows. Web ONE LINE and new software. `openkal-emscripten` is the first implementation in this ecosystem written ABOVE a C library, which clause 2 permits in as many words. FLAGS THE SUITE ITSELF HAS TO CARRY (`OPENKAL_CONFORMANCE_SUITE_FLAGS`). `OPENKAL_CONFORMANCE_IMPL_FEATURES` names features of the IMPLEMENTATION, and for every platform so far that was the whole of what an unusual arrangement needed. Emscripten is the first where it is not: its thread support is selected by `-pthread`, which chooses a different C library build, a different memory model and a different loader contract, so it is a property of the WHOLE LINK. Measured with the implementation's feature active and the suite built without the flag: DID NOT HOLD an execution context starts DID NOT HOLD four execution contexts start DID NOT HOLD contexts that ran at the same time have identities distinct which is the suite being right: if `openkal.task` is provided, a context starts. The variable adds the flags to the suite's compile AND link, because a flag that selects a memory model must reach every translation unit and the link, and one that reached half would produce a suite whose halves disagree. It does not yet reach far enough, and that is recorded rather than papered over: the specification package's own modules are compiled without it, so a run with the variable set now fails with error: POSIX thread support was disabled in precompiled file '.../pcm.cache/openkal.types.pcm' but is currently enabled A whole-graph flag channel is an engine change; `openkal-emscripten` gates the interface behind a feature so that the absence is a link error rather than a present-and-failing operation, and its README carries the rest. AND THE FEATURE STAMP HAS TWO AXES NOW. The paragraph in this script about a feature-set change not invalidating the build applies to the new variable identically, and the first run that used it reported the previous run's build: a module cache compiled without the flag. The record is now `features|flags`. `check-surface.sh` TAKES `$NM`. A wasm object is not an ELF, and the host's binutils `nm` reports "file format not recognized" for one; the reader that does read it ships with the toolchain that produced it. Named in the environment like the runner and the features, with the default unchanged. Same class of defect as the leading-underscore note beside it, and found the same way: by writing another implementation. Co-authored-by: speak-agent <x.d2learn.org@gmail.com>
1 parent 26e32ec commit 029cad6

4 files changed

Lines changed: 183 additions & 10 deletions

File tree

examples/portable/README.md

Lines changed: 55 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,58 @@ It prints one line per interface, each beginning `openkal: `, and a final line
1818
reporting the number of observations that did not hold. An implementation
1919
passes when that number is zero.
2020

21-
The program requires an implementation that provides every interface. An
22-
implementation that omits one fails to link, and the linker names the operations
23-
it did not define — which is the diagnostic clause 4.2 describes.
21+
The program requires an implementation that provides every interface it uses.
22+
An implementation that omits one fails to link, and the linker names the
23+
operations it did not define — which is the diagnostic clause 4.2 describes.
24+
25+
## Five platforms, and the three ways one is reached
26+
27+
The manifest names an implementation per platform and the program names none.
28+
What is worth reading in it is that the five platforms are reached in three
29+
different ways:
30+
31+
| platform | line in the manifest | what supplies it |
32+
|---|---|---|
33+
| Linux (glibc, musl) | `cfg(os = "linux")` | `openkal-linux` |
34+
| Android, both ABIs | the SAME line | `openkal-linux`, unchanged |
35+
| macOS | `cfg(os = "macos")` | `openkal-macos` |
36+
| iOS, both simulator arches | `cfg(os = "ios")` | `openkal-macos`, unchanged |
37+
| Windows | `cfg(windows)` | `openkal-windows` |
38+
| Web (Emscripten) | `cfg(os = "emscripten")` | `openkal-emscripten` |
39+
40+
**Android needs no line of its own**, because `aarch64-linux-android` has
41+
`os = "linux"`: the kernel IS Linux, bionic is a C library above it, and an
42+
implementation written on the kernel's own system-call interface does not know
43+
which C library sits above it. Adding an Android line would be adding a second
44+
name for one answer.
45+
46+
**iOS needs a line and not a package.** Darwin is Darwin — the same traps, the
47+
same call numbers, the same calling convention — and what differs between macOS
48+
and iOS is the SDK and the deployment-target flag, which belong to the build
49+
tool. So one `cfg` line selects the macOS implementation for all three iOS rows.
50+
51+
**The Web needed new software.** Emscripten has no kernel to issue a call to,
52+
so an implementation there cannot be written beneath a C library and has to sit
53+
above one. `openkal-emscripten` provides twelve of the fifteen interfaces; this
54+
program uses eight, all of which are among them. A program that used
55+
`openkal.process` would fail at link naming the symbol, which is how a partial
56+
surface reports itself.
57+
58+
## The version pins here are a claim, and they were wrong
59+
60+
`src/main.cpp` was updated for 0.11's `kal_spawn` — one struct where there had
61+
been three declarations — and these pins were not, so the example built
62+
NOWHERE:
63+
64+
```
65+
src/main.cpp:256:19: error: 'kal_spawn' does not name a type
66+
```
67+
68+
It failed identically for the host and for every cross target, because a
69+
version pin in an example is a claim about what that example builds against and
70+
nothing was checking it. The program is not in any package's build, so no
71+
repository's continuous integration compiled it.
72+
73+
That is what the platform lines above are for as much as demonstration: each
74+
one is a target something can be asked to build, and the specification's own
75+
conformance job builds this source over each implementation it tests.

examples/portable/mcpp.toml

Lines changed: 57 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,66 @@ name = "portable"
99
version = "0.1.0"
1010

1111
[dependencies]
12-
openkal = "0.10.0"
12+
openkal = "0.12.0"
1313

14+
# AND THE VERSIONS HAVE TO FOLLOW THE SOURCE, which is the reason this example
15+
# is a criterion rather than an assumption.
16+
#
17+
# `src/main.cpp` was updated for 0.11's `kal_spawn` --- one struct where there
18+
# had been three declarations --- and these four pins were not. So the example
19+
# built nothing on any target:
20+
#
21+
# src/main.cpp:256:19: error: 'kal_spawn' does not name a type
22+
#
23+
# A version pin in an example is a claim about what that example builds
24+
# against, and nothing checked it: the example is not in any package's build,
25+
# so no repository's continuous integration compiled it. The platform legs
26+
# below exist so that it cannot go stale silently again.
1427
[target.'cfg(os = "linux")'.dependencies]
15-
openkal-linux = "0.9.0"
28+
openkal-linux = "0.12.0"
1629

1730
[target.'cfg(os = "macos")'.dependencies]
18-
openkal-macos = "0.7.0"
31+
openkal-macos = "0.9.0"
1932

2033
[target.'cfg(windows)'.dependencies]
21-
openkal-windows = "0.5.0"
34+
openkal-windows = "0.7.0"
35+
36+
# ANDROID IS NOT A LINE HERE, AND THAT IS THE POINT.
37+
#
38+
# `aarch64-linux-android` and `x86_64-linux-android` have `os = "linux"`,
39+
# because the kernel IS Linux: bionic is a C library above it, and an
40+
# implementation written on the kernel's own system-call interface does not
41+
# know which C library sits above it. So `cfg(os = "linux")` above already
42+
# selects `openkal-linux` for both Android rows, and adding an Android line
43+
# would be adding a second name for one answer.
44+
#
45+
# Verified against the released engine rather than assumed: both ABIs build
46+
# over `openkal-linux` and their objects name no C library symbol, and a
47+
# program over openkal alone ran on an emulator.
48+
49+
# iOS REUSES THE macOS IMPLEMENTATION, AND THAT NEEDED A LINE BECAUSE THE OS
50+
# SEGMENT DIFFERS.
51+
#
52+
# Darwin is Darwin: the same Mach traps, the same BSD call numbers, the same
53+
# calling convention. What differs between macOS and iOS is the SDK and the
54+
# deployment-target flag, which are the build tool's business and not the
55+
# implementation's -- so this is one `cfg` line and no new package.
56+
#
57+
# All three iOS rows match: the device and both simulator arches carry
58+
# `os = "ios"`.
59+
[target.'cfg(os = "ios")'.dependencies]
60+
openkal-macos = "0.9.0"
61+
62+
# THE WEB IS THE ONE PLATFORM THAT NEEDED NEW SOFTWARE.
63+
#
64+
# Emscripten has no kernel to issue a call to, so an implementation cannot be
65+
# written the way the other four are -- beneath a C library -- and must sit
66+
# ABOVE one, which clause 2 permits. `openkal-emscripten` is that
67+
# implementation.
68+
#
69+
# It provides twelve of the fifteen interfaces. This program uses eight, all of
70+
# which are among them; a program that used `openkal.process` would fail at
71+
# LINK naming the symbol, which is clause 6.2's second time and is how a
72+
# partial surface reports itself.
73+
[target.'cfg(os = "emscripten")'.dependencies]
74+
openkal-emscripten = "0.1.0"

tools/check-surface.sh

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,20 @@ spec="$(grep -vE '^[[:space:]]*(#|$)' "$list" | sort -u)"
3232
# would find no names at all on one of them — and would report that as success,
3333
# because an empty surface contains nothing unspecified. The defect was found by
3434
# writing a second implementation, which is what a second implementation is for.
35-
found="$(nm --defined-only "$@" \
35+
# THE SYMBOL READER IS NAMED, BECAUSE `nm` DOES NOT READ EVERY OBJECT THIS
36+
# ECOSYSTEM PRODUCES.
37+
#
38+
# A wasm object is not an ELF, and the host's binutils `nm` reports
39+
# "file format not recognized" for one. The reader that does read it ships with
40+
# the toolchain that produced it -- `llvm-nm` inside the emsdk payload -- so it
41+
# is named in the environment rather than assumed, in the same way the runner
42+
# and the features are. The default is unchanged, so every existing caller is.
43+
#
44+
# This is the same class of defect as the leading-underscore note above, found
45+
# the same way: by writing another implementation.
46+
NM="${NM:-nm}"
47+
48+
found="$($NM --defined-only "$@" \
3649
| awk '$2=="T"||$2=="W"||$2=="R"||$2=="D"||$2=="B"||$2=="S"{print $3}' \
3750
| sed 's/^_//' \
3851
| grep '^kal_' | sort -u || true)"

tools/run-conformance.sh

Lines changed: 57 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,47 @@ if [ -n "$impl_features" ]; then
108108
impl_line="$package = { path = \"$implementation_native\", features = [\"$impl_features\"] }"
109109
fi
110110

111+
# FLAGS THE SUITE ITSELF HAS TO CARRY, WHICH IS NOT THE SAME AS FLAGS THE
112+
# IMPLEMENTATION CARRIES.
113+
#
114+
# `OPENKAL_CONFORMANCE_IMPL_FEATURES` above names features of the
115+
# IMPLEMENTATION, and for every platform so far that has been the whole of what
116+
# an unusual arrangement needed. Emscripten is the first where it is not: its
117+
# thread support is selected by `-pthread`, which chooses a different C library
118+
# build, a different memory model and a different loader contract --- so it is a
119+
# property of the WHOLE LINK, and a suite compiled without it cannot start a
120+
# context however the implementation was compiled.
121+
#
122+
# Measured 2026-09-11, with the implementation's `threads` feature active and
123+
# the suite built without the flag:
124+
#
125+
# DID NOT HOLD an execution context starts
126+
# DID NOT HOLD four execution contexts start
127+
# DID NOT HOLD contexts that ran at the same time have identities distinct
128+
#
129+
# which is the suite being right: if `openkal.task` is provided, a context
130+
# starts. The flags therefore belong to the suite as well, and they are named in
131+
# the environment for the same reason the runner and the features are ---
132+
# whoever runs the suite knows the arrangement and the suite cannot.
133+
#
134+
# Added to BOTH sides deliberately: a flag that selects a memory model must
135+
# reach every translation unit and the link, and a variable that reached one of
136+
# them would produce a suite whose halves disagree.
137+
suite_flags="${OPENKAL_CONFORMANCE_SUITE_FLAGS:-}"
138+
if [ -n "$suite_flags" ]; then
139+
quoted=""
140+
for f in $suite_flags; do
141+
[ -n "$quoted" ] && quoted="$quoted, "
142+
quoted="$quoted\"$f\""
143+
done
144+
{
145+
printf '\n[build]\n'
146+
printf 'cxxflags = [%s]\n' "$quoted"
147+
printf 'ldflags = [%s]\n' "$quoted"
148+
} >> "$suite/mcpp.toml"
149+
echo "--- the suite carries: $suite_flags ---"
150+
fi
151+
111152
if ! grep -q "^$package = " "$suite/mcpp.toml"; then
112153
# Appended immediately after openkal, which is inside [dependencies]. A
113154
# plain append would land under [features].
@@ -143,8 +184,22 @@ cd "$suite"
143184
# The remedy is to remember which set the build in `target' was made for, and to
144185
# discard the build when the answer changes. Re-running the same set still
145186
# builds incrementally, which is what the record is for.
187+
# AND THE SUITE'S FLAGS ARE PART OF WHAT THE RECORD HAS TO REMEMBER.
188+
#
189+
# The paragraph above is about the feature set; `OPENKAL_CONFORMANCE_SUITE_FLAGS`
190+
# is a second axis with the same property, and the first run that used it
191+
# reported the previous run's build:
192+
#
193+
# error: POSIX thread support was disabled in precompiled file
194+
# '.../pcm.cache/openkal.types.pcm' but is currently enabled
195+
#
196+
# which is the module cache from a build made without the flag. The remedy is
197+
# the one already written here, applied to both axes rather than to one: a
198+
# record of what the build in `target' was made for, and a discard when the
199+
# answer changes.
146200
stamp="target/.features"
147-
if [ ! -f "$stamp" ] || [ "$(cat "$stamp")" != "$features" ]; then
201+
want_stamp="$features|$suite_flags"
202+
if [ ! -f "$stamp" ] || [ "$(cat "$stamp")" != "$want_stamp" ]; then
148203
rm -rf target
149204
fi
150205
# ⚠️⚠️ AND THE SAME DEFECT AGAIN, IN THE LINE THAT FINDS WHAT WAS BUILT.
@@ -170,7 +225,7 @@ find target -type f \( -name 'openkal-conformance' -o -name 'openkal-conformance
170225
-delete 2> /dev/null || true
171226

172227
mcpp build --features "$features" "$@"
173-
mkdir -p target && printf '%s' "$features" > "$stamp"
228+
mkdir -p target && printf '%s' "$want_stamp" > "$stamp"
174229

175230
produced="$(find target -type f \( -name 'openkal-conformance' -o -name 'openkal-conformance.exe' \))"
176231
count="$(printf '%s\n' "$produced" | grep -c . || true)"

0 commit comments

Comments
 (0)