第二章 开发环境搭建:交叉编译工具链、QEMU模拟器与硬件选型
好,咱们正式开始动手了。这一章我带你搭开发环境。
说实话,很多初学者一上来就被环境折腾得够呛。工具链装不上、QEMU跑不起来、板子选错……这些坑我当年都踩过。今天咱们一次说清楚。
2.1 交叉编译工具链:GCC for ARM
先讲核心——交叉编译工具链。
你想想看,你的电脑是x86架构,但目标芯片是ARM。你不能直接在电脑上编译出ARM能跑的程序吗?能,但需要特殊工具。这个工具就叫交叉编译工具链。
我个人习惯用Linaro GCC。为什么?因为它是ARM官方推荐的,更新快,兼容性好。我在项目中遇到过用其他工具链编译出来的程序,在树莓派上跑着跑着就崩了,换成Linaro就没事。嗯,这里要注意。
安装步骤(以Ubuntu 20.04为例)
# 安装ARM交叉编译工具链
sudo apt-get update
sudo apt-get install gcc-arm-linux-gnueabihf
sudo apt-get install g++-arm-linux-gnueabihf
# 验证安装
arm-linux-gnueabihf-gcc --version
装完之后,你试试编译一个最简单的程序:
// hello.c
#include <stdio.h>
int main() {
printf("Hello, ARM World!\n");
return 0;
}
arm-linux-gnueabihf-gcc -o hello hello.c
file hello
看到输出是 ELF 32-bit LSB executable, ARM 就对了。这说明你编译出来的程序是ARM架构的,不是x86的。
我曾经在项目里犯过一个低级错误:用x86的gcc编译了程序,然后拷到ARM板子上跑。结果报错“Exec format error”。折腾了半天才发现是工具链用错了。所以每次编译前,先看一眼输出文件的架构。
工具链的组成
一个完整的交叉编译工具链包含这些:
| 组件 | 作用 | 常用命令 |
|---|---|---|
| 编译器 | 把C/C++代码编译成汇编 | arm-linux-gnueabihf-gcc |
| 汇编器 | 把汇编转成机器码 | arm-linux-gnueabihf-as |
| 链接器 | 把目标文件链接成可执行文件 | arm-linux-gnueabihf-ld |
| 调试器 | 调试ARM程序 | arm-linux-gnueabihf-gdb |
| 库 | 运行时库和头文件 | /usr/arm-linux-gnueabihf/lib/ |
说白了,你只需要记住 arm-linux-gnueabihf-gcc 这一个命令就够了。其他工具它内部会自动调用。
2.2 QEMU模拟器:没有板子也能学
不是每个人都有开发板。就算有,也不可能每次调试都往板子上烧程序。这时候QEMU就派上用场了。
QEMU是一个开源的模拟器。它能模拟完整的ARM开发板,包括CPU、内存、外设。我在项目初期做原型验证时,经常先用QEMU跑一遍,确认逻辑没问题再上真板子。效率高很多。
安装QEMU
sudo apt-get install qemu-system-arm
qemu-system-arm --version
装完之后,咱们试试模拟一个树莓派:
# 下载树莓派内核和文件系统
wget https://github.com/dhruvvyas90/qemu-rpi-kernel/raw/master/kernel-qemu-4.4.34-jessie
wget https://downloads.raspberrypi.org/raspbian_lite_latest
# 启动QEMU模拟树莓派
qemu-system-arm \
-kernel kernel-qemu-4.4.34-jessie \
-cpu arm1176 \
-m 256 \
-M versatilepb \
-no-reboot \
-serial stdio \
-append "root=/dev/sda2 panic=1 rootfstype=ext4 rw" \
-hda raspbian_lite_latest
第一次启动QEMU会比较慢,因为要解压文件系统。耐心等一两分钟就好。如果卡住了,按Ctrl+A然后按X退出。
启动成功后,你会看到一个完整的Linux命令行界面。这时候你就可以在上面编译程序、调试驱动了。和真板子体验几乎一样。
QEMU的调试功能
QEMU最强大的地方在于调试。你可以用GDB远程连接QEMU,单步执行ARM指令:
# 启动QEMU并开启GDB服务
qemu-system-arm -s -S -kernel my_program.bin ...
# 另一个终端启动GDB
arm-linux-gnueabihf-gdb my_program.elf
(gdb) target remote localhost:1234
(gdb) break main
(gdb) continue
(gdb) stepi
为什么会这样?因为QEMU在 -s 参数下会监听1234端口,等待GDB连接。 -S 参数让CPU在启动时暂停,等你下好断点再继续。这个组合拳我在调试启动代码时用过无数次,非常顺手。
2.3 硬件开发板选型建议
好了,软件环境搭好了。但最终还是要上真板子的。选哪块板子?我直接给结论。
树莓派 vs BeagleBone
| 对比项 | 树莓派4B | BeagleBone Black |
|---|---|---|
| CPU | BCM2711 (Cortex-A72) | AM3358 (Cortex-A8) |
| 主频 | 1.5GHz | 1GHz |
| 内存 | 2GB/4GB/8GB | 512MB |
| GPIO | 40针 | 92针(2x46) |
| 实时性 | 一般 | 好(有PRU协处理器) |
| 价格 | 约300元 | 约400元 |
| 社区资源 | 非常丰富 | 丰富 |
我的建议是这样的:
- 初学者选树莓派。社区资源多,遇到问题随便一搜就有答案。而且Cortex-A72性能强,跑Linux很流畅。
- 做嵌入式Linux底层开发选BeagleBone。它的PRU协处理器可以做实时控制,而且引出引脚多,适合做工业控制类项目。
- 如果预算有限,先玩QEMU。等把基础打牢了再买板子。我在带新人时,都是让他们先在QEMU上跑通所有实验,最后一周才上真板子。
我个人推荐:
1. 入门阶段:树莓派4B(2GB版本足够)
2. 进阶阶段:BeagleBone Black(适合驱动开发)
3. 调试阶段:QEMU + GDB(效率最高)
选板子的避坑指南
我曾经帮一个朋友选板子,他非要买一块很冷门的开发板。结果呢?资料少得可怜,遇到问题连个问的人都没有。最后折腾了一个月,还是换回了树莓派。
所以我的建议是:
- 别买太冷门的板子。社区活跃度比硬件参数更重要。
- 注意电源适配器。树莓派4B需要5V 3A的电源,用手机充电器可能带不动。
- 买一块带WiFi和蓝牙的板子。调试时不用插网线,方便很多。
2.4 环境验证:跑通第一个程序
环境搭好了,咱们跑个程序验证一下。我写了一个简单的点灯程序,你可以在树莓派或QEMU上试试:
// led_blink.c
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/mman.h>
#define GPIO_BASE 0xFE200000 // 树莓派4B的GPIO基地址
int main() {
int mem_fd = open("/dev/mem", O_RDWR | O_SYNC);
if (mem_fd < 0) {
perror("open /dev/mem failed");
return -1;
}
void *gpio_map = mmap(NULL, 4096, PROT_READ | PROT_WRITE,
MAP_SHARED, mem_fd, GPIO_BASE);
if (gpio_map == MAP_FAILED) {
perror("mmap failed");
close(mem_fd);
return -1;
}
printf("GPIO mapped at %p\n", gpio_map);
printf("Environment setup successfully!\n");
munmap(gpio_map, 4096);
close(mem_fd);
return 0;
}
# 交叉编译
arm-linux-gnueabihf-gcc -o led_blink led_blink.c
# 拷贝到板子或QEMU中运行
scp led_blink pi@192.168.1.100:~/
# 或者在QEMU中挂载文件系统后运行
如果看到 Environment setup successfully! 的打印,说明你的交叉编译工具链、QEMU(或开发板)全部正常工作。恭喜,环境搭建完成!
下一章咱们开始写真正的ARM汇编代码。你会看到Cortex-A的寄存器、指令集,以及如何用汇编控制硬件。做好准备,要开始动真格的了。