news 2026/4/16 12:23:12

【stm32】cmake脚本(一)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
【stm32】cmake脚本(一)

这个写了自动配置cmake环境脚本,可以自己改自己用的交叉编译器。

【stm32】bash自动配置buildenv自动配置编译环境_edgetx 编译-CSDN博客

平台ubuntu22.04,代码查看使用vscode。背景为一套可以按要求为不同stm32编译同样功能的代码。

使用了CMake缓存文件,可以提高后续代码编译速度。文件为CMakeCache.txt。

arm-none-eabi.cmake

# arm-none-eabi toolchain set(CMAKE_SYSTEM_NAME Generic) set(CMAKE_SYSTEM_PROCESSOR arm) set(CMAKE_CXX_STANDARD 17) set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY) if(MINGW OR WIN32) set(EXE_SUFFIX ".exe") set(CMAKE_OBJECT_PATH_MAX 200) endif() if(ARM_TOOLCHAIN_DIR) cmake_path(SET ARM_TOOLCHAIN_DIR NORMALIZE ${ARM_TOOLCHAIN_DIR}) set(ARM_TOOLCHAIN_DIR "${ARM_TOOLCHAIN_DIR}/") endif() set(CMAKE_AR ${ARM_TOOLCHAIN_DIR}arm-none-eabi-ar${EXE_SUFFIX}) set(CMAKE_ASM_COMPILER ${ARM_TOOLCHAIN_DIR}arm-none-eabi-gcc${EXE_SUFFIX}) set(CMAKE_C_COMPILER ${ARM_TOOLCHAIN_DIR}arm-none-eabi-gcc${EXE_SUFFIX}) set(CMAKE_CXX_COMPILER ${ARM_TOOLCHAIN_DIR}arm-none-eabi-g++${EXE_SUFFIX}) set(CMAKE_LINKER ${ARM_TOOLCHAIN_DIR}arm-none-eabi-ld${EXE_SUFFIX}) set(CMAKE_OBJCOPY ${ARM_TOOLCHAIN_DIR}arm-none-eabi-objcopy${EXE_SUFFIX} CACHE INTERNAL "") set(CMAKE_RANLIB ${ARM_TOOLCHAIN_DIR}arm-none-eabi-ranlib${EXE_SUFFIX} CACHE INTERNAL "") set(CMAKE_SIZE_UTIL ${ARM_TOOLCHAIN_DIR}arm-none-eabi-size${EXE_SUFFIX} CACHE INTERNAL "") set(CMAKE_STRIP ${ARM_TOOLCHAIN_DIR}arm-none-eabi-strip${EXE_SUFFIX} CACHE INTERNAL "") set(CMAKE_GCOV ${ARM_TOOLCHAIN_DIR}arm-none-eabi-gcov${EXE_SUFFIX} CACHE INTERNAL "") # Generate .elf files set(CMAKE_EXECUTABLE_SUFFIX ".elf") set(CMAKE_EXECUTABLE_SUFFIX_C ".elf") set(CMAKE_EXECUTABLE_SUFFIX_CXX ".elf") # Default C compiler flags set(CMAKE_C_FLAGS_DEBUG_INIT "-g3 -Og -Wall -pedantic -DDEBUG") set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG_INIT}" CACHE STRING "" FORCE) set(CMAKE_C_FLAGS_RELEASE_INIT "-O3 -Wall") set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE_INIT}" CACHE STRING "" FORCE) # Default C++ compiler flags set(CMAKE_CXX_FLAGS_DEBUG_INIT "-g3 -Og -Wall -pedantic -DDEBUG") set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG_INIT}" CACHE STRING "" FORCE) set(CMAKE_CXX_FLAGS_RELEASE_INIT "-O3 -Wall") set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE_INIT}" CACHE STRING "" FORCE) # customize linker command set(CMAKE_EXE_LINKER_FLAGS "") set(CMAKE_C_LINK_EXECUTABLE "<CMAKE_C_COMPILER> <FLAGS> <LINK_FLAGS> <OBJECTS> -o <TARGET> <LINK_LIBRARIES>") set(CMAKE_CXX_LINK_EXECUTABLE "<CMAKE_CXX_COMPILER> <FLAGS> <LINK_FLAGS> <OBJECTS> -o <TARGET> <LINK_LIBRARIES>") # 工具链文件中的标准配置 set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) # 构建工具来自主机 set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) # 库必须来自ARM工具链 set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) # 头文件必须来自ARM工具链

下面两个可以用默认不添加到代码中。

