首先,我们需要知道库的概念,库说白了就是一段编译好的二进制代码,加上头文件就可以供别人使用。
那么我们为什么会用到库呢?对于程序员来说经常会遇到这样一种情况,某些代码我们需要给别人使用,但是我们不想将源码给他,这个时候,就需要以库的形式封装,只暴露出头文件。还有一种情况是,对于不会经常改动的程序代码,我们想减少编译时间,就可以打包成库,因为库已经是编译好的二进制,编译的时候只需要Link一下,不会浪费编译时间了。
Link的时候由两种方式,静态和动态链接,就随之产生了静态库和动态库,下面我们分别介绍静态库和动态库。
一、静态库
Windows下后缀名是.lib,Linux下是.a。
静态库在编译的时候会被直接拷一份,复制到目标程序中,这段代码在目标程序就不会再改变了。
优点:
* 只要编译完成后,库文件就不需要了
* 目标程序没有外部依赖,直接就可以运行
缺点:
* 使用目标程序的体积增大
静态库的生成
查看静态库中的目录列表
* t:列出静态库的文件
* v:详细信息
编译一下
运行一下
当我们将静态库删除后,运行程序仍然可以运行,说明编译完成后,库文件就不需要了
2、动态库(也称共享库)
动态库在编译的时候不会拷贝到目标文件中,目标程序只会存储指向动态库的引用。程序在运行的时候才链接动态库的代码。
优点:
* 不需要拷贝到目标程序中,不会影响目标程序的体积
* 同一份库可以被多个程序使用
* 可以随时对库进行替换,不需要重新编译代码
缺点:
* 会带来一部分的性能损失
* 使得程序依赖于外部环境,如果环境缺少动态库或库的版本不正确,会导致***程序无法运行***
动态库的生成
第一次生成失败了,原因是针对可迁移R_X86_64_32平台,只读数据段’.rodata’不能创建成共享对象,原因是在动态链接动态库的时候,没有编译成位置无关代码,那么链接的时候可能因为某些代码的位置具有相关性,而在执行时出现错误。可执行文件在链接的时候就知道每一行代码、每一个变量在线性空间的什么位置,因此这些地址都会作为常数写到代码里,对于动态库,只有加载的时候才知道。
如果代码只含只读数据段,就不会出现这个问题了。
例如,我们修改一下代码:
我们的系统是AMD64位的,所以需要在编译的时候添加-fPIC选项
我们重新生成动态库
* shared:表示生成共享格式
* fPIC:产生位置无关码
* 库名规则:libXXX.so
使用动态库
l:链接动态库,只要库名即可
L:链接库所在的路径
运行动态库
我们将动态库删除后,运行main,运行失败,说明程序在运行的时候才链接动态库的代码