zoukankan      html  css  js  c++  java
  • 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("
      ");
      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 }
    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("
      ");
       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
    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
    ..... created by skytrails
  • 相关阅读:
    ACE反应器(Reactor)模式(1)
    net 命令
    ACE反应器(Reactor)模式(2)
    恢复SQLServer实例连接 (转载)
    在SQL Server Management Studio中可以运行作业但是用TSQL运行则失败 (转载)
    VirtualBox 之 共享磁盘
    从 IClassFactory 为 CLSID 为 {0002450000000000C000000000000046} 的 COM 组件创建实例失败,原因是出现以下错误: 8001010a解决办法 .
    SQLServer数据类型优先级对性能的影响 (转)
    封装getElementsByAttribute
    js中setAttribute 的兼容性
  • 原文地址:https://www.cnblogs.com/skytrails/p/4865531.html
Copyright © 2011-2022 走看看