静态库与共享库

      在用c c++编程时经常用到库,库有静态的,和共享库。在这里我只是说linux系统下的静态库和共享库。有人把共享库称为“动态库”,这是相对于“静态库”而言的,是为了说明在程序链接它时的不同。不过从更宏观的层次上叫它共享库更贴切。

 

用例子说明吧:

 

现在有这几个文件:

 

                    zerg.h     zerg.cpp       hydralisk.h     hydralisk.cpp       

 

需要用库的形式提供。

 

制作静态库:

 

1.编译

 

 

gcc -c zerg.cpp hydralisk.cpp

 

 

 

编译出zerg.o hydralisk.o

然后用一个命令“ar”,把所有的.o文件打包,生成静态库libzerg.a

 

2.打包 

 

 

ar -qcs -o libzerg.a zerg.o hydralisk.o

 

 

 

 

总结:可见,静态库就是对一些.o文件的打包而已。只编译,不链接。提供静态库其实不太实用,一般都是提供共享库,如果需要调试的话,就直接提供源码好了。静态库的优势仅仅是比共享库效率高一小点。

 

制作共享库:

 

1.编译

 

g++ -fPIC -c zerg.cpp hydralisk.cpp

 

 

编译出zerg.o hydralisk.o。 和上面编译静态库时不同的是,需要指定"-fPIC"选项。 PIC(position indepedent code) , 共享库在运行时链接,不能预先知道装载的内存地址,所以要用-fPIC告诉编译器。

 

2. 链接

 

 

g++ -shared -o libzerg.so.1.0.0 zerg.o hydralisk.o

 

 

这样就生成了共享库libzerg.so.1.0.0

 

这两步都是用g++完成的,所以两步可以合成一步,如下命令可以直接把源码编译成共享库:

 

一步生成:

 

g++ -shared -fPIC -o libzerg.so.1.0.0 zerg.cpp hydralisk.cpp

 

 

共享库的版本控制:

 

 

 

 

 

 

 参考资料:

共享库的版本控制段落摘自:

http://cache.baidu.com/c?m=9f65cb4a8c8507ed4fece7631046893b4c4380146d96864968d4e414c42246091138e0b924260d57938327365ff8540abdb6652969423db39bcc8849dbb8866d72c8713b3547da174f9658b8cb3732b12b872ae9b86893ad874484afa2c4af2044bd53127af1e7fb581763ce7880172693d18e49654860cefa466fe82f733eee27&p=c96ad615d9c044e90be290121100&user=baidu&fm=sc&query=windows+%B9%B2%CF%ED%BF%E2+%B0%E6%B1%BE%BF%D8%D6%C6&qid=d6505642138c09ac&p1=10

 

linux下的so文件不具有像windows下的额外属性。为了标识一个so的版本,gcc链接生成so目标时一般都采用libxxx.so.1.0.0的方式。

这样把so的版本信息记录在文件名里面。这个带版本信息的文件名就是realname。

 

那么exe可执行文件如何记录自己依赖的so呢,如果记录的是so的realname,那么so有新版本升级时,新的so必定具有不同的realname,exe就无法自动使用更新的so了。

好在linux下有软链这样的机制可以解决该问题。exe中不必记录依赖的so的realname,exe中记下一个指向实际realname的软链即可,这个软链就是soname啦。soname一般采用这样的名字 libxxx.so.1(保留大版本号1)

当有一个功能更新的so发布时,只需修改soname软链,指向升级后的realname文件即可。

比如我发布了xxx动态库的升级版 libxxx.so.1.0.1, 使软链libxxx.so.1指向libxxx.so.1.0.1即可。

soname是我们在编译其他程序时,往其他程序的二进制映像里面写入的共享库的名字。

 

那么什么是linkname呢?顾名思义,就是编译代码时的链接阶段使用的,比如我有一个程序需要链接libxxx.so.1.0.0库,

makefile需这样写 -lxxx.so.1.0.0,这r样写实在很长也很丑,而且如果后续libxxx有更新时,必须修改makefile文件才能链接到新的库上。

所以出现了一个新的链接到realname的软链,这个软链就叫 linkername。通常lingkername是不带任何版本信息的,取名如下 libxxx.so

这样makefile就变成了 -lxxx.so

 

这其中有一个问题,动态库的使用者(比如exe)是通过linkername链接的,而lingkername指向的是so的realname,我们前文说为了解决升级so重新编译的问题,exe文件里面记录的是其依赖的so的soname名字,而不是真实的realname,

那么exe是如何知道realname对应的soname呢?

答案在realname文件里面,在编译链接生成realname时, 同事也指定了其对应的soname,这个soname存储在realname的文件里面。

eg 如下编译命令:

gcc -g -Wall -shared -Wl,-soname,liberr.so.1 -o liberr.so.1.0.0 liberr.o -lc  // liberr.so.1是soname,将记录在生成的liberr.so.1.0.0文件里面

可以通过如下工具查看一个realname的so的对应的soname:

readelf -d ./liberr.so.1.0.0 

Dynamic section at offset 0xf10 contains 22 entries:

  Tag        Type                         Name/Value

 0x00000001 (NEEDED)                     Shared library: [libc.so.6]

 0x0000000e (SONAME)                     Library soname: [liberr.so.1] ===============< 其soname

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值