梗概
如果要生成动态链接库,就需要把源码,无论是.c .cpp .cu还是其他的语言写的程序,都通过编译器变成.o文件,之后把相应的.o文件进行链接成为.so动态链接库。这样就可以直接调用其中的函数了。
形成过程: .c .cpp .cu -> .o -> .so
使用 : test.c + .so - > test
./test
但是其中还是有许多的小细节需要注意的。
现在就举个栗子:
把yolo算法,编译成动态链接库,其中需要用到opencv、cuda、cudnn。之后讲介绍怎么把这些库一起与源码进行编译,生成可以用的.so。
源码文件分为三类:.c文件 .h头文件和 .cu的cuda文件
【分析编译.c文件】
gcc -fPIC -DOPENCV `pkg-config --cflags opencv` -DGPU -I/usr/local/cuda/include/ -DCUDNN
-Wall -Wfatal-errors -Ofast -DOPENCV -DGPU -DCUDNN -c ./src/image.c -o obj/image.o
gcc : 编译器
-fPIC: 使用 -fPIC 选项,会生成 PIC 代码。告诉编译器产生与位置无关代码(Position-Independent Code), .so 要求为 PIC,以达到动态链接的目的,否则,无法实现动态链接。
`pkg-config –cflags opencv`: 根据pkg-config信息来找到opencv的include,因为源文件中包含使用了一些opencv的函数,所以需要引入include文件。对应的“ 两个反引号不要少。
-I/usr/local/cuda/include/ : 首先-I表示根据需要在/usr/local/cuda/include/目录下找到对应的文件。并包含进去一起编译。
-Wall: 表示把所有警告都展示出来。
-Wfatal-errors: 表示当发生第一个错误的时候停止编译,这样的好处就是可以找到错误的地方,防止许多无用的信息掩盖了错误信息。
-Ofast:编译所采用的优化手段。
-c: 进行源文件的编译成.o文件
-o: 输出到哪里,并且文件名是什么,只有紧跟其后的一项是输出
-DOPENCV,-DGPU,-DCUDNN:这些选项就是控制代码中的宏定义,如果带有这些选项进行编译,证明宏定义是选定的。即#ifdef OPENCV 是定义了的,否则没有定义。这也相当与vs中的预处理选项。通过这项可以根据修改Makefile文件来确定某个库是否使用,在源码中再通过宏定义来实现,非常方便。
【分析.cu文件编译】
nvcc --gpu-architecture=compute_52 --gpu-code=compute_52 -DOPENCV `pkg-config --cflags opencv2`
-DGPU -I/usr/local/cuda/include/ -DCUDNN --compiler-options "-Wall -Wfatal-errors -Ofast
-DOPENCV -DGPU -DCUDNN -fPIC" -c ./src/convolutional_kernels.cu -o obj/convolutional_kernels.o
很多与c的编译差不多。
nvcc : cuda的编译器
–gpu-architecture=compute_52 –gpu-code=compute_52 : 这个是根据显卡计算能力来确定的,来表示gpu的架构是说明,我的显卡是GT960,所以是compute_52
–compiler-options : 在双引号中填写一些编译选项。 尤其是-fPIC选项,因为在外面写是编译不通过的,只能在双引号里面写。
把所有的.c文件和.cu文件都编译成.o文件,当然都是-fPIC编译的,即是位置无关的。
现在就开始通过这些目标文件来进行.so的生成。
gcc -shared -o libtest.so *.o
-shared : 因为要做成动态链接库,所以需要把该库做成可以共享的。
*.o : 即刚才生成的所有.o文件,依次添加进去。
但是只把这些.o文件进行链接,链接到libtest.so文件中,虽然也可以生成.so文件,但是在使用时会出现一些错误,如:undefined reference to `cudnnGetConvolutionBackwardDataWorkspaceSize’ 等关于cudnn的错误。 所以需要在链接的时候把cudnn的相关链接也链接进去。
gcc -shared -o libtest.so *.o -L/usr/local/cuda/lib64 -lcuda -lcudart -lcublas -lcurand -lcudnn
-L/usr/local/cuda/lib64 : 确定lib的路径,-L后面跟的就是lib所在的路径,如果要引入其中的.so文件,只需要-l开头即可,后面跟文件名去掉lib的名字即可。
这样就生成了.so文件。
使用.so文件:
Step 1:
gcc -c test.c $(pkg-config --cflags --libs opencv)
因为test.c中有opencv的函数,所以编译的时候需要引入opencv,生成test.o文件
Step 2:
gcc -o test test.o libtest.so -L/usr/local/cuda/lib64 -lcuda -lcudart -lcublas -lcurand -lcudnn
把程序与cuda的库进行动态链接,生成可执行文件test。