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

set_target_properties() 是 CMake 中用于设置目标属性的关键命令,它允许精细控制库、可执行文件等目标的构建行为、输出特性和安装配置。

基本语法

cmake 复制代码
set_target_properties(target1 target2 ...
                      PROPERTIES
                        property1 value1
                        property2 value2
                        ...
)

属性分类详解

一、输出文件属性

1. 名称和前缀后缀
cmake 复制代码
set_target_properties(mylib PROPERTIES
    OUTPUT_NAME "mylib"           # 输出文件基本名(不包含扩展名)
    PREFIX ""                     # 前缀(默认:共享库"lib",Windows DLL 无前缀)
    SUFFIX ".so.1"                # 后缀(覆盖默认扩展名)
    IMPORT_PREFIX "lib"           # 导入库前缀
    IMPORT_SUFFIX ".dll.a"        # 导入库后缀(MinGW)
)
2. 版本控制属性
cmake 复制代码
set_target_properties(mylib PROPERTIES
    VERSION 2.5.3                 # 完整版本号(影响文件命名)
    SOVERSION 2                   # API 版本号(影响符号链接)
    MACHO_COMPATIBILITY_VERSION "2.0"    # macOS 兼容版本
    MACHO_CURRENT_VERSION "2.5.3"        # macOS 当前版本
    BUNDLE_VERSION "2.5.3"        # macOS Bundle 版本
)
3. 输出目录属性
cmake 复制代码
# 通用输出目录
set_target_properties(myapp PROPERTIES
    ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib"
    LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib"
    RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin"
)

# 按配置的输出目录
set_target_properties(myapp PROPERTIES
    ARCHIVE_OUTPUT_DIRECTORY_DEBUG "${CMAKE_BINARY_DIR}/debug/lib"
    LIBRARY_OUTPUT_DIRECTORY_DEBUG "${CMAKE_BINARY_DIR}/debug/lib"
    RUNTIME_OUTPUT_DIRECTORY_DEBUG "${CMAKE_BINARY_DIR}/debug/bin"
    
    ARCHIVE_OUTPUT_DIRECTORY_RELEASE "${CMAKE_BINARY_DIR}/release/lib"
    LIBRARY_OUTPUT_DIRECTORY_RELEASE "${CMAKE_BINARY_DIR}/release/lib"
    RUNTIME_OUTPUT_DIRECTORY_RELEASE "${CMAKE_BINARY_DIR}/release/bin"
)

# 按配置的后缀
set_target_properties(myapp PROPERTIES
    DEBUG_POSTFIX "_d"           # Debug 后缀
    RELEASE_POSTFIX ""           # Release 后缀
    RELWITHDEBINFO_POSTFIX "_rd" # RelWithDebInfo 后缀
    MINSIZEREL_POSTFIX "_ms"     # MinSizeRel 后缀
)

二、编译属性

1. 语言标准属性
cmake 复制代码
set_target_properties(myapp PROPERTIES
    C_STANDARD 11                # C 标准版本
    C_STANDARD_REQUIRED ON       # 必须使用指定标准
    C_EXTENSIONS OFF             # 禁用编译器扩展
    
    CXX_STANDARD 17              # C++ 标准版本
    CXX_STANDARD_REQUIRED ON     # 必须使用指定标准
    CXX_EXTENSIONS OFF           # 禁用编译器扩展
)
2. 编译特性
cmake 复制代码
set_target_properties(myapp PROPERTIES
    COMPILE_DEFINITIONS "USE_FEATURE_X=1;ANOTHER_DEFINE=2"
    COMPILE_DEFINITIONS_DEBUG "DEBUG_MODE=1;LOG_LEVEL=3"
    COMPILE_DEFINITIONS_RELEASE "NDEBUG;OPTIMIZE"
    
    COMPILE_OPTIONS "-Wall;-Wextra;-Werror"
    COMPILE_OPTIONS_DEBUG "-O0;-g3"
    COMPILE_OPTIONS_RELEASE "-O3;-flto"
    
    COMPILE_PDB_NAME "myapp"     # PDB 文件名(MSVC)
    COMPILE_PDB_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/pdb"
)
3. 平台相关编译属性
cmake 复制代码
# Windows 特定
if(WIN32)
    set_target_properties(myapp PROPERTIES
        WIN32_EXECUTABLE TRUE          # Windows GUI 应用程序
        VS_SCC_LOCALPATH "."           # Visual Studio 源代码控制
        VS_SCC_PROJECTNAME "MyProject"
        VS_SCC_PROVIDER "Git"
        VS_GLOBAL_SECTION_PRE_MySection "key=value"
    )
