【CMake】`add_library()` 命令详解

add_library() 是 CMake 中用于创建库目标的核心命令,它将源代码文件编译链接成静态库、共享库或接口库。

基本语法

1. 普通库文件

cmake 复制代码
add_library(<target> [STATIC | SHARED | MODULE]
            [EXCLUDE_FROM_ALL]
            [<source>...])

2. 导入的库

cmake 复制代码
add_library(<target> [STATIC | SHARED | MODULE | UNKNOWN] IMPORTED
            [GLOBAL])

3. 接口库

cmake 复制代码
add_library(<target> INTERFACE
            [IMPORTED] [GLOBAL])

4. 别名库

cmake 复制代码
add_library(<target> ALIAS <aliased-target>)

5. 对象库

cmake 复制代码
add_library(<target> OBJECT [<source>...])

参数详解

必需参数

<target>
  • 作用:定义库目标名称
  • 命名规则
    • 在项目中必须唯一
    • 建议使用小写字母、数字和下划线
    • 避免使用 CMake 关键字
  • 生成的文件名
    • 可通过 set_target_properties() 修改
    • 默认使用目标名作为库名

库类型关键字

类型 说明 生成文件 典型用途
STATIC 静态库 .a (Unix), .lib (Windows) 链接时复制代码到可执行文件
SHARED 共享库 .so (Linux), .dylib (macOS), .dll (Windows) 运行时动态加载
MODULE 模块库 同共享库,但不链接到其他目标 插件、可加载模块
INTERFACE 接口库 不生成实际库文件 仅头文件库、传递依赖
OBJECT 对象库 .obj/.o 文件集合 源码级复用
IMPORTED 导入库 引用外部已构建的库 第三方库、系统库

详细用法示例

1. 静态库

cmake 复制代码
# 创建静态库
add_library(mystatic STATIC
    src/mylib.cpp
    src/utils.cpp
    include/mylib.h
)

# 设置静态库属性
set_target_properties(mystatic PROPERTIES
    OUTPUT_NAME "mystatic"          # 输出文件名
    ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib"
    POSITION_INDEPENDENT_CODE ON    # 启用 PIC(某些情况下需要)
)

# 链接静态库
add_executable(myapp main.cpp)
target_link_libraries(myapp PRIVATE mystatic)

2. 共享库

cmake 复制代码
# 创建共享库
add_library(myshared SHARED
    src/mylib.cpp
    src/utils.cpp
    include/mylib.h
)

# 设置版本信息
set_target_properties(myshared PROPERTIES
    VERSION 1.2.3                   # 完整版本号
    SOVERSION 1                     # API 版本号
    OUTPUT_NAME "myshared"          # 库文件名(不含扩展名)
    LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib"
    RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin"  # Windows DLL
)

# 平台特定设置
if(WIN32)
    # Windows DLL 需要导出符号
    target_compile_definitions(myshared PRIVATE MYSHARED_EXPORTS)
    target_sources(myshared PRIVATE src/mylib.def)  # 模块定义文件
endif()

# 链接共享库
add_executable(myapp main.cpp)
target_link_libraries(myapp PRIVATE myshared)

3. 模块库

cmake 复制代码
# 创建模块库(插件)
add_library(myplugin MODULE
    src/plugin.cpp
    src/plugin_impl.cpp
    include/plugin.h
)

# 模块库特定设置
set_target_properties(myplugin PROPERTIES
    PREFIX ""                       # 移除 "lib" 前缀
    SUFFIX ".plugin"                # 自定义后缀
    LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/plugins"
)

# 设置插件符号可见性
target_compile_definitions(myplugin PRIVATE
    MYPLUGIN_BUILDING_DLL
)

# 导出插件接口
target_include_directories(myplugin PUBLIC
    $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
    $<INSTALL_INTERFACE:include>
)

4. 接口库

cmake 复制代码
# 创建接口库(仅头文件库)
add_library(myheader INTERFACE)

