Linux静态库和动态库学习总结

一、废话

之前由于工作需要,要封装一个Linux加密解密转换的动态库,这个之前只做过Windows下面的,Linux下面还真没有做过,之后做了整一个晚上才算做好,不过其中也学到了不少东西,包括Linux下的动态库和静态库,MakeFile等等。之前就已经写了一个练习,之后怕又忘了,总结一下备忘,以后也好查。

很大部分内容都是收集的一些东西还有自己学习的体会,有什么错误或者问题请直接提出。

二、关于库的问题

1.库的原则

现实中每个程序都要依赖很多基础的底层库,不可能每个人的代码都从零开始。尽量不重复做别人已经做过的事,就是尽量充分利用别人的劳动成果。就是“站在巨人的肩膀上”做事情。

2.库的种类

根据链接时期的不同,库又有:静态库和共享库(动态库)

二者的不同点在于代码被载入的时刻不同

静态库的代码在编译过程中已经被载入可执行程序,因此体积较大

共享库的代码是在可执行程序运行时才载入内存的,在编译过程中仅简单的引用,因此代码体积较小。

3.静态库和动态库的比较

接静态库其实从某种意义上来说只不过它操作的对象是目标代码而不是源码而已。因为静态库被链接后库就直接嵌入可执行文件中了,这样就带来了两个问题。

(1)首先就是系统空间被浪费了。这是显而易见的,想象一下,如果多个程序链接了同一个库,则每一个生成的可执行文件就都会有一个库的副本,必然会浪费系统空间。

(2)再者,一旦发现了库中有bug,挽救起来就比较麻烦了。必须一一把链接该库的程序找出来,然后重新编译。

而动态库的出现正弥补了静态库的以上弊端。因为动态库是在程序运行时被链接的,所以磁盘上只须保留一份副本,因此节约了磁盘空间。如果发现了bug或要升级也很简单,只要用新的库把原来的替换掉就行了。

但是静态库也有自己的优点:

编译后的执行程序不需要外部的函数库支持,因为所有使用的函数都已经被编译进去了。

静态库的名字一般是libxxx.a(Linux)

动态库的名字一般是libxxx.so (Linux),有时候也是 libxxx.so.major.minor,xxxx是该lib的名称,major是主版本号, minor是副版本号

linux系统有几个重要的目录存放相应的函数库,如/lib /usr/lib

4.如何判断一个程序有没有链接动态库

(1)file命令

file程序是用来判断文件类型的,啥文件一看都清楚明了。

(2)ldd命令

看动态库,如果目标程序没有链接动态库,则打印“not a dynamic executable” (不是动态可执行文件)

<file :run和run_dyn都是可运行文件,action.h上一个ASCII C++文件>

<ldd: run_dyn 使用了共享库,action.o是不动态可执行文件>

5.linux下库文件是如何产生的

(1)静态库

静态库的后缀是.a,它的产生分两步

Step 1.由源文件编译生成一堆.o,每个.o里都包含这个编译单元的符号表

Step 2.ar命令将很多.o转换成.a,成文静态库

(2)动态库

动态库的后缀是.so,它由gcc加特定参数编译产生。

三、我的学习例子

1.要用到的工具

g++/gcc

ar

gcc常用参数

-L 加载库文件路径

-l 指明库文件名字

-fPIC 达到动态链接的目的,还有一个什么要注意的,忘了

-I dir选项的功能,在头文件的搜索路径列表中添加 dir 目录

2.我的文件

(1)doThing

//dosomething.h

  1: #ifndef DOSOMETHING_H 
  2: #define DOSOMETHING_H 
  3:  
  4: #include <string> 
  5:  
  6: void doThing(const std::string& strThing); 
  7:  
  8: #endif // DOSOMETHING_H 
  9: 

//dosomething.cpp

  1: #include "dosomething.h" 
  2: #include<iostream> 
  3:  
  4: void doThing(const std::string& strThing) 
  5: { 
  6:   std::cout << "start do thing :" << strThing << std::endl; 
  7: } 
  8: 

(2)Action类,使用doThing函数

//action.h

  1: #ifndef ACTION_H 
  2: #define ACTION_H 
  3: #include<string> 
  4:  
  5: using namespace std; 
  6:  
  7: class Action 
  8: { 
  9:   public: 
 10:     void setAction(const string& strAction); 
 11:     void doAction(void); 
 12:      
 13:   private: 
 14:     string mstrAction; 
 15: }; 
 16:  
 17: #endif // ACTION_H 
 18: 

//action.cpp

  1: #include "action.h" 
  2: #include "dosomething.h" 
  3:  
  4: void Action::setAction(const string& strAction) 
  5: { 
  6:   mstrAction = strAction; 
  7: } 
  8:  
  9: void Action::doAction(void ) 
 10: { 
 11:   doThing(mstrAction); 
 12: } 
 13: 

(3)主文件

//main.cpp

  1: #include <iostream> 
  2: #include "action.h" 
  3:  
  4: int main(int argc, char **argv) 
  5: { 
  6:      
  7:   Action action; 
  8:   action.setAction("say hello!"); 
  9:   action.doAction(); 
 10:    
 11:   return 0; 
 12: } 
 13: 

 

linux下生成写库文件代码好像更容易些,不用写Windows下面那样的在头文件还要要写DLL导出,显得很干净。

3.使用静态库的方法

基本命令:

g++ –c –o –L –l -I

ar cr 打包

最后生成了run,可以直接执行成功。

4.使用动态库

基本命令:

g++ –c –o –shared –fPIC –L –l –I

生成so时加 –shared –fPIC

我在生成后立即执行有错误了。

原因:因为在动态函数库使用时,会查找/usr/lib、/lib目录下的动态函数库,而此时我们生成的库不在里边。

这个时候有好几种方法可以让他成功运行:

(1)最直接最简单的方法就是把so拉到/usr/lib或/lib中去,但这好像有点污染环境吧?

(2)export LD_LIBRARY_PATH=$(pwd)

(3)可以在/etc/ld.so.conf文件里加入我们生成的库的目录,然后/sbin/ldconfig

关于/etc/ld.so.conf

/etc/ld.so.conf里面存放的是链接器和加载器搜索共享库时要检查的目录,默认是从/usr/lib /lib中读取的,所以想要顺利运行,我们也可以把我们库的目录加入到这个文件中并执行/sbin/ldconfig 。

关于/etc/ld.so.cache

/etc/ld.so.cache里面保存了常用的动态函数库,且会先把他们加载到内存中,因为内存的访问速度远远大于硬盘的访问速度,这样可以提高软件加载动态函数库的速度了。

使用了第(2)种方法解决问题

四、其它涉及到的东西

(1)dlopen方法的动态库显式调用

(2)gcc的各个参数

(3)makefile的编写

五、感谢

学习过程中参考了好多其它文章,由于之前存的TXT参考,无法查找出处给出链接,在这里谢谢作者,这里仅供本人学习。

您可以对本文随意转载修改或使用,但请保持正确性,不要误导他人。

本文出处:http://pppboy.blog.163.com/blog/static/302037962011112104720934/


郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。