Linux下编译并打包MNN项目迁移至其他设备

1. 构建项目结构

该项目是利用MNN框架对MTCNN网络进行推理,实现对目标的实时检测

运行环境:Linux

相关库:opencv,MNN

先给出项目的总体结构,如下:

bash 复制代码
mtcnn_mnn/
├── include/
│   ├── opencv2/              # OpenCV 的头文件
│   ├── MNN/                  # MNN 的头文件
│   └── mtcnn.h               # 项目内部的头文件
├── lib/
│   ├── libopencv_core.so     # OpenCV 的动态库
│   ├── libopencv_imgproc.so
│   ├── libopencv_highgui.so
│   ├── libopencv_videoio.so
│   ├── libopencv_imgcodecs.so
│   └── libMNN.so             # MNN 的动态库
├── src/                      # 项目源文件
│   ├── main.cpp
│   └── mtcnn.cpp
├── Makefile
└── detection                 # 生成的可执行文件

接下来我们将逐一进行构建

如果需要将项目迁移到其他 Linux 设备上运行,必须确保以下内容被正确迁移:

(1) 头文件

① OpenCV 的头文件

路径:/home/opencv-4.10.0/build_shared/include/opencv4/opencv2/

需要复制整个 opencv2 文件夹到项目的 include/ 目录下:

bash 复制代码
cp -r /home/opencv-4.10.0/build_shared/include/opencv4/opencv2 ./include/

② MNN 的头文件

路径:/home/MNN/build_shared/include/MNN/

需要复制整个 MNN 文件夹到项目的 include/ 目录下:

bash 复制代码
cp -r /home/MNN/build_shared/include/MNN ./include/

③ 项目内部头文件

确保项目的 include/ 目录中的头文件已经存在。

(2) 动态库文件

① OpenCV 的动态库

路径:/home/opencv-4.10.0/build_shared/lib/

需要复制以下文件到项目的 lib/ 目录下:

bash 复制代码
mkdir -p ./lib
cp /home/opencv-4.10.0/build_shared/lib/libopencv_core.so* ./lib/
cp /home/opencv-4.10.0/build_shared/lib/libopencv_imgproc.so* ./lib/
cp /home/opencv-4.10.0/build_shared/lib/libopencv_highgui.so* ./lib/
cp /home/opencv-4.10.0/build_shared/lib/libopencv_videoio.so* ./lib/
cp /home/opencv-4.10.0/build_shared/lib/libopencv_imgcodecs.so* ./lib/

② MNN 的动态库

路径:/home/MNN/build_shared/lib/

需要复制以下文件到项目的 lib/ 目录下:

bash 复制代码
cp /home/MNN/build_shared/lib/libMNN.so* ./lib/

2. 编写Makefile文件(动态链接库版本)

makefile 文件如下:

bash 复制代码
# 编译器
CXX = g++

# 编译选项
CXXFLAGS = -Wall -I./include -O2

# OpenCV 的头文件和库文件路径
OPENCV_INCLUDE_DIR = /home/mtcnn_mnn/include
OPENCV_LIB_DIR = /home/mtcnn_mnn/lib

# MNN 的头文件和库文件路径
MNN_CFLAGS = -I/home/mtcnn_mnn/include  
MNN_LIBS = -L/home/mtcnn_mnn/lib -lMNN  

# 目标可执行文件名
TARGET = detection

# 源文件目录
SRCDIR = src

# 头文件目录
INCDIR = include

# 链接库路径
OPENCV_LIBS = -L$(OPENCV_LIB_DIR) -lopencv_core -lopencv_imgproc -lopencv_highgui -lopencv_videoio -lopencv_imgcodecs

