常见编译,烧录和调试工具介绍

常见编译、烧录与调试工具介绍

本文介绍软件开发和嵌入式开发中常见的编译、链接、调试、烧录工具,例如 gccg++gdbpyocdopenocd 等。理解这些工具之间的关系,有助于看懂一个程序从源代码变成可运行程序,或者从源代码变成单片机固件的完整过程。

1. 从源码到运行的大致流程

一个 C/C++ 程序通常会经历以下步骤:

text 复制代码
源代码
  |
  | 编译
  v
目标文件 .o
  |
  | 链接
  v
可执行文件 .elf / .exe
  |
  | 格式转换
  v
固件文件 .bin / .hex
  |
  | 烧录
  v
芯片 Flash
  |
  | 调试
  v
运行、断点、单步、查看变量

在普通桌面程序中,生成可执行文件后通常就可以直接运行。

在嵌入式开发中,还需要把程序烧录到单片机、开发板或其他目标设备中。

2. 编译器

编译器负责把人写的源代码转换成机器能够理解的目标代码。

gcc

gcc 是 GNU Compiler Collection 中最常见的 C 语言编译器。

常见用途:

  • 编译 C 语言源文件。
  • 生成目标文件 .o
  • 生成可执行程序。
  • 在嵌入式开发中,也可以通过交叉编译器生成目标芯片可运行的程序。

示例:

bash 复制代码
gcc main.c -o main

含义是把 main.c 编译成名为 main 的可执行文件。

g++

g++ 是 GNU 的 C++ 编译器,用于编译 C++ 程序。

示例:

bash 复制代码
g++ main.cpp -o main

gccg++ 的区别:

  • gcc 默认用于 C 语言。
  • g++ 默认用于 C++ 语言。
  • g++ 在链接时会自动链接 C++ 标准库。
  • gcc 编译 C++ 程序时,可能需要手动指定 C++ 标准库。

clang / clang++

clangclang++ 是 LLVM 项目的 C/C++ 编译器。

特点:

  • 编译速度快。
  • 报错信息通常比较友好。
  • 常用于现代 C/C++ 项目。
  • 在 macOS、Linux、嵌入式和大型工程中都很常见。

交叉编译

交叉编译器是指"在一种平台上编译出另一种平台运行的程序"的编译器。

例如:

  • 在电脑上编译 STM32 单片机程序。
  • 在 x86 Linux 上编译 ARM Linux 程序。
  • 在电脑上编译 RISC-V 裸机程序。

常见交叉编译器:

  • arm-none-eabi-gcc:ARM Cortex-M 裸机嵌入式 C 编译器。
  • arm-none-eabi-g++:ARM Cortex-M 裸机嵌入式 C++ 编译器。
  • riscv64-unknown-elf-gcc:RISC-V 裸机交叉编译器。
  • avr-gcc:AVR 单片机常用编译器。

其中 none-eabi 大致表示:

  • none:没有操作系统。
  • eabi:嵌入式应用二进制接口。

所以 arm-none-eabi-gcc 常用于没有 Linux、Windows 这类操作系统的 ARM 单片机项目。

3. 汇编、链接和二进制工具

编译器不是单独完成所有工作的。一个完整工具链中,还包括汇编器、链接器和各种二进制分析工具。

as

as 是 GNU 汇编器,用于把汇编代码转换成目标文件。

源文件可能是:

  • .s
  • .S

.S 文件通常会先经过预处理器处理,而 .s 一般直接作为汇编文件处理。

ld

ld 是 GNU 链接器。

链接器负责把多个 .o 目标文件、库文件和启动文件合并成最终的可执行文件。

在嵌入式开发中,链接器还要根据链接脚本 .ld 决定代码和数据放到芯片内存的什么位置。

例如:

  • 程序代码放到 Flash。
  • 全局变量放到 RAM。
  • 中断向量表放到 Flash 开头。

ar

ar 用来创建和管理静态库,常见输出文件是 .a

示例:

bash 复制代码
ar rcs libmath.a add.o sub.o

这表示把 add.osub.o 打包成静态库 libmath.a

objcopy

objcopy 用于转换二进制文件格式。

在嵌入式中非常常见,例如把 .elf 转成 .bin

bash 复制代码
arm-none-eabi-objcopy -O binary firmware.elf firmware.bin

