2. 开发环境搭建
说实话,很多同学在算法模型上花了大把时间,结果卡在环境搭建这一步。我见过太多人,模型跑通了,一上嵌入式设备就各种报错。说白了,交叉编译就是「在PC上编译,在ARM上运行」。这章我们就把这事彻底搞定。
本章核心目标:在 x86 宿主机上搭建完整的 ARM 交叉编译环境,完成 OpenCV、MNN、TensorRT 三个关键库的交叉编译,并配置 SSH 远程调试链路。
2.1 交叉编译工具链安装
交叉编译工具链,说白了就是一套能在 x86 上生成 ARM 可执行文件的编译器集合。我个人习惯用 Linaro 提供的 GCC 工具链,稳定且社区活跃。
我的经验:别用太新的 GCC 版本。我曾经在 GCC 11 上踩过坑,某些内联汇编语法变了,导致底层库编译不过。建议用 GCC 9.3 或 10.2,这两个版本我实测最稳。
2.1.1 下载与解压
# 以 aarch64 为例,下载 Linaro GCC 10.2
wget https://releases.linaro.org/components/toolchain/binaries/latest-7/aarch64-linux-gnu/gcc-linaro-7.5.0-2019.12-x86_64_aarch64-linux-gnu.tar.xz
# 解压到 /opt 目录
sudo tar -xvf gcc-linaro-7.5.0-2019.12-x86_64_aarch64-linux-gnu.tar.xz -C /opt/
# 添加环境变量
echo 'export PATH=$PATH:/opt/gcc-linaro-7.5.0-2019.12-x86_64_aarch64-linux-gnu/bin' >> ~/.bashrc
source ~/.bashrc
# 验证安装
aarch64-linux-gnu-gcc --version
2.1.2 工具链组成
| 组件 | 说明 | 常用命令 |
|---|---|---|
| 编译器 | C/C++ 编译器 | aarch64-linux-gnu-gcc / g++ |
| 链接器 | 生成 ARM 可执行文件 | aarch64-linux-gnu-ld |
| 汇编器 | 汇编代码转机器码 | aarch64-linux-gnu-as |
| 库管理器 | 静态库打包 | aarch64-linux-gnu-ar |
| 调试器 | 远程调试用 | aarch64-linux-gnu-gdb |
注意:如果你的目标设备是 32 位 ARM(如 Cortex-A7),工具链前缀是 arm-linux-gnueabihf-,别搞混了。我刚开始就犯过这个错,编译出来的程序在 64 位板子上跑不了。
2.2 OpenCV 交叉编译
OpenCV 是人脸识别的基础库。但嵌入式设备上不能直接用 apt 安装,必须自己交叉编译。嗯,这里要注意几个关键点。
2.2.1 编译脚本
# 下载 OpenCV 4.5.5
wget https://github.com/opencv/opencv/archive/4.5.5.tar.gz
tar -xzf 4.5.5.tar.gz
cd opencv-4.5.5
# 创建编译目录
mkdir build_arm && cd build_arm
# CMake 配置
cmake -DCMAKE_SYSTEM_NAME=Linux \
-DCMAKE_SYSTEM_PROCESSOR=aarch64 \
-DCMAKE_C_COMPILER=aarch64-linux-gnu-gcc \
-DCMAKE_CXX_COMPILER=aarch64-linux-gnu-g++ \
-DCMAKE_INSTALL_PREFIX=/opt/opencv_arm \
-DBUILD_opencv_python2=OFF \
-DBUILD_opencv_python3=OFF \
-DBUILD_TESTS=OFF \
-DBUILD_PERF_TESTS=OFF \
-DWITH_GTK=OFF \
-DWITH_V4L=ON \
-DWITH_JPEG=ON \
-DWITH_PNG=ON \
..
# 编译(建议用 -j4,别贪多)
make -j4
sudo make install
避坑指南:我曾经编译 OpenCV 时忘了关 GTK,结果在 ARM 板子上缺了一堆依赖库。嵌入式设备上 GTK 基本用不到,直接关掉。另外,WITH_V4L 一定要开,摄像头采集全靠它。
2.2.2 验证编译结果
# 检查生成的文件
ls /opt/opencv_arm/lib/
# 应该看到 libopencv_core.so, libopencv_imgproc.so 等
# 查看文件架构
file /opt/opencv_arm/lib/libopencv_core.so
# 输出: ELF 64-bit LSB shared object, ARM aarch64
2.3 MNN 交叉编译
MNN 是阿里巴巴开源的推理框架,对 ARM 优化做得不错。我个人在 RK3588 和树莓派上都用过,性能很稳。
2.3.1 编译步骤
# 克隆 MNN
git clone https://github.com/alibaba/MNN.git
cd MNN
# 创建编译目录
mkdir build_arm && cd build_arm
# CMake 配置
cmake -DCMAKE_SYSTEM_NAME=Linux \
-DCMAKE_SYSTEM_PROCESSOR=aarch64 \
-DCMAKE_C_COMPILER=aarch64-linux-gnu-gcc \
-DCMAKE_CXX_COMPILER=aarch64-linux-gnu-g++ \
-DCMAKE_INSTALL_PREFIX=/opt/mnn_arm \
-DMNN_BUILD_TRAIN=OFF \
-DMNN_BUILD_DEMO=OFF \
-DMNN_BUILD_QUANTOOLS=OFF \
-DMNN_ARM82=ON \
..
make -j4
sudo make install
关键参数说明:MNN_ARM82=ON 开启 ARMv8.2 优化,如果你的芯片支持 FP16 和 DOT 指令(如骁龙 855+、RK3588),推理速度能提升 30% 以上。
2.3.2 常见问题
- 编译报错找不到
pthread:在 CMake 命令后加-DMNN_USE_THREAD_POOL=OFF,改用 MNN 自带的线程池。 - 链接时提示
undefined reference to 'clock_gettime':链接时加-lrt。 - 运行时崩溃:检查目标设备的 GLIBC 版本,MNN 需要 GLIBC 2.27+。
2.4 TensorRT 交叉编译
TensorRT 是 NVIDIA 的推理优化库,只适用于 Jetson 系列设备(如 Jetson Nano、Xavier NX)。注意,TensorRT 的交叉编译和前面两个不太一样。
重要提醒:TensorRT 的交叉编译必须在 Jetson 设备上安装 JetPack SDK,然后在宿主机上使用 NVIDIA 提供的交叉编译工具链。别想着自己从头编译,那会把你逼疯的。
2.4.1 环境准备
| 组件 | 版本要求 | 获取方式 |
|---|---|---|
| JetPack SDK | 4.6+ | NVIDIA 官网下载 |
| 交叉编译工具链 | gcc-linaro-7.3.1 | JetPack 自带 |
| TensorRT | 8.0+ | JetPack 自带 |
| CUDA | 10.2+ | JetPack 自带 |
2.4.2 编译示例
# 设置环境变量(路径根据你的 JetPack 安装位置调整)
export CROSS_COMPILE=/opt/jetpack/toolchain/aarch64--glibc--stable-2022.08-1/bin/aarch64-linux-
export CC=${CROSS_COMPILE}gcc
export CXX=${CROSS_COMPILE}g++
export CUDA_PATH=/opt/jetpack/cuda
export TENSORRT_PATH=/opt/jetpack/tensorrt
# 编译 TensorRT 示例
cd $TENSORRT_PATH/samples
make -j4 TARGET=aarch64
我的经验:TensorRT 的交叉编译最容易出问题的是 CUDA 路径配置。我建议先在 Jetson 设备上跑一遍 trtexec 验证环境,确认没问题了再回宿主机编译。这样能省下大量排查时间。
2.5 SSH 与远程调试配置
环境搭好了,库也编译完了,怎么把东西传到板子上?怎么调试?这就是 SSH 和远程调试的事了。
2.5.1 SSH 连接配置
# 宿主机生成密钥(免密登录)
ssh-keygen -t rsa -b 4096
ssh-copy-id root@192.168.1.100 # 替换为你的板子 IP
# 测试连接
ssh root@192.168.1.100
# SCP 传输编译好的库
scp -r /opt/opencv_arm/lib/* root@192.168.1.100:/usr/lib/
2.5.2 远程调试配置
远程调试的核心思路:宿主机运行 GDB,目标设备运行 gdbserver。
# 目标设备上启动 gdbserver
gdbserver :2345 ./face_recognition
# 宿主机上连接调试
aarch64-linux-gnu-gdb ./face_recognition
(gdb) target remote 192.168.1.100:2345
(gdb) continue
调试技巧:如果程序崩溃,用 bt 命令查看调用栈。我遇到过很多次段错误,都是因为交叉编译时指针大小不一致导致的。用 print sizeof(void*) 确认一下,ARM 64 位应该是 8 字节。
2.5.3 常见网络问题排查
- SSH 连不上:先 ping 一下,确认网络通。然后检查板子上
sshd服务是否启动。 - SCP 传输慢:用
rsync -P替代,支持断点续传。 - gdbserver 启动失败:检查端口是否被占用,或者用
netstat -tlnp查看。 - 调试时符号表找不到:编译时加
-g -O0,别优化掉调试信息。
避坑指南:我曾经在调试时发现变量值全是 ???,折腾了半天才发现是编译时用了 -O2 优化,变量被优化掉了。调试阶段一定用 -O0,发布时再开优化。
2.6 环境验证清单
最后,给你一个自检清单。每完成一步就打个勾,确保环境没问题再往下走。
| 步骤 | 验证命令 | 预期结果 |
|---|---|---|
| 工具链安装 | aarch64-linux-gnu-gcc --version |
显示版本号 |
| OpenCV 编译 | file libopencv_core.so |
ELF 64-bit ARM aarch64 |
| MNN 编译 | file libMNN.so |
ELF 64-bit ARM aarch64 |
| TensorRT 编译 | file trtexec |
ELF 64-bit ARM aarch64 |
| SSH 连接 | ssh root@板子IP |
登录成功 |
| 远程调试 | gdbserver :2345 test |
Listening on port 2345 |
环境搭建这一步,说白了就是「一次配置,多次受益」。刚开始可能会觉得繁琐,但等你跑通第一个 demo 时,会发现前面所有的折腾都值了。嗯,接下来你就可以放心地进入模型转换和部署环节了。