共享库的编译、链接和运行

通过例子说明静态库、动态库以及链接和运行时库:

有如下的目录:

hejinxin@google:~/Mytest$ ls project/
lib1  lib2   test.c
hejinxin@google:~/Mytest$ cd project/
hejinxin@google:~/Mytest/project$ ls lib*
lib1:
say1.c  
lib2:
say2.c
在project目录下有lib1、lib2子目录和文件test.c,lib1和lib2下面分别有文件say1.c和say2.c,内容如下:

/*************************************************************************
	> File Name: say1.c
	> Author: jxhe
	> Created Time: 2015年01月22日 星期四 17时55分16秒
 ************************************************************************/

#include<stdio.h>
void say()
{
	printf("Say1!");
}
/*************************************************************************
	> File Name: say2.c
	> Author: jxhe
	> Created Time: 2015年01月22日 星期四 17时55分16秒
 ************************************************************************/

#include<stdio.h>
void say()
{
	printf("Say2!");
}
在project下面的test.c是调用lib1中的say()函数或者lib2中的say()。

/*************************************************************************
	> File Name: test.c
	> Author: jxhe
	> Created Time: 2015年01月22日 星期四 17时57分08秒
 ************************************************************************/

#include<stdio.h>
int main()
{
	say();
	return 0;
}
下面分别在lib1和lib2下编译.c文件,但是都生成同一个库名。

hejinxin@google:~/Mytest/project$ cd lib1/
hejinxin@google:~/Mytest/project/lib1$ ls
say1.c 
hejinxin@google:~/Mytest/project/lib1$ gcc -o libsay.so -fPIC -shared say1.c
hejinxin@google:~/Mytest/project/lib1$ ls
libsay.so  say1.c
文件say2.c也作同样的编译。
现在通过指定共享库的路径,编译test可执行文件。

hejinxin@google:~/Mytest/project/lib1$ cd ..
hejinxin@google:~/Mytest/project$ ls
lib1  lib2  test.c
hejinxin@google:~/Mytest/project$ gcc -o test -Llib1 -lsay test.c 
hejinxin@google:~/Mytest/project$ ls
lib1  lib2  test  test.c
hejinxin@google:~/Mytest/project$ ./test 
./test: error while loading shared libraries: libsay.so: cannot open shared object file: No such file or directory
hejinxin@google:~/Mytest/project$ ldd test
linux-vdso.so.1 => (0x00007fff54945000)
libsay.so => not found
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fd5eb7e6000)
/lib64/ld-linux-x86-64.so.2 (0x00007fd5ebbbf000)

 
在执行test程序是报错,说没有libsay这个共享库。但是我们知道在编译是通过-L指定库在lib1下面,为什么ldd工具分析得出的结论是not found?这是因为程序执行时,查找库的路径和编译时指定的不同。有几种方法能修补现在的错误。一是,将包含目标共享库的路径添加到/etc/ld.so.conf,然后执行ldconfig。ldconfig的作用是读取ld.so.conf的内容到ld.so.cache中,然后程序执行中遇到调用共享库的函数时,就按照这个文件中提供的路径去查找;第二个方法是,将共享库所在的路径添加到环境变量LD_LIBRARY_PATH中。 
hejinxin@google:~/Mytest/project$ cat /etc/ld.so.conf
include /etc/ld.so.conf.d/*.conf
/home/hejinxin/Mytest/project/lib1
在加入到ld.so.conf之后,再调用ldd和执行程序查看结果。

hejinxin@google:~/Mytest</project$ ldd test
linux-vdso.so.1 =>  (0x00007fff792aa000)
libsay.so => /home/hejinxin/Mytarpackeg/project/lib1/libsay.so (0x00007fb43ecda000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fb43e91b000)
/lib64/ld-linux-x86-64.so.2 (0x00007fb43eef4000)
hejinxin@google:~/Mytest/project$ ./test
Say1!
可以看到效果了,libsay.so => 指向的地址正是这个共享库的目录,而不再是not found。test执行的结果是Say1!。那么,如果我们需要更新共享库,而不想重新编译整个程序时,怎么办呢?上例已经做了提前安排,就是lib2里也有一个同名的共享库,且函数接口也相同,只是函数内容不同。可以把lib2里的函数拷贝到lib1里,覆盖原先的库函数,看看执行结果:
hejinxin@google:~/Mytest/project/lib1$ ls
libsay.so.bak  say1.a  say1.c  say1.o
hejinxin@google:~/Mytest/project/lib1$ cp ../lib2/libsay.so  .
hejinxin@google:~/Mytest/project/lib1$ ls
libsay.so  libsay.so.bak  say1.a  say1.c  say1.o
hejinxin@google:~/Mytest/project/lib1$ cd ..
hejinxin@google:~/Mytest/project$ ls
lib1  lib2  test  test.c
hejinxin@google:~/Mytest/project$ ./test
Say2! 
结果输出的是Say2!,说明共享库更新成功!


1、什么是共享库

    共享库的代码是可以在多个应用程序之间共享的,也就是如果有多个程序(或者叫进程)调用相同的函数,可以把这些共同的函数提取出来制作成共享库。这样在运行时,内存中只需要拷贝一份就可以了。

2、共享库与静态库的区别

    静态库就是目标文件的简单打包,在编译过程中调用静态库,就会将涉及到的目标文件拷贝进可执行文件中,然后链接程序进行重定位。此后,程序的运行、调试都不再需要静态库了。如果每个可执行文件都拷贝一些基础函数或者目标文件,会有严重的内存空间浪费。同时,共享库在软件更新时也有优势,只要保证接口不变,用新的同名共享库覆盖原有的库就实现了软件更新。

3、如何编译共享库

    编译共享库需要给gcc指定相关的设置,-fPIC -shared,PIC是position independent code的缩写,就是位置无关的代码;-shared表明代码是共享的。

4、链接过程是怎样的

    程序编译的最后一个过程就是链接,链接器ld负责将多个目标文件链接起来,修改它们中的重定位表,使得可重定位符号指定到特定位置。

5、运行时如何操作

    在程序运行时,系统会首先判断这个程序是动态链接的还是静态链接的。如果是动态链接的,运行时动态连接器ld-linux.so检查程序依赖的共享库,并判断是否已经在内存中?如果不在,加载这些库绑定重定位的符号。这里就有一个问题了,运行时动态连接器是如何找到共享库?会首先查找/etc/ld.so.cache,如果没有这个库的路径,就程序就无法运行。而ld.so.cache其实是通过ldconfig程序读取/etc/ld.so.conf文件的内容,因此,安装库后应该把库文件的路径加入到/etc/ld.so.conf文件里面。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值