当前位置: 首页 > news >正文

VSCode+arm-none-eabi-gcc交叉编译+CMake构建+OpenOCD(基于STM32的标准库/HAL库)

前言:什么是CMake?

Answer:简而言之,CMake是Make的maker。

一、CMake的安装

  • 进入CMake官网的下载地址Get the Software,根据系统安装对应的Binary distributions。
    在这里插入图片描述
  • 或者在CMake——国内镜像获取二进制镜像安装包。 在这里插入图片描述
  • 或者访问GitHub的xPack项目xPack CMake v3.28.6-1,下载即可。

记得添加用户/系统的环境变量,然后打开cmd窗口,输入cmake -version,查看CMake环境变量是否添加成功,如下图所示。
在这里插入图片描述

二、工程所需配置文件

本文以【STM32F103ZET6】单片机为示例来进行演示,以下配置文件对于标准库/HAL库工程是通用的。
更多细节请基于【VSCode编辑+GCC for ARM交叉编译工具链+Makefile构建+OpenOCD调试(基于STM32的标准库)】该篇文章参考。

下面列出几个重要的配置文件:

①:

  • settings.json

  • c_cpp_properties.json

  • tasks.json

  • launch.json

  • settings.json、c_cpp_properties.json、tasks.json、launch.json的修改要点请参考【.vscode文件夹中各个JSON脚本需要修改的地方】。

②:

  • CMakeLists.txt

③:

  • MCU链接脚本.ld、MCU汇编启动文件.s、MCU寄存器文件.svd的获取方式请参考【VSCode编辑+GCC for ARM交叉编译工具链+Makefile构建+OpenOCD调试(基于STM32的标准库)】。

三、VSCode脚本文件

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","__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","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(CMAKE_SIZE arm-none-eabi-size)
set(CMAKE_READELF arm-none-eabi-readelf)
set(CMAKE_NM arm-none-eabi-nm)
# 链接的类型设置为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-m0 / cortex-m0+ / cortex-m1
#   +---------------------------------------------------+
#   | -mthumb -mcpu=cortex-m0/cortex-m0+/cortex-m1 或 -mthumb -march=armv6-m |
#   +---------------------------------------------------+#   对于 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 |
#   +---------------+---------------+--------------+--------------+----------|
#   |               |     None      |              |              |          |
#   |    -g         |     Debug     |     no       |     yes      |    no    |
#   |-O3 -DNDEBUG   |    Release    |    full      |      no      |   yes    |
#   |-O2 -g -DNDEBUG| RelWithDebInfo|    good      |      no      |    no    |
#   |-Os -DNDEBUG   |   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(-Og -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)# -Wl,--gc-sections 链接使用的分段方式,需要配合C文件/汇编生成obj的时候同样选型分段方式,
# 好处是链接的时候源文件中的未使用变量和未调用函数将不会被链接到elf文件中,最终可执行文件elf会很精简。
# -no-warn-rwx-segments:消除 LOAD segment with RWX permissions 警告
# -flto, 链接时优化,会减少程序体积,同时也会略微降低性能(当测试coremark时)
# -specs=nano.specs选择链接精简C库newlib-nano,而非标准C库glibc或newlib。
# -specs=nosys.specs禁止链接任何系统库(如glibc或newlib)。
# -u_printf_float显式启用浮点数打印 -u_scanf_float显式启用浮点数输入
set(OPTIMIZE_LD_FLAGS -Wl,--gc-sections,--no-warn-rwx-segments -flto -specs=nano.specs -specs=nosys.specs -u_printf_float -u_scanf_float)#添加.ld链接脚本路径
# -T$(LDSCRIPT)依赖的可执行文件链接脚本
set(LINKER_SCRIPT "${CMAKE_SOURCE_DIR}/link_script/STM32F103VETx_FLASH.ld")#-cref则生成交叉引用表方便查找未定义的符号引用(比如编译时出现的undefined reference)
#--print-memory-usage选项提供链接器文件中定义的每个内存区域使用的内存的详细信息
# -Wl,-Map=$(BUILD_DIR)/$(TARGET).map,--cref 生成map文件
set(MAP_FLAGS -Wl,--print-memory-usage,-Map=${PROJECT_BINARY_DIR}/${PROJECT_NAME}.map,--cref)#链接选项配置
add_link_options(${MCU_FLAGS})
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)# Print executable size
add_custom_command(TARGET "${PROJECT_NAME}.elf" POST_BUILDCOMMENT "Invoking: Cross ARM GNU Print Size"COMMAND ${CMAKE_SIZE} ${PROJECT_NAME}.elf)# Create hex & bin file
add_custom_command(TARGET "${PROJECT_NAME}.elf" POST_BUILDCOMMAND ${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 工具链使用(一)
10)arm gcc编译选项
11)【ARMv8M Cortex-M33 系列 3.1 – RT-Thread renesas/ra4m2-eco 移植编译篇 nosys.specs 介绍】
12)GCC编译器的常用参数及用法,你都清楚吗?
13)用CMake提升STM32开发效率:完整配置与构建流程(一)