# 添加头文件包含目录
target_include_directories(myheader INTERFACE
    ${CMAKE_CURRENT_SOURCE_DIR}/include
)

# 添加编译定义
target_compile_definitions(myheader INTERFACE
    USE_MYHEADER=1
)

# 添加编译特性
target_compile_features(myheader INTERFACE cxx_std_17)

# 添加链接选项
target_link_libraries(myheader INTERFACE
    Threads::Threads
)

# 使用接口库
add_executable(myapp main.cpp)
target_link_libraries(myapp PRIVATE myheader)

5. 对象库

cmake 复制代码
# 创建对象库
add_library(myobjects OBJECT
    src/common.cpp
    src/utils.cpp
)

# 在其他目标中重用对象文件
add_executable(app1 app1.cpp)
add_executable(app2 app2.cpp)

# 链接对象库
target_link_libraries(app1 PRIVATE myobjects)
target_link_libraries(app2 PRIVATE myobjects)

# 对象库也可以有自己的依赖
target_include_directories(myobjects PUBLIC include)
target_compile_definitions(myobjects PRIVATE COMMON_DEFINE=1)

6. 导入库

cmake 复制代码
# 导入已存在的库
add_library(external_lib STATIC IMPORTED)

# 设置导入库的路径
set_target_properties(external_lib PROPERTIES
    IMPORTED_LOCATION "/usr/lib/libexternal.a"
    INTERFACE_INCLUDE_DIRECTORIES "/usr/include/external"
)

# 导入不同配置的库
add_library(external_shared SHARED IMPORTED)

set_target_properties(external_shared PROPERTIES
    IMPORTED_LOCATION_DEBUG "/path/to/debug/libexternal.so"
    IMPORTED_LOCATION_RELEASE "/path/to/release/libexternal.so"
    INTERFACE_INCLUDE_DIRECTORIES "/usr/include/external"
)

# 使用导入库
add_executable(myapp main.cpp)
target_link_libraries(myapp PRIVATE external_lib external_shared)

高级特性

1. 条件编译库类型

cmake 复制代码
# 根据选项决定构建静态库还是共享库
option(BUILD_SHARED_LIBS "构建共享库" ON)

if(BUILD_SHARED_LIBS)
    add_library(mylib SHARED src/mylib.cpp)
else()
    add_library(mylib STATIC src/mylib.cpp)
endif()

# 或者使用 CMake 内置变量
set(BUILD_SHARED_LIBS ON CACHE BOOL "构建共享库")
add_library(mylib src/mylib.cpp)  # 类型由 BUILD_SHARED_LIBS 决定

2. 生成器表达式

cmake 复制代码
# 根据配置添加不同的源文件
add_library(mylib
    src/base.cpp
    $<$<CONFIG:Debug>:src/debug_helpers.cpp>
    $<$<CONFIG:Release>:src/optimizations.cpp>
    $<$<BOOL:${ENABLE_FEATURE_X}>:src/feature_x.cpp>
)

# 平台特定的源文件
add_library(mylib
    src/common.cpp
    $<$<PLATFORM_ID:Windows>:src/win32_specific.cpp>
    $<$<PLATFORM_ID:Linux>:src/linux_specific.cpp>
    $<$<PLATFORM_ID:Darwin>:src/macos_specific.mm>
)

# 编译器特定的编译选项
target_compile_options(mylib PRIVATE
    $<$<CXX_COMPILER_ID:GNU>:-Wall>
    $<$<CXX_COMPILER_ID:MSVC>:/W4>
)

3. 库的组合和聚合

cmake 复制代码
# 创建多个子库
add_library(core STATIC src/core.cpp)
add_library(utils STATIC src/utils.cpp)
add_library(network STATIC src/network.cpp)

# 创建聚合库
add_library(full_lib INTERFACE)
target_link_libraries(full_lib INTERFACE core utils network)

# 或者创建实际的库包装
add_library(combined SHARED)
target_sources(combined PRIVATE
    $<TARGET_OBJECTS:core>
    $<TARGET_OBJECTS:utils>
    $<TARGET_OBJECTS:network>
)

