Skip to content

Commit b2cd69f

Browse files
docs: 裸机生态定位文档补实施记录,十四条被实测推翻的假设 (#470)
方案部分写于实施之前。本次补上第二部分,记录落地结果,并且与方案分开—— 因为**十七项假设中有十四项被实测推翻或修正**,而被推翻的过程本身是这份 文档最有价值的部分:只记录结论的方案,读者无法判断哪些结论被检验过。 新增内容:八个维度各自的落点与判据、实际执行的任务依赖图(其中一条边是 实施中才发现的)、九个仓库的交付与版本、三个项目模板的分工、十四条被推翻 的假设按杀伤力排序、以及四项尚未完成的事及其定位。 杀伤力最大的三条: * 「mcpp 从目标行解析 C 库」被读成「mcpp 会安装它」——引擎只查找不安装, 而 0.3.0 删索引安装边时把这两件事混为了一谈; * 「板级包在零 libc 档无事可做」——不用 C 库的开发者需要的是更多板级包 而不是更少; * libc++ 的 `__config_site` 只为宿主 triple 出厂,所以合成它是用 libc++ 做任何交叉的唯一办法,不合成时标准强制的 34 个头 0/34。 Co-authored-by: speak-agent <248744407+speak-agent@users.noreply.github.com>
1 parent 149424a commit b2cd69f

1 file changed

Lines changed: 121 additions & 0 deletions

File tree

.agents/docs/2026-08-20-freestanding-ecosystem-positioning.md

Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -690,3 +690,124 @@ C3 的三个新问题:ROM bootloader 的镜像头(esptool 格式)· 没有 semih
690690

691691
⚠️ 五项决策全部不要求引擎认识 KAL / HAL / ARCH,也全部不新增引擎轴——
692692
A 复用 `provides`,B 只改目标表的输入来源,C/D 是包与载荷,E 是案例选择。
693+
694+
---
695+
696+
# 第二部分:实施记录(2026-08-20)
697+
698+
本部分记录上述方案的落地结果。它与方案分开,因为**十七项假设中有十四项被
699+
实测推翻或修正**,而被推翻的过程本身是这份文档最有价值的部分:一个只记录
700+
结论的方案,读者无法判断哪些结论是被检验过的。
701+
702+
## 7. 八个维度上的落点
703+
704+
| 维度 | 落点 | 判据 |
705+
|---|---|---|
706+
| **架构** | C 库成为**目标**的属性(`[target.X].sysroot`),而不是包的;板级包不再指名 picolibc、compiler-rt 或 multilib 目录 | `riscv-virt-rt``build.mcpp` 里三个硬编码名字全部换成查询;e2e/134 两侧钉住 |
707+
| **稳定性** | 每一条新诊断都有机器校验,不靠注释维持 | e2e/135 把诊断里给出的依赖行**粘回 manifest 再构建**;riscv-virt-rt 的 CI 断言拒绝消息的**内容**而非退出码 |
708+
| **优雅** | 新增能力零新引擎轴:`sysroot` 是既有目标表的一列,三个查询走既有的 build.mcpp 契约,分配器走既有的 capability 机制 | 引擎侧改动集中在 `triple.cppm``freestanding/target.cppm``prepare.cppm` 的填值处 |
709+
| **用户体验** | `mcpp new k --template riscv-virt-rt:nolibc-bsp` 产出**两个文件**的可运行内核工程 | 实测 294 字节镜像;对照 `:nolibc` 模板的五个文件 |
710+
| **兼容性** | 目标表新增行不改变既有两行;`nolibc` 是新 feature 而非默认;版本校验从硬错误降级为 `schemaWarnings` | 钉住 `std-freestanding 0.3.0` 的工程在校验加入后仍能加载 |
711+
| **跨平台** | 八个仓库补宿主平台轴(macos-14 + windows-2022) | 五个仓库三宿主全绿;`std-freestanding` 的 Windows 缺口**测量并记录**而非删除 |
712+
| **一致性** | 同一份探针源码在两台指令集不同的机器上运行,输出逐字相同 | openarch 的门槛判定,riscv64 与 aarch64 退出码均为 0 |
713+
| **无感升级** | 索引 `deps` 边补回后,消费者装板级包即得到目标 C 库;引擎发布走既有闭环 | 「拿走再装回来」实测:包与 qemu 一起藏起来后重新构建,两者都被装回 |
714+
715+
## 8. 任务依赖图(实际执行的形态)
716+
717+
```
718+
E1 引擎:[target.X].sysroot 覆盖与零 libc 档 ──┬─→ P1 std-freestanding nolibc feature
719+
├─→ P2 riscv-virt-rt 0.5.0 nolibc feature
720+
└─→ E4 aarch64-none-elf 目标行(零 libc)
721+
E2 引擎:三个目标查询接口 ────────────────────→ P2
722+
E3 引擎:operator new 缺失的具名诊断 ─────────→ P3 两个 alloc 实现包
723+
X1 索引:xim:qemu-arm(含 xlings-res 双端镜像)─┐
724+
E4 ───────────────────────────────────────────┴─→ A1 openarch aarch64 上下文后端
725+
└─→ A2 门槛判定(一份探针,两台机器)
726+
└─→ A3 openarch.pte 两个后端
727+
└─→ A4 CI 三腿
728+
X2 索引:riscv-virt-rt 的 picolibc 安装边补回 ─→ 全部生态仓库 CI
729+
```
730+
731+
⚠️ **图里有一条边是实施中才发现的**:`X2`。方案里没有它,因为方案假定
732+
「mcpp 从目标行解析 C 库」等同于「mcpp 安装它」。实测:引擎只在磁盘上**查找**,
733+
从不安装,而 0.3.0 删掉索引里的安装边时把这两件事混为了一谈。
734+
735+
## 9. 九个仓库的协作形态
736+
737+
| 仓库 | 本次交付 | 版本 |
738+
|---|---|---|
739+
| `mcpp-community/mcpp` | 引擎五项能力 + 目标表第三行 + 章节 13 | 2026.8.20.2 → **2026.8.20.3** |
740+
| `mcpplibs/std-freestanding` | `alloc` / `alloc-kal` / `alloc-libc` / `nolibc` 四个 feature;C++26 特性宏守卫;标准强制清单与合规断言 | 0.2.0 → **0.4.0** |
741+
| `mcpplibs/std-freestanding-nolibc` | 五个 C 函数 + 四份 C 头,供零 libc 档 | **0.2.0** |
742+
| `mcpplibs/std-freestanding-alloc-kal` | 十二个 operator new/delete,经 openkal | **0.1.0** |
743+
| `mcpplibs/std-freestanding-alloc-libc` | 同上,经目标 C 库 | **0.1.0** |
744+
| `mcpplibs/riscv-virt-rt` | 解耦三个硬编码名字;`openkal``nolibc` 两个 feature;两个零 libc 模板 | 0.3.0 → **0.5.0** |
745+
| `mcpplibs/openkal-opensbi` | SBI 控制台 + SRST + bump 分配器 | **0.1.0** |
746+
| `mcpplibs/openkal-uefi` | Boot Services 后端,偏移由 static_assert 钉住 | **0.1.0** |
747+
| `mcpplibs/openarch` | 第二个架构 + 页表项接口,门槛通过 | 0.1.0 → **0.2.0** |
748+
749+
外加两个索引仓库:`mcpplibs/mcpp-index`(包描述符)与
750+
`openxlings/xim-pkgindex`(`xim:qemu-arm`),以及新建的 `xlings-res/qemu-arm`
751+
双端镜像。
752+
753+
## 10. 项目模板
754+
755+
| 模板 | 生成 | 用途 |
756+
|---|---|---|
757+
| `riscv-virt-rt` | 普通 `int main()` 工程 | picolibc 之上的固件 |
758+
| `riscv-virt-rt:nolibc` | 五个文件,不依赖任何包 | 内核起点,展示**到底需要什么** |
759+
| `riscv-virt-rt:nolibc-bsp` | 两个文件,依赖板级包的 `nolibc` feature | 内核起点,展示**BSP 省掉了什么** |
760+
761+
⚠️ 后两者刻意成对存在。差别不在程序做什么,而在这块板的数据手册被抄进工程
762+
多少。
763+
764+
## 11. 被实测推翻的方案假设
765+
766+
按对方案的杀伤力排序。
767+
768+
1. **「mcpp 从目标行解析 C 库」被读成「mcpp 会安装它」。** 引擎只查找不安装;
769+
冷 runner 的整份日志里 `picolibc` 一次都没出现。索引的 `deps` 边是补法,
770+
而 0.3.0 把它连同构建期耦合一起删了。
771+
2. **`std-freestanding``std-freestanding-nolibc` 「互斥」。** 0.4.0 的
772+
`nolibc` feature 让子集在零 libc 档可用,实测 94/103。写着互斥的那段文档
773+
与推翻它的 feature 是同一个 PR 合入的。
774+
3. **板级包在零 libc 档「无事可做」。** 不用 C 库的开发者需要的是**更多**板级
775+
包而不是更少:UART 在哪、RAM 从哪开始、哪个模拟器启动它,没有一条是 C 库
776+
事实。0.5.0 把 C 库变成消费方式上的一个 feature。
777+
4. **`libc.empty()` 意味着「工程拒绝了 C 库」。** 它同样意味着「还没装」。本机
778+
picolibc 早就在,所以每次本地测试都过,CI 在冷机上失败。
779+
5. **UEFI 需要新的 PE freestanding 目标。** 不需要:`x86_64-windows-gnu`
780+
`-nostdlib -Wl,--subsystem,10` 就产出 `IMAGE_SUBSYSTEM_EFI_APPLICATION`
781+
6. **`-mabi=lp64` 是 aarch64 的 ABI 名。** clang 直接拒绝;正确的是 `aapcs`
782+
按 RISC-V 类推填表,恰好会在类推最像的地方错。
783+
7. **feature 可以控制 ISA 后端的宿主可测面。** 一个文件只要被任何 feature
784+
命名就归它独占——feature 未激活时不编译它,**即便 cfg 块显式列出**,而库
785+
构建仍报成功。头文件 `inline` 才是解法。
786+
8. **`std-freestanding` 的 Windows 失败是「包绑死在 libc++」。** 更深一层:
787+
libc++ 的 `__config_site` 只为**宿主 triple** 出厂,所以合成它是用 libc++
788+
**任何**交叉的唯一办法(不合成时标准强制的 34 个头 **0/34**)。Windows
789+
缺的是载荷没打包 `include/c++/v1`,而 libc++ 的头是与宿主无关的纯文本。
790+
9. **C++26 的 freestanding 特性宏可以当门。** libc++ 22.1.8 一个都不定义,
791+
libstdc++ 16.1.0 定义七个,两者都不定义那个元宏。拿在场当门会把这个包在
792+
libc++ 上清空。规则必须不对称:**在场且不足才排除,缺席不排除**
793+
10. **这个包提供的是「libc++ 恰好能编的东西」。** 它同时提供了**标准强制的
794+
全部 34 个**,而它宣传的 `<array>`/`<span>`/`<optional>`/`<vector>`
795+
**都不在**强制列表里。说法比实际低。
796+
11. **`mcpp build``mcpp test` 对 feature 源的判断一致。** 不一致:ADD 两边
797+
都跑而 DROP 被 `!includeDevDeps` 挡住,于是 `mcpp test` 编译未激活的
798+
feature 源。这是为 gtest 的 `main` feature 做的选择被推广到了每个包。
799+
12. **上下文接口预留的 128 字节是个余量。** 它已经假定了一条契约:保存的上下文
800+
只含整数状态。aarch64 连 `d8``d15` 一起保存需要 168 字节。
801+
13. **页表项自带其含义。** aarch64 写的是指向 `MAIR_EL1` 的索引,所以同样的位
802+
在两台 CPU 上描述不同的内存。本层因此接管那个寄存器。
803+
14. **QEMU 一个包支持很多指令集。** xPack 按目标族分包:`qemu-riscv`
804+
`bin/` 里只有两个程序。
805+
806+
## 12. 尚未完成
807+
808+
| | 状态 |
809+
|---|---|
810+
| `mcpp test``mcpp build` 的 feature 源不一致 | 已定位到 `prepare.cppm` 的 DROP 条件,未修——正确的修法要把「对测试规划器可见」与「编进库里」分开,并连 gtest 路径一起验证 |
811+
| Windows LLVM 载荷缺 `include/c++/v1` | 已定位。修法是往载荷里**加一份资源**,不动 Windows 宿主默认的 MSVC STL |
812+
| openarch 的 trap / per-CPU / 屏障 / 时钟 | 刻意未开始:形状取决于已完成的两条原语 |
813+
| x86_64 裸机目标 | 卡在模拟器载荷:没有上游为本索引服务的五个宿主目标发布 `qemu-system-x86_64` |

0 commit comments

Comments
 (0)