动态链接库是代码重用和模块化的重要工具,它使得将功能封装为独立的库更加容易,同时还可以动态加载和升级这些库,提高了程序的灵活性和可维护性。
当我们希望将C++源码编译成动态链接库,并在其他应用程序中调用这个动态链接库,是这篇文章的应用场景。这篇文档将介绍如何创建、编译、链接和调用C++动态链接库。
PS:本文以下内容根据我实际工作项目编写,不采用demo的形式。
首先,编写C++
源码文件,包括所需的类和函数。(看这篇文章的应该都有源码了吧!)
我实际的项目文件如下:
现在需要把ai_main.cpp
编译成动态链接库。难点在于(完成后看来也不是什么难点):ai_main.cpp
不仅调用了同级目录下的其他文件,还调用了其他路径的下源码文件(opencv
等)
使用C++
编译器将源码编译成共享库,我这里采用的是aarch64-mix210-linux-g++
编译工具链:
build
"的文件夹,该文件夹将用于构建目标文件和.so
文件。打开命令行终端并进入到该目录下。mkdir build && cd build
cpp
文件编译为目标文件(.o
文件):aarch64-mix210-linux-g++ -c -fPIC -I/home/data/ai/opencv/include -I/home/data/ai/Ascend/ascend-toolkit/5.10.t20.0.b200/arm64-lmixlinux200/aarch64-linux/include ../*.cpp
-c
选项告诉编译器只进行编译而不进行链接操作。
-fPIC
选项表示生成位置无关代码,这是生成共享库所必需的。
-I
选项指定头文件目录,如果有其他cpp
文件中使用了头文件,则需要将其添加到该选项中。
修改于2023年9月20日:添加了优化参数,使得后续生成的so库调用时间降低
aarch64-mix210-linux-g++ -c -fPIC -I/home/data/ai/opencv/include -I/home/data/ai/Ascend/ascend-toolkit/5.10.t20.0.b200/arm64-lmixlinux200/aarch64-linux/include ../*.cpp -O3 -flto -funroll-loops -finline-functions
.so
:aarch64-mix210-linux-g++ -shared -o libmy_main.so *.o
-shared
选项表示生成共享库文件。
-o
选项指定输出文件名。
修改于2023年9月20日:添加了优化参数,使得后续生成的so库调用时间降低
aarch64-mix210-linux-g++ -shared -o libmy_main.so *.o -O3 -flto -funroll-loops -finline-functions
完成后,你将在"build
"文件夹中找到生成的libmy_main.so
文件,这是可以给别人用来动态链接的共享库。
在上述命令中可以换成自己的编译工具(例如g++
),需要根据实际情况修改文件名和路径。另外,如果代码中有其他库的依赖,你需要确保这些库已经安装并在编译/链接时正确配置了相关选项。
通过运行以下命令来验证生成的SO文件是否可用:
file libmy_main.so
这应该显示类似于以下内容:
libmy_main.so: ELF 64-bit LSB shared object, ARM aarch64, version 1 (GNU/Linux), dynamically linked, not stripped
so
文件生成成功。
检查符号链接:
运行以下命令,并确保输出中包含后续所需调用函数的定义。
nm libmy_main.so | grep ai_track
输出类似于:
0000000000061218 T ai_track
出现以上结果,说明ai_track
函数在生成的共享库libmy_main.so
中是可见的。这意味着该函数的定义在共享库中是存在的。ai_track
需要替换成自己对外的接口函数,也就是其他程序调用so
的函数。
现在,我们将展示如何在另一个C++
程序中调用生成的C++
动态链接库。我这是是做的测试,把原来源码编译部分替换成调用生成的so
。
# 注释掉原来调用原代码部分
# SMP_SRCSCPP += $(wildcard $(PWD)/../media/ai/src/*.cpp)
# 添加共享库的头文件和库路径
COMM_INC += -I/home/ai/src/build/include
CFLAGS += -L/home/src/build/lib
# 添加共享库的链接标志,例如 libmy_main.so
CFLAGS += -lmy_main
# 如果共享库是C++库,添加C++编译器标志
CFLAGS += -lstdc++
其中:
COMM_INC += -I/home/ai/src/build/include
:目录下为so
提供的函数接口的头文件,可以直接复用源码中对应的ai_main.h
;
CFLAGS += -L/home/src/build/lib
:确保 -L 选项中指定的共享库路径是正确的,并且包含了包含所需共享库libmy_main.so
的目录;
CFLAGS += -lmy_main
:通常,共享库名称应该是去掉 lib
前缀和 .so
后缀的部分。在这种情况下,libmy_main.so
应该是 -lmy_main
;
我这里直接在原来的基础上重新编译:
make clean && make -j4
运行完成后会生成可执行文件,我这里可执行文件暂为run_main
运行run_main
文件时,需要指定so
动态链接库的路径
export LD_LIBRARY_PATH=/path/to/your/library:$LD_LIBRARY_PATH
或者,可以在使用运行时链接:
run_main -rpath /path/to/your/library
这将在运行时为应用程序指定共享库的搜索路径。
无论您选择哪种方法,都确保共享库的路径设置正确,以便您的应用程序可以正确找到和加载所需的共享库。
本文介绍了如何制作C++
动态链接库(so
文件)以及如何从另一个C++
程序中加载和调用该库。本文主要从笔者自身项目出发,其中的过程不一定适用所有人。
如果阅读本文对你有用,欢迎一键三连呀!!!
2023年9月5日14:25:02