endif()

# macOS 特定
if(APPLE)
    set_target_properties(myapp PROPERTIES
        MACOSX_BUNDLE TRUE             # 创建应用程序包
        MACOSX_BUNDLE_INFO_PLIST "${CMAKE_SOURCE_DIR}/Info.plist.in"
        MACOSX_BUNDLE_BUNDLE_NAME "MyApp"
        MACOSX_BUNDLE_BUNDLE_VERSION "1.0.0"
        MACOSX_BUNDLE_SHORT_VERSION_STRING "1.0"
        MACOSX_BUNDLE_GUI_IDENTIFIER "com.company.myapp"
        MACOSX_BUNDLE_ICON_FILE "MyApp.icns"
        MACOSX_BUNDLE_COPYRIGHT "Copyright © 2023 Company"
        MACOSX_RPATH ON                # 启用 RPATH
        INSTALL_NAME_DIR "@rpath"      # 安装名称目录
    )
endif()

三、链接属性

1. 链接选项和标志
cmake 复制代码
set_target_properties(myapp PROPERTIES
    LINK_FLAGS "-Wl,--as-needed"
    LINK_FLAGS_DEBUG "-fsanitize=address"
    LINK_FLAGS_RELEASE "-s"
    
    LINK_DEPENDS_NO_SHARED ON     # 即使有共享库也链接静态库
    LINK_INTERFACE_LIBRARIES "pthread;dl"  # 接口库
    LINK_INTERFACE_LIBRARIES_DEBUG "debug_lib"
    LINK_INTERFACE_LIBRARIES_RELEASE "optimized_lib"
    
    LINK_WHAT_YOU_USE ON          # 仅链接实际使用的库(clang/ld.lld)
    LINK_SEARCH_START_STATIC ON   # 优先静态链接
    LINK_SEARCH_END_STATIC ON     # 结束静态搜索
)
2. 共享库特定属性
cmake 复制代码
set_target_properties(mylib PROPERTIES
    POSITION_INDEPENDENT_CODE ON      # 启用 PIC(位置无关代码)
    NO_SONAME FALSE                   # 是否生成 SONAME(Unix)
    SOVERSION 2                       # SONAME 版本
    VERSION 2.5.3                     # 文件版本
    
    # Windows DLL 特定
    WINDOWS_EXPORT_ALL_SYMBOLS ON     # 自动导出所有符号
    DEFINE_SYMBOL "MYLIB_EXPORTS"     # 导出宏定义
    IMPORTED_IMPLIB "${CMAKE_BINARY_DIR}/lib/mylib.lib"  # 导入库
    
    # macOS 框架特定
    FRAMEWORK TRUE
    FRAMEWORK_VERSION A
    PUBLIC_HEADER "${CMAKE_SOURCE_DIR}/include/mylib.h"
    PRIVATE_HEADER "${CMAKE_SOURCE_DIR}/src/internal.h"
    RESOURCE "${CMAKE_SOURCE_DIR}/resources/icon.icns"
)
3. 符号可见性
cmake 复制代码
set_target_properties(mylib PROPERTIES
    C_VISIBILITY_PRESET "hidden"      # C 符号可见性
    CXX_VISIBILITY_PRESET "hidden"    # C++ 符号可见性
    VISIBILITY_INLINES_HIDDEN ON      # 内联函数可见性
    
    # 显式控制符号导出
    EXPORT_NAME "MyLib"               # 导出时的名称
    EXPORT_PROPERTIES "VERSION;SOVERSION"
)

