Zephyr构建系统-配置过程详解

Zephyr构建过程简述一文中说明过Zephyr的构建过程。Zephyr使用CMake进行构建,构建可以分为两个阶段

  • 配置生成阶段
  • 编译阶段

配置生成阶段执行 CMakeLists.txt 和.cmake构建脚本,配置完成后CMake 就有了 Zephyr 构建的内部模型,并且可以生成目标的构建脚本。这些构建脚本决定了编译阶段要执行那些动作,以及这些编译动作之间的顺序和关系。因此只要理解了配置生成阶段的过程,就理解Zephyr的构建编译过程。

Zephyr下CMake只支持生成 Ninja 和 Make配置。配置完成后,可以通过执行生成的构建脚本来开始构建编译阶段。在构建编译阶段,这些构建脚本可以重编译应用程序,在代码修改后不用再进行CMake的配置e。

CMake配置入口 链接到标题

当编译一个Zephyr的应用时,将首先使用应用的CMakeList.txt,例如当执行west build -b mm_feather zephyr/samples/hello_world时, 从CMake系统就会从zephyr/samples/hello_world/CMakeLists.txt开始处理

# SPDX-License-Identifier: Apache-2.0

cmake_minimum_required(VERSION 3.20.0)

find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
project(hello_world)

target_sources(app PRIVATE src/main.c)

进入该CMakeLists.txt,最开始就算查找Zephyr CMake-package并处理

Zephyr CMake-package 链接到标题

Zephyr的CMake package放在zephyr/share/zephyr-package下,在建立Zephyr构建环境的时候会执行west zephyr-export,这条指令将Zephyr的包信息写到~/.cmake/packages/Zephyr下,CMake系统在find_package(Zephyr)时就可以通过包信息就能找到zephyr/share/zephyr-package, 找到zephyr-package后将会按照下面顺序进行cmake处理

zephyr/share/zephyr-package/cmake/ZephyrConfigVersion.cmake
	zephyr/share/zephyr-package/cmake/zephyr_package_search.cmake
	zephyr/cmake/modules/version.cmake
	zephyr/share/zephyr-package/cmake/ZephyrConfig.cmake

Zephyr的CMake配置入口就是zephyr/share/zephyr-package/cmake/ZephyrConfig.cmake,它完成了真正的对Zephyr构建的配置

Zephyr构建配置 链接到标题

ZephyrConfig.cmake将调用zephyr/cmake/modules下的各种.cmake文件和生成的.cmake文件,各级目录的CMakeLists.txt来生成构建配置脚本。这些.cmake和CMakeLists.txt可以分为三大类:

  • 工具和环境配置
  • Zephyr配置文件的生成
  • Zephyr构建源文件添加,编译/链接/目标控制

这三大类生成的配置脚本执行顺序也是按照从上到下执行。

工具和环境配置 链接到标题

ZephyrConfig.cmake会includezephyr/cmake/modules内的.cmake文件,按照下面列表从上到下顺序执行:

  • python.cmake 查找python
  • user_cache.cmake 配置user cache文件夹
  • version.cmake 获取Zephyr版本
  • basic_settings.cmake 对基本设置进行处理(sysbuild)
  • west.cmake 通过west构建时,会进行west的一些处理
  • root.cmake 将Zephyr的一些root路径转换为绝对路径(MODULE_EXT_ROOT,BOARD_ROOT,SOC_ROOT,ARCH_ROOT,SCA_ROOT

环境准备好后就进行下一阶段Zephyr陪葬文件的生成

Zephyr配置文件的生成 链接到标题

ZephyrConfig.cmake会继续includezephyr/cmake/modules内的.cmake文件,按照下面列表从上到下顺序执行:

  • board.cmake 验证构建命令传入的主板是否合法,并设置主板参数
  • shields.cmake 验证构建命令传入的shields是否合法,并设置shields参数
  • snippets.cmake 通过zephyr/scripts/snippets.py读取片段文件,并进行片段变量的设置
  • arch_v1.cmake 对hwmv1的arch进行处理, hwmv1以后将会被废弃
  • hwm_v2.cmake 调用 list_hardware.py 生成构建用 Kconfig 文件,包含了所有hwmv2的Arch和Soc的Kconfig
  • configuration_files.cmake 找到要使用的 Kconfig,DT文件和应用配置所在目录
  • generated_file_directories.cmake 在构建目录中创建生成文件的目录
  • dts.cmake 生成设备树宏和完整的设备树文件
  • kconfig.cmake 处理Kconfig,扫描所有Kconfig项并生成配置项
  • arch_v2.cmake 根据 Kconfig 设置和 arch root 配置 ARCH 设置
  • soc_v1.cmake 根据 Kconfig 设置和 SoC 根目录配置 hwmv1的SoC 设置, 将来hwmv1将会被废弃
  • soc_v2.cmake 根据 Kconfig 设置和 SoC 根目录配置 hwmv2的SoC 设置

Zephyr构建内核源文件添加,编译/链接/目标控制 链接到标题

最后ZephyrConfig.cmake会includezephyr/cmake/modules/kernel.cmake, 该文件会负责添加要加入编译的源代码,建立编译/链接的选项和生成目标文件的控制. 下面列表按照按照从上到下顺序执行:

  • 首先通过下面cmake文件设置工具链和编译选项
    • zephyr/cmake/modules/FindTargetTools.cmake
    • zephyr/cmake/modules/FindScaTools.cmake
    • build/CMakeFiles/3.28.3/CMakeSystem.cmake
    • build/CMakeFiles/3.28.3/CMakeCCompiler.cmake
    • build/CMakeFiles/3.28.3/CMakeCXXCompiler.cmake
    • build/CMakeFiles/3.28.3/CMakeASMCompiler.cmake
    • zephyr/cmake/target_toolchain_flags.cmake
  • 再处理指定主板的cmake,使用的主板不同导入的cmake不同,例如mm_feather的如下:
    • zephyr/boards/madmachine/mm_feather/board.cmake
  • 最后以顶级目录zephyr/CMakeLists.txt开始逐项展开
    • 处理链接选项cmake
    • 依次处理arch/soc/board/subsys/driver下的CMakeLists.txt
    • 处理外部module的CMakeLists.txt
    • 处理外部kernel的CMakeLists.txt
    • 处理产生目标的cmake
    • 处理flash/usage/report的cmake

添加应用代码 链接到标题

在内核的cmake处理完后,回到应用的CMakeLists.txt中添加应用的代码

target_sources(app PRIVATE src/main.c)

关于extensions.cmake 链接到标题

Zephyr在zephyr/cmake/modules/extensions.cmake内封装了大量的CMake函数,在前面提到的所有.cmake和CMakeLists中都使用了这些函数,要更细节的理解这些文件,需要参考extensions.cmake.

小节 链接到标题

一图胜前言,下面这张图总结了Zephyr CMake生成构建配置各文件的依赖关系,需要注意的是这张图只表示的层级关系,图中的叶子节点都还可能有下一级

参考 链接到标题

https://docs.zephyrproject.org/3.6.0/build/cmake/index.html