静态库和动态库
说到库,你可能觉得这个名词有点陌生,但是我相信你绝对听过这个词,因为你在学习c语言时一定使用过系统给你的库。我们初始c语言输出hello world你肯定调用了printf函数,而你也一定包了头文件。这个头文件实际上就是系统给我们的库,这个库中有我们经常使用的库函数的实现。
静动态的区别
既然库中有我们需要函数的实现,那么从名字上来说,静动态库至少相同的点是他们的内容应该大体相同(都是函数的定义),实际上他们唯一的不同就是链接方式的不同,这里什么又是链接方式不同?先来举两个栗子吧。
- 你是一名高中生,你特别喜欢上网,你所在的县城中只有这么一家网吧,所以每次周末都要去这家网吧上网。但是突然有一天这家网吧倒闭了,你不知道,所以你还是像往常一样周末去这家网吧上网,但是去了你却发现这家网吧已经不存在了,对于超喜欢上网的你来说彷佛世界末日。
- 你是一名高中生,你特别喜欢上网,但是你家里有矿,非常有钱,所以你自己买了一台笔记本电脑。你从来不去网吧,你想上网时只需要拿出自己的笔记本,但是缺点是,你每次都要背着重重的笔记本,就算是40度的夏天汗流浃背的你还是背着他去上课。
现在我们来通过上面的例子来分析动静态库的不同。类比例子,你去网吧的好处就是你没有任何负担,直接去上网就可以,但是缺点也很明显,网吧倒闭后你就没有办法在上网了,并且相信每次步行到网吧也不好受。自己有笔记本的好处就是想什么时候上网就什么时候,但是缺点也很明显,自己本身的负担太大。
静态库:
- 优点:依赖性不强,使用速度快
- 缺点:会导致代码的体积膨胀,存储资源浪费严重
动态库:
- 优点:使用时只需要动态寻找,代码体积不会膨胀
- 缺点:依赖性太强,动态库出问题会导致整个项目出问题,并且动态查找库也需要耗费时间
生成静态库
在linux下静态库的名字是lib+库名字+.a,有兴趣的同学可以使用ls /usr/local/lib64/ 命令查看那些后缀为.a的静态库。还记得我们是怎么使用别人的静态库的么?没错,我们每次都包了头文件,现在我们来一起写一个支持加法的库
mymath.h
我们使用别人的库都会包头文件,头文件中一般放了函数的声名
mymath.c
为了生成一个自己的库,我们需要先在mymath.c中定义我们的加法函数,下一步就是打包我们的动态库了
libmymath.a
来介绍一条命名:ar -rc 命令,这是用来打包静态库的命令,他需要用mymath.c生成的.o文件,也就是汇编之后的机器码文件
这里我们的静态库就生成了,很简单,但是这还没完,你必须把他使用起来。我们将头文件和库放在了一个lib文件下
test.c
我们将这个目录拷贝到我们需要使用的文件中,来写一个简单的代码
test
我们使用test.c生成test,但是尽管我们mymath.c头文件,我们在生成时还是报错找不到,因为系统默认搜索路径下没有我们的库,所以我们需要对gcc的选项做点文章:
现在我们再生成我们的可执行程序:
这里多提一句,现在我们先记住这里test可执行程序的大小是8616,并且这里我们把库给“干掉”,这个可执行程序还是可以执行
生成动态库
在linux下动态库的名字是lib+库名字+.so ,打包一个动态库和静态库所需要的文件全部相同(mymath.h, mymath.c),只不过是打包生成动态库的命令有所区别
这里我们打包生成动态库时需要的工具的gcc加上-shared选项,并且生成我们的依赖文件.o也需要一个新命令-fPIC,有兴趣的同学可以查一查-fPIC代表了什么意思。
同样我们把它打包成一个目录
test.c/test
我们把这个lib目录拷贝到我们的要使用的文件夹中,因为我们需要的头文件路径和库路径都没变化,所以当前目录下的makefile不用更改,我们直接make,没有问题
现在我们运行程序:报错说找不到这个库,这里我们就一脸懵逼,我们在makefile中不是已经告诉路径了么
这里在介绍一个ldd命令,可以查看当前可执行程序所依赖的库:
其实这里我们要明白,我们make中的路径是告诉编译器的,这里我们明显可执行程序已经生成,编译器的使命也就达成了,这里找不到是系统找不到这个库,所以我们要把我们库的路径导入到系统的默认路径下。
介绍一个环境变量:LD_LIBRARY_PATH,从名字中我们就知道他是做什么的,现在我们将我们自己的路径的导入到环境变量中
现在就能找到了,执行我们的代码结果输出正常
其实我们也可以把自己的动态库拷贝到/usr/lib的路径下,可是那样污染库文件的概率太大,还是尽量不要那么做为好。使用idconfig也可以跟新路径,但是这里还是推荐导出环境变量的做法。
这里还有要提的一点是,我们说静态链接文件会比动态链接文件大很多,但是由于这里我们写的库代码太少了,所以动态库也只比静态库小了一点,不过正常情况下,你可以给gcc加上-static选项看看和不加的情况下文件的大小差距有多大。结果会让你很吃惊。
总结
我们这里着重的给大家介绍了动静态库的区别,优缺点和如何生成。但是在实际的编码中相信大概率你也不会自己写一个库,首先我们的能力有限,写出的库不具有实际价值。在一个就是你现在所使用的函数,现有库中基本也都有。我们的目的是为了明白我们使用别人的库原理是怎么样的,这是很有必要了解的知识。