第 1 章:West 工作区与 Zephyr 构建流程
学习方式:源码阅读、构建产物分析、native_sim/native/64 运行
1. 本章目标
学完本章,应当能够回答:
2. 先建立五个基本概念
2.1 Workspace
Workspace 是由 west 管理的一组 Git 工程和配置目录。它不是某个单独的应用。
当前 workspace 根目录是:
/home/yff/project/
使用以下命令确认:
cd ~/project/
west topdir
实际输出:
/home/yff/project/
结论:编译确认。
2.2 Manifest project
Manifest 决定 workspace 包含哪些工程、每个工程放在哪里以及使用哪个 revision。
.west/config 中记录:
[manifest]
path = imxrt-kit
file = west.yml
所以当前 workspace 的 manifest 文件是:
imxrt-kit/west.yml
可用命令确认:
west manifest –path
实际输出:
/home/yff/project/imxrt-kit/west.yml
这里的 manifest project 是 imxrt-kit。它不仅保存产品代码,还决定需要拉取 Zephyr 和哪些 HAL 模块。
2.3 Zephyr base
Zephyr base 是 Zephyr 内核源码根目录:
~/project/zephyr
.west/config 中还有:
[zephyr]
base = ./zephyr/
当前版本:
git -C zephyr describe –tags –always –dirty
输出:
v4.1.0-rc1-dirty
dirty 表示 Zephyr 仓库存在未提交修改。它不一定是错误,但记录构建环境时必须保留这一信息。
2.4 Application
Application 是一次构建的应用入口,通常至少包含:
application/
├── CMakeLists.txt
├── prj.conf
└── src/
└── main.c
本章使用的 application 是:
zephyr/samples/hello_world
它的 CMakeLists.txt 核心内容:
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
project(hello_world)
target_sources(app PRIVATE src/main.c)
含义:
main.c 只有:
int main(void)
{
printf("Hello World! %s\\n", CONFIG_BOARD_TARGET);
return 0;
}
这个例子虽然简单,却同时验证了 application、Kconfig 宏、console 和主线程启动。
2.5 Board 与 qualifier
Board 描述一个构建目标的硬件或模拟平台。
本章使用:
native_sim/native/64
它可以拆成:
board name : native_sim
SoC : native
variant : 64
在 zephyr/boards/native/native_sim/board.yml 中可以看到:
boards:
– name: native_sim
socs:
– name: native
variants:
– name: "64"
因此 native/64 不是目录名的随意拼接,而是 board 定义的一部分。
3. 当前 workspace 的工程组成
命令:
west list -f '{name}\\t{path}\\t{revision}'
当前主要工程:
| manifest | imxrt-kit | 产品 application、外置驱动、board、DTS、manifest |
| zephyr | zephyr | Zephyr 内核、子系统、驱动框架、官方 samples |
| cmsis | modules/hal/cmsis | Arm CMSIS |
| hal_nxp | modules/hal/nxp | NXP MCUXpresso HAL |
| hal_nordic | modules/hal/nordic | Nordic HAL |
| hal_stm32 | modules/hal/stm32 | STM32 HAL |
imxrt-kit/west.yml 使用 Zephyr manifest 的 import,并通过 allowlist 只引入需要的模块。这说明:
west manifest
├── 决定 Zephyr revision
└── 决定需要哪些外部 modules/HAL
4. Module 与 Application 的区别
imxrt-kit 同时具有两种身份:
module.yml 中:
build:
kconfig: Kconfig
cmake: .
settings:
board_root: .
dts_root: .
含义:
- 把 imxrt-kit/Kconfig 合并进 Zephyr Kconfig 树;
- 构建时加载 imxrt-kit/CMakeLists.txt;
- 从 imxrt-kit/boards 查找外置 board;
- 从 imxrt-kit/dts 查找 binding 和 DTS 内容。
Application 与 module 的区别:
| 角色 | 一次构建的入口 | 向 Zephyr 提供可复用能力 |
| 常见内容 | main.c、prj.conf、overlay | 驱动、库、Kconfig、board、binding |
| 每次构建数量 | 通常一个 | 可以有多个 |
| 当前例子 | cm33_cpu0、hello_world | imxrt-kit、hal_nxp |
5. west build 到底做了什么
本章成功执行的命令:
cd ~/project/
export ZEPHYR_SDK_INSTALL_DIR=/home/yff/zephyr-sdk/zephyr-sdk-0.17.1
source zephyr/zephyr-env.sh
west build \\
-b native_sim/native/64 \\
zephyr/samples/hello_world \\
–build-dir /mnt/c/study/1-zephyr/work/ch01_hello_native64 \\
-p always
参数解释:
| -b native_sim/native/64 | 选择 board、SoC qualifier 和 64 位 variant |
| zephyr/samples/hello_world | application 源码目录 |
| –build-dir … | 构建产物目录 |
| -p always | 每次先 pristine,避免旧 CMake cache 干扰 |
5.1 阶段一:west 解析 workspace
west 找到:
- workspace 根目录;
- manifest;
- Zephyr base;
- application;
- board target;
- build directory。
5.2 阶段二:CMake 加载 Zephyr
application 的:
find_package(Zephyr REQUIRED …)
会进入 Zephyr 的 CMake 构建系统。此时开始发现 modules、board、toolchain 和构建配置。
5.3 阶段三:选择 board、SoC 和 toolchain
实际输出确认:
Board: native_sim, qualifiers: native/64
Found host-tools: zephyr 0.17.1
Found toolchain: host (gcc/ld)
Found BOARD.dts: …/native_sim_64.dts
需要区分:
- host tools:例如 DTC;
- target toolchain:把 C 源码编成目标程序;
- native_sim 的 target 恰好也是当前 Linux 主机。
5.4 阶段四:生成最终 Devicetree
构建系统合并 board DTS、DTSI、overlay 后生成:
work/ch01_hello_native64/zephyr/zephyr.dts
同时生成:
zephyr/include/generated/zephyr/devicetree_generated.h
第一个文件适合人阅读,第二个文件供 C 预处理宏使用。
5.5 阶段五:合并 Kconfig
实际日志:
Loaded configuration '…/native_sim_64_defconfig'
Merged configuration '…/samples/hello_world/prj.conf'
Configuration saved to '…/zephyr/.config'
Kconfig header saved to '…/zephyr/autoconf.h'
合并关系可以先简化理解为:
SoC/board 默认配置
+ application/prj.conf
+ 其他 conf、shield、snippet 等输入
-> 最终 .config
-> autoconf.h
第 2 章会专门研究优先级、依赖和 Kconfig 表达式。
5.6 阶段六:编译和链接
Ninja 编译:
- application 的 main.c;
- Zephyr kernel;
- console/timer 等启用的驱动;
- board 与 SoC 实现;
- 启用的库和子系统。
最后生成 zephyr.elf 和 native simulator 可执行文件。
6. 本章运行结果
运行命令:
west build \\
–build-dir /mnt/c/study/1-zephyr/work/ch01_hello_native64 \\
-t run
实际输出:
*** Booting Zephyr OS build v4.1.0-rc1 ***
Hello World! native_sim/native/64
结论:模拟确认。
从这一行已经可以反推:
7. 用生成文件证明构建结果
7.1 .config
位置:
C:\\study\\1-zephyr\\work\\ch01_hello_native64\\zephyr\\.config
本次关键值:
CONFIG_BOARD="native_sim"
CONFIG_BOARD_TARGET="native_sim/native/64"
CONFIG_64BIT=y
CONFIG_CONSOLE=y
CONFIG_PRINTK=y
CONFIG_MULTITHREADING=y
CONFIG_MAIN_STACK_SIZE=1024
CONFIG_SYS_CLOCK_TICKS_PER_SEC=100
用途:确认 Kconfig 最终选择。
7.2 autoconf.h
位置:
zephyr/include/generated/zephyr/autoconf.h
其中对应内容:
#define CONFIG_BOARD "native_sim"
#define CONFIG_BOARD_TARGET "native_sim/native/64"
#define CONFIG_64BIT 1
#define CONFIG_MULTITHREADING 1
#define CONFIG_MAIN_STACK_SIZE 1024
这解释了为什么 C 代码可以直接使用 CONFIG_BOARD_TARGET。
一般先查 .config,只有研究预处理或编译问题时才深入 autoconf.h。
7.3 zephyr.dts
本次最终 DTS 中包含:
chosen {
zephyr,console = &uart0;
};
并且 uart0 的 compatible 为:
zephyr,native-posix-uart
这说明 printf() 最终输出到哪里,不只是由 C 代码决定,还与 chosen console 和对应设备驱动有关。
7.4 zephyr.map
Linker map 用于分析:
- 某个函数是否进入固件;
- 某个符号来自哪个 object/library;
- FLASH/RAM 占用;
- 静态变量放在哪个 section。
示例:
rg -n "main|z_cstart|k_thread" \\
/mnt/c/study/1-zephyr/work/ch01_hello_native64/zephyr/zephyr.map
7.5 ELF 与最终可执行文件
本次主要文件:
zephyr.elf # Zephyr ELF,包含符号和调试信息
zephyr.exe # native_sim runner 可执行文件
后续可以使用:
file zephyr/zephyr.elf
size zephyr/zephyr.elf
nm -n zephyr/zephyr.elf
objdump -h zephyr/zephyr.elf
学习链接、section、设备初始化时会再次使用。
8. 建议的日常命令
cd ~/project/
# workspace 信息
west topdir
west manifest –path
west list
# 查看可用 board
west boards | less
west boards | rg native_sim
# 构建并运行主机模拟程序
export ZEPHYR_SDK_INSTALL_DIR=/home/yff/zephyr-sdk/zephyr-sdk-0.17.1
source zephyr/zephyr-env.sh
west build \\
-b native_sim/native/64 \\
zephyr/samples/hello_world \\
–build-dir /mnt/c/study/1-zephyr/work/ch01_hello_native64 \\
-p always
west build \\
–build-dir /mnt/c/study/1-zephyr/work/ch01_hello_native64 \\
-t run
# 检查最终配置和设备树
rg '^CONFIG_(BOARD|BOARD_TARGET|64BIT|PRINTK|MULTITHREADING)=' \\
/mnt/c/study/1-zephyr/work/ch01_hello_native64/zephyr/.config
less /mnt/c/study/1-zephyr/work/ch01_hello_native64/zephyr/zephyr.dts
9. 自测问题
尝试回答:
10. 本章结论
Zephyr 构建不是“把 main.c 交给 GCC”这么简单,而是:
west workspace/manifest
-> application + modules + board
-> CMake 发现构建组成
-> Devicetree 生成硬件描述
-> Kconfig 生成软件配置
-> 编译 kernel、drivers、subsystems、app
-> linker 生成 ELF 和目标产物
最重要的排查习惯:
软件配置问题 -> 查 zephyr/.config
硬件描述问题 -> 查 zephyr/zephyr.dts
宏展开问题 -> 查 generated headers
符号/内存问题 -> 查 zephyr.map 和 zephyr.elf
下一章:Kconfig 配置系统——从 prj.conf 到 .config,并通过一个可运行的自定义配置项实验理解依赖和默认值。



