zoukankan      html  css  js  c++  java
  • Linux下动态库的使用

    【简介】

    linux环境下的动态库一般名为libxxx.so, 用ldd命令分析某个可执行程序,可以看到该程序依赖哪些动态库,以及路径。 如 ldd ./test

      linux-vdso.so.1 =>  (0x00007fffaab52000)

      libc.so.6 => /lib64/libc.so.6 (0x0000003c4c800000)

      /lib64/ld-linux-x86-64.so.2 (0x0000003c4c000000)

    如果有依赖库找不到,程序会无法正常运行。

    【创建一个动态库】

    util.cpp

    1
    2
    3
    4
    extern "C" int InsertSubStr(char* pszBuf, int nPos, char* pValue)
    {
         return 1;
    }

    代码为cpp时,函数可以重载,在symbol里生成的函数名会带上修饰,如_ZwqInsertSubStrBstl. 加上extern "C"之后在symbol里就是原名,当然也就不能有同名函数了。如果函数体使用了该修饰后,头文件定义也必须加上,否则调用者编译时会找不到函数名。

    makefile

    1
    2
    3
    4
    5
    libmyutil.so : util.o
      g++ -shared -o libmyutil.so util.o
     
    util.o : util.cpp
      g++ -fPIC -c util.cpp -o util.o

     如果没有编译错误,则会生成libmyutil.so文件。因为使用了-shared编译选项,如果在代码里引用了其他库libabc.so,在编译时不会报错(不像windows下那样会报unresolve external,或者我还没找到设置方法)。如果调用者也没有引用该库libabc.so,则加载或运行时会报错。所以知道引用了哪些库,最好在makefile里加上,如g++ -shared -labc -o libmyutil.so util.o

    QT创建动态库时,会生成libxx.so.1.0.0等几个带版本号的符号链接,可以加上 CONFIG += plugin 这样就不带版本号了。

    【使用动态库】

    像windows一样,也有直接编译链接和动态加载两种方式

    1.直接编译链接

    include头文件的函数定义后,在程序中调用函数,再在makefile中加上-lmyutil即可。用ldd命令分析执行程序,可以看到引用了libmyutil.so QT编译时,需要在pro文件里指定路径 LIB += -L../lib -lmymodule

    2.动态加载

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    #include <dlfcn.h>
     
    typedef int (*fnTestFoo)(char* pszBuf, int nPos, char* pValue);
     
      void *hso = dlopen("./libmyutil.so", RTLD_NOW);//RTLD_LAZY);//
      if(!hso)
      {
        printf("dlopen failed:%s ", dlerror());
        return;
      }
      fnTestFoo fnTest = (fnTestFoo)dlsym(hso, "InsertSubStr");
      char *perr = dlerror();
      if(perr)
      {
        printf("load symbol failed:%s ", perr);
        return;
      }
      char szText[256]="abcdef";
      fnTestFoo(szText, 2, "xyz");
      printf("%s ", szText);
      dlclose(hso);

    可以看出与windows函数的对应:dlopen=LoadLibrary,dlsym=GetProcAddress. 这几个函数在libdl.so中,编译时在makefile中加上-ldl dlopen

    可以有选项RTLD_NOW/RTLD_LAZY,前者为加载时解析依赖关系,失败则报错停止运行;后者为先不解析,运行到相应的代码时,如果有依赖关系错误再报错。

    动态加载C++类

    如果想要使用动态库中的C++类,直接使用肯定不行,因为编译时会找不到构造函数。其实只要在动态库中输出一个函数,创建类对象

    CTest *GetClass_DL(void)

    {

        return (new CTest());

    }

    这样就可以了,析构函数也一样。

    【依赖关系和路径】

    在windows下可以用depends来查看库的依赖关系,在Linux下有好几个工具可以达到类似效果,如上面提到的文件依赖关系的ldd. 如果要查看函数依赖关系,可以用nm命令,如nm test

    1
    2
    3
    4
    5
    6
    7
    8
    0000000000601170 d _DYNAMIC
                     w _Jv_RegisterClasses
    00000000004008e4 T _Z8callFunciPPcPFiS_zE
                     U dlclose@@GLIBC_2.2.5
                     U dlerror@@GLIBC_2.2.5
                     U dlopen@@GLIBC_2.2.5
                     U dlsym@@GLIBC_2.2.5
    0000000000400da2 T main

    其中T(text)前面是在本程序中的地址;U(unresolved)表示引用的外部库函数,以及对应的库名称。另外还有w(weak),A(absolute)不了解。 另外还有objdump命令,更详细的显示程序内的内容。

    动态加载dlopen时,最好是指定全路径,否则当前路径可能发生变化。当编译链接库文件时,有时运行程序会找不到库文件报错:error while loading shared libraries: libxxx.so.1: cannot open shared object file: No such file or directory.很多时候是未指定路径。

    与windows不同,把dll放在exe一起就行了,加载时会先从当前路径查找。linux下的库文件的路径配置在/etc/ld.so.conf 中,内容如下一行

    include ld.so.conf.d/*.conf

    在conf.d目录,可以看到其他软件所需的库文件路径,如mysql-x86_64.conf 里面也只有一行:/usr/lib64/mysql

    所以如果自己的库文件不放在系统的库路径如/usr/lib64下的话,也可以照此方法增加myapp.conf文件,写上/mylib, 放在这里即可。

    sudo ldconfig更新配置(注意较慢),用ldconfig -p|grep libmyxxx可以查看自己的库是否在系统的路径里。当在路径里新增so文件时,配置不会自动更新。

    如果不想更改系统的库文件路径,也可以在运行时修改环境变量LD_LIBRARY_PATH,如 $ export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/my_library_path $ ./my_app

    原文: https://www.cnblogs.com/chaos77/p/6874378.html

  • 相关阅读:
    Linnia学习记录
    漫漫考研路
    ENS的学习记录
    KnockoutJS 3.X API 第四章 数据绑定(4) 控制流with绑定
    KnockoutJS 3.X API 第四章 数据绑定(3) 控制流if绑定和ifnot绑定
    KnockoutJS 3.X API 第四章 数据绑定(2) 控制流foreach绑定
    KnockoutJS 3.X API 第四章 数据绑定(1) 文本及样式绑定
    KnockoutJS 3.X API 第三章 计算监控属性(5) 参考手册
    KnockoutJS 3.X API 第三章 计算监控属性(4)Pure computed observables
    KnockoutJS 3.X API 第三章 计算监控属性(3) KO如何实现依赖追踪
  • 原文地址:https://www.cnblogs.com/jiftle/p/8401776.html
Copyright © 2011-2022 走看看