也可以转成 Intel HEX 格式:

bash 复制代码
arm-none-eabi-objcopy -O ihex firmware.elf firmware.hex

objdump

objdump 用于查看目标文件或可执行文件的内容。

常见用途:

  • 反汇编。
  • 查看段信息。
  • 分析生成的机器指令。

示例:

bash 复制代码
arm-none-eabi-objdump -d firmware.elf

readelf

readelf 用于查看 ELF 文件结构。

常见用途:

  • 查看 ELF 头。
  • 查看段表。
  • 查看符号表。
  • 查看程序入口地址。

示例:

bash 复制代码
readelf -h firmware.elf

nm

nm 用于查看目标文件、库文件或 ELF 文件中的符号。

常见用途:

  • 查看函数是否存在。
  • 查看全局变量符号。
  • 分析链接错误。

示例:

bash 复制代码
nm firmware.elf

size

size 用于查看程序占用的代码和数据大小。

示例:

bash 复制代码
arm-none-eabi-size firmware.elf

常见输出中的字段:

  • text:代码段,通常放在 Flash。
  • data:已初始化全局变量,通常需要占用 Flash 和 RAM。
  • bss:未初始化全局变量,通常占用 RAM。

strip

strip 用于去掉可执行文件中的符号和调试信息,从而减小文件体积。

桌面程序发布时可能会用到。

嵌入式调试阶段一般不要随便去掉调试信息,否则会影响 GDB 调试体验。

4. 调试工具

调试工具用于观察程序运行状态,例如设置断点、单步执行、查看变量、查看寄存器、查看内存。

gdb

gdb 是 GNU Debugger,是 C/C++ 开发中非常常见的调试器。

常见功能:

  • 设置断点。
  • 单步执行。
  • 查看变量。
  • 查看调用栈。
  • 查看寄存器。
  • 查看内存。
  • 远程连接目标设备。

示例:

bash 复制代码
gdb ./main

常见 GDB 命令:

gdb 复制代码
break main
run
next
step
continue
print variable_name
backtrace
quit

arm-none-eabi-gdb

arm-none-eabi-gdb 是面向 ARM 裸机嵌入式目标的 GDB。

它通常不会直接运行程序,而是连接到一个调试服务,例如:

  • OpenOCD
  • pyOCD
  • J-Link GDB Server
  • ST-LINK GDB Server

示例:

bash 复制代码
arm-none-eabi-gdb firmware.elf

连接远程调试服务:

gdb 复制代码
target remote localhost:3333

lldb

lldb 是 LLVM 项目的调试器。

它和 gdb 类似,常见于:

  • macOS 开发。
  • LLVM/Clang 生态。
  • 一些现代 C/C++ 项目。

gdbserver

gdbserver 用于远程调试 Linux 程序。

典型场景:

  • 目标设备上运行 gdbserver
  • 开发电脑上运行 gdb
  • 两者通过网络连接。

示例:

bash 复制代码
gdbserver :1234 ./app

电脑端连接:

gdb 复制代码
target remote target_ip:1234

5. 嵌入式调试和烧录工具

嵌入式开发中,程序需要下载到芯片 Flash 中。调试时,还需要通过调试器访问芯片内部状态。

常见调试接口:

  • JTAG
  • SWD
  • UART Bootloader
  • USB DFU

pyOCD

pyOCD 是一个 Python 编写的 ARM Cortex-M 调试和烧录工具。

它常用于支持 CMSIS-DAP / DAPLink 的开发板。

常见功能:

  • 擦除芯片。
  • 烧录固件。
  • 启动 GDB Server。
  • 复位目标板。
  • 查看目标芯片信息。

常见命令:

bash 复制代码
pyocd list
pyocd flash firmware.bin
pyocd erase --chip
pyocd gdbserver

适合场景:

  • ARM Cortex-M 单片机。
  • CMSIS-DAP 调试器。
  • DAPLink 开发板。
  • 希望用 Python 工具链管理烧录和调试流程。

OpenOCD

OpenOCD 是 Open On-Chip Debugger 的缩写,是非常常见的开源嵌入式调试和烧录工具。

常见功能:

  • 启动 GDB Server。
  • 通过 JTAG/SWD 调试芯片。
  • 烧录 Flash。
  • 复位目标芯片。
  • 查看寄存器和内存。

