在编写程序时,动态库是常常用到的工具,在vs等编程环境下只需要,完成工程的本地化配置或是直接将dll配置到环境变量即可(不推荐,毕竟小题大做了),而对于像楼主这样刚刚接触Linux操作系统的菜鸟来说,配置动态(共享)库还不是一个简单的问题。
在介绍动态库的调用方法之前,先介绍一下动态库的编译(如何生成so文件)
需要一个包含几个方法声明的头文件和对应的定义文件。例如
//so_test.h 头文件
#include "stdio.h"
void test_a();
void test_b();
void test_c();
//test_a.c:
#include "so_test.h"
void test_a()
{
printf("this is in test_a...\n");
}
//test_b.c:
#include "so_test.h"
void test_b()
{
printf("this is in test_b...\n");
}
#include "so_test.h"
void test_c()
{
printf("this is in test_c...\n");
}
将上述so_test.h test_a.c test_b.c test_c.c 文件放与同一目录下,执行
gcc test_a.c test_b.c test_c.c -fPIC -shared -o libtest.so
此时,我们可以看到 多出了一个libtest.so文件,这里的命名有些讲究,应该命名为lib+xxxx+.so后面再解释为什么,这就是我们刚刚生成的共享库文件。
-fPIC:表示编译为位置独立的代码,不用此选项的话编译后的代码是位置相关的所以动态载入时是通过代码拷贝的方式来满足不同进程的需要,而不能达到真正代码段共享的目的(好像不是必须的哦)
-shared : 该选项指定生成动态连接库,这个是必须的
到这来似乎完成了共享库的编写,那么我们先来简单的介绍下两种调用方式:
①隐式调用
②显示调用
简单来时,隐式调用就是指在我们的程序代码中,没有定义我们调用了哪个共享库,只是包含了某个贡献库的头文件而已,而在编译的时候需要指明共享库。我们继续用示例说明:
#include "so_test.h"
int main()
{
test_a();
test_b();
test_c();
return 0;
}
很简单的调用,和普通的链接没什么区别啊!是的不过在编译的时候要花费一些功夫
gcc test.c -L. -ltest -o test
-L. : 表示需要链接的共享库在当前目录;
-Itest : 表示调用的共享库的文件名为 lib+test+.so 即libtest.so
我们运行一下生成的test文件
无法打开shared object file
为什么不行,别急 我们借助ldd命令查看下 test文件的链接情况
ldd text
我们刚刚写的libtest.so 就和你放在一个文件夹居然说找不到,服了(:зゝ∠)
话说链接库可以从以下五个位置检索
①环境变量LD_LIBRARY_PATH列出的用分号间隔的所有目录;
②文件/etc/ld.so.cache中找到的库的列表,由ldconfig命令刷新;
③目录usr/lib;
④目录/lib;
⑤当前目录;
我建议还是将我们生成的共享库拷贝到/usr/lib/或/lib目录下,修改LD_LIBRARY_PATH不是和windows环境下改环境变量一样小题大做吗?(个人看法请大神指正)
cp libtest.so /usr/lib/
现在我们发现他能找到我们写的共享库了,也就能正常运行了。
好的接下来看看显示调用
此时我们已经写好了libtest.so共享库,并且已拷贝至/usr/lib/目录下
显示调用,就是在代码中明确指明我们需要调用的共享库,而不需要在编译时指明,因此我们需要一些特殊的函数完成上述功能。
我们需要用到一个头文件dlfcn.h 和其对应的四个函数。下面在介绍具体步骤再加以说明。
①把dlfcn.h系统头文件包含进来
②用dlopen()函数打开库文件,并指定打开方式;
dllope()有两个参数
第一个参数为共享库的名称,能取到的位置不在累述了。
第二个参数为打开共享库的方式。有两个取值
①RTLD_NOW:将共享库中的所有函数加载到内存
②RTLD_LAZY:会推后共享库中的函数的加载操作,直到调用dlsym()时方加载某函数
返回值是一个void *指针
③用dlerror()函数测试是否打开成功,并进行错误处理,返回值是一个char *;
④用dlsym获得函数地址,存放在一个函数指针中,调用格式是dlsym(void *,”fcnname”);
⑤用获得的函数指针进行函数调用。
⑥程序结束时用dlclose(void *)关闭打开的动态库,防止资源泄露。
#include <dlfcn.h> //包含头文件
#include "so_test.h" //包含共享库头文件
int main(int argc,char *argv[])
{
void(*pT)(); //申请一个与共享库对应的函数指针
void *Handle=dlopen("libtest.so",RTLD_LAZY);
//打开共享库,并有void指针 Handle保存
if(Handle==NULL) //检测是否打开成功
{
printf("Fail load library\n");
return -1;
}
char * pE=dlerror(); //检测函数是否打开成功
if(pE!=NULL)
{
printf("%s\n",pE);
return -1;
}
pT=dlsym(Handle,"test_a"); //调用具体的函数
pE=dlerror(); //再次检测函数打开是否成功
if(pE!=NULL)
{
printf("%s\n",pE);
return -1;
}
(*pT)(); //调用共享库的函数
dlclose(Handle); //关闭共享库
return 0;
}
编译命令为
gcc -o main -ldl test.c
-ldl : 指明生成对象需要使用共享库,但不用具体指明哪个共享库
(^o^)/~ 调用动态(共享库)的方法就先说到这来喽!!