2. 嵌入式Linux开发环境搭建:把“手术台”支起来

做嵌入式Linux开发,说白了就是“交叉编译”。你想想看,咱们的llama.cpp要在ARM板子上跑,但代码却是在x86的PC上写的。这就好比你要给一个病人做手术,但手术台太小,你只能在另一张桌子上把器械准备好,再拿过去用。

所以,环境搭建的第一步——你得把这张“准备桌”支起来。今天我就带你过一遍我个人的标准流程。

2.1 安装交叉编译工具链

交叉编译工具链,就是能在PC上生成ARM可执行文件的“编译器全家桶”。我常用的有两个:

工具链名称 目标架构 适用场景
gcc-arm-linux-gnueabihf 32位ARM (armv7-a) 树莓派2/3,全志H3等老款芯片
gcc-aarch64-linux-gnu 64位ARM (armv8-a) 树莓派3B+/4/5,RK3568/RK3588等

个人经验: 如果你不确定选哪个,可以去板子的官方文档看“uname -m”的输出。如果是“armv7l”,选32位;如果是“aarch64”,选64位。我在一个项目里吃过亏,拿32位工具链去编译64位的库,折腾了一整天。

2.1.1 从包管理器安装(推荐新手)

Debian/Ubuntu系统下,直接写:

# 安装 32 位工具链
sudo apt-get install gcc-arm-linux-gnueabihf

# 安装 64 位工具链
sudo apt-get install gcc-aarch64-linux-gnu

装完验证一下:

arm-linux-gnueabihf-gcc --version
aarch64-linux-gnu-gcc --version

输出能看到版本号,就说明装好了。简单吧?

2.1.2 手动安装Linaro工具链(我习惯的方式)

我为什么偏爱手动安装?因为版本更可控。有些生产环境必须锁定编译器版本,用apt-get往往会升级到最新版,反而出问题。

# 下载Linaro提供的预编译工具链
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

# 解压到指定目录
tar -xvf gcc-linaro-7.5.0-2019.12-x86_64_arm-linux-gnueabihf.tar.xz -C /opt/

# 配置环境变量
echo 'export PATH=$PATH:/opt/gcc-linaro-7.5.0-2019.12-x86_64_arm-linux-gnueabihf/bin' >> ~/.bashrc
source ~/.bashrc

2.2 配置TFTP与NFS

工具链装好只是第一步。你编译出来的内核和程序,怎么快速传给板子?每次插拔SD卡太原始了。这时候就要请出两位老搭档:TFTP和NFS。

  • TFTP:简单文件传输,一般用来下载内核和设备树,启动Uboot时用。
  • NFS:网络文件系统,把PC上的目录挂载到板子上,开发阶段直接在上面运行程序。

2.2.1 TFTP服务器配置

我用的是tftpd-hpa,轻量好用。

# 安装
sudo apt-get install tftpd-hpa

# 配置,指定TFTP根目录
sudo vi /etc/default/tftpd-hpa

# 内容如下:
TFTP_USERNAME="tftp"
TFTP_DIRECTORY="/srv/tftp"
TFTP_ADDRESS="0.0.0.0:69"
TFTP_OPTIONS="--secure --create"

# 创建目录并设置权限
sudo mkdir -p /srv/tftp
sudo chown -R tftp:tftp /srv/tftp

# 重启服务
sudo systemctl restart tftpd-hpa
sudo systemctl enable tftpd-hpa

注意: 我曾经因为防火墙没关,折腾了半小时连不上板子。Ubuntu默认防火墙不开放UDP 69端口,你最好检查一下:sudo ufw status。如果开启,记得加规则:sudo ufw allow 69/udp。

2.2.2 NFS服务器配置

NFS才是开发阶段的大杀器。你想想看,写代码、编译、然后直接通过网络跑程序,根本不用搬文件。

# 安装NFS服务器
sudo apt-get install nfs-kernel-server