OpenOCD 通常需要指定:

  • 调试器配置文件。
  • 目标芯片配置文件。

示例:

bash 复制代码
openocd -f interface/stlink.cfg -f target/stm32f4x.cfg

启动后,GDB 可以连接:

gdb 复制代码
target remote localhost:3333

适合场景:

  • STM32。
  • nRF。
  • RISC-V。
  • 使用 ST-LINK、J-Link、CMSIS-DAP 等调试器。
  • 需要灵活配置调试流程。

J-Link 是 SEGGER 公司的调试器,支持大量芯片。

常见工具:

  • JLinkExe
  • JLinkGDBServer
  • JFlash

特点:

  • 支持芯片多。
  • 速度快。
  • 商业工具链中很常见。
  • 与 Keil、IAR、VS Code、GDB 等工具都可以配合。

ST-LINK 是 STMicroelectronics 常用的 STM32 调试器。

常见工具:

  • STM32CubeProgrammer
  • ST-LINK GDB Server
  • st-flash

常见用途:

  • 烧录 STM32 固件。
  • 擦除 STM32 芯片。
  • 通过 SWD 调试 STM32。

示例:

bash 复制代码
st-flash write firmware.bin 0x08000000

其中 0x08000000 通常是 STM32 内部 Flash 的起始地址。

esptool.py

esptool.py 是 Espressif 官方常用的 ESP8266 / ESP32 烧录工具。

常见用途:

  • 烧录 ESP32 固件。
  • 擦除 Flash。
  • 读取芯片信息。

示例:

bash 复制代码
esptool.py --chip esp32 --port /dev/ttyUSB0 erase_flash

avrdude

avrdude 常用于 AVR 单片机烧录,例如 ATmega328P。

Arduino UNO 背后也经常会使用 avrdude 完成程序下载。

示例:

bash 复制代码
avrdude -p m328p -c arduino -P /dev/ttyUSB0 -b 115200 -U flash:w:firmware.hex

dfu-util

dfu-util 用于通过 USB DFU 协议烧录固件。

DFU 是 Device Firmware Upgrade 的缩写,很多芯片和开发板支持通过 USB 进入 DFU 模式后升级固件。

示例:

bash 复制代码
dfu-util -a 0 -D firmware.bin

nrfjprog

nrfjprog 是 Nordic nRF 系列芯片常用的命令行烧录工具。

常见用途:

  • 烧录 nRF52 / nRF53 固件。
  • 擦除芯片。
  • 复位芯片。
  • 读取芯片状态。

示例:

bash 复制代码
nrfjprog --program firmware.hex --chiperase --reset

probe-rs

probe-rs 是 Rust 生态中的嵌入式调试和烧录工具。

常见用途:

  • 烧录 ARM / RISC-V 固件。
  • 与 Rust 嵌入式项目配合。
  • 启动调试会话。

它在 Rust 嵌入式开发中越来越常见。

6. 构建系统

项目变大以后,不可能每次都手动输入一长串编译命令。构建系统用于自动管理编译、链接、依赖关系和输出文件。

make

make 是经典构建工具,读取 Makefile 执行构建规则。

示例:

bash 复制代码
make
make clean

优点:

  • 简单直接。
  • 在 C/C++ 和嵌入式项目中非常常见。
  • 很多开源项目都支持。

缺点:

  • 复杂项目中的 Makefile 可能比较难维护。

CMake

CMake 是跨平台构建系统生成器。

它本身通常不直接编译代码,而是生成其他构建系统需要的文件,例如:

  • Makefile
  • Ninja 构建文件
  • Visual Studio 工程

常见流程:

bash 复制代码
cmake -S . -B build
cmake --build build

适合场景:

  • 跨平台 C/C++ 项目。
  • 需要管理多个库和可执行文件。
  • 需要支持 Linux、Windows、macOS。
  • 需要和 IDE 配合。

Ninja

Ninja 是一个高速构建工具。

它通常由 CMake 或 Meson 生成构建文件,然后由 Ninja 执行实际构建。

示例:

bash 复制代码
cmake -S . -B build -G Ninja
ninja -C build

特点:

  • 速度快。
  • 输出简洁。
  • 适合大型项目。

Meson

Meson 是现代构建系统,通常配合 Ninja 使用。

示例:

bash 复制代码
meson setup build
meson compile -C build

west

