linux下动态库的版本号

据说linux下的动态库管理机制可以避免微软件DLL Hell的问题.

今天抽了点时间研究了一下, 发现其实本质上是利用别名(soname)技术来实现的.

在编译so文件时, 通过参数-soname将别名传入链接器ld(gcc可通过参数-Wl来将-soname参数传入链接器), 那么生成的动态库文件中Dynamic section中的SONAME将会被填入输入的别名. 如果没有-soname参数, 则Dynamic section中将不会有SONAME字段生成.

当使用命令gcc -g -Wall -o main -L. -lver时, 在进行链接时, 链接器ld会首先去当前目录查找libver.so, libver.so也被称为链接名字, 链接器会提取libver.so中的SONAME字段中的名字作为运行时要加载的动态库的名字, 如果没有SONAME字段则使用链接名字作为运行时要加载的动态库的名字(可通过readelf -d file来查看).

linux下为了更方便我们管理动态库, 提供了ldconfig程序. ldconfig的主要功能就是搜索/lib, /usr/lib, /etc/ld.so.conf内所列的目录, 提取动态库的SONAME,并将其作为软链接的名字来建立软链接, 以使程序运行时可以按别名加载.


一个具体例子来说明上述机制是怎么避免DLL Hell问题.

可执行文件main中依赖于一个动态库liba.so.
编译liba.so时可以使用gcc -g -Wall –shared -fPIC -o liba.so sourcefiles -Wl,-soname,liba.so.1来生成liba.so
编译main时可以使用gcc -g -Wall -o main -L. -la, 链接时依来liba.so动态库, 运行时依赖的实际上是liba.so.1文件(liba.so文件的别名)

当main程序发布时, 附带的动态库文件名为liba.so.1.1.3(SONAME为liba.so.1), 安装程序时将liba.so.1.1.3拷贝到/usr/lib/目录下, 然后运行ldconfig, 将会自动生成liba.so.1的软连接指向liba.so.1.1.3.
如果以后liba.so有bug修改且没有接口修改(兼容之前发布的main程序), 那么单独发布liba.so.1.2.1 (SONAME为liba.so.1) 文件并将其拷内到/usr/lib/目录下运行ldconfig, ldconfig会自动更新软连接liba.so.1指向liba.so.1.2.1.

如果是使用dlopen动态加载则直接使用dlopen(“liba.so.1”, xxx)来指定所需要的动态库的主版本号即可.

这样就避免了多个版本的动态库相互覆盖的问题, 也就从根本上避免了DLL Hell的问题.



发表评论