参考资料
STM32 CMake Project Template
stm32l4_demo - skb666
为什么使用 CMake? 很早就想过用 CMake 来代替 eclipse 构建工程,优点是可以使用 VsCode 编译工程进行开发。另外还方便在 Jenkins 上使用脚本构建工程,目前使用 eclipse 构建工程,需要把生成的 Makefile 和多个 .arg 文件传 SVN,Jenkins 上通过 eclipse 生成的 Makefile 脚本编译工程,需要管控很多 Make 相关的文件,而且工程文件目录调整后,需要重新用 eclipse 生成一份 Makefile 供 Jenkins 使用。
遇到的问题 一开始使用 CMake 遇到很多问题,主要还是我在使用 Windows 开发环境,有些地方需要注意。我后来使用 WSL 使用CMake 的时候还是很顺利的,而且 Linux 中的包管理器很好用,准备开发环境非常方便,确实比 Windows 开发优秀很多。如果可以的话,我也想拥有一台电脑装 Linux 操作系统做日常软件开发。
现在改了 CMake 脚本,在 Windows 下也可以完成构建和编译了!,主要是加了 set(CMAKE_SYSTEM_NAME Generic)
,CMAKE_SYSTEM_NAME
变量用于指定项目的目标操作系统名称,”Generic” 通常表示你不是针对特定的操作系统进行构建,而是希望以更通用或跨平台的方式构建项目,这通常用于编写可以在多个不同平台上编译和运行的代码。否则链接时会出现以下报错:
1 2 3 4 5 6 7 [ 2%] Linking C executable C:/Users/33110/Projects/stm32l4_demo/output/stm32l4_demo.elf.exe c:/program files (x86)/gcc-arm-none-eabi-10.3-2021.10/bin/../lib/gcc/arm-none-eabi/10.3.1/../../../../arm-none-eabi/bin/ld.exe: unrecognized option '--major-image-version' c:/program files (x86)/gcc-arm-none-eabi-10.3-2021.10/bin/../lib/gcc/arm-none-eabi/10.3.1/../../../../arm-none-eabi/bin/ld.exe: use the --help option for usage information collect2.exe: error: ld returned 1 exit status make[2]: *** [CMakeFiles/stm32l4_demo.elf.dir/build.make:764:C:/Users/33110/Projects/stm32l4_demo/output/stm32l4_demo.elf.exe] 错误 1 make[1]: *** [CMakeFiles/Makefile2:83:CMakeFiles/stm32l4_demo.elf.dir/all] 错误 2 make: *** [Makefile:91:all] 错误 2
CMake 脚本 CMake 脚本分为两个,将不同平台编译工具链相关的抽离出来,在一份 CMake 工程可以编译出不同平台的结果。脚本内容如下:
CMakeLists.txt 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 cmake_minimum_required (VERSION 3.10 )set (PROJECT_NAME "my_ytm32_prj" )project (${PROJECT_NAME} LANGUAGES C CXX)set (CMAKE_VERBOSE_MAKEFILE on )MESSAGE (STATUS "PROJECT_NAME: " ${PROJECT_NAME} )MESSAGE (STATUS "CMAKE_TOOLCHAIN_FILE: " ${CMAKE_TOOLCHAIN_FILE} )MESSAGE (STATUS "MCU: " ${MCU} )MESSAGE (STATUS "LD_SCRIPT: " ${LD_SCRIPT} )MESSAGE (STATUS "ASM_SOURCES: " ${ASM_SOURCES} )MESSAGE (STATUS "MAP_FILE: " ${MAP_FILE} )add_compile_options (-O2 -fmessage-length=0 -fsigned-char -ffunction-sections -fdata-sections -fno-strict-aliasing)add_link_options (-T${LD_SCRIPT} -Xlinker --gc-sections -Wl,-Map=${MAP_FILE} )set_property (SOURCE ${ASM_SOURCES} PROPERTY LANGUAGE C)set_source_files_properties (${ASM_SOURCES} PROPERTIES COMPILE_FLAGS "-x assembler-with-cpp -DSTART_FROM_FLASH" )file (GLOB_RECURSE SOURCE_FILES "${CMAKE_SOURCE_DIR}/source/*.c" "${CMAKE_SOURCE_DIR}/Project_Settings/Startup_Code/*.c" )add_executable (${PROJECT_NAME} .elf ${SOURCE_FILES} ${ASM_SOURCES} )target_compile_definitions (${PROJECT_NAME} .elf PUBLIC CPU_YTM32B1ME0 YTM32B1ME0 ) target_link_libraries (${PROJECT_NAME} .elf PUBLIC m)target_include_directories (${PROJECT_NAME} .elf PUBLIC "${CMAKE_SOURCE_DIR}/Project_Settings/Startup_Code" "${CMAKE_SOURCE_DIR}/Project_Settings/Startup_Code/CMSIS/Core/Include" "${CMAKE_SOURCE_DIR}/source/inc" ) add_custom_target ( PRE_BUILD_DUMMY ALL ) add_custom_command ( TARGET PRE_BUILD_DUMMY PRE_BUILD COMMAND ${CMAKE_SOURCE_DIR} /../Bin/generate_version.sh WORKING_DIRECTORY ${CMAKE_OUTPUT_DIRECTORY} ) add_dependencies (${PROJECT_NAME} .elf PRE_BUILD_DUMMY)add_custom_command ( TARGET ${PROJECT_NAME} .elf POST_BUILD COMMAND ${CMAKE_SOURCE_DIR} /../Bin/BuildTools/PostBuild.bat ${PROJECT_NAME} ${TOOLCHAINS_PATH} ${TOOLCHAINS_PREFIX} COMMAND ${TOOLCHAINS_PATH} /${TOOLCHAINS_PREFIX} objcopy -O binary -S ${PROJECT_NAME} .elf ${PROJECT_NAME} .bin COMMAND ${TOOLCHAINS_PATH} /${TOOLCHAINS_PREFIX} objcopy -O binary -S ${PROJECT_NAME} .elf ${PROJECT_NAME} .srec COMMAND ${TOOLCHAINS_PATH} /${TOOLCHAINS_PREFIX} objcopy -O binary -S ${PROJECT_NAME} .elf ${PROJECT_NAME} .hex WORKING_DIRECTORY ${CMAKE_OUTPUT_DIRECTORY} )
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 set (CMAKE_SYSTEM_NAME Generic)set (CMAKE_SYSTEM_PROCESSOR ARM)set (CMAKE_BUILD_TYPE Debug)set (TOOLCHAINS_PATH "C:/Yuntu/YuntuIDE/tools/bin" )set (TOOLCHAINS_PREFIX "arm-none-eabi-" )set (CMAKE_C_COMPILER "${TOOLCHAINS_PATH}/${TOOLCHAINS_PREFIX}gcc.exe" )set (CMAKE_CXX_COMPILER "${TOOLCHAINS_PATH}/${TOOLCHAINS_PREFIX}g++.exe" )set (CMAKE_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR} /Debug)set (CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_OUTPUT_DIRECTORY} )set (CPU "-mcpu=cortex-m33" )set (FPU "" )set (FLOAT-ABI "" )set (MCU "${CPU} -mthumb ${FPU} ${FLOAT-ABI}" )set (CMAKE_C_STANDARD_REQUIRED ON )set (CMAKE_C_STANDARD 11 )set (CMAKE_C_FLAGS "${MCU}" )set (CMAKE_C_FLAGS_DEBUG "-g3" )set (CMAKE_C_FLAGS_RELEASE "" )set (CMAKE_CXX_STANDARD_REQUIRED ON )set (CMAKE_CXX_STANDARD 17 )set (CMAKE_CXX_FLAGS "${MCU}" )set (CMAKE_CXX_FLAGS_DEBUG "-g3" )set (CMAKE_CXX_FLAGS_RELEASE "" )set (LD_SCRIPT "${PROJECT_SOURCE_DIR}/Project_Settings/Linker_Files/flash.ld" )set (ASM_SOURCES "${PROJECT_SOURCE_DIR}/Project_Settings/Startup_Code/YTM32B1ME0_startup_gcc.S" )set (MAP_FILE "${CMAKE_OUTPUT_DIRECTORY}/${PROJECT_NAME}.map" )set (CMAKE_EXE_LINKER_FLAGS "--specs=nosys.specs" )set (CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)set (CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)set (CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)set (CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)
构建及编译指令 1 2 3 cd Project cmake -G "Unix Makefiles" -S. -BDebug -DCMAKE_TOOLCHAIN_FILE=toolchains.cmake cmake --build Debug --target all -- -j8
写cmake脚本时遇到的问题
vscode生成cmake时需要加入指定工具链的命令-DCMAKE_TOOLCHAIN_FILE=toolchains.cmake
,这个需在vscode cmake拓展设置中配置。
vscode生成cmake可以选择是Debug还是Release,还可选择工具链,既然我通过上面一个方案传入工具链的cmake,vscode配置工具链成未指定就可以了。
cmake生成时会有检查工具链,有些工具链可能会报错,gcc10.5需要加set(CMAKE_EXE_LINKER_FLAGS "--specs=nosys.specs")
。
gcc4.9就不支持--specs=nosys.specs
这个选项,跳过编译器检查需要加 set(CMAKE_C_COMPILER_WORKS 1) set(CMAKE_CXX_COMPILER_WORKS 1)
。
跨平台的编译需要加set(CMAKE_SYSTEM_NAME Generic) set(CMAKE_SYSTEM_PROCESSOR ARM)
,否则会链接错误。
更详细的编译信息set(CMAKE_VERBOSE_MAKEFILE on)
需要加在project(${PROJECT_NAME} LANGUAGES C CXX)
后面,否则不起作用。
set(CMAKE_SYSTEM_NAME Generic)
需要加在project(${PROJECT_NAME} LANGUAGES C CXX)
前面,否则不起作用,这类问题还没搞清楚为什么有的需要在project前有的需要在后,解决方法是由于未起作用试出来的。
待优化
现在链接顺序和 eclipse 编译出来的不一致,导致二进制不同(经测试,手动改变链接顺序,改成与 eclipse 一致,编译结果 bin 一致)。
没根据系统选择不同的cmake脚本,linux 下可能不兼容。