前言
当我们开发一个较大规模的程序时,将代码拆分为多个模块可提高可维护性和代码重用性。在C++中,我们可以通过创建和使用静态库和动态库来实现这一点。在本篇博客中,我将为你介绍如何创建和使用静态库和动态库。
一、动态库与静态库
1、静态库以及优缺点
静态库:在编译时与程序代码直接链接,生成的可执行文件包含了库中所有需要的代码。因此,可执行文件较大,但不需要额外的库文件。静态库:通常以 .lib(Windows)或 .a(Linux/UNIX)为扩展名。
静态库的优点:
简单易用:静态库是一组已编译好的目标文件的集合,使用起来非常简单方便,只需链接到应用程序中即可。
独立性:静态库包含了其所需的所有代码和依赖项,使得应用程序在不同的环境中也能独立运行,不受外部环境的影响。
性能优势:静态库在编译时被完整地链接到应用程序中,可以在编译期间进行优化,减少了运行时的开销,因此通常具有更好的性能。
静态库的缺点:
冗余:由于静态库将其所有代码和依赖项都链接到应用程序中,可能会导致应用程序的体积较大,占用较多的存储空间。
更新麻烦:如果静态库更新了,需要重新编译并重新链接整个应用程序,这可能会增加维护的复杂性。
版本问题:如果应用程序使用的是不同版本的静态库,可能会导致冲突和兼容性问题。在这种情况下,需要小心管理库的版本,并确保正确链接适当的版本。
2、动态库以及优缺点
动态库:在编译时不直接链接到程序中,而是在程序运行时动态链接。生成的可执行文件不包含库中的代码,只包含对库的引用。因此,可执行文件较小,但需要库文件才能运行。动态库:通常以 .dll(Windows)或 .so(Linux/UNIX)为扩展名。
优点:
代码重用:动态库允许多个程序共享相同的代码,有助于减少冗余和提高维护性。
内存占用:由于多个程序可以共享同一动态库的内存实例,因此可以减少内存占用。
更新简便:对动态库的更新不需要重新编译使用它的程序,只需要替换动态库文件即可。这可以降低更新和维护成本。
缺点:
代码重用:动态库允许多个程序共享相同的代码,有助于减少冗余和提高维护性。
内存占用:由于多个程序可以共享同一动态库的内存实例,因此可以减少内存占用。
更新简便:对动态库的更新不需要重新编译使用它的程序,只需要替换动态库文件即可。这可以降低更新和维护成本。
二、静态库的制作与使用
创建静态库
静态库是编译后的目标文件的集合,可以被链接到应用程序中。下面是创建静态库的步骤:
-
编写源代码文件并编译为目标文件(.o):首先,你需要编写你的源代码文件,然后使用编译器将其编译为目标文件。例如,假设有两个源代码文件
math.cpp
和string.cpp
:// math.cpp int add(int a, int b) { return a + b; } // string.cpp #include <string> std::string concatenate(const std::string& str1, const std::string& str2) { return str1 + str2; }
使用以下命令分别将这两个源文件编译为目标文件:
g++ -c math.cpp -o math.o g++ -c string.cpp -o string.o
-
将目标文件打包为静态库(.a):使用
ar
命令将目标文件打包为静态库。例如,将上一步生成的两个目标文件打包为静态库libmylib.a
:ar rcs libmylib.a math.o string.o
此命令将创建名为
libmylib.a
的静态库。
使用静态库
一旦创建了静态库,我们可以在应用程序中使用它。以下是使用静态库的步骤:
-
编写应用程序源代码:编写一个应用程序的源代码文件,使用静态库中提供的函数或类等。例如,假设有一个应用程序文件
main.cpp
:#include <iostream> #include "math.h" int main() { int result = add(3, 4); std::cout << "Result: " << result << std::endl; return 0; }
-
编译应用程序并链接静态库:使用编译器编译应用程序源代码,并将静态库链接到应用程序中。例如,使用以下命令编译
main.cpp
并链接libmylib.a
静态库:g++ main.cpp -o main -L. -lmylib
此命令将生成可执行文件
main
。-L.
:指定静态库所在的目录(当前目录)。-lmylib
:指定要链接的静态库的名称(去掉lib
前缀和.a
后缀)。
-
运行应用程序:运行生成的可执行文件。
./main
应该会看到输出的结果为
Result: 7
。
三、动态库的制作与使用
创建动态库
与静态库不同,动态库在运行时被加载。下面是创建动态库的步骤:
-
编写源代码文件并编译为目标文件(.o):与创建静态库相同,你需要将源代码文件编译为目标文件。
-
将目标文件编译为共享对象(.so):使用以下命令将目标文件编译为动态库:
g++ -shared -o libmylib.so math.o string.o
此命令将创建名为
libmylib.so
的动态库。
使用动态库
使用动态库与使用静态库类似,以下是使用动态库的步骤:
-
编写应用程序源代码:编写一个应用程序的源代码文件,使用动态库中提供的函数或类等。
-
编译应用程序并链接动态库:与使用静态库相比,编译和链接的命令稍有不同:
g++ main.cpp -o main -L. -lmylib
其中,
-lmylib
指定要链接的动态库名称,而编译器会根据系统配置自动查找和加载动态库。 -
运行应用程序:运行生成的可执行文件。
./main
你应该能够看到与静态库相同的输出结果。
四、cmake编写静态库与动态库
cmake_minimum_required(VERSION 3.12)
project(MyProject)
# 添加源代码文件
add_executable(MyApp main.cpp)
# 添加静态库
add_library(MyLib STATIC math.cpp string.cpp)
# 添加动态库
add_library(MyLib SHARED math.cpp string.cpp)
# 链接静态库到应用程序
target_link_libraries(MyApp PRIVATE MyLib)