2. 开发环境搭建:交叉编译工具链安装、TFTP/NFS网络引导配置、Ubuntu 22.04开发机准备

说实话,嵌入式Linux开发的第一步,往往是最磨人的。我记得刚入行那会儿,光搭环境就折腾了两天,最后发现是路径写错了。嗯,这节课咱们就把这些坑提前填上。

2.1 Ubuntu 22.04 开发机准备

我建议你直接用 Ubuntu 22.04 LTS,别问为什么不用20.04或者24.04。22.04的软件源最稳,交叉编译工具链的兼容性也最好。我在项目中试过24.04,有些老版本的库直接报错,折腾半天不值得。

硬件建议:

  • CPU:4核以上,编译内核时能省一半时间
  • 内存:至少8GB,16GB更舒服
  • 硬盘:预留80GB以上,一个完整的SDK解压下来就20多GB

装好系统后,第一件事就是换源。你想想看,从国内连国外源下载包,速度能急死人。

# 备份原源
sudo cp /etc/apt/sources.list /etc/apt/sources.list.bak

# 替换为清华源
sudo sed -i 's/archive.ubuntu.com/mirrors.tuna.tsinghua.edu.cn/g' /etc/apt/sources.list
sudo sed -i 's/security.ubuntu.com/mirrors.tuna.tsinghua.edu.cn/g' /etc/apt/sources.list

# 更新
sudo apt update && sudo apt upgrade -y

然后安装基础开发包。我习惯一次性装全,省得后面编译时缺这个少那个。

sudo apt install -y build-essential git vim curl wget \
  net-tools openssh-server nfs-kernel-server tftpd-hpa \
  xinetd u-boot-tools device-tree-compiler

小技巧:装完系统后,建议把SSH服务开起来。这样你可以在Windows上用MobaXterm或者Xshell连过来,不用一直蹲在Ubuntu主机前操作。

2.2 交叉编译工具链安装

交叉编译,说白了就是在你的x86电脑上编译出ARM架构能跑的程序。我刚开始做的时候总觉得这事很玄乎,其实原理很简单——编译器本身跑在x86上,但它生成的目标代码是ARM指令集。

这里我推荐两种方式,你根据实际情况选一个。

方式一:使用Linaro官方工具链(推荐)

Linaro的工具链最干净,没有厂商定制的那堆乱七八糟的东西。我在项目里一直用这个,从来没出过兼容性问题。

# 下载ARM 32位工具链
wget https://releases.linaro.org/components/toolchain/binaries/latest-7/arm-linux-gnueabihf/gcc-linaro-7.5.0-2019.12-x86_64_arm-linux-gnueabihf.tar.xz

# 解压到/opt目录
sudo tar -xf 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

# 验证安装
arm-linux-gnueabihf-gcc --version

方式二:使用厂商SDK

如果你用的是NXP i.MX系列或者TI AM系列,厂商会提供完整的SDK。我建议你直接用厂商的,因为里面包含了板级支持包和驱动源码。

# 以NXP i.MX8M为例
# 从NXP官网下载L5.15.52_2.1.0 SDK
chmod +x fsl-imx-xwayland-glibc-x86_64-imx-image-core-cortexa53-crypto-toolchain-5.15-kirkstone.sh
./fsl-imx-xwayland-glibc-x86_64-imx-image-core-cortexa53-crypto-toolchain-5.15-kirkstone.sh

# 安装后source环境
source /opt/fsl-imx-xwayland/5.15-kirkstone/environment-setup-cortexa53-crypto-poky-linux

注意:交叉编译工具链的版本必须与内核版本匹配。我曾经在一个项目里用了高版本的gcc编译老内核,结果编译出来的驱动模块加载时直接panic。血的教训啊。

2.3 TFTP服务器配置

TFTP这玩意儿,说白了就是个极简版的FTP。它用来在U-Boot启动时通过网络下载内核和设备树。为什么不用U盘?因为调试阶段你一天可能要烧写几十次内核,插拔U盘能把你逼疯。

