C/C++ 静态库与动态库(静态链接与动态链接的区别)

什么是库?

库是已经写好的,成熟的,可以复用的代码。程序员编程的时候都要依赖很多基础的底层库。本质上来说库是一种可执行代码的二进制形式,可以被操作系统载入内存执行。库有两种:静态库(.a、.lib)和动态库(.so、.dll)。

回顾将源程序到可执行程序的过程:

预处理
编译
汇编
链接
.c
.i
.s
.o
a.out
链接

链接主要完成两个任务:

  1. 合并目标文件。
  2. 符号解析与重定位。
静态链接

在链接阶段,将汇编生成的.o文件和所需要的库一起链接打包到可执行文件中去。因此称为静态链接。
一个静态库可以简单看成是一组目标文件(.o/.obj文件)的集合,即很多目标文件经过压缩打包后形成的一个文件。它有以下特点

  1. 静态库对函数的链接是在编译时完成的。
  2. 移植性好。
  3. 浪费空间和资源,因为和所需要函数相关的所有的库都被打包进可执行文件了。

Linux静态库命名规范:必须是"lib[your_library_name].a"。

创建静态库的步骤

  1. 首先编译成目标文件.o:
    g++ -c statictest.cpp
    
  2. 再使用ar工具将目标文件打包成.a静态库文件(Linux下使用ar工具、Windows下vs使用lib.exe):
    ar -crv libstatictest.a statictest.o
    

    可以使用makefile文件(CMake等等工程管理工具)来生成静态库,更方便快速。

  3. 使用静态库:
    g++
    -L:库所在目录
    -l:链接时需要的库,编译器查找时会在指定的名称前加lib,后面加上.a(静态链接)或.so(动态链接)来确定库的名称。
    g++ main.cpp -L../directoryOfLib -lstatictest
    
动态链接

静态库有什么问题?

  1. 浪费空间。
  2. 库更新以后需要重新编译:库是被复制到可执行文件中去了,如果某个库更新了,则与它相关的所有可执行文件都需要重新编译。

为了解决以上问题,可以使用动态库:

  1. 解决浪费空间:动态库在编译时不会被载入,而是在程序运行时才载入。此时如果不同的应用程序调用相同的库,那么在内存中只需要一份该库的实例。
  2. 解决全量更新问题:动态库修改后不用修改重新编译生成可执行文件,增量更新。

动态库的特点:

  1. 动态库只有一份,可以实现进程之间的资源共享。(因此动态库也称为共享库)
  2. 对库函数的链接推迟到程序运行时。
  3. 程序升级变得简单。
  4. 可以在链接载入时完全由程序员在程序代码中控制。

Linux动态库命名规范:必须是"lib[your_library_name].so"。

每个共享库都有个特殊的名字"soname"。在程序启动后,程序通过这个名字来告诉动态加载器该载入哪个共享库。
在文件系统中,"soname"是一个链接。对于每个动态库来说,对于编译器来说,有一个指向实际库镜像文件 - “lib[soname].so”。

创建动态库的步骤

  1. 首先编译成目标文件.o,此时要加编译器选项-fPIC(position independent code):

    g++ -fPIC -c dynamictest.cpp
    

    -fPIC ,产生与位置无关代码(Position-IndependentCode),作用于编译阶段,使产生的代码中只有相对地址,故而代码可以被加载器加载到内存的任意位置,都可以正确的执行。这正是共享库所要求的,共享库被加载时,在内存的位置不是固定的。

  2. 生成动态库,-shared:

    g++ -shared -o libdynamictest.so dynamictest.o
    
  3. 使用动态库(同静态库):

    g++ main.cpp -L../directoryOfLib -ldynamictest
    

如何告诉系统我创建了一个动态库?或者说动态库是如何定位库的?

系统加载程序的时候,知道了所需依赖库的名称。那么它如何寻找呢?此时就需要系统动态载入器了"dynamiclinker/loader"。

对于elf格式的可执行文件,是由ld-linux.so*来完成的。它先后搜索elf文件的DT_RPATH段—环境变量LD_LIBRARY_PATH—/etc/ld.so.cache文件列表—/lib/,/usr/lib 目录找到库文件后将其载入内存。

所以,如何让系统找到库?

  1. 放在安装在/lib或者/usr/lib下。
  2. 将目录添加到/etc/ld.so.cache文件中:
    - 编辑/etc/ld.so.conf文件,加入库文件所在目录的路径。
    - 运行ldconfig ,该命令会重建/etc/ld.so.cache文件。
  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值