Skip to content

RFC: mcpp 对裸机/freestanding target 的支持(riscv64-none-elf 类,toy_kernel 用例) #403

Description

@lildengzi

背景

用 mcpp 构建一个 RISC-V 64 裸机(freestanding)内核(toy_kernel:无 OS、无 libc、qemu virt 机 -kernel 启动),发现 mcpp 目前没有裸机/freestanding 概念,被迫用大量 hack 才能工作。希望 RFC 讨论 mcpp 如何原生支持这类目标。

关联:#276 讨论的是 hosted 嵌入式 Linux SDK(Buildroot/Yocto,有 libc/sysroot);本文讨论的是无 OS 的裸机riscv64-none-elf 类,无 libc、无动态链接器),是 #276 未覆盖的另一条线。官方嵌入式设计(.agents/docs/2026-07-24-embedded-platform-support-design.md)决策 #15 曾将 freestanding 推迟,这里重新开放讨论。

具体痛点(toy_kernel 实测)

项目:toy_kernel,RISC-V 64 freestanding 内核,qemu virt 机。

痛点 1:mcpp 无法表达"裸机 target"(最核心)

mcpp.toml 被迫写成这样:

[toolchain]
default = "llvm@22.1.8"

[build]
static_stdlib = false
cxxflags = [
    "-ffreestanding", "-nostdlib",
    "-fno-rtti", "-fno-exceptions",
    "-march=rv64gc", "-mcmodel=medany",
    "-mstrict-align",
    "-fPIE", "-fno-omit-frame-pointer",
]

mcpp 把项目当 x86_64 宿主处理(没有"target 是裸机 riscv64"的概念),-march=rv64gc/-mcmodel=medany 被按宿主架构解析,默认 mcpp build 直接失败

error: unsupported argument 'medany' to option '-mcmodel=' for target 'x86_64-unknown-linux-gnu'
error: unsupported option '-mstrict-align' for target 'x86_64-unknown-linux-gnu'
error: unknown target CPU 'rv64gc'

痛点 2:mcpp 无法做裸机链接(link.ld + -nostdlib + 无 libc)

裸机链接需要自定义链接脚本 + 无 CRT/libc。Makefile 被迫手动做:

riscv64-linux-gnu-g++ -nostartfiles -nostdlib -static -T link.ld \
  -o build/toy_kernel.elf libtoy_kernel.a -lgcc

mcpp 的链接模型只有 hosted(libc/crt/动态链接器),无自定义链接脚本、无 freestanding 链接模式

痛点 3:mcpp 无法 run/debug 裸机产物

mcpp run 假设 hosted 可执行文件。裸机需要:

qemu-system-riscv64 -machine virt -cpu max -m 256M \
  -nographic -bios default -kernel build/toy_kernel.elf
# 调试: qemu -s -S + gdb 远程

Makefile 被迫手写 run/debug/test。

痛点 4:产物目录错乱

--target riscv64-linux-musl(hosted musl)与裸机 hack 混在 target/

target/x86_64-linux-gnu/.../bin/libtoy_kernel.a     # 旧 hack 产物
target/riscv64-linux-musl/.../bin/libtoy_kernel.a   # hosted musl 产物

Makefile 靠 find target -name "*.a" | head -1 取第一个,取到哪个全看运气。

痛点 5:汇编 .S 的裸机 flag 靠 glob 透传,脆弱

flags = [{ glob = "src/**/*.S", asmflags = ["-march=rv64gc"] }]

mcpp 把汇编也按宿主处理时同样解析错。

可能的讨论方向(开放)

  1. 裸机 target 的表达riscv64-none-elf(无 OS 段)进 kKnownTargets?还是 [target.'cfg(freestanding)'] 谓词?
  2. 链接模型CLibMode::None(linkmodel.cppm 已有此枚举)在裸机下如何接自定义 -T link.ld + -nostdlib
  3. run/debugmcpp run 是否能支持"qemu -kernel"类裸机运行器,或至少提供可配置的 run 命令模板?
  4. import std:裸机无 libc,import std 不可用——是否需要 import std 降级/关断?freestanding modules 是更大的特性(官方已推迟),但裸机 C++(无 RTTI/异常)是现实的。
  5. 工具链riscv64-none-elf 类裸机工具链(newlib/picolibc)在 xim 生态的打包。

期望

  • 明确 mcpp 对裸机/freestanding 的定位(支持 / 明确不支持 / 部分支持)。
  • 如果是"部分支持",最小可落地形态是什么(比如:让 [target] 能表达裸机 triple + 链接脚本 + run 命令模板,先覆盖 RISC-V qemu 场景)。
  • toy_kernel 可作为持续验证用例。

环境

  • mcpp 2026.8.8.4
  • 工具链:llvm@22.1.8(宿主)+ riscv64-linux-musl-gcc 16.1.0(交叉,PR #585)
  • qemu-system-riscv64 11.0.3

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