五、tips和遗留问题

📚① 默认情况下,CMake使用本地编译器,如gcc,而嵌入式开发需使用交叉编译器,如arm-none-eabi-gcc,因此需要明确地告知CMake使用交叉编译器。在VSCode中,CMake选择配置本地的arm-none-eabi-gcc或gcc工具链的方法步骤如下图所示:
在这里插入图片描述
同时修改c_cpp_properties.json"compilerPath"处为arm-none-eabi-gcc.exe的绝对路径,如下图所示,
在这里插入图片描述

📚② 如果读者将上述的CMakeLists.txt文件移植到自己的标准库 / HAL库工程后或者更改了CMakeMakefile构建生成类型后,需要重新生成CMake和当前项目相关的配置,否则会报错。参考方法的截图如下,
在这里插入图片描述
📚③ 设置CMake的构建文件类型(已解决)

  • 查看CMake在操作系统中默认的构建文件类型:打开cmd→输入cmake -G→下拉观察到有*符号在前的选项,是默认选择的CMake构建文件类型,如下图所示:笔者的Windows操作系统默认选择NMake Makefiles
    在这里插入图片描述

  • 设置CMake的构建文件类型:

  • 在Windows操作系统中:按下键盘的开始菜单键→直接打出“高级”→查看高级系统设置→设置环境变量→在用户变量区新建环境变量,设置变量名为CMAKE_GENERATOR和变量值为Unix Makefiles,之后一直点击确定即可。
    NOTE:Windows操作系统的CMake构建文件类型可选择不设置环境变量,只在VSCode中设置即可,此处只是作拓展说明。
    在这里插入图片描述
    再次打开cmd,输入cmake -G,可以看到CMake在操作系统中默认的构建文件类型已被修改为Unix Makefiles,如下图所示。
    在这里插入图片描述

  • 在VSCode中:依次打开VSCode左侧的CMake Tools→项目大纲右侧的【更多操作】→编辑CMake缓存(UI)→进入到CMake缓存编辑器→找到CMAKE_GENERATOR,可以看到VSCode中的CMake默认使用Unix Makefiles来构建文件。
    在这里插入图片描述
    问题来了:我们如何修改CMake默认的构建文件类型呢?例如将 Unix MakefilesMinGW Makefiles
    答案:在工程目录的.vscode中settings.json文件中加入"cmake.generator": "MinGW Makefiles"即可。
    如下图所示:
    在这里插入图片描述
    更换了CMake默认的构建文件类型后,此时点击构建工程会发生如下错误:
    在这里插入图片描述
    我们按如下指示,令CMake清理所有项目并重新配置即可解决
    在这里插入图片描述
    可以看到,CMake缓存编辑器的CMAKE_GENERATOR已经被更换为了MinGW Makefiles
    在这里插入图片描述

📚④ /build构建目录
GNU/Linux上,CMake默认生成Unix Makefiles来构建项目:
在这里插入图片描述

  • CMakeFiles:包含临时文件的目录,CMake用于检测操作系统、编译器等。此外,根据所选的生成器 make / ninja,它还包含特定的文件。
  • cmake_install.cmake:处理安装规则的CMake脚本,在项目安装时使用。
  • CMakeCache.txt:如文件名所示,CMake缓存。CMake在重新运行配置时使用这个文件
  • Makefile: make将运行指令来构建项目。(如果选择ninja构建生成器,则该文件为build.ninja和rules.ninja:包含Ninja的所有的构建语句和构建规则

📚⑤ 显式启用 “浮点数输入” 的问题(已解决)

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"命令选项来引入该符号。

#显式指定"-u"命令选项-u _scanf_float-u _printf_float

参考链接:
1)Newlib 与 Newlib-Nano区别
2) [开发工具]为什么gcc编译出来的程序大小和Keil差别这么大
3)Shrink Your MCU code size with GCC ARM Embedded 4.7
4)嵌入式GCC库: newlib与nanolib区别
5)CoIDE 1.6.2下使用ARM GCC 4.7 Newlib-nano printf 重定向到UART
6)Stm32串口搭配DMA实现自定义printf、scanf

CMakeLists.txt的可选链接选项配置中,如果仿照Makefile中一样的-u _printf_float -u _scanf_float显式启用,即如下图所示,则会发生报错:无法找到_scanf_float。

在这里插入图片描述
因此在CMakeLists.txt中,笔者删除了-u后面的空格,将显式启用修改为-u_printf_float -u_scanf_float,即可消除报错并能正常打印浮点数,如下图所示。
在这里插入图片描述
在这里插入图片描述

相关文章:

VSCode+arm-none-eabi-gcc交叉编译+CMake构建+OpenOCD(基于STM32的标准库/HAL库)

前言&#xff1a;什么是CMake&#xff1f; Answer&#xff1a;简而言之&#xff0c;CMake是Make的maker。 一、CMake的安装 进入CMake官网的下载地址Get the Software&#xff0c;根据系统安装对应的Binary distributions。 或者在CMake——国内镜像获取二进制镜像安装包。 …...

MarsCode AI实战:利用DeepSeek 快速搭建你的口语学习搭子

资料来源&#xff1a;火山引擎-开发者社区 成品抢先看&#xff01; 自从MarsCode AI Chat模型全新升级&#xff0c;接入 Deepseek-R1、Deepseek-V3和豆包大模型1.5 三大模型&#xff0c;越来越多朋友注意到了AI编程能给我们带来的无限可能&#xff0c;也开始跃跃欲试想要尝试从…...

导出的使用

一.导出的具体使用步骤 1.在web开发中&#xff0c;导出是很常见的一个功能&#xff0c;当我进行个人项目练习的时候&#xff0c;导出的时候无法控制列宽以及居中样式&#xff0c;后续发现导出插件无法进行修改&#xff0c;整个插件较为简便易懂的同时&#xff0c;对于EX的控制…...

【OCR】总结github上开源 OCR 工具:让文字识别更简单

前言 在数字化的时代&#xff0c;光学字符识别&#xff08;OCR&#xff09;技术成为了我们处理文档、图像文字信息的得力助手。它能够将图像中的文字信息转换为可编辑和可处理的文本数据&#xff0c;极大地提高了信息处理的效率。今天&#xff0c;我要给大家介绍一些优秀的开源…...

struts1+struts2项目兼容升级到了spring boot 2.7

原项目比较复杂&#xff0c;集成了各种框架&#xff08;struts1 struts2 spring3等&#xff09;&#xff0c;趁工作之余练练手&#xff0c;学习一下springboot。大概花了一周时间才调通。 一、调整jar版本&#xff0c;寻找合适的版本。 第一步、首先原项目JDK6&#xff0c;要…...

Odoo 18 中的列表(list) 、表单(Form)、数据透视表、图表视图、看板视图、活动视图、日历视图等综合应用实例

Odoo 18 中的 视图应用实例 在 Odoo 中&#xff0c;视图是用户界面中表示业务对象的重要组成部分。无论您是扩展现有功能还是创建全新的功能&#xff0c;业务对象都至关重要。这些对象通过不同类型的视图向用户展示&#xff0c;而 Odoo 会根据 XML 描述动态生成这些视图。 列…...

单元测试mock

一、背景 现在有A类,B类,C类&#xff0c;A类依赖B类,依赖C类&#xff0c;如果想要测试A类中的某个方法的业务逻辑。A类依赖其他类&#xff0c;则把其他类给mock&#xff0c;然后A类需要真实对象。这样就可以测试A类中的方法。 举例&#xff1a;Ticket类需要调用Flight类和Pas…...

PDF文件转Markdown,基于开源项目marker

​ 首先我们来问下deepseek 为啥要选marker呢 基于深度学习&#xff0c;一看就逼格拉满。搞科研必备&#xff0c;效果应该不会太差。跟其他的阿猫阿狗工具没法比。 看下官网 https://github.com/VikParuchuri/marker ​ 一看头像是个印度佬&#xff0c;自吹——又快又好。…...

mysql中find_in_set()函数用法详解及增强函数

MySQL的 FIND_IN_SET()函数是一种特殊的函数&#xff0c;它主要用于搜索一个字符串在一个逗号分隔的字符串列表中的位置。 函数的基本语法 FIND_IN_SET(str, strlist) 其中&#xff0c;str是你想要查找的字符串&#xff0c;而 strlist是一个包含多个以逗号分隔的字符串的列表…...

深入理解 JavaScript/TypeScript 中的假值(Falsy Values)与逻辑判断 ✨

&#x1f579;️ 深入理解 JavaScript/TypeScript 中的假值&#xff08;Falsy Values&#xff09;与逻辑判断 在 JavaScript/TypeScript 开发中&#xff0c;if (!value) 是最常见的条件判断之一。它看似简单&#xff0c;却隐藏着语言的核心设计逻辑&#xff0c;也是许多开发者…...

批量合并 PPT 文件,支持合并成单个文件也支持按文件夹合并

合并多个 PPT 为一个 PPT 文档是我们经常会碰到的需求&#xff0c;合并后不仅更容易管理&#xff0c;在某些场景&#xff08;比如批量打印&#xff09;下也非常的有用&#xff0c;那当我们需要批量合并多个 PPT 文档地时候&#xff0c;我们有没有比较高效的方法呢&#xff1f;今…...

Java复习

在开篇前首先申明一下&#xff0c;本文虽不够系统&#xff0c;但复习够用&#xff0c;尤其是快速回忆( •̀ ω •́ )✧与提问。 主打一个速度。 本文将会从Java的基础语法、面向对象、API、字符串、集合、进阶...等六方面讲起。 一、Java的基础语法&#xff1a; 1、Java入门…...

keepalived+nginx+tomcat高可用

1.要求 角色主机名软件IP地址用户client192.168.72.90keepalivedvip192.168.72.100mastermasterkeepalived, nginx192.168.72.30backupbackupkeepalived, nginx192.168.72.32webtomcat1tomcat192.168.72.41webtomcat2tomcat192.168.72.42 1.搭建Tomcat 1.1下载jdk wget http…...

RK3568 Android11 sh366006驱动

sh366006.c /* 谁愿压抑心中怒愤冲动咒骂这虚与伪与假从没信要屈膝面对生命纵没有别人帮一生只靠我双手让我放声疯狂叫囔今天的他 呼风可改雨不可一世太嚣张 --《不可一世》Beyond */ #include <linux/module.h> #include <linux/init.h> #include <linux/fs.h…...

实现分布式锁需要考虑哪些问题?

&#x1f512; 什么是分布式锁&#xff1f; 分布式锁是在分布式系统中控制共享资源访问的机制&#xff0c;用于解决高并发场景下数据不一致、操作冲突等问题。核心目标是保证跨进程 / 跨节点的互斥性&#xff0c;常见实现方案包括&#xff1a;数据库锁、Redis 锁、ZooKeeper 锁…...

【UI设计】一些好用的免费图标素材网站

阿里巴巴矢量图标库https://www.iconfont.cn/国内最大的矢量图标库之一&#xff0c;拥有 800 万 图标资源。特色功能包括团队协作、多端适配、定制化编辑等&#xff0c;适合企业级项目、电商设计、中文产品开发等场景。IconParkhttps://iconpark.oceanengine.com/home字节跳动…...

mysql-大批量插入数据的三种方式和使用场景

1.批量插入三种方式 INSERT INTO … SELECTINSERT INTO … VALUES (…)LOAD DATA INFILE ‘/path/to/datafile.csv’ INTO TABLE table_name 2.批量插入 2.1 INSERT INTO … SELECT 用途&#xff1a;从另一个表中选择数据并插入到目标表中。 语法示例&#xff1a; INSERT …...

创建自己的github.io

1、创建GitHub账号 GitHub地址&#xff1a;https://github.com/ 点击Sign up创建账号 如果已创建&#xff0c;点击Sign in登录 2、创建仓库 假设Owner为username&#xff0c;则Repository name为username.github.io说明&#xff1a; 1、Owner为用户名 2、Repository name为仓…...

Oracle 常用语法汇总

系列文章目录 本文对Oracle 常用的语法进行汇总 文章目录 系列文章目录一、Oracle 表&表字段操作&#xff1a;1.1 DDL语句(数据定义语言)Create、Alter、Drop、Truncate&#xff1a;1.1.1 建表&#xff1a;建表&#xff1a;注释COMMENT :表中字段的约束&#xff1a;表中字…...

java小白日记38(集合-List)

List接口基本介绍 List接口是collection接口的子接口 &#xff08;1&#xff09;List集合类中元素有序&#xff08;即添加顺序和取出顺序一致&#xff09;、且可以重复 &#xff08;2&#xff09;List集合中的每个元素都有其对应的顺序索引&#xff0c;即支持索引 &#xf…...

高能ISP模块功能说明

先看一些常见缩写&#xff1a; BPS&#xff1a;Bayer processing segment CPP&#xff1a;Camera post processor DE&#xff1a;Detailed enhancement EIS&#xff1a;Electronic image stabilization IFE&#xff1a;Image front-end engine IPE&#xff1a;Image-proc…...

单臂路由实验

单臂路由实验 文章目录 单臂路由实验单臂路由简介工作原理优点与缺点应用场景 实验拓扑实验需求&#xff1a;实验步骤&#xff1a;1.PC 配置 IP 地址2.PC3 属于 Vlan10&#xff0c;PC4 属于 Vlan20&#xff0c;配置单臂路由实现 Vlan10 和 Vlan20 三层互通2.1.在 SW2 上创建 Vl…...

SpringMVC全局异常处理机制

异常处理机制 异常处理的两种方式&#xff1a; 编程式异常处理&#xff1a;是指在代码中显式地编写处理异常的逻辑。它通常涉及到对异常类型的检测及其处理&#xff0c;例如使用 try-catch 块来捕获异常&#xff0c;然后在 catch 块中编写特定的处理代码&#xff0c;或者在 f…...

UDS诊断、ECU刷写、自动化测试、车联网测试、DTC故障注入测试、坏境测试、可靠性测试、压力测试、性能测试等

每日直播时间&#xff1a;&#xff08;直播方式&#xff1a;腾讯会议&#xff09; 周一到周五&#xff1a;20&#xff1a;00-23&#xff1a;00 周六与周日&#xff1a;9&#xff1a;00-17&#xff1a;00 向进腾讯会议学习的&#xff0c;可以关注我并后台留言 直播内容&#xff…...

C++的常用容器嵌套

在 C 中&#xff0c;数据结构之间的嵌套是非常常见的&#xff0c;尤其是在处理复杂数据时。以下是几种最常用的数据结构嵌套方式及其典型应用场景的总结&#xff1a; 1. std::vector 嵌套 std::vector 定义&#xff1a;std::vector<std::vector<T>>。用途&#xf…...

Mac - Cursor 配置 + GPT 4.0/4.5/o1/o3/Deepseek Api 使用

前言 新换了电脑&#xff0c;所以需要新配置一些环境。已经安装好了Goland&#xff0c;但近期可能有GoJava前端的需求&#xff0c;所以使用Cursor。 除去学校各种奇奇怪怪&#xff0c;这已经是一年多来配置的第4台Windows和第四台Mac的Golang环境了。。。且是自己工作外买的第…...

【数据挖掘】Python基础环境安装配置

【数据挖掘】Python基础环境安装配置 一、摘要二、安装Python3.13.2三、安装Jupyter Notebook四、安装Numpy和Pandas以及matplotlib五、安装scikit-learn库和seaborn库 一、摘要 本文主要介绍如何在Windows上安装Python3.13.2&#xff0c;然后基于该Python版本安装Jupyter not…...

详解string类+迭代器

迭代器 概念&#xff1a;在 C 中&#xff0c;迭代器是访问容器&#xff08;如数组、列表、向量、字符串等&#xff09;元素的一种方式。迭代器提供了一种统一的接口&#xff0c;使得你可以使用相同的代码来遍历不同类型的容器。迭代器本质上是一个指针或者指针的封装&#xff0…...

OpenCV DNN 模块使用指南

