Linux动态库应用

Linux动态库应用

简介:

  • 动态库在编程过程中是一个很重要的技术,在实际开发过程中,我们在设计各模块时,常常会用到一些通用的功能,如文件处理,网络接口等。这时候,我们可以有两种选择:一种是用动态链接技术,一种是静态链接技术。动态链接,顾名思义,就是在程序运行时调用动态库中的函数。静态链接,则是在编译时就已经把代码拷贝到程序中。相比来说,动态库更节省空间与资源,但静态库调用速度更快,因为它是直接编译进程序中;静态库还有一个缺点是当一个静态库被修改时,整个涉及的模块都要重新编译,这对软件更新还说是一个很大的问题,而动态库则只需要更新库文件就可以完成更新。

动态库调用方式一

  1. 库函数介绍:
    函数原型说明备注
    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对应
  2. 设计一个动态库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
    
    
  3. 用如下命令生成一个动态链接库: 
    1 linux@skytrails$ gcc -shared -fPIC -o libfunc.so func.c
  4. 设计调用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("\n");
    24     pfunc = (void(*)(void))dlsym(handle, "func1");
    25     if (NULL == pfunc){
    26         error = dlerror();
    27         printf("call dlsym failed!%s\n", error);
    28     }
    29     else{
    30         (*pfunc)();
    31     }
    32     printf("\n");
    33     pfunc = (void(*)(void))dlsym(handle, "func2");
    34     if (NULL == pfunc){
    35         error = dlerror();
    36         printf("call dlsym failed!%s\n", error);
    37     }
    38     else{
    39         (*pfunc)();
    40     }
    41     printf("\n");
    42     pfunc = (void(*)(void))dlsym(handle, "func3");
    43     if (NULL == pfunc){
    44         error = dlerror();
    45         printf("call dlsym failed!%s\n", error);
    46     }
    47     else{
    48         (*pfunc)();
    49     }
    50     printf("\n");
    51     pfunc = (void(*)(void))dlsym(handle, "func4");
    52     if (NULL == pfunc){
    53         error = dlerror();
    54         printf("call dlsym failed!%s\n", error);
    55     }
    56     else{
    57         (*pfunc)();
    58     }
    59     printf("\n");
    60     exit(1);
    61 }
  5. 链接libfunc.so生成可执行文件:
    1     linux@skytrails$ gcc -shared -fPIC main.c -o main -ldl
  6. 在命令行下运行可得到:
    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
  7. 完整的编译可以制作成简易的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

     

  8. 注意事项:
    • 调用库函数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

动态库调用方式二

  1. 简介:
    • 第二种方式其实前面已经应用了。就是libdl.so的调用,在调用库函数dlopen等时需要用到。下面用一个代码实例来说明其应用。
  2. 代码示例(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("\n");
     8     func2();
     9     printf("\n");
    10     func3();
    11     printf("\n");
    12     func4();
    13     printf("\n");
    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
  3. 执行make
    1 linux@skytrails$ make
    2 gcc func.c -o libfunc.so -fPIC -shared
    3 gcc main.c -o main -L. -lfunc
  4. 执行程序
    1 linux@skytrails$ ./main
    2 this is call func1
    3 this is call func2
    4 this is call func3
    5 this is call func4

posted on 2015-10-09 23:50  skytrails  阅读(238)  评论(0编辑  收藏  举报

导航