认识静态链接库和linux下的创建

来源:互联网 发布:广东11选5当前遗漏数据 编辑:程序博客网 时间:2024/05/18 21:41

转自:http://www.lingcc.com/2010/05/25/10951/

什么是静态链接库?

静态链接库,即static library或 statically-linked library。

和动态链接库,即dynamic library 或dynamicly-linked library相对,

是Windows和Linux系统中比较常用的库文件。

 

Windows中分别用SLL和DLL文件表示,Linux中分别是.a和.so文件.

静态链接库实际是一些object files(.o文件)和头文件的压缩包,通过GNU工具链中的ar(archiver)程序创建。

但是在使用时,不仅要包含lib库文件,还是要包含相应的头文件。

例如:要是用printf(),就应该在源程序中包含#include <stdio.h>一样。

静态链接库、动态链接库和共享库

那为何还要有动态链接库呢?

静态练级库虽然能很好的节省编译时间。

对于一个简单的ls程序,我们需要有屏幕输出,有字符串和格式操作,有文件系统访问等等函数,都要在一个程序中。

此时,这个程序会很大。一个小小的ls可能都会有好几兆。如果还有个rm程序,同样也需屏幕输出文件系统访问。那么这两个东西(指:屏幕输出文件系统访问),我们可以放到两个库文件里,在执行ls,或者rm的时候,用到屏幕输出操作,就将相应的函数对应的机器码载入内存中,执行。然后再从内存中释放。接着载入文件系统访问的相关函数。这样我们的程序就能变小很多。这种可以动态装载到内存中的库文件就是动态链接库了。Windows下的DLL文件就是动态链接库

还有个问题,其实ls和rm使用的屏幕输出函数是一样的。内存很小的时候,同时执行ls和rm,有必要同时载入两份相同的代码到内存中吗?于是就有了共享库,不同的程序可以共享相同的代码。都可以访问,执行。于是就有了共享库的概念Linux下的.so文件就是共享库

这时候又有个问题,程序执行时,访存,跳转的地址是一定的,那两个程序又如何共享相同的库代码呢?这就靠位置无关的代码生成了。本博曾经写过文章介绍它们,请参考Gcc和Open64中的-fPIC选项 和GCC中的pie和fpie选项两篇文章。

下图是关于共享库和静态链接库的示意图,可以简单看出些区别。

静态链接库和共享库

为什么要有静态链接库?

首先,随着程序规模的增加,有些常用函数可能不需要每次都编译,于是就可以把它们作为库的方式来存放。这样用户就能很方便的链接生成最后的程序,不用一遍遍的重新编译某些常用程序文件。必须内核,硬件驱动,文件系统,glibc等等库文件,一些基本函数都采用了这种形式。

其次,一些闭源代码,可以通过库的方式来发布,这样可以保证代码不公开。

再次,相比动态链接的程序,或者共享库程序,连接到静态库的程序会快1%-5%左右

另外,有些特殊环境,必须使用静态链接库。比如在Linux系统,需要chroot到另一个系统环境中时,动态链接库就不再起作用,因为那些是在原来系统的文件树下,如/usr/lib.但在chroot的环境中,无法访问。

怎么用静态链接库?

既然静态链接库的出现,是为了缩短编译时间。而普通可执行程序又可以分为静态链和动态链两种形式。因此我们就分开介绍之,原因无他,只是想顺便介绍一下动态链可执行程序和静态链可执行程序在运行时的一些区别。

对于静态链接库的应用,加上-lname,就会链接libname.a这个静态链接库文件。一般静态链接库文件的搜索路径为系统默认的路径(如/usr/lib/)和当前路径。你也可以用过-L选项,指定GCC搜索某个特定文件夹。注意-l和-L的参数要加载待编译源码文件之后。

静态链接库既可以在编译时用于生成单个可执行文件,也可以在运行时根据编译或者连接时确定的静态偏移量载入内存中。

编译静态链接可执行程序

编译静态链可执行程序,对于gcc,只要加上-static即可。

编译时,程序中若有对库函数的调用,编译器或者连接器就会将库中相应的代码拷贝到目标文件中,生成一个独立的可执行文件。

编译动态链接可执行程序

不加-static编译生成的可执行程序都是动态链接的,编译时所做工作很少,仅仅记录了该程序需要什么库函数,以及该库函数在库中到索引。

但对于动态链接程序,在系统启动该可执行程序时,装载器loader必须能找到相应的共享库文件.so文件或者静态链接库文件.a(已经很少使用这种形式了),并将其载入内存中,一般的,有两种途径可以指定链接库文件的位置,

  • 编译动态链接可执行程序时,通过rpath指定,这个可以在编译时增加选项-Wl,-rpath=DIRS.这种方式不需要在运行时做任何修改,该选项会在连接时,写入可执行程序中。
  • 运行时由ld.so指定。默认共享库搜索路径是/usr/local/lib,/usr/lib以及当前目录,你可以通过修改$LD_LIBRARY_PATH变量修改。系统管理员也可以在/etc/profile中修改,以便对所有用户有效。当然修改/etc/ld.so.conf也行,这样所有的程序都将更改寻找链接库文件的路径。

很晕吧

静态链接库的常用操作

制作静态链接库

$ar rcs liba.a a.o b.o c.o a_header.h b_header.h

上面命令,将a.o, b.o, c.o, a_header.h, b_header.h作成静态链接库liba.a.

  • 选项r:将 .o , .h文件插入到liba.a文件中
  • c:创建一个压缩文件。
  • s:将.o文件的索引信息写入压缩文件中,或者升级已有索引。这和执行 ranlib liba.a的效果过一样。索引信息会存在压缩包的一个符号文件夹内,连接器可以通过名称找到位置,这样可以加速连接时间。
解压静态链接库

$ar xv liba.a

该命令会把liba.a中所有的文件解压缩到当前目录下。

  • x:解压缩该压缩包
  • v:可视化,解压缩同时输出到屏幕
查看内容

$nm --print-armap liba.a

该命令查看liba.a中包含哪些文件,每个文件中包含哪些函数。

  • 在列出压缩包中所有文件中的符号,同时包含索引:每个元素到符号的映射
实践:

本文不再给出具体实践,可以参考An Introduction to GCC – Shared libraries and static libraries

参考:

  1. http://www.network-theory.co.uk/docs/gccintro/gccintro_25.html
  2. http://en.wikipedia.org/wiki/Static_library
  3. http://cpp.codenewbie.com/articles/cpp/1444/Static_Link_Librarys-Page_1.html
  4. http://tldp.org/HOWTO/Program-Library-HOWTO/static-libraries.html
  5. http://www.faqs.org/docs/linux_scratch/chapter05/whystatic.html
  6. http://en.wikipedia.org/wiki/Dynamic-link_library
  7. http://www.ibm.com/developerworks/linux/library/l-dynamic-libraries/index.html