OpenCV DNN 模块使用指南 一、模块概述 OpenCV 的 DNN&#xff08;深度神经网络&#xff09;模块为开发者提供了强大的深度学习功能&#xff0c;能够加载并运行多种格式的预训练深度学习模型。此模块广泛应用于图像分类、目标检测、语义分割等众多计算机视觉任务。接下来&…...

温度(Temperature)在大模型输出中的作用与底层原理

温度&#xff08;Temperature&#xff09;在大模型输出中的作用与底层原理 在深度学习领域&#xff0c;尤其是自然语言处理&#xff08;NLP&#xff09;中&#xff0c;大型语言模型&#xff08;LLM&#xff09;的输出生成通常依赖于概率分布的采样。温度&#xff08;temperatu…...

智能汽车图像及视频处理方案,支持视频智能拍摄能力

美摄科技&#xff0c;作为智能汽车图像及视频处理领域的先行者&#xff0c;凭借其卓越的技术实力和前瞻性的设计理念&#xff0c;为全球智能汽车制造商带来了一场视觉盛宴的革新。我们自豪地推出——美摄科技智能汽车图像及视频处理方案&#xff0c;一个集高效性、智能化、画质…...

一文讲清 C++ CRTP(Curiously Recurring Template Pattern,奇异递归模板模式)

CRTP是 C 中的一种模板元编程技术&#xff0c;其核心原理是通过模板继承和静态多态&#xff0c;在编译期实现基类对派生类成员的访问&#xff0c;从而避免运行时虚函数调用的开销。 1. CRTP 的基本结构 CRTP 的核心思想是&#xff1a;基类是一个模板类&#xff0c;其模板参数…...

如何用Function Calling解锁OpenAI的「真实世界」交互能力?(附Node.js 实战)

一、Function Calling&#xff1a;大模型的「手脚延伸器」 1.1 核心定义 Function Calling是OpenAI在2023年6月13日推出的革命性功能&#xff08;对应模型版本gpt-3.5-turbo-0613和gpt-4-0613&#xff09;&#xff0c;允许开发者通过自然语言指令触发预定义函数&#xff0c;实…...

MySQL:float,decimal(1)

会四舍五入 无符号浮点数 更改321zyy1下的salary 为float类型 decimal:...

基于DrissionPage的DY无水印视频采集

基于DrissionPage的Dy无水印视频采集技术解析 目录 一、项目背景与痛点分析 1.1 典型应用场景1.2 传统方案痛点对比1.3 需求分析流程图二、系统架构设计 2.1 核心架构图2.2 执行流程图解三、开发环境配置 3.1 版本要求3.2 环境搭建指南四、实现流程详解 4.1 主要处理阶段4.2 关…...

yt-dlp工具下载视频使用方法

使用 yt-dlp 下载有土播视频时&#xff0c;可以很容易地同时下载字幕文件。 下面是详细操作说明&#xff1a; 一、下载视频并同时下载字幕&#xff1a; 基础命令&#xff1a; yt-dlp --write-subs 视频链接示例&#xff1a; yt-dlp --write-subs https://www.youdubo.com/wa…...

canvas数据标注功能简单实现:矩形、圆形

背景说明 基于UI同学的设计&#xff0c;在市面上找不到刚刚好的数据标注工具&#xff0c;遂决定自行开发。目前需求是实现图片的矩形、圆形标注&#xff0c;并获取标注的坐标信息&#xff0c;使用canvas可以比较方便的实现该功能。 主要功能 选中图形&#xff0c;进行拖动 使…...

Linux与HTTP报头属性和请求方式

HTTP报头属性、请求方式 本篇介绍 在上一节深入HTTP序列化和反序列化已经详细讲解了HTTP是如何进行序列化和反序列化的&#xff0c;但是上一节对请求报头和响应报头的具体内容并没有做出具体的说明&#xff0c;本节就会基于这个问题继续探讨HttpServer&#xff1b;另外在介绍…...

WordPress漏洞

一&#xff0c;后台修改模板拿WebShell 1&#xff0c;安装好靶场后访问 2&#xff0c;在如图所示的位置选择一个php文件写入一句话木马&#xff0c;我们这里选择在404.php中写入 3&#xff0c;访问404.php 二&#xff0c;上传主题拿WebShell 1&#xff0c;找到如图所示的页面…...

go命令使用

