编译链接 - 库

简介

  • 库是实现代码复用的官方方式,相对于其它方式,库是二进制形式更安全,更独立。
  • 库有以下两种:
  1. 动态库
  2. 静态库
  • 其它代码复用的方法
  1. 代码形式
  2. 编译时产生的中间文件:.o文件
  • 中间文件也可以代码复用,链接进程序,但是直接使用中间文件不方便,太零碎,静态库是在中间文件的基础上实现的一种代码复用方式。

静态库

  • 静态库本质上只是将中间文件打包在一起,链接时链接单位依然是中间文件,链接时被使用到的中间文件都会被链接进可执行程序,链接后可执行程序不再需要库的支持。
  • Linux系统上静态库文件以.a结尾。

链接方式

  • 静态库只支持一种方式:链接时会以中间文件为单位,将使用到中间文件链接进可执行程序。
  • 连接时只使用少量接口的静态库不会导致编译出的程序过大;经过测试得知:链接时只是将程序使用到的中间文件拷贝进程,并不会拷贝所有的中间文件
  • 由于链接单位是中间文件,因此一个中间文件中未使用到的函数也会链接进程序,为了解决这个问题,标准库等都是一个函数一个文件或者功能非常紧密的函数一个文件。

创建方法

  • 使用ar工具可以实现中间文件打包成静态库。
假设gcc已经生成了a.o, b.o, c.o,使用下面的命令即可生成libmylib.a
ar rcs libmylib.a a.o b.o c.o

动态库

  • 动态库是独立的链接单元,链接时也不会将中间文件链接进可执行程序,只是将符号表信息等链接进可执行程序,可执行程序运行时依然需要动态库的支持,在程序加载或运行时,会根据链接信息跳转到动态库相应的代码段处执行。
  • 为了实现以上,动态库不仅仅是将中间文件打包在一起,还对中间文件有特殊要求,并且打包时进行特殊处理,例如:加上可被链接实现。
  • 动态库和程序之间是相互独立的,动态库丢失,程序运行时会提示错误找不到相应的库。
  • Linux系统上动态库文件以.so结尾。

链接方式

  • 动态库支持两种链接方式:
  1. 动态链接(dynamic linking):程序启动时自动去链接动态库。
  2. 动态装载(dynamic loading):程序员通过手动调用dlopen等接口实现动态库的动态装载和卸载。

创建方法

共享内容

  • 动态库又叫做共享库,不仅仅支持单个进程进行链接,也支持多个进程进行连接,动态库共享的是代码段。

加载原理

  • 动态库加载是以进程为宿主的,动态库不能执行,没有独立的数据段,只有独立的代码段,因此数据是保存在链接进程内的。
  • 多个进程加载动态库,动态库的代码段共享,只有一份,每个进程调用时会跳转到动态库的代码段。
  • 一个进程中多个线程使用动态库,动态库中使用到的数据是共享的,因为线程和进程不同的是,在一个进程中创建线程,线程是和进程共享虚拟内存的,只是各自的线程栈不共享,

库的使用

  • 对于静态库和动态库,编译链接时库的使用方法是统一的,编译后静态库就没作用了,而动态库需要保存到相应位置。

编译链接

  1. 编译时设置需要链接的库
gcc -lxx
  • -l参数就是用来指定程序要链接的库,-l参数紧接着就是库名
  • 库名跟真正的库文件名有什么关系呢?就拿数学库来说,他的库名是m,他的库文件名是libm.so,很容易看出,把库文件名的头lib和尾.so去掉就是库名了,静态库也是一样的
  • 在静态库和动态库都存在的情况下,gcc默认是优先使用动态库的,如果需要使用静态库需要:
gcc -static -lxx
  1. 编译时设置库的路径
  • 放在/lib和/usr/lib和/usr/local/lib里的库直接用-l参数就能链接了,其它目录需要在编译时指定
-L/aaa/bbb/ccc -ltest
  • -L: “链接”的时候,去找库的目录,
  • 也就是所有的 -lFOO选项里的库,都会先从 -L 指定的目录去找,然后是默认的地方。
  • 编译时的-L选项并不影响运行时的环境变量LDLIBRARYPATH,-L只是指定了程序编译连接时库的路径,并不影响程序执行时库的路径

程序运行

  • 对于使用动态库的程序,执行时,系统会到默认路径下查找该程序所需要的库,如果找不到会提示错误信息,类似cannot open shared object file。

静态库和动态库的区别

  1. 动态库比静态库更独立:接口未变的情况下,如果静态库改变了程序必须重新编译,而动态库只替换下动态库文件就好了。
  2. 文件大小不同:相同实现的情况下,动态库为了实现共享需要做些额外处理,因此动态库比静态库更大;链接静态库的可执行程序大小比链接动态库的大,因为动态库是独立的;库大小加上可执行文件的大小,使用动态库的更大些,因此如果未使用到动态库的共享功能,在系统资源不足环境下使用静态库更节省一些。
  3. 占用内存:动态链接库如果有多个进程链接它的话,比静态链接库占有的内存少,因为动态库代码段 只占一份内存,而静态链接有多少个进程就有几份;如果只有一个进程使用动态库,动态库占用的内存反而 多点,因为动态库需要支持进程的链接,需要一些额外处理。
  4. 运行速度:静态链接比动态链接运行也快点,因为动态链接不管是运行时链接还是动态加载,运行时 都比静态链接多一步链接,链接后速度应该是一样的。

默认链接库

  • 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)
  • c++ 程序
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 库。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值