# 创建共享目录
sudo mkdir -p /srv/nfs/rootfs
sudo chown -R nobody:nogroup /srv/nfs/rootfs

# 配置导出
sudo vi /etc/exports

# 添加如下行(具体IP或网段按你网络来)
/srv/nfs/rootfs *(rw,sync,no_subtree_check,no_root_squash)

# 生效配置
sudo exportfs -a
sudo systemctl restart nfs-kernel-server

关键参数说明:

  • rw:可读写
  • sync:同步写入,保证数据一致性
  • no_root_squash:允许板子上的root用户保持root权限。这个很重要,不然后面llama.cpp写日志都报权限不足。

2.3 使用QEMU模拟运行

有人会问:“我没有开发板怎么办?” 嗯,这个问题我遇到过,那会儿项目刚立项,板子还没到货。我用QEMU撑了三周,进度一点没落下。

QEMU可以模拟ARM处理器,让你在PC上“虚拟”一台开发板。我们用qemu-system-arm。

# 安装QEMU及相关支持
sudo apt-get install qemu-system-arm qemu-user-static

# 验证
qemu-system-arm --version

2.3.1 下载并测试一个简化内核

我们先用QEMU跑一个最小系统,验证整个工具链是否通畅。

# 下载vexpress开发板的内核和设备树
wget https://bootlin.com/doc/training/embedded-linux-qemu/linux-5.10.65-arm.tar.xz
tar xJf linux-5.10.65-arm.tar.xz

# 启动QEMU模拟器
qemu-system-arm -M vexpress-a9 \
    -kernel linux-5.10.65-arm/arch/arm/boot/zImage \
    -dtb linux-5.10.65-arm/arch/arm/boot/dts/vexpress-v2p-ca9.dtb \
    -nographic \
    -append "console=ttyAMA0,115200 root=/dev/mmcblk0"

如果一切正常,你会看到内核启动的日志打印。看到那行“VFS: Mounted root (ext4 filesystem)”,就说明环境跑通了。

2.3.2 交叉编译一个测试程序并跑在QEMU上

环境通了,我们来验证交叉编译器能工作。

# 编写测试程序
cat > hello.c << EOF
#include <stdio.h>

int main() {
    printf("Hello from QEMU ARM!\n");
    return 0;
}
EOF

# 交叉编译
arm-linux-gnueabihf-gcc -static -o hello hello.c

# 查看文件类型(确保是ARM架构)
file hello
# 输出: ELF 32-bit LSB executable, ARM, EABI5 version 1 ...

把编译好的hello文件放到共享目录,启动QEMU后执行:

# 在QEMU虚拟板子上
/hello
# 输出: Hello from QEMU ARM!

看到这行字,就说明你的整个交叉开发环境——从工具链到QEMU模拟器——全部通顺了。

核心思路: 在PC上开发,在QEMU或板子上运行。环境搭建的本质就是打通“编译-传输-运行”这条链路。链路通,万事通。

嵌入式Linux开发环境搭建流程图 嵌入式Linux开发环境搭建流程 PC Linux 开发机 x86_64 架构 交叉编译工具链 gcc-arm-linux-* TFTP 传输 下载内核/设备树 NFS 文件系统 挂载根文件系统 QEMU 模拟 / 开发板 ARM 架构 关键链路说明 ① 在PC上使用交叉工具链 编译ARM架构的程序 ② 通过TFTP下载内核 ③ 通过NFS挂载文件系统 ④ 在QEMU或真实板子上 运行并调试程序

避坑提醒: 我之前在一个项目里,因为NFS的版本不对(PC是NFSv4,板子里内核只支持NFSv3),挂载时一直报“RPC: Timed out”。花了半天才发现。所以配置时最好在/etc/exports里明确版本,或者用vers=3参数挂载:mount -t nfs -o nfsvers=3,noacl 192.168.1.100:/srv/nfs/rootfs /mnt