Linux下C编程使用动态链接库
为了方便程序功能的后期升级扩展,在程序设计时经常会用到动态库,这样子程序只有到运行阶段才会去加载动态库并且使用库中的函数,那么我们往往只需要更新DLL(Windows系统)或SO(Linux系统)文件即可达到,同时打包成库也有利于保密和核心技术的积累,话不多说,接下来看看Linux下的动态链接库相关内容:
1.头文件及编译选项
在Linux下对so动态链接库进行操作时,需#include <dlfcn.h>,将dlfcn.h头文件包含进来,并且在使用gcc编译时要使用-ldl选项。
2.常用函数
a.void *dlopen(const char *filename, int flag);
其中,函数返回动态库的操作Handle(句柄),filename为库名,而flag常用的值有如下两个(必须使用其中一个,其他标志可使用man dlopen查看):
RTLD_LAZY:在打开SO时不对共享库的函数进行加载操作,等到dlsym调用时才加载指定函数;
RTLD_NOW:在打开SO时将共享库的所有函数加载至内存。
b.void *dlsym(void *handle, const char *symbol); 从dlopen返回的handle里找名为symbol的函数指针并将其返回,注意这里返回的是void *,须做类型转换。
c.int dlclose(void *handle); 关闭dlopen打开的Handle。
d.char *dlerror(void); 当上述动态链接库操作函数被调用后,再调用本函数时,返回NULL表示没有错误发生,如果有错误发现,其将返回一个错误字符串,即出错信息。
3.如何查找库 这里忽略ELF文件里的DT_RPATH和DT_RUNPATH标志时的情况,下面是标准的查找库顺序:首先查找LD_LIBRARY_PATH环境变量对应的目录,找不到时再查找/etc/ld.so.cache文件(由ldconfig命令维护刷新),再找不到时则查找/lib和/usr/lib目录。
4.如何制作SO 在gcc生成so时使用-shared参数。
有了如上这些基础后,我们还是实例学习下如何使用so这玩意:
slam.c(编译成slam.so):
#include <stdio.h>
void print(char *str)
{
printf("%s\n", str);
}
cso_exam.c:
#include <stdio.h>
#include <dlfcn.h>
int main(int argc, char * argv[])
{
if (argc != 2) {
printf("Usage:%s whattoprint\n", argv[0]);
return 0;
}
void * slam_handle;
void (*print_func)(char * str);
slam_handle = dlopen("slam.so", RTLD_LAZY);
if (!slam_handle) {
printf("dlopen failed.\n");
return -1;
}
print_func = (void (*)(char*))dlsym(slam_handle, "print");
if (dlerror() != NULL) {
printf("dlsym failed.\n");
return -1;
}
(*print_func)(argv[1]);
return 0;
}
Makefile:
all:
gcc -o slam.so -shared -fPIC slam.c
gcc -rdynamic -o cso cso_exam.c -ldl
clean:
rm -rf slam.so cso
对应的源码文件目录树如下:
/home/xinu/xinu/c_cpp/c_so_example/
├── cso_exam.c
├── Makefile
└── slam.c
至此,所有准备工作都搞定了,接下来make后会在当前目录下生成cso和slam.so两文件,为了让程序运行时搜索库能是当前目录,我们执行如下命令:
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:.
接下来运行./cso hello就不会提示找不到库了。
参考网址:
http://blog.csdn.net/gubenpeiyuan/article/details/16864771
http://www.eifr.com/article.php?id=1766&page=1
http://hi.baidu.com/mcu99/item/56784b36c3465485b611db75