west 是 Zephyr RTOS 常用的项目管理和构建工具。

常见用途:

  • 管理多个 Git 仓库。
  • 配置 Zephyr 工程。
  • 编译固件。
  • 烧录固件。
  • 调试目标板。

示例:

bash 复制代码
west build -b nrf52840dk_nrf52840 app
west flash
west debug

7. 包管理和工具链管理

包管理器用于安装编译器、调试器、库和其他开发工具。

常见工具:

  • apt:Debian / Ubuntu 包管理器。
  • dnf:Fedora 包管理器。
  • pacman:Arch Linux 包管理器。
  • brew:macOS 常用包管理器。
  • pip:Python 包管理器,常用于安装 pyocdesptool.py
  • conda:Python 环境和包管理工具。
  • vcpkg:C/C++ 包管理器。
  • conan:C/C++ 包管理器。
  • rustup:Rust 工具链管理器。
  • cargo:Rust 构建和包管理工具。

示例:

bash 复制代码
pip install pyocd
pip install esptool

8. 常见文件类型

源代码文件

  • .c:C 源文件。
  • .cpp / .cc / .cxx:C++ 源文件。
  • .h:C/C++ 头文件。
  • .hpp:C++ 头文件。
  • .s:汇编源文件。
  • .S:会经过预处理的汇编源文件。

编译中间文件

  • .o:目标文件,已经编译但还没有完成链接。
  • .a:静态库。
  • .so:Linux 动态库。
  • .dll:Windows 动态库。
  • .dylib:macOS 动态库。

可执行和固件文件

  • .elf:Executable and Linkable Format,嵌入式开发中非常常见,包含程序、符号、调试信息等。
  • .exe:Windows 可执行文件。
  • .bin:裸二进制文件,通常用于烧录。
  • .hex:Intel HEX 格式文件,常用于烧录。
  • .uf2:常见于一些开发板的拖拽式烧录格式。

辅助文件

  • .map:链接映射文件,可以查看函数、变量和段的地址分布。
  • .ld:链接脚本,用于控制程序在内存中的布局。
  • .json:配置文件,某些工程和工具会使用。
  • .cfg:配置文件,OpenOCD 等工具常见。

9. 常见硬件调试器

软件工具通常需要配合硬件调试器,才能访问单片机或 SoC。

ST-LINK 是 STM32 开发中最常见的调试器之一。

特点:

  • 常见于 STM32 Nucleo、Discovery 开发板。
  • 支持 SWD。
  • 可用于烧录和调试 STM32。

J-Link 是 SEGGER 的调试器。

特点:

  • 支持芯片种类多。
  • 速度快。
  • 工业和商业开发中很常见。
  • 可配合 GDB、Keil、IAR、OpenOCD 等工具。

CMSIS-DAP

CMSIS-DAP 是 ARM 定义的一种调试接口标准。

特点:

  • 开源生态支持较好。
  • pyOCD 支持良好。
  • 很多开发板集成 CMSIS-DAP 或 DAPLink。

DAPLink 是基于 CMSIS-DAP 的开源调试和烧录方案。

常见特点:

  • 支持调试。
  • 支持串口转发。
  • 有些开发板支持拖拽 .bin.hex 文件完成烧录。

Black Magic Probe

Black Magic Probe 是一种特殊的调试器,它本身内置 GDB Server。

使用时通常可以直接让 GDB 连接调试器,不一定需要 OpenOCD 或 pyOCD 作为中间层。

ULINK 是 Keil 生态中常见的 ARM 调试器。

常见于:

  • Keil MDK。
  • 商业 ARM 嵌入式开发。

PICkit

PICkit 是 Microchip 常见的调试和烧录工具。

常见用于:

  • PIC 单片机。
  • AVR 单片机。
  • Microchip 生态项目。

10. 一个典型 STM32 编译烧录调试流程

下面以 STM32 为例,说明这些工具如何配合。

第一步:编写源码

常见文件:

text 复制代码
main.c
startup_stm32.s
stm32.ld

其中:

  • main.c 是主程序。
  • startup_stm32.s 是启动文件。
  • stm32.ld 是链接脚本。

第二步:编译

bash 复制代码
arm-none-eabi-gcc -c main.c -mcpu=cortex-m4 -mthumb -o main.o

生成:

text 复制代码
main.o

