说道“动态库版本兼容”,很多人头脑中首先蹦出的就是“Dll Hell”。啊,这曾经让人头疼的难题。时至今日,这个难题已经很好地解决了。
 
在进一步讨论之前来思考一个问题:Linux下为什么没有让人头痛的“DllHell”?
回答这个问题,非常easy,因为——Linux下根本没有dll!
 
哈哈,当然这只是个玩笑,接下来展开一下这个话题,很多有动态库的系统都会面临这个难题,但各自解决的思路却各不相同。
 
Dll hell是指windows 上动态库新版本覆盖旧版本,但是却不兼容老版本。常常发生在程序升级之后,动态库更新,原有程序运行不起来;或者装新软件,但是已有的软件运行不起来。
 
一、linux下的解决方案——命名规范
Linux 上的Dll ,叫sharedlibrary。Linux 系统面临和Window一样的问题,如何控制动态库的多个版本问题。为解决这个问题,Linux 为解决这个问题,引入了一套命名机制,如果遵守这个机制来做,就可以避免这个问题。但是这只事一个约定,不是强制的。但是建议遵守这个约定,否则同样也会出现 Linux 版的Dll hell 问题。
 
Real Name
首先是共享库本身的文件名:共享库的命名必须如 libname.so.x.y.z
最前面使用前缀”lib”,中间是库的名字和后缀”.so”,最后三个数字是版本号。x是主版本号(Major Version Number),y是次版本号(Minor Version Number),z是发布版本号(Release Version Number)。
 
主版本号(不兼容):重大升级,不同主版本的库之间的库是不兼容的。所以如果要保证向后兼容就不能删除旧的动态库的版本。
 
次版本号(向下兼容): 增量升级,增加一些新的接口但保留原有接口。高次版本号的库向后兼容低次版本号的库。
 
发布版本号(相互兼容):库的一些诸如错误修改、性能改进等,不添加新接口,也不更改接口。主版本号和此版本号相同的前提下,不同发布版本之间完全兼容。
 
SO-NAME
严格遵守上述规定,确实能避免动态库因为版本冲突的问题,但是读者可能有疑问:在程序加载或运行的时候,动态链接器是如何知道程序依赖哪些库,如何选择库的不同版本?
Solaris和Linux等采用SO-NAME( Shortfor shared object name )的命名机制来记录共享库的依赖关系。每个共享库都有一个对应的“SO-NAME”(共享库文件名去掉次版本号和发布版本号)。比如一个共享库名为libtest.so.3.8.2,那么它的SO-NAME就是libtest.so.3。
 
 
在Linux系统中,系统会为每个共享库所在的目录创建一个跟SO-NAME相同的并且指向它的软连接(Symbol Link)。这个软连接会指向目录中主版本号相同、次版本号和发布版本号最新的共享库。也就是说,比如目录中有两个共享库版本分别为:/lib/libtest.so.3.8.2和/lib/libtest.so.3.7.5,么软连接/lib/libtest.so.3指向/lib/libtest.so.3.8.2。
 
建立以SO-NAME为名字的软连接的目的是,使得所有依赖某个共享库的模块,在编译、链接和运行时,都使用共享库的SO-NAME,而不需要使用详细版本号。在编译生产ELF文件时候,如果文件A依赖于文件B,那么A的链接文件中的”.dynamic”段中会有DT_NEED类型的字段,字段的值就是B的SO-NAME。这样当动态链接器进行共享库依赖文件查找时,就会依据系统中各种共享库目录中的SO-NAME软连接自动定向到最新兼容版本的共享库。
 
★  readelf -d sharelibrary 可以查看so-name
★  Linux提供了一个工具——ldconfig,当系统中安装或更新一个共享库时,需要运行这个工具,它会遍历默认所有共享库目录,比如/lib, /usr/lib等,然后更新所有的软链接,使她们指向最新共享库。
 
Link Name
 
