打酱油的萧萧

一个打酱油的程序员

[转]Linux 如何解决共享库的版本控制

萧萧 posted @ 2011年3月21日 22:50 in Linux with tags LDD lib library linux ldconfig , 3913 阅读

Linux 系统,也同样面临和Window一样的问题,如何控制动态库的多个版本问题。Window之前没有处理好,为此专门有个名词来形容这个问题 “Dll hell”,其严重影响软件的升级和维护。 Dll hell 是指windows 上动态库新版本覆盖旧版本,但是却不兼容老版本。常常发生在程序升级之后,动态库更新,原有程序运行不起来;或者装新软件,但是已有的软件运行不起来。 同样Linux操作系统,也有同样的问题,那么它是怎么解决的呢?

Linux 为解决这个问题,引入了一套机制,如果遵守这个机制来做,就可以避免这个问题。 但是这只事一个约定,不是强制的。但是建议遵守这个约定,否则同样也会出现 Linux 版的Dll hell 问题。 下面来介绍一个这个机制。 这个机制是通过文件名,来控制dll (shared library) 的版本。

Linux 上的Dll ,叫shared library,其有三个名字,分别又不同的目的。

第一个是共享库本身的文件名(real name),其通常包含版本号,常常是是这样: libmath.so.1.1.1234 。 lib是Linux 上的库的约定前缀,math 是共享库名子,so 是共享库的后缀名,1.1.1234的是共享库的版本号,其主版本号+小版本号+build号。主板号,代表当前动态库的版本,如果动态库的接口有变化,那么这个版本号就要加1;后面的两个版本号(小版本号 和 build 号)是告诉你详细的信息,比如为一个hot-fix 而生成的一个版本,其小版本号加1,build号也应有变化。 这个文件名包含共享库的代码。

第二个是动态库的soname( Short for shared object name),其是应用程序加载dll 时候,其寻找共享库用的文件名。其格式为:lib + math+.so + ( major version number)

其只包含major version number,换句话说,也就是只要其接口没有变,应用程序都可以用,不管你其后minor build version or build version。问题来了,程序运行时怎么通过soname 找个real name? Soname 存在哪里?如果与real name 关联起来?什么时候存的?

这就是接下来要介绍的第三个共享库的名字,link name,顾名思义,就是在编译过程,link 阶段用的文件名。 其将sonmae 和real name 关联起来。

第三个名字,共享库的连接名(link name),是专门为build 阶段连接而用的名字。这个名字就是lib + math +.so ,比如libmath.so。其是不带任何版本信息的。在共享库编译过程中,连接(link) 阶段,编译器将生成一个共享库及real name,同时将共享库的soname,写在共享库文件里的文件头里面。可以用命令 readelf -d sharelibrary 去查看。

在应用程序引用共享库时,其会用到共享库的link name。在应用程序的link阶段,其通过link名字找到动态库,并且把共享库的soname 提取出来,写在自己的共享库的头里面。当应用程序加载时候就会通过soname 去在给定的路径下寻找该共享库。

下面通过这个代码来说明一下系统是如何做的,并且介绍系统的一些设施和工具:

/* hello.c - demonstrate library use. */
#include <stdio.h>
void hello(void) {
  printf("Hello, library world.\n");
}
/* libhello.h - demonstrate library use. */
void hello(void);
/* main.c -- demonstrate direct use of the "hello" routine */
#include "hello.h"
int main(void) {
  hello(); 
  return 0;
}
 
1.生成共享库,关联real name 和soname 。
     gcc -g -Wall -fPIC -c hello.c -o hello.o
     gcc -shared -W,soname,-libhello.so.0 -o libhello.so.0.0.0 hello.o
     将会生成共享库libhello.so.0.0.0.
     可以用系统提供的工具查看共享库的头:
      readelf -d libhello.so.0.0.0 | grep libhello
ox00000000000e(SONAME)    library soname: [libhello.so.0]
 
2.应用程序,引用共享库。
      先手动生成link 名字,以被后面的程序链接时用
      ln -s libhello.so.0.0.0 libhello.so.0
      gcc -g -Wall -c main.c -o main.o -I.
      gcc  -o main main.o -lhello -L.
      查看编译出来的程序:
      readelf -d main | grep libhello
