2. 开发环境搭建:交叉编译工具链安装、嵌入式Linux系统构建、SSH与NFS服务配置

好,咱们正式开始动手了。这一章,说白了就是给HUD软件开发搭个“窝”。你想想看,HUD的硬件资源有限,不可能在上面直接写代码、编译代码。我们得在强大的PC上干活,然后把编译好的程序丢到嵌入式板子上跑。这个流程,就叫交叉编译。

我个人习惯把开发环境分成三块:交叉编译工具链嵌入式Linux系统、以及网络调试服务。这三块搞定了,后面写代码、调试、集成才会顺畅。咱们一个一个来。

2.1 交叉编译工具链安装

什么是交叉编译工具链?说白了,就是一套能在你的x86电脑上,生成ARM架构可执行文件的编译器、链接器、库文件集合。我刚开始做嵌入式时,总觉得这东西很神秘,后来发现它就是一套定制化的GCC工具。

对于HUD项目,我建议使用Linaro GCC或者ARM官方的GNU工具链。这里以ARM Cortex-A系列为例,我们选择gcc-arm-9.2-2019.12-x86_64-arm-none-linux-gnueabihf这个版本。

核心要点:工具链版本必须与你的Linux内核版本、glibc版本匹配。否则编译出来的程序跑不起来,或者跑起来就段错误。

安装步骤其实很简单,解压、配置环境变量就行。

# 下载工具链(假设放在 /opt 目录下)
wget https://developer.arm.com/-/media/Files/downloads/gnu-a/9.2-2019.12/binrel/gcc-arm-9.2-2019.12-x86_64-arm-none-linux-gnueabihf.tar.xz

# 解压
sudo tar -xvf gcc-arm-9.2-2019.12-x86_64-arm-none-linux-gnueabihf.tar.xz -C /opt/

# 配置环境变量(建议写入 ~/.bashrc 或 /etc/profile)
export PATH=$PATH:/opt/gcc-arm-9.2-2019.12-x86_64-arm-none-linux-gnueabihf/bin
export CROSS_COMPILE=arm-none-linux-gnueabihf-
export ARCH=arm

我的小技巧:我个人习惯把工具链路径单独写一个脚本文件,比如 setenv.sh,每次打开新终端时 source 一下。这样不会污染全局环境,也方便切换不同项目。

验证是否安装成功,跑一下这个命令:

arm-none-linux-gnueabihf-gcc --version

如果能看到版本信息,恭喜你,第一步搞定了。

嗯,这里要注意:不要用系统自带的gcc去编译嵌入式程序。我见过有人图省事,直接用PC的gcc编译,然后丢到板子上,结果报错“无法执行二进制文件”。这就像把汽油加进柴油车,肯定跑不动。

2.2 嵌入式Linux系统构建

有了工具链,接下来要构建一个能在HUD硬件上运行的Linux系统。这个系统包含三要素:Bootloader(引导加载程序)、Kernel(内核)、Rootfs(根文件系统)。

对于HUD这种资源受限的嵌入式设备,我推荐使用Buildroot或者Yocto。Buildroot更轻量、上手快,适合我们这种需要快速迭代的项目。Yocto功能更强大,但学习曲线陡峭,适合大规模量产。

这里我用Buildroot演示,因为它够用、够快。

2.2.1 获取Buildroot并配置

# 下载Buildroot(我习惯用长期支持版本)
wget https://buildroot.org/downloads/buildroot-2023.02.tar.gz
tar -xvf buildroot-2023.02.tar.gz
cd buildroot-2023.02

# 配置目标平台(以树莓派3为例,HUD硬件类似)
make raspberrypi3_defconfig

# 进入菜单配置界面
make menuconfig

在menuconfig里,你需要关注几个关键选项:

配置项 推荐值 说明
Target Architecture ARM (little endian) HUD常用ARM架构
Target Architecture Variant cortex-a7 / cortex-a53 根据具体芯片选择
Toolchain type External toolchain 使用我们刚才安装的工具链
System configuration Enable root login with password 设置root密码,方便调试
Target packages openssh, nfs-utils, gdb 调试必备工具

