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
11 changes: 10 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ C library.

```toml
[dependencies]
openkal-llvm-runtime = "0.19.0"
openkal-llvm-runtime = "0.19.1"
```

> **Engine floor (mcpp 2026.11.2.1):** 0.17.0 is built over openkal-musl 0.26.0,
Expand Down Expand Up @@ -330,6 +330,15 @@ grants against raw file truncation. The runtime implementation is unchanged.

## OpenKal 0.24 dependency group

Runtime 0.19.1 reads a name beneath a volume, `X:/...`, as the C library beneath
does: `X:` is the root name and `/` the root directory, so the working directory on
a system with volumes is absolute and `absolute`, `canonical` and `relative` keep
it (openkal-llvm-runtime#64). `X:` without a separator stays an ordinary name.
Both probes (`examples/cxx`, `examples/image-cxx`) state the decomposition, the
append and the working-directory results; without the change four of them fail on
Linux and the working-directory results fail on Windows. The dependency on
openkal-musl is the compatible range `^0.28.0`.

Runtime 0.19.0 selects openkal-musl 0.28.0 and its matching OpenKal 0.24
implementations. The C++ runtime surface and allocator feature selection
remain unchanged.
26 changes: 26 additions & 0 deletions examples/cxx/src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,32 @@ int main() {
check(same, "a string grows past the allocator's own mappings");
}

// --- names beneath a volume (openkal-llvm-runtime#64) -------------------
//
// The C library names a file on a system with volumes `D:/...` and takes
// `X:/` as a root. The same name is absolute to std::filesystem, and the
// working directory is absolute on every system.
{
namespace fs = std::filesystem;
const fs::path v = "D:/a/b.txt";
check(v.is_absolute() && v.root_name() == "D:" && v.root_directory() == "/", "`D:/a/b.txt' has a root name and a root directory");
check(v.relative_path() == "a/b.txt" && v.parent_path() == "D:/a" && v.filename() == "b.txt", "and decomposes beneath it");
std::vector<std::string> forward, backward;
for (const auto& e : v) forward.push_back(e.string());
for (auto it = v.end(); it != v.begin();) backward.insert(backward.begin(), (--it)->string());
check(forward == std::vector<std::string>{"D:", "/", "a", "b.txt"} && backward == forward, "its elements are the same read either way");
check(!fs::path("D:").is_absolute() && fs::path("D:").root_name().empty(), "`D:' without a separator is an ordinary name");
check(!fs::path("D:x").is_absolute(), "`D:x' is relative");
check((fs::path("x") / "D:/y") == "D:/y" && fs::path("x").append(std::string("D:/y")) == "D:/y", "appending an absolute volume name replaces the path");
check(fs::path("D:/a/b").lexically_relative("D:/a") == "b" && fs::path("/a/b").is_absolute(), "a name relative to a volume, and `/' unchanged");
std::error_code cwd_ec;
const fs::path cwd = fs::current_path(cwd_ec);
check(!cwd_ec && cwd.is_absolute(), "the working directory is absolute");
check(fs::absolute(cwd, cwd_ec) == cwd && !cwd_ec, "absolute() of it is itself");
const fs::path can = fs::canonical(cwd, cwd_ec);
check(!cwd_ec && can.is_absolute(), "canonical() of it succeeds");
}

// --- std::filesystem, which is the C++ face of openkal.fs ---------------

namespace fs = std::filesystem;
Expand Down
26 changes: 26 additions & 0 deletions examples/image-cxx/src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,32 @@ int main(int argc, char** argv) {

check(std::format("{:>6.2f}", 3.14159) == " 3.14", "formatting a floating-point value");

// --- names beneath a volume (openkal-llvm-runtime#64) -------------------
//
// The C library names a file on a system with volumes `D:/...` and takes
// `X:/` as a root. The same name is absolute to std::filesystem, and the
// working directory is absolute on every system.
{
namespace fs = std::filesystem;
const fs::path v = "D:/a/b.txt";
check(v.is_absolute() && v.root_name() == "D:" && v.root_directory() == "/", "`D:/a/b.txt' has a root name and a root directory");
check(v.relative_path() == "a/b.txt" && v.parent_path() == "D:/a" && v.filename() == "b.txt", "and decomposes beneath it");
std::vector<std::string> forward, backward;
for (const auto& e : v) forward.push_back(e.string());
for (auto it = v.end(); it != v.begin();) backward.insert(backward.begin(), (--it)->string());
check(forward == std::vector<std::string>{"D:", "/", "a", "b.txt"} && backward == forward, "its elements are the same read either way");
check(!fs::path("D:").is_absolute() && fs::path("D:").root_name().empty(), "`D:' without a separator is an ordinary name");
check(!fs::path("D:x").is_absolute(), "`D:x' is relative");
check((fs::path("x") / "D:/y") == "D:/y" && fs::path("x").append(std::string("D:/y")) == "D:/y", "appending an absolute volume name replaces the path");
check(fs::path("D:/a/b").lexically_relative("D:/a") == "b" && fs::path("/a/b").is_absolute(), "a name relative to a volume, and `/' unchanged");
std::error_code cwd_ec;
const fs::path cwd = fs::current_path(cwd_ec);
check(!cwd_ec && cwd.is_absolute(), "the working directory is absolute");
check(fs::absolute(cwd, cwd_ec) == cwd && !cwd_ec, "absolute() of it is itself");
const fs::path can = fs::canonical(cwd, cwd_ec);
check(!cwd_ec && can.is_absolute(), "canonical() of it succeeds");
}

std::println("-- failures: {} --", failures);
return failures ? 1 : 0;
}
19 changes: 17 additions & 2 deletions llvm/PATCHES.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,10 @@ grep -rn "openkal ─── BEGIN" llvm/

## 已替换

五处,四个文件,一个判据 —— 每一处都能填进上面那句话。
六处,五个文件,一个判据 —— 每一处都能填进上面那句话。

```sh
grep -rn "openkal ─── BEGIN" llvm/ # 10 处标记(含配对的 #else/#endif)
grep -rn "openkal ─── BEGIN" llvm/ # 30 处 BEGIN 标记
```

| 文件 | 上游按什么分派 | 平台面 | openkal 的答案 |
Expand All @@ -42,6 +42,21 @@ grep -rn "openkal ─── BEGIN" llvm/ # 10 处标记(含配对的 #else/#e
| `libunwind/src/RWMutex.hpp` | `_WIN32` | 读写锁 | pthread ⇒ musl ⇒ `kal_task_*` |
| `libunwind/src/UnwindCursor.hpp` | `_WIN32` | (无) | 整段没被用到,只是被 include |
| `compiler-rt/…/emutls.c` | `_WIN32` | 互斥 + 对齐分配 | pthread + `posix_memalign` |
| `libcxx/src/filesystem/path_parser.h` | `_LIBCPP_WIN32API` | 名字的根 | C 库的根:`/` 与 `X:/`(0.19.1) |

### `libcxx/src/filesystem/path_parser.h` 与 `port/include/__filesystem/path.h` — 卷下的名字(0.19.1)

C 库(openkal-musl)在有卷的系统上把文件写作 `D:/...`,并像对待 `/` 一样把 `X:/` 当作根
(其 `root_length`)。libc++ 只在 `_LIBCPP_WIN32API` 下识别盘符,按 POSIX 规则读 `D:/a` 时它是
相对名:工作目录的 `is_absolute()` 为假,`absolute`、`canonical`、`relative` 拼出不存在的名字
(openkal-llvm-runtime#64)。

- `path_parser.h` 的 `consumeRootName` 在 `OPENKAL` 下接受后面紧跟 `/` 的 `X:` 作为根名,正向与
反向解析都一样;不带分隔符的 `X:` 仍是普通名字,与 C 库一致。`path_parser.h` 由同目录的
`.cpp` 以引号包含,无法遮蔽,所以原地标记。
- `__filesystem/path.h` 的 `append(Source)` 在 POSIX 分支只看首字符是否为分隔符;覆盖件在
`OPENKAL` 或 `__OPENKAL__` 下改用 `path::is_absolute()` 判断,使 `path / "D:/y"` 与
`path / path("D:/y")` 结果相同。头文件按本文的约定放在 `port/include/` 覆盖,vendored 树不动。

### `libcxx/src/atomic.cpp` — `std::atomic` 的等待与唤醒

Expand Down
21 changes: 21 additions & 0 deletions llvm/libcxx/src/filesystem/path_parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -329,6 +329,27 @@ struct PathParser {
return Ret;
if (PosPtr Ret = consumeNetworkRoot(P, End))
return Ret;
// ─── openkal ─── BEGIN ────────────────────────────────────────────────────────
#elif defined(OPENKAL)
// openkal: A VOLUME IS A ROOT NAME WHEN A SEPARATOR FOLLOWS IT.
//
// The C library beneath (openkal-musl) names a file on a system with
// volumes `D:/...`, and takes `X:/` as a root exactly as it takes `/`
// (its root_length). Read as a POSIX name, `D:/a` was relative, so
// `current_path().is_absolute()` was false and `absolute`, `canonical`
// and `relative` built names that do not exist (openkal-llvm-runtime#64).
// `D:` without a separator stays an ordinary name, as it is to the C
// library.
if (P < End) {
if (End - P >= 3 && isDriveLetter(P[0]) && P[1] == ':' && P[2] == '/')
return P + 2;
} else if (P != End) {
const PosPtr First = Path.data();
const PosPtr Last = Path.data() + Path.size();
if (P - 1 == First && P - 1 > End && P[0] == ':' && isDriveLetter(P[-1]) && P + 1 < Last && P[1] == '/')
return P - 2;
}
// ─── openkal ─── END ──────────────────────────────────────────────────────────
#endif
return nullptr;
}
Expand Down
6 changes: 3 additions & 3 deletions mcpp.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[package]
namespace = "mcpplibs"
name = "openkal-llvm-runtime"
version = "0.19.0"
version = "0.19.1"
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"]
Expand Down Expand Up @@ -230,10 +230,10 @@ cflags = ["-DDISABLE_AARCH64_FMV=1"]
# (measured on OpenSBI: every request for an arena refused, ENOMEM). A
# target's edge replaces a general one, so each states every feature.
[target.'cfg(not(os = "none"))'.dependencies]
openkal-musl = { version = "0.28.0", default-features = false, features = ["posix", "malloc-mimalloc"] }
openkal-musl = { version = "^0.28.0", default-features = false, features = ["posix", "malloc-mimalloc"] }

[target.'cfg(os = "none")'.dependencies]
openkal-musl = { version = "0.28.0", default-features = false, features = ["posix", "malloc-mallocng"] }
openkal-musl = { version = "^0.28.0", default-features = false, features = ["posix", "malloc-mallocng"] }

[build]

Expand Down
Loading
Loading