本文已过时,STM32CubeMX已官方支持CMake,最新配置模板请参考本人仓库NianLee0/stm32-cmake-template: stm32 cmake 模板

这是一个用CMake组织的STM32项目demo,其CMake配置文件可供移植参考
CMakeLists框架参考跃鹿战队的powerful_framework,将和硬件平台有关的配置以变量的形式统一存放在Config.cmake,方便移植,同时增加了OpenOCD下载和RTT启动任务

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
cmake_minimum_required(VERSION 3.16)
# 指定编译平台/架构与语言标准, 推荐指定Ninja为构建工具,可以加快编译速度(相比make)
set(CMAKE_SYSTEM_NAME Generic)
set(CMAKE_SYSTEM_PROCESSOR arm)

set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY)
# 指定工具链
set(CMAKE_C_COMPILER_FORCED TRUE) # skip compiler test
set(CMAKE_CXX_COMPILER_FORCED TRUE)
set(CMAKE_C_COMPILER arm-none-eabi-gcc)
set(CMAKE_CXX_COMPILER arm-none-eabi-g++)
set(CMAKE_ASM_COMPILER arm-none-eabi-gcc)
set(CMAKE_OBJCOPY arm-none-eabi-objcopy)
set(CMAKE_OBJDUMP arm-none-eabi-objdump)
set(SIZE arm-none-eabi-size)
set(CMAKE_AR arm-none-eabi-ar)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_C_STANDARD 11)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)

# 指定工程名称和语言类型
get_filename_component(PROJECT_NAME ${CMAKE_CURRENT_SOURCE_DIR} NAME)
project(${PROJECT_NAME} C CXX ASM)

# 包含自定义变量和函数
include(Config.cmake)

link_directories(${CMAKE_SOURCE_DIR}/ExtLibs/DSP/Lib)

if(BUILD_DSP)
add_subdirectory(${CMAKE_SOURCE_DIR}/ExtLibs/DSP/Source)
endif()

# Generic compiler settings for optimization and basic link lib
add_compile_options(-pipe ${MCU_FLAGS} -Wall -Werror -fmessage-length=0 # basic options
-ffunction-sections -fdata-sections -fno-common # optimize options
)

add_link_options(-pipe ${MCU_FLAGS} -T${LINKER_SCRIPT} # -Wl,--no-warn-rwx-segments close RWX warning
-lc -lstdc++ -lm -lnosys # lib options
-Wl,--gc-sections -flto -specs=nano.specs -specs=nosys.specs # optimize options
-Wl,-Map=${PROJECT_BINARY_DIR}/${PROJECT_NAME}.map -Wl,--cref -Wl,--print-memory-usage # map options
) # if your executable is too large , try option '-s' to strip symbols

# add_compile_definitions() works for compile stage
# while add_definitions() works for both compile and link stage
add_definitions(
-DUSE_HAL_DRIVER
-D${MCU_DEFINE}
# -DARM_MATH_CM4
# -DARM_MATH_MATRIX_CHECK
# -DARM_MATH_ROUNDING
# -DARM_MATH_LOOPUNROLL
# -DDISABLEFLOAT16
) # need -D<macro> to define macro

# add inc
if(${USE_EIGEN})
include_sub_directories_recursively(${CMAKE_SOURCE_DIR}/ExtLibs/Eigen3)
endif()
include_sub_directories_recursively(${CMAKE_SOURCE_DIR}/Core)
include_sub_directories_recursively(${CMAKE_SOURCE_DIR}/Drivers)
include_sub_directories_recursively(${CMAKE_SOURCE_DIR}/Middlewares)

# add source, only surfix .c .cpp
file(GLOB_RECURSE SOURCES
"Drivers/*.c"
"Middlewares/*.c"
"Core/*.c"
)

# 汇编文件路径
set(ASM_SOURCES ${STARTUP_NAME})

if(SEGGER_RTT)
list(APPEND ASM_SOURCES ${RTT_ASM_DIR}) # 添加RTT汇编文件路径
endif()

set_source_files_properties(${ASM_SOURCES} PROPERTIES COMPILE_FLAGS "-x assembler-with-cpp")

# Build types
if ("${CMAKE_BUILD_TYPE}" STREQUAL "Release")
message(STATUS "Maximum optimization for speed")
add_compile_options(-Ofast)
elseif ("${CMAKE_BUILD_TYPE}" STREQUAL "RelWithDebInfo")
message(STATUS "Maximum optimization for speed, debug info included")
add_compile_options(-Ofast -g)
elseif ("${CMAKE_BUILD_TYPE}" STREQUAL "MinSizeRel")
message(STATUS "Maximum optimization for size")
add_compile_options(-Os)
else ()
message(STATUS "Minimal optimization, debug info included")
add_compile_options(-Og -g -gdwarf-2)
add_definitions(-DESC_DEBUG) # ESC Debug
endif ()

