linux下动态共享库的创建,使用与更新(包括ldconfig的使用) 分类: Linux/Unix 2010-09-23 16:50 701人阅读 评论(0) 收藏 举报 linuxlibraryp

linux下动态共享库的创建,使用与更新(包括ldconfig的使用)

分类: Linux/Unix   701人阅读  评论(0)  收藏  举报

目录(?)[+]

一 创建并编译共享库

动态链接库一般以lib开头,形如libmymodule.so.1.0.0.   

后面跟的三个版本号,从左到右的含义为:

(1) 大版本号,当接口变得和之前不兼容,则新增一个大版本号。

(2) 一般增加了接口,不过旧的接口不变,则新增此版本号。

(3) 接口不做任何变化,只是实现做了修改,则新增此版本号。 

假设我们的库只包含 module.cpp, 则用命令

[c-sharp]  view plain copy
  1. g++ -fPIC -Wall -c module.cpp  

生成module.o,再用命令

[c-sharp]  view plain copy
  1. g++ -shared -Wl,-soname,libmymodule.so.1 -o libmymodule.so.1.0.0 module.o  

生成libmymodule.so.1.0.0共享库。这里的libmymodule.so.1.0.0也叫做共享库的real name.

  • -fPIC是使生成的目标文件“位置无关(Position Independent Code)”从而可以被多个程序共享。
  • -shared 指定产生共享库。
  • -Wl,-soname,libmymodule.so.1 指定共享库的soname为libmymodule.so.1,若不指定,则无soname. soname的作用后面会提到。可以用objdump -p libmymodule.so.1.0.0 | grep SONAME  查看soname. 

 一般soname带且只带大版本号,比如这里的libmymodule.so.1, 是因为共享库的相互兼容的不同版本,都具有相同的soname(在升级的时候,需要用soname来对应)。而如果大版本号变了,意味着接口变得不兼容了,也就没有必要让这个版本和之前的共享库兼容了。这个时候,启用一个新的soname是更好的做法。

二 编译主程序

因为gcc中,用-l参数指定的库文件必须满足格式lib*.so 所以我们需要建立软连接libmymodule.so, 并令其指向libmymodule.so.1.0.0

[c-sharp]  view plain copy
  1. ln -s libmymodule.so.1.0.0 libmymodule.so  

这里的libmymodule.so就是所谓的"link name"。 

假设我们的主程序(相对于库来说),代码在main.cpp里,则用命令

[c-sharp]  view plain copy
  1. g++ -o main main.cpp -L. -lmymodule  

生产可执行程序main。注意link name只在编译的时候需要,主程序会记住根据这个文件最终所指的共享库的soname,用来在运行的时候,查找加载动态库。如果共享库没有指定soname, 那么主程序会记住这个'link name",也就是lib*.so这样形式的名字,做为soname, 在运行的时候,用这个名字来查找加载动态库。

  • -L指定搜索库的文件夹,
  • -l 指定所依赖的库。注意这里需要去掉前面的“lib”和后面的“.so”

 三 运行期 

这个时候,运行./main会出现以下错误:

./main: error while loading shared libraries: libmymodule.so.1: cannot open shared object file: No such file or directory 

使用ldd main可以查看所依赖的动态库是否被满足,执行“ldd main":

发现有一行libmymodule.so.1 => not found,说明在运行期,加载器没有找到对应的共享库文件。 

加载器会在以下地方查找main程序中记住的所需要的库的soname:

(1) /etc/ld.so.cache 这是一个cache,存放soname到共享库文件的soname link (一个文件名为soname的软连接) 的映射(key->value值对)。

(2) /usr/lib 和 /lib

(3) 环境变量LD_LIBRARY_PATH指定的文件夹。

可以用ldconfig 命令,解决这个问题。ldconfig主要做2件事情:

一是扫描/lib和/usr/lib和/etc/ld.so.conf里指定文件夹,对里面的共享库建立soname link (ldconfig会根据文件名里的版本号,自动找到最新的共享库文件,并把soname link指向这个最新的共享库文件)

二是更新/etc/ld.so.cache,建立soname到soname link的映射。 

加载器如果在ld.so.cache中查到所需的soname,则会依次找到 soname-->soname link-->实际的共享库文件。如果找不到,则会在/usr/lib和/lib中查找文件名为soname的文件,作为共享库文件加载。注意,在这里,加载器不会去找/etc/ld.so.conf里指定的文件夹,只会找/usr/lib和/lib所以如果在/etc/ld.so.conf里指定的文件夹,增加了soname link,必须要运行ldconfig来更新ld.so.cache。 

ldconfig -n /path/to/dir 命令可以指定某文件夹,不过只会做第一件事,也就是建立soname link-->实际的共享库文件。不会更新ld.so.cache 所以不需要root权限。 

ldconfig -p 命令可以打印ld.so.conf里已经有的键值对。 

好了,了解了以上知识,我们可以用以下方法解决找不到共享库的问题: 

(a) 将libmymodule.so.1.0.0拷到/lib或者/usr/lib里,或者/etc/ld.so.conf指定的文件夹,然后执行sudo ldconfig. 于是ldconfig会自动在/lib或/usr/lib或/etc/ld.so.conf指定的文件夹里生成soname link (文件名为libmymodule.so.1) 指向libmymodule.so.1.0.0,然后在ld.so.cache中增加libmymodule.so.1到/lib /libmymodule.so.1或/usr/lib/libmymodule.so.1的映射(前者是个名字,后者是个软连接文件) 

(b) 使用LD_LIBRARY_PATH=/PATH/TO/SO ./main来运行程序。前提是在/PATH/TO/SO中建立一个名字为soname的软连接,使其指向实际的共享文件。 

(c) 在/lib或/usr/lib中,手动建立软连接 libmymodule.so.1 令其指向实际的共享库文件 libmymodule.so.1.0.0。 因为前面提到的,加载器在ld.so.cache中找不到要找的键为soname的项,会在/lib或/usr/lib中找名字为soname的文件。这方法虽然可以用,不过感觉比较粗暴。不推荐。

四 升级共享库

如果是用上述(a)方法使用共享库的,只需要将新的共享库,比如 libmymodule.so.1.0.1拷到原来的目录(/lib或/usr/lib或者/etc/ld.so.conf指定的文件夹),然后运行 ldconfig即可。ldconfig会更新soname link, 使其指向最新的共享库文件libmymodule.so.1.0.1,ld.so.cache不需要更新。 

如果是用上述(b)(c)方法是用共享库的,需要更新相应的软连接,使其指向最新的共享库文件。 

 

五 动态加载共享库

在主程序中动态加载共享库时,如果指定的是绝对路径("/"开头的),则加载该绝对路径指向的共享库文件。如果不是绝对路径,而是一个文件名,则将这个文件名当作soname,然后依照上述的方法,查找加载相应的共享库文件。

六 注意点

如果在共享库中,要用到主程序的变量或者方法,要在编译主程序时,加上-rdynamic参数,使得所有名字在共享库的空间中可见。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值