欢迎光临
我们一直在努力

Zephyr学习 - 第一章 West 工作区与 Zephyr 构建流程

第 1 章:West 工作区与 Zephyr 构建流程

学习方式:源码阅读、构建产物分析、native_sim/native/64 运行

1. 本章目标

学完本章,应当能够回答:

  • 当前目录为什么是一个 Zephyr workspace?
  • west、Zephyr、application、module、board 分别是什么?
  • west build 内部依次做了什么?
  • prj.conf 和 overlay 最终去了哪里?
  • 哪些生成文件可以证明自己的判断?
  • 为什么同一个 sample 换一个 board qualifier,构建结果会不同?
  • 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)

    含义:

  • 找到并加载 Zephyr 构建系统;
  • 定义 CMake project;
  • 把 src/main.c 加入 Zephyr 提供的 app target。
  • 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 同时具有两种身份:

  • 它是 west manifest project;
  • 它又通过 imxrt-kit/zephyr/module.yml 成为 Zephyr module。
  • 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 的区别:

    项目ApplicationModule
    角色 一次构建的入口 向 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

    结论:模拟确认。

    从这一行已经可以反推:

  • Zephyr 内核完成初始化;
  • console 驱动可用;
  • main thread 已运行;
  • CONFIG_BOARD_TARGET 最终值为 native_sim/native/64;
  • application 的 main.c 已进入最终可执行文件。
  • 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. 自测问题

    尝试回答:

  • .west/config 和 west.yml 分别负责什么?
  • imxrt-kit 为什么能向 Zephyr 添加驱动和 DTS binding?
  • application 和 module 有什么区别?
  • prj.conf 是最终配置吗?
  • 查配置问题时,为什么先看 .config?
  • 查硬件描述问题时,为什么先看 zephyr.dts?
  • autoconf.h 是谁生成的,给谁使用?
  • native_sim/native/64 中三个部分各表示什么?
  • -p always 解决什么问题?
  • zephyr.map 能帮助排查哪些问题?
  • 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,并通过一个可运行的自定义配置项实验理解依赖和默认值。

    赞(0)
    未经允许不得转载:171主机测评 » Zephyr学习 - 第一章 West 工作区与 Zephyr 构建流程
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址