在用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
共享库的版本控制:
参考资料:
共享库的版本控制段落摘自:
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