跳到主要内容

CMake 库目标

本章将介绍如何使用 CMake 创建和管理库目标,包括静态库、动态库和接口库。

库的类型

类型关键字特点
静态库STATIC编译时链接,体积大,性能好
动态库SHARED运行时加载,体积小,更新方便
模块库MODULE运行时动态加载(插件)
对象库OBJECT编译但归档,供其他目标使用
接口库INTERFACE仅头文件,无编译输出

创建静态库

add_library(mylib STATIC
src/lib.cpp
src/helper.cpp
)

target_include_directories(mylib
PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/include
PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/src
)

创建动态库

add_library(mylib SHARED
src/lib.cpp
src/helper.cpp
)

# 设置导出符号
target_compile_definitions(mylib PRIVATE MYLIB_EXPORTS)

符号导出

mylib_export.h

#ifdef MYLIB_EXPORTS
#define MYLIB_API __attribute__((visibility("default")))
#else
#define MYLIB_API
#endif

MYLIB_API void my_function();

Windows DLL 导出

#ifdef _WIN32
#ifdef MYLIB_EXPORTS
#define MYLIB_API __declspec(dllexport)
#else
#define MYLIB_API __declspec(dllimport)
#endif
#else
#define MYLIB_API
#endif

创建接口库

接口库用于纯头文件库:

add_library(mylib INTERFACE)

target_include_directories(mylib INTERFACE
${CMAKE_CURRENT_SOURCE_DIR}/include
)

# 设置编译特性
target_compile_features(mylib INTERFACE cxx_std_17)

使用库

链接库到可执行文件

add_library(mylib STATIC src/lib.cpp)

add_executable(myapp src/main.cpp)

target_link_libraries(myapp PRIVATE mylib)

链接可见性

target_link_libraries(target
PRIVATE lib_internal # 仅当前目标使用
PUBLIC lib_public # 当前目标和依赖者都可使用
INTERFACE lib_interface # 仅依赖者可使用
)

示例

# 库 A 依赖库 B
add_library(B ...)
add_library(A ...)

# 如果 B 的头文件出现在 A 的公共头文件中
target_link_libraries(A PUBLIC B)

# 如果 B 仅在 A 的实现中使用
target_link_libraries(A PRIVATE B)

对象库

对象库编译源文件但不创建库文件:

add_library(common_obj OBJECT
src/common.cpp
src/utils.cpp
)

# 静态库使用对象库
add_library(mylib STATIC $<TARGET_OBJECTS:common_obj>)

# 动态库使用同一对象库
add_library(mylib_shared SHARED $<TARGET_OBJECTS:common_obj>)

库的安装

导出配置

add_library(mylib src/lib.cpp)

# 安装库和头文件
install(TARGETS mylib
EXPORT mylibTargets
ARCHIVE DESTINATION lib
LIBRARY DESTINATION lib
RUNTIME DESTINATION bin
INCLUDES DESTINATION include
)

install(DIRECTORY include/
DESTINATION include
)

# 导出目标
install(EXPORT mylibTargets
FILE mylibTargets.cmake
NAMESPACE mylib::
DESTINATION lib/cmake/mylib
)

版本控制

set_target_properties(mylib PROPERTIES
VERSION ${PROJECT_VERSION}
SOVERSION 1 # API 版本
)

这将生成:

  • libmylib.so.1.0.0(实际文件)
  • libmylib.so.1 -> libmylib.so.1.0.0
  • libmylib.so -> libmylib.so.1

小结

本章我们学习了:

  1. 库的类型:静态、动态、接口、对象库
  2. 创建库:add_library 命令
  3. 符号导出:跨平台 DLL/SO 导出
  4. 链接可见性:PUBLIC、PRIVATE、INTERFACE
  5. 库安装:导出配置和版本控制

练习

  1. 创建一个静态库并链接到可执行文件
  2. 实现跨平台的动态库导出
  3. 创建一个纯头文件库