简介
- 库是实现代码复用的官方方式,相对于其它方式,库是二进制形式更安全,更独立。
- 库有以下两种:
- 动态库
- 静态库
- 代码形式
- 编译时产生的中间文件:.o文件
- 中间文件也可以代码复用,链接进程序,但是直接使用中间文件不方便,太零碎,静态库是在中间文件的基础上实现的一种代码复用方式。
静态库
- 静态库本质上只是将中间文件打包在一起,链接时链接单位依然是中间文件,链接时被使用到的中间文件都会被链接进可执行程序,链接后可执行程序不再需要库的支持。
- Linux系统上静态库文件以.a结尾。
链接方式
- 静态库只支持一种方式:链接时会以中间文件为单位,将使用到中间文件链接进可执行程序。
- 连接时只使用少量接口的静态库不会导致编译出的程序过大;经过测试得知:链接时只是将程序使用到的中间文件拷贝进程,并不会拷贝所有的中间文件。
- 由于链接单位是中间文件,因此一个中间文件中未使用到的函数也会链接进程序,为了解决这个问题,标准库等都是一个函数一个文件或者功能非常紧密的函数一个文件。
创建方法
假设gcc已经生成了a.o, b.o, c.o,使用下面的命令即可生成libmylib.a
ar rcs libmylib.a a.o b.o c.o
动态库
- 动态库是独立的链接单元,链接时也不会将中间文件链接进可执行程序,只是将符号表信息等链接进可执行程序,可执行程序运行时依然需要动态库的支持,在程序加载或运行时,会根据链接信息跳转到动态库相应的代码段处执行。
- 为了实现以上,动态库不仅仅是将中间文件打包在一起,还对中间文件有特殊要求,并且打包时进行特殊处理,例如:加上可被链接实现。
- 动态库和程序之间是相互独立的,动态库丢失,程序运行时会提示错误找不到相应的库。
- Linux系统上动态库文件以.so结尾。
链接方式
- 动态链接(dynamic linking):程序启动时自动去链接动态库。
- 动态装载(dynamic loading):程序员通过手动调用dlopen等接口实现动态库的动态装载和卸载。
创建方法
共享内容
- 动态库又叫做共享库,不仅仅支持单个进程进行链接,也支持多个进程进行连接,动态库共享的是代码段。
加载原理
- 动态库加载是以进程为宿主的,动态库不能执行,没有独立的数据段,只有独立的代码段,因此数据是保存在链接进程内的。
- 多个进程加载动态库,动态库的代码段共享,只有一份,每个进程调用时会跳转到动态库的代码段。
- 一个进程中多个线程使用动态库,动态库中使用到的数据是共享的,因为线程和进程不同的是,在一个进程中创建线程,线程是和进程共享虚拟内存的,只是各自的线程栈不共享,
库的使用
- 对于静态库和动态库,编译链接时库的使用方法是统一的,编译后静态库就没作用了,而动态库需要保存到相应位置。
编译链接
- 编译时设置需要链接的库
gcc -lxx
- -l参数就是用来指定程序要链接的库,-l参数紧接着就是库名
- 库名跟真正的库文件名有什么关系呢?就拿数学库来说,他的库名是m,他的库文件名是libm.so,很容易看出,把库文件名的头lib和尾.so去掉就是库名了,静态库也是一样的
- 在静态库和动态库都存在的情况下,gcc默认是优先使用动态库的,如果需要使用静态库需要:
gcc -static -lxx
- 编译时设置库的路径
- 放在/lib和/usr/lib和/usr/local/lib里的库直接用-l参数就能链接了,其它目录需要在编译时指定
-L/aaa/bbb/ccc -ltest
- -L: “链接”的时候,去找库的目录,
- 也就是所有的 -lFOO选项里的库,都会先从 -L 指定的目录去找,然后是默认的地方。
- 编译时的-L选项并不影响运行时的环境变量LDLIBRARYPATH,-L只是指定了程序编译连接时库的路径,并不影响程序执行时库的路径
程序运行
- 对于使用动态库的程序,执行时,系统会到默认路径下查找该程序所需要的库,如果找不到会提示错误信息,类似cannot open shared object file。
静态库和动态库的区别
- 动态库比静态库更独立:接口未变的情况下,如果静态库改变了程序必须重新编译,而动态库只替换下动态库文件就好了。
- 文件大小不同:相同实现的情况下,动态库为了实现共享需要做些额外处理,因此动态库比静态库更大;链接静态库的可执行程序大小比链接动态库的大,因为动态库是独立的;库大小加上可执行文件的大小,使用动态库的更大些,因此如果未使用到动态库的共享功能,在系统资源不足环境下使用静态库更节省一些。
- 占用内存:动态链接库如果有多个进程链接它的话,比静态链接库占有的内存少,因为动态库代码段 只占一份内存,而静态链接有多少个进程就有几份;如果只有一个进程使用动态库,动态库占用的内存反而 多点,因为动态库需要支持进程的链接,需要一些额外处理。
- 运行速度:静态链接比动态链接运行也快点,因为动态链接不管是运行时链接还是动态加载,运行时 都比静态链接多一步链接,链接后速度应该是一样的。
默认链接库
- c/c++编译时,编译器不管代码内容都会链接一些默认的动态库,如下所示:
- c 程序
root@debian:~/demo$ ldd print_back
linux-gate.so.1 (0xb772d000)
libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0xb7563000)
/lib/ld-linux.so.2 (0xb772f000)
root@debian:~/demo$ ldd test
linux-gate.so.1 (0xb7721000)
libstdc++.so.6 => /usr/lib/i386-linux-gnu/libstdc++.so.6 (0xb7592000)
libm.so.6 => /lib/i386-linux-gnu/libm.so.6 (0xb753d000)
libgcc_s.so.1 => /lib/i386-linux-gnu/libgcc_s.so.1 (0xb751f000)
libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0xb7367000)
/lib/ld-linux.so.2 (0xb7723000)
- c 程序默认链接libc.so.6;c++ 程序默认链接libstdc++.so.6,libm.so.6,libgcc_s.so.1,libc.so.6。
- 混合编程c调用c++动态库 需要手动链接libstdc++.so.6 库。