1 库的分类
根据链接时期的不同,库又有静态库和动态库之分。
静态库是在链接阶段被链接的(好像是废话,但事实就是这样),所以生成的可执行文件就不受库的影响了,即使库被删除了,程序依然可以成功运行。
有别于静态库,动态库的链接是在程序执行的时候被链接的。所以,即使程序编译完,库仍须保留在系统上,以供程序运行时调用。(TODO:链接动态库时链接阶段到底做了什么)
2 静态库和动态库的比较
链接静态库其实从某种意义上来说也是一种粘贴复制,只不过它操作的对象是目标代码而不是源码而已。因为静态库被链接后库就直接嵌入可执行文件中了,这样就带来了两个问题。
首先就是系统空间被浪费了。这是显而易见的,想象一下,如果多个程序链接了同一个库,则每一个生成的可执行文件就都会有一个库的副本,必然会浪费系统空间。
再者,人非圣贤,即使是精心调试的库,也难免会有错。一旦发现了库中有bug,挽救起来就比较麻烦了。必须一一把链接该库的程序找出来,然后重新编译。
而动态库的出现正弥补了静态库的以上弊端。因为动态库是在程序运行时被链接的,所以磁盘上只须保留一份副本,因此节约了磁盘空间。如果发现了bug或要升级也很简单,只要用新的库把原来的替换掉就行了。
那么,是不是静态库就一无是处了呢?
答曰:非也非也。不是有句话么:存在即是合理。静态库既然没有湮没在滔滔的历史长河中,就必然有它的用武之地。想象一下这样的情况:如果你用libpcap库编了一个程序,要给被人运行,而他的系统上没有装pcap库,该怎么解决呢?最简单的办法就是编译该程序时把所有要链接的库都链接它们的静态库,这样,就可以在别人的系统上直接运行该程序了。
所谓有得必有失,正因为动态库在程序运行时被链接,故程序的运行速度和链接静态库的版本相比必然会打折扣。然而瑕不掩瑜,动态库的不足相对于它带来的好处在现今硬件下简直是微不足道的,所以链接程序在链接时一般是优先链接动态库的,除非用-static参数指定链接静态库。
动态链接库:
#include
void func(){
printf("In func( )\n");
}
#incude
int main()
{
printf("Use Dynamic Link Library \n");
func( );
return 0;
}
生成动态链接库: gcc -shared -o libtest.so test.c ( 注意生成的动态链接库的文件名字必须以lib开头,后缀名是.so,-shared 选项是指定生成动态链接库)
这样在当前目录先就多了一个libtest.so名字的动态链接库
编译main.c: gcc -o main main.c -ltest -L./ (-l 选项指定动态链接库的名字,前缀lib和后缀.so可以省略。-L选项是指定动态链接库的位置,如果不指定会去默认的路劲下搜索,如:/lib,/usr/lib/)
编译完成后在当前目录会多一个名叫main的可执行文件,但是执行./main还是会报错(由于动态链接库的使用包括两个阶段,链接(链接器)和加载(加载器))
解决办法:1、可以把当前路径加入 /etc/ld.so.conf中然后运行ldconfig,或者以当前路径为参数运行ldconfig(要有root权限才行)。
2、把当前路径加入环境变量LD_LIBRARY_PATH中:export LD_LIBRARY_PATH=./:LD_LIBRARY_PATH
3、当然,如果你觉得不会引起混乱的话,可以直接把该库拷入/lib,/usr/lib/等位置(无可避免,这样做也要有权限),这样链接器和加载器就都可以准确的找到该库了。
采用了以上三种方法之一后在运行./main就可以正常的执行了
静态链接库:
生成静态链接库:
gcc -c test.c (编译完成后在当前目录下生成test.o文件)
ar -r libtest.a test.o (将test.o归档成静态链接文件,程序 ar 配合参数 -r 创建一个新库 libhello.a 并将命令行中列出的对象文件插入。采用这种方法,如果库不存在的话,参数 -r 将创建一个新的库,而如果库存在的话,将用新的模块替换原来的模块。)命令执行后在当前目录生成已给 libhello.a的静态链接文件
编译main.c:
gcc -o main main.c -ltest -L./ 这条命令执行后在当前目录下会生成可执行文件main ,运行./main, 程序正常运行
阅读(2263) | 评论(0) | 转发(0) |