当我们开发一个软件的时候,可以将软件用到的一些函数、功能等放入一个仓库——库。动态库和静态库的区别在于,前者是运行时调用,后者是编译时集成到可执行程序中的。下面是动态库和静态库的对比[1]:
比较项优点缺点动态库体积小,升级方便,编程语言间可共享可执行运行依赖,兼容性问题静态库装载较快,可能存在相同代码段运行时无依赖CMake工具生成动态库相当简单,只需要掌握一条指令add_library
利用给定源文件集合向项目增加一个输出库命令。其基本语法如下:
add_library( [STATIC | SHARED | MODULE]
[EXCLUDE_FROM_ALL]
[...])
库名为
name
,库将会从命令的[...]
所列的源文件编译;[STATIC | SHARED | MODULE]
,可以指定库的类型;STATIC
静态库,SHARED
动态库,MODULE
模块。如果这个参数没有指定,默认是STATIC
或SHARED
(具体是哪一个取决于BUILD_SHARED_LIB
是否处于ON
状态),同时POSITION_INDEPENDENT_CODE
自动开启,也就是默认创建与位置无关的库。[...]
生成库所用的源文件
默认情况下,动态库将会被创建在CMAKE_BINARY_DIR
,如果你想改变输出位置,可以尝试改变以下变量:ARCHIVE_OUT_DIRECTORY
LIBARARY_OUTPUT_DIRECTORY
RUNTIME_OUTPUT_DIRECTORY
,同样你也可以通过OUTPUT_NAME
来修改输出的库名。
在linux环境下编程,我们如果想要使用第三方的库,基本上有以下几种方式[1]:
- 1、将第三方库的源码合并到我们的工程项目代码中,一起编译。
- 2、将第三方库编译成静态库(xxx.a),我们在使用时,在Makefile中引用该静态库。
- 3、将第三方库编译成动态库(xxx.so),我们在使用时,隐性调用该动态库,具体表现为需要 在程序中包含动态库的头文件,同时需要在/usr/lib路径下,存放动态库文件,以便程序调用。
- 4、将第三方库编译成动态库(xxx.so),我们在使用时,显性调用该动态库,在程序中,不需要包含动态库的头文件,使用 dlopen、dlsym等接口函数调用该动态库。
第1和2种,本质上是一样的,使用静态库,编译时,会将静态库的内容合并到工程代码中,唯一区别的是当我们拿不到第三方库的源码时,可以直接使用静态库,相当于使用一个黑盒子,静态库提供接口。 第3和4种方式,我们常用的是第3种方式,也就是隐性调用,但是显性调用一种程序插件的概念,随用随加载,不用不加载。
1.2 对象库(不常见,可以用静态库代替)将源代码编译生成的.o
文件抽象成一个OBJECT
对象库。当你使用这个对象库时(如add_library或者add_executable),需要通过与此对象库对应的对象表达式来使用。
add_library( OBJECT [...])
Object库主要用来定义源文件编译生成的目标文件集合,可以作为其他目标的输入来源:
add_library(archive OBJECT archive.cpp zip.cpp lzma.cpp)# 将单个源文件archieve zip.cpp和lzma.cpp处理成名为archive的对象库
add_library(archiveExtras STATIC $ extras.cpp)# 通过$$作为目标程序来源
add_executable(test_exe $ test.cpp) # 同上
也可以链接到其他目标中去:
add_library(archive OBJECT archive.cpp zip.cpp lzma.cpp)
add_library(archiveExtras STATIC extras.cpp)
target_link_libraries(archiveExtras PUBLIC archive) # archieve目标库加上extras目标对象=archiveExtras
add_executable(test_exe test.cpp)
target_link_libraries(test_exe archive) # 目标文件的一个库链接
1.3 接口库
接口库是一个不编译源文件并且不产生任何实际库文件的库,但是可以有一些特性设置并且能够被安装和输出,一般来说这些属性(INTERFACE_*)如INTERFACE_INCLUDE_DIRECTORIES
,INTERFACE_COMPILE_DEFINITIONS
,INTERFACE_COMPILE_OPTIONS
, INTERFACE_LINK_LIBRARIES
,INTERFACE_SOURCES
和INTERFACE_POSITION_INDEPENDENT_CODE
,接口库只能使用以下命令:
set_property()
target_link_libraries(INTERFACE)
target_link_options(INTERFACE)
target_include_directories(INTERFACE)
target_compile_options(INTERFACE)
target_compile_definitions(INTERFACE)
target_sources(INTERFACE)
接口库主要是用在仅有头文件的库:
add_library(Eigen INTERFACE
src/eigen.h
src/vector.h
src/matrix.h
)
target_include_directories(Eigen INTERFACE
$
$
)
add_executable(exe1 exe1.cpp)
target_link_libraries(exe1 Eigen)
[1] https://docs.microsoft.com/zh-cn/windows/win32/dlls/advantages-of-dynamic-linking [2] https://cmake.org/cmake/help/latest/command/add_library.html?highlight=add_library#command:add_library [3] https://blog.csdn.net/u012351051/article/details/115497369 [4] https://zhuanlan.zhihu.com/p/56167140 [5]https://docs.microsoft.com/zh-cn/cpp/build/linking-an-executable-to-a-dll?view=msvc-170