开发环境搭建:工欲善其事,必先利其器

做嵌入式Linux开发,第一关就是搭环境。我见过太多新手卡在这一步,折腾几天连个Hello World都跑不起来。说白了,环境没搭好,后面全是坑。这一章咱们就把Ubuntu虚拟机、交叉编译工具链、TFTP/NFS服务、串口终端这些基础工具一次性搞定。

本章核心目标: 搭建一套可复用的嵌入式开发环境,确保宿主机(Ubuntu)能与目标板(ARM开发板)正常通信、传输文件、调试程序。

2.1 Ubuntu虚拟机安装

我个人习惯用VMware Workstation,当然VirtualBox也行。选哪个不重要,关键是版本要对。我建议用Ubuntu 20.04 LTS或22.04 LTS,这两个版本社区支持好,软件包全,遇到问题容易搜到答案。

安装时注意几点:

  • 磁盘空间: 至少分配80GB,别抠门。交叉编译工具链、内核源码、文件系统镜像,随便一放就是几十G。
  • 内存: 4GB起步,8GB更舒服。编译内核时内存不够会直接OOM(Out Of Memory),我吃过这个亏。
  • CPU核心: 给2-4核,编译能快不少。
  • 网络模式: 选桥接模式,这样开发板和虚拟机能在同一网段,方便后续NFS和TFTP通信。
小技巧: 安装完Ubuntu后,先执行 sudo apt update && sudo apt upgrade -y 把系统更新到最新。然后装个 build-essential 和 vim,这是最基本的开发工具包。

2.2 交叉编译工具链配置

交叉编译,说白了就是在x86的电脑上编译出ARM架构能跑的二进制文件。你想想看,开发板那点算力,编译个Linux内核得等到猴年马月?所以必须在PC上搞定。

工具链的选择,我推荐两种:

类型 来源 适用场景
Linaro GCC 官方发布包 通用ARM Cortex-A系列,社区支持好
Buildroot / Yocto 源码构建 定制化需求,需要精确控制库版本

这里我以Linaro GCC 7.5.0为例,演示安装步骤:

# 下载工具链
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/

# 配置环境变量(写入 ~/.bashrc)
export PATH=/opt/gcc-linaro-7.5.0-2019.12-x86_64_arm-linux-gnueabihf/bin:$PATH
export ARCH=arm
export CROSS_COMPILE=arm-linux-gnueabihf-

# 使环境变量生效
source ~/.bashrc

# 验证安装
arm-linux-gnueabihf-gcc --version
避坑指南: 我曾经在64位Ubuntu上装32位工具链,结果死活跑不起来。后来发现缺了32位库,执行 sudo apt install lib32z1 lib32ncurses5 才解决。另外,环境变量一定要写到 ~/.bashrc 里,别只写在当前终端,否则新开窗口又得重新配。

2.3 TFTP/NFS服务搭建

这两个服务是嵌入式开发的「快递员」。TFTP负责把内核、设备树文件传给开发板,NFS则让开发板直接挂载PC上的文件系统,方便调试。

2.3.1 TFTP服务

TFTP简单粗暴,适合传小文件。配置步骤如下:

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

# 创建TFTP根目录
sudo mkdir -p /tftpboot
sudo chmod 777 /tftpboot

# 修改配置文件 /etc/default/tftpd-hpa
TFTP_USERNAME="tftp"
TFTP_DIRECTORY="/tftpboot"
TFTP_ADDRESS="0.0.0.0:69"
TFTP_OPTIONS="-l -c -s"

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

测试方法:在 /tftpboot 下放个文件,然后在开发板uboot里执行 tftp 0x82000000 zImage,能下载成功就说明通了。

2.3.2 NFS服务

NFS比TFTP高级,开发板可以直接读写PC上的文件,调试应用程序时特别方便。我习惯把根文件系统放在NFS共享目录里,开发板启动时直接挂载。

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

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

# 编辑 /etc/exports,添加共享配置
/srv/nfs/rootfs *(rw,sync,no_subtree_check,no_root_squash)

# 重启NFS服务
sudo systemctl restart nfs-kernel-server
sudo exportfs -av
注意: no_root_squash 这个参数很重要。不加的话,开发板上的root用户会被映射成nobody,写文件时权限会出问题。我在项目里遇到过,排查了半天才发现是这儿的坑。

2.4 串口终端工具使用

串口是嵌入式开发者的「眼睛」。开发板没网口、没显示器的时候,全靠串口看启动日志、敲命令。我常用的工具有三个:

工具 特点 推荐场景
minicom 经典、稳定、配置稍复杂 日常调试,习惯命令行
screen 轻量、无需配置 快速连接,临时用一下
MobaXterm 图形化、支持多标签 Windows用户,功能全面

这里我重点讲minicom,因为它是Linux下最正统的串口工具:

# 安装minicom
sudo apt install minicom

# 首次配置
sudo minicom -s

# 进入配置菜单后,选择 "Serial port setup"
# 关键参数设置:
# A - Serial Device: /dev/ttyUSB0 (根据实际设备修改)
# B - Lockfile Location: /var/lock
# E - Bps/Par/Bits: 115200 8N1
# F - Hardware Flow Control: No
# G - Software Flow Control: No

# 保存为默认配置
# 选择 "Save setup as dfl"

# 启动连接
sudo minicom
常见问题: 连不上串口时,先检查 ls -l /dev/ttyUSB* 看设备是否存在。如果权限不够,把当前用户加到dialout组:sudo usermod -a -G dialout $USER,然后注销重新登录。我曾经忘了加组,折腾了半小时才发现是权限问题。

2.5 整体环境验证

所有服务搭好后,我习惯画一张图来理清它们之间的关系。你看下面这张图就明白了:

嵌入式开发环境架构图 嵌入式Linux开发环境架构图 宿主机(Ubuntu 20.04 LTS) 交叉编译工具链 arm-linux-gnueabihf-gcc TFTP服务 /tftpboot → 内核/设备树 NFS服务 /srv/nfs/rootfs → 根文件系统 串口终端(minicom) 目标板(ARM Cortex-A7) U-Boot引导程序 tftp 0x82000000 zImage Linux内核 zImage + 设备树 根文件系统 NFS挂载 /srv/nfs/rootfs 串口调试输出 TFTP传输 NFS挂载 串口线(RS-232) 宿主机通过TFTP传内核、NFS挂载文件系统、串口查看调试信息,三者协同工作

从这张图能看出来,整个环境是分层协作的:

  • 编译阶段: 在宿主机上用交叉编译工具链生成内核、设备树、应用程序
  • 传输阶段: TFTP把内核和设备树传给开发板,NFS提供文件系统
  • 调试阶段: 串口终端实时查看启动日志,发现问题随时修改
验证清单: 环境搭好后,按这个列表逐项检查,确保万无一失。
  1. 交叉编译工具链能正常编译Hello World
  2. 开发板通过TFTP能下载内核镜像
  3. 开发板通过NFS能挂载根文件系统
  4. 串口终端能正常显示uboot和内核启动日志

嗯,到这里开发环境就全部就绪了。这些工具看着琐碎,但每一个都是后面章节的基础。你花半天时间把环境搭扎实,后面编译内核、移植驱动时会顺畅得多。我当年第一次搭环境时也踩了不少坑,但一旦跑通了,那种成就感还是很爽的。