将Keil工程移植为CMake工程
前期准备
一个Keil工程
根据主机平台和目标平台选择并安装交叉编译工具链,目标平台为ARM的直接官网下载:Arm GNU 工具链下载 – Arm Developer。如本文选择
安装CMake、Ninja(非必须,因为MinGW支持Unix make)、CLion(或VSCode等其他支持CMake工程的IDE)
创建CMake工程
可以直接将原工程复制一份,或者新建一份并将源文件按照Keil分组(其实爱咋分咋分),在工程根目录新建CMakeLists.txt
文件,内容如下所示:
# 设置工程依赖的最低CMake版本
cmake_minimum_required(VERSION 3.20)
set(CMAKE_SYSTEM_NAME Generic)
set(CMAKE_SYSTEM_VERSION 1)
# 设置交叉编译工具链
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_AR arm-none-eabi-ar)
set(CMAKE_OBJCOPY arm-none-eabi-objcopy)
set(CMAKE_OBJDUMP arm-none-eabi-objdump)
set(SIZE arm-none-eabi-size)
# 优先链接静态库
set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY)
# 项目设置 (项目名称、项目包含的编程语言)
project(GD32F30xTest C CXX ASM)
# 设置C标准为C11
set(CMAKE_C_STANDARD 11)
# 设置C++标准为C++11
set(CMAKE_CXX_STANDARD 11)
# 不要链接标准C/C++库
add_compile_options(-nostdlib)
add_link_options(-nostdlib)
# 添加硬浮点选项 (如果目标平台有FPU)
add_compile_definitions(ARM_MATH_CM4;ARM_MATH_MATRIX_CHECK;ARM_MATH_ROUNDING)
add_compile_options(-mfloat-abi=hard -mfpu=fpv4-sp-d16)
add_link_options(-mfloat-abi=hard -mfpu=fpv4-sp-d16)
# 添加软浮点选项 (如果目标平台没有FPU)
#add_compile_options(-mfloat-abi=soft)
# 指定CPU内核架构、指令集和其他编译选项
add_compile_options(-mcpu=cortex-m4 -mthumb -mthumb-interwork)
add_compile_options(-ffunction-sections -fdata-sections -fno-common -fmessage-length=0)
#set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-rtti")
# uncomment to mitigate c++17 absolute addresses warnings
#set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-register")
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)
endif ()
add_definitions(
-D_RTE_
-DGD32F30X_CL
-DUSE_STDPERIPH_DRIVER
-DUSE_USBFS
-DUSE_FATFS
-D__FPU_PRESENT=1
-D__FPU_USED=1
-DARM_MATH_CM4
# 添加其他宏定义
)
include_directories(
"Firmware/CMSIS"
"Firmware/CMSIS/GD/GD32F30x/Include"
"Firmware/GD32F30x_standard_peripheral/Include"
# 添加其他include路径
)
file(GLOB_RECURSE SOURCES
"Firmware/CMSIS/*.h"
"Firmware/CMSIS/GD/GD32F30x/Include/*.h"
"Firmware/CMSIS/GD/GD32F30x/Source/system_gd32f30x.c"
"Firmware/CMSIS/GD/GD32F30x/Source/GCC/startup_gd32f30x_cl.s"
"Firmware/GD32F30x_standard_peripheral/Include/*.h"
"Firmware/GD32F30x_standard_peripheral/Source/*.c"
"main.c"
# 添加其他源文件路径
)
# 设置链接脚本文件
set(LINKER_SCRIPT ${CMAKE_SOURCE_DIR}/gd32f30x_flash.ld)
# 设置链接器选项
add_link_options(-Wl,-gc-sections,--print-memory-usage,-Map=${PROJECT_BINARY_DIR}/${PROJECT_NAME}.map)
add_link_options(-mcpu=cortex-m4 -mthumb -mthumb-interwork)
add_link_options(-T ${LINKER_SCRIPT})
add_link_options(-specs=nano.specs -specs=nosys.specs -u _printf_float)
add_executable(${PROJECT_NAME}.elf ${SOURCES} ${LINKER_SCRIPT})
# 链接静态库
target_link_libraries(${PROJECT_NAME}.elf ${CMAKE_SOURCE_DIR}/EMWIN/STemWin/Lib/STemWin_CM4_wc16_ot.a)
set(HEX_FILE ${PROJECT_BINARY_DIR}/${PROJECT_NAME}.hex)
set(BIN_FILE ${PROJECT_BINARY_DIR}/${PROJECT_NAME}.bin)
# 生成hex文件和bin文件
add_custom_command(TARGET ${PROJECT_NAME}.elf POST_BUILD
COMMAND ${CMAKE_OBJCOPY} -Oihex $<TARGET_FILE:${PROJECT_NAME}.elf> ${HEX_FILE}
COMMAND ${CMAKE_OBJCOPY} -Obinary $<TARGET_FILE:${PROJECT_NAME}.elf> ${BIN_FILE}
COMMENT "Building ${HEX_FILE}
Building ${BIN_FILE}")
根据工程实际情况及需要修改上述内容,各种编译选项和宏定义可以参考Keil中的Options for Target
-> C/C++
-> Compiler control string
,就能愉快地使用CMake管理和构建工程了,配合使用CLion或VSCode,体验吊打Keil这上古神器。值得一提的是,CLion(本文使用2024.3)现在直接支持设置SEGGER J-Link调试了,不再需要像之前一样使用OpenOCD了,当然,如果使用其他调试器的话,大概还是要配置OpenOCD的,不过我这里刚好都是用的J-Link。
后话
鉴于某些MCU厂商不提供适用于GCC的链接脚本和启动文件,如果不想手动从ARMCC或IAR移植过来的话,也可以直接使用ARMCC或IAR的工具链,这样还有一个好处是不会破坏原有的工程(也就是说既可以使用CMake来管理和构建,也可以使用Keil),并且不会出现因为使用不同的工具链而出现与其他人不同的问题,坏处就是ARMCC实在是太落后了。。。ARMCLANG要好点,编译速度也快点,但是一些老工程往往使用ARMCC,如果直接设置成ARMCLANG的话大概率编译不过。
CMake配置使用ARMCC或其他自定义编译器,参见:https://github.com/JetBrains/clion-custom-defined-compiler-examples