常见编译,烧录和调试工具介绍
常见编译、烧录与调试工具介绍本文介绍软件开发和嵌入式开发中常见的编译、链接、调试、烧录工具例如gcc、g、gdb、pyocd、openocd等。理解这些工具之间的关系有助于看懂一个程序从源代码变成可运行程序或者从源代码变成单片机固件的完整过程。1. 从源码到运行的大致流程一个 C/C 程序通常会经历以下步骤源代码 | | 编译 v 目标文件 .o | | 链接 v 可执行文件 .elf / .exe | | 格式转换 v 固件文件 .bin / .hex | | 烧录 v 芯片 Flash | | 调试 v 运行、断点、单步、查看变量在普通桌面程序中生成可执行文件后通常就可以直接运行。在嵌入式开发中还需要把程序烧录到单片机、开发板或其他目标设备中。2. 编译器编译器负责把人写的源代码转换成机器能够理解的目标代码。gccgcc是 GNU Compiler Collection 中最常见的 C 语言编译器。常见用途编译 C 语言源文件。生成目标文件.o。生成可执行程序。在嵌入式开发中也可以通过交叉编译器生成目标芯片可运行的程序。示例gcc main.c-omain含义是把main.c编译成名为main的可执行文件。gg是 GNU 的 C 编译器用于编译 C 程序。示例g main.cpp-omaingcc和g的区别gcc默认用于 C 语言。g默认用于 C 语言。g在链接时会自动链接 C 标准库。用gcc编译 C 程序时可能需要手动指定 C 标准库。clang / clangclang和clang是 LLVM 项目的 C/C 编译器。特点编译速度快。报错信息通常比较友好。常用于现代 C/C 项目。在 macOS、Linux、嵌入式和大型工程中都很常见。交叉编译交叉编译器是指“在一种平台上编译出另一种平台运行的程序”的编译器。例如在电脑上编译 STM32 单片机程序。在 x86 Linux 上编译 ARM Linux 程序。在电脑上编译 RISC-V 裸机程序。常见交叉编译器arm-none-eabi-gccARM Cortex-M 裸机嵌入式 C 编译器。arm-none-eabi-gARM Cortex-M 裸机嵌入式 C 编译器。riscv64-unknown-elf-gccRISC-V 裸机交叉编译器。avr-gccAVR 单片机常用编译器。其中none-eabi大致表示none没有操作系统。eabi嵌入式应用二进制接口。所以arm-none-eabi-gcc常用于没有 Linux、Windows 这类操作系统的 ARM 单片机项目。3. 汇编、链接和二进制工具编译器不是单独完成所有工作的。一个完整工具链中还包括汇编器、链接器和各种二进制分析工具。asas是 GNU 汇编器用于把汇编代码转换成目标文件。源文件可能是.s.S.S文件通常会先经过预处理器处理而.s一般直接作为汇编文件处理。ldld是 GNU 链接器。链接器负责把多个.o目标文件、库文件和启动文件合并成最终的可执行文件。在嵌入式开发中链接器还要根据链接脚本.ld决定代码和数据放到芯片内存的什么位置。例如程序代码放到 Flash。全局变量放到 RAM。中断向量表放到 Flash 开头。arar用来创建和管理静态库常见输出文件是.a。示例ar rcs libmath.a add.o sub.o这表示把add.o和sub.o打包成静态库libmath.a。objcopyobjcopy用于转换二进制文件格式。在嵌入式中非常常见例如把.elf转成.binarm-none-eabi-objcopy-Obinary firmware.elf firmware.bin也可以转成 Intel HEX 格式arm-none-eabi-objcopy-Oihex firmware.elf firmware.hexobjdumpobjdump用于查看目标文件或可执行文件的内容。常见用途反汇编。查看段信息。分析生成的机器指令。示例arm-none-eabi-objdump-dfirmware.elfreadelfreadelf用于查看 ELF 文件结构。常见用途查看 ELF 头。查看段表。查看符号表。查看程序入口地址。示例readelf-hfirmware.elfnmnm用于查看目标文件、库文件或 ELF 文件中的符号。常见用途查看函数是否存在。查看全局变量符号。分析链接错误。示例nm firmware.elfsizesize用于查看程序占用的代码和数据大小。示例arm-none-eabi-size firmware.elf常见输出中的字段text代码段通常放在 Flash。data已初始化全局变量通常需要占用 Flash 和 RAM。bss未初始化全局变量通常占用 RAM。stripstrip用于去掉可执行文件中的符号和调试信息从而减小文件体积。桌面程序发布时可能会用到。嵌入式调试阶段一般不要随便去掉调试信息否则会影响 GDB 调试体验。4. 调试工具调试工具用于观察程序运行状态例如设置断点、单步执行、查看变量、查看寄存器、查看内存。gdbgdb是 GNU Debugger是 C/C 开发中非常常见的调试器。常见功能设置断点。单步执行。查看变量。查看调用栈。查看寄存器。查看内存。远程连接目标设备。示例gdb ./main常见 GDB 命令break main run next step continue print variable_name backtrace quitarm-none-eabi-gdbarm-none-eabi-gdb是面向 ARM 裸机嵌入式目标的 GDB。它通常不会直接运行程序而是连接到一个调试服务例如OpenOCDpyOCDJ-Link GDB ServerST-LINK GDB Server示例arm-none-eabi-gdb firmware.elf连接远程调试服务target remote localhost:3333lldblldb是 LLVM 项目的调试器。它和gdb类似常见于macOS 开发。LLVM/Clang 生态。一些现代 C/C 项目。gdbservergdbserver用于远程调试 Linux 程序。典型场景目标设备上运行gdbserver。开发电脑上运行gdb。两者通过网络连接。示例gdbserver :1234 ./app电脑端连接target remote target_ip:12345. 嵌入式调试和烧录工具嵌入式开发中程序需要下载到芯片 Flash 中。调试时还需要通过调试器访问芯片内部状态。常见调试接口JTAGSWDUART BootloaderUSB DFUpyOCDpyOCD是一个 Python 编写的 ARM Cortex-M 调试和烧录工具。它常用于支持 CMSIS-DAP / DAPLink 的开发板。常见功能擦除芯片。烧录固件。启动 GDB Server。复位目标板。查看目标芯片信息。常见命令pyocd list pyocd flash firmware.bin pyocd erase--chippyocd gdbserver适合场景ARM Cortex-M 单片机。CMSIS-DAP 调试器。DAPLink 开发板。希望用 Python 工具链管理烧录和调试流程。OpenOCDOpenOCD是 Open On-Chip Debugger 的缩写是非常常见的开源嵌入式调试和烧录工具。常见功能启动 GDB Server。通过 JTAG/SWD 调试芯片。烧录 Flash。复位目标芯片。查看寄存器和内存。OpenOCD 通常需要指定调试器配置文件。目标芯片配置文件。示例openocd-finterface/stlink.cfg-ftarget/stm32f4x.cfg启动后GDB 可以连接target remote localhost:3333适合场景STM32。nRF。RISC-V。使用 ST-LINK、J-Link、CMSIS-DAP 等调试器。需要灵活配置调试流程。J-Link 工具J-Link 是 SEGGER 公司的调试器支持大量芯片。常见工具JLinkExeJLinkGDBServerJFlash特点支持芯片多。速度快。商业工具链中很常见。与 Keil、IAR、VS Code、GDB 等工具都可以配合。ST-LINK 工具ST-LINK 是 STMicroelectronics 常用的 STM32 调试器。常见工具STM32CubeProgrammerST-LINK GDB Serverst-flash常见用途烧录 STM32 固件。擦除 STM32 芯片。通过 SWD 调试 STM32。示例st-flashwritefirmware.bin 0x08000000其中0x08000000通常是 STM32 内部 Flash 的起始地址。esptool.pyesptool.py是 Espressif 官方常用的 ESP8266 / ESP32 烧录工具。常见用途烧录 ESP32 固件。擦除 Flash。读取芯片信息。示例esptool.py--chipesp32--port/dev/ttyUSB0 erase_flashavrdudeavrdude常用于 AVR 单片机烧录例如 ATmega328P。Arduino UNO 背后也经常会使用avrdude完成程序下载。示例avrdude-pm328p-carduino-P/dev/ttyUSB0-b115200-Uflash:w:firmware.hexdfu-utildfu-util用于通过 USB DFU 协议烧录固件。DFU 是 Device Firmware Upgrade 的缩写很多芯片和开发板支持通过 USB 进入 DFU 模式后升级固件。示例dfu-util-a0-Dfirmware.binnrfjprognrfjprog是 Nordic nRF 系列芯片常用的命令行烧录工具。常见用途烧录 nRF52 / nRF53 固件。擦除芯片。复位芯片。读取芯片状态。示例nrfjprog--programfirmware.hex--chiperase--resetprobe-rsprobe-rs是 Rust 生态中的嵌入式调试和烧录工具。常见用途烧录 ARM / RISC-V 固件。与 Rust 嵌入式项目配合。启动调试会话。它在 Rust 嵌入式开发中越来越常见。6. 构建系统项目变大以后不可能每次都手动输入一长串编译命令。构建系统用于自动管理编译、链接、依赖关系和输出文件。makemake是经典构建工具读取Makefile执行构建规则。示例makemakeclean优点简单直接。在 C/C 和嵌入式项目中非常常见。很多开源项目都支持。缺点复杂项目中的 Makefile 可能比较难维护。CMakeCMake是跨平台构建系统生成器。它本身通常不直接编译代码而是生成其他构建系统需要的文件例如MakefileNinja 构建文件Visual Studio 工程常见流程cmake-S.-Bbuild cmake--buildbuild适合场景跨平台 C/C 项目。需要管理多个库和可执行文件。需要支持 Linux、Windows、macOS。需要和 IDE 配合。NinjaNinja是一个高速构建工具。它通常由 CMake 或 Meson 生成构建文件然后由 Ninja 执行实际构建。示例cmake-S.-Bbuild-GNinja ninja-Cbuild特点速度快。输出简洁。适合大型项目。MesonMeson是现代构建系统通常配合 Ninja 使用。示例meson setup build meson compile-Cbuildwestwest是 Zephyr RTOS 常用的项目管理和构建工具。常见用途管理多个 Git 仓库。配置 Zephyr 工程。编译固件。烧录固件。调试目标板。示例west build-bnrf52840dk_nrf52840 app west flash west debug7. 包管理和工具链管理包管理器用于安装编译器、调试器、库和其他开发工具。常见工具aptDebian / Ubuntu 包管理器。dnfFedora 包管理器。pacmanArch Linux 包管理器。brewmacOS 常用包管理器。pipPython 包管理器常用于安装pyocd、esptool.py。condaPython 环境和包管理工具。vcpkgC/C 包管理器。conanC/C 包管理器。rustupRust 工具链管理器。cargoRust 构建和包管理工具。示例pipinstallpyocd pipinstallesptool8. 常见文件类型源代码文件.cC 源文件。.cpp/.cc/.cxxC 源文件。.hC/C 头文件。.hppC 头文件。.s汇编源文件。.S会经过预处理的汇编源文件。编译中间文件.o目标文件已经编译但还没有完成链接。.a静态库。.soLinux 动态库。.dllWindows 动态库。.dylibmacOS 动态库。可执行和固件文件.elfExecutable and Linkable Format嵌入式开发中非常常见包含程序、符号、调试信息等。.exeWindows 可执行文件。.bin裸二进制文件通常用于烧录。.hexIntel HEX 格式文件常用于烧录。.uf2常见于一些开发板的拖拽式烧录格式。辅助文件.map链接映射文件可以查看函数、变量和段的地址分布。.ld链接脚本用于控制程序在内存中的布局。.json配置文件某些工程和工具会使用。.cfg配置文件OpenOCD 等工具常见。9. 常见硬件调试器软件工具通常需要配合硬件调试器才能访问单片机或 SoC。ST-LINKST-LINK 是 STM32 开发中最常见的调试器之一。特点常见于 STM32 Nucleo、Discovery 开发板。支持 SWD。可用于烧录和调试 STM32。J-LinkJ-Link 是 SEGGER 的调试器。特点支持芯片种类多。速度快。工业和商业开发中很常见。可配合 GDB、Keil、IAR、OpenOCD 等工具。CMSIS-DAPCMSIS-DAP 是 ARM 定义的一种调试接口标准。特点开源生态支持较好。pyOCD支持良好。很多开发板集成 CMSIS-DAP 或 DAPLink。DAPLinkDAPLink 是基于 CMSIS-DAP 的开源调试和烧录方案。常见特点支持调试。支持串口转发。有些开发板支持拖拽.bin或.hex文件完成烧录。Black Magic ProbeBlack Magic Probe 是一种特殊的调试器它本身内置 GDB Server。使用时通常可以直接让 GDB 连接调试器不一定需要 OpenOCD 或 pyOCD 作为中间层。ULINKULINK 是 Keil 生态中常见的 ARM 调试器。常见于Keil MDK。商业 ARM 嵌入式开发。PICkitPICkit 是 Microchip 常见的调试和烧录工具。常见用于PIC 单片机。AVR 单片机。Microchip 生态项目。10. 一个典型 STM32 编译烧录调试流程下面以 STM32 为例说明这些工具如何配合。第一步编写源码常见文件main.c startup_stm32.s stm32.ld其中main.c是主程序。startup_stm32.s是启动文件。stm32.ld是链接脚本。第二步编译arm-none-eabi-gcc-cmain.c-mcpucortex-m4-mthumb-omain.o生成main.o第三步链接arm-none-eabi-gcc main.o startup_stm32.o-Tstm32.ld-ofirmware.elf生成firmware.elf第四步查看大小arm-none-eabi-size firmware.elf用于确认程序是否超过芯片 Flash 或 RAM 容量。第五步转换固件格式arm-none-eabi-objcopy-Obinary firmware.elf firmware.bin生成firmware.bin第六步烧录使用 OpenOCDopenocd-finterface/stlink.cfg-ftarget/stm32f4x.cfg-cprogram firmware.elf verify reset exit或者使用 st-flashst-flashwritefirmware.bin 0x08000000第七步调试先启动 OpenOCDopenocd-finterface/stlink.cfg-ftarget/stm32f4x.cfg再启动 GDBarm-none-eabi-gdb firmware.elf在 GDB 中连接目标target remote localhost:3333 break main continue这样就可以在单片机上设置断点、单步执行和查看变量。11. 各工具之间的关系总结类别工具主要作用C 编译器gcc编译 C 程序C 编译器g编译 C 程序LLVM 编译器clang/clang编译 C/C 程序ARM 交叉编译器arm-none-eabi-gcc编译 ARM 裸机程序汇编器as汇编源码生成目标文件链接器ld把目标文件和库链接成可执行文件静态库工具ar创建.a静态库格式转换objcopy.elf转.bin/.hex反汇编objdump查看汇编和目标文件内容ELF 分析readelf查看 ELF 文件结构符号分析nm查看函数和变量符号大小分析size查看代码和数据占用调试器gdb调试本机程序嵌入式调试器arm-none-eabi-gdb调试 ARM 嵌入式程序调试烧录服务OpenOCD连接 GDB 和目标芯片调试烧录工具pyOCDARM Cortex-M 烧录和调试STM32 烧录st-flash/STM32CubeProgrammer烧录 STM32ESP 烧录esptool.py烧录 ESP8266 / ESP32AVR 烧录avrdude烧录 AVR 单片机DFU 烧录dfu-util通过 USB DFU 烧录构建工具make根据 Makefile 构建项目构建生成器CMake生成 Makefile 或 Ninja 工程高速构建Ninja快速执行构建Zephyr 工具west管理、构建、烧录 Zephyr 项目12. 初学者应该先掌握哪些如果刚开始学习 C/C 或嵌入式开发建议按下面顺序理解gcc/g知道如何把源代码编译成程序。.c/.cpp/.h/.o/.elf/.bin知道常见文件的含义。make知道如何自动化编译。gdb知道如何断点调试。objcopy/size知道嵌入式固件如何转换和查看大小。OpenOCD或pyOCD知道如何烧录和调试单片机。CMake/Ninja知道现代项目如何组织构建。13. 最核心的一句话这些工具可以按职责理解gcc / g / clang 负责把源码编译成目标文件 ld 负责把目标文件链接成程序 objcopy / size / nm 负责转换和分析生成文件 gdb / lldb 负责调试程序 OpenOCD / pyOCD 负责连接调试器和芯片 st-flash / esptool 负责把固件写入芯片 make / CMake / Ninja 负责自动化整个构建过程把这些工具放到完整流程中看就不会觉得它们是零散的命令而是一条从“源代码”到“程序运行”的工具链。