2、嵌入式Linux开发环境搭建:交叉编译工具链、TFTP/NFS与调试工具

大家好,我是你们的讲师。今天我们来聊聊嵌入式Linux开发环境的搭建。说实话,很多初学者觉得这步就是装个软件、配个路径,没什么技术含量。但我得说,环境搭得好,后面少烦恼。我在项目里见过太多因为工具链版本不对、网络文件系统没配好,白白浪费一两天的情况。

这一章,我们聚焦三个核心:交叉编译工具链(GCC for ARM64)TFTP/NFS网络文件系统,以及串口终端与调试工具。嗯,一个一个来。

2.1 交叉编译工具链:GCC for ARM64

先问个问题:为什么需要交叉编译?

你想想看,你的开发机是x86架构,而自动驾驶平台用的是ARM64(比如NVIDIA Orin、NXP S32G)。x86上编译出来的程序,ARM64跑不了。反过来,ARM64上直接编译?算力有限,而且开发效率太低。所以,我们得在x86上编译出ARM64能跑的程序——这就是交叉编译。

2.1.1 工具链的选择

我个人习惯用Linaro提供的GCC工具链,稳定且社区活跃。当然,你也可以用芯片厂商提供的定制版,比如NVIDIA的JetPack里就带了。

常用的ARM64交叉编译工具链有:

  • aarch64-linux-gnu-gcc:标准GNU工具链,适合通用Linux系统
  • aarch64-linux-gnu-g++:C++编译器
  • aarch64-linux-gnu-ld:链接器
  • aarch64-linux-gnu-objdump:反汇编工具

重要提示:工具链版本必须与目标系统的内核版本、glibc版本匹配。否则,编译出来的程序可能无法运行,或者运行时出现奇怪的段错误。

2.1.2 安装与配置

安装其实很简单。以Ubuntu 20.04为例:

# 安装ARM64交叉编译工具链
sudo apt-get install gcc-aarch64-linux-gnu g++-aarch64-linux-gnu

# 验证安装
aarch64-linux-gnu-gcc --version

安装完成后,写个简单的测试程序:

// hello.c
#include <stdio.h>

int main() {
    printf("Hello from ARM64!\n");
    return 0;
}
# 编译
aarch64-linux-gnu-gcc -o hello hello.c

# 查看文件信息
file hello
# 输出:hello: ELF 64-bit LSB executable, ARM aarch64, ...

看到“ARM aarch64”就对了。我曾经有一次编译完忘了检查,直接拷到板子上跑,结果报“Exec format error”。嗯,当时排查了半天才发现是工具链没配对。

2.1.3 避坑指南:静态链接 vs 动态链接

这里有个坑,我踩过。如果你的目标系统上缺少某些动态库,编译时最好用静态链接:

aarch64-linux-gnu-gcc -static -o hello hello.c

静态链接生成的文件会大一些,但省去了库依赖的麻烦。特别是自动驾驶平台,有时候为了精简系统,很多库都没装全。

我的建议:开发阶段用动态链接,方便调试;发布阶段用静态链接,确保兼容性。

2.2 TFTP/NFS网络文件系统搭建

接下来是网络文件系统。说白了,就是让开发板和主机之间共享文件。为什么要搞这个?

你想想看,每次修改代码都要重新烧写镜像、重启板子,多浪费时间。用NFS,代码直接放在主机上,板子通过网络挂载,改完就能跑。TFTP则常用于网络引导内核。

2.2.1 TFTP服务器搭建

TFTP(Trivial File Transfer Protocol)很简单,就是用来传文件的。我一般用它来下载内核镜像和设备树。

# 安装TFTP服务器
sudo apt-get install tftpd-hpa

# 配置TFTP目录
sudo mkdir -p /srv/tftp
sudo chmod 777 /srv/tftp

# 编辑配置文件 /etc/default/tftpd-hpa
# 内容如下:
TFTP_USERNAME="tftp"
TFTP_DIRECTORY="/srv/tftp"
TFTP_ADDRESS="0.0.0.0:69"
TFTP_OPTIONS="--secure"

# 重启服务
sudo systemctl restart tftpd-hpa

测试一下:

# 在主机上创建一个测试文件
echo "Hello TFTP" > /srv/tftp/test.txt

# 在板子上用tftp客户端下载
tftp 192.168.1.100 -c get test.txt

注意:TFTP没有认证机制,所以不要暴露在公网上。我一般只在开发用的局域网里用。

2.2.2 NFS服务器搭建

NFS(Network File System)就强大得多了。它允许板子直接挂载主机上的目录,就像访问本地文件一样。

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

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

# 编辑 /etc/exports,添加:
/srv/nfs/rootfs 192.168.1.0/24(rw,sync,no_subtree_check,no_root_squash)

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

在板子上挂载:

# 在板子上执行
mount -t nfs -o nolock 192.168.1.100:/srv/nfs/rootfs /mnt

挂载成功后,你在主机上修改文件,板子上立刻就能看到。这对于调试应用程序和内核模块来说,简直是神器。

关键参数说明

参数含义
rw读写权限
sync同步写入,保证数据一致性
no_subtree_check禁用子树检查,提升性能
no_root_squash允许root用户保留权限,否则板子上root会被映射成nobody

我记得有一次,板子挂载NFS后一直报“Permission denied”。查了半天,发现是no_root_squash没加。板子上的root用户被映射成了普通用户,自然没权限写文件。

2.3 串口终端与调试工具

最后,我们聊聊串口调试。自动驾驶平台通常没有显示器、键盘,串口就是你和板子沟通的唯一通道。

2.3.1 Minicom

Minicom是Linux下最经典的串口工具。我个人习惯用它,轻量、稳定。

# 安装
sudo apt-get install minicom

# 配置
sudo minicom -s

进入配置界面后,设置:

  • 串口设备:/dev/ttyUSB0(根据实际情况调整)
  • 波特率:115200
  • 数据位:8
  • 停止位:1
  • 奇偶校验:无
  • 硬件流控:关闭

保存配置为默认,以后直接运行minicom就行。

小技巧:如果板子没反应,先检查串口线是不是交叉线(Null Modem)。我吃过这个亏,焊了根直连线,折腾了一下午。

2.3.2 Putty

如果你在Windows上开发,Putty是首选。虽然它是个图形工具,但配置思路和Minicom一样。

关键设置:

  • Connection type: Serial
  • Serial line: COM3(根据设备管理器查看)
  • Speed: 115200
  • Flow control: None

配置好后,点击Open就能连上。Putty还有个好处,可以保存session,下次直接双击打开。

2.3.3 调试技巧

串口调试时,我常用这几个命令:

# 查看内核启动日志
dmesg | tail

# 查看系统信息
cat /proc/cpuinfo
cat /proc/meminfo

# 查看网络状态
ifconfig
ping 192.168.1.100

如果板子启动时串口没输出,先检查:

  1. 串口线是否接对(TX接RX,RX接TX)
  2. 波特率是否匹配(常见的是115200或9600)
  3. 板子是否已经上电
  4. U-Boot的串口参数是否配置正确

重要提醒:串口调试时,千万不要带电插拔串口线。我烧过一块板子的串口芯片,就是因为手贱。先断电,再接线,这是铁律。

小结

好了,这一章的内容就到这里。我们搭建了交叉编译环境,配好了TFTP和NFS,还学会了用串口和板子对话。这些工具看起来琐碎,但它们是嵌入式Linux开发的基石。

下一章,我们会把这些工具用起来,真正开始移植U-Boot和内核。到时候你会发现,今天搭的环境,就是明天的效率。

有什么问题,欢迎在群里讨论。我们下章见。