四、安装属性

1. 安装路径属性
cmake 复制代码
include(GNUInstallDirs)

set_target_properties(myapp PROPERTIES
    INSTALL_RPATH "$ORIGIN/../lib"    # 运行时库搜索路径
    INSTALL_RPATH_USE_LINK_PATH ON    # 使用链接路径作为 RPATH
    BUILD_WITH_INSTALL_RPATH ON       # 构建时使用安装 RPATH
    SKIP_BUILD_RPATH OFF              # 不禁用构建 RPATH
    
    # 安装名称(macOS)
    INSTALL_NAME_DIR "@rpath"
    BUILD_WITH_INSTALL_NAME_DIR ON
)
2. 组件安装
cmake 复制代码
set_target_properties(myapp PROPERTIES
    ARCHIVE_OUTPUT_NAME "myapp"       # 静态库安装名
    LIBRARY_OUTPUT_NAME "myapp"       # 共享库安装名
    RUNTIME_OUTPUT_NAME "myapp"       # 可执行文件安装名
    
    # 按组件设置安装属性
    COMPONENT "runtime"              # 运行时组件
    EXCLUDE_FROM_DEFAULT_BUILD ON    # 从默认构建中排除
    EXCLUDE_FROM_ALL ON              # 从所有构建中排除
)

五、IDE 和生成器属性

1. Visual Studio 属性
cmake 复制代码
if(MSVC)
    set_target_properties(myapp PROPERTIES
        VS_GLOBAL_KEYWORD "Win32Proj"
        VS_GLOBAL_PROJECT_TYPES "{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}"
        VS_GLOBAL_ROOTNAMESPACE "MyApp"
        
        # 平台工具集
        VS_PLATFORM_TOOLSET "v143"
        VS_WINDOWS_TARGET_PLATFORM_VERSION "10.0"
        
        # 调试配置
        VS_DEBUGGER_WORKING_DIRECTORY "${CMAKE_BINARY_DIR}/bin/$<CONFIG>"
        VS_DEBUGGER_ENVIRONMENT "PATH=${CMAKE_BINARY_DIR}/bin/$<CONFIG>;%PATH%"
        VS_DEBUGGER_COMMAND_ARGUMENTS "--config test"
        
        # 输出文件
        VS_USER_PROPS "${CMAKE_SOURCE_DIR}/myprops.props"
        VS_SDK_REFERENCES "WindowsApp"
    )
endif()
2. Xcode 属性
cmake 复制代码
if(CMAKE_GENERATOR STREQUAL "Xcode")
    set_target_properties(myapp PROPERTIES
        XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY "Apple Development"
        XCODE_ATTRIBUTE_DEVELOPMENT_TEAM "ABCD1234EF"
        XCODE_ATTRIBUTE_PROVISIONING_PROFILE_SPECIFIER "MyApp Profile"
        XCODE_ATTRIBUTE_TARGETED_DEVICE_FAMILY "1,2"
        XCODE_ATTRIBUTE_IPHONEOS_DEPLOYMENT_TARGET "14.0"
        XCODE_ATTRIBUTE_MACOSX_DEPLOYMENT_TARGET "11.0"
        XCODE_ATTRIBUTE_CLANG_ENABLE_OBJC_ARC "YES"
        XCODE_ATTRIBUTE_GCC_OPTIMIZATION_LEVEL "$(GCC_OPTIMIZATION_LEVEL_$(CONFIGURATION))"
    )
endif()
3. 通用 IDE 属性
cmake 复制代码
set_target_properties(myapp PROPERTIES
    FOLDER "MyProject/Applications"      # Visual Studio/Xcode 文件夹
    LABELS "application;gui"             # 目标标签
    XCODE_SCHEME_ENVIRONMENT "DISABLE_ANIMATIONS=1"
    XCODE_SCHEME_ARGUMENTS "--verbose"
    XCODE_SCHEME_WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}"
    
    # 源码分组
    VS_SOURCE_GROUP "Header Files" FILES ${HEADER_FILES}
    VS_SOURCE_GROUP "Source Files" FILES ${SOURCE_FILES}
    VS_SOURCE_GROUP "Resources" FILES ${RESOURCE_FILES}
)