我曾经踩过的坑:有一次我忘了配置外部工具链路径,Buildroot自己下载了一个。结果编译出来的glibc版本和我的应用不匹配,程序跑起来就崩溃。排查了整整一天。所以,一定要在Buildroot配置中明确指定外部工具链路径

2.2.2 编译系统

配置完成后,开始编译。这个过程比较耗时,第一次编译可能需要半小时到一小时。

# 开始编译(-j参数根据CPU核心数调整)
make -j4

编译完成后,在 output/images/ 目录下会生成以下文件:

  • zImage — 压缩后的内核镜像
  • rootfs.ext4 — 根文件系统镜像
  • *.dtb — 设备树文件(硬件描述)
  • boot.vfat — 启动分区

把这些文件烧录到SD卡或eMMC中,你的HUD硬件就能启动Linux了。

2.3 SSH与NFS服务配置

系统能跑起来了,但怎么跟它交互?怎么把编译好的程序传上去?这就是SSH和NFS的用武之地。

2.3.1 SSH服务配置

SSH是远程登录的标配。在Buildroot配置中,我们已经勾选了openssh。系统启动后,需要做以下配置:

# 在HUD板子上执行
# 启动SSH服务
/etc/init.d/S50sshd start

# 设置开机自启
update-rc.d sshd defaults

# 查看IP地址
ifconfig eth0

然后在PC上就可以通过SSH登录了:

ssh root@192.168.1.100

我的经验:如果SSH连不上,先ping一下看网络通不通。很多时候是IP地址没配好,或者网线没插紧。别问我怎么知道的...有一次我在实验室折腾了半小时,结果发现交换机电源没开。

2.3.2 NFS服务配置

NFS(网络文件系统)是嵌入式开发的利器。它允许你把PC上的一个目录挂载到HUD板子上,这样你编译好的程序直接就能在板子上运行,省去了反复拷贝的麻烦。

第一步:在PC上配置NFS服务器

# 安装NFS服务器(Ubuntu/Debian)
sudo apt-get install nfs-kernel-server

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

# 配置导出文件
sudo vim /etc/exports
# 添加以下内容:
/srv/nfs/hud *(rw,sync,no_subtree_check,no_root_squash)

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

第二步:在HUD板子上挂载NFS

# 在HUD板子上执行
# 创建挂载点
mkdir -p /mnt/nfs

# 挂载(假设PC IP为192.168.1.10)
mount -t nfs -o nolock 192.168.1.10:/srv/nfs/hud /mnt/nfs

# 验证
ls /mnt/nfs

如果能看到PC上的文件,说明NFS配置成功了。

为什么推荐NFS?因为开发HUD软件时,你需要频繁修改代码、重新编译、测试。用NFS的话,在PC上编译完,直接在板子上运行,整个过程不到10秒。如果用U盘拷贝,每次都要插拔,效率太低了。

2.4 避坑指南与总结

搭建开发环境时,有几个坑我替你们踩过了:

  • 工具链版本不匹配:我曾经用gcc 8.x编译的程序,在gcc 7.x的库上跑,结果报错“GLIBC_2.28 not found”。解决方案是保持工具链和系统库版本一致。
  • NFS权限问题:如果挂载后只有只读权限,检查 /etc/exports 中的 no_root_squash 选项是否加了。不加的话,root用户会被映射成nobody,权限不够。
  • SSH密钥认证失败:第一次连接时,如果板子上的SSH密钥是新的,PC会提示“Host key verification failed”。删掉 ~/.ssh/known_hosts 中对应的旧记录就行。

好了,环境搭建就到这里。你现在应该有了一个可以编译、运行、调试的完整开发环境。下一章,我们会开始写HUD的显示驱动代码。到时候,你就可以用这套环境,一边编译一边测试了。

记住一句话:环境搭得好,开发没烦恼。别嫌这一步麻烦,后面你会感谢现在认真搭环境的自己。