Zephyr 构建系统、Kconfig 与设备树
1. 构建入口
典型应用:
1 | cmake_minimum_required(VERSION 3.20.0) |
find_package(Zephyr) 找到 Zephyr package 后,加载 cmake/modules/zephyr_default.cmake。该文件按严格顺序加载:
1 | workspace/application configuration |
DTS 先于 Kconfig 的主要原因是部分 Kconfig 默认值和依赖可读取设备树信息。
2. west build 到最终镜像
1 | west build -b <board> <app> |
常见输出:
1 | build/ |
3. CMake target 模型
根 CMakeLists.txt 创建:
zephyr_interface:承载全局 include、defines、compile/link options;zephyr:通用 catch-all library;- 多个
zephyr_library_named()子库; app:应用源码 target;zephyr_pre0、zephyr_pre1、zephyr_final:链接阶段。
Zephyr 不直接把所有源文件堆入一个 target。各目录使用:
1 | zephyr_library() |
因此“配置为 n”通常意味着源码根本不进入编译。
4. 多阶段链接
根 CMakeLists.txt 最多执行三阶段:
zephyr_pre0- section 地址仍可能变化;
zephyr_pre1- section 大小和地址固定;
zephyr_final- 最终 ELF。
需要额外阶段的典型功能:
CONFIG_DEVICE_DEPS:生成 device dependency handles;CONFIG_GEN_ISR_TABLES:生成 ISR table;CONFIG_USERSPACE:生成 kernel object hash table;- userspace application memory partitions。
生成器必须先观察预链接 ELF 中的符号/section,再产生 C/二进制对象参与下一次链接。
5. Kconfig
总入口 Kconfig 只加载 Kconfig.zephyr。后者继续聚合 arch、SoC、board、drivers、subsys、lib 和 application Kconfig。
配置来源通常按以下层次组合:
1 | SoC/board defconfig |
5.1 关键概念
config:定义 symbol;default:满足条件时给默认值;depends on:控制 symbol 可见/可选;select:强制另一个 bool 为 y,不检查其依赖,需谨慎;imply:弱建议;choice:互斥选择;menuconfig:可进入子菜单的配置项。
最终真相是 .config,不是 prj.conf。用户请求值可能因依赖不满足而被丢弃,并产生 warning。
5.2 代码使用
1 |
|
autoconf.h 通过构建系统自动注入,无需应用手动 include。
6. Devicetree 输入合并
设备树输入大致为:
1 | architecture/SoC .dtsi |
核心构建逻辑在 cmake/modules/dts.cmake,解析器位于 scripts/dts/,bindings 位于 dts/bindings/。
7. Binding 与 compatible
binding YAML 描述:
compatible;include的基础 schema;properties类型、required、enum、default;child-binding;- bus/child-bus;
- specifier cells,如
gpio-cells、interrupt-cells。
设备节点:
1 | sensor@48 { |
驱动:
1 |
|
匹配不是运行时字符串扫描。compatible 经生成头转换为 C 宏,实例宏在编译期展开成静态对象。
8. 常用 DTS 宏
节点定位:
1 | DT_NODELABEL(name) |
属性读取:
1 | DT_PROP(node, prop) |
遍历与条件:
1 | DT_NODE_HAS_STATUS(node, okay) |
设备规格:
1 | GPIO_DT_SPEC_GET(...) |
spec 结构把 controller struct device *、pin/address/channel 和 flags 打包,应用无需重复解析 phandle cells。
9. Board、SoC 与 Arch 选择
-b <board> 触发:
- 从 board roots 查找
board.yml; - 解析 board、revision、SoC/qualifier;
- 加载 board DTS 和 defconfig;
- SoC 描述选择 architecture;
- 工具链和 linker 根据 architecture/SoC 配置;
- board runner 决定 flash/debug 命令。
Hardware model v2 可用类似:
1 | board[/soc[/cpucluster]] |
一个 board.yml 可以声明多个 board 或多个 SoC 变体。
10. Zephyr modules
west manifest 中的 project 可通过 zephyr/module.yml 注册:
- CMake;
- Kconfig;
- DTS root;
- board/SoC root;
- samples/tests;
- sysbuild。
cmake/modules/zephyr_module.cmake 和脚本扫描 workspace,生成模块列表。模块不一定在 Zephyr 主树中,例如 MCUboot、HAL、crypto 库通常位于相邻目录。
11. Sysbuild
普通 build 只构建一个 Zephyr image;sysbuild 管理多个相互依赖 image:
1 | sysbuild |
每个 image 有独立:
- CMake cache;
.config;- DTS;
- build 目录。
SB_CONFIG_* 控制 sysbuild 域,不能与 image 内 CONFIG_* 混用。MCUboot 联合构建会把 slot/footer、签名和依赖参数传递给应用 image。
12. Linker 与 iterable sections
Zephyr linker script 由 arch/SoC linker fragments、公共 section 定义和应用 snippets 组合。
关键用途:
.text/.rodata/.data/.bss/noinit;- init entry;
- device objects;
- shell commands;
- logging metadata;
- ztest suites;
- network L2;
- userspace objects。
STRUCT_SECTION_ITERABLE(type, name) 把对象放入命名 section;运行时使用 STRUCT_SECTION_FOREACH() 遍历。该模式减少显式注册代码和动态分配。
13. 常用构建命令
1 | west build -b <board> -d build/<name> <app> |
需要完全重新求解 board/DTS/Kconfig 时使用:
1 | west build -p always ... |
不要通过手改 build/zephyr/.config 或生成头文件保存配置;下次 configure 会覆盖。
14. 构建问题定位
Kconfig warning
检查:
- symbol 是否真实存在;
- 依赖是否满足;
- 是否被 choice 排除;
.config中最终值;menuconfig中 help 和 dependency。
DTS error
检查:
build/zephyr/zephyr.dts;- 对应 binding;
status = "okay";reg、interrupt、clock、pinctrl cells;- overlay 是否实际被 CMake 发现。
__device_dts_ord_N
在 devicetree_generated.h 查 ordinal 对应节点,然后确认:
- 节点 enabled;
- 驱动 Kconfig 为 y;
- 驱动 CMake 加入源文件;
- compatible 与
DT_DRV_COMPAT一致; - bus/controller device 也已创建。
链接溢出
查看 zephyr.map、rom_report、ram_report,区分:
- flash payload;
- RAM
.data/.bss/noinit; - thread stack;
- heap;
- logging buffers;
- MCUboot header/trailer 保留区。
正在加载留言…