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
相关推荐
鱼饼6号19 分钟前
Jenkins Pipeline 构建 CI/CD 流程
linux·运维·服务器·ci/cd·容器·jenkins
努力做小白35 分钟前
Linux扩展
linux·c语言·笔记
程序设计实验室1 小时前
服务器时间漂移,如何开启Linux NTP自动同步
linux
0509151 小时前
实验四 进程调度实验
linux·数据结构·算法·课程设计
程序猿(雷霆之王)1 小时前
Linux——动静态库
linux·运维·服务器
JhonKI1 小时前
【Linux网络】打造初级网络计算器 - 从协议设计到服务实现
linux·运维·网络
Herbig2 小时前
服务器上安装node
linux·node.js
敖云岚2 小时前
【Linux】Centos7 安装 Docker 详细教程
linux·运维·服务器
JhonKI2 小时前
【Linux网络】构建HTTP响应与请求处理系统 - HttpResponse从理解到实现
linux·网络·http
FJW0208143 小时前
【Linux】web服务器的部署和优化
linux·运维·服务器·rhce