读者: 为一个由平台包配置的目标构建的人(ok 映像,<arch>-openkal)、要改动该配置一部分的人,
以及为一类目标编写平台包的人。
本章回答的那一个问题: 一类目标怎样作为一个包来配置,构建怎样选择它,工程怎样覆盖或替换它。
不在这里: 平台所命名的目标侧各层,见 22 —— 目标侧;openkal 的模型与宿主上的 交叉构建,见 24 —— 基于 openkal 的交叉构建;打包一个程序,见 10 —— 发布打包;精确规则,见 SPEC-013。
在此之前:34 —— 编写板级支持包。 在此之后:40 —— 裸机与 freestanding 目标。
平台是一个带版本的包,陈述一类目标所需的全部内容:工具链、目标侧各层的提供包、构建在本机运行的
工具、编译与链接约定、产物的命名与封装,以及运行器。工程一项都不必写。目标表为 x86_64-openkal 与
aarch64-openkal 选择 mcpplibs.openkal-platform(2026.10.27.1+),这两个目标的内置支持即是如此。
一个只写出源码的工程:
[package]
name = "app"
version = "0.1.0"mcpp run --target x86_64-openkal Resolved llvm@23.1.3 → x86_64-openkal → …/xim-x-llvm/23.1.3/bin/clang++
the platform's (openkal-platform 0.18.0), replacing your gcc@16.1.0 — override with `[target.x86_64-openkal] toolchain`
Target x86_64-openkal → x86_64-unknown-none-elf
compiler-runtime compiler-rt (openkal-llvm-runtime@0.16.6, platform)
c-abi musl (openkal-musl@0.22.6, platform)
c++-abi libc++ (openkal-llvm-runtime@0.16.6, platform)
Platform openkal-platform 0.18.0 (built-in)
tools okld, okrun (openkal-tools@0.1.3, platform)
runner okrun (platform)
link lld, start ok_main (platform)
Compiling app v0.1.0 (.)
Running `okrun … target/x86_64-openkal/…/bin/app.oke`
每个值都带来源报告。mcpp test、mcpp pack 与 --target aarch64-openkal 无需更多声明;与本机架构不同的
映像经执行宿主运行(24)。mcpp.lock 以
origin = "platform" 记录平台加入的包,并以 targets 写出每个条目的配置(只属于本机原生配置的条目不写),
因此为本机的构建与为 ok 映像的构建不互相改写对方的条目。
| 组 | 键 | 作用 |
|---|---|---|
| 目标 | targets、toolchain、sysroot |
服务哪些三元组、它们使用的工具链、预构建的目标基 |
| 层 | [platform.layers] |
c-abi、c++-abi、compiler-runtime、kernel-abi 的提供包,或 false |
| 工具 | [platform.tools] |
为本机构建的程序,或查找到的程序({ program = "<name>" }) |
| 编译 | [platform.build]、[platform.build.'cfg(…)'] |
目标每个翻译单元的标志 |
| 链接 | [platform.link] |
driver、flags、start、script、inputs、名字 exe 与 shared、封装步骤 seal |
| 运行 | runner、runners |
mcpp run 与 mcpp test 怎样启动产物,以及具名的设备动作 |
| 载体 | carrier |
mcpp pack 为依赖加载器的产物按系统构建的程序:self-contained 树的运行器、单文件;一个表或表的列表,每项服务其 hosts 中的 <os>-<arch> |
| 运行器存在之处 | runner.hosts |
运行器程序存在的 <os>-<arch>:需要它的包在哪里运行(runs_on.with,10) |
| 代码 | plugin |
在平台阶段运行的构建程序,陈述随依赖图而变的部分 |
| 版本组 | [platform.versions] |
一个家族中每个包的一个版本 |
| 宿主部分 | [platform.hosted] |
宿主三元组选用该平台时适用的部分 |
工程在 [target.<selector>] 下以平台自己的键名覆盖一个字段。cfg(platform = "openkal") 不论架构都匹配该平台:
[target.'cfg(platform = "openkal")'.layers]
c-abi = { path = "../openkal-musl" } # a working tree in place of the release
[target.'cfg(platform = "openkal")'.tools]
okld = { path = "../openkal-image/tools" }
[target.'cfg(platform = "openkal")']
runner = ["my-okrun", "{}"]| 字段 | 规则 |
|---|---|
编译标志、link.flags |
追加在平台的之后;约定不能删除 |
link.inputs、link.seal |
整体替换 |
layers、tools、runners |
按键替换;<layer> = false 不提供该层 |
runner |
argv 替换;未写出时保留 host 与 exclusive |
| 其余字段 | 替换 |
同样的表也可以写在 ~/.mcpp/config.toml 中,对一台机器生效。图中已有包提供的层交给该包,报告为 graph。
C++ 运行时的包同时提供编译器运行时,因此 "c++-abi" = false 只有与 compiler-runtime = false 同时写出才生效。
第一个给出答案的来源决定目标的平台:
| 来源 | 写法 |
|---|---|
| 命令行 | --platform openkal-platform@0.18.0、--platform path:../openkal-platform、--platform none |
| 环境变量 | MCPP_TARGET_X86_64_OPENKAL_PLATFORM=… |
| 工程 | [target.<selector>] platform = "openkal-platform@0.18.0",或 { path = "…" } |
| 本机 | ~/.mcpp/config.toml 中的同一个键 |
| 目标表 | 平台列(mcpp toolchain list) |
platform 不能写在 cfg(platform = …) 选择器下。none 只以引擎对该目标的约定构建。
构建程序与构建运行的工具按本机的约定为本机编译。[host] platform 为它们选择一个平台:
[host]
platform = "openkal-platform@0.18.0" Host platform openkal-platform 0.18.0 (mcpp.toml:2): build programs are x86_64-openkal images run by okrun
此后每个构建程序都编译为本机架构的 ok 映像,在 Linux、macOS 与 Windows 上使用同一个工具链,经平台的运行器
运行。平台自己的工具仍以原生方式构建。--host-platform 与 MCPP_HOST_PLATFORM 对一次运行选择它,
~/.mcpp/config.toml 中的 [host] 对一台机器选择它。
宿主三元组选用一个平台时,只适用平台的 [platform.hosted] 部分:它的工具链与它的层。对 openkal-platform 而言,
即家族的 C 库与 C++ 运行时,位于系统自己的 openkal 实现之上:
[target.'cfg(any(linux, macos, windows))']
platform = "openkal-platform@0.18.0"Windows 上这一安排对应 GNU ABI 的行(--target x86_64-windows-gnu);[platform.hosted] targets 之外的
三元组被拒绝,消息给出它所服务的同系统同架构的行。
[platform.versions] 为一个包与包之间精确钉住的家族列出每个包的一个版本。依赖图中出现其中某个包的
另一个版本时,在任何编译之前拒绝:
error: openkal-musl 0.22.2 is in this build, and the platform openkal-platform 0.18.0 is a version group that names openkal-musl 0.22.9.
requested by: own
The family's packages pin one another exactly, so two versions of one of
them cannot be linked into one program. Either select the platform release
of that version ([target.<selector>] platform = "openkal-platform@<version>"), or write
openkal-musl = "0.22.6" where it is requested.
从目录或仓库取得的包不受版本组约束。
平台包是带 [platform] 段的包。openkal-platform 的节选:
[package]
namespace = "mcpplibs"
name = "openkal-platform"
version = "0.18.0"
mcpp = ">=2026.10.30.1"
[platform]
targets = ["x86_64-openkal", "aarch64-openkal"]
toolchain = "llvm@23.1.3"
runner = { cmd = ["okrun", "{}"], host = "same-arch" }
carrier = { package = "openkal-run@0.1.3", section = ".oke", main = "carrier/main.cpp" }
plugin = "build.mcpp"
[platform.layers]
compiler-runtime = "openkal-llvm-runtime@0.16.6"
"c++-abi" = "openkal-llvm-runtime@0.16.6"
c-abi = { name = "openkal-musl", version = "0.22.6", default-features = false, features = ["posix"] }
[platform.tools]
okld = "openkal-tools@0.1.3"
okrun = "openkal-tools@0.1.3"
[platform.build]
cxxflags = ["-fPIC", "-femulated-tls", "-fvisibility=hidden", "-fasynchronous-unwind-tables"]
[platform.build.'cfg(arch = "aarch64")']
cxxflags = ["-ffixed-x18", "-mno-outline-atomics"]
[platform.link]
driver = "lld"
start = "ok_main"
flags = ["-shared", "-z", "max-page-size=65536", "-z", "now", "--gc-sections", "--icf=safe", "--eh-frame-hdr"]
inputs = [{ from = ["okld", "note-source"], as = "ok-notes.S" }]
exe = "{name}.oke"
shared = "lib{name}.okso"
seal = [["okld", "note", "{}"], ["okld", "check", "{}", "--with", "{needed}"]]- 程序写名字,不写位置。
inputs与seal中的okld依次在图为本机构建的程序、声明的载荷、PATH中查找。 {}是产物。 封装步骤中的{needed}展开为产物所需的共享映像;它前面的--with在每个映像前重复。- 封装步骤失败时不发布。 上一次成功构建发布的产物保留原位。
- 随依赖图而变的部分写成代码。
plugin = "build.mcpp"在平台阶段运行(mcpp::phase()为"platform"), 可以陈述标志、链接字段与运行器(mcpp::link_driver、mcpp::link_input_from、mcpp::artifact_name、mcpp::seal、mcpp::run_host);其他指令被拒绝,平台提供的包格式除外(pack-format与artifactaction,例如由暂存树生成okb)。板级支持包的构建程序在构建阶段陈述同样的字段 (34)。 - 载体的入口读取它携带的内容。 mcpp 把携带的字节放在
mcpp_carried_begin与mcpp_carried_end之间 (入口的名字在mcpp_carried_name):程序为 self-contained 树的运行器时不携带任何内容,运行其第一个参数所指的映像; 或映像本身;或映像引用其他映像时的单文件所携带的全部映像的一个 stored zip(PK\x03\x04,每个映像对齐到 64 KiB)(SPEC-013 §11)。
开发期间,工程以 --platform path:<dir> 或 platform = { path = "<dir>" } 选择工作树。在平台包中执行
mcpp test 而不给 --target 时,以该包为平台为其每个 targets 构建测试,运行本机架构的那些与给出了执行宿主的
那些(2026.10.29.1+),其余报告为已构建、未运行。
mcpp self env --target x86_64-openkal # toolchain, platform, tools, runner, and why runs are refused here
mcpp self env --target x86_64-openkal --format json
mcpp self env --host # the host graph, its runner and tools once its build programs were built
mcpp toolchain list # the PLATFORM column
mcpp toolchain install --target x86_64-openkal # fetch and build what the target needs--message-format json 在 plan 事件与 result.json 中给出 platform 与 hostPlatform
(50)。
| 原因 | 条件 | 出路 |
|---|---|---|
platform-not-a-platform |
所选的包没有 [platform] |
选择一个平台包,或 none |
platform-target-unserved |
平台不服务该三元组 | 为它的某个 targets 构建,或为消息给出的宿主行构建 |
platform-tool-absent |
链接或封装要运行的程序既未构建、也未找到 | 在 [target.'cfg(platform = "…")'.tools] 下写出构建它的包 |
platform-version-group |
家族中某个包的另一个版本在图中 | 选择携带该版本的平台版本,或钉住版本组中的版本 |
platform-phase-directive |
插件陈述了平台阶段不接受的指令 | 改由包自己的构建程序陈述 |
lld-required-absent |
平台以 ld.lld 链接,而工具链没有它 |
使用平台的工具链 |
- 一个平台的每个字段只有一个值;随架构不同的字段只有标志可以写在
[platform.build.'cfg(arch = "…")']下。 - 宿主图的平台按一次运行或一个工程选择;缺省为宿主约定。
[host]只接受platform。