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
e0b28ef
0.1.0 --- mcpplibs.os over openkal 0.17
Sunrisepeak Oct 26, 2026
ae987ce
the target partitions are committed: src/targets, which the ignore of…
Sunrisepeak Oct 26, 2026
b82f445
windows: advapi32 reached at run time, so the package links nothing b…
Sunrisepeak Oct 26, 2026
0d1c836
platform: ARCH, the architecture of the build, from a partition the m…
Sunrisepeak Oct 26, 2026
4bd0175
the ok-image target: host() when the image is loaded, env::loader and…
Sunrisepeak Oct 26, 2026
787988c
an ok image on Windows: names made absolute in the host's spelling (f…
Sunrisepeak Oct 26, 2026
cf6dfbf
process_test: a failed start says why
Sunrisepeak Oct 26, 2026
db4fbfb
an ok image on Windows: a program named by a Windows path is started …
Sunrisepeak Oct 26, 2026
525d64b
README: a Windows name's spelling, single backslashes
Sunrisepeak Oct 26, 2026
73036ec
a name held open is removed at once where the volume claims KAL_FS_PR…
Sunrisepeak Oct 26, 2026
795f384
process: output onto this program's error output (stdio::error), end_…
Sunrisepeak Oct 26, 2026
66b862f
find_executable: on Windows a bare name is never looked for as writte…
Sunrisepeak Oct 26, 2026
bf243fb
linux: the translator is classified from its facts (classify_translat…
Sunrisepeak Oct 26, 2026
f4c2a07
ci: linux_test is one of the suites that must run
Sunrisepeak Oct 26, 2026
5476bb6
ipc: connection::shutdown, safe from another thread, wakes a reader; …
Sunrisepeak Oct 26, 2026
d16d185
openkal 0.17.0 and its implementations, by version
Sunrisepeak Oct 26, 2026
d4b5ad6
the ok-image graph by version: openkal-llvm-runtime 0.16.0 and openka…
Sunrisepeak Oct 26, 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
222 changes: 222 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,222 @@
name: CI

# What this workflow asserts about mcpplibs.os.
#
# tests every module behaves as stated, on every system and with every
# compiler family a consumer builds it with (the native rows)
# platform a platform module used outside `if constexpr' for its platform
# fails to LINK, and the same use in a discarded branch links (R5)
#
# The library is built with the mcpp under cross-validation: until mcpp
# 2026.10.26.2 is released, a unit with a module map that imports another
# package's module through a third (`mcpplibs.os.terminal' through
# `mcpplibs.os.error') does not compile under GCC (mcpp part 2 design §10.2),
# so the mcpp named by MCPP_SOURCE_REF is built and used.

on:
push:
branches: [main]
pull_request:
workflow_dispatch:
inputs:
mcpp_ref:
description: "Branch of mcpp-community/mcpp to build and test with (empty = the released mcpp)"
required: false
default: ""

env:
MCPP_SOURCE_REF: ${{ github.event.inputs.mcpp_ref || vars.MCPP_SOURCE_REF || 'release/2026.10.26.2' }}
XLINGS_VERSION: v2026.10.26.1
XLINGS_NON_INTERACTIVE: '1'

jobs:
native:
name: ${{ matrix.os }} ${{ matrix.toolchain }} ${{ matrix.profile }}
runs-on: ${{ matrix.os }}
timeout-minutes: 90
strategy:
fail-fast: false
matrix:
include:
- { os: ubuntu-24.04, toolchain: '[email protected]', profile: dev }
- { os: ubuntu-24.04, toolchain: '[email protected]', profile: release }
- { os: ubuntu-24.04, toolchain: '[email protected]', profile: dev }
- { os: ubuntu-24.04-arm, toolchain: '[email protected]', profile: dev }
- { os: macos-15, toolchain: '[email protected]', profile: dev }
- { os: windows-2022, toolchain: '[email protected]', profile: dev }
- { os: windows-2022, toolchain: 'msvc@system', profile: dev }
defaults:
run:
shell: bash
steps:
- uses: actions/checkout@v4

- name: Install xlings and mcpp (Unix)
if: runner.os != 'Windows'
run: |
curl -fsSL https://raw.githubusercontent.com/openxlings/xlings/main/tools/other/quick_install.sh \
| bash -s "$XLINGS_VERSION"
echo "$HOME/.xlings/subos/current/bin" >> "$GITHUB_PATH"

- name: Install xlings and mcpp (Windows)
if: runner.os == 'Windows'
shell: pwsh
run: |
irm https://d2learn.org/xlings-install.ps1.txt | iex
"$env:USERPROFILE\.xlings\subos\current\bin" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append

- name: The mcpp under cross-validation
run: |
for attempt in 1 2 3 4 5 6; do
xlings update > /dev/null 2>&1 || true
if xlings install mcpp -y -g; then break; fi
[ "$attempt" = 6 ] && { echo "::error::mcpp could not be installed"; exit 1; }
sleep 60
done
mcpp --version
mcpp self config --mirror GLOBAL
if [ -n "${MCPP_SOURCE_REF:-}" ]; then
src="$RUNNER_TEMP/mcpp-src"
git clone --quiet --depth 1 --branch "$MCPP_SOURCE_REF" https://github.com/mcpp-community/mcpp.git "$src"
rm -f "$src/.xlings.json"
( cd "$src" && mcpp build --release )
built=$(find "$src/target" -type f \( -name mcpp -o -name mcpp.exe \) | head -1)
[ -n "$built" ] || { echo "::error::mcpp did not build from $MCPP_SOURCE_REF"; exit 1; }
echo "$(cd "$(dirname "$built")" && pwd)" >> "$GITHUB_PATH"
echo "under review: $("$built" --version) (from $MCPP_SOURCE_REF)"
fi

- name: Select the toolchain
run: |
spec='${{ matrix.toolchain }}'
case "$spec" in
msvc*) mcpp toolchain default msvc ;;
*) mcpp toolchain install "${spec%@*}" "${spec#*@}"
mcpp toolchain default "$spec" ;;
esac