查看配置信息 go env配置go国内源 export GO111MODULEon export GOPROXYhttps://goproxy.cn测试 go install github.com/jesseduffield/lazydockerlatesthttps://github.com/jesseduffield/lazydocker...

uniapp vue3使用uniapp的生命周期

使用uniapp的onLoad等生命周期 // 需要引入 import { onLoad , onShow } from dcloudio/uni-app; // 箭头函数 onLoad(()>{//内容 })使用vue生命周期 vue官方文档&#xff1a;https://cn.vuejs.org/api/options-lifecycle.html import { ref,onMounted } from vue; onMou…...

nginx vue history模式 try_files

server {listen 80;server_name localhost chat.test.com;#配置根目录location / {root /temp/test;#index index.html index.htm;try_files $uri $uri/ /index.html;add_header Content-Security-Policy upgrade-insecure-requests;}} https://blog.csdn.net/xutongbao/…...

【css酷炫效果】纯CSS实现悬浮弹性按钮

【css酷炫效果】纯CSS实现悬浮弹性按钮 缘创作背景html结构css样式完整代码效果图 想直接拿走的老板&#xff0c;链接放在这里&#xff1a;https://download.csdn.net/download/u011561335/90492020 缘 创作随缘&#xff0c;不定时更新。 创作背景 刚看到csdn出活动了&…...

MySQL自动化配置工具开发:探索如何用脚本实现MySQL一键安装与配置,提升运维效率

引言 MySQL作为最流行的开源关系型数据库之一,广泛应用于各类业务场景。然而,手动安装和配置MySQL不仅耗时,还容易出错。为了提高运维效率,开发一款MySQL自动化配置工具显得尤为重要。本文将探索如何通过脚本实现MySQL的一键安装与配置,并提供具体的配置脚本文档和关键参…...

如何查看安卓版本号的方法(例如查看是13、12、11、10...)

开发过程中需要了解到安卓版本号是多少&#xff0c;那么以下有三种方法可以知晓安卓手机的Android版本号。 方法1&#xff1a;手机设置直接查看 1.打开【设置】 --> 滑动到手机最底部 --> 点击【关于手机】或 【系统】--> 选择【Android版本】 2.直接查看版本号&am…...

ubuntu 解挂载时提示 “umount: /home/xx/Applications/yy: target is busy.”

问题如题所示&#xff0c;我挂载一个squanfs文件系统到指定目录&#xff0c;当我使用完后&#xff0c;准备解挂载时&#xff0c;提示umount: /home/xx/Applications/yy: target is busy.&#xff0c;具体的如图所示&#xff0c; 这种提示通常是表明这个路径的内容正在被某些进…...

Java XML与JSON相互转换详解

目录 一、为什么需要XML与JSON转换二、使用Jackson库进行转换1. 添加依赖2. XML转JSON3. JSON转XML三、注意事项在现代软件开发中,数据格式的转换是一项常见的任务,特别是在处理不同系统或服务之间的数据交换时。XML(可扩展标记语言)和JSON(JavaScript对象表示法)是两种广…...

[AI速读]用持续集成(CI)优化芯片验证环境:Jenkins与EDA工具的实战指南

在芯片验证中,回归测试(Regression Test)是确保设计稳定性的关键步骤。但随着设计复杂度增加,手动管理海量测试用例、分析日志和覆盖率数据变得异常耗时。本文将介绍如何利用持续集成(CI)工具Jenkins,结合EDA验证环境(如Cadence vManager),实现自动化测试与结果分析,…...

Java-SpringBootWeb入门、Spring官方脚手架连接不上解决方法

一. Spring 官网&#xff1a;Spring | Home Spring发展到今天已经形成了一种开发生态圈&#xff0c;Spring提供了若干个子项目&#xff0c;每个项目用于完成特定的功能(Spring全家桶) Spring Boot可以帮助我们非常快速的构建应用程序、简化开发、提高效率 。 二. Spring Boot入…...

WEB攻防-PHP反序列化-字符串逃逸

目录 前置知识 字符串逃逸-减少 字符串逃逸-增多 前置知识 1.PHP 在反序列化时&#xff0c;语法是以 ; 作为字段的分隔&#xff0c;以 } 作为结尾&#xff0c;在结束符}之后的任何内容不会影响反序列化的后的结果 class people{ public $namelili; public $age20; } var_du…...