返回首页   进站必读

9.3 动态库


9.3 动态库

9.3.1 动态库的概念

动态库是一个包含可由多个程序同时使用的代码和数据的库。
动态库包含一个或者多个已被编译、链接并与使用他们的进程分开存储的函数。
动态库有助于共享数据和资源。动态库是动态链接的,动态链接提供了一种方法,使进程可以调用不属于其可执行代码的函数。PS:动态库不是可执行文件。

动态库在链接阶段没有被复制到程序中,而是在运行时由系统动态加载到内存中供程序调用。
使用动态库的优点是系统只需要载入一次动态库,不同的程序就可以得到内存中相同的库的复本,因此节省了很多内存。

9.3.2 动态库的生成

组成共享库的目标文件和一般的目标文件有所不同,在编译的时要加-fPIC选项,还是关于stack,例如:

$ gcc -c fPIC stack.c push.c pop.c is_empty.c

-f后面跟一些编译器选项,PIC是其中一种,表示生成位置无关代码(Position Independent Code)。

编译生成动态库:

$ gcc shared -o libstack.so stack.o push.o pop.o is_empty.o

9.3.3 动态库的动态链接

现在我们把main.c和动态库编译链接在一起,然后运行:

$ gcc main.c -g -L. -lstack -o main
$ ./main
./main:error while loading shared libraries: libstack.so:cannot open
shared object file: No such file or directory

结果:编译没有问题,由于指定了-L.选项,编译器可以在当前目录下找到libstack.so,而运行时却说找不到libstack.so。那么运行时在哪些路径下找动态库呢?首先用ldd命令查看可执行文件依赖于哪些动态库:

$ ldd main
linux-gate.so.1 => (0xb7f5c000)
libstack.so => not found
libc.so.6 => /lib/tls/i686/cmov/libc.so.6 (0xb7dcf000)
/lib/ld-linux.so.2 (0xf7f42000)

ldd模拟执行一遍main,在运行过程中做动态链接,从而得知这个程序依赖于哪些动态库,这些动态库在什么路径下。gcc 调用ld做链接时用-dynamic-linker /lib/ld-linux.so.2 选项指定动态连接器的路径,,动态连接器它也像其他动态库一样加载到进程的地址空间中。而另外一个选项-lc之说明了需要链接libc库,却没有指出libc库的完整路径,-lstack就是这样,动态库的路径需要运行时由动态连接器/lib/ld-linux.so.2去查找。

9.3.4 设置动态链接器搜索动态库的路径

上面的例子中,动态连接器找到的路径是:/lib/tls/i685/cmov/.libc.so.6,而libstack的路径没有找到,无法完成链接。那么动态链接器会到哪些目录下搜索动态库呢?从ld.so(8)可以查到动态库路径的搜索顺序:

1. 首先在环境变量LD\_LIBRARY\_PATH保存的路径中查找。
2. 然后从缓存文件/etc/ld.so.cache中查找。这个缓存文件是由ldconfig命令读取配置文件/etc/ld.so.conf生成的,这个后面会详细解释。
3. 如果上述步骤都找不到,则到默认的系统库文件目录中查找,先是/usr/lib
   然后是/lib。

一、修改环境变量法

$ LD_LIBRARY_PATH = /home/akaedu/testdir ./main

这个方法只适合在开发调试中临时用一下,设置环境变量法通常是不推荐的。

二、修改配置文件法
这是最常用的方法。把libstack.so所在的目录的绝对路径(比如/home/akaedu/somedir)添加到配置文件/etc/lib.so.conf(该文件中每个路径占一行),然后运行ldconfig:

$ sodu ldconfig -v

ldconfig命令可以生成/etc/ld.so.cache缓存文件,动态连接器就从这个缓存文件中搜索动态库。

三、文件拷贝法
把libstack.so拷到/usr/lib或/lib目录,这样可以确保动态链接器能找到这个动态库。

四、写死路径法

$ gcc main.c -g -L. -lstack -o main -W1 -rpath, /home/akaedu/somedir

注意选项-W1, -rpath, /home/akaedu/somedir, -W1 表示gcc传给链接器的选项。这种方法不推荐,把搜索路径写死在可执行文件中是一种硬代码的做法。