Linux动态库(含依赖库)实战与简析

来源:互联网 发布:数据库表设计例子 编辑:程序博客网 时间:2024/06/06 19:54

注意:这篇文章和我上篇文章Linux静态库(含依赖库)实战与简析是对应的。因为动态库和静态库需要对比着去理解才能有更好的效果。故而,在此我依旧使用静态库讲解的那篇文章所用到的例子,这里再简略赘述一下例子:

假设用户目录下的工程目录如下(p1/p2/ptest为三个目录,代表三个工程,.c/.h分别为工程源文件):

~├─p1│      p1.c│      p1.h│├─p2│      p2.c│      p2.h│└─ptest       test.c
其中,p2依赖p1,ptest依赖p2,即: p1 <- p2 <- ptest。我们打算将p1、p2都编译成动态库.so,供ptest调用。

源文件内容这里就不贴了,和静态库那篇博客中提到的一模一样,没有任何改动。点我去看源代码

下面开始编译并打包成so:

p1:

$gcc -c p1.c$gcc -shared -fPIC p1.o -o libp1.so

在Linux中库的名称有规定格式:"lib"+“LIBNAME” +".so",所以这里我为p1的动态库命名为libp1.so,这在以后调用的时候方便很多。

这里插叙一下gcc的选项的含义(man手册中其实都可以找到):

-shared 顾名思义,打包成共享动态库。其实动态库后缀名.so就是shared object的缩写。

-fPIC 表示编译为位置无关的代码,默认是位置相关的,故每个进程启动载入动态库时必须通过代码拷贝的方式来满足不同进程的需要,即每个进程各自拷贝一份这段代码,显然不能达到共享的目的。

p2:

$gcc -c p2.c$gcc -shared -fPIC p2.o -o libp2.so
ptest:

$gcc test.c -L../p1 -lp2 -L../p2 -lp1 -o test
请注意上面我使用了相对路径;p1和p2顺序不能颠倒。

-LXXX表示主动指定引用库路径,后面不能跟空格!

-lXXX表示引用库的名称。引用的时候,只要XXX为库名(不是文件名),这里我两个库为p1和p2,故就用-lp1和-lp2.


完成后,生成了可执行文件test。直接./test运行会出错的。因为系统不知道libp1.so和libp2.so的位置。

这里有两种方法,第一是将上述两个so文件拷贝到系统默认库位置(不同Linux位置可能不一样),第二是设置环境变量LD_LIBRARY_PATH,这样程序在运行的时候,会根据此变量的路径去查找:

$export LD_LIBRARY_PATH=~/p1:~/p2

然后运行:

$./testI am p1's a.I am p2's a.

可以看到,函数都能被正确调用了。


-----------------------------俺是华丽的分割线-----------------------
从以上工程结构可以得出:

1、与静态库不同,动态库是使用gcc这个工具来打包封装的,主要使用-shared 和 -fPIC选项。但是它们的原料都是需要使用.o目标文件。

2、动态库的运行似乎比较麻烦,需要设置环境变量或拷贝到系统默认库路径中(前提是你要有root权限),但是它也有自己的好处。

3、我们依旧使用ldd来查看可执行文件test的库引用情况:

$ ldd test        linux-gate.so.1 =>  (0x00eb7000)        libp2.so => /home/kyle/p2/libp2.so (0x00ae5000)        libp1.so => /home/kyle/p1/libp1.so (0x003e6000)        libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0x0043e000)        /lib/ld-linux.so.2 (0x008e3000)
可以看到有了两个我们自定义的库libp1.so和libp2.so。比较上篇文章对静态库的解析,就可以发现静态库与动态库的最大区别了:它仅仅是对库的引用,而不是合并到可执行文件中,即可执行文件中只是保留了调用接口而并没有函数实体,将调用者和被调用者代码独立起来。提高复用性,降低耦合。

0 0
原创粉丝点击