set(CMAKE_C_STANDARD_REQUIRED ON) set(CMAKE_C_EXTENSIONS ON)

行1作用:如果编译器不支持指定的 C11 标准,报错并停止构建。大部分用off

行2作用:允许使用编译器特定的扩展功能。#-std=gnu11。大部分用on

开头设置

# arm-none-eabi toolchain set(CMAKE_SYSTEM_NAME Generic) set(CMAKE_SYSTEM_PROCESSOR arm) set(CMAKE_CXX_STANDARD 17)

作用:告诉 CMake 这是裸机系统(无操作系统),禁用所有操作系统特定功能。

作用:指定目标处理器架构为 ARM。

作用:设置 C++ 语言标准为 C++17(注意:这里只设置了C++,没有设置C标准)。

if(MINGW OR WIN32) set(EXE_SUFFIX ".exe") set(CMAKE_OBJECT_PATH_MAX 200) endif()

Windows 平台特殊处理,添加.exe后缀并解决长路径问题。

toolchain

设置工具,不代表一定使用。加粗的要注意一点。

工具作用在STM32开发中的具体用途
arm-none-eabi-gccC编译器编译C源代码为STM32机器码
arm-none-eabi-g++C++编译器编译C++代码(如果项目使用)
arm-none-eabi-ld链接器将多个.o文件链接成最终可执行文件
arm-none-eabi-ar静态库工具创建和管理静态库文件(.a)
arm-none-eabi-objcopy二进制转换将ELF转换为HEX/BIN烧录文件
arm-none-eabi-objdump反汇编查看机器码对应的汇编指令
arm-none-eabi-size大小分析查看固件各段大小(Flash/RAM使用)
arm-none-eabi-strip符号剔除移除调试符号,减小固件大小
arm-none-eabi-ranlib库索引为静态库生成索引,加快链接速度
arm-none-eabi-gcov代码覆盖测试覆盖率分析(开发阶段)
if(ARM_TOOLCHAIN_DIR) cmake_path(SET ARM_TOOLCHAIN_DIR NORMALIZE ${ARM_TOOLCHAIN_DIR}) set(ARM_TOOLCHAIN_DIR "${ARM_TOOLCHAIN_DIR}/") endif() set(CMAKE_AR ${ARM_TOOLCHAIN_DIR}arm-none-eabi-ar${EXE_SUFFIX}) set(CMAKE_ASM_COMPILER ${ARM_TOOLCHAIN_DIR}arm-none-eabi-gcc${EXE_SUFFIX}) set(CMAKE_C_COMPILER ${ARM_TOOLCHAIN_DIR}arm-none-eabi-gcc${EXE_SUFFIX}) set(CMAKE_CXX_COMPILER ${ARM_TOOLCHAIN_DIR}arm-none-eabi-g++${EXE_SUFFIX}) set(CMAKE_LINKER ${ARM_TOOLCHAIN_DIR}arm-none-eabi-ld${EXE_SUFFIX}) set(CMAKE_OBJCOPY ${ARM_TOOLCHAIN_DIR}arm-none-eabi-objcopy${EXE_SUFFIX} CACHE INTERNAL "") set(CMAKE_RANLIB ${ARM_TOOLCHAIN_DIR}arm-none-eabi-ranlib${EXE_SUFFIX} CACHE INTERNAL "") set(CMAKE_SIZE_UTIL ${ARM_TOOLCHAIN_DIR}arm-none-eabi-size${EXE_SUFFIX} CACHE INTERNAL "") set(CMAKE_STRIP ${ARM_TOOLCHAIN_DIR}arm-none-eabi-strip${EXE_SUFFIX} CACHE INTERNAL "") set(CMAKE_GCOV ${ARM_TOOLCHAIN_DIR}arm-none-eabi-gcov${EXE_SUFFIX} CACHE INTERNAL "")

这里建议自己设置。

没有设置路径会在Path下找。设置全套编译工具,使用 GCC 作为 C/C++/ASM 编译器,ld 作为链接器。

有cache的行是设置二进制工具并缓存,避免重复查找。

对于set(CMAKE_OBJCOPY ${ARM_TOOLCHAIN_DIR}arm-none-eabi-objcopy${EXE_SUFFIX} CACHE INTERNAL "")cache缓存

部分作用示例
CACHE将变量存入CMake缓存持久化保存
INTERNAL内部变量,不显示在GUI中对用户隐藏
""变量描述(空字符串)无需描述

链接器使用:

使用 g++ 作为链接器
set(CMAKE_LINKER ${TOOLCHAIN_PREFIX}g++)