配置步骤其实很简单:

# 修改TFTP配置文件
sudo vim /etc/default/tftpd-hpa

# 内容如下
TFTP_USERNAME="tftp"
TFTP_DIRECTORY="/tftpboot"
TFTP_ADDRESS="0.0.0.0:69"
TFTP_OPTIONS="-l -c -s"

# 创建TFTP根目录并设置权限
sudo mkdir -p /tftpboot
sudo chmod 777 /tftpboot

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

测试一下:

# 在/tftpboot下放一个测试文件
echo "Hello TFTP" | sudo tee /tftpboot/test.txt

# 在本机测试
tftp localhost
tftp> get test.txt
tftp> quit

# 查看是否下载成功
cat test.txt

避坑指南:防火墙一定要关掉,或者开放69端口。我曾经在客户现场调试,死活连不上TFTP,查了半天发现是ufw在作怪。

2.4 NFS服务器配置

NFS的作用是让开发板通过网络挂载你的开发机目录。这样你编译好的程序直接放在共享目录里,开发板上就能跑,不用每次都烧写文件系统。

配置步骤:

# 创建NFS共享目录
sudo mkdir -p /srv/nfs/rootfs

# 修改exports文件
sudo vim /etc/exports

# 添加以下内容(根据你的网段调整)
/srv/nfs/rootfs *(rw,sync,no_subtree_check,no_root_squash)

# 重启NFS服务
sudo systemctl restart nfs-kernel-server

# 验证
sudo exportfs -v

然后在U-Boot中设置启动参数:

# U-Boot命令行
setenv serverip 192.168.1.100    # 开发机IP
setenv ipaddr 192.168.1.200      # 开发板IP
setenv nfsroot /srv/nfs/rootfs
setenv bootargs console=ttymxc0,115200 root=/dev/nfs nfsroot=${serverip}:${nfsroot},v3,tcp ip=${ipaddr}:${serverip}:::eth0:off
saveenv
boot

关键点:

  • 开发板和开发机必须在同一个网段
  • no_root_squash选项必须加,否则开发板上的root用户没有写权限
  • NFS版本建议用v3,v4在某些老内核上会有兼容问题

2.5 整体架构图

下面这张图展示了开发环境的核心工作流程。你仔细看,其实就三个角色:开发机、网络服务、目标板。

嵌入式Linux开发环境架构图 嵌入式Linux开发环境架构图 Ubuntu 22.04 开发机 交叉编译工具链 TFTP服务器 NFS服务器 网络服务层 TFTP (端口69) NFS (端口2049) SSH (端口22) ARM目标板 U-Boot引导 Linux内核 根文件系统 提供服务 网络引导 数据流说明 ① 开发机通过TFTP向目标板传输内核镜像(zImage)和设备树(.dtb) ② 目标板通过NFS挂载开发机上的根文件系统,实现无盘启动 ③ 开发机通过SSH远程登录目标板,进行调试和程序部署 编译内核 TFTP下载 NFS挂载 运行调试

2.6 环境验证清单

搭完环境后,我建议你按这个清单逐项检查,少走弯路。

检查项 验证命令 预期结果
交叉编译器 arm-linux-gnueabihf-gcc --version 显示版本号,无报错
TFTP服务 systemctl status tftpd-hpa active (running)
NFS服务 systemctl status nfs-kernel-server active (exited)
NFS共享 showmount -e localhost 显示共享目录列表
TFTP下载 tftp localhost -c get test.txt 成功下载文件
NFS挂载 sudo mount -t nfs localhost:/srv/nfs/rootfs /mnt 挂载成功,可读写

常见问题排查:

  • TFTP连接超时:检查防火墙,确认69端口开放
  • NFS挂载报错"Permission denied":检查exports文件中的no_root_squash选项
  • 交叉编译报错"cannot execute binary file":确认你用的是正确的架构版本(arm vs aarch64)