add_executable(${PROJECT_NAME}.elf ${SOURCES} ${ASM_SOURCES} ${LINKER_SCRIPT})

if(BUILD_DSP)
add_dependencies(${PROJECT_NAME}.elf CMSISDSP) # build DSP lib
target_link_libraries(${PROJECT_NAME}.elf ${DSP_NAME}) # link DSP lib
endif()

# build binary and hex file
add_custom_command(
TARGET ${PROJECT_NAME}.elf POST_BUILD
COMMAND ${CMAKE_OBJCOPY} -Oihex $<TARGET_FILE:${PROJECT_NAME}.elf> ${PROJECT_BINARY_DIR}/${PROJECT_NAME}.hex
COMMAND ${CMAKE_OBJCOPY} -Obinary $<TARGET_FILE:${PROJECT_NAME}.elf> ${PROJECT_BINARY_DIR}/${PROJECT_NAME}.bin
COMMENT "Building hex & bin file..."
COMMENT "EXCUTABLE SIZE:"
COMMAND ${SIZE} ${PROJECT_NAME}.elf
)

# 烧录任务
add_custom_target(Download
COMMAND
openocd
-f ${OPENOCD_ROOT}/interface/${OPENOCD_INTERFACE}
-f ${OPENOCD_ROOT}/target/${OPENOCD_TARGET}
-c init -c halt
-c "flash write_image erase ${BIN_DIR} ${OPENOCD_FLASH_START}"
-c reset -c shutdown
)

# RTT调试任务
add_custom_target(Start_RTT COMMAND openocd -f ${OPENOCD_ROOT}/h7_rtt.cfg)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
# 选择构建类型
set(CMAKE_BUILD_TYPE Debug) # Debug Release RelWithDebInfo MinSizeRel

# board specific settings, arch/fpu/instruction
# -mfloat-abi=hard 硬件浮点 -mfloat-abi=soft 软件浮点
# cortex-m7 -mfpu=fpv5-sp-d16 单精度 -mfpu=fpv5-d16 双精度
# cortex-m4 -mfpu=fpv4-sp-d16 单精度
# cortex-m3 无fpu
set(MCU_FLAGS -mcpu=cortex-m7 -mthumb -mthumb-interwork -mfloat-abi=hard -mfpu=fpv5-d16)
set(LINKER_SCRIPT "${CMAKE_SOURCE_DIR}/STM32H723VGTx_FLASH.ld") # 指定链接脚本
set(CMSISCORE "${CMAKE_SOURCE_DIR}/Drivers/CMSIS")
set(DSP_NAME "libCMSISDSP.a") # 指定DSP库名称

# 构建选项
option(USE_EIGEN OFF) # 是否使用Eigen库
option(BUILD_DSP OFF) # 是否编译DSP库,若要定制须修改DSP/Source/CMakeLists.txt
option(SEGGER_RTT ON) # 是否使用SEGGER RTT

set(MCU_DEFINE STM32H723xx)
set(STARTUP_NAME startup_stm32h723xx.s)
set(RTT_ASM_DIR ${PROJECT_SOURCE_DIR}/Middlewares/Third_Party/SEGGER/RTT/SEGGER_RTT_ASM_ARMv7M.s)
set(OPENOCD_ROOT D:/Tools/OpenOCD/share/openocd/scripts)
set(OPENOCD_INTERFACE cmsis-dap.cfg)
set(OPENOCD_TARGET stm32h7x.cfg)
set(OPENOCD_FLASH_START 0x08000000)
set(BIN_DIR ${PROJECT_NAME}.bin)

# 递归包含头文件的函数
function(include_sub_directories_recursively root_dir)
if (IS_DIRECTORY ${root_dir}) # 当前路径是一个目录吗,是的话就加入到包含目录
message("include dir: " ${root_dir})
include_directories(${root_dir})
endif()

file(GLOB ALL_SUB RELATIVE ${root_dir} ${root_dir}/*) # 获得当前目录下的所有文件,让如ALL_SUB列表中
foreach(sub ${ALL_SUB})
if (IS_DIRECTORY ${root_dir}/${sub})
include_sub_directories_recursively(${root_dir}/${sub}) # 对子目录递归调用,包含
endif()
endforeach()
endfunction()