From d312675a8919ff9d3ac362e68a7c8dbadfc8727f Mon Sep 17 00:00:00 2001 From: tz12323 <2760686250@qq.com> Date: Tue, 20 Oct 2026 13:52:23 +0800 Subject: [PATCH] fix libserial s bug on aarch64 --- .agents/docs/2026-10-03-add-libserial-plan.md | 32 ++++++++++ pkgs/c/compat.libserial.lua | 59 +++++++++++++++++-- .../libserial/0001-guard-musl-max-baud.patch | 13 ++++ 3 files changed, 99 insertions(+), 5 deletions(-) create mode 100644 pkgs/c/patches/libserial/0001-guard-musl-max-baud.patch diff --git a/.agents/docs/2026-10-03-add-libserial-plan.md b/.agents/docs/2026-10-03-add-libserial-plan.md index 2933e54a..d82cdc38 100644 --- a/.agents/docs/2026-10-03-add-libserial-plan.md +++ b/.agents/docs/2026-10-03-add-libserial-plan.md @@ -141,3 +141,35 @@ libstdc++ 仍保留(仅弃用告警),libc++ 在 C++20 及以上直接删掉,于 **另**:原分支合并 main 时把 CHANGELOG 中 `openkal-llvm-runtime 0.15.4` 与 `openkal-linux 0.16.1 / openkal-musl 0.20.1` 两条误删,已按 main 恢复。 + +## 11. 维护者追加(2026-10-20):aarch64 musl 的 `__MAX_BAUD` + +**现象**:aarch64-linux-musl 配合严格 Clang 告警配置时, +`src/libserial/SerialPortConstants.h` 的 `#if __MAX_BAUD > B2000000` 报 +`'__MAX_BAUD' is not defined, evaluates to 0 [-Werror,-Wundef]`。 + +**根因**:`__MAX_BAUD` 是 glibc `bits/termios.h` 的私有辅助宏。musl 1.2.5 定义了 +`B2000000` 到 `B4000000`,但没有定义 `__MAX_BAUD`。上游把“该 libc 的最高波特率” +误写成所有 Linux libc 都保证的宏。 + +**补丁**:`pkgs/c/patches/libserial/0001-guard-musl-max-baud.patch` 由 git 生成, +把条件改为 `#if defined(__MAX_BAUD) && __MAX_BAUD > B2000000`。 +`compat.libserial` 的 install hook 从描述符自身路径找到补丁,并以 +`git apply` 打入解包树;应用后读取 `SerialPortConstants.h` 断言新文本确实存在, +避免 git 在仓库内发现父级 `.git` 后“Skipped patch”却仍返回成功。 + +版本资源提升为 `revision = 1`,让已经安装过 revision 0 的用户重新执行 install hook。 +install hook 同时显式导入 `xim.libxpkg.log`。 + +**验证**: + +- 纯 aarch64 musl 头 + Clang 22.1.8: + `-Wundef -Werror=undef` 对原式报上述错误,补丁式通过。 +- 用打补丁后的实际 `SerialPortConstants.h` 配合 aarch64 musl 与 libc++ 头编译, + `-Wundef -Werror=undef` 通过。 +- 清掉本包缓存后,mcpp `2026.10.1.2` 冷安装并通过 + `mcpp test -p libserial --cache off`;安装目录中的头已包含守卫,安装标记为 + `revision: 1`。 +- OpenKal 的完整 aarch64-linux-musl 图在此之前还会先停在 + `linux/serial.h: file not found`;这是 OpenKal C 环境没有提供 Linux UAPI 的另一问题, + 不属于本补丁处理的 `__MAX_BAUD` 缺陷。 diff --git a/pkgs/c/compat.libserial.lua b/pkgs/c/compat.libserial.lua index 636e61cc..f87137d4 100644 --- a/pkgs/c/compat.libserial.lua +++ b/pkgs/c/compat.libserial.lua @@ -18,7 +18,7 @@ -- compat.libaio. (Single-platform `xpm` is why platform-version-parity stays -- quiet: it only compares platforms that both carry versions.) -- --- TWO CONSUMER-VISIBLE DEFECTS ARE FIXED HERE. The first: src/libserial/SerialPortConstants.h +-- THREE CONSUMER-VISIBLE DEFECTS ARE FIXED HERE. The first: src/libserial/SerialPortConstants.h -- declares `using DataBuffer = std::vector;` but includes neither -- nor . On gcc 16.1.0 / libstdc++ this compiles only by -- accident of transitive includes — a bare consumer that opens the header first @@ -43,6 +43,15 @@ -- it needs, asserting each match count so an upstream change -- fails the install instead of silently skipping the fix. -- +-- The third: SerialPortConstants.h guards the 2-4 Mbaud Linux enum values with +-- `#if __MAX_BAUD > B2000000`. __MAX_BAUD is a glibc bits/termios.h detail; +-- musl deliberately does not define it, so strict Clang configurations (for +-- example -Wundef -Werror) reject the public header on aarch64-linux-musl. +-- The checked-in patch pkgs/c/patches/libserial/0001-guard-musl-max-baud.patch +-- tests the macro before comparing it. install() applies it with `git apply` +-- before the result_of rewrite, and fails loudly when the upstream context no +-- longer matches instead of shipping an unpatched payload. +-- -- NO FEATURE. The three TUs are the whole library; upstream's optional parts -- are the GoogleTest suite (test/, its own main()), the SIP Python bindings -- (sip/) and the Doxygen docs (doxygen.conf.in) — none is an optional @@ -69,6 +78,8 @@ package = { CN = "https://gitcode.com/mcpp-res/libserial/releases/download/1.0.0/libserial-1.0.0.tar.gz", }, sha256 = "063142d6bfe08898316e9a6055f2ddeedef56de06f7cfc8dcdfecc6efabf4bdd", + -- 1: apply the musl __MAX_BAUD patch in install(). + revision = 1, }, }, }, @@ -115,14 +126,52 @@ package = { }, } +local descriptor_dir = debug.getinfo(1, "S").source:match("^@(.*)/[^/]+$") + import("xim.libxpkg.pkginfo") +import("xim.libxpkg.log") --- See the header note: the C++20-removed std::result_of in SerialPort.h. --- Patched in the unpacked tree, which is then moved into the install dir as --- its single wrap level so the `*/src` globs keep matching (compat.ftxui / --- taskflow.taskflow do the same). +-- See the header notes: apply the tracked musl __MAX_BAUD patch, fix the +-- C++20-removed std::result_of in SerialPort.h, then move the unpacked tree +-- into the install dir as its single wrap level so the `*/src` globs keep +-- matching (compat.ftxui / taskflow.taskflow do the same). function install() local wrap = "libserial-" .. pkginfo.version() + + local function quote(value) + return "'" .. tostring(value):gsub("'", "'\\''") .. "'" + end + + if not descriptor_dir then + log.error("compat.libserial: cannot locate the descriptor directory") + return false + end + local musl_patch = path.join(descriptor_dir, + "patches/libserial/0001-guard-musl-max-baud.patch") + if not os.isfile(musl_patch) then + log.error("compat.libserial: patch file not found: %s", musl_patch) + return false + end + -- The unpacked payload lives under this checkout's ignored .mcpp/ tree in + -- local tests. Without an explicit non-repository git-dir, git discovers + -- mcpp-index's .git and silently skips the ignored target ("Skipped + -- patch"). A nonexistent git-dir keeps `git apply` in plain-file mode. + local apply_command = "git -C " .. quote(wrap) + .. " --git-dir=/__mcpp_no_git_dir__ apply --whitespace=nowarn " + .. quote(musl_patch) + local applied, apply_result = pcall(os.exec, apply_command) + if not applied or not apply_result then + log.error("compat.libserial: failed to apply %s", musl_patch) + return false + end + local constants = path.join(wrap, "src/libserial/SerialPortConstants.h") + local constants_text = io.readfile(constants) + local patched_marker = "#if defined(__MAX_BAUD) && __MAX_BAUD > B2000000" + if not constants_text or not constants_text:find(patched_marker, 1, true) then + log.error("compat.libserial: patch did not reach %s", constants) + return false + end + local function patch(relative, before, after, expected) local source = path.join(wrap, relative) local content = io.readfile(source) diff --git a/pkgs/c/patches/libserial/0001-guard-musl-max-baud.patch b/pkgs/c/patches/libserial/0001-guard-musl-max-baud.patch new file mode 100644 index 00000000..a0cc68b5 --- /dev/null +++ b/pkgs/c/patches/libserial/0001-guard-musl-max-baud.patch @@ -0,0 +1,13 @@ +diff --git a/src/libserial/SerialPortConstants.h b/src/libserial/SerialPortConstants.h +index 4f05bd5..c75ee67 100644 +--- a/src/libserial/SerialPortConstants.h ++++ b/src/libserial/SerialPortConstants.h +@@ -216,7 +216,7 @@ namespace LibSerial + BAUD_1000000 = B1000000, + BAUD_1152000 = B1152000, + BAUD_1500000 = B1500000, +-#if __MAX_BAUD > B2000000 ++#if defined(__MAX_BAUD) && __MAX_BAUD > B2000000 + BAUD_2000000 = B2000000, + BAUD_2500000 = B2500000, + BAUD_3000000 = B3000000,