linux下静态库、动态库相关问题总结

来源:互联网 发布:最好的读书笔记软件 编辑:程序博客网 时间:2024/05/09 01:19

  前段时间项目中用到了对方给的库文件,从最初的不会用到现在小有心得,并且在看了网上很多大牛的博客后,总结下发在这里。

下一篇会发一篇关于在交叉编译环境下,静态库和动态库加载的问题。

 

一、静态库、动态库的概念

      库文件是一些函数、变量的集合,已编译过的代码。一般分为静态库和动态库两种。

静态库: 静态是指每个用到该库的应用程序都拥有一份自己的库拷贝;应用程序运行的时候,即使将库删除也没有问题,因为应用程序自己已经有了自己的拷贝。但是这也称为了它的缺点,因为静态库如果发生改变的话,那么应用程序也就需要重新进行编译了

 

动态库: 一个共享库有可能被多个所有应用程序共享。因此,对每个应用程序来说,即使不再使用某个共享库,也不应将其删除。此外,应用程序需要正确的环境变量设置(LD_LIBRARY_PATH),从而找到共享库所在的位置,否则,应用程序运行时会报告找不到这个库。

 

二、静态库、动态库的创建

创建:
无论静态库还是动态库,创建都分为两步,第一步创建目标文件,第二步生产库。
1).静态库的创建:
#gcc -c test.c -o test.o
#ar rcs libtest.a test.o
名字为libtest.a的静态库就生产了,其中选项:
r 表明将模块加入到静态库中;
c 表示创建静态库;
s 表示生产索引;
还有更多选项像增加、删除库中的目标文件,包括将静态库解包等可以通过man来获得。


2).动态库的创建:
#gcc -fPIC -c test.c -o test.c
#gcc --share test.o -o libtest.so
-fPIC 为了跨平台

 

三、静态库、动态库的使用

 环境变量配置:

库文件在连接(静态库和共享库)和运行(仅限于使用共享库的程序)时被使用,其搜索路径是在系统中进行设置的。
一般 Linux 系统把 /lib 和 /usr/lib 两个目录作为默认的库搜索路径,所以使用这两个目录中的库时不需要进行设置搜索路径即可直接使用。对于处于默认库搜索路径之外的库,需要将库的位置添加到库的搜索路径之中。设置库文件的搜索路径有下列两种方式,可任选其一使用:
在环境变量 LD_LIBRARY_PATH 中指明库的搜索路径。 比如一个libtest.a库在/home/test/lib目录下,在终端内

$ export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/home/test/lib
在 /etc/ld.so.conf 文件中添加库的搜索路径。添加方法也极其简单,将库文件的绝对路径直接写进去就OK了,一行一个,例如:

/usr/local/lib
/opt/lib

需要注意的是:第二种搜索路径的设置方式对于程序连接时的库(包括共享库和静态库)的定位已经足够了,但是对于使用了共享库的程序的执行还是不够的。这是因为为了加快程序执行时对共享库的定位速度,避免使用搜索路径查找共享库的低效率,所以是直接读取库列表文件 /etc/ld.so.cache 从中进行搜索的。/etc/ld.so.cache 是一个非文本的数据文件,不能直接编辑,它是根据 /etc/ld.so.conf 中设置的搜索路径由 /sbin/ldconfig 命令将这些搜索路径下的共享库文件集中在一起而生成的(ldconfig 命令要以 root 权限执行)。

        因此,为了保证程序执行时对库的定位,在 /etc/ld.so.conf 中进行了库搜索路径的设置之后,还必须要运行 /sbin/ldconfig 命令更新 /etc/ld.so.cache 文件之后才可以。ldconfig ,简单的说,它的作用就是将/etc/ld.so.conf列出的路径下的库文件缓存到/etc/ld.so.cache 以供使用。因此当安装完一些库文件,(例如刚安装好glib),或者修改ld.so.conf增加新的库路径后,需要运行一下 /sbin/ldconfig使所有的库文件都被缓存到ld.so.cache中,如果没做,即使库文件明明就在/usr/lib下的,也是不会被使用的,结果编译过程中抱错,缺少xxx库,去查看发现明明就在那放着,这时候会很是郁闷的。

 

 使用:
编译链接目标程序的方法是一样的:
#gcc main.c -L. -ltest -o main
-L.指定现在本目录下搜索库,如果没有,会到系统默认的目录下搜索,一般为/lib、/usr/lib下。
对于静态库,这个步骤之后就可以将libtest.a库删掉,因为它已经被编译进了目标程序,不再需要它了。
而对于动态库,libtest.so库只是在目标程序里做了标记,在运行程序时才会动态加载,那么从哪加载呢?加载目录会由/etc/ld.so.conf来指定,一般默认是/lib、/usr/lib,所以要想让动态库顺利加载,你可以将库文件copy到上面的两个目录下,或者设置export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/XXX/YYY,后面为你自己动态库的目录,再或者修改/etc/ld.so.conf文件,把库所在的路径加到文件末尾,并执行ldconfig刷新。这样,加入的目录下的所有库文件都可见。

 

四、静态库、动态库的加载顺序

GCC在链接过程中,对参数中的库的顺序是有要求的,参数右侧的库会先于左侧的库加载,也就是说参数的解析是从右往左的。

    假设库B依赖与库A,则链接的时候要写为:
       gcc -o bin B A
   如果写为:
       gcc -o bin A B
   则在B中引用的A中的内容就会无法链接通过
如果在同一目录下,既有静态库又有动态库,则在默认情况下是先加载动态库,因为对gcc来说默认方式是加载动态库,如果要让静态库优先加载的话,则需要加上-static参数