# 设置合并库的属性
set_target_properties(combined PROPERTIES
    OUTPUT_NAME "combined"
    VERSION 1.0.0
    SOVERSION 1
)

4. 符号可见性控制

cmake 复制代码
# 设置默认符号可见性
set(CMAKE_CXX_VISIBILITY_PRESET hidden)
set(CMAKE_VISIBILITY_INLINES_HIDDEN ON)

add_library(mylib SHARED src/mylib.cpp)

# 显式导出特定符号
target_compile_definitions(mylib PRIVATE
    MYLIB_BUILDING_DLL
)

# 在头文件中使用:
# #ifdef MYLIB_BUILDING_DLL
#   #define MYLIB_API __declspec(dllexport)
# #else
#   #define MYLIB_API __declspec(dllimport)
# #endif

# 或者使用生成器表达式
target_compile_definitions(mylib PRIVATE
    $<$<BOOL:${BUILD_SHARED_LIBS}>:MYLIB_BUILDING_DLL>
)

目标属性设置

常用库属性

cmake 复制代码
add_library(mylib src/mylib.cpp)

# 输出文件相关
set_target_properties(mylib PROPERTIES
    OUTPUT_NAME "mylib"                     # 基本名称
    PREFIX ""                               # 前缀(默认为 "lib")
    SUFFIX ".so"                            # 后缀
    IMPORT_PREFIX ""                        # 导入库前缀
    IMPORT_SUFFIX ".lib"                    # 导入库后缀
)

# 版本控制
set_target_properties(mylib PROPERTIES
    VERSION ${PROJECT_VERSION}              # 完整版本号
    SOVERSION ${PROJECT_VERSION_MAJOR}      # API 版本号
    MACOSX_RPATH ON                         # macOS RPATH 处理
)

# 输出目录
set_target_properties(mylib PROPERTIES
    ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib"
    LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib"
    RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin"  # Windows DLL
)

# 编译特性
set_target_properties(mylib PROPERTIES
    CXX_STANDARD 17
    CXX_STANDARD_REQUIRED ON
    CXX_EXTENSIONS OFF
    POSITION_INDEPENDENT_CODE ON            # 启用 PIC
)

平台特定属性

cmake 复制代码
if(WIN32)
    set_target_properties(mylib PROPERTIES
        WINDOWS_EXPORT_ALL_SYMBOLS ON       # 自动导出所有符号
        MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>"
    )
    
    # 添加模块定义文件
    if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/mylib.def)
        target_sources(mylib PRIVATE mylib.def)
    endif()
    
elseif(APPLE)
    set_target_properties(mylib PROPERTIES
        MACOSX_FRAMEWORK_IDENTIFIER "com.company.mylib"
        MACOSX_FRAMEWORK_BUNDLE_VERSION ${PROJECT_VERSION}
        XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY "Apple Development"
    )
    
elseif(UNIX)
    set_target_properties(mylib PROPERTIES
        NO_SONAME FALSE                     # 是否生成 SONAME
        VERSION ${PROJECT_VERSION}
        SOVERSION ${PROJECT_VERSION_MAJOR}
    )
endif()

完整项目示例

示例1:跨平台数学库

cmake 复制代码
cmake_minimum_required(VERSION 3.15)
project(MathLibrary VERSION 2.1.0 LANGUAGES CXX)

# 选项配置
option(BUILD_SHARED_LIBS "构建共享库" ON)
option(BUILD_TESTING "构建测试" ON)
option(ENABLE_SIMD "启用 SIMD 优化" OFF)

# 设置 C++ 标准
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

# 源文件分组
set(MATH_CORE_SOURCES
    src/core/vector.cpp
    src/core/matrix.cpp
    src/core/quaternion.cpp
)

set(MATH_ALGEBRA_SOURCES
    src/algebra/solver.cpp
    src/algebra/eigen.cpp
    src/algebra/lu_decomposition.cpp
)