第三步:链接

bash 复制代码
arm-none-eabi-gcc main.o startup_stm32.o -T stm32.ld -o firmware.elf

生成:

text 复制代码
firmware.elf

第四步:查看大小

bash 复制代码
arm-none-eabi-size firmware.elf

用于确认程序是否超过芯片 Flash 或 RAM 容量。

第五步:转换固件格式

bash 复制代码
arm-none-eabi-objcopy -O binary firmware.elf firmware.bin

生成:

text 复制代码
firmware.bin

第六步:烧录

使用 OpenOCD:

bash 复制代码
openocd -f interface/stlink.cfg -f target/stm32f4x.cfg -c "program firmware.elf verify reset exit"

或者使用 st-flash:

bash 复制代码
st-flash write firmware.bin 0x08000000

第七步:调试

先启动 OpenOCD:

bash 复制代码
openocd -f interface/stlink.cfg -f target/stm32f4x.cfg

再启动 GDB:

bash 复制代码
arm-none-eabi-gdb firmware.elf

在 GDB 中连接目标:

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 和目标芯片
调试烧录工具 pyOCD ARM Cortex-M 烧录和调试
STM32 烧录 st-flash / STM32CubeProgrammer 烧录 STM32
ESP 烧录 esptool.py 烧录 ESP8266 / ESP32
AVR 烧录 avrdude 烧录 AVR 单片机
DFU 烧录 dfu-util 通过 USB DFU 烧录
构建工具 make 根据 Makefile 构建项目
构建生成器 CMake 生成 Makefile 或 Ninja 工程
高速构建 Ninja 快速执行构建
Zephyr 工具 west 管理、构建、烧录 Zephyr 项目

12. 初学者应该先掌握哪些

如果刚开始学习 C/C++ 或嵌入式开发,建议按下面顺序理解:

  1. gcc / g++:知道如何把源代码编译成程序。
  2. .c / .cpp / .h / .o / .elf / .bin:知道常见文件的含义。
  3. make:知道如何自动化编译。
  4. gdb:知道如何断点调试。
  5. objcopy / size:知道嵌入式固件如何转换和查看大小。
  6. OpenOCDpyOCD:知道如何烧录和调试单片机。
  7. CMake / Ninja:知道现代项目如何组织构建。

13. 最核心的一句话

这些工具可以按职责理解:

text 复制代码
gcc / g++ / clang      负责把源码编译成目标文件
ld                    负责把目标文件链接成程序
objcopy / size / nm    负责转换和分析生成文件
gdb / lldb             负责调试程序
OpenOCD / pyOCD        负责连接调试器和芯片
st-flash / esptool     负责把固件写入芯片
make / CMake / Ninja   负责自动化整个构建过程

把这些工具放到完整流程中看,就不会觉得它们是零散的命令,而是一条从"源代码"到"程序运行"的工具链。

相关推荐
济6171 小时前
【ROS2 Humble 开发专栏】Ubuntu22.04 基于 OpenCV 实现颜色阈值分割与目标坐标定位|附完整工程源码
嵌入式硬件·嵌入式·ros2·机器人开发·机器人方向
txh05071 小时前
串口数据调试-直观表示
嵌入式硬件·学习
半条-咸鱼1 小时前
【STM32】底层 CPU 流程、NVIC 优先级、GPIO 编程与事件(EVT)区别
stm32·单片机·嵌入式硬件
csg11071 小时前
工厂智能化改造(五):橡塑卷材边缘对齐与纠偏——一个典型非标案例
单片机·嵌入式硬件·物联网·自动化
振南的单片机世界2 小时前
地址总线定“找谁”,数据总线定“搬多少”
arm开发·stm32·单片机
yong99902 小时前
手机蓝牙发送指令STM32串口接收控制 LED 亮灭
stm32·单片机·智能手机
来点抹茶吗2 小时前
U-Boot、内核移植与根文件系统构建(BeagleBone Green Gateway&AM335X)
linux·嵌入式硬件·ubuntu·debian
嵌入式小站11 小时前
STM32 零基础可移植教程 17:USART + DMA + IDLE,串口不定长接收怎么做
stm32·单片机·嵌入式硬件
史蒂芬_丁11 小时前
Cortex-M内核中断保护机制详解:PRIMASK寄存器的正确使用方法
单片机·嵌入式硬件