背景
用 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 把汇编也按宿主处理时同样解析错。
可能的讨论方向(开放)
- 裸机 target 的表达:
riscv64-none-elf(无 OS 段)进 kKnownTargets?还是 [target.'cfg(freestanding)'] 谓词?
- 链接模型:
CLibMode::None(linkmodel.cppm 已有此枚举)在裸机下如何接自定义 -T link.ld + -nostdlib?
- run/debug:
mcpp run 是否能支持"qemu -kernel"类裸机运行器,或至少提供可配置的 run 命令模板?
- import std:裸机无 libc,
import std 不可用——是否需要 import std 降级/关断?freestanding modules 是更大的特性(官方已推迟),但裸机 C++(无 RTTI/异常)是现实的。
- 工具链:
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
背景
用 mcpp 构建一个 RISC-V 64 裸机(freestanding)内核(toy_kernel:无 OS、无 libc、qemu virt 机
-kernel启动),发现 mcpp 目前没有裸机/freestanding 概念,被迫用大量 hack 才能工作。希望 RFC 讨论 mcpp 如何原生支持这类目标。具体痛点(toy_kernel 实测)
项目:
toy_kernel,RISC-V 64 freestanding 内核,qemu virt 机。痛点 1:mcpp 无法表达"裸机 target"(最核心)
mcpp.toml被迫写成这样:mcpp 把项目当 x86_64 宿主处理(没有"target 是裸机 riscv64"的概念),
-march=rv64gc/-mcmodel=medany被按宿主架构解析,默认mcpp build直接失败:痛点 2:mcpp 无法做裸机链接(link.ld + -nostdlib + 无 libc)
裸机链接需要自定义链接脚本 + 无 CRT/libc。Makefile 被迫手动做:
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/:Makefile 靠
find target -name "*.a" | head -1取第一个,取到哪个全看运气。痛点 5:汇编
.S的裸机 flag 靠 glob 透传,脆弱mcpp 把汇编也按宿主处理时同样解析错。
可能的讨论方向(开放)
riscv64-none-elf(无 OS 段)进 kKnownTargets?还是[target.'cfg(freestanding)']谓词?CLibMode::None(linkmodel.cppm 已有此枚举)在裸机下如何接自定义-T link.ld+-nostdlib?mcpp run是否能支持"qemu -kernel"类裸机运行器,或至少提供可配置的 run 命令模板?import std不可用——是否需要import std降级/关断?freestanding modules 是更大的特性(官方已推迟),但裸机 C++(无 RTTI/异常)是现实的。riscv64-none-elf类裸机工具链(newlib/picolibc)在 xim 生态的打包。期望
[target]能表达裸机 triple + 链接脚本 + run 命令模板,先覆盖 RISC-V qemu 场景)。环境