您如何在 cmake install 脚本语句中使用file(GET_RUNTIME_DEPENDENCIES...)?我在网上找不到这种用法的例子,而且我不清楚使用 [[ ]] 嵌入式自定义脚本的文档和错误消息中的声明。
我得到的印象是,在安装时,这可用于定位您的 cmake 目标的文件依赖项,并可能将它们与您的安装操作一起带过来,使其以独立形式使用。
例如,我的应用程序依赖于 QT,并且期望如果配置正确,则该应用程序所需的 QT dll 将被复制到 bin。(我只是想确保在这种情况下我也没有误解它的功能)。它可能不会直接复制文件,但我假设提供了要复制的文件列表,然后安装将处理(全部在安装时完成)。
我天真地尝试只是抛出一些东西开始是:
set(TARGET_NAME "myapp")
# installation settings
install(TARGETS ${TARGET_NAME}
[[
file(GET_RUNTIME_DEPENDENCIES
RESOLVED_DEPENDENCIES_VAR RES
UNRESOLVED_DEPENDENCIES_VAR UNRES
CONFLICTING_DEPENDENCIES_PREFIX CONFLICTING_DEPENDENCIES
EXECUTABLES ${TARGET_NAME}
)]]
RUNTIME DESTINATION "${INSTALL_X_BIN}" COMPONENT libraries
LIBRARY DESTINATION "${INSTALL_X_LIB}" COMPONENT libraries
)
Run Code Online (Sandbox Code Playgroud)
然而,这当然给了我:
CMake Error at applications/CMakeLists.txt:117 (install):
install TARGETS given target " file(GET_RUNTIME_DEPENDENCIES
RESOLVED_DEPENDENCIES_VAR RES
UNRESOLVED_DEPENDENCIES_VAR UNRES
CONFLICTING_DEPENDENCIES_PREFIX CONFLICTING_DEPENDENCIES
EXECUTABLES ${TARGET_NAME}
)" which does not exist.
-- Configuring incomplete, errors occurred!
Run Code Online (Sandbox Code Playgroud)
我觉得这很愚蠢,就像我错过了一些非常基本的东西。
FeR*_*eRD 17
从 CMake 的下一个版本 (3.21) 开始,您可能不想file(GET_RUNTIME_DEPENDENCIES)
在某些情况下使用。(这将是一件好事,因为它工作......很差。一方面,它无法区分 32 位和 64 位共享库,因此在 Linux 上返回错误的架构库是很常见的. 再说一次,这种发展不会改变这一事实。)
如果您使用的是需要GET_RUNTIME_DEPENDENCIES
逻辑的最常见平台 Windows,那么下一个版本的 CMake 正在寻求使用新的生成器表达式再次尝试(希望第四次(?)时间的魅力):$<TARGET_RUNTIME_DLLS:target>
.
它被记录为“目标在运行时依赖的 DLL 列表。这是由目标的传递依赖项中所有SHARED
和MODULE
目标的位置决定的。[...] 此生成器表达式可用于复制所有 DLL目标依赖于 POST_BUILD 自定义命令中的输出目录。”
考虑到我目前在 a 中有自定义逻辑CMakeLists.txt
来精确地做到这一点,因为它是使库的单元测试从构建目录可执行的唯一方法,我希望这个新表达式能让这更容易一些。
($<TARGET_RUNTIME_DLLS>
不会解决 . 的问题file(GET_RUNTIME_DEPENDENCIES)
,但一些提交刚刚合并到 CMake 即将推出的 3.21 分支中,通过教它如何区分不同架构的库。万岁!)
你提到了Qt。无论您在这里做什么,这种方法都不太可能单独对 Qt 起作用,因为无法仅使用程序/库的运行时依赖项来发现您的安装可能还需要的任何 Qt插件或其他组件。Qt 的依赖项比库更复杂。
(我在这里的回答演示了如何获取用于捆绑的 Qt 插件信息,以QCocoaIntegrationPlugin
macOS 上的QPA 为例。IMPORTED
在最近的版本中,所有 Qt 插件都由它们自己的CMake 目标表示,因此通常可以编写install(CODE ...)
脚本来获取这些目标以类似于以下代码的方式使用生成器表达式。)
file(GET_RUNTIME_DEPENDENCIES)
正如 Tsyvarev 在评论中指出的那样,GET_RUNTIME_DEPENDENCIES
旨在用于安装阶段,而不是配置阶段。因此,它需要放在install(CODE ...)
orinstall(SCRIPT ...)
语句中,这将导致代码评估延迟到构建完成之后。(实际上,install(CODE ...)
将给定的代码直接插入到当前目录的cmake_install.cmake
脚本中。您只需查看该文件即可检查结果,甚至无需运行安装。)
延迟评估也带来了一些皱纹。主要是:代码不理解目标。安装阶段不再存在目标。因此,要包含任何目标信息,您必须使用生成器表达式来插入正确的值。
虽然 CMake 文档表明变量引用和转义不在括号参数内计算,但生成器表达式是. 因此,您可以组合CODE
包装中的内容[[
]]
以避免转义所有内容。
您仍然必须小心变量扩展/转义。大多数变量(包括您创建的任何变量)在安装上下文中都不可用 — 只有少数变量可用,例如CMAKE_INSTALL_PREFIX
. 您必须扩展或设置任何其他内容。
AFAICT,没有生成器表达式来访问任意变量。有一些用于特定的变量/值,但你不能说类似$<LIST:MY_LIST_VAR>
或$<VALUE:MY_STRING_VAR>
组合变量和括号参数。
因此,如果您想使用 .config 中的配置上下文中的变量(CODE
它们将在安装时进行评估),最简单的方法是通过set()
-ing 中的变量将它们“传输”到安装脚本中CODE
。
file(INSTALL TYPE SHARED_LIBRARY)
要安装共享库依赖项,您可以使用file(INSTALL)
CMake 本身在cmake_install.cmake
构建共享库目标时使用的相同命令。它使用TYPE SHARED_LIBRARY
选项来添加一些额外的处理。该FOLLOW_SYMLINK_CHAIN
选项也特别方便。它们将一起file(INSTALL)
解析源文件中的符号链接,并在目标路径中自动重新创建它们。
总而言之,你想要做这样的事情:
set(MY_DEPENDENCY_PATHS /path/one /path/two)
# Transfer the value of ${MY_DEPENDENCY_PATHS} into the install script
install(CODE "set(MY_DEPENDENCY_PATHS \"${MY_DEPENDENCY_PATHS}\")")
install(CODE [[
file(GET_RUNTIME_DEPENDENCIES
LIBRARIES $<TARGET_FILE:mylibtarget>
EXECUTABLES $<TARGET_FILE:myprogtarget>
RESOLVED_DEPENDENCIES_VAR _r_deps
UNRESOLVED_DEPENDENCIES_VAR _u_deps
DIRECTORIES ${MY_DEPENDENCY_PATHS}
)
foreach(_file ${_r_deps})
file(INSTALL
DESTINATION "${CMAKE_INSTALL_PREFIX}/lib"
TYPE SHARED_LIBRARY
FOLLLOW_SYMLINK_CHAIN
FILES "${_file}"
)
endforeach()
list(LENGTH _u_deps _u_length)
if("${_u_length}" GREATER 0)
message(WARNING "Unresolved dependencies detected!")
endif()
]])
Run Code Online (Sandbox Code Playgroud)
* –(请注意,DIRECTORIES
在非 Windows 系统上使用该参数将导致 CMake 发出警告,因为文件的依赖项应该仅使用当前环境才能解析。)
如果代码变得太复杂,总有创建一个单独的脚本文件的选项copy_deps.cmake
中${CMAKE_CURRENT_SOURCE_DIR}
和使用install(SCRIPT copy_deps.cmake)
。(此答案的先前版本建议使用file(GENERATE...)
来构建脚本 - 这将不起作用,因为在处理CMakeLists.txt
.之后才会写入文件。)
归档时间: |
|
查看次数: |
3683 次 |
最近记录: |