Linux下的共享库类似windows下的dll,共命令约定如下:
静态库一般由字母 lib 开头,并有 .a 的扩展名,而共享对象有两个不同的名称:soname 和 real name。
soname 包含前缀 "lib",然后紧跟库名,其次是 ".so"(后面紧跟另一个圆点),以及表明主版本号的数字。
soname 可以由前缀的路径信息来限定。real name 是包含库的已编译代码的真正文件名。
real name 在 soname 后添加一个圆点、小的数字、另外一个圆点和发布号。格式如下:
libxxxx.so.major.minor
其中,xxxx是库的名字,major是主版本号,minor 是次版本号或叫发布号,次版本号和其相应的圆点是可选的。
soname是记录在共享库中的,其它库使用这个共享库时,实际上只需要的提供soname,动态链接器会找到名称是soname的动态库给程序使用。
这种带版本号的共享库主要是为了你可以很方便的升级你的函数库,如果某个API改变了,创建库的程序会改变主版本号,然而,如果一个函数升级了某个函数库,而功能没有发生变化,这时只需要改变次版本号,由于只改变了次版本号,所以soname没有发生改变,这样就可以做到与旧的共享库保持兼容。
下面简要说明动态库的编写过程:
/* file libhello.h - for example use! */
void printhello();
库的代码很基本,在下一个清单中显示。
/* file libprint.c */
#include "stdio.h"
void printhello()
{
printf("hello opendba/n");
}
$ gcc -fPIC -c libhello.c
$ ld -shared -soname libhello.so.1 -o libhello.so.1.0 -lc libhello.o
-soname也可以用-h代替。
注意,gcc 命令行中的 -fPIC 选项。这是生成 Position-Independent Code 所必须要的。把这个命令翻译出来就是:生成可以在进程的进程空间的任何地方载入的代码。这对于共享对象是非常重要的。使用这个选项,使得必须执行重定位的数量降低到最少。一旦载入可执行程序使用的共享对象,就必须给它分配一些空间。必须给文本和数据部分配一些位置。如果它们不是以“位置独立”方式来构建,那么载入共享对象时,程序要做大量的重定位,这会影响到性能。
现在我们分析一下传给 ld 的选项。-shared 选项表明输出的文件被认为是共享的库。通过 -soname name 选项,可以指定 soname 是什么。-o name 指定了共享对象的real name,也就是实际生成的动态库的文件名称。
为了让动态链接库为系统所共享,还需运行动态链接库的管理命令--ldconfig
ldconfig 命令的用途,主要是在默认搜寻目录(/lib和/usr/lib)以及动态库配置文件/etc/ld.so.conf内所列的目录下,搜索出可共享的动态 链接库(格式如前介绍,lib*.so*),进而创建出动态装入程序(ld.so)所需的连接和缓存文件.缓存文件默认为 /etc/ld.so.cache,此文件保存已排好序的动态链接库名字列表.
ldconfig -p 输出共享库soname实际对应的共享库的文件名称。
一个程序/shared库一般都要依赖其他的一些库,这可以用ldd来查看,它列出了依赖的库的soname,因为实际依赖是库的接口,而soname正是反映了库的接口信息。linux使用ELF作为可执行程序和库的格式,这些依赖的库的soname保存在ELF的某个fileld里。当一个可执行程序执行时,ld.so负责把它所依赖的shared库加载到内存并链接,它按照以下顺序寻找shared库:
1. 在LD_LIBRARY_PATH环境变量指定的目录下
2. ld.so.cache文件该shared库对应的文件
3. /usr/lib和/lib目录下
环境变量:
LD_BIND_NOW
--- 正常来讲,函数在呼叫之前是不会让程式寻找(looked up)的.设定这个旗号会使得程式库一载入,所有的寻找(lookups)便会发生,同时也造成起始的时间(startup time)较慢.当你想测试程式,确定所有的连结都没有问题时,这项旗号就变得很有用.LD_PRELOAD
可以设定一个档案,使其具有*覆盖*(overriding)函数定义的能力.例如,如果你要测试记忆体分配的方略(strategies),而且还想置换*malloc*,那麽你可以写好准备替换的副程式(routine),并把它编译成mallolc.
,然後:$ LD_PRELOAD=malloc.o; export LD_PRELOAD $ some_test_program
LD_ELF_PRELOAD
与LD_AOUT_PRELOAD
很类似,但是仅适用於正确的二进位型态.如果设定了LD_
something_PRELOAD
与LD_PRELOAD
,比较明确的那一个会被用到.LD_LIBRARY_PATH
是一连串以分号隔离的目录名称,用来搜寻共享程式库.对ld而言,并没有任何的影响;这项只有在执行期间才有影响.另外,对执行setuid与setgid的程式而言,这一项是无效的.而LD_ELF_LIBRARY_PATH
与LD_AOUT_LIBRARY_PATH
这两种旗号可根据各别的二进位型式分别导向不同的搜寻路径.一般正常的运作下,不应该会用到LD_LIBRARY_PATH
;把需要搜寻的目录加到/etc/ld.so.conf/
里;然後重新执行ldconfig.LD_NOWARN
仅适用於a.out.一旦设定了这一项(LD_NOWARN=true; export LD_NOWARN
),它会告诉载入器必须处理fatal-warnings(像是次要版本不相容等)的警告讯息.LD_WARN
仅适用於ELF.设定这一项时,它会将通常是致命讯息的"Can*t find library"转换成警告讯息.对正常的操作而言,这并没有多大的用处,可是对ldd就很重要了.LD_TRACE_LOADED_OBJECTS
仅适用於ELF.而且会使得程式以为它们是由ldd
所执行的:$ LD_TRACE_LOADED_OBJECTS=true /usr/bin/lynx libncurses.so.1 => /usr/lib/libncurses.so.1.9.6 libc.so.5 => /lib/libc.so.5.2.18