备忘:2026-09-04 生态批次之后仍未闭合的四条(armv7a 无 C 库/板级包、riscv32 无后端、ninja 空转未定因、armv7a 无 preemption) · Issue #558 · mcpp-community/mcpp · GitHub
Skip to content

备忘:2026-09-04 生态批次之后仍未闭合的四条(armv7a 无 C 库/板级包、riscv32 无后端、ninja 空转未定因、armv7a 无 preemption) #558

Description

@Sunrisepeak

2026-09-04 那一轮生态推进(mcpp 2026.9.4.3、openarch 0.9.0、三个板级包、两个 C 库源码包)之后剩下的四条。都不是回归,都是没做完或没定因的;开一个汇总备忘,避免它们只活在设计文档里。

四条分属不同仓库,汇总在这里只是为了不丢;真正动手时应各自开 PR。

设计与实测记录:

  • .agents/docs/2026-09-04-four-gaps-after-the-ecosystem-batch.md(方案 + §7 实测回填)
  • .agents/docs/2026-09-04-named-runners-and-the-universal-command-surface.md §17

1. armv7a 没有 C 库路线,也没有板级包

归属:mcpplibs/picolibc + 一个新的板级包仓

已有的部分:

  • mcpp 目标表有 armv7a-none-eabi / armv7a-none-eabihf 两行,libdir 是三元组
  • openarch 0.9.0 有 armv7a 后端(cpu / pte / context / trap 四组)
  • e2e 336_armv7a_builds_and_boots.sh 与 openarch 的 armv7a job 每次 CI 都启动一个真实镜像并读退出码

缺的部分:

  • picolibc.picolibc[target.'cfg(arch = ...)'] 块只有五个 M-profile 拼写(thumbv6m / thumbv7m / thumbv7em / thumbv8m.base / thumbv8m.main),没有 armv7a
  • xim:picolibc-arm 预编译载荷只有 7 个 thumb 目录,同样不覆盖
  • 没有 armv7a 的板级包(链接脚本、启动、控制台、runner)

今天 armv7a 只能零 libc:能编、能启动、能退出,但 printf 用不了。

闭合它需要:picolibc 加一个 cfg(arch = "armv7a") 块(machine 目录与 thumb 共用 libc/machine/arm,主要是选文件与排除项),外加一个 armv7a-virt-rt 之类的板级包,目标机器是 qemu -M virt -cpu cortex-a15——那台机器 CI 已经在用了。

判据:一个 printf 程序在 armv7a 上打印并退 0,与 338_cortex_m_picolibc_sysroot.sh 同形。

2. riscv32 没有 openarch 后端;x86_64-none-elf 没有板级包

归属:mcpplibs/openarch;板级包另议

backend-auto 的 target 行覆盖 riscv64、aarch64、x86_64、五个 thumb 拼写、armv7a。riscv32 不在其中——riscv-virt-rt 自己是服务 rv32 的(CI 有 rv32 自测),但那上面用不了 openarch。

x86_64-none-elf 反过来:openarch 后端四组齐全,却没有板级包,所以没有「一行就能启动」的入口。

两条都不紧急,记下来是因为它们让「支持矩阵」有洞而矩阵本身看不出来。

3. ninja 空转,未定因

归属:mcpp(或上游 ninja)

签名已刻画且稳定:99.9% 占一个核、0 个子进程系统时间为 0(纯用户态循环)、8 条边的图产物齐全无缺失输入。三次全新沙箱都复现,都发生在 mcpp build 之后那次 mcpp run

不是图的问题:宿主上同一工程、同样两条 stage_file 边,2 秒完成;手工对同一目录跑同一个 ninja 二进制立刻退 0;事后在同一沙箱按同样顺序重跑两次都成功 ⇒ 非确定性。

取不到栈,三条路都堵死:

  • gdb -pptrace_scope=1 拒(空转的 ninja 不是任何能 attach 的 shell 的后代)
  • perf record -pperf_event_paranoid=4
  • 把 gdb 变成 ninja 的父进程(yama level 1 下合法)之后,空转就不再发生——这一条最有信息量:触发条件与时序/环境有关,不是这份 manifest 的函数

嫌疑最窄的描述(推断,非测量):输出不变的 restat 边 → phony → 被当 order-only 依赖消费。这张图里唯一「不跑命令就完成」的边就是那条 phony,而 stage_file 是唯一一条命令经常被跳过却成功的规则。三段全是 mcpp 自己构造的,可改。

下次复现时的取证手段已经就位:MCPP_NINJA_DEBUG=explain 会给两处 ninja 启动追加 -d explain,空转时会反复打同一条边的判定理由。或者在开发机上放开 ptrace_scope=0,一次就能定。

已修的那一半(确定的):杀掉 mcpp 不再留下孤儿 ninja(进程组 / job object + SIGKILL,mcpp 2026.9.4.3),回归测试 340_no_orphan_survives_a_killed_mcpp.sh2026.9.4.2 会红。

4. openarch:preemption 在 armv7a 上被扣住

归属:mcpplibs/openarch

arch_trap_switch 要求 trap 恢复到另一个上下文。riscv64 / aarch64 上恢复地址在寄存器里(mepc / ELR_EL1),dispatcher 可以在切换前后存取;Cortex-M 用 PendSV 专门做这件事。

ARMv7-A 上它由 srsdb 写在 SVC 栈上,所以 trap 中途换栈会改变 rfeia 弹出的帧——只有当被恢复的上下文也经同一路径挂起时才良定义。这是一个真实设计,但不是本后端测量过的设计,所以在 provides 里扣住该能力,让需要它的消费者在解析期按名字被拒,而不是链接到一个能编过却会错的实现。

这与 Cortex-M 扣住 openarch:address-space 是同一机制。

闭合它需要:把「进入 trap 的上下文必须经同一路径挂起」写成 backend 的契约,在两个上下文之间真的抢占一次并断言寄存器与返回地址,与 examples/preempt 同形。


不在此列(已闭合,写出来避免误读)

状态
mcpp run 折叠退出码 已修,三段契约写在 docs/11 §6(中英)
孤儿 ninja 已修,判据落在进程状态
板级包的模拟器分档 已修,并连同索引描述符的安装期边一起(只改包不改索引的话,分档什么都买不到)
xim:ninja@1.12.1 无校验和 已补四平台 sha256

生态验证现状:全新沙箱 20/20 ECOSYSTEM OK,走已发布索引 + CN 镜像。

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions