第二章:开发环境搭建
说实话,很多做固件开发的新人,上来就急着写代码。结果呢?编译不过、调试不了、版本乱成一锅粥。我见过太多这样的案例了。今天咱们就把开发环境这第一步走扎实。
2.1 Linux开发环境配置
做服务器芯片固件开发,Linux是标配。我个人习惯用Ubuntu 20.04 LTS,稳定,社区支持好。当然CentOS、Debian也行,看团队统一。
先说说基础依赖包。你想想看,一个干净的Linux系统,缺的东西可不少。我一般这么装:
sudo apt-get update
sudo apt-get install -y build-essential
sudo apt-get install -y git vim curl wget
sudo apt-get install -y libncurses5-dev libssl-dev
sudo apt-get install -y bison flex bc
sudo apt-get install -y python3 python3-pip
sudo apt-get install -y device-tree-compiler
嗯,这里要注意。不同芯片平台可能还有额外依赖。比如ARM平台需要gcc-arm-linux-gnueabihf,RISC-V平台需要riscv64-linux-gnu-gcc。别一股脑全装,看项目需求。
2.2 交叉编译工具链安装
交叉编译,说白了就是在PC上编译出能在目标芯片上跑的程序。为什么需要这个?因为服务器芯片的资源有限,你不可能在上面跑编译器。
我遇到过最坑的事:有人直接把PC上的gcc编译出来的二进制烧到芯片里,结果跑不起来。嗯,架构都不一样,怎么可能跑得起来?
安装交叉编译工具链,常见两种方式:
方式一:从芯片厂商获取
这是最推荐的方式。比如Intel的Slim Bootloader、ARM的GNU Toolchain。厂商会提供预编译好的工具链,直接解压就能用。
# 以ARM64为例
wget https://developer.arm.com/-/media/Files/downloads/gnu-a/10.3-2021.07/binrel/gcc-arm-10.3-2021.07-x86_64-aarch64-none-linux-gnu.tar.xz
tar -xf gcc-arm-10.3-2021.07-x86_64-aarch64-none-linux-gnu.tar.xz
export PATH=$PATH:/path/to/gcc-arm-10.3-2021.07-x86_64-aarch64-none-linux-gnu/bin
方式二:自己编译
如果你用的芯片比较小众,或者需要定制优化,那就得自己编译crosstool-NG。我当年为了一个MIPS的芯片,折腾了整整两天才把工具链搞定。
git clone https://github.com/crosstool-ng/crosstool-ng
cd crosstool-ng
./bootstrap
./configure --enable-local
make
./ct-ng menuconfig # 配置目标架构
./ct-ng build
2.3 版本控制工具Git的使用
做固件开发,Git是基本功。我见过有人用U盘拷代码,结果版本搞混了,把稳定版覆盖了。那场面,啧啧。
这里我分享几个固件开发中常用的Git操作:
基本工作流
# 克隆仓库
git clone git@github.com:your-company/firmware.git
# 创建分支
git checkout -b feature/uart-driver
# 提交代码
git add .
git commit -m "feat: add UART driver for chip X"
# 推送到远程
git push origin feature/uart-driver
固件开发特有的Git技巧
固件开发经常要维护多个版本。比如芯片A的v1.0、v1.1,芯片B的v2.0。我习惯用tag来标记发布版本:
# 打标签
git tag -a v1.0.0 -m "Release version 1.0.0"
git push origin v1.0.0
# 查看历史
git log --oneline --graph --all
避坑指南: 我曾经在固件开发中犯过一个低级错误——直接在master分支上改代码。结果同事拉取代码后编译不过,整个团队等我修复。从那以后,我坚持「功能分支+Code Review」的流程。
2.4 固件调试工具准备
调试固件和调试普通程序不一样。你不能直接printf,因为芯片可能连串口都没初始化。你需要一套专业的调试工具链。
必备调试工具清单
| 工具名称 | 用途 | 我的推荐 |
|---|---|---|
| OpenOCD | 通过JTAG/SWD调试芯片 | 开源免费,支持多种调试器 |
| GDB | 源码级调试 | 配合OpenOCD使用,功能强大 |
| UART工具 | 串口日志输出 | minicom或screen,简单实用 |
| 逻辑分析仪 | 抓取硬件信号 | Saleae Logic,性价比高 |
| Trace工具 | 指令执行追踪 | ARM的DSTREAM或Lauterbach |
搭建调试环境
以OpenOCD+GDB为例,我一般这么配置:
# 安装OpenOCD
sudo apt-get install openocd
# 启动OpenOCD,连接调试器
openocd -f interface/jlink.cfg -f target/stm32f4x.cfg
# 另一个终端启动GDB
aarch64-none-linux-gnu-gdb firmware.elf
(gdb) target remote localhost:3333
(gdb) monitor reset halt
(gdb) load
(gdb) continue
我的调试心得: 刚开始做固件调试时,我总喜欢用print大法。后来发现,很多时候print本身就会改变程序行为(比如时序问题)。现在我的习惯是:先用逻辑分析仪看硬件信号对不对,再用GDB单步调试,最后才加print。这个顺序能省下不少时间。
串口调试配置
串口是固件开发者的「眼睛」。我习惯用screen工具:
# 查看串口设备
ls /dev/ttyUSB*
# 连接串口,波特率115200
screen /dev/ttyUSB0 115200
# 退出screen:Ctrl+A, 然后按K
好了,开发环境搭建就讲到这里。下一章咱们开始实战——写第一个固件程序。到时候我会带着大家从零开始,把今天配置的环境用起来。