# 找到所有源文件
SOURCES := $(wildcard $(SRCDIR)/*.cpp)

# 生成目标文件列表
OBJECTS := $(patsubst $(SRCDIR)/%.cpp, %.o, $(SOURCES))

# 默认目标
all: $(TARGET)

# 链接目标文件生成可执行文件
$(TARGET): $(OBJECTS)
	$(CXX) $(CXXFLAGS) $^ -o $@ $(OPENCV_LIBS) $(MNN_LIBS) -lpthread -ldl -lgomp -Wl,-rpath,'$$ORIGIN/lib' 
  # 设置动态库的运行时搜索路径为当前目录下的 lib 文件夹

# 规则:从源文件生成目标文件
%.o: $(SRCDIR)/%.cpp
	$(CXX) $(CXXFLAGS) \
	-I$(OPENCV_INCLUDE_DIR) \
	-I$(INCDIR) \
	$(MNN_CFLAGS) \
	-c $< -o $@

# 清理生成的文件
clean:
	rm -f $(OBJECTS) $(TARGET)

.PHONY: all clean

关键语句说明:

① 使用动态库

  • 配置 OpenCV 和 MNN 的动态库:

    复制代码
    OPENCV_LIBS = -L$(OPENCV_LIB_DIR) -lopencv_core -lopencv_imgproc -lopencv_highgui -lopencv_videoio -lopencv_imgcodecs
    MNN_LIBS = -L$(MNN_LIB_DIR) -lMNN
  • -L 指定动态库的路径。

  • -l 指定动态库的名称(去掉 lib 前缀和 .so 后缀)。

② 设置动态库的运行时路径

  • 添加 -Wl,-rpath,'$$ORIGIN/lib' 选项,告诉运行时加载器在当前目录的 lib/ 文件夹中查找动态库。
  • $$ORIGIN 是一个特殊的变量,表示可执行文件所在的目录。

**3.**编译工程

构建完所有项目所需的文件后,开始编译工程

bash 复制代码
make

4. 在新设备上运行

将整个项目文件夹拷贝到新设备。

确保新设备上有以下依赖项:

libstdc++.so(通常预装在大多数 Linux 系统中)。

libpthread.solibdl.so 等系统库(通常也预装)。

在新设备上运行可执行文件:

bash 复制代码
./detection

常见运行问题如下:

① 权限问题

bash 复制代码
-bash: ./detection: Permission denied

首先查看 detection 文件的权限

bash 复制代码
ls -l detection

如果显示如下:

bash 复制代码
-rw-rw-r-- 1 root root 67256  4月 26 14:39 detection

说明缺少执行权限,因此需要增加执行权限,运行以下命令:

bash 复制代码
chmod +x detection

再次查看 detection 文件的权限,变更为:

bash 复制代码
-rwxrwxr-x 1 root root 67256  4月 26 14:39 detection

再次运行可执行文件:

bash 复制代码
./detection

② 动态库路径设置问题

如果出现类似以下错误

bash 复制代码
./detection: error while loading shared libraries: libopencv_imgcodecs.so.410: cannot open shared object file: No such file or directory

首先查看工程下的 lib 中是否有该文件

bash 复制代码
ls -l /home/mtcnn_mnn/lib/libopencv_imgcodecs.so.410

如果输出如下,说明文件存在,那就是运行时动态库路径未设置

bash 复制代码
-rw-rw-r-- 1 root root 2238336  4月 26 15:03 /home/mtcnn_mnn/lib/libopencv_imgcodecs.so.410

使用 LD_LIBRARY_PATH 环境变量

在运行程序之前,设置 LD_LIBRARY_PATH 环境变量,指向包含动态库的目录:

bash 复制代码
export LD_LIBRARY_PATH=export LD_LIBRARY_PATH=/home/mtcnn_mnn/lib:$LD_LIBRARY_PATH 

如果你希望永久设置该变量,可以将其添加到 ~/.bashrc~/.bash_profile 文件中:

bash 复制代码
echo 'export LD_LIBRARY_PATH=export LD_LIBRARY_PATH=/home/mtcnn_mnn/lib:$LD_LIBRARY_PATH' >> ~/.bashrc
source ~/.bashrc

③ 动态库缺失问题

如果出现类似以下错误

bash 复制代码
./detection: error while loading shared libraries: libdc1394.so.22: cannot open shared object file: No such file or directory

同样,首先查看工程下的 lib 中是否有该文件

bash 复制代码
ls -l /home/mtcnn_mnn/lib/libdc1394.so.22

如果输出如下,说明文件不存在

bash 复制代码
ls: cannot access '/home/mtcnn_mnn/lib/libdc1394.so.22': No such file or directory

运行以下命令,检查动态库是否正确加载:

bash 复制代码
ldd ./detection

如果出现如下情况:

bash 复制代码
libopencv_imgcodecs.so.410 => /home/mtcnn_mnn/lib/libopencv_imgcodecs.so.410 (0x00007f6287a00000)
libdc1394.so.22 => not found
libavcodec.so.58 => /lib/x86_64-linux-gnu/libavcodec.so.58 (0x00007f6286400000)
libavformat.so.58 => /lib/x86_64-linux-gnu/libavformat.so.58 (0x00007f6286000000)
libavutil.so.56 => /lib/x86_64-linux-gnu/libavutil.so.56 (0x00007f6285c00000)
libswscale.so.5 => /lib/x86_64-linux-gnu/libswscale.so.5 (0x00007f6288d62000)
libmvec.so.1 => /lib/x86_64-linux-gnu/libmvec.so.1 (0x00007f6288c65000)
/lib64/ld-linux-x86-64.so.2 (0x00007f628bbd0000)
libopenblas.so.0 => /lib/x86_64-linux-gnu/libopenblas.so.0 (0x00007f62837b0000)
libgfortran.so.5 => /lib/x86_64-linux-gnu/libgfortran.so.5 (0x00007f6283400000)
libatlas.so.3 => /lib/x86_64-linux-gnu/libatlas.so.3 (0x00007f6283000000)
libjpeg.so.8 => /lib/x86_64-linux-gnu/libjpeg.so.8 (0x00007f628897f000)
libwebp.so.6 => not found
libpng16.so.16 => /lib/x86_64-linux-gnu/libpng16.so.16 (0x00007f628acd8000)

说明存在未加载成功的动态库

bash 复制代码
libdc1394.so.22 => not found
libwebp.so.6 => not found

此时需要回到最初编译成功的机器上寻找在新设备上缺失的动态库

bash 复制代码
ls -l /usr/lib/x86_64-linux-gnu/libdc1394.so*

输出以下内容:

bash 复制代码
lrwxrwxrwx 1 root root     19 Sep 12  2019 /usr/lib/x86_64-linux-gnu/libdc1394.so -> libdc1394.so.22.2.1
lrwxrwxrwx 1 root root     19 Sep 12  2019 /usr/lib/x86_64-linux-gnu/libdc1394.so.22 -> libdc1394.so.22.2.1
-rw-r--r-- 1 root root 225328 Sep 12  2019 /usr/lib/x86_64-linux-gnu/libdc1394.so.22.2.1

缺失的是 libdc1394.so.22,该文件为一个符号链接,它指向 libdc1394.so.22.2.1,因此要同时复制这两个文件到工程的lib文件下

bash 复制代码
cp /usr/lib/x86_64-linux-gnu/libdc1394.so.22 ./lib/
cp /usr/lib/x86_64-linux-gnu/libdc1394.so.22.2.1 ./lib/

对于缺失的 libwebp.so.6 文件,重复以上操作即可。

最后将完整的工程文件拷贝到新机器上,再次检查动态库是否正确加载:

bash 复制代码
ldd ./detection

输出应显示所有动态库都已找到。


5. 注意事项

(1) 确保动态库版本一致

如果新设备上的系统库与旧设备不一致,可能会导致运行时错误。建议使用相同版本的 OpenCV 和 MNN 库。

(2) 权限问题

确保动态库文件具有正确的权限:

bash 复制代码
chmod +x ./lib/*.so
相关推荐
FoldWinCard19 小时前
D5 Linux 网络及端口命令
linux·运维·服务器
零涂毕业设计21 小时前
毕业设计模块开发-OLED显示屏(IIC协议0.96寸)STM32 ESP32 FPGA Linux驱动免费分享
linux·stm32·单片机·嵌入式·esp32·fpga·oled
tedcloud12321 小时前
OmniRoute怎么部署?开源AI模型路由平台Linux部署教程
linux·服务器·人工智能·开源·音视频
霸道流氓气质21 小时前
KMS 密钥管理服务(Key Management Service)原理与实践
linux·服务器·数据库
SakitamaX21 小时前
LVS(Linux Virtual Server)概念详解
linux·运维·lvs
小张同学a.21 小时前
Linux系统管理
linux·运维
阿龙的工作记录1 天前
深入理解Linux设备驱动模型
linux·嵌入式硬件·工作记录
代码村新手1 天前
Linux的基本指令
linux·运维·服务器
hkj88081 天前
Ubuntu 切换java版本
java·linux·ubuntu
撩得Android一次心动1 天前
Linux编程笔记3【个人用】
linux·笔记