1. CMake 工程下链接脚本的工作机制
STM32CubeMX 输出 CMake 工程,链接脚本放置路径:user_modifiable/Device/芯片型号/xxx_flash.ld。 链接脚本.ld作用:定义 MEMORY 内存段,指定 ROM (Flash)、RAM 的起始地址与长度,GCC‑LD 根据该脚本完成 elf 文件的地址布局。
传统 Makefile 工程,链接脚本默认作为工程依赖;但是CubeMX 生成的 CMake 默认模板,没有将 ld 文件注册为 target 的链接依赖。
CMake 逻辑:当构建目标的依赖文件没有发生变更,不会重新执行链接步骤。只有检测到
.c/.h源文件改动,才会触发编译‑链接;ld 脚本改动没有被纳入依赖列表,CMake 认为无需重新链接,直接复用上一次生成的 elf 文件,表现为修改 ld,但是 elf 地址不变。
资料获取:实战经验 | LAT1724 STM32CubeIDE for VSCode修改链接文件中的Flash起始地址无效?
2. 根因:缺少 LINK_DEPENDS 链接依赖属性
CMake 属性LINK_DEPENDS:用来声明影响链接过程的外部文件;当该列表内文件发生修改,CMake 会强制触发重新链接。 原始 CubeMX 输出 CMakeLists 没有配置LINK_DEPENDS指向*_flash.ld链接脚本,ld 文件变更不会触发 relink。
文档给出的 CMake 代码逻辑说明:
# Ensure linker script changes trigger re-link -------------------------
set(CMSIS_DEVICE_DIR "${CMSIS_RTE_FOLDER}/Device/${CMSIS_Dname}")
file(GLOB DEVICE_LD_SCRIPTS "${CMSIS_DEVICE_DIR}/*_flash.ld")
list(LENGTH DEVICE_LD_SCRIPTS DEVICE_LD_COUNT)
if(DEVICE_LD_COUNT EQUAL 1)
list(GET DEVICE_LD_SCRIPTS 0 LINKER_SCRIPT)
set_property(TARGET ${CMAKE_PROJECT_NAME} APPEND PROPERTY LINK_DEPENDS
"${LINKER_SCRIPT}")
elseif(DEVICE_LD_COUNT GREATER 1)
message(WARNING "Multiple linker scripts found in ${CMSIS_DEVICE_DIR}; select one explicitly.")
else()
message(WARNING "No linker script found in ${CMSIS_DEVICE_DIR}; relying on DFP fallback/template.")
endif()
逻辑拆解:
- 定位 CMSIS 设备目录,glob 通配查找
*_flash.ld链接脚本; - 判断脚本数量:找到 1 个脚本,把脚本路径追加到目标的
LINK_DEPENDS; - 如果多个 ld 脚本,输出警告,提示用户手动选定;找不到脚本输出降级警告,依赖 DFP 模板。
当添加该段代码后:只要 ld 文件保存修改,CMake 识别文件变动,下一次 Build 自动执行重新链接,新的 Flash 起始地址写入 ELF。
3. 两种解决手段的技术内核对比
| 方案 | 实现原理 | 优势 | 短板 | 适用场景 |
|---|---|---|---|---|
| 方案一:Clean Rebuild All Projects(手动清理) | 删除全部编译中间产物,全部源码重新编译、重新链接,无视依赖关系 | 无需修改 CMakeLists,零代码改动,快速临时验证 | 每次修改 ld 都必须手动清理;CI 自动化脚本无法自动感知;人工操作容易遗忘 | 临时调试,偶尔修改链接脚本 |
| 方案二:CMake 增加 LINK_DEPENDS 依赖 | 注册 ld 脚本作为链接依赖,ld 变更自动触发 relink | 一次修改 CMakeLists 永久生效;普通 Build 即可识别 ld 变更;兼容 CI 自动化编译 | 需要修改工程 CMakeLists 文件;多 ld 脚本需要关注警告信息 | 正式产品工程、Boot‑App 项目、持续集成 CI、功能安全项目 |
文档明确提示,手动清理方案对工程师并不友好,正式工程优先采用方案二自动依赖配置。
4. 与 LAT1730(X‑CUBE‑CLASSB)工程的关联性
参考 LAT1730《基于 VSCode 从零开始移植 STM32C5 的 X‑CUBE‑CLASSB》文档,该 Class‑B 功能安全移植文档已经完整引入该段完全一致的 CMake 依赖代码。 原因:X‑CUBE‑CLASSB 需要修改 ld 链接脚本新增.backup_buffer_section备份缓存段,调整栈 Stack 布局;如果没有增加LINK_DEPENDS,ld 脚本改动不会触发重链接,会造成 RAM 内存布局修改不生效,功能安全自检库运行异常。两份 ST 笔记是配套关系:做 STM32C5 VSCode CMake 工程,无论普通 Boot‑App 还是 Class‑B 安全库,都建议加入该依赖代码。
5. 潜在边界风险点
- DFP 设备包目录下存在多个
*_flash.ld脚本,代码会打印警告,此时 glob 拿到的脚本不一定是实际使用的脚本,需要手动指定LINKER_SCRIPT; - 如果移动 ld 链接脚本的存放路径,
CMSIS_RTE_FOLDER变量路径失效,依赖会失效; - 仅针对 CMake 工程;STM32CubeIDE 原生 Make 工程不存在该问题。
296