- name: Tests
run: |
profile='${{ matrix.profile }}'
mcpp test --profile "$profile" 2>&1 | tee tests.log
for name in platform_test fs_test process_test ipc_test dirs_terminal_test linux_test; do
grep -q "^$name \.\.\. ok" tests.log || { echo "::error::$name did not run or did not pass"; exit 1; }
done

- name: The compile-time constants of a native target (R3)
run: ( cd checks/constants && mcpp build ) || { echo "::error::a native constant does not hold"; exit 1; }

- name: A platform module is a link error outside its platform, and links in a discarded branch (R5)
run: |
( cd checks/discarded && mcpp build ) || { echo "::error::a discarded use of a platform module did not link"; exit 1; }
if ( cd checks/misuse && mcpp build ) > misuse.log 2>&1; then
cat misuse.log
echo "::error::a platform module used outside its platform linked"
exit 1
fi
grep -Eiq "undefined|unresolved" misuse.log || { cat misuse.log; echo "::error::the misuse failed for another reason than an undefined name"; exit 1; }
echo " ok the misuse fails at the link, naming what is undefined"

# ── THE TESTS AS OK IMAGES (`<arch>-openkal`, openkal SPEC clause 12) ──────
#
# The same five suites, built once on Linux for both architectures and run
# through okrun on four systems: `os::host()` is known only when an image is
# loaded, the conventions follow it, and a test that starts copies of itself
# starts the loader and the image (`os::env::self_command`).
images:
name: tests as ok images (built once)
runs-on: ubuntu-24.04
timeout-minutes: 120
defaults:
run:
shell: bash
steps:
- uses: actions/checkout@v4
- name: Install xlings
run: |
curl -fsSL https://raw.githubusercontent.com/openxlings/xlings/main/tools/other/quick_install.sh \
| bash -s "$XLINGS_VERSION"
echo "$HOME/.xlings/subos/current/bin" >> "$GITHUB_PATH"
- name: The mcpp that has the target
run: |
xlings update > /dev/null 2>&1 || true
xlings install mcpp -y -g
mcpp self config --mirror GLOBAL
src="$RUNNER_TEMP/mcpp-src"
git clone --quiet --depth 1 --branch "$MCPP_SOURCE_REF" https://github.com/mcpp-community/mcpp.git "$src"
rm -f "$src/.xlings.json"
( cd "$src" && mcpp build --release )
built=$(find "$src/target" -type f -name mcpp | head -1)
[ -n "$built" ] || { echo "::error::mcpp did not build"; exit 1; }
echo "$(cd "$(dirname "$built")" && pwd)" >> "$GITHUB_PATH"
- name: The suites, run here and built for the other architecture
run: |
set -euo pipefail
mcpp test --target x86_64-openkal 2>&1 | tee tests.log
for name in platform_test fs_test process_test ipc_test dirs_terminal_test linux_test; do
grep -q "^$name \.\.\. ok" tests.log || { echo "::error::$name did not pass as an image"; exit 1; }
done
mcpp test --target aarch64-openkal --no-run
for arch in x86_64 aarch64; do
mkdir -p "out/$arch"
cp target/"$arch"-openkal/*/bin/*_test.oke "out/$arch/"
done
(cd out && sha256sum */* | tee SHA256SUMS)
- uses: actions/upload-artifact@v4
with: { name: os-test-images, path: out }

