这个写了自动配置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有四种内置编译模式Debug 、Release 、MinSizeRel 和 RelWithDebInfo,这里用了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这样就找不到**make、cmake、git、python 这些构建过程的辅助工具。因此使用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 # 版本控制