高级用法

1. 条件属性设置

cmake 复制代码
# 根据配置设置不同属性
set_target_properties(myapp PROPERTIES
    $<$<CONFIG:Debug>:DEBUG_POSTFIX> "_d"
    $<$<CONFIG:Debug>:OUTPUT_NAME> "myapp_debug"
    $<$<CONFIG:Release>:OUTPUT_NAME> "myapp_release"
    
    # 根据编译器设置
    $<$<CXX_COMPILER_ID:GNU>:COMPILE_OPTIONS> "-Wall;-Wextra"
    $<$<CXX_COMPILER_ID:MSVC>:COMPILE_OPTIONS> "/W4;/WX"
    
    # 根据平台设置
    $<$<PLATFORM_ID:Windows>:SUFFIX> ".exe"
    $<$<PLATFORM_ID:Linux>:SUFFIX> ""
    $<$<PLATFORM_ID:Darwin>:SUFFIX> ".app"
)

2. 多目标批量设置

cmake 复制代码
# 为多个目标设置相同属性
set(ALL_TARGETS app1 app2 app3 lib1 lib2)

set_target_properties(${ALL_TARGETS} PROPERTIES
    CXX_STANDARD 17
    CXX_STANDARD_REQUIRED ON
    CXX_EXTENSIONS OFF
)

# 或使用循环
foreach(target IN LISTS ALL_TARGETS)
    set_target_properties(${target} PROPERTIES
        FOLDER "MyProject"
        VS_DEBUGGER_WORKING_DIRECTORY "${CMAKE_BINARY_DIR}/bin"
    )
endforeach()

3. 继承和覆盖属性

cmake 复制代码
# 创建基目标
add_library(base INTERFACE)
set_target_properties(base PROPERTIES
    INTERFACE_COMPILE_DEFINITIONS "BASE_DEFINE=1"
    INTERFACE_COMPILE_OPTIONS "-Wall"
)

# 派生目标
add_library(derived STATIC derived.cpp)
target_link_libraries(derived PUBLIC base)

# 覆盖/添加属性
set_target_properties(derived PROPERTIES
    COMPILE_DEFINITIONS "${BASE_DEFINE};DERIVED_DEFINE=2"
    COMPILE_OPTIONS "${BASE_OPTIONS};-Wextra"
)

4. 动态属性计算

cmake 复制代码
# 动态计算输出目录
set(BIN_DIR "${CMAKE_BINARY_DIR}/bin")
set(LIB_DIR "${CMAKE_BINARY_DIR}/lib")

if(CMAKE_BUILD_TYPE STREQUAL "Debug")
    set(BIN_DIR "${BIN_DIR}/debug")
    set(LIB_DIR "${LIB_DIR}/debug")
endif()

set_target_properties(myapp PROPERTIES
    RUNTIME_OUTPUT_DIRECTORY ${BIN_DIR}
    LIBRARY_OUTPUT_DIRECTORY ${LIB_DIR}
    ARCHIVE_OUTPUT_DIRECTORY ${LIB_DIR}
)

# 动态生成版本信息
string(TIMESTAMP BUILD_DATE "%Y%m%d")
set_target_properties(myapp PROPERTIES
    COMPILE_DEFINITIONS "BUILD_DATE=\"${BUILD_DATE}\""
)

实际项目示例

示例1:跨平台库项目

cmake 复制代码
cmake_minimum_required(VERSION 3.15)
project(CrossPlatformLib VERSION 2.3.1)

# 创建库
add_library(cplib SHARED
    src/libcore.cpp
    src/libutils.cpp
)

