【OS zephyr】编译分析(1)
目录
2、build.sh/zephyr-env.sh/build.py
阶段一:配置阶段(Configuration) - 由 west + CMake 主导
阶段二:编译阶段(Compilation) - 由编译器(如 GCC)主导
阶段三:链接阶段(Linking) - 由链接器(如 ld)主导
阶段四:后处理阶段(Post-processing) - 由 objcopy 等工具主导
1、概述
编译采用方式:python + west + cmake + ninja
编译最开始只需要make工具依赖makefile中的编译工具,链接工具,归档工具(打包库文件时需要),编译规则。后面由于工程庞大编译,裁剪,模块处理,跨平台方便才慢慢的引入了cmake, python, west 这些工具。
2、build.sh/zephyr-env.sh/build.py
build运行参数:
#python 入口参数处理
def main(argv):
parser = argparse.ArgumentParser()
parser.add_argument('-n', dest="cfgdel", help="remove cur build_config", action="store_true", required=False)
parser.add_argument('-c', dest="clear", help="remove board out dir and build_config", action="store_true", required=False)
parser.add_argument('-m', dest='menuconfig', help="do sdk Configuration", action="store_true", default=False)
parser.add_argument('-p', dest='pack', help="pack firmware only", action="store_true", default=False)
parser.add_argument('-l', dest="libname", help="build lib", required=False)
parser.add_argument('-s', dest="silent", help="silent mode", action="store_true", required=False)
parser.add_argument('-t', dest="sample", help="build sample, default build applicaction", action="store_true", required=False)
parser.add_argument('-u', dest="test", help="build test, default build applicaction", action="store_true", required=False)
parser.add_argument('-a', dest="hal_sample", help="build hal sample, default build applicaction", action="store_true", required=False)
parser.add_argument('-k', dest="bkeil", help="build by keil, default by gcc ", action="store_true", required=False)
parser.add_argument('-o', dest="old_checksum", help="use old checksum intead of rsa signature", action="store_true", required=False)
parser.add_argument('-S', dest="need_sign", help="need dynamic sign", action="store_true", required=False)
print("build")
args = parser.parse_args()
if args.sample == True: # zephyr/samples use -t
sdk_application_dir = sdk_samples_dir
elif args.test == True: # zephyr/tests use -u
sdk_application_dir = sdk_tests_dir
elif args.hal_sample == True: # ./samples use -a
sdk_application_dir = hal_samples_dir
else: # application
sdk_application_dir = sdk_app_dir
生成.build_config文件:
1、通过read_choice()s配置。
2、build_config_file = os.path.join(sdk_root, "build/.build_config")
fp = open(build_config_file,"w") #创建.build_config文件
fp.write("# Build config\n")
fp.write("BOARD=" + board_conf + "\n")
fp.write("APPLICATION=" + application + "\n")
fp.write("SUB_APP=" + sub_app + "\n")
fp.write("APP_CONF=" + app_conf + "\n")
fp.close()
启用west构建:
1、build_zephyr_app_by_gcc(board_conf, sdk_build, application_path, application_cfg_reldir, args.libname, args.silent)
2、函数中拼接west 命令:
build_args = "west build -p auto -b " + board + " -d " + out_dir + " " + app_dir
print("\n bulid cmd:%s \n\n" %(build_args))
3、ret = os.system(build_args) #运行west build命令。
west build命令其实执行的是:……\zephyr\scripts\west_commands\build.py。
4、class build.do_run:west 工具会创建这个类的实例,并调用其 do_run方法。
5、do_run():调用_run_cmake(),_run_build()。这两者会引用zcmake.py中的run_cmake(), run_build()接口。
6、cmake命令会引入CMakeLists.txt入口地址,开始执行CMakeLists.txt。
3、编译4阶段
阶段一:配置阶段(Configuration) - 由 west + CMake 主导
这个阶段的主要任务是生成构建目录(如 build/)中的所有构建规则和配置文件。这是 Zephyr 构建最复杂、最独特的部分。
输入:CMakeLists.txt(应用程序和 Zephyr 本身的);Kconfig文件 (应用程序的 prj.conf、板级配置、特性配置等);设备树源文件 (.dts, .dtsi, .overlay);源码文件结构
核心过程:解析所有 Kconfig文件,根据 prj.conf和板级默认配置生成最终的配置头文件。
处理设备树(DTS):编译设备树源文件,生成一个描述硬件布局的 C 头文件。
生成构建规则: 为每一个需要编译的源文件生成对应的编译命令和依赖关系。
关键输出 (位于 build/目录下):
* zephyr/.config: 最终的配置汇总,包含了所有 CONFIG_*宏的值。
* zephyr/include/generated/autoconf.h: 由 .config自动生成的 C 语言头文件。源码通过 #include <autoconf.h>和 #ifdef CONFIG_XXX来获取配置。zephyr/include/generated/devicetree_unfixed.h: 设备树编译后生成的头文件。源码通过 #include <devicetree.h>和类似 DT_NODELABEL(uart0)的宏来访问硬件信息。zephyr/linker.cmd: 最终使用的链接脚本,它整合了架构、SOC 和板级的所有链接片段,严格定义了内存布局。
build.ninja (或 Makefile): 真正的构建规则文件,包含了所有编译、链接命令。后续的 west build或 ninja命令就是读取这个文件来工作的。
cmake根据CMakeLists.txt文件(学名:组态档)去生成makefile,而CMakeLists.txt文件是需要自己手写的。
阶段二:编译阶段(Compilation) - 由编译器(如 GCC)主导
阶段三:链接阶段(Linking) - 由链接器(如 ld)主导
阶段四:后处理阶段(Post-processing) - 由 objcopy 等工具主导
4、cmake
CMake 的强大之处就在于它能够为各种各样的构建环境和工具链生成对应的构建文件。CMake 通过 “生成器 (Generators)” 来定义输出的构建系统类型。生成器主要分为两大类:单配置生成器 和 多配置生成器。CMake 可以生成哪些构建方式?
Unix Makefiles: 生成标准的 GNU Make 文件 (Makefile),用于 Linux、macOS 或类 Unix 环境。
Ninja: 生成 Ninja 构建文件 (build.ninja)。Ninja 是一个专注于速度的小型构建系统,比 Make 更快。
MinGW Makefiles: 生成用于 Windows 上 MinGW 或 MSYS2 环境的 Makefiles。
NMake Makefiles: 生成用于 Microsoft nmake.exe的 Makefiles。nmake是 Visual Studio 自带的一个轻量级命令行构建工具。
Watcom WMake: 生成用于 Watcom WMake 的 Makefiles (较少使用)。
| 组件 | 角色 | 作用 | 没有它会怎样 |
|---|---|---|---|
| .c/.h/.ld | 材料 | ||
| GCC/Clang | 工人 | 编译、链接单个文件 | 无法将源代码转换成机器码,根本不能构建程序 |
| Make/Ninja | 项目经理 | 解析依赖、调度任务、增量/并行构建 | 开发效率极低,无法进行大规模项目管理,因为工人看不懂施工图纸。 |
| Makefile/build.ninja | 施工图纸 | 用特定语法定义构建目标、依赖和规则 | “项目经理”无事可做,不知道要建造什么以及如何建造 |
例如:
# 使用 gcc
cmake -S . -B build -G Ninja \ -DCMAKE_C_COMPILER=<c-compiler-path> \ -DCMAKE_CXX_COMPILER=<cxx-compiler-path>
# 使用 Clang
cmake -S . -B build -G Ninja \ -DCMAKE_C_COMPILER=clang \ -DCMAKE_CXX_COMPILER=clang++ \ -DCMAKE_BUILD_TYPE=RelWithDebInfo
zephyr工程中……\zephyr\scripts\west_commands\build.py有部分类似定义。
cmake脚本入口
CMakeLists.txt:find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE)
CMake 的 find_package命令会按照预定义的规则去搜索两个可能存在的文件:
<PackageName>Config.cmake (现代首选)。zephyr中会调用\zephyr-package\cmake\ZephyrConfig.cmake
Find<PackageName>.cmake (传统模块)
step1:ZephyrConfig.cmake-> include(zephyr_default NO_POLICY_SCOPE)
step2:include(zephyr_default) -> zephyr_default.cmake -> include(kernel)
step3:include(kernel) -> kernel.cmake -> {
zephyr_library_named(app) #创建app library
set_property(TARGET app PROPERTY ARCHIVE_OUTPUT_DIRECTORY app)
add_subdirectory(${ZEPHYR_BASE} ${__build_dir})#增加zephyr根目录,执行目录下的CMakelists.txt;……\application\hyt_radio\outdir\ats3239_dvb_ext_nor,执行目录下的CMakeCache.txt。
}
step4:
add_library(zephyr_interface INTERFACE)#创建zephyr_interface library
zephyr_library_named(zephyr)#创建zephyr library
5、west
west build:Zephyr 的项目管理工具。Zephyr 官方开发的元工具,用于管理 Zephyr 项目和工作流。构建只是其功能之一。它在构建中做什么? 当您运行 west build时,它背后做了很多事情:
配置阶段:
这个阶段会处理 Kconfig 和 设备树,生成 autoconf.h和 devicetree.h等文件。调用 CMake,并为其设置一长串复杂的参数(-DCMAKE_TOOLCHAIN_FILE, -DBOARD=<board>, -DCMAKE_EXPORT_COMPILE_COMMANDS=ON等)。找到正确的 Zephyr 源码路径、应用程序源码路径。
解析你的命令行参数(如 -b <board>)。
生成阶段:
CMake 运行后,会根据 CMakeLists.txt文件生成构建脚本。默认情况下,这个构建脚本就是 build.ninja文件。
构建阶段:
west自动调用 ninja 来执行这个新生成的 build.ninja文件。你看到的编译输出和错误,实际上都是由 ninja工具产生的。
它的价值:它为你隐藏了所有复杂的 CMake 配置细节。你不需要记得那些繁琐的 -D变量,只需要简单地写 west build -b nucleo_f411re。因此,west build是对 ninja(和 cmake)的封装和自动化。它让你用一条简单的命令就能完成复杂的嵌入式项目构建,而无需手动处理 CMake 生成、Kconfig 解析和设备树编译等繁琐步骤。
6、FAQ
Q1:zephyr编译时报错如下:fatal error: opening dependency file modules\hal_acts\drivers\audio\phy_falcon\CMakeFiles\..__hal__actions__drivers__audio__phy_falcon.dir\phy_audio_dac.c.obj.d: No such file or directory
A1:Windows 路径长度限制(最常见原因)Windows 有 260 个字符的路径长度限制(MAX_PATH)。从错误信息看,您的路径很可能超过了这个限制。缩短项目路径或配置Windows为【启用 Win32 长路径】。
更多推荐



所有评论(0)