博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Linux下动态库的使用
阅读量:5062 次
发布时间:2019-06-12

本文共 3067 字,大约阅读时间需要 10 分钟。

【简介】

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

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

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

makefile

libmyutil.so : util.o  g++ -shared -o libmyutil.so util.outil.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.动态加载

#include 
typedef int (*fnTestFoo)(char* pszBuf, int nPos, char* pValue); void *hso = dlopen("./libmyutil.so", RTLD_NOW);//RTLD_LAZY);// if(!hso) { printf("dlopen failed:%s\n", dlerror()); return; } fnTestFoo fnTest = (fnTestFoo)dlsym(hso, "InsertSubStr"); char *perr = dlerror(); if(perr) { printf("load symbol failed:%s\n", perr); return; } char szText[256]="abcdef"; fnTestFoo(szText, 2, "xyz"); printf("%s\n", 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

0000000000601170 d _DYNAMIC                 w _Jv_RegisterClasses00000000004008e4 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.50000000000400da2 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

你可能感兴趣的文章
java学习笔记之String类
查看>>
UVA 11082 Matrix Decompressing 矩阵解压(最大流,经典)
查看>>
jdk从1.8降到jdk1.7失败
查看>>
硬件笔记之Thinkpad T470P更换2K屏幕
查看>>
【知识库】-数据库_MySQL 的七种 join
查看>>
iOS开发——缩放图片
查看>>
HTTP之URL的快捷方式
查看>>
满世界都是图论
查看>>
配置链路聚合中极小错误——失之毫厘谬以千里
查看>>
代码整洁
查看>>
蓝桥杯-分小组-java
查看>>
Android Toast
查看>>
iOS开发UI篇—Quartz2D使用(绘制基本图形)
查看>>
docker固定IP地址重启不变
查看>>
桌面图标修复||桌面图标不正常
查看>>
JavaScript基础(四)关于对象及JSON
查看>>
关于js sort排序方法
查看>>
JAVA面试常见问题之Redis篇
查看>>
jdk1.8 api 下载
查看>>
getElement的几中属性介绍
查看>>