# 设置通用属性
set_target_properties(cplib PROPERTIES
    # 输出命名
    OUTPUT_NAME "cplib"
    PREFIX ""
    SUFFIX ""
    
    # 版本控制
    VERSION ${PROJECT_VERSION}
    SOVERSION ${PROJECT_VERSION_MAJOR}
    
    # 编译标准
    CXX_STANDARD 17
    CXX_STANDARD_REQUIRED ON
    CXX_EXTENSIONS OFF
    
    # 符号可见性
    CXX_VISIBILITY_PRESET "hidden"
    VISIBILITY_INLINES_HIDDEN ON
)

# 平台特定属性
if(WIN32)
    set_target_properties(cplib PROPERTIES
        WINDOWS_EXPORT_ALL_SYMBOLS ON
        DEFINE_SYMBOL "CPLIB_EXPORTS"
        RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin"
        LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin"  # DLL 到 bin
    )
elseif(APPLE)
    set_target_properties(cplib PROPERTIES
        MACOSX_RPATH ON
        INSTALL_NAME_DIR "@rpath"
        BUILD_WITH_INSTALL_RPATH ON
        INSTALL_RPATH "@loader_path/../lib"
    )
else()
    # Linux/Unix
    set_target_properties(cplib PROPERTIES
        NO_SONAME FALSE
        INSTALL_RPATH "$ORIGIN/../lib:$ORIGIN/../lib64"
        BUILD_WITH_INSTALL_RPATH TRUE
    )
endif()

# 按配置设置
set_target_properties(cplib PROPERTIES
    DEBUG_POSTFIX "_d"
    RELEASE_POSTFIX ""
    RELWITHDEBINFO_POSTFIX "_rd"
    MINSIZEREL_POSTFIX "_ms"
    
    # 输出目录(按配置)
    ARCHIVE_OUTPUT_DIRECTORY_DEBUG "${CMAKE_BINARY_DIR}/debug/lib"
    LIBRARY_OUTPUT_DIRECTORY_DEBUG "${CMAKE_BINARY_DIR}/debug/lib"
    RUNTIME_OUTPUT_DIRECTORY_DEBUG "${CMAKE_BINARY_DIR}/debug/bin"
    
    ARCHIVE_OUTPUT_DIRECTORY_RELEASE "${CMAKE_BINARY_DIR}/release/lib"
    LIBRARY_OUTPUT_DIRECTORY_RELEASE "${CMAKE_BINARY_DIR}/release/lib"
    RUNTIME_OUTPUT_DIRECTORY_RELEASE "${CMAKE_BINARY_DIR}/release/bin"
)

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

# 安装属性
include(GNUInstallDirs)
set_target_properties(cplib PROPERTIES
    PUBLIC_HEADER "${CMAKE_CURRENT_SOURCE_DIR}/include/cplib.h"
    PRIVATE_HEADER "${CMAKE_CURRENT_SOURCE_DIR}/src/internal.h"
    
    # 安装到正确位置
    ARCHIVE_OUTPUT_NAME "cplib"
    LIBRARY_OUTPUT_NAME "cplib"
    RUNTIME_OUTPUT_NAME "cplib"
    
    # 组件
    COMPONENT "runtime"
)

示例2:GUI应用程序

cmake 复制代码
cmake_minimum_required(VERSION 3.16)
project(PhotoEditor VERSION 1.5.2)

# 创建应用程序
add_executable(photoeditor WIN32 MACOSX_BUNDLE
    src/main.cpp
    src/editor_window.cpp
    src/image_processor.cpp
)

# 通用应用程序属性
set_target_properties(photoeditor PROPERTIES
    OUTPUT_NAME "PhotoEditor"
    DEBUG_POSTFIX "_d"
    CXX_STANDARD 17
    CXX_STANDARD_REQUIRED ON
)

# Windows 特定
if(WIN32)
    set_target_properties(photoeditor PROPERTIES
        WIN32_EXECUTABLE TRUE
        VS_DEBUGGER_COMMAND_ARGUMENTS "--open test.jpg"
        VS_DEBUGGER_ENVIRONMENT "PATH=${CMAKE_BINARY_DIR}/bin/$<CONFIG>;%PATH%"
        VS_USER_PROPS "${CMAKE_SOURCE_DIR}/win32/PhotoEditor.props"
    )
    
    # 添加清单文件
    if(EXISTS "${CMAKE_SOURCE_DIR}/win32/PhotoEditor.manifest")
        set_target_properties(photoeditor PROPERTIES
            VS_CPP_MANIFEST_FILE "${CMAKE_SOURCE_DIR}/win32/PhotoEditor.manifest"
        )
    endif()
