最近在研究linux环境下完成动态链接库的调用,为后面的项目做准备,因为要做图像方面的处理,所以直接来一个包含opencv的动态链接库调用。
概念的东西后面在解释,直接开搞:
1、新建Function.cpp作为动态链接库,内容如下:
#include <stdio.h>
#include <opencv2/opencv.hpp>
using namespace cv;
int F_sum(int a,int b)
{
int c=a+b;
printf("this sum is: %d\n",c);
return 0;
}
int S_F(int flag,Mat ImageMat)
{
namedWindow("ImageWindow");
switch(flag)
{
case 0:
printf("this is a false\n");
break;
case 1:
imshow("ImageWindow",ImageMat);
break;
}
return 0;
}
2、新建Function.h作为头文件,内容如下:
#include <opencv2/opencv.hpp>
using namespace cv;
int F_sum(int a,int b);
int S_F(int flag,Mat ImageMat);
3、新建main.cpp作为主函数,用于链接库的调用测试,内容如下:
#include <opencv2/opencv.hpp>
#include "Function.h"
using namespace cv;
using namespace std;
int main()
{
Mat ImageMat=imread("1.jpg");
//imshow("image",ImageMat);
F_sum(8,8);
S_F(1,ImageMat);
waitKey();
return 0;
}
4、编译生成动态链接库:
将Function.cpp Function.h 放到linux某文件夹下
在该目录下,执行下列指令:
g++ -c -fPIC Function.cpp -o Function.o
g++ -shared Function.o -o libFunction.so
此时在该文件夹下就生成了,Function.o 和libFunction.so 两个文件,其中libFunction.so就是所谓的动态链接库。
注意:动态链接库的命名前面一定要加lib!
5、将libFunction.so 、Function.h、 main.cpp 放到同一目录下,执行下列指令:
g++ -c main.cpp -o main.o
g++ main.o -o main.exe `pkg-config --cflags --libs opencv` -L. -lFunction
export LD_LIBRARY_PATH=.
注意:1、链接的时候,要加上`pkg-config --cflags --libs opencv`, 可以连接到opencv库。
2、 -L. -lFunction,此语句是连接本地文件夹中的libFunction.so ,也就是上一步生成的。
6、执行 ./main.exe 测试程序效果,收工!
概念一:一个C++源代码要最终变成一个可执行文件需要经过四个步骤:
1、预处理(pro-processing)
2、编译(compiling)
3、汇编(assembling)
4、链接(link)
新建一个test.cpp,其变化过程如下:
test.cpp---(预处理)---test.i---(编译)---test.s---(汇编)---test.o---(链接)---test.exe
概念二: 相关关键字的解释
-o 选项表示将源代码预处理后输出在指定文件中
-E 选项使用g++/gcc将源代码预处理后不执行其他动作(预处理)
-S 选项使用g++/gcc将预处理后的文件编译,翻译成汇编代码(编译)
-c 选项将编译生成的test.s文件生成二进制目标代码(汇编)
-fPIC:表示编译为位置独立的代码,不用此选项的话编译后的代码是位置相关的。所以动态载入时是通过代码拷贝的方式来满足不同进程的需要,而不能达到真正代码段共享的目的。
-L.:表示要连接的库在当前目录中
-Shared : 该选项指定生成动态连接库(让连接器生成T类型的导出符号表,有时候也生成弱连接W类型的导出符号),不用该标志外部程序无法连接。相当于一个可执行文件.
-ltest:编译器查找动态连接库时有隐含的命名规则,即在给出的名字前面加上lib,后面加上.so来确定库的名称
概念三:linux中的.so文件是共享文件,跟windows下的.dll类似。
gcc和g++分别是GNU(一个开源组织)的c&c++编译器
对于.c后缀的文件,gcc把它当做是C程序,g++当做是C++程序;对于.cpp后缀的文件,gcc和g++都会当做c++程序。
gcc可以根据后缀名为.c或.cpp分别按c程序和c++程序来编译,但是g++无论是.c或.cpp都统一按c++程序来编译。
概念四:静态库和动态库对比
二者的不同点在于代码被载入的时刻不同。
静态库的代码在编译过程中已经被载入可执行程序,因此体积较大。
静态用.a为后缀, 例如: libhello.a
共享库(动态库)的代码是在可执行程序运行时才载入内存的,在编译过程中仅简单的引用,因此代码体积较小。
动态通常用.so为后缀, 例如:libhello.so
共享库(动态库)的好处是,不同的应用程序如果调用相同的库,那么在内存里只需要有一份该共享库的实例。
概念五:pkg-config工具
g++编译c++程序时,需要用-L和-I来分别制定连接库和头文件信息,但是opencv库文件和头文件繁多,不可能每次编译都写上一堆连接信息,而且不同人可能会安装在不同路径,查找也困难,于是需要使用pkg-config工具来自动找出依赖库和头文件信息,仅需输入pkg-config–libs –cflags opencv,
当安装一个库时(例如从RPM,deb或其他二进制包管理系统),会包括一个后缀名为pc的文件,在这个.pc文件里包含有数个条目。
可以在linux中打开opencv.pc看一下其内容,路径:/usr/local/lib/pkgconfig/opencv.pc
内容如下:
ls@Precision-Tower-5810:/usr/local/lib/pkgconfig$ cat opencv.pc
# Package Information for pkg-config
prefix=/usr/local
exec_prefix=${prefix}
libdir=${exec_prefix}/lib
includedir_old=${prefix}/include/opencv
includedir_new=${prefix}/include
Name: OpenCV
Description: Open Source Computer Vision Library
Version: 3.4.1
Libs: -L${exec_prefix}/lib -lopencv_ml -lopencv_superres -lopencv_cudacodec -lopencv_stitching -lopencv_cudastereo -lopencv_cudafeatures2d -lopencv_videostab -lopencv_cudaoptflow -lopencv_photo -lopencv_cudaobjdetect -lopencv_cudalegacy -lopencv_calib3d -lopencv_features2d -lopencv_highgui -lopencv_cudawarping -lopencv_cudaimgproc -lopencv_objdetect -lopencv_flann -lopencv_cudafilters -lopencv_cudaarithm -lopencv_cudabgsegm -lopencv_videoio -lopencv_imgcodecs -lopencv_shape -lopencv_video -lopencv_dnn -lopencv_imgproc -lopencv_core -lopencv_cudev
Libs.private: -ldl -lm -lpthread -lrt -lcudart -lnppc -lnppial -lnppicc -lnppicom -lnppidei -lnppif -lnppig -lnppim -lnppist -lnppisu -lnppitc -lnpps -lcublas -lcufft -L-L/usr/local/cuda -llib64
Cflags: -I${includedir_old} -I${includedir_new}
luzaiwang@jdh-Precision-Tower-5810:/usr/local/lib/pkgconfig$
可以看到内容里面。包含用于其他使用这个库的程序编译时需要的库设置,以及头文件的位置,版本信息和简介等等