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):
在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/16864771http://www.eifr.com/article.php?id=1766&page=1
http://hi.baidu.com/mcu99/item/56784b36c3465485b611db75
/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/16864771http://www.eifr.com/article.php?id=1766&page=1
http://hi.baidu.com/mcu99/item/56784b36c3465485b611db75
评论
发表评论