set(MATH_GEOMETRY_SOURCES
    src/geometry/shapes.cpp
    src/geometry/intersection.cpp
    src/geometry/transform.cpp
)

set(MATH_HEADERS
    include/mathlib/core/vector.h
    include/mathlib/core/matrix.h
    include/mathlib/algebra/solver.h
    include/mathlib/geometry/shapes.h
)

# SIMD 优化源文件(可选)
if(ENABLE_SIMD)
    if(CMAKE_SYSTEM_PROCESSOR MATCHES "x86|x86_64|AMD64")
        list(APPEND MATH_CORE_SOURCES src/core/simd_x86.cpp)
        target_compile_definitions(mathlib PRIVATE MATHLIB_USE_SIMD)
        target_compile_options(mathlib PRIVATE -msse2 -mavx)
    elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "arm|aarch64")
        list(APPEND MATH_CORE_SOURCES src/core/simd_arm.cpp)
        target_compile_definitions(mathlib PRIVATE MATHLIB_USE_SIMD)
        target_compile_options(mathlib PRIVATE -mfpu=neon)
    endif()
endif()

# 创建主库
add_library(mathlib
    ${MATH_CORE_SOURCES}
    ${MATH_ALGEBRA_SOURCES}
    ${MATH_GEOMETRY_SOURCES}
    ${MATH_HEADERS}
)

# 设置库属性
set_target_properties(mathlib PROPERTIES
    VERSION ${PROJECT_VERSION}
    SOVERSION ${PROJECT_VERSION_MAJOR}
    OUTPUT_NAME "mathlib"
    DEBUG_POSTFIX "_d"
    CXX_VISIBILITY_PRESET hidden
    VISIBILITY_INLINES_HIDDEN ON
)

# 包含目录
target_include_directories(mathlib PUBLIC
    $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
    $<INSTALL_INTERFACE:include>
)

# 编译定义
target_compile_definitions(mathlib PUBLIC
    MATHLIB_VERSION=${PROJECT_VERSION}
    $<$<CONFIG:Debug>:MATHLIB_DEBUG=1>
)

# 依赖项
find_package(Eigen3 3.3 REQUIRED)
target_link_libraries(mathlib PUBLIC Eigen3::Eigen)

if(UNIX)
    target_link_libraries(mathlib PUBLIC m)  # 数学库
endif()

# 创建接口库用于头文件
add_library(mathlib_headers INTERFACE)
target_include_directories(mathlib_headers INTERFACE include)

# 安装配置
include(GNUInstallDirs)

install(TARGETS mathlib mathlib_headers
    EXPORT MathLibraryTargets
    ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
    LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
    RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
    PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/mathlib
)

# 测试(可选)
if(BUILD_TESTING)
    enable_testing()
    add_subdirectory(tests)
endif()

示例2:插件系统

cmake 复制代码
cmake_minimum_required(VERSION 3.16)
project(PluginSystem VERSION 1.0.0)

# 主应用程序
add_executable(plugin_host
    src/host/main.cpp
    src/host/plugin_manager.cpp
)

# 插件接口(头文件库)
add_library(plugin_api INTERFACE)
target_include_directories(plugin_api INTERFACE include)
target_compile_definitions(plugin_api INTERFACE PLUGIN_API_VERSION=2)

# 为插件接口设置导出宏
if(WIN32)
    target_compile_definitions(plugin_api INTERFACE
        PLUGIN_EXPORT=__declspec(dllexport)
        PLUGIN_IMPORT=__declspec(dllimport)
    )
else()
    target_compile_definitions(plugin_api INTERFACE
        PLUGIN_EXPORT=__attribute__((visibility("default")))
        PLUGIN_IMPORT=
    )
endif()

# 示例插件1:图像过滤器
add_library(filter_plugin MODULE
    plugins/filter/src/filter_plugin.cpp
    plugins/filter/src/blur_filter.cpp
    plugins/filter/include/filter_plugin.h
)

target_link_libraries(filter_plugin PRIVATE plugin_api)
set_target_properties(filter_plugin PROPERTIES
    PREFIX ""
    SUFFIX ".plugin"
    LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/plugins
    RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/plugins  # Windows
)

# 示例插件2:效果插件
add_library(effect_plugin MODULE
    plugins/effect/src/effect_plugin.cpp
    plugins/effect/src/glow_effect.cpp
    plugins/effect/include/effect_plugin.h
)

target_link_libraries(effect_plugin PRIVATE plugin_api)
set_target_properties(effect_plugin PROPERTIES
    PREFIX ""
    SUFFIX ".plugin"
    LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/plugins
)

# 设置插件符号可见性
if(NOT WIN32)
    target_compile_options(filter_plugin PRIVATE -fvisibility=hidden)
    target_compile_options(effect_plugin PRIVATE -fvisibility=hidden)
endif()

# 安装插件
install(TARGETS filter_plugin effect_plugin
    LIBRARY DESTINATION lib/plugins
    RUNTIME DESTINATION bin/plugins  # Windows DLL
)

# 插件加载器库
add_library(plugin_loader SHARED
    src/loader/plugin_loader.cpp
    src/loader/plugin_registry.cpp
)

target_link_libraries(plugin_loader PRIVATE plugin_api)
target_link_libraries(plugin_host PRIVATE plugin_loader)

示例3:对象库的高级用法

cmake 复制代码
cmake_minimum_required(VERSION 3.18)
project(ObjectLibraryDemo VERSION 1.0.0)

# 公共对象库(包含通用功能)
add_library(common_objects OBJECT
    src/common/logging.cpp
    src/common/config.cpp
    src/common/utils.cpp
)

target_include_directories(common_objects PUBLIC include/common)
target_compile_definitions(common_objects PUBLIC COMMON_BUILD)

# 网络对象库
add_library(network_objects OBJECT
    src/network/tcp_client.cpp
    src/network/tcp_server.cpp
    src/network/udp_socket.cpp
)

target_include_directories(network_objects PUBLIC include/network)
target_compile_definitions(network_objects PUBLIC NETWORK_BUILD)
target_link_libraries(network_objects PUBLIC common_objects)

# 数据库对象库
add_library(database_objects OBJECT
    src/database/connection.cpp
    src/database/query.cpp
    src/database/transaction.cpp
)

target_include_directories(database_objects PUBLIC include/database)
target_compile_definitions(database_objects PUBLIC DATABASE_BUILD)
target_link_libraries(database_objects PUBLIC common_objects)

# 应用程序1:网络服务
add_executable(network_service
    src/apps/network_service.cpp
    $<TARGET_OBJECTS:common_objects>
    $<TARGET_OBJECTS:network_objects>
)

target_compile_definitions(network_service PRIVATE SERVICE_NETWORK)

# 应用程序2:数据库工具
add_executable(database_tool
    src/apps/database_tool.cpp
    $<TARGET_OBJECTS:common_objects>
    $<TARGET_OBJECTS:database_objects>
)

target_compile_definitions(database_tool PRIVATE TOOL_DATABASE)

# 应用程序3:完整应用(使用所有对象库)
add_executable(full_app
    src/apps/full_app.cpp
    $<TARGET_OBJECTS:common_objects>
    $<TARGET_OBJECTS:network_objects>
    $<TARGET_OBJECTS:database_objects>
)

# 创建静态库版本(重用对象)
add_library(full_static STATIC
    $<TARGET_OBJECTS:common_objects>
    $<TARGET_OBJECTS:network_objects>
    $<TARGET_OBJECTS:database_objects>
)

set_target_properties(full_static PROPERTIES
    OUTPUT_NAME "applib"
    ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib
)

最佳实践

1. 命名规范

cmake 复制代码
# 使用清晰的前缀
add_library(company_core STATIC ...)        # 公司核心库
add_library(project_utils SHARED ...)       # 项目工具库
add_library(external_boost IMPORTED ...)    # 外部库

