库是写好的现有的, 成熟的, 可以复用的代码。现实中每个程序都要依赖很多基础的底层库, 不可能每个人的代码都从零开始, 因此库的存在意义非同寻常。

本质上来说库是一种可执行代码的二进制形式, 可以被操作系统载入内存执行。

库有两种:静态库(.a、.lib)和动态库(.so、.dll)。

windows上对应的是.lib .dll linux上对应的是.a .so

编译过程

源文件(.h, .cpp等) => 预编译 => 编译 => 汇编 => 链接 => 可执行文件

而静态库、动态库区别来自链接阶段如何处理库从而链接成可执行文件, 分别称为静态链接和动态链接

静态库

在链接阶段, 会将汇编生成的目标文件.o与引用到的库一起链接打包到可执行文件中。因此对应的链接方式称为静态链接。

特点:

  • 静态库对函数库的链接是在编译阶段完成的

  • 程序在运行时与函数库再无关系, 移植方便

  • 浪费空间和资源, 因为所有相关的目标文件与涉及到的函数库将被链接合成一个可执行文件

问题:

  • 空间浪费:如果静态库再内存中存在多份拷贝, 例如该静态库占用1内存, 有2000个程序运用了该静态库, 将占用将近2GB内存

  • 对程序更新、部署和发布带来麻烦: 如果静态库liba.lib 更新将导致它的应用程序都需重新编译、发布给用户。对用户而言可能是一个很小的改动, 却导致整个程序重新下载, 全量更新

动态库

动态库在程序编译时并不会被连接到目标代码中, 而是在程序运行是才被载入。不同的应用程序如果调用相同的库, 那么在内存里只需要有一份该共享库的实例, 规避了空间浪费问题。动态库在程序运行是才被载入, 也解决了静态库对程序的更新、部署和发布页会带来麻烦。用户只需要更新动态库即可, 增量更新。

特点:

  • 动态库把对一些库函数的链接载入推迟到程序运行的时期

  • 可以实现进程之间的资源共享(因此动态库也称为共享库)

  • 程序升级变得简单

  • 可以真正做到链接载入完全由程序员在程序代码中控制(显示调用)

问题:

  • “DLL地狱”: 如果较新的版本不能正确地向后兼容, 则不兼容的更新库将破坏依赖于库以前版本的可执行文件

  • 程序及其使用的库可以作为软件包进行认证(例如, 关于正确性, 文档要求或性能), 但是, 如果可以更换组件, 则不能。(这也反对在关键系统中自动进行操作系统更新;在两种情况下, 操作系统和库均构成合格环境的一部分)

参考:

Linux 中的动态链接库和静态链接库是干什么的?

Linker (computing)