Linux动态库应用
简介:
-
动态库在编程过程中是一个很重要的技术,在实际开发过程中,我们在设计各模块时,常常会用到一些通用的功能,如文件处理,网络接口等。这时候,我们可以有两种选择:一种是用动态链接技术,一种是静态链接技术。动态链接,顾名思义,就是在程序运行时调用动态库中的函数。静态链接,则是在编译时就已经把代码拷贝到程序中。相比来说,动态库更节省空间与资源,但静态库调用速度更快,因为它是直接编译进程序中;静态库还有一个缺点是当一个静态库被修改时,整个涉及的模块都要重新编译,这对软件更新还说是一个很大的问题,而动态库则只需要更新库文件就可以完成更新。
动态库调用方式一
- 库函数介绍:
函数原型 说明 备注 void *dlopen(const char *filename, int flag) 该函数将打开一个新库,并把它装入内存 头文件:dlfcn.h,编译时需加上-ldl参数(gcc/g++) char *dlerror(void) 库函数报错函数 void *dlsym(void *handle, const char *symbol) 获取库符号的地址 void *dlclose(void *handle) 关闭库与dlopen对应 - 设计一个动态库libfunc.so
1 /****************************func.c***********************************/ 2 #include <stdio.h> 3 4 void func() 5 { 6 printf("this is call func"); 7 }
1 /****************************func.h***********************************/ 2 3 #ifdef __FUNC_H__ 4 #define __FUNC_H__ 5 6 void func(void); 7 8 #endif
- 用如下命令生成一个动态链接库:
1 linux@skytrails$ gcc -shared -fPIC -o libfunc.so func.c
- 设计调用libfunc.so的主函数:
1 /****************************main.c***********************************/ 2 #include <dlfcn.h> 3 #include <stdlib.h> 4 #include <stdio.h> 5 #include "func.h" 6 int main() { 7 void * handle; 8 void (*pfunc)(void); 9 char *error; 10 handle = dlopen("libfunc.so", RTLD_NOW); 11 if (NULL == handle){ 12 printf("call dlopen failed!"); 13 exit(0); 14 } 15 pfunc = (void(*)(void))dlsym(handle, "func"); 16 if (NULL == pfunc){ 17 error = dlerror(); 18 printf("call dlsym failed!%s", error); 19 } 20 else{ 21 (*pfunc)(); 22 } 23 printf(" "); 24 pfunc = (void(*)(void))dlsym(handle, "func1"); 25 if (NULL == pfunc){ 26 error = dlerror(); 27 printf("call dlsym failed!%s ", error); 28 } 29 else{ 30 (*pfunc)(); 31 } 32 printf(" "); 33 pfunc = (void(*)(void))dlsym(handle, "func2"); 34 if (NULL == pfunc){ 35 error = dlerror(); 36 printf("call dlsym failed!%s ", error); 37 } 38 else{ 39 (*pfunc)(); 40 } 41 printf(" "); 42 pfunc = (void(*)(void))dlsym(handle, "func3"); 43 if (NULL == pfunc){ 44 error = dlerror(); 45 printf("call dlsym failed!%s ", error); 46 } 47 else{ 48 (*pfunc)(); 49 } 50 printf(" "); 51 pfunc = (void(*)(void))dlsym(handle, "func4"); 52 if (NULL == pfunc){ 53 error = dlerror(); 54 printf("call dlsym failed!%s ", error); 55 } 56 else{ 57 (*pfunc)(); 58 } 59 printf(" "); 60 exit(1); 61 }
- 链接libfunc.so生成可执行文件:
1 linux@skytrails$ gcc -shared -fPIC main.c -o main -ldl
- 在命令行下运行可得到:
1 linux@skytrail$ ./main 2 call dlsym failed!./libfunc.so: undefined symbol: func 3 this is call func1 4 this is call func2 5 this is call func3 6 this is call func4
- 完整的编译可以制作成简易的makefile文件:
1 ################################ makefile文件 ################################ 2 all:libfunc.so main 3 libfunc.so:func.c func.h 4 gcc $< -o libfunc.so -fPIC -shared 5 main:main.c 6 gcc $< -o main -ldl
- 注意事项:
- 调用库函数dlopen,dlsym,dlclose时要加载库libdl.so。
- linux为程序动态库提供了5种搜索的路径,系统默认不搜索当前目录,可以根据下文的动态库搜索路径自已选择一种方式,否则找不到指定库文件。
- 如果把func.c文件后缀改成.cpp,则会以c++方式编译,这时会调用dlsym失败,提示找不到func*符号。这里因为c/c++的差异,需要在函数名前指定为extern "c"。
- 动态库搜索路径
优先级 路径 备注 1 DT_RPATH(ELF可执行文件中动态段) 编译目标代码时,对编译器(gcc/g++)加入链接参数-Wl,-rpath指定动态库搜索路径。优先级最高 2 LD_LIBRARY_PATH Linux环境变量 3 /etc/ld.so.conf中指定动态库路径 不同Linux系统文件不一样(debain)。这里是debain系统 4 /lib 默认动态为搜索路径 5 /usr/lib
动态库调用方式二
- 简介:
- 第二种方式其实前面已经应用了。就是libdl.so的调用,在调用库函数dlopen等时需要用到。下面用一个代码实例来说明其应用。
- 代码示例(libfunc.so库复用上面代码,makefile与main.c作一点小小的修改即可):
1 /******************************* main.c ******************************/ 2 #include <stdlib.h> 3 #include <stdio.h> 4 #include "func.h" 5 int main() { 6 func1(); 7 printf(" "); 8 func2(); 9 printf(" "); 10 func3(); 11 printf(" "); 12 func4(); 13 printf(" "); 14 exit(1); 15 }
1 ################################ makefile文件 ################################ 2 all:libfunc.so main 3 libfunc.so:func.c func.h 4 gcc $< -o libfunc.so -fPIC -shared 5 main:main.c 6 gcc $< -o $@ -L. -lfunc
- 执行make
1 linux@skytrails$ make 2 gcc func.c -o libfunc.so -fPIC -shared 3 gcc main.c -o main -L. -lfunc
- 执行程序
1 linux@skytrails$ ./main 2 this is call func1 3 this is call func2 4 this is call func3 5 this is call func4