From 38b069a604c604b8b6ef78c8c87bc3d9ec3368dd Mon Sep 17 00:00:00 2001 From: speak-agent <248744407+speak-agent@users.noreply.github.com> Date: Fri, 21 Aug 2026 11:37:25 +0800 Subject: [PATCH] =?UTF-8?q?docs(plan):=20=E5=9B=9B=E9=A1=B9=E4=BC=98?= =?UTF-8?q?=E5=8C=96=E7=9A=84=E5=AE=9E=E6=B5=8B=E5=9B=9E=E5=A1=AB,?= =?UTF-8?q?=E5=90=AB=E4=B8=89=E5=A4=84=E6=9C=AC=E6=96=87=E5=86=99=E9=94=99?= =?UTF-8?q?=E7=9A=84=E5=9C=B0=E6=96=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - §1.9 兼容性一节写得比实际悲观:引擎早有 mentions_missing_mcpp_api,按命名 空间匹配,所以新 API 自动被覆盖。§0 的教训在本节内部又应验一次 - §2.8 测量推翻了「可能只有 aarch64 成立」:两个都成立。三条缺陷全是第二个族 才暴露的,其中「链接成功而一跑就挂」的加载地址最值得记 - §3.6 判据 2 达成且比预测更强:零 libc 的板需要自带 crt0 是内容的差别不是 接口的差别 - §4.5 ⚠️ 判据 1 在这个机制下不可达,而发现这一点花了一次实现:断言「缺失」 不可 lint。两条规则在跑过之后被收窄,都是误报率决定的 --- .../2026-08-21-baremetal-optimization-plan.md | 132 ++++++++++++++++++ 1 file changed, 132 insertions(+) diff --git a/.agents/docs/2026-08-21-baremetal-optimization-plan.md b/.agents/docs/2026-08-21-baremetal-optimization-plan.md index 4591d35c..7f89e64b 100644 --- a/.agents/docs/2026-08-21-baremetal-optimization-plan.md +++ b/.agents/docs/2026-08-21-baremetal-optimization-plan.md @@ -1,5 +1,9 @@ # 裸机方向的优化方案 +⭐ **全部实施完毕(2026-08-21)。** 每一节末尾新增「已实施」小节,记录实测结果 +与本文写错的地方。⚠️ 其中 §4 的判据 1 **被机制本身否掉**,而否掉它的正是尝试 +实现它的过程。 + 2026-08-21。本文为 `2026-08-21-baremetal-ecosystem-assessment.md` 列出的四项优先事项给出 可执行方案。每项包含:成因(读码得出)、设计、实施步骤、判据、依赖与刻意不做的事。 @@ -143,6 +147,36 @@ motivating case(openarch 模板)不构成问题,它本来就 pin 了近期版本 * **不做严重级别分层(note/warn)。** 一个级别不够用之前不加第二个。 * **不做「警告即失败」开关。** 那是消费者的策略,不是引擎的。 +### 1.9 已实施(mcpp 2026.8.21.2) + +三个设计判断都成立,而**兼容性一节写得比实际更悲观**。 + +⭐ **§1.3 说用了 `mcpp::warning` 的包在老引擎上「失败形态是 clang 的 +『no member named』而不是 mcpp 的诊断」。错了 —— 引擎早有那个机制。** +`mentions_missing_mcpp_api` 按**命名空间 `'mcpp'`** 匹配,所以新 API 自动被它 +覆盖。实测(旧引擎 2026.8.20.3): + +``` +error: 'warning' is not a member of 'mcpp' + The `mcpp` build module this engine bundles does not have that name. + Either the package was written for a newer mcpp (try `mcpp self update`; + this is mcpp 2026.8.20.3), or the name is misspelled … +``` + +**§0 的教训在本节内部又应验一次:凭读码不足以下结论,要去跑。** + +⚠️ **§1.5 预判的「唯一真实实现风险」是对的,而测试写法上有一个未预料到的坑:** +不修改任何东西的第二次构建走**全工程 fast path**(`Finished dev in 0.00s`), +根本到不了 build.mcpp 阶段 —— 断言它等于测了 fast path。回归测试必须先 `touch` +一个源文件。由此定下一条边界并写进 docs/07:**全工程 no-op 构建什么都不打印, +包括这一条。** + +⭐ **判据 2 的「先看到它失败」真做了**:临时移除缓存命中处的发射,第二条断言变 +红而第一条仍绿。 + +采用侧:`openarch` 0.6.0 与 `riscv-virt-rt` 0.5.2。干净机器实测,而 +`riscv-virt-rt` 那条**归属到依赖而不是根** —— 包名由引擎传入,不由构建程序自己拼。 + --- ## 2. 【高】补 aarch64 / x86_64 的目标 C 库 @@ -226,6 +260,40 @@ aarch64 有上游端口;x86_64 的端口存在但受关注远少于 arm/riscv。 * **不追 newlib / musl 的裸机变体。** 一个实现先跑通,第二个由需求驱动。 * **不为 arm32(`arm-none-eabi`)开新行。** 那是新目标而非本项范围。 +### 2.8 已实施 —— ⭐ 覆盖两个目标而不是一个,且三条缺陷全是第二个族才暴露的 + +§2.3 要求先测量。测量结果推翻了「可能只有 aarch64 成立」的预期:**两个都成立** +(`libc.a` 7,070,160 / 6,458,288)。 + +构建器泛化为**一个脚本三个族**(而不是加第二份拷贝 —— 那正是 §4/R2 要防的)。 +加两个族只暴露了三条 riscv 两年没暴露的缺陷: + +| 缺陷 | 症状 | riscv 为什么没暴露 | +|---|---|---| +| 稀疏检出少 `third-party` | `'siphash/SipHash.h' file not found` | `emupac.cpp` 是 aarch64 专属 | +| 没设 `CMAKE_CXX_COMPILER_TARGET` | `unknown register name 'x30' in asm` | riscv 的 builtins 全是 C 与汇编,**没有 C++ 源** | +| 链接脚本默认加载地址 | **链接成功,一跑就挂** | 0x80000000 是 riscv `virt` 的 RAM 基址 | + +⭐ 第三条最值得记:**它链接成功**,只表现为机器不动。给 qemu 4GB 内存就跑起来 +—— 假设由此被证实。**一个只在配置慷慨的机器上才工作的加载地址,是最坏的一种错: +它通过。** + +⚠️⚠️ **x86_64 的链接问题上有一次假绿差点定案。** `-fuse-ld=lld` 看起来解决了; +把 PATH 收到只剩 coreutils 后**裸名与 `-B/bin` 两种都倒在** +`collect2 ... [cannot find ld]` —— 之前的通过是**环境里恰好有 `lld`**。真解与 +mcpp 引擎对这个 triple 的做法逐字相同:把链接从驱动手里拿走。 + +**判据**:aarch64 的 `printf` 镜像在 qemu `virt` **默认 128MB 下链接并运行**; +x86_64 在 `0x100000` 链接成功(⚠️ 它没有 semihosting —— 不给控制台时报 +`undefined symbol: stdout` 是**正确答案**)。 + +⚠️ **发布时又踩了一次「照抄上一版实测数字」**:描述符里的 sha256 是加载地址修复 +**之前**那一版的。发布出去的产物是对的,写错的是描述符。修完做了**四方核验**: +描述符 = 本地归档 = GLOBAL = CN。另一条:CN 端漏传 `.sha256` 侧文件,表现为 +`HTTP 404`。 + +**§2.4 的决策按建议执行:目标表的行没有填。** 这两个包是**可声明**的,不是默认的。 + --- ## 3. 【中】第二块板 @@ -278,6 +346,34 @@ aarch64 有上游端口;x86_64 的端口存在但受关注远少于 arm/riscv。 * **不上真实硬件。** CI 里没有硬件,而一个只能在作者机器上验证的板级包,其判据无法被 他人复核。真实硬件是第三块板的事。 +### 3.6 已实施(`mcpplibs/aarch64-virt-rt` 0.1.0) + +⭐ **判据 2 达成,而且比预测的更强。** §3.4 预期「两块板的指令集合相同」,并预留 +了它可能失败。由两个构建程序自己的 `build.mcpp.cache` 的 `d ` 行实测 —— +那是引擎记下的「发出过什么」,不是读源码: + +``` +riscv-virt-rt ldflag runner +aarch64-virt-rt ldflag runner +``` + +**同样两条。** C 库体现为 `ldflag` 的**值**不同: + +``` +riscv-virt-rt -lcrt0-semihost -lc -lsemihost + -lclang_rt.builtins-riscv64 -T …/picolibcpp.ld +aarch64-virt-rt -T …/virt.ld +``` + +⇒ **「板级包」与「C 库提供者」可分离,板级包接口完整。** CI 把它写成硬断言对着 +字面量比,所以任何一侧变了都必须来说明。 + +**§3.3 预判「零 libc 的板需要自带最小 crt0」是对的**,而它的性质比预判更准确: +那是**内容**的差别,不是**接口**的差别 —— 包多了一个 `boot.S`,指令一条没多。 + +⚠️ **`.bss` 不被任何别的东西清零**(`-kernel` 只加载 PT_LOAD 段),而那种失败 +**数据相关、不会在写代码的机器上复现** ⇒ 例子断言 `bss zeroed` 而不是假设它。 + --- ## 4. 【中】把「判据放在能观察的环境里」变成可检查的 @@ -338,6 +434,42 @@ n=$(LD_TRACE_LOADED_OBJECTS=1 "$loader" "$bin" | wc -l) ⚠️ 判据 1 是这项唯一有意义的判据。一个对已知的三次事故都报不出来的 linter,没有理由 相信它能报出第四次。 +### 4.5 已实施 —— ⚠️ 判据 1 不可达,而这是本文最重要的一处更正 + +`tools/lint-ci-assertions.sh` 已落地并接进 mcpp 的 CI(打印,不失败)。 + +⚠️⚠️ **判据 1「把 0.4.0、0.5.0 两份历史工作流喂给它,两份都必须被标出」在这个 +机制下不可达,而发现这一点花了一次实现。** + +0.5.0 的缺陷是可 lint 的:`if: matrix.arch == 'riscv64'` 把一个步骤门到矩阵的 +一行上,一行文本就说明白了。0.4.0 的缺陷**不是**:那一步只断言了 `mcpp build`, +也只声称了这么多 —— 文件里没有任何东西是错的,它只是比仓库在别处做出的主张更 +弱。**⭐ linter 检查写下来的东西,不检查没写的东西。** + +新增 R4 抓的是同一个**形状**的未来版本(把执行断言放在跑不了东西的作业里), +这是这个机制能给的全部。该限制写在工具头部第一段,以免下一个读者去找一条从不 +运行的路径。 + +**两条规则在跑过之后被收窄,两次都是误报率决定的:** + +* **R3** 原本对任何 `2>/dev/null | grep` 报警。而 `cmd 2>/dev/null | grep -q .` + 在机器看来一模一样,做的却是**相反**的事 —— 它断言输出非空,正是本规则要求的。 + 收窄到只对 `-v` / `-c` / 取反管道(按缺席判定)报警。 +* **R4** 原本对任何 `mcpp run` 报警,在**六个完全正确的作业**上误报:宿主目标的 + `mcpp run` 不需要模拟器。收窄到只对 freestanding 目标。 + +⚠️ **一条误报率那么高的规则不会被读**,而这条工具的全部价值就是被读到。 + +**对 mcpp 自身跑,剩一条真的**:`nm "$BIN" 2>/dev/null | grep -c` 在 `nm` 失败 +时打印「0 (good)」。已修成可区分两种情况。 + +⭐ **R2 已在 openarch 上落地并被反向验证过**:`.ci-identical-files` 声明「示例与 +模板的构建程序自 `// The emulator.` 起逐字节相同」,故意弄坏一侧,它报了。 + +⚠️ **写那条检查时,它先在自己身上犯了它要防的错。** 第一版用 sed 地址,而标记 +是一行 C++、含 `/` —— sed 把它当模式结尾,报 `unknown command: '/'`,**两边都空, +diff 通过**。改用 `grep -F` + `tail`,并断言两侧非空。 + --- ## 5. 【低】单 ISA 的第二个后端(riscv S 态)