Tock 板级构建辅助 crate(tock_build_scripts)完全指南:从 build.rs 到默认链接脚本
操作系统嵌入式嵌入式OS【免费下载链接】tockA secure embedded operating system for microcontrollers项目地址https://gitcode.com/gh_mirrors/to/tock点击查看免费下载导读tock_build_scripts是 Tock 内核仓库中为板级board构建提供支撑的辅助 crate它把调用默认链接脚本、校验编译参数、跟踪链接脚本变更等样板逻辑封装成一行函数调用并随 crate 打包了默认的tock_kernel_layout.ld链接脚本。无论是仓库内的 Tock 板卡如 hail、qemu_rv32_virt还是基于 Tock 的out-of-tree仓库外内核配置都可以通过三步接入获得一致的构建行为。读完本文你将掌握在自定义板卡中接入该 crate 的完整流程、其底层 build.rs 函数族的工作原理以及默认链接脚本定义的各内存区域与关键符号语义。这个 crate 解决什么问题Tock 的板卡 crate如boards/hail在编译时需要完成几件固定的事把板卡自身的layout.ld链接脚本以及它INCLUDE的芯片级链接脚本交给链接器保证链接器能搜索到 Tock 内核提供的通用链接脚本tock_kernel_layout.ld当上述链接脚本内容变化时触发重新编译校验构建所用的 RUSTFLAGS 没有被意外覆盖避免产出无效固件。tock_build_scripts正是把这些逻辑收敛为一个 crate。其官方定位在 boards/build_scripts/README.md 中写得很清楚该 crate 为构建 Tock 板卡提供辅助out-of-tree 的 Tock 内核配置可以可选地把该 crate 作为依赖引入以使用内核提供的 build.rs 功能该 crate 同时打包了默认的tock_kernel_layout.ld链接脚本。从源码看该 crate 结构极简boards/build_scripts/src/lib.rs 仅声明default模块并对外重导出default_linker_script真正的实现都在 boards/build_scripts/src/default.rs 中。整条调用链的入口是一个不返回值的函数default_linker_script()。三步接入在自定义板卡中使用该 crateREADME 给出了三个通用步骤下面逐一展开并结合仓库实际用法说明。第 1 步在 Cargo.toml 的 build-dependencies 中引入在板卡的Cargo.toml中把该 crate 加入构建依赖# Cargo.toml # ...Existing Cargo.toml contents... [build-dependencies] tock_build_scripts { git https://github.com/tock/tock}这样会确保构建脚本在板卡编译时可用。对于仓库内的板卡则使用相对路径引用例如 boards/hail/Cargo.toml[build-dependencies] tock_build_scripts { path ../build_scripts }仓库内绝大多数板卡apollo3 系列、arty_e21、clue_nrf52840、microbit_v2、各种 nrf52840dk 测试配置等都采用这种path ../build_scripts或path ../../build_scripts的形式。第 2 步在 build.rs 中调用辅助函数在板卡 crate 根目录的build.rs里常见用法就是直接调用提供的函数// build.rs fn main() { tock_build_scripts::default_linker_script(); }仓库中真实的 boards/build.rs 正是这样写的且其文档注释明确建议out-of-tree 板卡推荐把这个文件复制到自己的板卡 crate 中同时把Cargo.toml的[package] build字段指过去见 boards/hail/Cargo.toml 中的build ../build.rs。第 3 步提供板卡自身的 layout.lddefault_linker_script()约定板卡必须提供一个名为layout.ld的链接脚本该约定常量定义于 boards/build_scripts/src/default.rs。它的末尾应包含一行INCLUDE tock_kernel_layout.ld把通用内核布局引入INCLUDE tock_kernel_layout.ld例如 boards/hail/layout.ld 就是芯片布局 内核布局两级 INCLUDE 的典型写法INCLUDE ./chip_layout.ld INCLUDE tock_kernel_layout.ld其中chip_layout.ld如 boards/hail/chip_layout.ld负责定义MEMORY区域如 sam4l 的rom/prog/ram三块区域的 ORIGIN 与 LENGTH而tock_kernel_layout.ld负责定义所有 section 的排布。如果板卡未提供layout.lddefault_linker_script()会直接 panic 并提示 Boards must provide alayout.ldlink script file。源码级拆解default_linker_script() 到底做了什么default_linker_script()的实现位于 boards/build_scripts/src/default.rs依次执行四件事pub fn default_linker_script() { if !Path::new(LINKER_SCRIPT).exists() { panic!(Boards must provide a layout.ld link script file); } rustflags_check(); include_tock_kernel_layout(); add_board_dir_to_linker_search_path(); set_and_track_linker_script(LINKER_SCRIPT); }1. rustflags_check()防止 RUSTFLAGS 被覆盖Tock 通过cargo配置文件仓库内见 boards/cargo/tock_flags.toml 等设置整套 RUSTFLAGS但这些环境变量很容易被命令行参数无意覆盖——构建仍会成功产物却是无效的。为此 boards/build_scripts/src/default.rs 采用哨兵标记方案配置文件里设置cfg_tock_buildflagssentinel构建脚本检查CARGO_ENCODED_RUSTFLAGS中是否包含该标记若缺失则 panic 提示 Incorrect build configuration. Verify you are using unstable cargo and have not unintentionally set the RUSTFLAGS environment variable.。两个细节值得注意该检查仅在交叉编译TARGET ≠ HOST时执行从而避免cargo clippy等主机端工具误报如果你有意不使用标准 Tock 配置文件可以在自己的 cargo 配置中设置cfg-tock-buildflagssentinel来显式规避此错误。2. include_tock_kernel_layout()把默认链接脚本加入搜索路径见 boards/build_scripts/src/default.rs。它向链接器输出-L本 crate 的 CARGO_MANIFEST_DIR使链接器在搜索INCLUDE tock_kernel_layout.ld时能找到随 crate 打包的脚本同时输出cargo:rerun-if-changedtock_kernel_layout.ld 路径保证内核默认链接脚本一旦变更所有依赖它的板卡都会自动重编。3. add_board_dir_to_linker_search_path()把板卡目录加入链接器搜索路径见 boards/build_scripts/src/default.rs。它输出cargo:rustc-link-arg-L板卡 Cargo.toml 所在目录。源码注释特别点明这里必须用运行时读取的CARGO_MANIFEST_DIR而不能用编译期展开的std::env!(CARGO_MANIFEST_DIR)——因为前者指向板卡目录后者指向 build_scripts crate 自身目录二者是不同的路径。4. set_and_track_linker_script()传递链接脚本并递归跟踪 INCLUDE见 boards/build_scripts/src/default.rs输出cargo:rustc-link-arg-Tlayout.ld把板卡链接脚本交给链接器随后调用track_linker_script()。跟踪逻辑boards/build_scripts/src/default.rs值得一提跳过tock_kernel_layout.ld本身它已在第 2 步单独登记了 rerun 指令校验路径确实存在assert!(path.is_file(), ...)输出cargo:rerun-if-changedpath解析链接脚本中所有INCLUDE 相对路径行并递归跟踪因此layout.ld → chip_layout.ld → tock_kernel_layout.ld任意一环变更都会触发增量重建。这解释了为什么修改芯片内存布局后不需要手动 clean 重编——cargo 会在下一次cargo build时自动感知。默认链接脚本 tock_kernel_layout.ld 详解tock_build_scripts打包的 boards/build_scripts/tock_kernel_layout.ld 是 Tock 内核的通用链接脚本。对大多数开发者而言**只需在板卡/芯片链接脚本里定义 6 个变量ROM/PROG/RAM三块区域的ORIGIN与LENGTH和可选的PAGE_SIZE默认 512 字节**即可脚本头部对此有明确说明。板卡需要提供的符号契约如果你要从零编写自己的链接脚本则必须定义以下符号脚本头部注释逐条给出了语义符号含义_etextflash 中驻留数据含需拷贝的初始值的结束地址_srelocate/_erelocateSRAM 中可变程序数据的拷贝目标区间Tock 启动时把_erelocate - _srelocate字节从_etext拷贝到_srelocate_szero/_ezeroBSS 区间Tock 启动时清零_sapps/_eappsflash 中应用内存的起止_sappmem/_eappmemRAM 中应用内存的起止关键 section 排布tock_kernel_layout.ld的SECTIONS主体约 380 行核心布局如下.text rom刻意放在文件最前。注释解释了原因——QEMU 等系统用 multiboot 协议只扫描 ELF 前 8192 字节.text必须先定义才能保证.multiboot落在前 8K。section 内部依次放置.multiboot、ARM 向量表.vectors/.irqs、RISC-V 启动代码.riscv.start且_start_trap需 256 字节对齐以配合 lowRISC CPU、x86 启动代码.x86.start、常规.text/.rodata、C/C 构造函数与析构函数数组等。.storage rom按PAGE_SIZE对齐的片上内核非易失存储区配合utils.rs中的storage_volume!宏分配卷。.ccfg客户配置区通常位于 rom 末尾板卡未定义ccfg区域时不会被写入。.stackNOLOAD ram内核栈放在 SRAM最低地址这样栈向下溢出时进入不可映射/不可访问内存由硬件触发内存故障而非静默破坏数据。.relocateAT _etext ram需搬移的已初始化数据物理上放在 flash_etext处由 Tock 拷贝进 SRAM其中还定义了 RISC-V 全局指针__global_pointer$ . 0x800使编译器能用 12 位立即数访问前 4KB 数据内存。.appsNOLOAD prog应用二进制占位区默认不烧写需要时可用arm-none-eabi-objcopy --set-section-flags .appsLOAD,ALLOC elf使其随内核加载。内含 4 字节0xFF占位避免空 section 被链接器忽略导致 openocd 写失败。.sramNOLOAD ram内核 BSS.sbss/.bss/COMMON与应用内存.app_memory。_eappmem ORIGIN(ram) LENGTH(ram)表明应用使用 SRAM 剩余全部空间。.attributesAT rom 末尾以倒序 TLV格式存放内核元数据TOCK 哨兵 版本 Kernel Flash 区域 App RAM 区域供主机侧工具读取已安装内核信息具体字节布局在脚本内有 ASCII 图示。脚本末尾还有两道ASSERT防线其一确保 attributes 落在 ROM 末尾_eattributes _erom其二在链接收敛的最终 pass 校验text 搬移数据 attributes 未超出 ROM 容量溢出时给出明确错误信息。ENTRY(_stext)则把入口点设为文本段起始Cortex-M 为向量表RISC-V 为_start。板卡侧的实际示例qemu_rv32_virtboards/qemu_rv32_virt/layout.ld在MEMORY中定义三段 QEMU 模拟 DRAM 区域rom 0x80000000、prog 0x80100000、ram 0x80200000额外导出_sflash/_eflash/_ssram/_esram符号供 ePMP 配置使用然后INCLUDE tock_kernel_layout.ld。hailboards/hail/layout.ld两级 INCLUDE——先INCLUDE ./chip_layout.ldsam4l 芯片的内存区域定义再INCLUDE tock_kernel_layout.ld。常见问题与排查要点Boards must provide alayout.ldlink script file板卡 crate 根目录缺少layout.ld检查文件是否存在于 Cargo.toml 所在目录。Incorrect build configuration...RUSTFLAGS 被命令行覆盖导致哨兵标记丢失确认使用的是 unstable cargo 且未手动设置 RUSTFLAGS 环境变量或按上文所述在配置中设置cfg-tock-buildflagssentinel显式放行。Kernel attributes are not at the end of ROM / Text plus relocations plus attributes exceeds...ROM 区域LENGTH(rom)容量不足或rom/prog/ram的 ORIGIN/LENGTH 配置与芯片实际布局不符检查chip_layout.ld中的MEMORY定义。改动链接脚本后未生效正常情况下cargo:rerun-if-changed会自动处理layout.ld及其全部INCLUDE的追踪若手动修改了链接器搜索路径或移除了 build 依赖则需确认[build-dependencies]与[package] build配置完好。小结tock_build_scripts的价值在于把 Tock 板卡构建中必须做对、但容易出错的链接脚本接入与参数校验逻辑收敛为一处一个default_linker_script()调用即完成 RUSTFLAGS 哨兵校验、默认链接脚本搜索路径注入、板卡目录加入搜索路径、链接脚本及其所有 INCLUDE 的变更追踪四件事。配合随 crate 发布的tock_kernel_layout.ld自定义板卡只需专注定义好rom/prog/ram三个内存区域与PAGE_SIZE即可获得与 Tock 官方板卡一致的链接布局、启动语义与 ROM 容量检查。若要在仓库外复用这套能力参照 boards/build.rs 的写法把 build.rs 复制到自己的板卡 crate并在 Cargo.toml 中引入该 crate 即可。赞分享操作系统嵌入式嵌入式OS【免费下载链接】tockA secure embedded operating system for microcontrollers项目地址https://gitcode.com/gh_mirrors/to/tock点击查看免费下载相关推荐RustTraining工程实践build.rs构建脚本与交叉编译完全指南RustTraining工程实践build.rs构建脚本与交叉编译完全指南 RustTraining 是一套面向不同编程背景的 Rust 培训课程仓库其中文档教程Tauri 构建脚本 tauri-build 完全指南从 build.rs 到跨平台产物生成的编译期魔法Tauri 构建脚本 tauri build 完全指南从 build.rs 到跨平台产物生成的编译期魔法 tauri build 是 Tauri 桌面与移动应桌面应用跨平台移动开发conventional-changelog template 包深度解析Markdown 渲染辅助函数、仓库链接构建器与默认模板实现conventional changelog template 包深度解析Markdown 渲染辅助函数、仓库链接构建器与默认模板实现 convention开发工具CLI文档上一篇Apache Spark 访问 OpenStack Swift 对象存储完整指南swift:// 协议、Keystone 认证与 hadoop-cloud 集成下一篇D3PM 图像生成实战指南离散状态空间扩散模型在 CIFAR-10 上的 Flax/JAX 实现创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考