CMake 中 LINK_LIBRARIES 的递归列表 [英] Recursive list of LINK_LIBRARIES in CMake

查看:151
本文介绍了CMake 中 LINK_LIBRARIES 的递归列表的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试获取链接到 CMake 中特定目标的所有库的绝对路径列表,以用于调用 add_custom_command.但是,get_target_property(_LINK_LIBRARIES ${TARGET} LINK_LIBRARIES 仅包括直接依赖项(即在 target_link_libraries(${TARGET} ...) 调用中使用的任何内容).

I am trying to acquire a list of the absolute paths to all libraries linked to a specific target in CMake for use in a call to add_custom_command. However, get_target_property(_LINK_LIBRARIES ${TARGET} LINK_LIBRARIES only includes the direct dependencies (i.e. anything that is used in a target_link_libraries(${TARGET} ...) call).

因此,如果我链接另一个 CMake 目标,例如mylibrary,该列表将包括 mylibrary,但仅作为名称,不包含可传递链接的库.由于此列表还可以包含任意复杂的生成器表达式,因此检查每个项目是否为目标并递归检索其 LINK_LIBRARIES 是不可行的.此外,可以在稍后在 CMakeLists.txtif(TARGET mylibrary) 中指定目标.

Therefore, if I link another CMake target, e.g. mylibrary, the list would include mylibrary, but as a name only and without transitively linked libraries. As this list can also include arbitrarily complex generator expressions, checking each item if it is a target and retrieving its LINK_LIBRARIES recursively is not viable. Furthermore the target could be specified at a later point in the CMakeLists.txt and if(TARGET mylibrary) would be skipped.

对于 INCLUDE_DIRECTORIESCOMPILE_DEFINITIONS,这很容易解决,尽管在使用 get_target_property 时两者的行为相似(除了链接目标显然不是在列表中),形式为 $ 的生成器表达式生成所需的递归所需包含和定义列表.但是,$ 生成与 get_target_property 变体相同的列表.

For INCLUDE_DIRECTORIES and COMPILE_DEFINITIONS this is easily solved, as although both behave similarly when get_target_property is used (except that linked targets are obviously not in the list), a generator expression of the form $<TARGET_PROPERTY:${TARGET},INCLUDE_DIRECTORIES> produces the desired list of recursively required includes and definitions. However, $<TARGET_PROPERTY:${TARGET},LINK_LIBRARIES> produces the same list as the get_target_property variant.

如何检索所需的绝对路径列表?

How can I retrieve the desired list of absolute paths?

演示:

cmake_minimum_required(VERSION 2.8.12 FATAL_ERROR)

file(WRITE a.cpp "void foo() {};
")
file(WRITE b.cpp "int main(int, char**) { return 0; }
")

find_package(Boost REQUIRED COMPONENTS filesystem system)

add_library(A STATIC a.cpp)
target_include_directories(A PUBLIC ${Boost_INCLUDE_DIRS})
target_link_libraries(A PUBLIC ${Boost_LIBRARIES})

# demonstrates (at configure time) that the LINK_LIBRARIES property can contain
# arbitrary generator expressions, making a recursive solution infeasible
get_target_property(A_LINK_LIBRARIES A LINK_LIBRARIES)
message(STATUS "A LINK_LIBARIES: ${A_LINK_LIBRARIES}")

add_executable(B b.cpp b_lists)
target_link_libraries(B PRIVATE A)
target_include_directories(B PRIVATE .)

get_target_property(B_INCLUDE_DIRECTORIES B INCLUDE_DIRECTORIES)
get_target_property(B_LINK_LIBRARIES B LINK_LIBRARIES)

# demonstrates (at compile time) that method 1 is not recursive while method 2 is (for INCLUDE_DIRECTORIES)
# demonstrates (at compile time) that the library list is never recursive
add_custom_command(
    OUTPUT b_lists
    COMMAND ${CMAKE_COMMAND} -E echo "B INCLUDE_DIRECTORIES 1: ${B_INCLUDE_DIRECTORIES}"
    COMMAND ${CMAKE_COMMAND} -E echo "B INCLUDE_DIRECTORIES 2: $<TARGET_PROPERTY:B,INCLUDE_DIRECTORIES>"
    COMMAND ${CMAKE_COMMAND} -E echo "B LINK_LIBRARIES 1: ${B_LINK_LIBRARIES}"
    COMMAND ${CMAKE_COMMAND} -E echo "B LINK_LIBRARIES 2: $<TARGET_PROPERTY:B,LINK_LIBRARIES>"
    DEPENDS A
)
set_source_files_properties(b_lists PROPERTIES SYMBOLIC TRUE)

输出:

(configure)
A LINK_LIBARIES: $<$<NOT:$<CONFIG:DEBUG>>:D:/libs/boost-1_55_0/lib/boost_filesystem-vc110-mt-1_55.lib>;$<$<CONFIG:DEBUG>:D:/libs/boost-1_55_0/lib/boost_filesystem-vc110-mt-gd-1_55.lib>;$<$<NOT:$<CONFIG:DEBUG>>:D:/libs/boost-1_55_0/lib/boost_system-vc110-mt-1_55.lib>;$<$<CONFIG:DEBUG>:D:/libs/boost-1_55_0/lib/boost_system-vc110-mt-gd-1_55.lib>
(build)
Generating b_lists
B INCLUDE_DIRECTORIES 1: D:/projects/cmakeminimal/.
B INCLUDE_DIRECTORIES 2: D:/projects/cmakeminimal/.;D:/libs/boost-1_55_0/include/boost-1_55
B LINK_LIBRARIES 1: A
B LINK_LIBRARIES 2: A

推荐答案

你的愿望已经存在一段时间了 - 据我所知 - 还没有(对于 CMake 3.3.2)嵌入到 中CMake 本身(请参阅 0012435:获取目标的所有链接库的可能性?).

Your wish has been out there for a while and is - as far as I know - not yet (as for CMake 3.3.2) embedded into CMake itself (see 0012435: Possibility to get all link libraries for a target?).

我得到了一些希望,因为这张票列出了一些可能的替代方法.但是在我针对您的示例 CMake 项目测试了这些之后,我会说它们并不是真正的解决方案:

I got some hope because this ticket lists a few possible alternative approaches. But after I tested those against your example CMake project I would say they are not really a solution:

  1. export_library_dependencies() - 已弃用

注意:因为这仅适用于 Lib-To-Lib 依赖项,我有 - 对于此测试 - 将您的 add_executable() 更改为 add_library() 调用

Note: Because this works only for Lib-To-Lib dependencies I have - for this test - changed your add_executable() to an add_library() call

cmake_policy(SET CMP0033 OLD)
export_library_dependencies(LibToLibLinkDependencies.cmake)
include("${CMAKE_CURRENT_BINARY_DIR}/LibToLibLinkDependencies.cmake")

message("A_LIB_DEPENDS: ${A_LIB_DEPENDS}")
message("B_LIB_DEPENDS: ${B_LIB_DEPENDS}")

会给例如

A_LIB_DEPENDS: optimized;../libboost_filesystem-vc110-mt-1_53.lib;debug;../libboost_filesystem-vc110-mt-gd-1_53.lib;...
B_LIB_DEPENDS: general;A;

另见 policy CMP0033 export_library_dependencies() 命令不应该是称为

export(TARGETS ...)

cmake_policy(SET CMP0024 OLD)
export(
    TARGETS A B
    FILE Test.cmake 
    NAMESPACE Imp_
)
include("${CMAKE_CURRENT_BINARY_DIR}/Test.cmake")

但这会将生成器表达式保留在输出中,您需要将所有依赖目标添加到列表中,所以不好.

But this keeps the generator expressions in the output and you need add to the list all depending targets, so no good.

另见策略CMP0024禁止包含导出结果".

GET_PREREQUISITES()

我从 如何使用 cmake 函数 get_prerequisites 和 get_filename_component 进行目标依赖项安装?,但它显示 - 如模块文档中所述 - 它仅列出了共享库.

I've taken the code from how to use the cmake functions get_prerequisites and get_filename_component for target dependency installation?, but it shows - as described in the module's documentation - that it lists only the shared libraries.

add_custom_command(
    OUTPUT b_lists
    APPEND
    COMMAND ${CMAKE_COMMAND} -D MY_BINARY_LOCATION="$<TARGET_FILE:B>" -P "${CMAKE_CURRENT_LIST_DIR}/ListSharedLibDependencies.cmake"
)

ListSharedLibDependencies.cmake

include(GetPrerequisites)

get_prerequisites(${MY_BINARY_LOCATION} DEPENDENCIES 0 0 "" "")

foreach(DEPENDENCY_FILE ${DEPENDENCIES})
    gp_resolve_item("${MY_BINARY_LOCATION}" "${DEPENDENCY_FILE}" "" "" resolved_file)
    message("resolved_file='${resolved_file}'")
endforeach()

会在我的 Windows 机器上输出:

would output on my Windows machine:

resolved_file='C:/Windows/SysWOW64/KERNEL32.dll'
resolved_file='C:/Windows/SysWOW64/MSVCR110D.dll'

参考资料

这篇关于CMake 中 LINK_LIBRARIES 的递归列表的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