优点

  • 自动处理C++标准库(libstdc++)

  • 自动处理异常处理(unwind库)

  • 自动处理静态构造函数

  • 简化C++项目配置

缺点

  • ❌ 可能链接不必要的C++库,增加固件大小

  • ❌ 对纯C项目有些"过重"

使用 ld 作为链接器
set(CMAKE_LINKER ${TOOLCHAIN_PREFIX}ld)

这里用ld作为链接器,因为编译bootloader,需要体积小的固件。

优点

  • 极致精简,只链接明确指定的库

  • 完全控制链接过程

  • 固件体积最小

缺点

  • 手动管理所有库依赖

  • C++特性(异常、静态构造)需要手动配置

生成 .elf 文件

# Generate .elf files set(CMAKE_EXECUTABLE_SUFFIX ".elf") set(CMAKE_EXECUTABLE_SUFFIX_C ".elf") set(CMAKE_EXECUTABLE_SUFFIX_CXX ".elf")

设置可执行文件输出格式为 ELF,这是嵌入式系统的标准格式。

调试/发布标志(CMake的预设机制

# Default C compiler flags set(CMAKE_C_FLAGS_DEBUG_INIT "-g3 -Og -Wall -pedantic -DDEBUG") set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG_INIT}" CACHE STRING "" FORCE) set(CMAKE_C_FLAGS_RELEASE_INIT "-O3 -Wall") set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE_INIT}" CACHE STRING "" FORCE) # Default C++ compiler flags set(CMAKE_CXX_FLAGS_DEBUG_INIT "-g3 -Og -Wall -pedantic -DDEBUG") set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG_INIT}" CACHE STRING "" FORCE) set(CMAKE_CXX_FLAGS_RELEASE_INIT "-O3 -Wall") set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE_INIT}" CACHE STRING "" FORCE)

CMake的预设机制

这里的CMAKE_C_FLAGS_RELEASE和CMAKE_CXX_FLAGS_DEBUG作用于后面的编译命令中的占位符<FLAGS>,两个使用哪一个取决于你的编译模式。

Cmake有四种内置编译模式DebugReleaseMinSizeRelRelWithDebInfo,这里用了Debug和Release。命令cmake -DCMAKE_BUILD_TYPE=Debug可以切换编译模式。

C 语言

set(CMAKE_C_FLAGS_DEBUG_INIT "-g3 -Og -Wall -pedantic -DDEBUG")

作用调试模式:最大调试信息(-g3)、优化调试(-Og)、全警告(-Wall)、严格标准(-pedantic)、定义 DEBUG 宏。

set(CMAKE_C_FLAGS_RELEASE_INIT "-O3 -Wall")

作用发布模式:最大优化(-O3)、开启警告。

C++ 标志

set(CMAKE_CXX_FLAGS_DEBUG_INIT "-g3 -Og -Wall -pedantic -DDEBUG") set(CMAKE_CXX_FLAGS_RELEASE_INIT "-O3 -Wall")

和C语言一样。

编译

# customize linker command set(CMAKE_EXE_LINKER_FLAGS "") set(CMAKE_C_LINK_EXECUTABLE "<CMAKE_C_COMPILER> <FLAGS> <LINK_FLAGS> <OBJECTS> -o <TARGET> <LINK_LIBRARIES>") set(CMAKE_CXX_LINK_EXECUTABLE "<CMAKE_CXX_COMPILER> <FLAGS> <LINK_FLAGS> <OBJECTS> -o <TARGET> <LINK_LIBRARIES>")
占位符默认值来源如何自定义
<FLAGS>CMAKE_C_FLAGS(C)
CMAKE_CXX_FLAGS(C++)
set(CMAKE_C_FLAGS "-mcpu=cortex-m4")
<LINK_FLAGS>CMAKE_EXE_LINKER_FLAGSset(CMAKE_EXE_LINKER_FLAGS "-Tlink.ld")
<OBJECTS>add_executable()的源文件列表自动生成,无需手动设置
<TARGET>add_executable(目标名 ...)第一个参数就是目标名
<LINK_LIBRARIES>target_link_libraries(目标名 ...)第二个参数开始的所有库

这里的<FLAGS>在调试/发布标志里讲解了。其他的因为不同的stm32取决于其他CMakeLists文件里定义了,并且CMAKE_C_LINK_EXECUTABLE和CMAKE_C++_LINK_EXECUTABLE也是为主CMakeLists文件做准备。

交叉编译(Cross-Compiling)的核心隔离配置

这几个也是CMake的预设机制

模式设置值含义实际例子
PROGRAM(程序)NEVER从不在目标系统找find_program(CMAKE_COMMAND)cmake
LIBRARY(库)ONLY只在目标系统找find_library(M_LIB m)libm.a
INCLUDE(头文件)ONLY只在目标系统找find_path(STDIO_H stdio.h)找头文件
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) # 构建工具来自主机

