VSCode编辑+GCC for ARM交叉编译工具链+CMake构建+OpenOCD调试(基于STM32的标准库/HAL库)
一、CMake安装
- 进入CMake官网的下载地址Get the Software,根据系统安装对应的Binary distributions。
- 或者在CMake——国内镜像获取二进制镜像安装包。
- 或者访问GitHub的xPack项目xPack CMake v3.28.6-1,下载即可。
记得添加用户/系统的环境变量,打开cmd窗口,输入
cmake -version
,查看CMake环境变量是否添加成功,如下图所示。
二、VSCode各个配置脚本文件
本文以【STM32F103ZET6
】单片机作为示例来进行演示,以下配置文件对于标准库/HAL库的工程是通用的,修改CMakeLists.txt里面的源文件和头文件引用部分即可。
更多细节请参考【VSCode编辑+GCC for ARM交叉编译工具链+Makefile构建+OpenOCD调试(基于STM32的标准库)】
下面列出几个主要的配置文件:
settings.json
c_cpp_properties.json
tasks.json
launch.json
CMakeLists.txt
⭐ MCU链接脚本.ld、MCU汇编启动文件.s、MCU寄存器文件.svd请参考【VSCode编辑+GCC for ARM交叉编译工具链+Makefile构建+OpenOCD调试(基于STM32的标准库)】文章获取。
settings.json:
{
// 字符集编码选择
"files.encoding": "utf8",
// 自动保存任意文件
"files.autoSave": "afterDelay",
// 开启 material icons
"workbench.iconTheme": "office-material-icon-theme",
// theme主题设置
"workbench.colorTheme": "Default Dark Modern",
//粘贴时格式化代码
"editor.formatOnPaste": true,
//保存时格式化代码
"editor.formatOnSave": true,
//设置字体的大小,最小值能设置为6
"editor.fontSize": 15,
//设置字体的粗细
"editor.fontWeight": "500",
//设置字体的样式
// "terminal.integrated.fontFamily":"Courier New",
//使用Ctrl+滚轮缩放编辑区的字体大小
"editor.mouseWheelZoom": true,
//使用Ctrl+滚轮缩放终端Terminal的字体大小
"terminal.integrated.mouseWheelZoom": true,
//设置为false,这样打开新的文件时,不会自动关闭旧的文件
"workbench.editor.enablePreview": false,
"security.workspace.trust.enabled": false,
"VsCodeTaskButtons.showCounter": true,
"VsCodeTaskButtons.tasks": [
{
"label": "$(tools) Build", // 显示标签
"task": "CMake build", // 对应tasks.json里的任务label
"tooltip": "🛠️ build" // 工具提示框
},
{
"label": "$(notebook-delete-cell) Clean",
"task": "CMake clean",
"tooltip": "🧹 clean"
},
{
"label": "$(notebook-delete-cell) $(tools) Re-bulid", //"$(notebook-delete-cell) & $(tools)",
"task": "CMake cleanRebuild",
"tooltip": "🛠️ rebuild" // "🧹 & 🛠️ rebuild"
},
{
"label": "$(zap) Download",
// "task": "CMake download",
"tasks": [
{
"label": "⚓ CMSIS-DAP-Link", //icon copied from https://emojipedia.org/
"task": "flash with CMSIS-DAP-Link"
},
{
"label": "⤵️ ST-Link", //icon copied from https://emojipedia.org/
"task": "flash with ST-Link"
},
{
"label": "🚀 J-Link", //icon copied from https://emojipedia.org/
"task": "flash with J-Link"
}
],
"tooltip": "⚡ download"
}
],
}
c_cpp_properties.json:
{
"configurations": [
{
"name": "Win32-arm-gcc-dev",
"includePath": [ // 设置编辑器中的头文件查找目录
"${workspaceFolder}/**"
],
"defines": [
"_DEBUG",
"UNICODE",
"_UNICODE",
"__MICROLIB",
"__CC_ARM" // 解决编辑器中提示无法识别uint32_t, uint16_t, uint8_t的问题
],
"compilerPath": "E:/embedded_dev_tools/xpack-arm-none-eabi-gcc-13.3.1-1.1/bin/arm-none-eabi-gcc.exe",//解决编辑器中提示无法识别例如__attribute__((weak))等gcc编译器功能选项
"cStandard": "gnu17", // 设置使用的C标准
"cppStandard": "gnu++17", // 设置使用的C++标准
"intelliSenseMode": "gcc-arm", // 设置编译器类型,解决编辑器中提示无法识别例如__attribute__((weak))等gcc编译器功能选项
"configurationProvider": "ms-vscode.cmake-tools"
}
],
"version": 4
}
tasks.json:
{
//快捷键ctrl+shift+B调出各个task命令
"tasks": [
{
"type": "cmake",
"label": "CMake build",
"command": "build",
"targets": [
"${workspaceRootFolderName}.elf"
],
"group": "build",
"problemMatcher": [
"$gcc"
]
},
{
"type": "cmake",
"label": "CMake cleanRebuild",
"command": "cleanRebuild",
"targets": [
"${workspaceRootFolderName}.elf"
],
"group": "build",
"problemMatcher": [
"$gcc"
]
},
{
"type": "cmake",
"label": "CMake clean",
"command": "clean",
"problemMatcher": [
"$gcc"
]
},
{
"type": "shell",
"label": "flash with CMSIS-DAP-Link",
"command": "openocd",
"args": [
"-f",
"interface/cmsis-dap.cfg",
"-f",
"target/stm32f1x.cfg",
"-c",
"program build/${workspaceRootFolderName}.elf verify reset exit"
],
"problemMatcher": [
"$gcc"
],
"group": "build"
},
{
"type": "shell",
"label": "flash with ST-Link",
"command": "openocd",
"args": [
"-f",
"interface/stlink.cfg",
"-f",
"target/stm32f1x.cfg",
"-c",
"program build/${workspaceRootFolderName}.elf verify reset exit"
],
"problemMatcher": [
"$gcc"
],
"group": "build"
},
{
"type": "shell",
"label": "flash with J-Link",
"command": "openocd",
"args": [
"-f",
"interface/jlink-swd.cfg",
"-f",
"target/stm32f1x.cfg",
"-c",
"program build/${workspaceRootFolderName}.elf verify reset exit"
],
"problemMatcher": [
"$gcc"
],
"group": "build"
}
],
"version": "2.0.0"
}
launch.json:
{
// 使用 IntelliSense 了解相关属性。
// 悬停以查看现有属性的描述。
// 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "Debug with CMSIS-DAP-Link",
"cwd": "${workspaceRoot}",
"executable": "./build/${workspaceRootFolderName}.elf",
"request": "launch",
"type": "cortex-debug",
"servertype": "openocd",
"device": "STM32F103VET6",
// "openOCDLaunchCommands": [
// "adapter speed 10000"
// ],
"configFiles": [
"interface/cmsis-dap.cfg", // D:/Software/arm_riscv_develop_tools/openocd/openocd/scripts/interface
"target/stm32f1x.cfg" // D:/Software/arm_riscv_develop_tools/openocd/openocd/scripts/target
],
"svdFile": "./STM32F103.svd", //选择寄存器文件
"liveWatch": {
"enabled": true,
"samplesPerSecond": 4
},
"searchDir": [],
"runToEntryPoint": "main",
"showDevDebugOutput": "none",
"preLaunchTask": "flash with CMSIS-DAP-Link"
},
{
"name": "Debug with ST-Link",
"cwd": "${workspaceRoot}",
"executable": "./build/${workspaceRootFolderName}.elf",
"request": "launch",
"type": "cortex-debug",
"servertype": "openocd",
"device": "STM32F103VET6",
// "openOCDLaunchCommands": [
// "adapter speed 10000"
// ],
"configFiles": [
"interface/stlink.cfg", // D:/Software/arm_riscv_develop_tools/openocd/openocd/scripts/interface
"target/stm32f1x.cfg" // D:/Software/arm_riscv_develop_tools/openocd/openocd/scripts/target
],
"svdFile": "./STM32F103.svd", //选择寄存器文件
"liveWatch": {
"enabled": true,
"samplesPerSecond": 4
},
"searchDir": [],
"runToEntryPoint": "main",
"showDevDebugOutput": "none",
"preLaunchTask": "flash with ST-Link"
},
{
"name": "Debug with J-Link",
"cwd": "${workspaceRoot}",
"executable": "./build/${workspaceRootFolderName}.elf",
"request": "launch",
"type": "cortex-debug",
"servertype": "openocd",
"device": "STM32F103VET6",
// "openOCDLaunchCommands": [
// "adapter speed 10000"
// ],
"configFiles": [
"interface/jlink-swd.cfg", // D:/Software/arm_riscv_develop_tools/openocd/openocd/scripts/interface
"target/stm32f1x.cfg" // D:/Software/arm_riscv_develop_tools/openocd/openocd/scripts/target
],
"svdFile": "./STM32F103.svd", //选择寄存器文件
"liveWatch": {
"enabled": true,
"samplesPerSecond": 4
},
"searchDir": [],
"runToEntryPoint": "main",
"showDevDebugOutput": "none",
"preLaunchTask": "flash with J-Link"
}
]
}
三、CMakeLists.txt——构建文件
CMakeLists.txt:
#THIS FILE IS AUTO GENERATED FROM THE TEMPLATE! DO NOT CHANGE!
set(CMAKE_SYSTEM_NAME Generic)
set(CMAKE_SYSTEM_VERSION 1)
# cmake最低版本需求
cmake_minimum_required(VERSION 3.20)
# 设置编译器:specify cross compilers and tools
# 当编译工具链路径被加到环境变量中,可以直接写编译工具的名称;若未加入环境变量,此处应写对应交叉编译工具链的绝对路径。
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)
# 链接的类型设置为STATIC, 以便嵌入式ARM-GNU通过CMake的"编译器检查"
set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY)
# project : 定义工程名称,并可以指定工程可支持的语言,语法格式为 project(项目域名 语言)
# .HEX .bin .elf .map的文件名设置
project(Led_Toggle C CXX ASM)
# C/C++语言标准版本配置
set(CMAKE_C_STANDARD 17)
set(CMAKE_CXX_STANDARD 17)
#Uncomment for hardware floating point
#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)
#Uncomment for software floating point
#add_compile_options(-mfloat-abi=soft)
#编译选项定义
# 对于 cortex-m3
# +---------------------------------------------------+
# | -mthumb -mcpu=cortex-m3 或 -mthumb -march=armv7-m |
# +---------------------------------------------------+
# 对于 cortex-m4
# +---------------------------------------------------+
# | -mthumb -mcpu=cortex-m4 或 -mthumb -march=armv7-m|
# +---------------------------------------------------+
# 对于 cortex-m7
# +---------------------------------------------------+
# | -mthumb -mcpu=cortex-m7 或 -mthumb -march=armv7-m |
# +---------------------------------------------------+
# -mcpu=cortex-m3 告诉编译器为 ARM Cortex-M3 处理器生成代码
# -mthumb 启用 Thumb 指令集,Thumb 指令集是一种 16 位指令集
# -march=armv7-m 指定目标架构,ARMv7-M 是 Cortex-M3 处理器使用的架构
set(MCU_FLAGS -mcpu=cortex-m3 -mthumb -mthumb-interwork) # 编译选项定义修改处
#-fdata-sections用于将每个符号创建为一个sections,其中每个sections名与data名保持一致。
#-ffunction-sections用于将每个函数创建为一个sections,其中每个sections名与function名保持一致。
#用于代码的分割和裁剪,会将每一个函数都拆分成.text(Code+RO-data)段、.data(RW-data)段、.bss(ZI-data)段,这部分和对象文件的链接有关。如果没有这两个参数,编译器就会按文件分段而不是按照函数分段。
#加上这两个参数,配合链接器可以#去除代码中无用的部分,减少最终可执行文件的大小。
#-fno-common用于未初始化的全局变量当成强符号,重复定义就会报错。
#开启-fmessage-length=0会让编译器展示所有的消息而不会限制错误和警告输出的长度
set(OPTIMIZE_COMPILE_FLAGS -ffunction-sections -fdata-sections -fno-common -fmessage-length=0)
# 针对所有编译器,开启编译警告 (包括C、C++编译器),-Wall可开启所有警告;-Werror将所有警告视为error
# add_compile_options("-Wall -Werror")
add_compile_options(${MCU_FLAGS})
add_compile_options(${OPTIMIZE_COMPILE_FLAGS})
# /*
# 编译等级选项:优化等级
# -O0:无任何优化,关闭所有优化选项
# -O、-O1:1级优化,
# -O2: 2级优化,
# -Os: 2.5级优化,-Os启用所有通常不会增加代码大小的-O2优化。 它还执行旨在减少代码大小的进一步优化。
# -O3: 最高级优化。
# -Og:优化调试体验。 -Og启用不会干扰调试的优化。 它是标准编辑 - 编译 - 调试周期可以选择的优化级别,提供合理的优化级别,同时保持快速编译和良好的调试体验。
# -Ofast:无视严格的标准合规性。 -Ofast启用所有-O3优化。 它还打开并非对所有符合标准的程序有效的优化。
# */
#设置代码调试等级
set(CMAKE_BUILD_TYPE "Debug")
# +---------------+--------------+--------------+----------+
# | | optimization | assert works | stripped |
# +---------------+--------------+--------------+----------|
# | Debug | no | yes | no |
# | Release | full | no | yes |
# | RelWithDebInfo| good | no | no |
# | MinSizeRel | size | no | yes |
# +---------------+--------------+--------------+----------+
# Release 进行优化,提高速度 -排除调试信息
if ("${CMAKE_BUILD_TYPE}" STREQUAL "Release")
message(VERBOSE "Maximum optimization for speed")
add_compile_options(-Ofast)
# RelWithDebInfo 进行优化,提高速度 -包含调试信息
elseif ("${CMAKE_BUILD_TYPE}" STREQUAL "RelWithDebInfo")
message(VERBOSE "Maximum optimization for speed, debug info included")
add_compile_options(-Ofast -g)
# MinSizeRel 优化二进制大小 -排除调试信息
elseif ("${CMAKE_BUILD_TYPE}" STREQUAL "MinSizeRel")
message(VERBOSE "Maximum optimization for size")
add_compile_options(-Os)
# Debug 禁用优化 -包含调试信息
else ()
message(VERBOSE "Minimal optimization, debug info included")
add_compile_options(-O0 -g)
endif ()
#添加C文件编译宏定义
add_definitions(
-DUSE_HAL_DRIVER
-DSTM32F103xE
-DUSE_STDPERIPH_DRIVER
-DSTM32F10X_HD
)
# add_definitions(-DUSE_STDPERIPH_DRIVER -DSTM32F10X_HD)
#添加头文件路径,即.h文件
include_directories(
./STM32F10x_FWLib/inc
./SYSTEM/delay
./SYSTEM/sys
./SYSTEM/usart
./HARDWARE/inc
./USER/inc
./CORE/inc
./CMSIS/inc
)
# 这三个变量指代的内容是一致的,指的是工程编译产生的目录
# +------------------+--------------------+--------------------------+
# | CMAKE_BINARY_DIR | PROJECT_BINARY_DIR | <projectname>_BINARY_DIR |
# +------------------+--------------------+--------------------------+
# 这三个变量指代的内容是一致的,指的就是工程顶级目录
# +------------------+--------------------+--------------------------+
# | CMAKE_SOURCE_DIR | PROJECT_SOURCE_DIR | <projectname>_SOURCE_DIR |
# +------------------+--------------------+--------------------------+
#添加汇编启动文件路径,startup文件是STM32CubeMX生成的(需要gcc版本,不要使用MDK版本)
ENABLE_LANGUAGE(ASM) #为了让cmake识别启动文件
set(SRC_STARTUP "${CMAKE_SOURCE_DIR}/startup_s/startup_stm32f103xe.s")
#添加源文件路径,即.c文件
#file语法,前一个参数是固定的GLOB_RECURSE, 后面一个参数自行定义
file(GLOB_RECURSE SOURCES
./STM32F10x_FWLib/src/*.c
./USER/src/*.c
./CMSIS/src/*.c
./CORE/src/*.c
./SYSTEM/delay/*.c
./SYSTEM/sys/*.c
./SYSTEM/usart/*.c
./HARDWARE/src/*.c
)
#-specs=nosys.specs -specs=nano.specs选择链接精简C库newlib-nano,而非标准C库glibc/glibc++
#-u _printf_float显式启用浮点数打印 -u _scanf_float显式启用浮点数输入
set(OPTIMIZE_LD_FLAGS -Wl,--no-warn-rwx-segments -flto -specs=nano.specs -specs=nosys.specs -u _printf_float) # -u _scanf_float
#添加.ld链接脚本路径
set(LINKER_SCRIPT "${CMAKE_SOURCE_DIR}/link_script/STM32F103VETx_FLASH.ld")
#-cref则生成交叉引用表方便查找未定义的符号引用(比如编译时出现的undefined reference)
#--print-memory-usage选项提供链接器文件中定义的每个内存区域使用的内存的详细信息
#输出.map文件
set(MAP_FLAGS -Wl,--cref,--print-memory-usage,-Map=${PROJECT_BINARY_DIR}/${PROJECT_NAME}.map)
#链接选项配置
add_link_options(${MCU_FLAGS})
# add_link_options(-Wl,--no-warn-rwx-segments,--print-memory-usage,-Map=${PROJECT_BINARY_DIR}/${PROJECT_NAME}.map)
# add_link_options(-specs=nano.specs -specs=nosys.specs -u _printf_float) # -u _scanf_float
add_link_options(${OPTIMIZE_LD_FLAGS})
add_link_options(-T ${LINKER_SCRIPT})
add_link_options(${MAP_FLAGS})
#根据源文件、汇编启动文件、链接脚本 生成 .elf可执行文件
add_executable(${PROJECT_NAME}.elf ${SRC_STARTUP} ${SOURCES} ${LINKER_SCRIPT})
set(ELF_FILE ${PROJECT_BINARY_DIR}/${PROJECT_NAME}.elf)
set(HEX_FILE ${PROJECT_BINARY_DIR}/${PROJECT_NAME}.hex)
set(BIN_FILE ${PROJECT_BINARY_DIR}/${PROJECT_NAME}.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}")
CMakeLists.txt
文件及注释的参考链接如下:
1)使用VScode开发STM32:基于CMake(包含标准库和HAL库工程)
2)VSCode 和 CMake 搭建嵌入式开发环境
3) 在Windows上使用VS Code搭建开发环境-基于STM32F103C8T6
4)cmake:设置编译选项
5)CMake进阶(一)设置编译选项
6)跨平台编译工具-CMake的语法特性与常用变量
7)【gcc】gcc优化等级 -O1 -O2 -O3 -Os -Ofast -Og|gcc关闭优化
8)arm-none-eabi-gcc编译、链接选项详解
9)gcc for arm 工具链使用(一)
📚NOTE:
①默认情况下,CMake使用本地编译器,如gcc,而嵌入式开发使用的是交叉编译器,如arm-none-eabi-gcc,CMake无法知道该使用哪个交叉编译器,因此需要明确地告知CMake。在VSCode中,CMake选择配置本地的arm-gcc或gcc工具链的方法步骤如下图所示,
同时修改c_cpp_properties.json
的"compilerPath"
处为arm-none-eabi-gcc.exe
的绝对路径,如下图所示,
②如果读者将上述的CMakeLists.txt
文件移植到自己的标准库 / HAL库工程后,需要重新生成CMake和当前项目相关的配置,否则会报错。参考方法的截图如下,
③显式启用浮点数打印和输入功能的问题(未解决)
arm-none-eabi-gcc工具链发布时自带有2个基于newlib的预构建C库:一个是标准的newlib,另一个是newlib-nano(优化了代码大小)
要使用newlib-nano,用户应该提供额外的gcc编译和链接时选项:-specs=nano.specs。
在编译时,如果-specs=nano.specs被传递给编译器,那么一个专门为newlib-nano配置的“newlib.h”
头文件会被使用。
nano.specs还能处理另外两个gcc库:libstdc++_nano.a和libsupc++_nano.a,它们同样针对代码大小进行了优化。
newlib-nano相比newlib,不仅仅是库的名字上的区别。浮点数的格式化input/output被实现为弱符号(隐式)。如果要使用%f,则必须通过显式指定"-u"
命令选项来引入该符号。
参考链接:
1)Newlib 与 Newlib-Nano区别
2) [开发工具]为什么gcc编译出来的程序大小和Keil差别这么大
3)Shrink Your MCU code size with GCC ARM Embedded 4.7
#显式指定"-u"命令选项
-u _scanf_float
-u _printf_float
在CMakeLists.txt
的可选链接选项配置中,加入-u _printf_float,_scanf_float
,虽然这样不会报错,但是load程序进MCU后,无法打印浮点数。
如下图所示,
如果仿照使用Makefile
中一样的-u _printf_float -u _scanf_float
显式启用,即如下图所示,则会发生报错:无法找到_scanf_float。
可能是笔者对CMake语法不熟悉,不太能理解在CMakeLists.txt
中为何需写成-u _printf_float,_scanf_float
才不报错(但是无法打印浮点数)。
所以最终笔者改成了只显式启用-u _printf_float
浮点数打印,没有加上显式启用-u _scanf_float
浮点数输入。
如果各位读者对此有深入研究的见解,欢迎发表评论,指点笔者一二。
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.kler.cn/a/445140.html 如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!