From 2fa10d75f520b8529781110df13697b873151246 Mon Sep 17 00:00:00 2001 From: speak-agent Date: Sat, 29 Aug 2026 01:15:38 +0800 Subject: [PATCH 1/3] 0.4.0 --- repin the C library, which no longer answers a question with another one's answer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit openkal-musl 0.7.0. Nothing in this package changes: it names the C library and the C library named the specification, so what moves is one line. What the consumers of this package get is measured rather than asserted. The same `std::filesystem` program, run over this stack and over the host's own toolchain, now agrees row for row where it did not: stat on a node naming another was a link, is what the name refers to is_regular_file on the same was false for bytes it could read file_size on the same was refused exists on one naming nothing was true is_directory in an enumeration was false for one naming a directory copy of a tree holding one was ENOSYS; one such node made a whole tree uncopyable readlink was ENOSYS equivalent of two different files was TRUE, with no error and `signal(SIGABRT, …)`, which any terminal library, death test or crash reporter performs before it does anything else, no longer ends the program. --- mcpp.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mcpp.toml b/mcpp.toml index 5134d4c1..fb552c9e 100644 --- a/mcpp.toml +++ b/mcpp.toml @@ -1,7 +1,7 @@ [package] namespace = "mcpplibs" name = "openkal-llvm-runtime" -version = "0.3.1" +version = "0.4.0" description = "LLVM's C++ runtime libraries — libc++, libc++abi and libunwind — configured for openkal-musl rather than for a host C library." license = "Apache-2.0" authors = ["mcpplibs"] @@ -208,7 +208,7 @@ sources = [ cflags = ["-DDISABLE_AARCH64_FMV=1"] [dependencies] -openkal-musl = "0.6.0" +openkal-musl = "0.7.0" [build] cxx_standard = "c++23" From c2b8381da9a55f827ca53204b12a51196bcf198c Mon Sep 17 00:00:00 2001 From: speak-agent Date: Sat, 29 Aug 2026 01:39:19 +0800 Subject: [PATCH 2/3] README: the versions it names are the versions that exist Every README here opens by showing what a program writes in its manifest, which is the first thing a reader copies and the last thing anyone edits. These lines had drifted --- the specification's own README asked for a version four minor releases old --- and nothing checked them. `openkal/tools/check-readme-versions.sh` now does. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index cac0985f..2e159ef7 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ C library. ```toml [dependencies] -openkal-llvm-runtime = "0.3.1" +openkal-llvm-runtime = "0.4.0" ``` A C++ standard library is not portable in the way a program is. It is From cbf17933099ebc1456fc2078b7fd6b456e2e8d76 Mon Sep 17 00:00:00 2001 From: sunrisepeak Date: Sat, 29 Aug 2026 02:13:00 +0800 Subject: [PATCH 3/3] test: the operation that was a refusal and is now an operation examples/cxx asserted that creating a symbolic link is refused. openkal 0.9 added kal_fs_link_create, openkal-musl 0.7 answers symlinkat with it, and the refusal stopped arriving -- so this failed, which is the good case. An assertion that had merely tolerated both answers would have made the arrival of the operation invisible here, and this file is the only place in the ecosystem where a C++ standard library exercises it. The link is now created, read back, and asked about both ways: an enquiry that does not resolve reports the link, one that resolves reports the file, and the size read through it is the file's. Writing that produced a failure of its own worth recording. The target was first spelled `dir / "a.txt"', which looks more careful than `"a.txt"' and is wrong: a link's content is resolved relative to the directory holding the link, so it named cxx-probe.d/cxx-probe.d/a.txt and dangled. Three assertions failed against a port that was answering correctly. --- examples/cxx/src/main.cpp | 52 ++++++++++++++++++++++++++++++++------- 1 file changed, 43 insertions(+), 9 deletions(-) diff --git a/examples/cxx/src/main.cpp b/examples/cxx/src/main.cpp index ee2b92ab..f0bf52b8 100644 --- a/examples/cxx/src/main.cpp +++ b/examples/cxx/src/main.cpp @@ -94,26 +94,60 @@ int main() { check(fs::file_size(dir / "b.txt", ec) == 10 && !ec, "and the copy has the same size"); - // ⭐⭐ AND THE TWO OPERATIONS openkal HAS NO ATOM FOR, CHECKED AS REFUSALS. + // ⭐⭐ AND THE OPERATION openkal HAS NO ATOM FOR, CHECKED AS A REFUSAL. // - // `kal_node_info` carries a boolean `writable` and not a mode word, and - // SURFACE.txt has no operation that creates a symbolic link. openkal-musl - // therefore refuses `chmod` and `symlink` rather than succeeding and - // reporting something else afterwards --- and a refusal that arrives as a + // `kal_node_info` carries a boolean `writable` and not a mode word, so + // openkal-musl refuses `chmod` rather than succeeding and reporting + // something else afterwards --- and a refusal that arrives as a // `std::error_code` is what a C++ caller can act upon. // // ⚠️ THIS IS THE HALF THAT WOULD BE OMITTED. A probe checking only that the // supported operations work would pass just as well for a port that - // silently accepted these two, which is the outcome the report + // silently accepted it, which is the outcome the report // (openkal-linux#13) described as "expected 0600, got 0777". ec.clear(); fs::permissions(dir / "a.txt", fs::perms::owner_read, ec); check(static_cast(ec), "changing permission bits is refused, not ignored"); + // ⭐⭐ AND THE ONE THAT WAS A REFUSAL AND IS NOW AN OPERATION. + // + // This block read `create_symlink ... check(ec)` --- a link was refused, + // and the refusal was the assertion. openkal 0.9 added `kal_fs_link_create` + // and `kal_fs_link_read`, openkal-musl 0.7 answers `symlinkat` and + // `readlinkat` with them, and the refusal stopped arriving. + // + // ⚠️ A TEST THAT ASSERTS A LIMITATION BECOMES FALSE WHEN THE LIMITATION IS + // LIFTED, AND IT FAILS RATHER THAN GOING QUIET. That is the good case and + // it is why the assertion was written this way round: had it merely + // tolerated both answers, the arrival of the operation would have been + // invisible here, and this file is the only place in the ecosystem where a + // C++ standard library exercises it. + // ⚠️ THE TARGET IS `a.txt' AND NOT `dir / "a.txt"'. A link's content is + // resolved relative to the directory HOLDING THE LINK, not to the working + // directory --- so the second spelling, which looks more careful, produces + // `cxx-probe.d/cxx-probe.d/a.txt' and a dangling link. It was written that + // way here first, and the three assertions below failed against a port that + // was answering correctly. ec.clear(); - fs::create_symlink(dir / "a.txt", dir / "link", ec); - check(static_cast(ec), "creating a symbolic link is refused, not ignored"); - + fs::create_symlink("a.txt", dir / "link", ec); + check(!ec, "a symbolic link is created"); + check(fs::read_symlink(dir / "link", ec) == "a.txt" && !ec, + "and reading it gives back the name it was made from"); + + // The distinction the link exists to make: an enquiry that resolves and one + // that does not answer about different nodes. A port that conflated them + // reported every link as the file it points at, which is what made a tree + // containing one uncopyable. + check(fs::is_symlink(fs::symlink_status(dir / "link", ec)) && !ec, + "an enquiry that does not resolve reports the link itself"); + check(fs::is_regular_file(fs::status(dir / "link", ec)) && !ec, + "and one that resolves reports the file it names"); + check(fs::file_size(dir / "link", ec) == 10 && !ec, + "so the size read through it is the file's"); + + // ⭐ AND THE TREE IS STILL WALKABLE. `remove_all` recurses, and a directory + // holding a link is the case where resolving during the walk removes the + // wrong node or loops. fs::remove_all(dir, ec); check(!fs::exists(dir, ec), "the directory and its contents are removed");