CMake指令:add_library()
目录
1.简介
2.库类型详解
3.高级用法
4.库属性配置
5.安装规则
6.总结
1.简介
add_library
是 CMake 中用于定义库目标的核心命令,可创建多种类型的库。以下是其详细用法、参数和应用场景:
add_library(<name> [STATIC | SHARED | MODULE | OBJECT | INTERFACE][EXCLUDE_FROM_ALL][source1] [source2 ...])
<name>
:库的逻辑名称(如mylib
),生成的文件名为libmylib.a
(静态库)或libmylib.so
(共享库)。- 库类型(可选):
STATIC
:静态库(.a
/.lib
)。SHARED
:共享库(.so
/.dll
)。MODULE
:模块库(动态加载,类似共享库但不链接)。OBJECT
:目标文件集合(.o
/.obj
,不生成库文件)。INTERFACE
:接口库(无编译产物,仅传递编译信息)。
EXCLUDE_FROM_ALL
:可选参数,使该库不参与默认构建。[source1] [source2] [...]
:指定生成库的源文件
2.库类型详解
1. 静态库(STATIC)
add_library(mylib STATIC src/file1.cpp src/file2.cpp)
- 特点:
- 编译为
.a
(Linux)或.lib
(Windows)文件。 - 链接时被完整复制到可执行文件中,导致文件体积增大,但运行时无需依赖外部库。
- 编译为
- 适用场景:封闭系统、嵌入式开发、需要简化依赖的场景。
2.共享库(SHARED)
add_library(mylib SHARED src/file1.cpp src/file2.cpp)
- 特点:
- 编译为
.so
(Linux)或.dll
(Windows)文件。 - 运行时动态加载,多个程序可共享同一个库,减少内存占用。
- 编译为
- 适用场景:大型项目、需要动态更新库的场景。
3.模块库(MODULE)
add_library(mymodule MODULE src/module.cpp)
- 特点:
- 类似共享库,但不直接链接到可执行文件,而是通过
dlopen()
(Linux)或LoadLibrary()
(Windows)动态加载。
- 类似共享库,但不直接链接到可执行文件,而是通过
- 适用场景:插件系统、动态加载扩展功能。
4.目标文件集合(OBJECT)
add_library(myobjects OBJECT src/file1.cpp src/file2.cpp)
add_executable(myapp $<TARGET_OBJECTS:myobjects> src/main.cpp)
- 特点:
- 不生成库文件,仅编译源文件为
.o
/.obj
文件。 - 可被多个目标重复使用,减少重复编译。
- 不生成库文件,仅编译源文件为
- 适用场景:大型项目中共享公共代码、优化编译时间。
5.接口库(INTERFACE)
add_library(myinterface INTERFACE)
target_include_directories(myinterface INTERFACE include/)
- 特点:
- 无编译产物,仅用于传递编译信息(如头文件路径、编译定义)。
- 适用场景:头文件仅库(如
Eigen
)、抽象依赖关系。
3.高级用法
1. 导入现有库(IMPORTED)
add_library(external_lib SHARED IMPORTED)
set_target_properties(external_lib PROPERTIESIMPORTED_LOCATION "/path/to/libexternal.so"INTERFACE_INCLUDE_DIRECTORIES "/path/to/include"
)
- 作用:引用外部已存在的库,避免重新编译。
2.ALIAS 别名
add_library(myproject::mylib ALIAS mylib)
- 作用:为库创建别名,便于在子项目或导出时使用。
3.条件编译
if(WIN32)add_library(mylib STATIC src/win/file.cpp)
else()add_library(mylib STATIC src/unix/file.cpp)
endif()
4.库属性配置
使用 set_target_properties
或 target_*
命令配置库属性:
add_library(mylib SHARED src/file.cpp)# 设置版本信息
set_target_properties(mylib PROPERTIESVERSION "1.2.3"SOVERSION "1"
)# 添加头文件路径
target_include_directories(mylibPUBLIC include/ # 公开头文件(供依赖者使用)PRIVATE src/internal/ # 私有头文件(仅库内部使用)
)# 链接其他库
target_link_libraries(mylib PUBLIC pthread)
可见性控制:
PUBLIC
:传递给链接此库的目标,并继承给依赖该目标的其他目标。PRIVATE
:仅用于此库自身,不传递给其他目标。INTERFACE
:仅用于接口库,定义使用该库所需的配置,仅传递给链接此库的目标。
示例如下:
set(THIRD_PARTY_DIR "${CMAKE_CURRENT_SOURCE_DIR}/3rdparty" CACHE PATH "third-party")
set(MINIZ_DIR "${THIRD_PARTY_DIR}/miniz-3.0.2" CACHE PATH "miniz")add_library(miniz INTERFACE)
set_target_properties(miniz PROPERTIESINTERFACE_INCLUDE_DIRECTORIES "${MINIZ_DIR}"
)
INTERFACE_INCLUDE_DIRECTORIES:
这是一个特殊的属性,用于定义使用该库时需要包含的头文件路径。
INTERFACE
表示这些路径只传递给依赖该库的目标(即 “使用者”),而不影响库本身的编译。- 相比之下,
PUBLIC
和PRIVATE
属性会同时影响库本身和依赖它的目标。
与其他命令的对比,这行代码等价于:
target_include_directories(miniz INTERFACE "${MINIZ_DIR}")
两者的区别在于:
target_include_directories
是现代 CMake 推荐的方式,语法更简洁。set_target_properties
更适合一次性设置多个属性(见下方示例)。
实际应用场景
假设 miniz
是一个头文件仅库(Header-only Library),其他模块需要包含它的头文件才能使用。通过设置 INTERFACE_INCLUDE_DIRECTORIES
,可以让依赖 miniz
的目标自动获得正确的头文件路径:
# 设置 miniz 库的接口属性
add_library(miniz INTERFACE)
set_target_properties(miniz PROPERTIESINTERFACE_INCLUDE_DIRECTORIES "${CMAKE_SOURCE_DIR}/third_party/miniz/include"
)# 其他目标链接 miniz 时,自动包含上述目录
add_executable(my_app main.cpp)
target_link_libraries(my_app PRIVATE miniz) # 无需再手动添加 include 目录
多属性设置示例
set_target_properties
更常用于一次性设置多个属性:
set_target_properties(miniz PROPERTIESINTERFACE_INCLUDE_DIRECTORIES "${MINIZ_DIR}" # 头文件路径INTERFACE_COMPILE_DEFINITIONS "USE_MINIZ=1" # 编译定义INTERFACE_COMPILE_FEATURES "cxx_std_11" # C++ 标准要求
)
5.安装规则
install(TARGETS mylibARCHIVE DESTINATION lib # 静态库安装路径LIBRARY DESTINATION lib # 共享库安装路径RUNTIME DESTINATION bin # 可执行文件安装路径(仅适用于 MODULE)
)install(DIRECTORY include/ DESTINATION include) # 安装头文件
6.总结
add_library
是 CMake 构建系统的核心命令之一,通过灵活选择库类型和配置属性,可满足各种项目的需求。合理设计库结构和依赖关系,能显著提升项目的可维护性和跨平台兼容性。