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
14 changes: 13 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.1"
openkal-llvm-runtime = "0.19.2"
```

> **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,18 @@ grants against raw file truncation. The runtime implementation is unchanged.

## OpenKal 0.24 dependency group

Runtime 0.19.2 keeps the volume where a name is rebuilt part by part. `X:` is a
root name only with the separator after it, so `lexically_normal` appended `D:` as
an ordinary name and the root directory replaced it (`D:/a/./b` became `/a/b`), and
so did `weakly_canonical`, which ends in it, and `path("D:/a") / "/b"`. On Windows a
program over the hosted arrangement then named every file beneath no volume: a
launcher could not start its runner (mcpp-community/mcpp#889). `lexically_normal`
now begins its result with the volume and its root directory as written, and
appending a rooted name beneath a volume keeps the volume (`D:/b`), as
[fs.path.append] states it for a system with root names. Both probes state the
three results; without the change two fail on Linux and under the Windows hosted
arrangement.

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
Expand Down
9 changes: 9 additions & 0 deletions examples/cxx/src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,15 @@ int main() {
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");
// 0.19.2: a builder that appends element by element keeps the volume.
check((fs::path("D:/a") / "/b") == "D:/b" && (fs::path("D:/a") / fs::path("/b")) == "D:/b"
&& fs::path("D:/a").append(std::string("/b")) == "D:/b", "a rooted name appended beneath a volume keeps it");
check(fs::path("D:/a/./b/../c").lexically_normal() == "D:/a/c" && fs::path("D:/").lexically_normal() == "D:/",
"lexically_normal() keeps the volume");
check((fs::path("/a") / "/b") == "/b" && fs::path("/a/../b").lexically_normal() == "/b", "and `/' is unchanged");
const fs::path missing = cwd / "openkal-no-such-name" / "." / "x";
const fs::path weak = fs::weakly_canonical(missing, cwd_ec);
check(!cwd_ec && weak.is_absolute() && weak.root_name() == cwd.root_name(), "weakly_canonical() keeps the working directory's volume");
}

// --- std::filesystem, which is the C++ face of openkal.fs ---------------
Expand Down
9 changes: 9 additions & 0 deletions examples/image-cxx/src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,15 @@ int main(int argc, char** argv) {
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");
// 0.19.2: a builder that appends element by element keeps the volume.
check((fs::path("D:/a") / "/b") == "D:/b" && (fs::path("D:/a") / fs::path("/b")) == "D:/b"
&& fs::path("D:/a").append(std::string("/b")) == "D:/b", "a rooted name appended beneath a volume keeps it");
check(fs::path("D:/a/./b/../c").lexically_normal() == "D:/a/c" && fs::path("D:/").lexically_normal() == "D:/",
"lexically_normal() keeps the volume");
check((fs::path("/a") / "/b") == "/b" && fs::path("/a/../b").lexically_normal() == "/b", "and `/' is unchanged");
const fs::path missing = cwd / "openkal-no-such-name" / "." / "x";
const fs::path weak = fs::weakly_canonical(missing, cwd_ec);
check(!cwd_ec && weak.is_absolute() && weak.root_name() == cwd.root_name(), "weakly_canonical() keeps the working directory's volume");
}