endif()

# macOS 特定
if(APPLE)
    set_target_properties(photoeditor PROPERTIES
        MACOSX_BUNDLE TRUE
        MACOSX_BUNDLE_INFO_PLIST "${CMAKE_SOURCE_DIR}/macos/Info.plist.in"
        MACOSX_BUNDLE_BUNDLE_NAME "PhotoEditor"
        MACOSX_BUNDLE_BUNDLE_VERSION "${PROJECT_VERSION}"
        MACOSX_BUNDLE_SHORT_VERSION_STRING "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}"
        MACOSX_BUNDLE_GUI_IDENTIFIER "com.company.photoeditor"
        MACOSX_BUNDLE_ICON_FILE "PhotoEditor.icns"
        MACOSX_BUNDLE_COPYRIGHT "Copyright © 2023 Company"
        MACOSX_BUNDLE_LS_MINIMUM_SYSTEM_VERSION "10.15"
        MACOSX_BUNDLE_NS_HUMAN_READABLE_COPYRIGHT "Copyright 2023"
        
        # Xcode 属性
        XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY "Apple Development"
        XCODE_ATTRIBUTE_DEVELOPMENT_TEAM "XYZ123ABC"
        XCODE_ATTRIBUTE_GCC_OPTIMIZATION_LEVEL "$(GCC_OPTIMIZATION_LEVEL_$(CONFIGURATION))"
    )
    
    # 设置文件夹
    set_target_properties(photoeditor PROPERTIES
        FOLDER "Applications"
    )
endif()

# 设置输出目录
set_target_properties(photoeditor PROPERTIES
    RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin"
    RUNTIME_OUTPUT_DIRECTORY_DEBUG "${CMAKE_BINARY_DIR}/bin/debug"
    RUNTIME_OUTPUT_DIRECTORY_RELEASE "${CMAKE_BINARY_DIR}/bin/release"
    
    # Visual Studio 文件夹组织
    VS_SOURCE_GROUP "Source Files" FILES ${APP_SOURCES}
    VS_SOURCE_GROUP "Header Files" FILES ${APP_HEADERS}
    VS_SOURCE_GROUP "Resources" FILES ${APP_RESOURCES}
    VS_SOURCE_GROUP "UI Files" FILES ${APP_UI_FILES}
)

# Qt 特定(如果使用 Qt)
if(QT_FOUND)
    set_target_properties(photoeditor PROPERTIES
        AUTOMOC ON
        AUTORCC ON
        AUTOUIC ON
        
        # Qt 插件路径
        QT_PLUGIN_PATH "${QT_INSTALL_PLUGINS}"
        
        # Windows: 复制 Qt DLLs
        WIN32_DEPLOYMENT_TARGET "10.0"
    )
endif()

示例3:库版本管理和ABI兼容

cmake 复制代码
cmake_minimum_required(VERSION 3.18)
project(ABIStableLib VERSION 3.2.0)

# 确定 ABI 版本
math(EXPR ABI_VERSION "${PROJECT_VERSION_MAJOR} + 1")  # 示例:API 变化时增加

add_library(abilib SHARED
    src/abi_stable.cpp
    src/compatibility.cpp
)

# 严格的版本控制
set_target_properties(abilib PROPERTIES
    # 文件命名
    OUTPUT_NAME "abilib"
    
    # 版本信息
    VERSION ${PROJECT_VERSION}           # 文件版本:3.2.0
    SOVERSION ${ABI_VERSION}             # ABI 版本:4 (soname: libabilib.so.4)
    
    # macOS 版本
    MACHO_COMPATIBILITY_VERSION "${ABI_VERSION}.0"
    MACHO_CURRENT_VERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}"
    
    # 严格的符号控制
    CXX_VISIBILITY_PRESET "hidden"
    VISIBILITY_INLINES_HIDDEN ON
    
    # 位置无关代码
    POSITION_INDEPENDENT_CODE ON
)

