在Linux中,动态库和静态库是两种不同的库文件类型,它们在编译和运行时的处理方式有所不同。
静态库
- 定义:静态库是一个包含了多个目标文件的归档文件,通常以
.a
作为文件扩展名。 - 编译过程:在编译时,静态库的代码会被复制到最终生成的可执行文件中。这意味着可执行文件包含了所有需要的代码。
- 优点:
- 不依赖于外部库文件,部署时只需分发可执行文件。
- 启动速度较快,因为所有代码都已经包含在可执行文件中。
- 缺点:
- 可执行文件的体积较大,因为包含了所有库的代码。
- 更新库时需要重新编译所有依赖于该库的可执行文件。
动态库
- 定义:动态库是一个在运行时被加载的库文件,通常以
.so
作为文件扩展名(共享对象)。 - 编译过程:在编译时,动态库的引用会被记录在可执行文件中,而不是将库的代码直接复制到可执行文件中。
- 优点:
- 可执行文件体积较小,因为只包含了对动态库的引用。
- 更新库时,只需替换动态库文件,而不需要重新编译依赖于该库的可执行文件。
- 缺点:
- 运行时需要加载动态库,可能导致启动速度稍慢。
- 如果动态库缺失或版本不兼容,可能导致运行时错误。
运行加载的区别
-
静态库:
- 在编译时,静态库的代码被直接嵌入到可执行文件中,因此在运行时不需要额外加载库文件。
-
动态库:
- 在运行时,操作系统会根据可执行文件中的信息查找并加载所需的动态库。这通常通过动态链接器(如
ld.so
)来完成。 - 动态库可以在多个程序之间共享,节省内存和存储空间。
- 在运行时,操作系统会根据可执行文件中的信息查找并加载所需的动态库。这通常通过动态链接器(如
总结
- 静态库:编译时链接,运行时不需要外部库,体积大,更新不便。
- 动态库:运行时链接,体积小,更新方便,但依赖于外部库的存在和兼容性。
选择使用静态库还是动态库,通常取决于具体的应用需求和部署环境。
在 CMake 中,add_library()
函数可以用来创建库,但默认情况下它并不总是创建静态库。具体来说,add_library()
的行为取决于你提供的参数。
add_library()
的用法
-
创建静态库:
如果你使用add_library()
并且没有指定库类型,CMake 默认会创建一个静态库。示例:add_library(my_static_lib source1.cpp source2.cpp)
-
创建动态库:
如果你想创建一个动态库(共享库),需要明确指定库类型为SHARED
。示例:add_library(my_shared_lib SHARED source1.cpp source2.cpp)
- 默认情况下,
add_library()
创建的是静态库。 - 如果需要创建动态库或模块库,必须显式指定
SHARED
。
生成静态库不需要链接动态库
在生成静态库时,通常不需要链接依赖的动态库。静态库(如 .a
文件)是将目标文件(.o
文件)打包在一起的文件,编译时会将这些目标文件的代码直接包含在最终的可执行文件中。
然而,在编译静态库时,如果你的静态库的代码依赖于某些动态库的接口(例如,使用了动态库中的函数),你仍然需要在编译时确保这些接口的声明可用(通常通过包含相应的头文件)。但在生成静态库的过程中,不会将动态库的代码链接到静态库中。
当你使用这个静态库生成最终的可执行文件时,链接器会在链接阶段查找并链接所需的动态库。 因此,最终的可执行文件在运行时仍然需要这些动态库。所以生成静态库时,即使你target_link_libraries()
没有设置需要链接的动态库的信息也不会报错。但是使用这个静态库生成最终可执行文件时,会报undefined reference to
的错误。
虽然在CMakeLists.txt中通过 target_link_libraries()
设置了动态库的信息,但是在静态库对应的build.make
文件中是不会出现静态库依赖的动态库(.so
)的信息。如果想查看莫个静态库依赖了哪些动态库,可以先用一个可执行文件链接这个静态库,然后通过ldd
(只能用于动态库和可执行文件)命令查看这个可执行文件依赖哪些动态库。
生成动态库需要链接动态库
在生成动态库时,通常不会将其依赖的库直接链接到生成的动态库中。动态库(如 .dll
、.so
文件)在编译时会记录其依赖的其他库的信息,但这些依赖库不会被嵌入到动态库中。
具体来说,动态库的生成过程通常包括以下几个步骤:
- 编译源代码:将源代码编译成目标文件(.o 或 .obj 文件)。
- 链接:在链接阶段,动态库会引用它所依赖的其他库,但不会将这些库的代码直接包含在动态库中。相反,动态库会在运行时动态加载这些依赖库。
因此,当你使用一个动态库时,确保在运行时能够找到其依赖的库是非常重要的。这通常涉及到设置正确的库路径或环境变量,以便操作系统能够找到这些依赖库。
总结来说,动态库在生成时不会将依赖的库链接到库中,而是通过动态链接的方式在运行时加载这些依赖库。在动态库对应的build.make
文件中会出现依赖的动态库(.so
)的信息。