当我们在编译器里使用共享库的时候,如用GCC的“-l”参数链接共享库libtXXX.so.3.8.1,只需要在编译器命令行指定 -l XXX 即可,省略了前缀和版本信息。编译器会根据当前环境,在系统中的相关路径(往往由-L参数指定)查找最新版本的XXX库。这个XXX就是共享库的“链接名”。不同类型的库可能有相同的链接名,比如C语言运行库有静态版本(libc.a)也动态版本(libc.so.x.y.z)的区别,如果在链接时使用参数”-lc”,那么连接器就会根据输出文件的情况(动态/静态)来选择合适版本的库。eg. ld使用“-static”参数时吗,”-lc”会查找libc.a;如果使用“-Bdynamic”(默认),会查找最新版本的libc.so.x.y.z。
 
更详细可以参见
http://www.linuxidc.com/Linux/2012-04/59071.htm
 
 
.Net下的解决方案——Manifest文件
.Net框架中,一个程序集(Assembly)有两种类型:应用程序程序集(.exe)与库程序集(DLL动态链接库)。一个程序集包括一个或个文件,所以需要一个清单文件(Manifest文件)来描述程序集。Manifest文件描述了程序集的名字,版本号以及程序集的各种资源,同时也描述了该程序集的运行所依赖的资源,包括DLL以及其他资源文件等。Manifest是一个XML文件。每个DLL有自己的Manifest。对于应用程序而言,manifest文件可以和可执行文件在同一目录,也可以作为一个资源嵌入到可执行文件内部(Embed Manifest)。
 
XP以前的windows版本,在执行可执行文件是不会考虑manifest文件的。它会直接到system32目录下查找可执行文件锁依赖的DLL。在这种情况下,manifest是多余的。XP之后的操作系统,在执行可执行文件时则会首先读取程序集的manifest文件,获得该可执行文件需要调用的DLL列表,操作系统再根据DLL的manifest文件去寻找对应的DLL调用。
 
 
Windows的解决方案——COM组件
采用标准COM组件,有很多好处:面向接口和对象编程语言无关性,采用二进制标准,可以实现跨语言调用版本升级方便,增加新接口,组件升级后老客户程序不用重新编译位置透明,客户程序不用关心组件的位置重用方便,通过包容和聚合可以快速重用已有组件我们可以看到标准COM组件非常强大,但是很多时候我们并不需要标准COM组件的所有特性,比如我们不希望引入注册表,也不希望引入COM运行库,我们希望我们的程序是完全“绿色”的。这时我们就会采用“COM思想架构“开发非标准的COM组件。

转自 http://blog.sina.com.cn/s/blog_5cf54f0e0101cpct.html