# 平台特定的符号导出
if(WIN32)
    set_target_properties(abilib PROPERTIES
        DEFINE_SYMBOL "ABILIB_EXPORTS"
        WINDOWS_EXPORT_ALL_SYMBOLS OFF  # 显式控制导出
    )
endif()

# ABI 检查标记
target_compile_definitions(abilib PRIVATE
    ABILIB_ABI_VERSION=${ABI_VERSION}
    ABILIB_API_VERSION=${PROJECT_VERSION_MAJOR}
)

# 安装配置
include(GNUInstallDirs)

set_target_properties(abilib PROPERTIES
    # 安装路径
    ARCHIVE_OUTPUT_NAME "abilib"
    LIBRARY_OUTPUT_NAME "abilib"
    
    # RPATH 设置
    INSTALL_RPATH "$ORIGIN/../lib"
    BUILD_WITH_INSTALL_RPATH ON
    
    # 头文件安装
    PUBLIC_HEADER "${CMAKE_CURRENT_SOURCE_DIR}/include/abilib.h"
    
    # 导出设置
    EXPORT_NAME "ABILib"
    EXPORT_PROPERTIES "VERSION;SOVERSION"
)

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

# 创建别名以保持向后兼容
add_library(abilib_v${PROJECT_VERSION_MAJOR} ALIAS abilib)
add_library(abilib_abi${ABI_VERSION} ALIAS abilib)

调试和验证

查看目标属性

cmake 复制代码
# 获取并打印所有属性
function(print_target_properties target)
    if(NOT TARGET ${target})
        message(WARNING "目标 ${target} 不存在")
        return()
    endif()
    
    message(STATUS "=== ${target} 的属性 ===")
    
    # 预定义属性列表(部分)
    set(PROPERTY_LIST
        OUTPUT_NAME
        PREFIX
        SUFFIX
        VERSION
        SOVERSION
        CXX_STANDARD
        CXX_STANDARD_REQUIRED
        CXX_EXTENSIONS
        DEBUG_POSTFIX
        RELEASE_POSTFIX
        ARCHIVE_OUTPUT_DIRECTORY
        LIBRARY_OUTPUT_DIRECTORY
        RUNTIME_OUTPUT_DIRECTORY
        COMPILE_DEFINITIONS
        COMPILE_OPTIONS
        LINK_FLAGS
        INSTALL_RPATH
        FOLDER
        TYPE
    )
    
    foreach(prop ${PROPERTY_LIST})
        get_target_property(value ${target} ${prop})
        if(value)
            message(STATUS "${prop}: ${value}")
        endif()
    endforeach()
    
    # 获取所有属性(包括自定义的)
    get_target_property(all_props ${target} PROPERTIES)
    if(all_props)
        message(STATUS "--- 所有属性 ---")
        foreach(prop ${all_props})
            get_target_property(value ${target} ${prop})
            if(value AND NOT prop IN_LIST PROPERTY_LIST)
                message(STATUS "${prop}: ${value}")
            endif()
        endforeach()
    endif()
    
    message(STATUS "====================")
endfunction()

# 使用示例
add_library(mylib SHARED mylib.cpp)
set_target_properties(mylib PROPERTIES
    OUTPUT_NAME "mylib"
    VERSION "1.0.0"
    CXX_STANDARD 17
)

print_target_properties(mylib)

验证属性设置

