2. 开发环境搭建
嵌入式Linux开发与桌面开发最大的区别在于交叉编译与远程调试。开发机(x86_64)无法直接运行ARM二进制文件,目标板(ARM64/ARM32)资源有限,无法承载完整的编译工具链。因此,一套高效、稳定的开发环境是后续内核裁剪与量产的基础。本章将分三部分搭建完整环境:交叉编译工具链、网络启动服务(TFTP/NFS)、串口与网络调试终端。
2.1 交叉编译工具链安装
交叉编译工具链是嵌入式开发的“第一把钥匙”。它运行在x86_64主机上,但生成的二进制代码在ARM目标板上执行。工具链包含编译器(gcc)、汇编器(as)、链接器(ld)、库文件(glibc/uclibc)以及调试器(gdb)。
2.1.1 工具链选择与下载
推荐使用Linaro或ARM官方提供的预编译工具链,避免从源码编译的复杂性。以下为常见选择:
| 工具链名称 | 架构 | ABI | 适用场景 |
|---|---|---|---|
| gcc-arm-10.3-2021.07-x86_64-aarch64-none-linux-gnu | ARM64 (AArch64) | LP64 | 树莓派4/5、RK3588、Jetson Nano |
| gcc-arm-10.3-2021.07-x86_64-arm-none-linux-gnueabihf | ARM32 (ARMv7-A) | 硬浮点 (HF) | STM32MP1、i.MX6ULL、AM335x |
| gcc-arm-10.3-2021.07-x86_64-arm-none-eabi | ARM32 (ARMv7-M/R) | 裸机 (Bare-metal) | STM32F4、Cortex-M系列 |
cat /proc/cpuinfo | grep Features,若包含 fp 和 neon,则使用HF工具链。
2.1.2 安装步骤
以下以ARM64工具链为例,演示完整安装与验证流程:
# 1. 下载工具链(约200MB)
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
# 2. 解压到 /opt 目录
sudo tar -xvf gcc-arm-10.3-2021.07-x86_64-aarch64-none-linux-gnu.tar.xz -C /opt/
# 3. 添加环境变量(写入 ~/.bashrc 或 /etc/profile)
export PATH=$PATH:/opt/gcc-arm-10.3-2021.07-x86_64-aarch64-none-linux-gnu/bin
# 4. 使环境变量生效
source ~/.bashrc
# 5. 验证安装
aarch64-none-linux-gnu-gcc --version
# 输出示例:aarch64-none-linux-gnu-gcc (GCC) 10.3.1 20210621 (release)
2.1.3 测试交叉编译
编写一个简单的Hello World程序,验证工具链能否正确生成ARM64可执行文件:
// hello.c
#include <stdio.h>
int main(void) {
printf("Hello from ARM64!\n");
return 0;
}
# 交叉编译
aarch64-none-linux-gnu-gcc -o hello_arm64 hello.c
# 查看生成的文件类型
file hello_arm64
# 输出:hello_arm64: ELF 64-bit LSB executable, ARM aarch64, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux-aarch64.so.1
# 注意:不能在x86主机上直接运行!
./hello_arm64
# 输出:bash: ./hello_arm64: cannot execute binary file: Exec format error
file 命令确认生成的ELF文件架构为 ARM aarch64,且动态链接器路径正确。若显示 x86-64,说明未使用交叉编译器,请检查PATH路径。
2.2 TFTP/NFS服务器配置
在开发阶段,频繁烧写eMMC/SD卡效率极低。通过TFTP(Trivial File Transfer Protocol)下载内核与设备树,通过NFS(Network File System)挂载根文件系统,可以实现“网络启动+无盘开发”,大幅缩短迭代周期。
2.2.1 网络启动架构
下图展示了U-Boot通过TFTP加载内核,并通过NFS挂载根文件系统的完整流程:
2.2.2 TFTP服务器配置
TFTP用于在U-Boot阶段快速下载内核镜像(Image)和设备树(DTB)。配置步骤如下:
# 1. 安装TFTP服务器
sudo apt update
sudo apt install tftpd-hpa -y
# 2. 创建TFTP根目录并设置权限
sudo mkdir -p /srv/tftp
sudo chmod 777 /srv/tftp
# 3. 修改配置文件 /etc/default/tftpd-hpa
sudo vim /etc/default/tftpd-hpa
# 文件内容如下:
TFTP_USERNAME="tftp"
TFTP_DIRECTORY="/srv/tftp"
TFTP_ADDRESS="0.0.0.0:69"
TFTP_OPTIONS="--secure --create"
# 4. 重启服务并设置开机自启
sudo systemctl restart tftpd-hpa
sudo systemctl enable tftpd-hpa
# 5. 验证服务状态
sudo systemctl status tftpd-hpa
# 输出应包含:active (running)
# 6. 测试TFTP(本地回环测试)
echo "TFTP Test" | sudo tee /srv/tftp/test.txt
tftp localhost -c get test.txt
cat test.txt
# 输出:TFTP Test
sudo ufw allow 69/udp。目标板与开发机需在同一网段,建议使用静态IP。
2.2.3 NFS服务器配置
NFS用于挂载根文件系统,使目标板直接使用开发机上的文件系统目录,实现“无盘启动”。
# 1. 安装NFS服务器
sudo apt install nfs-kernel-server -y
# 2. 创建NFS导出目录(存放根文件系统)
sudo mkdir -p /srv/nfs/rootfs
# 3. 解压或复制根文件系统到导出目录
# 例如使用Buildroot生成的rootfs.tar
sudo tar -xvf rootfs.tar -C /srv/nfs/rootfs/
# 4. 配置 /etc/exports
sudo vim /etc/exports
# 添加以下内容(根据实际网段修改)
/srv/nfs/rootfs *(rw,sync,no_subtree_check,no_root_squash)
# 参数说明:
# rw:读写权限
# sync:同步写入
# no_subtree_check:禁用子树检查,提高性能
# no_root_squash:允许目标板root用户拥有完整权限
# 5. 重启NFS服务
sudo systemctl restart nfs-kernel-server
# 6. 验证导出
showmount -e localhost
# 输出:Export list for localhost: /srv/nfs/rootfs *
no_root_squash 是嵌入式开发的关键选项。若不添加,目标板的root用户会被映射为nobody,导致无法创建设备节点、修改系统文件。量产阶段应关闭此选项以增强安全性。
2.2.4 U-Boot网络启动参数
在目标板的U-Boot命令行中,设置以下环境变量即可实现网络启动:
# 设置开发机IP、目标板IP、网关
setenv serverip 192.168.1.100 # 开发机IP
setenv ipaddr 192.168.1.50 # 目标板IP
setenv gatewayip 192.168.1.1
# 设置TFTP文件路径
setenv image_name Image # 内核镜像文件名
setenv fdt_name board.dtb # 设备树文件名
# 设置NFS根文件系统路径
setenv rootpath /srv/nfs/rootfs
setenv nfsargs root=/dev/nfs rw nfsroot=${serverip}:${rootpath},v3,tcp ip=${ipaddr}:${serverip}:${gatewayip}:255.255.255.0::eth0:off
# 启动命令
setenv bootcmd 'tftp ${loadaddr} ${image_name}; tftp ${fdt_addr_r} ${fdt_name}; booti ${loadaddr} - ${fdt_addr_r}'
setenv bootargs console=ttyAMA0,115200 ${nfsargs}
# 保存并启动
saveenv
boot
2.3 串口终端与网络调试环境
串口是嵌入式开发中最可靠的“生命线”——即使网络未初始化、内核崩溃,串口依然能输出信息。网络调试(SSH/GDB)则用于高效的文件传输与远程调试。
2.3.1 串口终端配置
推荐使用 Minicom 或 Picocom 作为串口终端工具。Picocom更轻量,配置更简单:
# 1. 安装Picocom
sudo apt install picocom -y
# 2. 查看串口设备
ls -l /dev/ttyUSB* # USB转串口
ls -l /dev/ttyACM* # 原生串口设备
# 3. 连接串口(常见参数:115200 8N1)
sudo picocom -b 115200 -d 8 -p n -s 1 /dev/ttyUSB0
# 常用快捷键:
# Ctrl+A, Ctrl+X:退出Picocom
# Ctrl+A, Ctrl+Z:查看帮助
# Ctrl+A, Ctrl+U:上传文件(配合ymodem)
| 参数 | 含义 | 典型值 |
|---|---|---|
| -b | 波特率 (Baud rate) | 115200 |
| -d | 数据位 (Data bits) | 8 |
| -p | 校验位 (Parity) | n (无校验) |
| -s | 停止位 (Stop bits) | 1 |
sudo 运行picocom较麻烦。将当前用户加入 dialout 组即可免sudo:sudo usermod -aG dialout $USER,然后重新登录。
2.3.2 网络调试环境
目标板启动后,通过SSH进行文件传输与远程命令执行,通过GDB进行远程调试:
# 1. 目标板上启动SSH服务(若根文件系统包含openssh)
# 在目标板执行:
systemctl start sshd
systemctl enable sshd
# 2. 从开发机SSH登录目标板
ssh root@192.168.1.50
# 3. 使用scp传输文件
scp hello_arm64 root@192.168.1.50:/root/
# 4. 远程GDB调试(目标板运行gdbserver)
# 目标板:
gdbserver :2345 /root/hello_arm64
# 开发机:
aarch64-none-linux-gnu-gdb hello_arm64
(gdb) target remote 192.168.1.50:2345
(gdb) continue
2.3.3 调试环境验证清单
完成上述配置后,使用以下清单逐项验证环境是否就绪:
| 验证项 | 命令/操作 | 预期结果 |
|---|---|---|
| 交叉编译器 | aarch64-none-linux-gnu-gcc --version |
显示版本号,无报错 |
| TFTP下载 | 目标板U-Boot执行 tftp ${loadaddr} Image |
显示下载进度,文件大小正确 |
| NFS挂载 | 目标板执行 mount -t nfs -o nfsvers=3 192.168.1.100:/srv/nfs/rootfs /mnt |
挂载成功,ls /mnt 显示根文件系统内容 |
| 串口输出 | 目标板上电,观察串口终端 | 显示U-Boot启动日志,内核启动日志 |
| SSH登录 | ssh root@192.168.1.50 |
成功登录目标板Shell |