9.5 KiB
带版本号固件产物生成说明
1. 对应提交
f5b4bd8 build: add versioned firmware artifact
该提交在不改变 ESP-IDF 原有应用镜像和烧录流程的前提下,为每次构建额外生成一份带项目版本号的固件文件,方便 OTA 发布、固件归档和版本追踪。
2. 问题原因
2.1 默认应用镜像名称无法区分版本
ESP-IDF 默认按照项目名称生成应用镜像。本项目的项目名为 TQ_Cat_Code,因此默认产物固定为:
build/TQ_Cat_Code.bin
无论当前固件版本是 1.0.1、1.0.2 还是后续版本,文件名都不会变化。连续构建或复制不同版本时,新文件容易覆盖旧文件,单看文件名也无法判断固件版本。
2.2 OTA 发布和固件归档依赖人工改名
在增加本次构建逻辑之前,如果需要向 OTA 服务上传带版本标识的固件,只能在构建完成后手工复制或重命名,例如:
TQ_Cat_Code.bin -> TQ_Cat_Code-1.0.2.bin
这种方式存在以下问题:
- 人工填写的版本号可能与固件内部版本不一致。
- 重命名时可能选错构建目录或上传旧文件。
- 自动发布脚本无法依赖稳定、可预测的版本化文件名。
- 多个版本放在同一目录时,固定名称不能提供有效区分。
2.3 不能直接替换 ESP-IDF 的默认产物
ESP-IDF 的烧录参数和项目描述仍引用 TQ_Cat_Code.bin。如果直接修改默认应用镜像名称,可能影响:
idf.py flash的默认烧录流程;flasher_args.json等构建元数据;- 已经依赖固定文件名的开发和生产脚本。
因此,本次修改选择保留默认产物,并额外生成版本化副本,而不是改变 ESP-IDF 的标准输出名称。
3. 解决方式
3.1 从 ESP-IDF 构建属性读取项目版本
提交在 project() 完成项目初始化后读取 PROJECT_VER:
idf_build_get_property(TQ_PROJECT_VERSION PROJECT_VER)
本项目通过根目录的 version.txt 管理版本。ESP-IDF 配置项目时会解析该文件,并将结果写入 PROJECT_VER。提交创建时的项目版本为:
1.0.2
构建逻辑直接使用 ESP-IDF 已解析的版本属性,而不是在 CMake 中重复读取或硬编码版本号。这样可以保证文件名中的版本与固件构建版本来自同一数据源。
3.2 组合版本化固件路径
版本化产物使用“项目名-项目版本.bin”的命名规则:
set(TQ_VERSIONED_FIRMWARE
"${CMAKE_BINARY_DIR}/${CMAKE_PROJECT_NAME}-${TQ_PROJECT_VERSION}.bin")
各变量在当前项目中的值为:
CMAKE_BINARY_DIR = build 目录
CMAKE_PROJECT_NAME = TQ_Cat_Code
TQ_PROJECT_VERSION = 1.0.2
因此最终输出路径为:
build/TQ_Cat_Code-1.0.2.bin
版本升级后不需要修改构建脚本。例如将 version.txt 更新为 1.0.3,重新配置并构建后,产物会自动变为:
build/TQ_Cat_Code-1.0.3.bin
3.3 在应用镜像生成后复制版本化副本
提交新增了一个默认参与构建的自定义目标:
add_custom_target(versioned_firmware ALL
COMMAND ${CMAKE_COMMAND} -E copy_if_different
"${CMAKE_BINARY_DIR}/${CMAKE_PROJECT_NAME}.bin"
"${TQ_VERSIONED_FIRMWARE}"
DEPENDS app
BYPRODUCTS "${TQ_VERSIONED_FIRMWARE}"
COMMENT "Creating versioned firmware ${CMAKE_PROJECT_NAME}-${TQ_PROJECT_VERSION}.bin"
VERBATIM
)
这段代码的行为如下。
versioned_firmware ALL
定义名为 versioned_firmware 的构建目标。ALL 表示执行常规项目构建时会自动执行该目标,无需额外运行单独命令。
copy_if_different
使用 CMake 自带的跨平台复制命令,将默认应用镜像复制为版本化文件:
build/TQ_Cat_Code.bin
-> build/TQ_Cat_Code-1.0.2.bin
只有源文件与目标文件内容不同时才会重新写入目标文件,可以避免未发生变化时进行无意义覆盖。该操作只是字节复制,不会再次编译、链接或修改固件内容。
DEPENDS app
声明版本化目标依赖 ESP-IDF 的 app 目标。CMake 必须先完成应用镜像构建,随后才能复制文件,避免在源 .bin 尚未生成时执行复制。
BYPRODUCTS
将版本化 .bin 声明为该目标的构建副产物,使 CMake 和底层构建工具能够识别这个文件由构建系统生成,而不是人工放入构建目录的未知文件。
COMMENT
构建过程中输出明确提示,例如:
Creating versioned firmware TQ_Cat_Code-1.0.2.bin
开发人员可以通过构建日志确认版本化产物生成步骤已执行。
VERBATIM
要求 CMake 按参数原意生成命令,正确处理路径中的空格、引号和平台差异,降低命令转义导致复制失败的风险。
4. 完整执行流程
构建过程变为:
读取 version.txt
|
v
ESP-IDF 设置 PROJECT_VER
|
v
编译并链接 app
|
v
生成 build/TQ_Cat_Code.bin
|
v
versioned_firmware 目标执行复制
|
v
生成 build/TQ_Cat_Code-1.0.2.bin
最终两个应用镜像同时存在:
build/TQ_Cat_Code.bin
build/TQ_Cat_Code-1.0.2.bin
两者内容完全相同,区别仅在文件名。当前工作区的实际构建结果中,两份文件大小一致,SHA-256 也一致:
baa959fda9572c249ceaf6b8937d35940bc4c7dece2814fa2daebe1c616abc6d
5. 解决成果
5.1 固件版本可以直接从文件名识别
版本信息进入构建产物名称后,无需打开固件或查询构建记录,即可识别文件对应的项目版本。
5.2 降低 OTA 上传选错版本的概率
OTA 发布人员或自动化脚本可以直接选择带版本号的固件文件,避免手工改名时版本号与实际固件不一致。
5.3 支持多个版本并行归档
不同版本使用不同文件名,可以在发布目录、测试目录或制品库中同时保存:
TQ_Cat_Code-1.0.1.bin
TQ_Cat_Code-1.0.2.bin
TQ_Cat_Code-1.0.3.bin
这有利于版本回溯、测试对比和问题复现。
5.4 保持原有开发与烧录流程兼容
默认的 TQ_Cat_Code.bin 仍然生成,ESP-IDF 的烧录参数没有改变。因此原有的构建、串口烧录和调试命令无需调整。
5.5 不增加固件运行时开销
修改只发生在构建阶段,没有增加设备端代码、任务、内存、Flash 占用或启动时间。版本化文件也不是另一份不同的固件镜像,只是原应用镜像的副本。
6. 后续影响
6.1 构建目录磁盘占用增加
构建目录会额外保存一份与应用镜像等大的文件。当前应用镜像约为 2.1 MiB,因此单次当前版本构建会增加约 2.1 MiB 的磁盘占用。
该影响只存在于开发机或构建服务器,不会使设备 Flash 中出现两份应用镜像,也不会增加 OTA 下载大小。
6.2 旧版本产物不会被自动删除
当版本从 1.0.2 更新为 1.0.3 后,新构建会生成新文件,但原来的版本化文件可能继续保留:
TQ_Cat_Code-1.0.2.bin
TQ_Cat_Code-1.0.3.bin
这便于本地归档,但也可能让长期复用的构建目录逐渐积累旧产物。发布脚本不应简单选择目录中任意一个带版本号的 .bin,而应根据当前 PROJECT_VER 计算准确文件名。需要清理时,可以通过完整清理构建目录移除历史副产物。
6.3 版本变化后必须重新配置构建系统
版本化路径在 CMake 配置阶段根据 PROJECT_VER 生成。修改 version.txt 后,应通过正常的 ESP-IDF 构建流程触发重新配置,确保目标文件名使用新版本。持续集成环境使用干净构建目录时不会受到这一问题影响。
6.4 该文件只是应用镜像,不是完整烧录包
TQ_Cat_Code-1.0.2.bin 只对应应用程序分区。它不包含以下独立镜像:
- Bootloader;
- 分区表;
- OTA data 初始化镜像;
- 独立模型分区镜像。
当前 LCD 图片和提示音已包含在应用镜像内,会随应用 OTA 一起更新。
该文件适合应用分区 OTA,不能被误认为包含全部分区的整机合并烧录镜像。工厂烧录仍需按照 ESP-IDF 生成的烧录参数写入各个分区。
6.5 OTA 服务和发布脚本需要明确选择规则
新增文件不会自动改变 OTA 上传流程,也不会自动把固件发布到服务器。后续自动化应明确:
- 从当前项目版本计算版本化文件名;
- 上传前校验文件存在且构建成功;
- 计算并记录文件大小与 SHA-256;
- 保证 OTA 元数据中的版本、大小和摘要与该文件一致。
6.6 项目名或版本字符串会直接进入文件名
文件名由 CMAKE_PROJECT_NAME 和 PROJECT_VER 直接组合。当前值只包含适合文件名的字母、数字、下划线、点和连字符,不存在兼容性问题。后续如果引入带斜杠、空格或其他特殊字符的版本规则,需要额外确认制品库、上传脚本和目标文件系统是否支持。
7. 结论
该提交以较小的构建配置改动解决了固件产物缺少版本标识的问题。它复用 ESP-IDF 的统一项目版本,保留原始应用镜像和烧录流程,并自动生成内容完全一致的版本化副本。
该方案不会影响设备运行行为,主要后续影响是构建目录增加一份应用镜像、历史版本文件可能累积,以及发布流程必须正确区分“应用 OTA 镜像”和“完整烧录镜像”。