参考链接:https://blog.csdn.net/zhuquantai/article/details/100173772
何为库?
在编写代码过程中,经常会重复使用一些代码或者函数,因此,可将重复使用部分封装好,在使用时加载即可,这就是库的重要作用。库实质上是二进制形式的可执行文件,即可以被操作系统载入内存执行。库有两种形式:静态库(.a、.lib)和动态库(.so、.dll)。
所谓静态、动态是指链接。回顾一下,将一个程序编译成可执行程序的步骤:
image.png
静态库
静态库是在链接阶段,将汇编生成的目标文件.o与代码中引用到的库一起链接打包到可执行文件中。由于静态库与汇编生成的目标文件一起链接为可执行文件,那么静态库必定跟.o文件格式相似。因此,一个静态库可以简单看成是一组目标文件(.o/.obj文件)的集合,即很多目标文件经过压缩打包后形成的一个文件。静态库有如下特征:
- 静态库对函数库的链接是放在编译时期完成的;
- 程序在运行时与函数库再无瓜葛,移植方便;
- 浪费空间和资源,因为所有相关的目标文件与牵涉到的函数库被链接合成一个可执行文件。如果存在多个文件代码引用,库将被复制多份加载。
创建静态库(.a)
通过上面的流程可以知道,Linux创建静态库过程如下:
- 将代码文件编译成目标文件.o(StaticMath.o)
g++ -c StaticMath.cpp
注意带参数-c,否则直接编译为可执行文件
- 通过ar工具将目标文件打包成.a静态库文件
ar -crv libstaticmath.a StaticMath.o
生成静态库libstaticmath.a。
使用静态库
Linux下使用静态库,只需要在编译的时候,指定静态库的搜索路径(-L选项)、指定静态库名(不需要lib前缀和.a后缀,-l选项)。
g++ TestStaticLibrary.cpp -L../StaticLibrary -lstaticmath
-L:表示要连接的库所在目录
-l:指定链接时需要的动态库,编译器查找动态连接库时有隐含的命名规则,即在给出的名字前面加上lib,后面加上.a或.so来确定库的名称。
动态库(.so)
动态链接库的名字形式为 libxxx.so,前缀是lib,后缀名为“.so”。
动态库在程序编译时并不会被连接到目标代码中,而是在程序运行是才被载入。不同的应用程序如果调用相同的库,那么在内存里只需要有一份该共享库的实例,规避了空间浪费问题。动态库在程序运行是才被载入,也解决了静态库对程序的更新、部署和发布页会带来麻烦。用户只需要更新动态库即可,增量更新。
创建动态库(.so)
- 生成目标文件,此时要加编译器选项-fpic
g++ -fPIC -c DynamicMath.cpp
-fPIC 创建与地址无关的编译程序(pic,position independent code),是为了能够在多个应用程序间共享。
- 生成动态库,此时要加链接器选项-shared
g++ -shared -o libdynmath.so DynamicMath.o
-shared指定生成动态链接库。
使用动态库
引用动态库编译成可执行文件(跟静态库方式一样):
g++ TestDynamicLibrary.cpp -L../DynamicLibrary -ldynmath
如果报错,是因为:
-
当系统加载可执行代码时候,能够知道其所依赖的库的名字,但是还需要知道绝对路径。此时就需要系统动态载入器(dynamic linker/loader)。
-
对于elf格式的可执行程序,是由ld-linux.so*来完成的,它先后搜索elf文件的DT_RPATH段—环境变量LD_LIBRARY_PATH—/etc/ld.so.cache文件列表—/lib/,/usr/lib 目录找到库文件后将其载入内存。
如何让系统能够找到它:
如果安装在/lib或者/usr/lib下,那么ld默认能够找到,无需其他操作。
如果安装在其他目录,需要将其添加到/etc/ld.so.cache文件中,步骤如下:
-
编辑/etc/ld.so.conf文件,加入库文件所在目录的路径
-
运行ldconfig ,该命令会重建/etc/ld.so.cache文件
我们将创建的动态库复制到/usr/lib下面,然后运行测试程序。
网友评论