images-run:
name: tests as ok images on ${{ matrix.host }}
needs: images
runs-on: ${{ matrix.os }}
timeout-minutes: 45
strategy:
fail-fast: false
matrix:
include:
- { host: linux-x86_64, os: ubuntu-24.04, arch: x86_64 }
- { host: linux-aarch64, os: ubuntu-24.04-arm, arch: aarch64 }
- { host: macos-arm64, os: macos-15, arch: aarch64 }
- { host: windows-x86_64, os: windows-2022, arch: x86_64 }
defaults:
run:
shell: bash
steps:
- uses: actions/download-artifact@v4
with: { name: os-test-images, path: out }
- name: Install xlings (Unix)
if: runner.os != 'Windows'
run: |
curl -fsSL https://raw.githubusercontent.com/openxlings/xlings/main/tools/other/quick_install.sh \
| bash -s "$XLINGS_VERSION"
echo "$HOME/.xlings/subos/current/bin" >> "$GITHUB_PATH"
- name: Install xlings (Windows)
if: runner.os == 'Windows'
shell: pwsh
run: |
irm https://d2learn.org/xlings-install.ps1.txt | iex
"$env:USERPROFILE\.xlings\subos\current\bin" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append
- name: okrun, built here
run: |
xlings install mcpp -y -g
mcpp self config --mirror GLOBAL
mcpp toolchain install llvm 23.1.3
mcpp toolchain default [email protected]
git clone --quiet --depth 1 --branch openkal-0.17.0 https://github.com/mcpplibs/openkal-image.git "$RUNNER_TEMP/oi"
( cd "$RUNNER_TEMP/oi/tools" && mcpp build --release )
okrun=$(find "$RUNNER_TEMP/oi/target" -path '*bin*' \( -name okrun -o -name okrun.exe \) -type f | head -1)
[ -n "$okrun" ] || { echo "::error::okrun did not build"; exit 1; }
echo "OKRUN=$okrun" >> "$GITHUB_ENV"
- name: The same bytes, every suite
run: |
set -euo pipefail
a='${{ matrix.arch }}'
if command -v sha256sum > /dev/null; then (cd out && sha256sum -c SHA256SUMS)
else (cd out && shasum -a 256 -c SHA256SUMS); fi
failed=0
for t in out/"$a"/*_test.oke; do
echo "::group::$t"
if "$OKRUN" "$t"; then echo " ok $t"; else echo "::error::$t"; failed=1; fi
echo "::endgroup::"
done
exit $failed
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
target/
/target/
/checks/*/target/
compile_commands.json
*.log
mcpp.lock

