linux 共享库

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,也就是实际生成的动态库的文件名称。

为了让动态链接库为系统所共享,还需运行动态链接库的管理命令–ldconfigldconfig 命令的用途,主要是在默认搜寻目录(/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_PRELOADLD_AOUT_PRELOAD很类似,但是仅适用於正确的二进位型态.如果设定了LD_something_PRELOADLD_PRELOAD,比较明确的那一个会被用到.LD_LIBRARY_PATH是一连串以分号隔离的目录名称,用来搜寻共享程式库.对ld而言,并没有任何的影响;这项只有在执行期间才有影响.另外,对执行setuid与setgid的程式而言,这一项是无效的.而LD_ELF_LIBRARY_PATHLD_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

未曾失败的人恐怕也未曾成功过。

linux 共享库

相关文章:

你感兴趣的文章:

标签云: