CMake:打印目标的属性,包括其依赖项

chr*_*opo 2 cmake

我目前尝试编写一个 custom_target 来打印目标的属性(例如 COMPILE_DEFINITIONS)。我几乎将这个 custom_target 创建的调用放在我的 Top-Level-CMakeLists.txt 的末尾,以确保所有模块都已被调用。

目标是打印出目标的所有属性,包括通过 target_link_libraries 依赖项给出的属性。

简化示例:

add_library(libA STATIC)
add_library(libB STATIC)

target_compile_definitions(libA 
    PRIVATE
        PRIV_A
    PUBLIC
        PUB_A
    INTERFACE
        INT_A
)

target_compile_definitions(libB 
    PRIVATE
        PRIV_B
    PUBLIC
        PUB_B
    INTERFACE
        INT_B
)

# create dependency from A -> B, 
# this should compile A with all PUBLIC and INTERFACE defintions from B
target_link_libraries(libA libB)

get_target_property(compile_defs libA COMPILE_DEFINITIONS)
get_target_property(compile_defs_intf libA INTERFACE_COMPILE_DEFINITIONS)

message("compile_defs: ${compile_defs}")
message("compile_defs_intf: ${compile_defs_intf}")
Run Code Online (Sandbox Code Playgroud)

这将打印:

compile_defs: PRIV_A; PUB_A
compile_defs_intf: PUB_A; INT_A
 
Run Code Online (Sandbox Code Playgroud)

其实我想得到:

compile_defs: PRIV_A; PUB_A; PUB_B; INT_B
Run Code Online (Sandbox Code Playgroud)

但显然在这个阶段,依赖关系尚未解析/包含在属性中。一种可能的解决方法是迭代目标 A 的所有依赖项并收集依赖项目标的所有 INTERFACE_PROPERTIES。但这需要一些安静的递归来解决树中的所有依赖关系(例如需要解决所有依赖关系......)。

是否可以获得目标的属性,包括。以更简单的方式了解其依赖关系(PUBLIC、INTERFACE 属性)?

Kam*_*Cuk 5

首先获取所有依赖库:

# target_get_linked_libraries.cmake
# 
function(list_add_if_not_present list elem)
    list(FIND "${list}" "${elem}" exists)
    if(exists EQUAL -1)
        list(APPEND "${list}" "${elem}")
        set("${list}" "${${list}}" PARENT_SCOPE)
     endif()
endfunction()

macro(_target_get_linked_libraries_in _target _outlist)
    list_add_if_not_present("${_outlist}" "${_target}")

    # get libraries
    get_target_property(target_type "${_target}" TYPE)
    if (${target_type} STREQUAL "INTERFACE_LIBRARY")
        get_target_property(libs "${_target}" INTERFACE_LINK_LIBRARIES)
    else()
        get_target_property(libs "${_target}" LINK_LIBRARIES)
    endif()

    foreach(lib IN LISTS libs)
        if(NOT TARGET "${lib}")
            continue()
        endif()
        
        list(FIND "${_outlist}" "${lib}" exists)
        if(NOT exists EQUAL -1)
            continue()
        endif()
        
        _target_get_linked_libraries_in("${lib}" "${_outlist}")
        
    endforeach()
endmacro()

function(target_get_linked_libraries _target _outlist)
    set(${_outlist} "${_target}")
    _target_get_linked_libraries_in(${_target} ${_outlist})
    set(${_outlist} ${${_outlist}} PARENT_SCOPE) 
endfunction()
Run Code Online (Sandbox Code Playgroud)

然后迭代所有依赖库并获取接口定义:

cmake_minimum_required(VERSION 3.11)
project(A)

add_library(libB STATIC)
target_compile_definitions(libB 
    PRIVATE PRIV_B
    PUBLIC PUB_B
    INTERFACE INT_B
)

add_library(libA STATIC)
target_compile_definitions(libA 
    PRIVATE PRIV_A
    PUBLIC PUB_A
    INTERFACE INT_A
)
target_link_libraries(libA PUBLIC libB)

include(target_get_linked_libraries.cmake)
target_get_linked_libraries(libA libraries)
set(compile_defs)
foreach(i IN LISTS libraries)
    if("${i}" STREQUAL libA)
        get_target_property(tmp "${i}" COMPILE_DEFINITIONS)
    else()
        get_target_property(tmp "${i}" INTERFACE_COMPILE_DEFINITIONS)
    endif()
    list(APPEND compile_defs "${tmp}")
endforeach()

message("compile_defs: ${compile_defs}")
message(FATAL_ERROR "")
Run Code Online (Sandbox Code Playgroud)

会输出:

$ cmake .
compile_defs: PRIV_A;PUB_A;PUB_B;INT_B
Run Code Online (Sandbox Code Playgroud)