【stm32】cmake脚本(一)

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

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

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

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

arm-none-eabi.cmake

cpp 复制代码
# 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工具链

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

cpp 复制代码
set(CMAKE_C_STANDARD_REQUIRED ON)
set(CMAKE_C_EXTENSIONS ON)

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

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

开头设置

cpp 复制代码
# 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标准)。

cpp 复制代码
if(MINGW OR WIN32)
  set(EXE_SUFFIX ".exe")
  set(CMAKE_OBJECT_PATH_MAX 200)
endif()

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

toolchain

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

工具 作用 在STM32开发中的具体用途
arm-none-eabi-gcc C编译器 编译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 代码覆盖 测试覆盖率分析(开发阶段)
cpp 复制代码
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++ 作为链接器
cpp 复制代码
set(CMAKE_LINKER ${TOOLCHAIN_PREFIX}g++)

优点

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

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

  • 自动处理静态构造函数

  • 简化C++项目配置

缺点

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

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

使用 ld 作为链接器
cpp 复制代码
set(CMAKE_LINKER ${TOOLCHAIN_PREFIX}ld)

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

优点

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

  • 完全控制链接过程

  • 固件体积最小

缺点

  • 手动管理所有库依赖

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

生成 .elf 文件

cpp 复制代码
# Generate .elf files
set(CMAKE_EXECUTABLE_SUFFIX ".elf")
set(CMAKE_EXECUTABLE_SUFFIX_C ".elf")
set(CMAKE_EXECUTABLE_SUFFIX_CXX ".elf")

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

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

cpp 复制代码
# 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 语言

cpp 复制代码
set(CMAKE_C_FLAGS_DEBUG_INIT "-g3 -Og -Wall -pedantic -DDEBUG")

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

cpp 复制代码
set(CMAKE_C_FLAGS_RELEASE_INIT "-O3 -Wall")

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

C++ 标志

cpp 复制代码
set(CMAKE_CXX_FLAGS_DEBUG_INIT "-g3 -Og -Wall -pedantic -DDEBUG")
set(CMAKE_CXX_FLAGS_RELEASE_INIT "-O3 -Wall")

和C语言一样。

编译

cpp 复制代码
# 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_FLAGS set(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) 找头文件
cpp 复制代码
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      # 版本控制
相关推荐
菠萝地亚狂想曲13 分钟前
FreeRTOS heap4
c语言·stm32·嵌入式开发
The Mr.Nobody16 分钟前
基于STM32F407的 TFTP Server
arm开发·stm32·嵌入式硬件
飞凌嵌入式17 分钟前
如何用JishuShell在RK3588核心板上快速部署OpenClaw?
arm开发·人工智能·嵌入式硬件·openclaw
余生皆假期-23 分钟前
永磁同步电机的星形 (Y) 和三角形 (Δ) 有何不同?
单片机·嵌入式硬件
点灯小铭24 分钟前
基于单片机的空气质量检测仪系统设计
单片机·嵌入式硬件·毕业设计·课程设计·期末大作业
狂奔蜗牛(bradley)25 分钟前
嵌入式软件中如何用责任链模式重构串口协议栈
网络·单片机·mcu·重构·责任链模式
时空自由民.37 分钟前
LCD显示的图像散乱原因
单片机
鸟电波44 分钟前
硬件笔记——Allegro绘制PCB(未完待续)
笔记·嵌入式硬件·智能硬件
悠哉悠哉愿意1 小时前
【单片机复习笔记】十三届国赛复盘2
笔记·单片机·嵌入式硬件
清风6666661 小时前
基于单片机的矿井温度、烟雾与甲烷检测通风报警系统设计
单片机·嵌入式硬件·毕业设计·课程设计·期末大作业