【问题标题】:CMake: Print properties of a target including its dependenciesCMake:打印目标的属性,包括其依赖项
【发布时间】:2020-09-20 08:31:41
【问题描述】:

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

目标是打印出目标的所有属性,包括依赖项通过 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}")

这将打印:

compile_defs: PRIV_A; PUB_A
compile_defs_intf: PUB_A; INT_A
 

其实我想得到:

compile_defs: PRIV_A; PUB_A; PUB_B; INT_B

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

是否可以获取目标的属性,包括。以更简单的方式对其依赖项(PUBLIC、INTERFACE 属性)?

【问题讨论】:

  • 为什么不在目标链接中使用PRIVATE,即target_link_libraries(libA PRIVATE libB)
  • 嗨@Mizux。不明白为什么这会有所帮助。使用 PRIVATE 不会改变属性不可见的事实。你能解释一下你的答案是什么意思吗?
  • 您可以查询目标的依赖库。像这样实现它:递归迭代目标和每个依赖项并将 COMPILE_DEFINITIONS 添加到某个全局列表中。

标签: cmake


【解决方案1】:

首先获取所有依赖库:

# 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()

然后只需遍历所有依赖库并获取接口定义:

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 "")

会输出:

$ cmake .
compile_defs: PRIV_A;PUB_A;PUB_B;INT_B

【讨论】:

  • 嗨,KamilCuk。实际上,这也是我最初的问题中所述的最初想法。我曾希望有一些本地方式来访问已解决的深层依赖关系,但显然需要一些“魔法”。非常感谢您提供这个。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-08-20
  • 2013-04-30
  • 1970-01-01
相关资源
最近更新 更多