Chinaunix首页 | 论坛 | 博客
  • 博客访问: 308324
  • 博文数量: 40
  • 博客积分: 1
  • 博客等级: 民兵
  • 技术积分: 670
  • 用 户 组: 普通用户
  • 注册时间: 2011-07-31 11:19
个人简介

从事银行核心系统设计开发的程序猿

文章存档

2019年(1)

2018年(4)

2017年(11)

2016年(6)

2015年(18)

分类: C/C++

2017-05-23 06:36:35

    世界上唯一不变的是变化,对于动态连接库更是如此。动态库天生为方便程序的更新而设计,只需要替代库文件,无需重新编译主程序,即可运行更新后的版本。另外,动态库是多应用共享的,多个程序使用同一个库,那么库只会加载一份。
    但是,现实往往不这么简单。既然动态库有新版本,那就会有与旧版本兼容或者不兼容的情况出现。当系统里存在多个使用此动态库的应用程序时,如果是兼容旧版本的更新还好,如果是不兼容,那么使用旧版本的应用程序就会受影响不能正常运行。特别的,当动态库集中放在系统指定的库目录下时(windows的system32),版本的冲突就形成了著名的“windows dll hell”。


    为了解决这个问题,很多UNIX系统使用了ELF格式的DT_SONAME字段来应对。例如,linux的ld命令中,就有这么一个选项。
       -h name
       -soname=name
           When creating an ELF shared object, set the internal DT_SONAME
           field to the specified name.  When an executable is linked with a
           shared object which has a DT_SONAME field, then when the executable
           is run the dynamic linker will attempt to load the shared object
           specified by the DT_SONAME field rather than the using the file
           name given to the linker.
    表示使用-h或者-soname选项,可以在动态库里指定DT_SONAME字段,保存运行时查找的动态库名字,使得编译时和运行时动态库名可以不同。例如,编译libwel.so时使用-soname=libwel.so.1,那么编译可执行程序时-lwel,连接libwel.so,会记录运行时在搜索路径查找libwel.so.1加载。

    ELF是一种应用非常广泛的二进制目标格式,与之类似的,UNIX的二进制目标还有a.out格式(SCO UNIX),XCOFF格式(AIX)。这两种格式就无法支持soname了。


    那么,如何使多个版本的动态连接库同时支持呢,总结一下使用这种命名方式既可以新旧不兼容版本共存,又可以兼容版本正常升级。动态库命名为libxxx.so.n.m,soname名为libxxx.so.n,建立软连接libxxx.so指向最新的n版本libxxx.so.n供编译可执行程序使用,建立软连接libxxx.so.n指向版本n最新的m版本。这样,n的变化表示不兼容旧版本的改动,相同n下m的变化表示兼容n版本的改动。
    还是以libwel.so举例。1.0版本的wel.c提供的函数void welcome(void) { printf("aaa\n"); },编译成库libwel.so.1.0,soname为libwel.so.1。建立软连接libwel.so.1,libwel.so。使用1.0库的主程序main1.c调用welcome(),编译成main1程序。1.1版本的wel.c改成void welcome(void) { printf("bbb\n"); },动态库只修改内部实现,对外接口兼容1.0版本,编译成库libwel.so.1.1。此时更新软连接libwel.so.1为libwel.so.1.1,主程序main1无需变动,即可输出更新后的bbb。2.0版本的wel.c改变了对外接口,提供的函数void welcome(char *p) { printf("%s\n",p); }。编译成库libwel.so.2.0,soname为libwel.so.2。建立软连接libwel.so.2,libwel.so。使用2.0库的主程序main2.c应以一个参数调用welcome("test")。main1和main2主程序互不兼容,必须分别调用版本1和版本2的库。此时,库目录下存在libwel.so.1指向1.1版本,libwel.so.2指向2.0版本,main1会连接1.1版本运行,main2会连接2.0版本运行。由此可见,小版本升级时应用程序自动使用最新版本,大版本升级时,使用旧版本的“过时”应用程序不受影响,从而避免了动态库版本的混乱。


    同样,以link方式为例,给出各UNIX平台加设soname的动态库编译方法。(AIX不支持)

 linux:
  编译libwel.so:
   gcc -fPIC -shared -Wl,-soname,libwel.so.1 -o libwel.so.1.0 wel.c -lc
   ln -sf libwel.so.1.0 libwel.so.1
   ln -sf libwel.so.1 libwel.so
    -Wl,-soname,libwel.so.1 指定libwel.so.1.0的实际soname为libwel.so.1


 sco unix open server:
  编译libwel.so:
   cc -K pic -G -h libwel.so.1 -o libwel.so.1.0 wel.c -lc
   ln -sf libwel.so.1.0 libwel.so.1
   ln -sf libwel.so.1 libwel.so
    -h libwel.so.1 指定libwel.so.1.0的实际soname为libwel.so.1


 HP UX:
  编译libwel.so:
   cc +z -c wel.c
   ld -b -o libwel.sl.1.0 wel.o +h libwel.sl.1 -lc
   ln -sf libwel.sl.1.0 libwel.sl.1
   ln -sf libwel.sl.1 libwel.sl
    +h libwel.sl.1 指定libwel.sl.1.0的实际soname为libwel.sl.1


 SUN OS:
  编译libwel.so:
   cc -G -h libwel.so.1 -o libwel.so.1.0 wel.c -lc
   ln -sf libwel.so.1.0 libwel.so.1
   ln -sf libwel.so.1 libwel.so
    -h libwel.so.1 指定libwel.so.1.0的实际soname为libwel.so.1


阅读(3249) | 评论(1) | 转发(0) |
给主人留下些什么吧!~~

pacman20002019-08-08 10:19:52

AIX运行过动态库后,再重新编译,会报错正在被使用不能覆盖,这是因为系统加载了缓存没有释放,这时候需要以root权限执行slibclean命令,即可清理释放无人使用的动态库。