# 避免通用名称
# 不好:add_library(utils ...)
# 好:add_library(myproject_utils ...)

2. 头文件管理

cmake 复制代码
# 方法1:将头文件添加到源文件列表(IDE友好)
add_library(mylib
    src/mylib.cpp
    include/mylib/public.h
    src/mylib/private.h
)

# 方法2:使用 PUBLIC_HEADER 属性
add_library(mylib src/mylib.cpp)
set_target_properties(mylib PROPERTIES
    PUBLIC_HEADER "include/mylib/public.h"
)

# 方法3:接口库包装头文件
add_library(mylib_headers INTERFACE)
target_include_directories(mylib_headers INTERFACE include)
add_library(mylib src/mylib.cpp)
target_link_libraries(mylib PUBLIC mylib_headers)

3. 版本控制策略

cmake 复制代码
# 语义化版本控制
set(PROJECT_VERSION_MAJOR 2)
set(PROJECT_VERSION_MINOR 1)
set(PROJECT_VERSION_PATCH 3)
set(PROJECT_VERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}")

add_library(mylib SHARED ...)
set_target_properties(mylib PROPERTIES
    VERSION ${PROJECT_VERSION}      # 完整版本号
    SOVERSION ${PROJECT_VERSION_MAJOR}  # API 版本(ABI 兼容)
)

# 生成版本头文件
configure_file(
    ${CMAKE_CURRENT_SOURCE_DIR}/include/mylib/version.h.in
    ${CMAKE_CURRENT_BINARY_DIR}/include/mylib/version.h
)
target_include_directories(mylib PUBLIC
    $<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}/include>
)

4. 跨平台兼容性

cmake 复制代码
add_library(mylib SHARED ...)

# Windows 特定设置
if(WIN32)
    # 自动导出所有符号(简化方式)
    set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)
    
    # 或者使用模块定义文件
    if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/mylib.def)
        target_sources(mylib PRIVATE mylib.def)
    endif()
    
    # 运行时库设置
    if(MSVC)
        set_target_properties(mylib PROPERTIES
            MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>DLL"
        )
    endif()
endif()

# Unix 系统设置
if(UNIX AND NOT APPLE)
    # RPATH 处理
    set_target_properties(mylib PROPERTIES
        BUILD_WITH_INSTALL_RPATH TRUE
        INSTALL_RPATH "$ORIGIN/../lib"
    )
endif()

# macOS 设置
if(APPLE)
    set_target_properties(mylib PROPERTIES
        MACOSX_RPATH ON
        INSTALL_NAME_DIR "@rpath"
    )
endif()

常见问题和解决方案

问题1:符号冲突

cmake 复制代码
# 不同库中的同名函数冲突
# 解决方案1:使用命名空间
add_library(lib1 STATIC src1.cpp)
target_compile_definitions(lib1 PRIVATE LIB1_NAMESPACE=lib1)

add_library(lib2 STATIC src2.cpp)  
target_compile_definitions(lib2 PRIVATE LIB2_NAMESPACE=lib2)

# 解决方案2:隐藏符号(共享库)
set(CMAKE_CXX_VISIBILITY_PRESET hidden)
set(CMAKE_VISIBILITY_INLINES_HIDDEN ON)
add_library(mylib SHARED ...)

# 显式导出需要的符号
target_compile_definitions(mylib PRIVATE MYLIB_EXPORTS)
# 在头文件中:#ifdef MYLIB_EXPORTS
#              #define API __declspec(dllexport)
#              #else
#              #define API __declspec(dllimport)
#              #endif

问题2:循环依赖

cmake 复制代码
# 库A依赖库B,库B又依赖库A
# 解决方案:提取公共接口
add_library(common INTERFACE)
target_compile_features(common INTERFACE cxx_std_17)
target_include_directories(common INTERFACE include)

add_library(libA STATIC libA.cpp)
target_link_libraries(libA PUBLIC common)

add_library(libB STATIC libB.cpp)
target_link_libraries(libB PUBLIC common libA)  # 单向依赖

# 或者使用对象库
add_library(common_objects OBJECT common1.cpp common2.cpp)
add_library(libA STATIC libA.cpp $<TARGET_OBJECTS:common_objects>)
add_library(libB STATIC libB.cpp $<TARGET_OBJECTS:common_objects>)

问题3:安装后找不到库

cmake 复制代码
# 安装时设置正确的 RPATH
include(GNUInstallDirs)

install(TARGETS mylib
    LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
    RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}  # Windows DLL
)

# 设置安装 RPATH
if(UNIX AND NOT APPLE)
    set_target_properties(mylib PROPERTIES
        INSTALL_RPATH "$ORIGIN/../${CMAKE_INSTALL_LIBDIR}"
        BUILD_WITH_INSTALL_RPATH TRUE
    )
endif()

# 创建导入目标供 find_package 使用
install(EXPORT mylib-targets
    FILE MyLibConfig.cmake
    NAMESPACE MyLib::
    DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/MyLib
)

调试技巧

检查库属性

cmake 复制代码
add_library(mylib STATIC src.cpp)

# 查看所有属性
get_target_property(props mylib PROPERTIES)
foreach(prop ${props})
    get_target_property(value mylib ${prop})
    if(value)
        message(STATUS "${prop} = ${value}")
    endif()
endforeach()

# 查看源文件
get_target_property(sources mylib SOURCES)
message(STATUS "源文件: ${sources}")

# 查看链接库
get_target_property(link_libs mylib LINK_LIBRARIES)
message(STATUS "链接库: ${link_libs}")

验证库类型

cmake 复制代码
function(validate_library target expected_type)
    if(NOT TARGET ${target})
        message(FATAL_ERROR "目标 ${target} 不存在")
    endif()
    
    get_target_property(actual_type ${target} TYPE)
    
    if(NOT actual_type STREQUAL expected_type)
        if(expected_type STREQUAL "STATIC_LIBRARY")
            set(expected_str "静态库")
        elseif(expected_type STREQUAL "SHARED_LIBRARY")
            set(expected_str "共享库")
        elseif(expected_type STREQUAL "MODULE_LIBRARY")
            set(expected_str "模块库")
        else()
            set(expected_str ${expected_type})
        endif()
        
        message(WARNING "${target} 不是 ${expected_str}")
    endif()
endfunction()

# 使用示例
add_library(mystatic STATIC ...)
validate_library(mystatic "STATIC_LIBRARY")

add_library(myshared SHARED ...)
validate_library(myshared "SHARED_LIBRARY")

add_library() 是 CMake 构建系统的核心,合理使用可以创建高效、可维护的库组件,支持复杂的项目结构和跨平台部署需求。掌握不同类型的库及其特性,对于构建专业级软件项目至关重要。

相关推荐
十五年专注C++开发5 小时前
CMake进阶:find_package使用总结
开发语言·c++·cmake·跨平台编译
Source.Liu1 天前
【CMake】`add_executable()` 命令详解
cmake
Source.Liu2 天前
【CMake】概述
cmake
charlee443 天前
CMake构建学习笔记32-CMake版本切换
cmake·版本管理·构建·update·alternatives
阳洞洞4 天前
cmake中如何从include_directories中移除某个特定的头文件
c++·cmake
Mr_WangAndy4 天前
cmake_CMake内置属性解决头文件包含/CMake定义C/C++标准/include_directories()/宏定义
cmake·宏定义·c++标准·头文件包含
番茄灭世神5 天前
使用VScode开发ARM核芯片通用配置
arm开发·vscode·mcu·cmake·clangd·llvm·ninja
charlee446 天前
CMake构建学习笔记31-构建前执行可执行程序
sqlite·cmake·构建·构建前脚本
Mr_WangAndy7 天前
cmake_file(GLOB)详解
cmake·cmake file·cmake文件操作