ox000000000001(NEEDED)    shared library: [libhello.so.0]
 
      运行该程序,需要指定共享库的路径。 有两种办法,第一种使用环境变量“LD_LIBRARY_PATH”. 两外一种办法就是将共享库拷贝到系统目录(path 环境变量指定的其中一个目录)。
      
      暂停! 我们还没有解决一个问题是,程序只知道soname,怎么从soname 找到共享库,即real name 文件呢? 这需要我们定义一个link文件,连接到共享库本身。
      ln -s libhello.so.0.0.0 libhello.so.0
     当然这个路径需要放到LD_LIBRARY_PATH环境变量中。
     这样就可以运行该程序。
 
[Note]Linux 系统提供一个命令 ldconifg 专门为生成共享库的soname 文件,以便程序在加载时后通过soname 找到共享库。 同时该命令也为加速加载共享库,把系统的共享库放到一个缓存文件中,这样可以提高查找速度。可以用下面命令看一下系统已有的被缓存起来的共享库。
     ldconfig -p
 
3.共享库,小版本升级,即接口不变.
      当升级小版本时,共享库的soname 是不变的,所以需要重新把soname 的那个连接文件指定新版本就可以。 调用ldconfig命令,系统会帮你做修改那个soname link文件,并把它指向新的版本呢。这时候你的应用程序就自动升级了。
 
4.共享库,主版本升级,即接口发生变化。
       当升级主版本时,共享库的soname 就会加1.比如libhello.so.0.0.0 变为 libhello.so.1.0.0. 这时候再运行ldconfig 文件,就会发现生成两个连接 文件。
    ln -s libhello.so.0---->libhello.so.0.0.0
    ln -s libhello.so.1----->libhello.so.1.0.0
尽管共享库升级,但是你的程序依旧用的是旧的共享库,并且两个之间不会相互影响。
 
      问题是如果更新的共享库只是增加一些接口,并没有修改已有的接口,也就是向前兼容。但是这时候它的主版本号却增加1. 如果你的应用程序想调用新的共享库,该怎么办? 简单,只要手工把soname 文件修改,使其指向新的版本就可以。(这时候ldconfig 文件不会帮你做这样的事,因为这时候soname 和real name 的版本号主板本号不一致,只能手动修改)。
      比如: ln -s libhello.so.0 ---> libhello.so.1.0.0
      
但是有时候,主版本号增加,接口发生变化,可能向前不兼容。这时候再这样子修改,就会报错,“xx”方法找不到之类的错误。
总结一下,Linux 系统是通过共享库的三个不同名字,来管理共享库的多个版本。 real name 就是共享库的实际文件名字,soname 就是共享库加载时的用的文件名。在生成共享库的时候,编译器将soname 绑定到共享库的文件头里,二者关联起来。 在应用程序引用共享库时,其通过link name 来完成,link时将按照系统指定的目录去搜索link名字找到共享库,并将共享库的soname写在应用程序的头文件里。当应用程序加载共享库时,就会通过soname在系统指定的目录(path or LD_LIBRARY)去寻找共享库。
    
当共享库升级时,分为两种。一种是主板本不变,升级小版本和build 号。在这种情况下,系统会通过更新soname( ldconfig 来维护),来使用新的版本号。这中情况下,旧版本就没有用,可以删掉。另外一种是主版本升级,其意味着库的接口发生变化,当然,这时候不能覆盖已有的soname。系统通过增加一个soname(ldconfig -p 里面增加一项),使得新旧版本同时存在。原有的应用程序在加载时,还是根据自己头文件的旧soname 去寻找老的库文件。
 
5.如果编译的时候没有指定,共享库的soname,会怎么样?
    
这是一个trick 的地方。第一系统将会在生成库的时候,就没有soname放到库的头里面。从而应用程序连接时候,就把linkname 放到应用程序依赖库里面。或者换句话说就是,soname这时候不带版本号。 有时候有人直接利用这点来升级应用程序,比如,新版本的库,直接拷贝到系统目录下,就会覆盖掉已经存在的旧的库文件,直接升级。 这个给程序员很大程度的便利性,如果一不小心,就会调到类似windows的Dll hell 陷阱里面。建议不要这样做。
 
【Note】
  1. 指定共享库加载的路径。LD_LIBRARY_PATH 优先与 path 环境变量。
  2. ldd 可以查看程序,或者共享库依赖的库的路径
  3. nm 查看共享库暴露的接口
  4. ldconfig 可以自动生成soname 的连接文件。并提供catch 加速查找。
  5.readelf 可以查看动态库的信息,比如依赖的库,本身的somae。
  6. objdump 与readelf 类似。
  7 ld The GUN linker
  8. ld.so  dynamic linker or loader
  9. as the portable GNU assembley
【Reference】

 

Avatar_small
doyle 说:
2011年3月22日 08:56

