说道“动态库版本兼容”,很多人头脑中首先蹦出的就是“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. 在电子商务里,一般会提到这样几个词:商品、单品、SPU、SKU

    简单理解一下,SPU是标准化产品单元,区分品种:SKU是库存量单位,区分单品:商品特指与商家有关的商品,可对应多个SKU. 首先,搞清楚商品与单品的区别.例如,iphone是一个单品,但是在淘宝上当很 ...

  2. spark ml阅读笔记

    参考文档:http://www.cnblogs.com/huliangwen/p/7491797.html

  3. angularjs之ui-bootstrap的Datepicker Popup不使用JS实现双日期选择控件

    最开始使用ui-bootstrap的Datepicker Popup日期选择插件实现双日期选择时间范围时,在网上搜了一些通过JS去实现的方法,不过后来发现可以不必通过JS去处理,只需要使用其自身的属性 ...

  4. 调用中行接口针对返回报文(xml形式)做相关处理

    最近在对接中行银行接口,在获取返回报文的时候遇到一些问题,现在在这里做个总结 TIP: 在返回报文之前,要对前置机的URL请求,在这期间遇到一个坑,还是通过查看日志才发现问题 在填写转账信息的时候要求 ...

  5. Linux编译ffmpeg

    Linux编译ffmpeg并转换MP3到AMR AMR格式是智能手机上的常用音频文件格式,比如MP3格式的压缩比大,但是文件比MP3小,所以在移动互联项目中应用比较广泛.去年年底协助联想研究院开发一款 ...

  6. emacs 为什么找不到运行程序?

    我记得前段时间有个朋友问我为什么在emacs中打不开matlab程序?明明在terminal下是能打开的,却在emacs中不行. 今天自己最终遇到了相似的问题,我今天安装racket 6.0.安装好后 ...

  7. Python-根据成绩分析是否继续深造

    案例:该数据集的是一个关于每个学生成绩的数据集,接下来我们对该数据集进行分析,判断学生是否适合继续深造 数据集特征展示 GRE 成绩 (290 to 340) TOEFL 成绩(92 to 120) ...

  8. JSTL之C标签学习

    JSTL 核心标签库标签共有13个,功能上分为4类: 1.表达式控制标签:out.set.remove.catch 2.流程控制标签:if.choose.when.otherwise 3.循环标签:f ...

  9. Python数据类型中的字符串类型

    1.换行字符:\n print ('I love python.\nAnd you?') 2.转义字符(\):\\ print ('\\\n\\') 3.制表字符(对齐表格的各列):\t print ...

  10. Node.js笔记(九)Nodejs与shell

    众所周知.Nodejs是单进程异步执行的.但不光是单进程,Nodejs也提供了多进程方面的支持 其创始人应该还是比較重视这一块的,最有力的证据就是child_process是Nodejs核心模块之中的 ...