【Linux基础】静态库与动态库探究

来源:互联网 发布:数据库物理设计实例 编辑:程序博客网 时间:2024/05/16 11:33

在Linux操作系统中,普遍使用ELF格式作为可执行程序或者程序生成过程中的中间格式。ELF(Executable and Linking Format,可执行连接格式)是UNIX系统实验室(USL)作为应用程序二进制接口(Application BinaryInterface,ABI)而开发和发布的。工具接口标准委员会(TIS)选择了正在发展中的ELF标准作为工作在32位Intel体系上不同操作系统之间可移植的二进制文件格式。本文不对ELF文件格式及其组成做太多解释,以免冲淡本文的主题,大家只要知道这么个概念就行。


ELF文件有三种形式:

1,可重定位文件(*.o):包含代码和数据,其形式可以在编译时与其他可重定位文件组合起来生成可执行文件。

2,可执行文件:包含二进制的代码和数据,可直接拷贝到存储器并执行。

3,共享库文件(*.so):一种特殊的可重定位文件,可以在运行时被动态的加载到存储器并链接。


下面我们就开始主题深入探究下Linux下静态库和动态库的创建和使用。

静态库:这类库的名字一般是libxxx.axxx为库的名字。利用静态函数库编译成的文件比较大,因为整个函数库的所有数据都会被整合进目标代码中,他的优点就显而易见了,即编译后的执行程序不需要外部的函数库支持,因为所有使用的函数都已经被编译进去了。当然这也会成为他的缺点,因为如果静态函数库改变了,那么你的程序必须重新编译。

动态库:这类库的名字一般是libxxx.M.N.so,同样的xxx为库的名字,M是库的主版本号,N是库的副版本号。当然也可以不要版本号,但名字必须有。相对于静态函数库,动态函数库在编译的时候并没有被编译进目标代码中,你的程序执行到相关函数时才调用该函数库里的相应函数,因此动态函数库所产生的可执行文件比较小。由于函数库没有被整合进你的程序,而是程序运行时动态的申请并调用,所以程序的运行环境中必须提供相应的库。动态函数库的改变并不影响你的程序,所以动态函数库的升级比较方便。linux系统有几个重要的目录存放相应的函数库,如/lib /usr/lib。

当要使用静态的程序库时,连接器会找出程序所需的函数,然后将它们拷贝到执行文件,由于这种拷贝是完整的,所以一旦连接成功,静态程序库也就不再需要了。然而,对动态库而言,就不是这样。动态库会在执行程序内留下一个标记指明当程序执行时,首先必须载入这个库。由于动态库节省空间,linux下进行连接的缺省操作是首先连接动态库,也就是说,如果同时存在静态和动态库,不特别指定的话,将与动态库相连接。

下面我们来用例子说明问题:

1.静态库的创建和使用:

首先你得做点准备工作,我在自己的机器上(ubuntu14.04)创建了common.h add.c sub.c mul.c dive.c五个文件还有一个测试文件main.c,具体内容如下:


******************************************************************************************




******************************************************************************************



******************************************************************************************

然后只需gcc命令,生成对应的可重定位文件,*.o文件。



然后通过ar指令生成静态库libmycal.a文件。

ar命令参数如下:

-r            将objfile文件插入静态库尾或者替换静态库中同名文件

-x            从静态库文件中抽取文件objfile

-t             打印静态库的成员文件列表

-d            从静态库中删除文件objfile

-s           重置静态库文件索引

-v            创建文件冗余信息

-c            创建静态库文件



******************************************************************************************

然后编译main.c文件来测试链接静态库是否成功:


如图可以看出结果,生成的app可以执行,证明链接正确。


2.动态库的创建和使用:

静态库*.a文件的存在主要是为了支持较老的a.out格式的可执行文件而存在的。目前用的最多的要数动态库了。

动态库的后缀为*.so。在Linux发行版中大多数的动态库基本都位于/usr/lib和/lib目录下。在开发和使用我们自己动态库之前,请容许我先落里罗嗦的跟大家唠叨唠叨Linux下和动态库相关的事儿吧。

有时候当我们的应用程序无法运行时,它会提示我们说它找不到什么样的库,或者哪个库的版本又不合它胃口了等等之类的话。那么应用程序它是怎么知道需要哪些库的呢?我们前面已几个学了个很棒的命令ldd,用就是用来查看一个文件到底依赖了那些so库文件。

Linux系统中动态链接库的配置文件一般在/etc/ld.so.conf文件内,它里面存放的内容是可以被Linux共享的动态联库所在的目录的名字。在/etc目录下还存在一个名叫ld.so.cache的文件。从名字来看,我们知道它肯定是动态链接库的什么缓存文件。为了使得动态链接库可以被系统使用,当我们修改了/etc/ld.so.conf或/etc/ld.so.conf.d/目录下的任何文件,或者往那些目录下拷贝了新的动态链接库文件时,都需要运行一个很重要的命令:ldconfig,该命令位于/sbin目录下,主要的用途就是负责搜索/lib和/usr/lib,以及配置文件/etc/ld.so.conf里所列的目录下搜索可用的动态链接库文件,然后创建处动态加载程序/lib/ld-linux.so.2所需要的连接和(默认)缓存文件/etc/ld.so.cache(此文件里保存着已经排好序的动态链接库名字列表)。

也就是说:当用户在某个目录下面创建或拷贝了一个动态链接库,若想使其被系统共享,可以执行一下"ldconfig目录名"这个命令。此命令的功能在于让ldconfig将指定目录下的动态链接库被系统共享起来,即:在缓存文件/etc/ld.so.cache中追加进指定目录下的共享库。请注意:如果此目录不在/lib,/usr/lib/etc/ld.so.conf文件所列的目录里面,则再次单独运行ldconfig时,此目录下的动态链接库可能不被系统共享了。单独运行ldconfig时,它只会搜索/lib/usr/lib以及在/etc/ld.so.conf文件里所列的目录,用它们来重建/etc/ld.so.cache

下面我们就来实际操作一下。

首先我们用gcc -shared -Wl,soname ,libmycal.so.1 -o libmycal.so.1.10 *.o生成动态库。关于soname下面会详细介绍,*.o就是刚才静态库用的四个文件。




然后gcc生成app可执行程序,当你./app时是无法执行的,因为它无法链接到所需的动态库,用ldd app看看app所依赖的动态库发现not found.此时就是刚才说明的问题了。无法链接到libmycal.so.1这个库。

设置配置文件sudo vi /etc/ld.so.conf,添加你libmycal.so.1所在的路径。然后sudo ldconfig -v刷新库文件位置,然后gcc编译出app,这次就可以顺利执了。

******************************************************************************************


到此动态库的创建和使用已完结,下面我们对刚才遗留的问题soname进行解答:

共享库的命名有三种soname,realname,linkname,例如上面的libmycal.so,这是它的linkname,soname为libmycal.so.1后面加上库的主版本号而已,readlname为libmycal.so.1.10还得有次版本号。

他们的关系是soname和linkname是realname的软连接。如图:


******************************************************************************************


我们前面说过,动态库是程序实现时动态加载的,当你更换环境后,此环境下必须有这个库才可以生成所谓的可执行文件,还有必须的条件是你链接的库和此环境下的库的主版本号soname必须相同,因为同一主版本号下的库,它们的函数接口是一致的。linkname主要是在编译连接阶段使用,方面makefile,因为makefile里我们gcc时使用的是linkname,当更新库版本时,不用关注版本。realname则是我们链接的真正的库。

1 0
原创粉丝点击