3、开发环境搭建:Linux开发环境配置(Ubuntu 22.04)、交叉编译工具链安装、QEMU模拟器与硬件开发板准备
说实话,做域控制器中间件开发,环境搭建是第一道坎。很多人觉得这步简单,随便装个虚拟机就开始搞。但我见过太多人因为环境没配好,后面调试时浪费大量时间。今天我就把这块掰开揉碎了讲清楚。
3.1 Ubuntu 22.04 开发环境配置
我个人习惯用 Ubuntu 22.04 LTS 作为宿主机。为什么选这个版本?因为它的软件包更新、社区支持都很好,而且跟 ARM 交叉编译链的兼容性最稳定。
基础依赖安装
先把基础工具链装上。别嫌多,后面编译内核、调试程序都用得上:
sudo apt update
sudo apt install -y build-essential git vim cmake
sudo apt install -y libncurses5-dev libssl-dev
sudo apt install -y flex bison libelf-dev
sudo apt install -y qemu-system-arm qemu-user-static
sudo apt install -y gcc-arm-linux-gnueabihf g++-arm-linux-gnueabihf
嗯,这里要注意:libncurses5-dev 和 libssl-dev 是编译 Linux 内核时必须的。我刚开始做的时候漏装了 libssl-dev,结果内核配置界面死活出不来,折腾了半天才发现是这个问题。
配置 SSH 与 VNC 远程开发
实际项目中,开发板通常不在你手边。我建议提前配好 SSH 和 VNC:
sudo apt install -y openssh-server x11vnc
sudo systemctl enable ssh
sudo systemctl start ssh
为什么要配 VNC?因为有些开发板没有显示器接口,或者你想在远程桌面里调试图形界面。我在一个车载项目中,开发板放在实验室机柜里,全靠 VNC 连上去看日志。
~/.bashrc 里加上交叉编译链的路径,省得每次都要 export:
echo 'export PATH=$PATH:/usr/bin' >> ~/.bashrc
source ~/.bashrc
3.2 交叉编译工具链安装
说白了,交叉编译就是在 x86 的电脑上编译出 ARM 架构能跑的程序。你想想看,域控制器里用的芯片大多是 ARM Cortex-A 系列,比如 NXP i.MX8、TI TDA4 这些,你的笔记本是 x86 架构,不交叉编译根本跑不了。
选择工具链
我推荐两种方式:
- Linaro 官方工具链:稳定、通用,适合大多数项目
- 芯片厂商提供的 SDK:比如 NXP 的 Yocto BSP,里面自带工具链
这里我以 Linaro 的 gcc-arm-linux-gnueabihf 为例:
# 下载 Linaro 工具链
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 -xvf gcc-linaro-7.5.0-2019.12-x86_64_arm-linux-gnueabihf.tar.xz -C /opt/
# 配置环境变量
export PATH=/opt/gcc-linaro-7.5.0-2019.12-x86_64_arm-linux-gnueabihf/bin:$PATH
验证工具链
装完一定要验证一下:
arm-linux-gnueabihf-gcc --version
arm-linux-gnueabihf-gcc -v 2>&1 | grep Target
如果输出显示 Target: arm-linux-gnueabihf,那就对了。
Illegal instruction。后来才发现工具链的架构跟板子不匹配。所以一定要确认你的开发板是 armv7 还是 armv8,是硬浮点还是软浮点。
测试编译
写个简单的 Hello World 测试一下:
// hello.c
#include <stdio.h>
int main() {
printf("Hello from Domain Controller!\n");
return 0;
}
// 编译
arm-linux-gnueabihf-gcc -o hello hello.c
// 查看文件信息
file hello
// 输出: ELF 32-bit LSB executable, ARM, EABI5 version 1 (SYSV)
3.3 QEMU 模拟器与硬件开发板准备
QEMU 这东西,说白了就是个软件模拟的 ARM 开发板。为什么需要它?因为硬件开发板不是随时都有的。我记得有一次项目赶进度,开发板还在海关清关,我就先用 QEMU 把中间件框架搭起来了,等板子到了直接烧录验证,省了整整两周时间。
安装 QEMU
前面已经装过了,这里再确认一下:
qemu-system-arm --version
qemu-arm --version
用 QEMU 模拟一个 ARM 开发板
我常用 QEMU 模拟 vexpress-a9 开发板,它跟很多域控制器用的 Cortex-A9 架构一致:
# 下载内核和设备树
wget https://releases.linaro.org/components/kernel/uefi-linaro/latest/vexpress64/Image
wget https://releases.linaro.org/components/kernel/uefi-linaro/latest/vexpress64/vexpress-v2p-ca15-tc1.dtb
# 启动 QEMU
qemu-system-arm -M vexpress-a9 \
-kernel vmlinuz-3.2.0-vexpress \
-dtb vexpress-v2p-ca9.dtb \
-append "console=ttyAMA0 root=/dev/mmcblk0" \
-sd rootfs.ext3 \
-nographic
启动后你会看到一个 ARM Linux 的终端。这时候你可以用交叉编译好的程序测试:
# 在宿主机上编译
arm-linux-gnueabihf-gcc -static -o hello_qemu hello.c
# 用 QEMU 用户模式运行
qemu-arm hello_qemu
- 系统模式(-M):模拟整个开发板,可以跑完整的 Linux 系统
- 用户模式(qemu-arm):只模拟 CPU,直接运行单个 ARM 程序
硬件开发板准备
以 NXP i.MX8M Mini 开发板为例,你需要准备:
- 硬件清单:开发板、12V 电源、USB 转串口线、网线、SD 卡(16GB 以上)
- 烧录工具:
uuu(NXP 的烧录工具)或dd命令 - 串口调试:
screen /dev/ttyUSB0 115200
烧录系统镜像的典型步骤:
# 下载 NXP 官方 BSP
wget https://www.nxp.com/lgfiles/updates/L5.10.72_2.2.0_images_MX8MMEVK.zip
# 解压并烧录到 SD 卡
sudo dd if=imx-boot-imx8mm-evk-sd.bin-flash_evk of=/dev/sdb bs=1k seek=1 conv=fsync
# 插入 SD 卡,上电启动
# 用串口查看启动日志
screen /dev/ttyUSB0 115200
/dev/sdb 是你的 SD 卡,不是硬盘!我曾经手滑把公司的服务器硬盘给写了,那叫一个酸爽。建议先用 lsblk 查看设备列表,拔插 SD 卡确认设备名。
3.4 环境验证:跑一个完整的中间件示例
环境搭好了,我们来验证一下整个链路是否通畅。写一个简单的 DDS(数据分发服务)发布订阅程序:
// publisher.c
#include <stdio.h>
#include <unistd.h>
int main() {
int count = 0;
while (1) {
printf("Publishing: sensor_data_%d\n", count++);
sleep(1);
}
return 0;
}
// 交叉编译
arm-linux-gnueabihf-gcc -static -o publisher publisher.c
// 在 QEMU 中运行
qemu-arm ./publisher
如果能看到每秒打印一条消息,说明你的交叉编译链和 QEMU 环境都正常工作了。
3.5 本章知识体系
下面这张图总结了开发环境搭建的核心逻辑:
环境搭建这件事,说白了就是打通「开发-编译-运行」这条链路。你想想看,如果宿主机、工具链、目标平台这三者有一个环节没配好,后面写再多代码也跑不起来。我建议你按照上面的步骤一步步来,每完成一步就验证一下,别一口气装完再调试,那样出了问题很难定位。
- Ubuntu 22.04 装好基础依赖和远程开发工具
- 交叉编译链选对架构版本,验证能编译出 ARM 可执行文件
- QEMU 用来在没有硬件时做前期开发验证
- 硬件开发板准备好烧录工具和串口调试
- 最后用一个小程序跑通全链路
好了,环境搭好了,后面我们就可以正式开始写中间件代码了。