2. 开发环境搭建:交叉编译工具链安装、OpenCV/MNN/TensorRT库的交叉编译、SSH与远程调试配置

说实话,很多同学在算法模型上花了大把时间,结果卡在环境搭建这一步。我见过太多人,模型跑通了,一上嵌入式设备就各种报错。说白了,交叉编译就是「在PC上编译,在ARM上运行」。这章我们就把这事彻底搞定。

本章核心目标:在 x86 宿主机上搭建完整的 ARM 交叉编译环境,完成 OpenCV、MNN、TensorRT 三个关键库的交叉编译,并配置 SSH 远程调试链路。

嵌入式人脸识别部署环境搭建全景 x86 宿主机 (Ubuntu 20.04) 交叉编译工具链 OpenCV / MNN / TensorRT ARM 目标设备 SSH / SCP 传输 远程调试 (gdbserver) 关键流程 ① 宿主机安装交叉编译工具链 ② 交叉编译 OpenCV / MNN / TensorRT ③ SCP 传输到目标设备 + 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 时,会发现前面所有的折腾都值了。嗯,接下来你就可以放心地进入模型转换和部署环节了。