在我们的 Linux 操作系统当中,函式库是很重要的一个项目。
因为很多的软件之间都会互相取用彼此提供的函式库来进行特殊功能的运行,
例如很多需要验证身份的程序都习惯利用 PAM 这个模块提供的验证机制来实作,而很多网络连线机制则习惯利用 SSL
函式库来进行连线加密的机制。所以说,函式库的利用是很重要的。不过,
函式库又依照是否被编译到程序内部而分为动态与静态函式库,这两者之间有何差异?哪一种函式库比较好?
底下我们就来谈一谈先!
动态与静态函式库
首先我们要知道的是,函式库的类型有哪些?依据函式库被使用的类型而分为两大类,分别是静态
(Static) 与动态 (Dynamic) 函式库两类。底下我们来谈一谈这两种类行的函式库吧!
- 扩展名:(扩展名为 .a)
这类的函式库通常扩展名为 libxxx.a 的类型;
- 编译行为:
这类函式库在编译的时候会直接整合到运行程序当中,所以利用静态函式库编译成的文件会比较大一些喔;
- 独立运行的状态:
这类函式库最大的优点,就是编译成功的可运行档可以独立运行,而不需要再向外部要求读取函式库的内容
(请参照动态函式库的说明)。
- 升级难易度:
虽然运行档可以独立运行,但因为函式库是直接整合到运行档中,
因此若函式库升级时,整个运行档必须要重新编译才能将新版的函式库整合到程序当中。
也就是说,在升级方面,只要函式库升级了,所有将此函式库纳入的程序都需要重新编译!
- 扩展名:(扩展名为 .so)
这类函式库通常扩展名为 libxxx.so
的类型;
- 编译行为:
动态函式库与静态函式库的编译行为差异挺大的。
与静态函式库被整个捉到程序中不同的,动态函式库在编译的时候,在程序里面只有一个『指向
(Pointer)』的位置而已。也就是说,动态函式库的内容并没有被整合到运行档当中,而是当运行档要使用到函式库的机制时,
程序才会去读取函式库来使用。由於运行档当中仅具有指向动态函式库所在的指标而已,
并不包含函式库的内容,所以他的文件会比较小一点。
- 独立运行的状态:
这类型的函式库所编译出来的程序不能被独立运行,
因为当我们使用到函式库的机制时,程序才会去读取函式库,所以函式库文件『必须要存在』才行,而且,函式库的『所在目录也不能改变』,因为我们的可运行档里面仅有『指标』亦即当要取用该动态函式库时,
程序会主动去某个路径下读取,呵呵!所以动态函式库可不能随意移动或删除,会影响很多相依的程序软件喔!
- 升级难易度:
虽然这类型的运行档无法独立运行,然而由於是具有指向的功能,
所以,当函式库升级后,运行档根本不需要进行重新编译的行为,因为运行档会直接指向新的函式库文件
(前提是函式库新旧版本的档名相同喔!)。
目前的 Linux distribution 比较倾向於使用动态函式库,因为如同上面提到的最重要的一点,
就是函式库的升级方便!由於 Linux 系统里面的软件相依性太复杂了,如果使用太多的静态函式库,那么升级某一个函式库时,
都会对整个系统造成很大的冲击!因为其他相依的运行档也要同时重新编译啊!
这个时候动态函式库可就有用多了,因为只要动态函式库升级就好,其他的软件根本无须变动。
那么这些函式库放置在哪里呢?绝大多数的函式库都放置在:/usr/lib, /lib 目录下!
此外,Linux 系统里面很多的函式库其实 kernel 就提供了,那么 kernel
的函式库放在哪里?呵呵!就是在
/lib/modules 里面啦!里面的数据可多著呢!不过要注意的是,
不同版本的核心提供的函式库差异性是挺大的,所以
kernel 2.4.xx 版本的系统不要想将核心换成 2.6.xx 喔!
很容易由於函式库的不同而导致很多原本可以运行的软件无法顺利运行呢!
ldconfig
与 /etc/ld.so.conf
在了解了动态与静态函式库,也知道我们目前的 Linux
大多是将函式库做成动态函式库之后,再来要知道的就是,那有没有办法添加函式库的读取效能?
我们知道内存的存取速度是硬盘的好几倍,所以,如果我们将常用到的动态函式库先加载内存当中 (缓存,
cache),如此一来,当软件要取用动态函式库时,就不需要从头由硬盘里面读出罗!
这样不就可以增进动态函式库的读取速度?没错,是这样的!这个时候就需要
ldconfig 与 /etc/ld.so.conf 的协助了。
如何将动态函式库加载高速缓存当中呢?
- 首先,我们必须要在 /etc/ld.so.conf 里面写下『
想要读入高速缓存当中的动态函式库所在的目录』,注意喔,
是目录而不是文件;
- 接下来则是利用 ldconfig 这个运行档将 /etc/ld.so.conf 的数据读入缓存当中;
- 同时也将数据记录一份在 /etc/ld.so.cache 这个文件当中呐!
图 5.2.1、使用 ldconfig 预加载动态函式库到内存中
事实上, ldconfig 还可以用来判断动态函式库的连结资讯呢!赶紧利用 CentOS
来测试看看。假设你想要将目前你系统下的 MySQL 函式库加入到缓存当中时,可以这样做:
[root@www ~]# ldconfig [-f conf] [ -C cache]
[root@www ~]# ldconfig [-p]
选项与参数:
-f conf :那个 conf 指的是某个文件名称,也就是说,使用 conf 作为 libarary
函式库的取得路径,而不以 /etc/ld.so.conf 为默认值
-C cache:那个 cache 指的是某个文件名称,也就是说,使用 cache 作为缓存缓存
的函式库数据,而不以 /etc/ld.so.cache 为默认值
-p :列出目前有的所有函式库数据内容 (在 /etc/ld.so.cache 内的数据!)
范例一:假设我的 MySQL 数据库函式库在 /usr/lib/mysql 当中,如何读进 cache ?
[root@www ~]# vi /etc/ld.so.conf
include ld.so.conf.d/*.conf
/usr/lib/mysql <==这一行新增的啦!
[root@www ~]# ldconfig <==画面上不会显示任何的资讯,不要太紧张!正常的!
[root@www ~]# ldconfig -p
530 libs found in cache `/etc/ld.so.cache'
libz.so.1 (libc6) => /usr/lib/libz.so.1
libxslt.so.1 (libc6) => /usr/lib/libxslt.so.1
....(底下省略)....
# 函式库名称 => 该函式库实际路径
|
透过上面的动作,我们可以将 MySQL 的相关函式库给他读入缓存当中,这样可以加快函式库读取的效率呢!
在某些时候,你可能会自行加入某些 Tarball 安装的动态函式库,而你想要让这些动态函式库的相关连结可以被读入到缓存当中,
这个时候你可以将动态函式库所在的目录名称写入 /etc/ld.so.conf 当中,然后运行 ldconfig 就可以啦!
程序的动态函式库解析: ldd
说了这么多,那么我如何判断某个可运行的 binary 文件含有什么动态函式库呢?很简单,利用
ldd 就可以晓得了!例如我想要知道 /usr/bin/passwd 这个程序含有的动态函式库有哪些,可以这样做:
[root@www ~]# ldd [-vdr] [filename]
选项与参数:
-v :列出所有内容资讯;
-d :重新将数据有遗失的 link 点秀出来!
-r :将 ELF 有关的错误内容秀出来!
范例一:找出 /usr/bin/passwd 这个文件的函式库数据
[root@www ~]# ldd /usr/bin/passwd
....(前面省略)....
libaudit.so.0 => /lib/libaudit.so.0 (0x00494000) <==SELinux
libselinux.so.1 => /lib/libselinux.so.1 (0x00101000) <==SELinux
libc.so.6 => /lib/libc.so.6 (0x00b99000)
libpam.so.0 => /lib/libpam.so.0 (0x004ab000) <==PAM 模块
....(底下省略)....
# 我们前言的部分不是一直提到 passwd 有使用到 pam 的模块吗!怎么知道?
# 利用 ldd 察看一下这个文件,看到 libpam.so 了吧?这就是 pam 提供的函式库
范例二:找出 /lib/libc.so.6 这个函式的相关其他函式库!
[root@www ~]# ldd -v /lib/libc.so.6
/lib/ld-linux.so.2 (0x00ab3000)
linux-gate.so.1 => (0x00636000)
Version information: <==使用 -v 选项,添加显示其他版本资讯!
/lib/libc.so.6:
ld-linux.so.2 (GLIBC_PRIVATE) => /lib/ld-linux.so.2
ld-linux.so.2 (GLIBC_2.3) => /lib/ld-linux.so.2
ld-linux.so.2 (GLIBC_2.1) => /lib/ld-linux.so.2
|
未来如果你常常升级安装 RPM 的软件时 (下一章节会介绍),应该常常会发现那个『
相依属性』的问题吧!没错!我们可以先以
ldd 来视察『相依函式库』之间的相关性!以先取得了解!
例如上面的例子中,我们检查了 libc.so.6 这个在 /lib 当中的函式库,结果发现他其实还跟
ld-linux.so.2 有关!所以我们就需要来了解一下,那个文件到底是什么软件的函式库呀?使用
-v 这个参数还可以得知该函式库来自於哪一个软件!像上面的数据中,就可以得到该
libc.so.6 其实可以支持 GLIBC_2.1 等的版本!