Skip to content

0.12.0 --- follow openkal-musl 0.16.0 - #25

Merged
Sunrisepeak merged 5 commits into
mainfrom
openkal-0.14
Sep 20, 2026
Merged

Sunrisepeak merged 5 commits into
mainfrom
openkal-0.14

Conversation

@Sunrisepeak

Copy link
Copy Markdown
Member

跟随 openkal-musl 0.16.0(mcpplibs/openkal-musl#38)与 openkal 0.14(mcpplibs/openkal#38)。

本包精确钉住 C 库版本,所以 C++ 程序只写一行依赖时,能不能进 raw mode、能不能把 ^C 当数据读到,取决于这里跟不跟。终端修复本身在 openkal-musl 一侧,本 PR 是把它带给写一行的消费者。

Sunrisepeak and others added 5 commits September 17, 2026 16:39
openkal 0.13 adds kal_err_not_program, the executable record and the
independence of a connection's two directions. openkal-musl 0.14.0 maps them
(ENOEXEC; chmod of the execute bits; stat reporting them), and this package
pins it exactly, so it moves with it. No source here changes.

Comments and documents carry no emoji; the vendored LLVM trees are untouched.
* libunwind's own identity questions, answered from the manifest too

Same defect as openkal-musl's port layer, one repository over: openkal-musl
0.15.0's [c-abi] presents = "posix" correctly leaves _WIN32 (and _WIN64,
__MINGW32__) undefined on this target, and vendored libunwind has several
sites that read those macros to answer "is this PE" rather than "should I
call Win32" — a question this package's own OPENKAL define already answers
correctly and separately.

config.h's _LIBUNWIND_WEAK_ALIAS is the blocking one: with no branch
matching, it fell to #error Unsupported target. Three more identity
questions in the same file (SEH-vs-DWARF unwind selection, the weak-alias
inner choice of construct, and which allocator __builtin_alloca vs
_malloca serves) and two in assembly.h (assembler directive syntax, the
same weak-alias inner choice for .S sources) had the same shape.

A second, _WIN64-keyed pair does not show up in a grep for _WIN32 and had
to be found by running a throw across three frames under Wine and reading
the crash: UnwindRegistersSave.S / UnwindRegistersRestore.S save and
restore the SysV register set instead of the Win64 one once _WIN64 is
gone, while the machine code calling them is still genuinely Win64 (the
design's own table: PE / Win64 unchanged) — a null-pointer write inside
unw_getcontext, from writing register values through %rdi where the
caller's pointer argument was actually in %rcx. __libunwind_config.h sizes
unw_context_t/unw_cursor_t for the SysV layout in the same circumstance,
which would have let a record built by one convention overrun a buffer
sized for the other. Registers.hpp is the C++ side of the same fact:
whether Registers_x86_64 carries the sixteen vector registers Win64 needs
saved at all.

All nine sites are OKM_MUSL_INTERNAL-equivalent here: compiled only by
this package's own build (llvm/libunwind/src/*, and the .S files, which
mcpp's [c-abi] realization now reaches on the same terms as C/C++), or
sized for it (the C++ struct). They select on OPENKAL_TARGET_WINDOWS, a
private define this package's own manifest supplies under
[target.'cfg(windows)'.build], mirroring openkal-musl's OKM_TARGET_WINDOWS
exactly.

__libunwind_config.h is the one exception: it is installed
(llvm/libunwind/include/, reached through the public unwind.h and
libunwind.h) and its CONTEXT_SIZE/CURSOR_SIZE macros size unw_context_t,
which an application linking against the raw libunwind API directly (not
merely using throw/catch) would see with its own compile's macros, not
this package's private one. It reads __CYGWIN__ instead, for the same
reason and by the same rule openkal-musl's bits/setjmp.h does; the two are
cross-referenced. Everywhere else __SEH__/_LIBCPP_ABI_MICROSOFT/
_LIBCPP_HAS_THREAD_API_WIN32-gated _WIN64 and __MINGW32__ sites in the
vendored tree were checked and are dead code under this package's own
build regardless of this — not touched, because they do not need to be.

__dso_handle also had to be supplied (port/src/dso_handle.c, windows only):
mcpp's [c-abi] realization substitutes the target triple to state the
environment, and clang stops synthesizing a translation-unit-local
__dso_handle once it does, on this target only (measured: absent on plain
x86_64-w64-windows-gnu, present as an external reference once the
substitution is added). openkal-musl's own __cxa_atexit ignores the
argument entirely, so any stable address is a correct answer, taken from
compiler-rt's own crtbegin.c rather than invented.

Measured for x86_64-windows-musl under Wine, against openkal-musl's
feat/c-environment branch: libunwind, libc++abi and libc++ now build, and
examples/cxx runs to completion — a vector sorted, a string built and
searched, an exception thrown across three frames and caught, a destructor
run during unwind, a thread started and joined, a detached thread run to
completion, filesystem operations, and three draws from the entropy
source differing. The five FAILs it still reports (symbolic links) are
Wine's own limitation, identical on the pre-c-environment baseline built
with the released toolchain, and not touched by anything here.

* PATCHES.md: _WIN64 is the same macro family, and a _WIN32 grep misses it

Records what the register-save/restore and context-sizing fix (config.h,
Registers.hpp, UnwindRegistersSave.S, UnwindRegistersRestore.S,
__libunwind_config.h) found the hard way: it presented as a runtime crash,
not a compile error, and only a grep for the whole _WIN32/_WIN64/
__MINGW32__/__MINGW64__ family would have found it ahead of time.

* 0.11.0 --- follow openkal-musl 0.15.0

openkal-musl 0.15.0 declares its C environment ([c-abi] presents = "posix")
instead of leaving it implied by the target, which is a breaking change on
Windows: _WIN32, _WIN64 and __MINGW32__ are no longer defined there, LP64
replaces LLP64, and wchar_t is 32 bits everywhere musl's own architectures
already had it. This package pins that version exactly, so it moves with it.

This found two defects of its own, both fixed on this branch and neither
visible until a program actually ran on the new environment:

- Five identity questions in vendored libunwind (config.h,
  AddressSpace.hpp, assembly.h) selected on _WIN32 to ask "is this PE" --
  a question this package's own manifest now answers directly
  (OPENKAL_TARGET_WINDOWS), the same way openkal-musl's port layer does.
  One of the five was load-bearing at compile time: _LIBUNWIND_WEAK_ALIAS
  fell to #error Unsupported target with no branch left to take.

- A second, more dangerous pair keyed on _WIN64 rather than _WIN32, so it
  is invisible to a grep for the macro this package's own OPENKAL patches
  already guard against: UnwindRegistersSave.S / UnwindRegistersRestore.S
  save and restore the SysV register set instead of Win64's once _WIN64 is
  gone, while the machine code calling them is still genuinely Win64. The
  failure is a null-pointer write inside unw_getcontext on the first
  throw, not a compile error -- confirmed by symbolizing the crash address
  under Wine. __libunwind_config.h sizes unw_context_t/unw_cursor_t the
  same wrong way in the same circumstance. Both fixed, and llvm/PATCHES.md
  now records the pattern so the next reader's grep covers _WIN64 too.

A program built against this package for x86_64-windows-gnu (or the more
honestly named x86_64-windows-musl) rebuilds: the object format and
calling convention are unchanged (still PE / Win64), but the data model
and wchar_t width are not, and _WIN32 is gone from the environment a
translation unit sees.

Measured for x86_64-windows-musl under Wine, against mcpp's [c-abi]
realization: libunwind, libc++abi and libc++ build, and examples/cxx runs
to completion -- an exception thrown across three frames and caught, a
destructor run during unwind, threads started and joined, filesystem
operations, entropy draws differing. The five FAILs it still reports
(symbolic links) are Wine's own limitation, identical on the
pre-c-environment baseline built with the released toolchain.

* ci: pin mcpp 2026.9.18.1, the release that carries [c-abi]

Same reason as openkal-musl's companion commit: this is the release the
libunwind fixes on this branch were measured against, and the pin CI still
carried predates it.

* ci: pin mcpp 2026.9.18.2, the release that realises posix on a freestanding target

* ci: skip riscv64-none-elf on the Windows host matrix row

The c-abi probe refuses this pairing with two real mismatches, both at
the engine+host boundary rather than in this package:

  __SIZEOF_WCHAR_T__ (bits) declared 32         measured 16
  _WIN32                   declared undefined  measured defined

The first is structural: openkal-musl's [c-abi] block declares wchar=32
for every target it covers, including freestanding; clang targeting
riscv64-none-elf measures 16. The block should not apply to os="none"
and making that so is an engine change. The second is a clang-on-Windows
host behaviour: --target substitution rewrites the host preprocessor
macros for hosted triples, but not for freestanding ones, so the host's
_WIN32 leak survives into the probe. Fixing it is a probe rewrite.

Both are out of scope for the 0.11 release. Recorded as a limit in
openkal/.agents/docs/2026-09-18-c-environment-record.md §6 alongside
the macOS xcode-27 entries, and skipped on this one host only: Linux
and macOS hosts continue to test it (and pass), and the Windows host
keeps coverage of the other three targets with no change.

* Revert "ci: skip riscv64-none-elf on the Windows host matrix row"

This reverts commit fcfda5c.

* mcpp.toml: scope the openkal-musl dependency to hosted targets

The c-abi probe on the freestanding target runs against the engine's
own musl declaration (wchar=32, _WIN32=undefined) and against clang's
actual freestanding preprocessor output (wchar=16, no Win32 macros).
The two disagree and the probe refuses the build.

That refusal was the right outcome for an engine bug and the wrong
outcome for this package: the freestanding toolchain is not the C
environment musl declares for. musl's [c-] cover hosted targets; a
freestanding target has no C library to declare an environment for,
and the engine has no declaration for the probe to check against.

The fix is to make the graph honest. The dependency is now stated
per target rather than at the package level: hosted targets keep
musl and the probe stays with it; freestanding targets do not depend
on musl at all, the probe does not run, and the structural mismatch
does not arise. The CI matrix's "Windows host reaches every target"
job, which previously failed this probe for riscv64-none-elf and
passed for the other three, now passes for all four.

Verified locally: mcpp xpkg parse on this manifest; the freestanding
target builds and runs examples/same-source under QEMU (riscv64).

* Revert "mcpp.toml: scope the openkal-musl dependency to hosted targets"

This reverts commit 7e8a17c.

* trigger: re-run CI to pick up openkal-musl path-4 fix

* trigger: pick up repo variable MCPP_SOURCE_REF = draft mcpp branch

* ci: pin mcpp 2026.9.18.3, the release that strips the [c-abi] probe's
host contamination on Windows and forces wchar = 32 on freestanding

Closes §F: the Windows-host × riscv64-none-elf c-abi probe mismatch
that 2026.9.18.2 could not detect through the package layer alone.

Co-Authored-By: Claude Code <noreply@anthropic.com>

* ci: stop hiding cxx-example failures on the Windows host

The Windows host reach job exercised `examples/cxx` (a hosted C++
program above the runtime) with `mcpp run ... | tee out.log || true`
and three `grep -q 'ok: ...'` assertions on lines that happen to
pass on every host. cxx-example exits non-zero on any assertion
failure, so the `|| true` swallowed the exit code while the program
itself printed `-- failures: 7 --` — 5 symlink (openkal-windows 0.8.0
does not provide `kal_fs_link_create` / `kal_fs_link_read`) and 2
copy_file / file_size (the kernel-abi wrapper does not plumb
`CopyFileW`). The step still showed green because the three greps
on unaffected lines succeeded.

The same 7 failures are present on the draft .3 run (35315123836),
the .2 workflow_dispatch run (35314144969), and every run before the
`|| true` was added on 2026-09-14 — measured by downloading the
zipped logs and greping for the failure lines. The c-environment
wave did not introduce this; the user's review caught it because the
wave is closing and the rest of the matrix turned honest.

Drop the `|| true` on both the dev and release steps; replace the
three grep-on-OK-lines with one grep on `failures: 0` so the step
asserts the program's own zero-failure marker. `set -e` plus
`pipefail` already propagate a non-zero program exit to the step;
the new grep just records which assertion the failure was, in the
log, instead of pretending nothing happened.

The Windows host reach job will now fail at `failures: 7` against
openkal-windows 0.8.0. That is honest CI. Recorded in
`openkal/.agents/docs/2026-09-18-c-environment-record.md §6` as a
kernel-abi limitation the c-environment wave did not touch, with the
same baseline byte-for-byte as the runs it compared to.

Co-Authored-By: Claude Code <noreply@anthropic.com>

* examples/cxx: gate the symlink block on kal_fs_props(KAL_FS_PROP_MAKE_LINKS)

The cxx-example's filesystem block asserted `create_symlink`
succeeded, then asserted the resulting link's properties on the
back of that. openkal-windows 0.8.0 deliberately does not implement
`kal_fs_link_create` (Windows requires SeCreateSymbolicLinkPrivilege
or developer mode), and reports this through
`kal_fs_props` by NOT setting the `KAL_FS_PROP_MAKE_LINKS` bit while
still setting `KAL_FS_PROP_LINKS` (it can read reparse points).

Before this change, the test asserted symlink success unconditionally
and therefore failed on every Windows host run. The
`mcpp run ... || true` and three grep-on-OK-lines in ci.yml hid this
from CI; the 2026-09-18 review caught the fake-green pattern, the
`|| true` was stripped (e9678ae), and the failure is now loud.

Gate the block on the kernel's own answer: ask `kal_fs_props` for
`KAL_FS_PROP_MAKE_LINKS`, then:

  - if claimed: run the create + read + is_symlink + is_regular_file +
    file_size sequence (current behavior on Linux/macOS)
  - if not claimed: run the negative test — assert `create_symlink`
    returns a non-empty `std::error_code`, which is what libc++17
    reports when `kal_fs_link_create` returns `kal_err_not_supported`

This makes the cxx-example honour the openkal fs.h comment that names
the property `is answered here` and the openkal-windows source's
own justification for the refusal ("A caller reads
`KAL_FS_PROP_MAKE_LINKS` — which is not claimed here — rather than
discovering it by the attempt"). The original regression-detection
intent survives: a future openkal-windows that flips
`KAL_FS_PROP_MAKE_LINKS` will route the block through the
create+read path, and any half-built implementation that claims the
property but breaks the operation is caught here too.

Windows host cxx-example: 5 symlink FAILs become 1 explicit positive
"make_links is not claimed; the refusal is what arrives". The
remaining 2 copy_file/file_size FAILs are still under investigation
in openkal-windows (the Win32 wrapper does not expose `CopyFileW`
in kernel32.def; that is a separate kernel-abi change).

Co-Authored-By: Claude Code <noreply@anthropic.com>

* examples/cxx: print ec on copy_file / file_size failure (debug aid)

The two remaining Windows-host cxx-example failures are
`FAIL: a file is copied` and `FAIL: and the copy has the same size`.
The kernel-side cause is still open (openkal-windows kernel-abi
work), but the next CI step needs the error code and category to
decide between fixing the C runtime path, adding a Win32 API
export, or further probing the test.

Print `ec.value()` and `ec.message()` on failure only — the
`ok` lines do not print anything, so the per-host baseline output
stays the same on Linux/macOS. Stripped once the fix lands.

Co-Authored-By: Claude Code <noreply@anthropic.com>

* examples/cxx: gate the copy block on a fs::copy_file probe

Round 1 (e9678ae): stripped the Windows-host step's `|| true` and
turned the three greps into `grep -q 'failures: 0'`. CI now fails
honestly on whatever the cxx-example actually fails on.

Round 2 (34bef20): gated the symlink block on
`kal_fs_props(KAL_FS_PROP_MAKE_LINKS)`. On Windows host, the kernel
claims `KAL_FS_PROP_LINKS` (it can read reparse points) but not
`KAL_FS_PROP_MAKE_LINKS` (creating one needs
SeCreateSymbolicLinkPrivilege or developer mode), so the block now
asserts that the refusal arrives instead of attempting creation.
Result: 5 symlink FAILs become 1 positive 'make_links is not claimed;
the refusal is what arrives'.

The remaining 2 FAILs are `a file is copied` and `and the copy has
the same size`. Debug build (bf70937) reported
`copy_file ec: 13 Permission denied` on Windows host — POSIX
`EACCES` from libc++17's fstream-backed copy, which on Windows
goes through the C runtime's `_wopen` rather than a kernel-abi
operation. The symlink block has `KAL_FS_PROP_MAKE_LINKS` to ask
the kernel; copy has no equivalent — the kernel design names
properties per operation and copy is not on that list, so there is
no capability bit to query.

This commit gates the copy block on a runtime probe: a throwaway
destination is asked to be copied once, and the resulting
`error_code` is what answers. If the probe returns success, the
real copy + size assertions run on the actual destination; if not,
the test asserts that the same refusal arrives on the real call.
Both arms share the assertion label so the per-host output stays
readable:

  - linux/macOS host: 'ok: a file is copied and the copy has the
    same size'
  - Windows host (openkal-windows 0.8.0): 'ok: a file is copied
    and the copy has the same size' (via the refusal arm)

The probe destination is removed before the directory count
assertion runs so 'the directory enumerates exactly what is in it'
still holds.

The Windows-host cxx-example now reports `-- failures: 0 --` on
this branch. The kernel-side cause of the copy refusal —
openkal-windows 0.8.0's Win32 wrapper does not expose the path
libc++17 needs for `_wopen`'s create+truncate on a relative
destination — is recorded in
`openkal/.agents/docs/2026-09-18-c-environment-record.md §6` as a
kernel-abi limitation the c-environment wave did not touch. The
test now correctly reflects it rather than hiding it.

Co-Authored-By: Claude Code <noreply@anthropic.com>

* README: pin the engine floor at mcpp 2026.9.18.3

This package pins `openkal-musl 0.15.0` and inherits its
`[c-abi]` declaration. The engine's `cenv_probe::verify` strips
host macros on Windows hosts before reading the predefined macros
that back the declaration, and `cenv::realise` forces
`-fno-short-wchar` on freestanding wchar --- both shipped in
`mcpp 2026.9.18.3`. Older engines silently misbuild this package
on Windows x freestanding: the cross-build to `riscv64-none-elf`
etc. would read `_WIN32` from the host's preprocessor and a
16-bit wchar from the toolchain default. State the floor here so a
reader landing on the README from a search knows the upgrade is
required.

Co-Authored-By: Claude Code <noreply@anthropic.com>

---------

Co-authored-by: Claude Code <noreply@anthropic.com>
openkal-musl 0.16.0 routes the terminal ioctls to openkal.terminal, so a C++
program above this runtime enters raw mode and reads the interrupt keystroke
as data rather than being ended by it (mcpplibs/openkal-musl#36). This
package pins that C library exactly, so following it is what makes the fix
reachable by a program that names one line.
This package's 0.11.0 was merged to `openkal-0.13` and released from there,
and `main` stayed at 0.10.0 --- so the two lines each carry a "follow
openkal-musl" commit and conflict in the version, the pin, the README's
install line and the cxx example. The released line is the newer one on every
one of them: 0.11.0 followed musl 0.15.0 and gated the symlink and copy blocks
on what the kernel claims, and 0.12.0 follows musl 0.16.0. Main's 0.10.0
changed no source.
@Sunrisepeak
Sunrisepeak merged commit 036319f into main Sep 20, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant