2014年(124)
分类: 嵌入式
2014-08-13 20:19:23
现实中每个程序都要依赖很多基础的底层库,不可能每个人的代码都从零开始。尽量不重复做别人已经做过的事,就是尽量充分利用别人的劳动成果。就是“站在巨人的肩膀上”做事情。
2.库的种类
根据链接时期的不同,库又有:静态库和共享库(动态库)
二者的不同点在于代码被载入的时刻不同
静态库的代码在编译过程中已经被载入可执行程序,因此体积较大
共享库的代码是在可执行程序运行时才载入内存的,在编译过程中仅简单的引用,因此代码体积较小。
接静态库其实从某种意义上来说只不过它操作的对象是目标代码而不是源码而已。因为静态库被链接后库就直接嵌入可执行文件中了,这样就带来了两个问题。
(1)首先就是系统空间被浪费了。这是显而易见的,想象一下,如果多个程序链接了同一个库,则每一个生成的可执行文件就都会有一个库的副本,必然会浪费系统空间。
(2)再者,一旦发现了库中有bug,挽救起来就比较麻烦了。必须一一把链接该库的程序找出来,然后重新编译。
而动态库的出现正弥补了静态库的以上弊端。因为动态库是在程序运行时被链接的,所以磁盘上只须保留一份副本,因此节约了磁盘空间。如果发现了bug或要升级也很简单,只要用新的库把原来的替换掉就行了。
但是静态库也有自己的优点:
编译后的执行程序不需要外部的函数库支持,因为所有使用的函数都已经被编译进去了。
静态库的名字一般是libxxx.a(Linux)
动态库的名字一般是libxxx.so (Linux),有时候也是 libxxx.so.major.minor,xxxx是该lib的名称,major是主版本号, minor是副版本号
linux系统有几个重要的目录存放相应的函数库,如/lib /usr/lib
(1)file命令
file程序是用来判断文件类型的,啥文件一看都清楚明了。
(2)ldd命令
看动态库,如果目标程序没有链接动态库,则打印“not a dynamic executable” (不是动态可执行文件)
(1)静态库
静态库的后缀是.a,它的产生分两步
Step 1.由源文件编译生成一堆.o,每个.o里都包含这个编译单元的符号表
Step 2.ar命令将很多.o转换成.a,成文静态库
(2)动态库
动态库的后缀是.so,它由gcc加特定参数编译产生。
g++/gcc
ar
gcc常用参数
-L 加载库文件路径
-l 指明库文件名字
-fPIC 达到动态链接的目的,还有一个什么要注意的,忘了
-I dir选项的功能,在头文件的搜索路径列表中添加 dir 目录
(1)doThing
//dosomething.h
1: #ifndef DOSOMETHING_H2: #define DOSOMETHING_H3: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 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_H2: #define ACTION_H3: #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: #include2: #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导出,显得很干净。
基本命令:
g++ –c –o –L –l -I
ar cr 打包
最后生成了run,可以直接执行成功。
基本命令:
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的编写