CMAKE_FIND_ROOT_PATH这个可以自己设置,Linux默认就是/usr/bin,但是交叉编译的时候,这个路径被偷偷修改为之前编译器的路径了就不是/usr/bin这样就找不到makecmakegitpython这些构建过程的辅助工具。因此使用never。

修改原因是之前指定了交叉编译工具cmake自动修改导致的,如果你手动指定CMAKE_FIND_ROOT_PATH为/usr/bin就可以使用only。

其他两个同理,但是他们两个要的就是修改后的。

交叉编译:

# 找 make 和cmake程序时: # NEVER → 不在 /opt/gcc-arm 里找 → 在主机 /usr/bin 里找 ✅

本地编译:

# 找 make 和cmake程序时: # 在系统默认PATH里找 → /usr/bin/make ✅
/opt/gcc-arm/bin/(是x86程序) ├── arm-none-eabi-gcc # 目标编译器 ├── arm-none-eabi-ld # 目标链接器 ├── arm-none-eabi-objcopy # 目标工具 └── ...其他ARM工具 不包含:(是x86程序) ├── cmake # 构建系统生成器 ├── make # 构建执行器 ├── ninja # 替代构建器 └── git # 版本控制
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/16 6:50:02

Excalidraw如何实现像素级精准对齐?网格系统详解

Excalidraw 如何实现像素级精准对齐&#xff1f;网格系统详解 在数字协作工具日益普及的今天&#xff0c;虚拟白板早已不再是简单的“画图板”。从技术架构设计到产品原型草图&#xff0c;团队越来越依赖像 Excalidraw 这样的开源手绘风格白板来完成高信息密度的表达。它那看似…

作者头像 李华
网站建设 2026/4/10 2:49:07

27、高级线程同步技术详解

高级线程同步技术详解 在多线程编程中,线程同步是一个至关重要的问题,它关乎着程序的正确性、稳定性和性能。本文将深入探讨高级线程同步的相关技术,包括信号量、条件变量模型、阈值屏障对象、队列对象以及多阶段管道中队列的使用等内容。 信号量与条件变量模型 在某些情…

作者头像 李华
网站建设 2026/4/10 14:24:27

35、重叠 I/O 和扩展 I/O 详解

重叠 I/O 和扩展 I/O 详解 在进行 I/O 操作时,性能和可扩展性往往是主要目标。虽然内存映射 I/O 在处理文件时非常有效,但从内存映射 I/O 错误中恢复并非易事。接下来我们详细探讨重叠 I/O 以及与之相关的内容。 重叠 I/O 概述 异步 I/O(无论是重叠还是扩展)的首要要求是…

作者头像 李华
网站建设 2026/4/16 0:24:54

Excalidraw如何实现跨浏览器兼容?主流内核测试全覆盖

Excalidraw如何实现跨浏览器兼容&#xff1f;主流内核测试全覆盖 在远程协作成为常态的今天&#xff0c;一个能在任何设备、任何浏览器上“开箱即用”的白板工具&#xff0c;几乎是每个技术团队的刚需。而当你在Chrome里画好一张架构图&#xff0c;同事却在Safari中看到错位的线…

作者头像 李华
网站建设 2026/4/15 10:21:28

Excalidraw镜像通过GDPR合规审查,欧洲可用

Excalidraw 镜像通过 GDPR 合规审查&#xff0c;欧洲可用 在数字化办公日益深入的今天&#xff0c;远程协作工具早已不再是“锦上添花”&#xff0c;而是企业运转的核心基础设施。尤其是在欧盟这样对数据隐私有着严苛要求的市场中&#xff0c;一个看似简单的白板工具是否合规&…

作者头像 李华
网站建设 2026/4/8 5:10:58

7、Windows XP 操作指南

Windows XP 操作指南 1. 磁盘格式化 在当今时代,新电脑系统很少配备软盘驱动器,大多数人可能从未体验过格式化软盘的“乐趣”。但对于那些电脑仍有软盘驱动器,偶尔需要用软盘备份或传输文件的人来说,以下内容会很有用。 如今购买的大多数磁盘都是预格式化的,但有时你可…

作者头像 李华