解决Linux动态库版本兼容问题的更多相关文章

  1. 技巧:Linux 动态库与静态库制作及使用详解

    技巧:Linux 动态库与静态库制作及使用详解 标准库的三种连接方式及静态库制作与使用方法 Linux 应用开发通常要考虑三个问题,即:1)在 Linux 应用程序开发过程中遇到过标准库链接在不同 L ...

  2. .netcore在linux下使用P/invoke方式调用linux动态库

    http://www.mamicode.com/info-detail-2358309.html   .netcore下已经实现了通过p/invoke方式调用linux的动态链接库(*.so)文件 1 ...

  3. linux动态库编译和使用

    linux动态库编译和使用详细剖析 引言 重点讲述linux上使用gcc编译动态库的一些操作.并且对其深入的案例分析.最后介绍一下动态库插件技术, 让代码向后兼容.关于linux上使用gcc基础编译, ...

  4. windows动态库与Linux动态库

    Linux动态库和windows动态库的目的是基本一致的,但由于操作系统的不同,他们在许多方面还是不尽相同.但是尽管有差异Linux动态库的windows动态库还是可以移植的,有一些规则以及经验是必须 ...

  5. linux动态库编译和使用详细剖析 - 后续

    引言 - 也许是修行 很久以前写过关于动态库科普文章, 废话反正是说了好多. 核心就是在 linux 上面玩了一下 dlopen : ) linux动态库编译和使用详细剖析 - https://www ...

  6. LINUX动态库(.SO)搜索路径(目录)设置方法

    LINUX动态库(.SO)搜索路径(目录)设置方法 [root@VM_0_11_centos ld.so.conf.d]# cat /etc/ld.so.confinclude ld.so.conf. ...

  7. linux动态库默认搜索路径设置的三种方法

    众所周知, Linux 动态库的默认搜索路径是 /lib 和 /usr/lib .动态库被创建后,一般都复制到这两个目录中.当程序执行时需要某动态库, 并且该动态库还未加载到内存中,则系统会自动到这两 ...

  8. linux动态库加载RPATH, RUNPATH

    摘自http://gotowqj.iteye.com/blog/1926771 linux动态库加载RPATH, RUNPATH 链接动态库 如何程序在连接时使用了共享库,就必须在运行的时候能够找到共 ...

  9. Android NDK开发及调用标准linux动态库.so文件

    源:Android NDK开发及调用标准linux动态库.so文件 预备知识及环境搭建 1.NDK(native development Kit)原生开发工具包,用来快速开发C.C++动态库,并能自动 ...

随机推荐

  1. Cisco交换机SPAN&RSPAN调试实录

    Cisco交换机SPAN&RSPAN设置实录   本文出自 "李晨光原创技术博客" 博客,请务必保留此出处http://chenguang.blog.51cto.com/3 ...

  2. BZOJ 3675 APIO2014 序列切割 斜率优化DP

    题意:链接 方法:斜率优化DP 解析:这题BZ的数据我也是跪了,特意去网上找到当年的数据后面二十个最大的点都过了.就是过不了BZ. 看到这道题自己第一发DP是这么推得: 设f[i][j]是第j次分第i ...

  3. hdu 1588 Gauss Fibonacci(矩阵嵌矩阵)

    题目大意: 求出斐波那契中的 第 k*i+b 项的和. 思路分析: 定义斐波那契数列的矩阵 f(n)为斐波那契第n项 F(n) = f(n+1) f(n) 那么能够知道矩阵 A = 1 1 1  0 ...

  4. 互联网+时代IT管理者的转型

    最近,大众创业万众创新的热潮真是一浪接着一浪,它实际上是一次政府和企事业的自我改革,利用互联网+的思维与技术对生产模式.流通模式与运营模式进行全新的变革,商业的本质是没有变的,仅仅是穿了个马甲来表演. ...

  5. 从USB闪存驱动器启动 Hiren的BootCD --制作U盘启动盘

    从USB闪存驱动器启动 Hiren的BootCD 原文  http://www.hirensbootcd.org/usb-booting/ 本文基本上是翻译而来 要从USB闪存驱动器启动Hiren的B ...

  6. 在Qt Creator的项目中添加头文件和库

    在Qt Creator中的工程中,工程通过.pro文件管理. 额外需要连接的连接库unix:LIBS += -L your_lib_path -lyour_libwin32:LIBS += your_ ...

  7. 微信小程序简单常见首页demo

    wxml <view class='index-contier'> <view class="index-left"> <view>电池剩余&l ...

  8. geotools修改shapefile 属性名乱码问题

    在GeoServer中文社区的讨论地址为:http://opengeo.cn/bbs/read.php?tid=1701&page=e&#a 使用geotools修改shapefile ...

  9. Dao层封装泛型实现(spring mvc,springjdbctemplate)

    代码片段(6) [全屏查看所有代码] 1. [代码]BaseDao     跳至 [1] [2] [3] [4] [全屏预览] ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 1 ...

  10. [Node.js] Serve Static Files with Express

    In this lesson we will find out how to serve static assets (images, css, stylesheets, etc.) with Exp ...