总算明白为什么linux没人提dll hell了,原来是已经找到解决方法来.理解了.谢谢

Avatar_small
纵横天下 说:
2011年3月22日 21:37

“如果一步小心”
步->不?

Avatar_small
AzureSky 说:
2011年3月22日 21:46

@纵横天下: 这都给你发现,哎呀

Avatar_small
依云 说:
2011年3月23日 16:24

应该是 ldconfig -p 不是 ld 哦~

addicting games 说:
2018年8月17日 17:32

I enjoyed over read your blog post. Your blog have nice information I got good ideas from this amazing blog. I am always searching like this type blog post. I hope I will see again..

WE T1 说:
2018年9月12日 21:47

Your blog is very helpful.

vex 说:
2018年10月11日 17:50

Thank you for sharing this post. I enjoyed your post. I will regularly visit your blog.

www.hotmail.com 说:
2018年10月18日 10:20

Thank you so much. This is what I need to find. Hope to see more updates on the blog.

hotmail.com 说:
2018年11月15日 11:02

Thank you very much for publishing this kind of article. I like your article a lot. I actually want to share my website details with you please produce some information to increase performance like as your website.

CSUF Portal 说:
2019年5月24日 23:11

Thanking you will not be enough. This is really good. You are just exceptional.
Keep doing the good work

Lee Andrews 说:
2019年6月16日 12:26

Thanks for such very great information. This is the best sites for proving such kinds of good information Also visit my site
http://wellsfargoroutingnumber.strikingly.com/blog/legit-way-to-find-your-well-fargo-routing-number

<a href="http://wellsfargoroutingnumber.strikingly.com/blog/legit-way-to-find-your-well-fargo-routing-number/"> wells fargo routingnumber</a>

Bobby Graves 说:
2019年6月24日 11:32

Really, simple and great post, I like author’s writing skills.The article is well described and useful for everyone, keep writing articles like this

kindly have a look on below link i hope it will be very useful for you

https://routingnumberusbank.blogspot.com/2019/05/a-steering-number-is-critical-number.html

<a href="https://routingnumberusbank.blogspot.com/2019/05/a-steering-number-is-critical-number.html">routing number usbank</a>

Staci S. Phillips 说:
2019年7月18日 07:35

I would say your article is so interesting and informative for me and this article explained everything in detail. You have done a superb job thanks for sharing this kind of stuff with us.

purevpn vs nordvpn 说:
2019年9月30日 20:03

these files can be shared in an encrypted form. However, this technology is not used by every VPN network see more purevpn vs nordvpn

Red 说:
2019年12月03日 09:50

So dear, the day we left I have to promise you a word I'll find a place That is only fun.happy wheels run 3

Vidmate 说:
2019年12月20日 13:48

Vidmate is super cool and feasible to use, but you won’t find it easily on Google Play store.

Tellthebell 说:
2019年12月20日 13:49

Tellthebell is offering its customers a chance to win $500 by completing its customer’s satisfaction survey.

www.Gmail.com 说:
2020年3月19日 19:08

Having email is a essential thing when you use internet, but to use email more effectively is not easy, www.Gmail.com has the tutorial and tips you need.

kuttyrockers 说:
2020年11月26日 19:39

Thank you very much for publishing this kind of article. I like your article a lot. I actually want to share my website details with you please produce some information to increase performance like as your website.

Motion sensor light 说:
2022年5月16日 17:21

Thank you so much for sharing all this wonderful info!!!! It is so appreciated!!!

pavzi.com 说:
2024年1月27日 15:37

Pavzi.com provides all the news about Gadgets, the Economy, Technology, Business, Finance and many more. The main concept or our aim behind this website has been the will to provide resources with full information on each topic which can be accessed through the Internet. To ensure that every reader gets what is important and worthy about the topic they search and link to hear from us. pavzi.com Our site is a multiple Niche or category website which will ensure to provide information and resources on each and every topic. Some of the evergreen topics you will see on our website are Career, Job Recruitment, Educational, Technology, Reviews and others. We are targeting mostly so it is true that Tech, Finance, and Product Reviews. The only reason we have started this website is to make this site the need for your daily search use.

seo service london 说:
2024年2月27日 19:58

Nice post. I was checking constantly this blog and I am impressed! Extremely helpful information specially the last part I care for such info a lot. I was seeking this particular information for a very long time.

celebsagewiki 说:
2024年3月26日 19:39

Checking out the information of any celebrity on famous celebrities to know how much their name and fame worth and their family members.


登录 *


loading captcha image...
(输入验证码)
or Ctrl+Enter