2. 开发环境搭建:交叉编译工具链安装、TFTP/NFS服务器配置、串口终端与网络调试环境

嵌入式Linux开发与桌面开发最大的区别在于交叉编译与远程调试。开发机(x86_64)无法直接运行ARM二进制文件,目标板(ARM64/ARM32)资源有限,无法承载完整的编译工具链。因此,一套高效、稳定的开发环境是后续内核裁剪与量产的基础。本章将分三部分搭建完整环境:交叉编译工具链、网络启动服务(TFTP/NFS)、串口与网络调试终端。

环境概览: 本文以 Ubuntu 22.04 LTS 作为开发机(Host),目标板为 ARM64(Cortex-A72),使用 gcc-arm-10.3-2021.07 工具链。若使用其他架构(如ARM32、RISC-V),原理相同,仅需替换工具链名称与架构参数。

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系列
ABI匹配至关重要: 目标板使用硬浮点(HF)还是软浮点(SF),必须与工具链一致。使用错误的ABI会导致程序无法运行或段错误。查看目标板CPU特性: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挂载根文件系统的完整流程:

网络启动架构:TFTP + NFS 工作流程 开发机 (Host) Ubuntu 22.04 x86_64 TFTP 服务器 NFS 服务器 目标板 (Target) ARM64 Cortex-A72 U-Boot Bootloader Linux Kernel 流程说明: 1. 目标板上电 → U-Boot启动,通过TFTP从开发机下载 kernel Image 和 DTB 2. U-Boot bootm 命令启动内核,内核通过NFS挂载开发机上的根文件系统 3. 开发机上修改代码 → 重新编译内核 → 目标板重启即可加载新内核,无需烧写

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
防火墙注意: TFTP使用UDP 69端口。若开发机启用了ufw防火墙,需放行: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
开发效率提升: 完成本章环境搭建后,后续的内核裁剪、驱动开发、应用调试均可实现“编译 → TFTP传输 → 重启验证”的3分钟快速迭代,彻底告别SD卡拔插的繁琐流程。