Linux共享库概述( 三 )


管理共享函数库的关键是区分好这些名字 。 当可执行程序需要在自己的程序中列出这些他们需要的共享库函数的时候 , 它只要用soname就可以了;反过来 , 当你要创建一个新的共享函数库的时候 , 你要指定一个特定的文件名 , 其中包含很细节的版本信息 。 当你安装一个新版本的函数库的时候 , 你只要先将这些函数库文件拷贝到一些特定的目录中 , 运行ldconfig这个实用就可以 。 ldconfig检查已经存在的库文件 , 然后创建soname的符号链接到真正的函数库 , 同时设置/etc/ld.so.cache这个缓冲文件 。 这个我们稍后再讨论 。
ldconfig并不设置链接的名字 , 通常的做法是在安装过程中完成这个链接名字的建立 , 一般来说这个符号链接就简单的指向最新的soname或者最新版本的函数库文件 。 最好把这个符号链接指向soname , 因为通常当你升级你的库函数后 , 你就可以自动使用新版本的函数库类 。
我们来举例看看:/usr/lib/libreadline.so.3 是一个完全的完整的soname , ldconfig可以设置一个符号链接到其他某个真正的函数库文件 , 例如是/usr/lib/libreadline.so.3.0 。 同时还必须有一个链接名字 , 例如 /usr/lib/libreadline.so就是一个符号链接指向/usr/lib/libreadline.so.3 。
3.1.2. 文件系统中函数库文件的位置
共享函数库文件必须放在一些特定的目录里 , 这样通过系统的环境变量设置 , 应用程序才能正确的使用这些函数库 。 大部分的源码开发的程序都遵循GNU的一些标准 , 我们可以看info帮助文件获得相信的说明 , info信息的位置是:info:standards#Directory_Variables 。 GNU标准建议所有的函数库文件都放在/usr/local/lib目录下 , 而且建议命令可执行程序都放在/usr/local/bin目录下 。 这都是一些习惯问题 , 可以改变的 。
文件系统层次化标准FHS(Filesystem Hierarchy Standard)()规定了在一个发行包中大部分的函数库文件应该安装到/usr/lib目录下 , 但是如果某些库是在系统启动的时候要加载的 , 则放到/lib目录下 , 而那些不是系统本身一部分的库则放到/usr/local/lib下面 。
上面两个路径的不同并没有本质的冲突 。 GNU提出的标准主要对于开发者开发源码的 , 而FHS的建议则是针对发行版本的路径的 。 具体的位置信息可以看/etc/ld.so.conf里面的配置信息 。
这些函数库如何使用在基于GNU glibc的系统里 , 包括所有的linux系统 , 启动一个ELF格式的二进制可执行文件会自动启动和运行一个program loader 。 对于Linux系统 , 这个loader的名字是/lib/ld-linux.so.X(X是版本号) 。 这个loader启动后 , 反过来就会load所有的其他本程序要使用的共享函数库 。
到底在哪些目录里查找共享函数库呢?这些定义缺省的是放在/etc/ld.so.conf文件里面 , 我们可以修改这个文件 , 加入我们自己的一些特殊的路径要求 。 大多数RedHat系列的发行包的/etc/ld.so.conf文件里面不包括/usr/local/lib这个目录 , 如果没有这个目录的话 , 我们可以修改/etc/ld.so.conf , 自己手动加上这个条目 。
如果你想覆盖某个库中的一些函数 , 用自己的函数替换它们 , 同时保留该库中其他的函数的话 , 你可以在 /etc/ld.so.preload中加入你想要替换的库(.o结尾的文件) , 这些preloading的库函数将有优先加载的权利 。
当程序启动的时候搜索所有的目录显然会效率很低 , 于是Linux系统实际上用的是一个高速缓冲的做法 。 ldconfig缺省情况下读出/etc/ld.so.conf相关信息 , 然后设置适当地符号链接 , 然后写一个cache到 /etc/ld.so.cache这个文件中 , 而这个/etc/ld.so.cache则可以被其他程序有效的使用了 。 这样的做法可以大大提高访问函数库的速度 。 这就要求每次新增加一个动态加载的函数库的时候 , 就要运行ldconfig来更新这个cache , 如果要删除某个函数库 , 或者某个函数库的路径修改了 , 都要重新运行ldconfig来更新这个cache 。 通常的一些包管理器在安装一个新的函数库的时候就要运行ldconfig 。