|
上周就看到了,一直想翻译,直到今天才有空,翻译了半个下午,算是对自己有个交代了,呵呵。原文出自http://www.dirac.org/p/linux/libraries/,是一位理论物理学家。头一回翻译东西,难免很烂,见谅了:)
Peter's Linux Pages
lib文件
一般来说,库文件有两种:动态库和静态库。
1.动态库
动态库(也叫共用库)是编译好的代码片段,在程序执行时由运行时连接文件(runtime linker)/lib/ld.so加载。这有点类似于windows下的dll文件。在提高效率方面,这样做可以节省系统在以下方面的开销:
硬件设备:不同的程序可以共享相同的代码。
内存:内核可以将库文件的拷贝存放在内存里以便进程之间共享。
时间:只要你不再重新编译库文件,重新生成可执行文件只需处理更少的代码。
习惯上,动态库以字符串so命名,后面加上版本号。例如:
libc.so.6 C语言的库文件.千万别给删掉了:)
libcrypt.so.1 影子口令系统的编码库.
libncurses.so.4.2 The new curses library routines.
2.静态库
静态库在编译的时候被固定在了可执行文件中,而不是放在系统的某个地方由ld.so加载。这种做法好的一面是可执行文件自己包含了所需的所有库文件,并不依赖于系统中的其他代码,也不会出现库文件缺失的情况。你可以把这些代码复制给任何人,而它们保证可以工作。不好的一面就是可执行文件不必要的增大了,而且不同的程序之间不能共享代码。
习惯上,我们以后缀.a来标记静态库文件。例如:
libgtk.a GIMP和其他X应用的图形库.
libcrypt.a 影子口令系统的编码库.
libvga.a. [S]VGA图形库.
3.静态库与动态库的对比
使用静态库的程序要比使用动态库的程序稍微快一些。我曾见过有人说两者之间启动时间的相差5%的数量级。但是,别忘了,动态库的好处之一是建立在一种假定条件下,即这些可执行代码已经被加载到了内存中.事实上,对于像libc这样的库文件,确实是一直保存在内存中的。如果你要运行一个使用静态库编译的netscape,必然要多等上一点时间。因此,对于“哪种库文件更快”这个问题的答案应该是“看情况而定”。但是一般来说,用动态库编译的的程序要更快一些,因为大部分情况下你所需要的库都已经加载到内存中了。
4.重要的文件/可执行文件
这个程序/lib/ls.so负责为可执行文件连接动态库。它在下面的文件夹里搜索库文件:
环境变量LD_LIBRARY_PATH中列出的目录,除非该程序设定了sid或者uid,以跳过环境变量。
文件/etc/ld.so.cache中列出的目录。
In /usr/lib
In /lib
至于为什么ld.so不去搜索/usr/local/lib,自有它的理由,我可以告诉你,但那会折磨死你。有些东西根本就不是要凡人知道的...
在/etc/ld.so.cache这个文件中包含了一个需要搜索的目录的汇总列表和一个备用库文件的列表。这个文件(/etc/ld.so.cache)是由/sbin/ldconfig创建的。
/sbin/ldconfig在系统启动时自动运行,也可在编译完成库文件后手动运行(每次安装软件之后都手动运行该文件是个不错的习惯)。 ldconfig生成/etc/ld.so.cache文件,它搜索/lib、/usr/lib以及其他在/etc/ld.so.conf中列出的需要搜索的目录。
在配置文件/etc/ld.so.conf中列出了所有ldconfig需要搜索以生成ld.so.cache文件的目录。如果你把库文件放在了不是默认的文件夹里(比如/home/lib),你应该把这个目录手工添加到ld.so.conf里,然后重新运行ldconfig。
5.非常有用的工具
许多程序都要求你的系统中存在某些动态库以便运行时调用,你如何才能找出哪些动态库是某个程序所需要的呢?这理有两种方法。
你可以使用strace,例如,先在终端下面用locate命令找出你系统里的xmms,xcalc或者xpaint所在的位置,然后运行以下命令:
strace -o LOG /usr/X11R6/bin/xcalc
关闭程序之后你会发现一个叫LOG的文件留了下来。用文本编辑器打开LOG,查找字符串so。你能看到哪些库文件被xcalc调用,还有上面提到的几个文件比如ld.so.cache或者libc.so。你或许还能看到一些有趣的东西,比如当在一个目录中没有找到某一个库,返回“file not found”,程序会到另一个目录继续搜索该库。就像下面这样:
open("/usr/local/rvplayer5.0/libXext.so.6", O_RDONLY) = -1 ENOENT (No such
file or directory)
open("/usr/X11R6/lib/libXext.so.6", O_RDONLY) = 4
很明显,libXext.so.6不在/usr/local/rvplayer5.0中,但是随后ld.so在/usr/X11R6/lib中找到了它。幸运的是,还有一种获取这些信息的更方便的方法:
ldd /usr/X11R6/bin/xcalc (必须使用完整的路径)
ldd将会返回如下信息:
libXaw.so.6 => /usr/X11R6/lib/Xaw3d/libXaw.so.6 (0x40020000)
libXmu.so.6 => /usr/X11R6/lib/libXmu.so.6 (0x40077000)
libXt.so.6 => /usr/X11R6/lib/libXt.so.6 (0x40089000)
libSM.so.6 => /usr/X11R6/lib/libSM.so.6 (0x400d3000)
libICE.so.6 => /usr/X11R6/lib/libICE.so.6 (0x400dd000)
libXext.so.6 => /usr/X11R6/lib/libXext.so.6 (0x400f3000)
libX11.so.6 => /usr/X11R6/lib/libX11.so.6 (0x400ff000)
libm.so.6 => /lib/libm.so.6 (0x401a5000)
libc.so.6 => /usr/lib/libc.so.6 (0x401c2000)
/lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x40000000)
呵呵,它甚至把库文件所在的位置都给你找了出来!用着很舒服吧?
6.结束语
当你准备写一个“helloworld”那样的小程序然后用gcc编译时,用的是动态库还是静态库呢?除非你给连接器-static选项,gcc使用的是动态库。例如,这是我的演示程序:
% cat try.c
#include<stdio.h>
int main(void) {
printf("Hello, world!\n");
return 0; }
用gcc编译:
% gcc try.c
下面就是ldd大显身手了:
% ldd a.out
libc.so.6 => /usr/lib/libc.so.6 (0x40020000)
/lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x40000000)
现在我们使用静态库编译:
% gcc -static try.c
再用ldd分析这个新的可执行文件:
% ldd a.out
not a dynamic executable
看到了吗?这就是理论的实际运用!
Peter's Linux Pages |
|