外部库依赖性层次结构

时间:2015-09-23 19:33:53

标签: cmake

我正在构建一个依赖于由相当多的库组成的第三方库的项目。这些库之间的依赖关系的DAG是明确定义的,例如它可能是以下字母表示库和箭头是依赖关系

x -> a, b
y -> a, c
z -> x, b   // note I don't need to specify a here as it is implied by x

所以我真正想要的是能够在CMake中表达这个DAG并且能够在不重复的情况下扩展依赖性。所以

Expand( y, z ) -> y, z, x, a, b, c    // Note only one a

我会尽力避免尝试扩展功能,因为我无法想出任何优雅的东西,我对CMake并不擅长。

额外的功能是检测顶级依赖关系中的冗余,以便

Expand( z, x )  // x not needed as z depends on it

注意CMake已经为内部项目库依赖项执行了类似的操作,并在target_link_libraries之类的内容中使用它,但这些是外部的,因此CMake不知道外部依赖树。

1 个答案:

答案 0 :(得分:0)

据我从CMake文档中了解,target_link_libraries不能将导入的库作为第一个参数。但是您可以轻松地开发函数,该函数从依赖(导入)库中读取属性,并为依赖(导入)库填充相应的属性。因此,导出的导入库可以与右侧的target_link_libraries一起使用。

# _combine_targets_property(VAR PROP target1 target2 ...)
# Helper function: Collects @PROP properties (as lists) from @target1, @target2 ..,
# combines these lists into one and store into variable @VAR.
function(_combine_targets_property VAR PROP)
    set(values) # Resulted list
    foreach(t ${ARGN})
        get_property(v TARGET ${t} PROPERTY ${PROP})
        list(APPEND values ${v})
    endforeach()
    set(${VAR} ${values} PARENT_SCOPE)
endfunction()

# imported_link_libraries(t_dest target1 target2 ...)
# Make imported library target @t_dest effectively linked with @target1, @target2 ...
function(imported_link_libraries t_dest)
    # IMPORTED_LOCATION's and INTERFACE_LINK_LIBRARIES's from dependencies
    # should be appended to target's INTERFACE_LINK_LIBRARIES.
    get_property(v1 TARGET ${t_dest} PROPERTY INTERFACE_LINK_LIBRARIES)
    _combine_targets_property(v2 IMPORTED_LOCATION ${ARGN})
    _combine_targets_property(v3 INTERFACE_LINK_LIBRARIES ${ARGN})
    set(v ${v1} ${v2} ${v3})
    list(REMOVE_DUPLICATES v)
    set_property(TARGET ${t_dest} PROPERTY INTERFACE_LINK_LIBRARIES ${v})

    # INTERFACE_INCLUDE_DIRECTORIES' from dependencies
    # should be appended to corresponded target's property.
    get_property(v1 TARGET ${t_dest} PROPERTY INTERFACE_INCLUDE_DIRECTORIES)
    _combine_targets_property(v2 INTERFACE_INCLUDE_DIRECTORIES ${ARGN})
    set(v ${v1} ${v2})
    list(REMOVE_DUPLICATES v)
    set_property(TARGET ${t_dest} PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${v})

    # Process other interface properties if needed. E.g., INTERFACE_COMPILE_DEFINITIONS.
    ...
endfunction()

用法示例:

add_library(a IMPORTED)
set_target_properties(a IMPORTED_LOCATION <a_lib> INCLUDE_DIRECTORIES <a_include_dirs>)

add_library(b IMPORTED)
set_target_properties(b IMPORTED_LOCATION <b_lib> INCLUDE_DIRECTORIES <b_include_dirs>)

add_library(x IMPORTED)
set_target_properties(x IMPORTED_LOCATION <x_lib> INCLUDE_DIRECTORIES <x_include_dirs>)

imported_link_libraries(x a b)

add_executable(my_exec ...)
target_link_libraries(my_exec x)

请注意,导入的目标名称不会在依赖项中跟踪,这类似于target_link_libraries()行为。此外,未检测到还原(但会自动删除重复项)。这两个功能对于CMake来说并不自然,但如果需要,可以实现它们。