cmake 复制代码
# 验证关键属性
function(validate_target_properties target)
    if(NOT TARGET ${target})
        message(FATAL_ERROR "目标 ${target} 不存在")
    endif()
    
    # 检查必要属性
    get_target_property(target_type ${target} TYPE)
    
    if(target_type STREQUAL "SHARED_LIBRARY" OR target_type STREQUAL "MODULE_LIBRARY")
        get_target_property(version ${target} VERSION)
        get_target_property(soversion ${target} SOVERSION)
        
        if(NOT version)
            message(WARNING "共享库 ${target} 未设置 VERSION 属性")
        endif()
        
        if(NOT soversion)
            message(WARNING "共享库 ${target} 未设置 SOVERSION 属性")
        endif()
        
        get_target_property(pic ${target} POSITION_INDEPENDENT_CODE)
        if(NOT pic)
            message(STATUS "建议为共享库 ${target} 设置 POSITION_INDEPENDENT_CODE ON")
        endif()
    endif()
    
    # 检查编译标准
    get_target_property(cxx_std ${target} CXX_STANDARD)
    if(NOT cxx_std)
        message(STATUS "目标 ${target} 未设置 C++ 标准")
    endif()
    
    # 检查输出名称
    get_target_property(output_name ${target} OUTPUT_NAME)
    if(NOT output_name)
        message(DEBUG "目标 ${target} 使用默认输出名称")
    endif()
endfunction()

最佳实践

1. 属性组织策略

cmake 复制代码
# 将属性分组到变量中
set(COMPILE_PROPERTIES
    CXX_STANDARD 17
    CXX_STANDARD_REQUIRED ON
    CXX_EXTENSIONS OFF
    CXX_VISIBILITY_PRESET "hidden"
    VISIBILITY_INLINES_HIDDEN ON
)

set(OUTPUT_PROPERTIES
    DEBUG_POSTFIX "_d"
    RELEASE_POSTFIX ""
    OUTPUT_NAME "mylib"
)

set(VERSION_PROPERTIES
    VERSION ${PROJECT_VERSION}
    SOVERSION ${PROJECT_VERSION_MAJOR}
)

# 批量设置
set_target_properties(mylib PROPERTIES
    ${COMPILE_PROPERTIES}
    ${OUTPUT_PROPERTIES}
    ${VERSION_PROPERTIES}
)

2. 平台抽象层

cmake 复制代码
# 定义平台抽象属性
if(WIN32)
    set(PLATFORM_PROPERTIES
        WINDOWS_EXPORT_ALL_SYMBOLS ON
        DEFINE_SYMBOL "MYLIB_EXPORTS"
    )
elseif(APPLE)
    set(PLATFORM_PROPERTIES
        MACOSX_RPATH ON
        INSTALL_NAME_DIR "@rpath"
    )
else()
    set(PLATFORM_PROPERTIES
        NO_SONAME FALSE
        INSTALL_RPATH "$ORIGIN/../lib"
    )
endif()

# 应用到目标
set_target_properties(mylib PROPERTIES ${PLATFORM_PROPERTIES})

3. 配置相关属性管理

cmake 复制代码
# 定义配置相关的属性
set(CONFIG_DEBUG_PROPERTIES
    DEBUG_POSTFIX "_d"
    COMPILE_DEFINITIONS "DEBUG=1;_DEBUG"
    COMPILE_OPTIONS "-O0;-g3"
)

set(CONFIG_RELEASE_PROPERTIES
    COMPILE_DEFINITIONS "NDEBUG"
    COMPILE_OPTIONS "-O3;-DNDEBUG"
)

# 使用生成器表达式应用
set_target_properties(mylib PROPERTIES
    $<$<CONFIG:Debug>:DEBUG_POSTFIX> "_d"
    $<$<CONFIG:Debug>:COMPILE_DEFINITIONS> "DEBUG=1;_DEBUG"
    $<$<CONFIG:Debug>:COMPILE_OPTIONS> "-O0;-g3"
    
    $<$<CONFIG:Release>:COMPILE_DEFINITIONS> "NDEBUG"
    $<$<CONFIG:Release>:COMPILE_OPTIONS> "-O3;-DNDEBUG"
)

set_target_properties() 是 CMake 中用于精细控制目标行为的核心命令,掌握它可以让你的构建系统更加专业和强大。合理使用目标属性可以大大提升项目的可维护性、可移植性和专业性。

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