库(library)是为多个程序复用而打包的代码集合。典型的 C++ 库由两部分组成:
- 头文件:声明库向使用者暴露(提供)的功能;
- 预编译二进制文件:将该功能预先编译为机器码的实现。
某些库可能拆分为多个文件,或包含多个头文件。
库被预先编译的原因如下:
- 库通常不常改动,不必每次编写使用它的程序都重新编译,否则浪费时间;
- 预编译的目标文件为机器码,可防止他人访问或修改源代码,这对出于知识产权考虑不愿公开源码的商业机构或个人尤为重要。
库分为两类:静态库与动态库。
静态库(又称归档库,archive)
静态库中的例程在编译时被直接编译并链接到最终可执行文件中。当编译使用静态库的程序时,程序所用到的全部静态库功能都会成为可执行文件的一部分。
- Windows 下静态库扩展名通常为 .lib;
- Linux 下通常为 .a(archive)。
优点:
- 仅需分发可执行文件即可让用户运行程序;
- 由于库已嵌入程序,确保始终使用正确版本;
- 与自行编写的功能一样,可直接调用。
缺点:
- 每个可执行文件都含一份库副本,导致空间浪费;
- 升级困难——更新库时必须替换整个可执行文件。
动态库(又称共享库,shared library)
动态库中的例程在运行时才被加载到应用程序中。编译使用动态库的程序时,库并不并入可执行文件,而是保持独立。
- Windows 下扩展名通常为 .dll(dynamic link library);
- Linux 下通常为 .so(shared object)。
优点:
- 多个程序可共享同一份库,节省磁盘与内存;
- 可在不替换所有依赖程序的情况下,单独升级动态库。
由于动态库未在编译期链接,使用它们的程序必须显式加载并与动态库交互,机制复杂,接口不便。为简化使用,可借助导入库(import library)。
导入库是一种自动完成动态库加载与调用的库。
- Windows 中,通常由与动态库同名的静态库(.lib)充当;该静态库在编译期链接到程序,之后即可像使用静态库一样调用动态库功能。
- Linux 中,.so 文件本身兼具动态库与导入库角色;多数链接器在创建动态库时可同时生成导入库。
库的安装与使用
了解库的种类后,以下介绍如何在程序中使用库。C++ 库的安装通常分四步:
获取库
优先下载操作系统对应的预编译包,避免自行编译。若无预编译包,则需下载源码自行编译(本节不展开)。- Windows:库通常以 .zip 形式发布;
- Linux:通常以 .RPM 等包形式发布。包管理器可能已收录常见库(如 SDL),请先检查。
安装库
- Linux:调用包管理器自动完成;
- Windows:将库解压到自选目录,建议集中存放,如 C:\Libs,每个库单独子目录。
让编译器找到头文件
- Windows:头文件通常位于库的 include 子目录(例如库位于 C:\libs\SDL-1.2.11,则头文件在 C:\libs\SDL-1.2.11\include);
- Linux:头文件通常安装至 /usr/include,已包含在默认搜索路径;若安装在其他位置,需显式告知编译器。
告知链接器库文件位置
与第 3 步类似,需将库目录加入链接器搜索路径。- Windows:通常为库安装目录下的 lib 子目录;
- Linux:库通常安装至 /usr/lib,已包含在默认路径。
库安装完成且 IDE 知晓其位置后,每个项目还需执行以下三步:
- 若使用静态库或导入库,告知链接器需要链接的库文件;
- 在程序中加入
#include
引用库的头文件,使编译器了解库提供的全部功能; - 若使用动态库,确保程序运行时能找到它们。
- Linux:库通常位于 /usr/lib,默认搜索路径还包括 LD_LIBRARY_PATH 环境变量所列目录;
- Windows:默认搜索顺序为:程序所在目录、SetDllDirectory() 设置的目录、Windows、System、System32 目录,以及 PATH 环境变量中的目录。最简单做法是将 .dll 复制到可执行文件同级目录,发布时也通常一起分发。
步骤 3–5 涉及 IDE 配置。几乎所有 IDE 的原理相同,但界面各异,因此难点仅在于找到对应设置项。后续章节将在 Visual Studio 与 Code::Blocks 中示范上述步骤。若使用其他 IDE,可参照这两部分说明,稍加搜索即可完成配置。