96 changes: 95 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,97 @@
# mcpplibs.os

A C++ operating-system library over openkal. The first version is under review.
A C++ operating-system library over [openkal](https://github.com/mcpplibs/openkal):
processes, files, the environment, terminals, conventional directories and local IPC,
with compile-time platform constants and a few platform modules.

```toml
[dependencies]
os = { namespace = "mcpplibs", version = "0.1.0" }
```

```cpp
import std;
import mcpplibs.os;
namespace os = mcpplibs::os;

int main() {
auto r = os::process::run({ .program = "git", .args = { "--version" } });
if (r) std::print("{}", r->out);
if constexpr (os::is_windows) { /* compiled only for Windows */ }
}
```

## Layers

| Layer | What it is | Where it is |
|---|---|---|
| openkal | the kernel ABI: minimal composable atoms, one implementation per system | `mcpplibs/openkal`, `openkal-<os>` |
| **mcpplibs.os** | composition and conventions: PATH search, atomic and non-replacing publication, process trees, directory conventions, colour policy, local IPC | this package |
| a program | its domain | — |

The kernel layer is openkal and only openkal. Native code in this package serves only
what is not a kernel question: the machine beneath the system (`machine`), and the platform
modules.

## Modules

| Module | Contents |
|---|---|
| `mcpplibs.os.platform` | `PLATFORM`, `ARCH`, `is_linux` / `is_macos` / `is_windows` / `is_posix`, `exe_suffix`, `path_list_separator`; `host()`, a constant expression on a native target |
| `mcpplibs.os.error` | `errc` (openkal's closed set of conditions), `error`, `result<T>` |
| `mcpplibs.os.env` | variables, arguments, the program's own image, PATH search with PATHEXT |
| `mcpplibs.os.fs` | `write_atomic`, `publish` (no replace), `caps`, `lock`, links, `set_executable`, `stamp_of`, `identity_of`, `locate`, `absolute`, `names_a_place` |
| `mcpplibs.os.process` | `spawn`, `run`, pipes, output onto this program's error output, units and `end_unit`, bound lifetime, bounded waits and reads; `self`, `describe`, `alive` |
| `mcpplibs.os.interrupt` | `requested`, `wait`, `end_as_requested` |
| `mcpplibs.os.stdio` | the three streams as bytes |
| `mcpplibs.os.terminal` | `interactive`, `size`, `sequences`, `color`, `raw_mode` |
| `mcpplibs.os.dirs` | `home`, `config`, `data`, `state`, `cache`, `runtime`, `temp` |
| `mcpplibs.os.ipc` | a listener and a connection at a name in a directory; `single_instance` |
| `mcpplibs.os.net` | loopback TCP |
| `mcpplibs.os.machine` | the machine's architecture (through Rosetta and WoW64), memory |
| `mcpplibs.os.random` | bytes from the system's source of unpredictable bytes; `hex` |
| `mcpplibs.os.linux` / `.macos` / `.windows` / `.posix` | platform modules: declared on every target, defined only on their own |

## Rules

- **R0.** What std does, this package does not repeat.
- **R1.** A portable facility exists once, in `os::<area>`.
- **R2.** A platform module holds only what has no portable meaning. Each of its declarations
says why.
- **R3.** Compile-time platform constants are first-class. `host()` names the running system:
- on a native target it equals `PLATFORM` and is a constant expression;
- in an image (`<arch>-openkal`) it is an ordinary function, and using it in a constant
expression is a compile error.
- **R4.** A native handle does not appear in a portable type.
- **R5.** A platform module is declared on every target and defined only on its own. A call
outside `if constexpr` for that platform is a link error. The same call in a discarded branch
is not an odr-use, so it links. CI asserts both.
- **R6.** Where openkal is not in its shared form, this package's resources do not cross a
shared-object boundary.

Interface units import `std` and contain no system header and no macro. Implementation units
on openkal import only `openkal.*`. The Windows units declare the functions they call
themselves (`src/windows/win32.h`).

## As an ok image

Built for `<arch>-openkal` (openkal SPEC clause 12), a program over this library
is one image per architecture that `okrun` runs on Linux, macOS and Windows.
`os::PLATFORM` is `platform::openkal` and `os::is_image` is true; `os::host()`
is an ordinary function there, answered when the image is loaded, and
`os::conventions()` follows it; `exe_suffix` and `path_list_separator` are not
provided, so code that reads them is a compile error rather than a wrong answer
on another system. `os::env::loader()` names the program that runs the image,
and `os::env::self_command()` is what starts the same program again --- a
loader and an image, or the image alone when it is built for its system. A
name's spelling is the host's as well: `os::fs::absolute()` and
`os::fs::names_a_place()` read `C:\x` and `bin\x` as Windows does when the
image runs there, where the standard library inside an image reads names as
POSIX does. The
image carries its C library and C++ run-time (`openkal-llvm-runtime`); the
tests are built as images in CI and run through okrun on four systems, and
`checks/constants` holds the compile-time facts of a native target.

## License

Apache-2.0
10 changes: 10 additions & 0 deletions checks/constants/mcpp.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# The compile-time constants of a native target (R3; part 2 E29), checked when
# the program is compiled. An ok image has neither `exe_suffix' nor a constant
# `host()', so these facts are a build of their own on the native rows rather
# than part of tests/platform_test.cpp, which is also built as an image.
[package]
name = "os-check-constants"
version = "0.1.0"

[dependencies]
os = { path = "../.." }
17 changes: 17 additions & 0 deletions checks/constants/src/main.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// Built on every native row: each fact is a constant expression there.
import std;
import mcpplibs.os;

namespace os = mcpplibs::os;

static_assert(os::host() == os::PLATFORM);
static_assert(os::is_linux + os::is_macos + os::is_windows == 1);
static_assert(!os::is_image);
static_assert(os::exe_suffix == (os::is_windows ? ".exe" : ""));
static_assert(os::path_list_separator == (os::is_windows ? ';' : ':'));
static_assert(os::conventions_of(os::host()).exe_suffix == os::exe_suffix);

int main() {
if constexpr (os::host() == os::platform::windows) return os::path_list_separator == ';' ? 0 : 1;
else return os::path_list_separator == ':' ? 0 : 1;
}
6 changes: 6 additions & 0 deletions checks/discarded/mcpp.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
[package]
name = "os-check-discarded"
version = "0.1.0"

[dependencies]
os = { path = "../.." }
17 changes: 17 additions & 0 deletions checks/discarded/src/main.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// R5: the same calls in branches `if constexpr' discards are not odr-uses
// ([basic.def.odr]), so this program links on every system.
import std;
import mcpplibs.os;
import mcpplibs.os.linux;
import mcpplibs.os.macos;
import mcpplibs.os.windows;

namespace os = mcpplibs::os;

int main() {
int n = 0;
if constexpr (os::is_linux) n += static_cast<int>(os::linux::translator().has_value());
if constexpr (os::is_macos) n += static_cast<int>(os::macos::translated());
if constexpr (os::is_windows) n += static_cast<int>(os::windows::elevated());
return n >= 0 ? 0 : 1;
}
6 changes: 6 additions & 0 deletions checks/misuse/mcpp.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
[package]
name = "os-check-misuse"
version = "0.1.0"

[dependencies]
os = { path = "../.." }
Loading
Loading