Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
2,149 changes: 2,149 additions & 0 deletions .agents/docs/2026-08-28-beyond-static-linking-abi-review.md

Large diffs are not rendered by default.

26 changes: 23 additions & 3 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -258,11 +258,31 @@ jobs:
cat > .abi-probe/src/main.cpp <<'EOF'
#include <openkal/types.h>
#include <openkal/fs.h>
static_assert(__builtin_offsetof(kal_node_info, size) == 0);
static_assert(__builtin_offsetof(kal_node_info, modified_ns) == 8);
static_assert(sizeof(kal_node_info) == 24);
// `self_size' IS FIRST, AND THAT IS THE WHOLE OF THE GROWTH RULE.
// An implementation built at a later version reads this field before
// it touches anything else, which is how it learns how much of the
// structure the caller has. A layout in which it were not first would
// make the field unreadable by exactly the implementation it exists
// to inform.
static_assert(__builtin_offsetof(kal_node_info, self_size) == 0);
static_assert(__builtin_offsetof(kal_node_info, present) == 4);
// The fields that existed at 0.9.0, at the offsets they had. Growth
// is permitted only past the end; these do not move.
static_assert(__builtin_offsetof(kal_node_info, size) == 8);
static_assert(__builtin_offsetof(kal_node_info, modified_ns) == 16);
static_assert(__builtin_offsetof(kal_node_info, identity) == 24);
static_assert(__builtin_offsetof(kal_node_info, kind) == 40);
static_assert(__builtin_offsetof(kal_node_info, writable) == 44);
// The same at both pointer widths, which is the property this
// 32-bit row exists to observe: no field of it is pointer-sized.
static_assert(sizeof(kal_node_info) == 48);
static_assert(sizeof(kal_dir) == sizeof(kal_uintptr));
static_assert(sizeof(kal_file) == sizeof(kal_uintptr));
// A transfer is one signed word, and a signed word is a pointer's
// width. An implementation returning `int' here would truncate a
// count on a 64-bit machine and would be caught by nothing else.
static_assert(sizeof(kal_intptr) == sizeof(kal_uintptr));
static_assert((kal_intptr)-1 < 0);
extern "C" void _start() { for (;;) {} }
EOF
for t in riscv64-none-elf riscv32-none-elf; do
Expand Down
40 changes: 29 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,17 +14,35 @@ undefined references, which is the intended outcome.

| Module | Header | Interface | Class |
| --- | --- | --- | --- |
| `openkal.types` | `openkal/types.h` | machine word, error values, transfer result | — |
| `openkal.types` | `openkal/types.h` | machine word, error values, endpoint | — |
| `openkal.version` | `openkal/version.h` | what the implementation says about itself | every |
| `openkal.abort` | `openkal/abort.h` | termination | core |
| `openkal.stream` | `openkal/stream.h` | byte streams | core |
| `openkal.memory` | `openkal/memory.h` | allocation | core |
| `openkal.env` | `openkal/env.h` | the parameters a program receives at inception | standard |
| `openkal.time` | `openkal/time.h` | monotonic and wall time sources | standard |
| `openkal.fs` | `openkal/fs.h` | directories and open files, relative throughout | standard |
| `openkal.process` | `openkal/process.h` | starting a program and waiting for it | standard |
| `openkal.task` | `openkal/task.h` | execution contexts, and the primitive they are built upon | standard |
| `openkal.memory` | `openkal/memory.h` | allocation, and the environment's granularity | core |
| `openkal.env` | `openkal/env.h` | the parameters a program receives at inception | optional |
| `openkal.time` | `openkal/time.h` | monotonic and wall time sources | optional |
| `openkal.fs` | `openkal/fs.h` | directories and open files, relative throughout | optional |
| `openkal.process` | `openkal/process.h` | starting a program and waiting for it | optional |
| `openkal.task` | `openkal/task.h` | execution contexts, and the primitive they are built upon | optional |
| `openkal.random` | `openkal/random.h` | a source of unpredictable bytes | optional |
| `openkal.exec` | `openkal/exec.h` | a region of the address space a program may execute | optional |
| `openkal.terminal` | `openkal/terminal.h` | an interactive stream's treatment of what is typed | optional |
| `openkal.net` | `openkal/net.h` | a connection, and a listener for connections | optional |
| `openkal.datagram` | `openkal/datagram.h` | a message with a boundary | optional |
| `openkal.space` | `openkal/space.h` | an address space, and a context executing in one | optional |
| `openkal.timeout` | `openkal/timeout.h` | a bound upon operations that would otherwise wait | optional |

⚠️ **There were three classes and there are two.** Version 0.8 named a middle
one — *standard*, "an interface an implementation hosting a C library provides"
— and it was false: an implementation for a machine with firmware and no
operating system provides none of `openkal.fs`, `openkal.process` or
`openkal.task`, and a C library is hosted above it. Clause 6.1 makes an
interface's absence a fact a consumer learns from the linker; no class was
needed to predict it, and the prediction was wrong.

`openkal.version` is in the table and is not an interface: it provides no
resource, and every conforming implementation exports its two operations so that
a consumer with no linker to ask can ask before it calls.

### One statement of the declarations, two ways to reach it

Expand Down Expand Up @@ -59,16 +77,16 @@ conditional on the target.

```toml
[dependencies]
openkal = "0.5.1"
openkal = "0.9.0"

[target.'cfg(os = "linux")'.dependencies]
openkal-linux = "0.5.1"
openkal-linux = "0.7.0"

[target.'cfg(os = "macos")'.dependencies]
openkal-macos = "0.3.1"
openkal-macos = "0.6.0"

[target.'cfg(windows)'.dependencies]
openkal-windows = "0.1.1"
openkal-windows = "0.4.0"
```

The program imports the interface and names no implementation.
Expand Down
Loading
Loading