std::println("-- failures: {} --", failures);
Expand Down
12 changes: 10 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/ # 30 处 BEGIN 标记
grep -rn "openkal ─── BEGIN" llvm/ # 31 处 BEGIN 标记
```

| 文件 | 上游按什么分派 | 平台面 | openkal 的答案 |
Expand All @@ -43,6 +43,7 @@ grep -rn "openkal ─── BEGIN" llvm/ # 30 处 BEGIN 标记
| `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.cpp` | (无,`/=` 的 POSIX 语义) | 规范化的结果 | 卷与根目录按原样开头(0.19.2) |

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

Expand All @@ -57,6 +58,13 @@ C 库(openkal-musl)在有卷的系统上把文件写作 `D:/...`,并像对
- `__filesystem/path.h` 的 `append(Source)` 在 POSIX 分支只看首字符是否为分隔符;覆盖件在
`OPENKAL` 或 `__OPENKAL__` 下改用 `path::is_absolute()` 判断,使 `path / "D:/y"` 与
`path / path("D:/y")` 结果相同。头文件按本文的约定放在 `port/include/` 覆盖,vendored 树不动。
- 0.19.2:`X:` 只有后跟分隔符时才是根名,而 `lexically_normal` 逐段用 `/=` 重建结果:`D:` 被当作
普通名字,随后的根目录 `/` 按 POSIX 语义替换了它,`D:/a/./b` 变成 `/a/b`;以它收尾的
`weakly_canonical` 同样丢卷。Windows 上经托管方式运行的程序因此把文件名放到了卷之外,启动器
无法启动其运行器(mcpp-community/mcpp#889)。`path.cpp` 的 `lexically_normal` 在 `OPENKAL` 下
以原样的卷与根目录开头(原地标记);覆盖件的 `operator/=` 与两个 `append` 在追加“有根目录、
无根名”的名字时保留本身的卷(`D:/a` / `/b` 为 `D:/b`),与 [fs.path.append] 对有根名系统的规定
一致。

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

Expand Down
20 changes: 20 additions & 0 deletions llvm/libcxx/src/filesystem/path.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -224,8 +224,28 @@ path path::lexically_normal() const {

path Result;
Result.__pn_.reserve(Parts.size() + NewPathSize + NeedTrailingSep);
// ─── openkal ─── BEGIN ────────────────────────────────────────────────────────
#if defined(OPENKAL)
// openkal: THE VOLUME AND ITS ROOT DIRECTORY BEGIN THE RESULT AS WRITTEN.
//
// `X:` is a root name only with the separator after it (path_parser.h), so
// appended part by part `D:` was an ordinary name and the root directory
// `/` replaced it: `D:/a/./b`.lexically_normal() was `/a/b`, and
// weakly_canonical, which ends in it, lost the volume the same way
// (0.19.2; mcpp-community/mcpp#889).
size_t First = 0;
if (Parts.size() >= 2 && Parts[1].second == PK_RootSep && has_root_name()) {
Result.__pn_ += Parts[0].first;
Result.__pn_ += Parts[1].first;
First = 2;
}
for (size_t I = First; I < Parts.size(); ++I)
Result /= Parts[I].first;
#else
for (auto& PK : Parts)
Result /= PK.first;
#endif
// ─── openkal ─── END ──────────────────────────────────────────────────────────

if (NeedTrailingSep)
Result /= PATHSTR("");
Expand Down
2 changes: 1 addition & 1 deletion 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.1"
version = "0.19.2"
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
33 changes: 33 additions & 0 deletions port/include/__filesystem/path.h
Original file line number Diff line number Diff line change
Expand Up @@ -510,7 +510,34 @@ class _LIBCPP_EXPORTED_FROM_ABI path {
return operator/=(path(__first, __last));
}
# else
# if defined(OPENKAL) || defined(__OPENKAL__)
// openkal: A NAME BENEATH A VOLUME KEEPS ITS VOLUME (0.19.2).
//
// Appending a name that has a root directory and no root name (`/b`) to a
// name beneath a volume (`D:/a`) replaces the root directory and the
// relative path, and keeps the volume: `D:/b`, as [fs.path.append] states it
// for a system with root names. Taken as the whole name, `/` lost the
// volume in every builder that appends element by element:
// `D:/a/b`.lexically_normal() was `/a/b`, and so was a name that
// weakly_canonical and relative rebuild (0.19.1 made `X:/` a root name,
// openkal-llvm-runtime#64; mcpp-community/mcpp#889 found the loss).
_LIBCPP_HIDE_FROM_ABI bool __openkal_keep_volume(const path& __p) {
if (!__p.__root_name().empty() || __p.__root_directory().empty())
return false;
const __string_view __volume = __root_name();
if (__volume.empty())
return false;
string_type __whole(__volume);
__whole += __p.__pn_;
__pn_ = std::move(__whole);
return true;
}
# endif
_LIBCPP_HIDE_FROM_ABI path& operator/=(const path& __p) {
# if defined(OPENKAL) || defined(__OPENKAL__)
if (__openkal_keep_volume(__p))
return *this;
# endif
if (__p.is_absolute()) {
__pn_ = __p.__pn_;
return *this;
Expand Down Expand Up @@ -543,6 +570,8 @@ class _LIBCPP_EXPORTED_FROM_ABI path {
__pn_ = std::move(__whole.__pn_);
return *this;
}
} else if (__openkal_keep_volume(path(__src))) {
return *this;
}
# endif
if (__source_is_absolute)
Expand All @@ -558,6 +587,10 @@ class _LIBCPP_EXPORTED_FROM_ABI path {
typedef typename iterator_traits<_InputIt>::value_type _ItVal;
static_assert(__can_convert_char<_ItVal>::value, "Must convertible");
using _CVT = _PathCVT<_ItVal>;
# if defined(OPENKAL) || defined(__OPENKAL__)
if (__first != __last && filesystem::__is_separator(*__first) && __openkal_keep_volume(path(__first, __last)))
return *this;
# endif
if (__first != __last && filesystem::__is_separator(*__first))
__pn_.clear();
else if (has_filename())
Expand Down
Loading