2. 开发环境搭建:交叉编译工具链安装、QEMU模拟器配置、目标板与主机通信设置
做嵌入式Linux裁剪,第一步不是写代码,而是搭环境。我见过太多人一上来就急着改内核配置,结果编译都过不了,最后发现是工具链没装对。说白了,环境搭不好,后面全是白费功夫。
这一章,我们就把三件事搞定:交叉编译工具链、QEMU模拟器、主机与目标板的通信。这三样东西,就像木匠的刨子、锯子和尺子,缺一不可。
2.1 交叉编译工具链:为什么非得用这个?
你想想看,你的PC是x86架构,目标板可能是ARM、RISC-V或者MIPS。PC上编译出来的程序,目标板根本跑不了。交叉编译,就是在你的强大PC上,生成目标板能执行的二进制文件。
我个人习惯用Linaro提供的预编译工具链,稳定又省事。当然,你也可以用Buildroot或Yocto自己从头编一个,但那太费时间了。做裁剪嘛,效率第一。
2.1.1 安装ARM交叉编译工具链
以最常用的ARM Cortex-A系列为例,我们装gcc-arm-linux-gnueabihf。我在项目中遇到过用错版本导致浮点运算崩溃的情况,所以这里强调一下:hf 代表硬浮点,如果你的芯片支持硬件浮点,一定要选这个。
# 下载Linaro GCC 7.5版本(稳定,兼容性好)
wget https://releases.linaro.org/components/toolchain/binaries/7.5-2019.12/arm-linux-gnueabihf/gcc-linaro-7.5.0-2019.12-x86_64_arm-linux-gnueabihf.tar.xz
# 解压到 /opt 目录
sudo tar -xvf gcc-linaro-7.5.0-2019.12-x86_64_arm-linux-gnueabihf.tar.xz -C /opt/
# 添加环境变量(建议写到 ~/.bashrc 里永久生效)
export PATH=/opt/gcc-linaro-7.5.0-2019.12-x86_64_arm-linux-gnueabihf/bin:$PATH
# 验证安装
arm-linux-gnueabihf-gcc --version
2.1.2 验证工具链是否能用
装完别急着走,写个Hello World测一下。我曾经有一次装完没验证,结果编译内核时才发现链接器版本不对,排查了半天。
# 写一个测试文件
echo '#include <stdio.h>
int main() {
printf("Hello, Embedded Linux!\n");
return 0;
}' > test.c
# 交叉编译
arm-linux-gnueabihf-gcc test.c -o test_arm
# 查看生成的文件信息
file test_arm
# 输出应该类似:ELF 32-bit LSB executable, ARM, EABI5 version 1 (SYSV)
看到 ARM 字样,说明工具链工作正常。嗯,这里要注意:如果显示的是 x86-64,说明你用的是本地gcc,路径没配对。
2.2 QEMU模拟器:没有开发板也能干活
做裁剪,不可能每次改个配置就烧一次板子。QEMU就是你的虚拟开发板。我刚开始做嵌入式时,手头只有一块板子,同事排队用,后来全靠QEMU在PC上调试,效率翻了好几倍。
2.2.1 安装QEMU
QEMU支持多种架构。我们这里以ARM的versatilepb板型为例,这个板型在QEMU里模拟得最成熟。
# Ubuntu/Debian系安装
sudo apt-get update
sudo apt-get install qemu-system-arm qemu-user-static
# 验证安装
qemu-system-arm --version
2.2.2 用QEMU启动一个最小Linux系统
我们先用QEMU跑一个现成的内核和根文件系统,验证环境是否通。这一步很重要,别跳过。
# 下载测试用的内核和根文件系统(我用的是kernel.org的测试镜像)
wget https://people.debian.org/~aurel32/qemu/armhf/vmlinuz-3.2.0-4-vexpress
wget https://people.debian.org/~aurel32/qemu/armhf/initrd.img-3.2.0-4-vexpress
# 启动QEMU
qemu-system-arm \
-M vexpress-a9 \
-kernel vmlinuz-3.2.0-4-vexpress \
-initrd initrd.img-3.2.0-4-vexpress \
-append "console=ttyAMA0" \
-nographic
看到内核启动日志,最后出现 login: 提示,说明QEMU环境搭好了。按 Ctrl+A 再按 X 退出。
2.3 目标板与主机通信设置
QEMU跑起来了,但怎么跟它交互?怎么传文件?这就涉及到通信设置了。说白了,就是让主机(你的PC)和目标板(QEMU或真实板子)能互相说话。
2.3.1 串口通信:最基础的方式
真实开发板通常用串口。QEMU里我们用 -nographic 或 -serial stdio 把串口重定向到终端。我在项目中遇到过串口波特率不匹配导致乱码的问题,所以这里列个常用参数表:
| 参数 | 说明 | 典型值 |
|---|---|---|
-nographic |
无图形界面,串口输出到当前终端 | 常用 |
-serial stdio |
串口重定向到标准输入输出 | 调试时用 |
-serial tcp::4444,server |
串口通过TCP转发,可用telnet连接 | 远程调试 |
-serial file:output.log |
串口输出保存到文件 | 记录日志 |
2.3.2 网络通信:让QEMU能上网
裁剪系统时,经常需要从目标板下载包或同步文件。QEMU默认提供用户模式网络(User Networking),但功能有限。我建议用Tap网络模式,性能更好,功能更全。
# 创建Tap网络接口(需要root权限)
sudo ip tuntap add dev tap0 mode tap
sudo ip addr add 192.168.100.1/24 dev tap0
sudo ip link set tap0 up
# 启动QEMU并连接Tap网络
qemu-system-arm \
-M vexpress-a9 \
-kernel vmlinuz-3.2.0-4-vexpress \
-initrd initrd.img-3.2.0-4-vexpress \
-append "console=ttyAMA0 root=/dev/mmcblk0" \
-netdev tap,id=net0,ifname=tap0,script=no,downscript=no \
-device virtio-net-device,netdev=net0 \
-nographic
在目标板里配置IP:
# 在QEMU的Linux终端里执行
ifconfig eth0 192.168.100.2 netmask 255.255.255.0 up
ping 192.168.100.1 # 测试与主机的连通性
核心要点: 主机IP设为192.168.100.1,目标板设为192.168.100.2。这样两边就能互相ping通了。如果ping不通,八成是防火墙没关,或者Tap接口没配好。
2.3.3 文件传输:用NFS共享目录
裁剪过程中,最频繁的操作就是:在主机上编译好程序,传到目标板上测试。用U盘拷来拷去太原始了。我习惯用NFS(网络文件系统),直接把主机目录挂载到目标板上。
主机端配置:
# 安装NFS服务器
sudo apt-get install nfs-kernel-server
# 创建共享目录
mkdir -p /home/yourname/nfs_share
chmod 777 /home/yourname/nfs_share
# 编辑 /etc/exports,添加一行
echo "/home/yourname/nfs_share 192.168.100.0/24(rw,sync,no_subtree_check,no_root_squash)" | sudo tee -a /etc/exports
# 重启NFS服务
sudo systemctl restart nfs-kernel-server
目标板端挂载:
# 在QEMU的Linux终端里执行
mount -t nfs -o nolock 192.168.100.1:/home/yourname/nfs_share /mnt
# 验证
ls /mnt
# 应该能看到主机上的文件
mount: unknown filesystem type 'nfs',说明内核没配好,先回内核配置里把NFS勾上。
2.4 本章知识体系总览
说了这么多,我画张图帮你理清思路。开发环境搭建的核心就是这三层:工具链负责编译,QEMU负责运行,通信负责交互。三者环环相扣。
2.5 常见问题与排查思路
环境搭建总会遇到各种坑。我把这些年踩过的雷整理一下,你遇到了可以直接对照排查。
- 工具链装完找不到命令 —— 八成是PATH没配对。检查
echo $PATH里有没有工具链的bin目录。我建议直接写到~/.bashrc里,别每次手动export。 - QEMU启动后黑屏 —— 可能是内核参数没传对。试试加上
console=ttyAMA0或console=ttyS0,具体看板型。我遇到过用vexpress板型但传了ttyS0,结果死活没输出。 - NFS挂载报错"Permission denied" —— 检查
/etc/exports里的权限设置,别忘了加no_root_squash。另外,目标板的内核必须支持NFS客户端。 - 网络ping不通 —— 先确认Tap接口有没有up,再检查主机防火墙。我习惯直接
sudo ufw disable省事,但生产环境别这么干。
我的经验: 环境搭建最忌讳「一步到位」。我每次都是分三步走:先验证工具链能编译,再验证QEMU能启动,最后验证通信能传文件。每一步都确认没问题了,再往下走。这样出了问题,能立刻定位到是哪一步。
好了,环境搭好了,工具链能编译了,QEMU能跑起来了,主机和目标板也能聊天了。接下来,我们就可以正式开始裁剪之旅了。记住,环境是基础,基础不牢,地动山摇。花点时间把这一步做扎实,后面会顺畅很多。