CMake -将DLL复制到运行时输出目录

72qzrwbm  于 2023-01-13  发布在  其他
关注(0)|答案(3)|浏览(1039)

我尝试创建一个简单的CMake,它检索Qt的DLL并将其复制到cmake创建可执行文件的目录中。
使用g ++或clang时效果很好,但MSVC(Visual Studio 2017)会创建一个 * Debug * 或 * Release * 目录。
我找不到一种方法来检索写入可执行文件的实际目录的路径(${CMAKE_CURRENT_BINARY_DIR}返回 * Release * 或 * Debug * 的父目录)。
我见过有人使用目标属性RUNTIME_OUTPUT_DIRECTORY,但当我使用它时,它是空的。
我不想改变输出目录,我只想知道它的路径(所以我不想改变RUNTIME_OUTPUT_DIRECTORY的值)
谢谢!

soat7uwm

soat7uwm1#

在Visual Studio中,在 * 配置 * 步骤(处理CMakeLists.txt文件时)中,build type未设置,因此没有可直接使用的 * 构建类型 * 相关变量或属性。应使用generator-expressions
例如,可以使用$<TARGET_FILE_DIR:tgt>生成器表达式提取可执行文件或库目标的输出目录。它将返回完整目录,并已附加"Release/"或" Debug/"。
注意,生成器表达式只有在文档中 * 明确 * 允许使用时才能使用。例如,它们不能在message()命令中使用。
或者,您可以显式地设置变量CMAKE_RUNTIME_OUTPUT_DIRECTORY,这样对于每种构建类型,都将向其追加适当的子目录。但是为了提取该子目录,您应该再次求助于生成器表达式:$<CONFIG>.
从技术上讲,可以为任何构建类型设置相同的输出目录,但不推荐这样做,因为一种构建类型的文件会被另一种构建类型的文件覆盖。

t1rydlwq

t1rydlwq2#

Visual Studio 2022和CMake的示例。
将其放在CMakeLists.txt的末尾:

if (WIN32)
  add_custom_command(
    TARGET qcpp POST_BUILD
    COMMAND ${CMAKE_COMMAND} -E copy_if_different "${PROJECT_SOURCE_DIR}/include/external/c.dll" "${CMAKE_BINARY_DIR}"
    COMMAND_EXPAND_LISTS
  )
endif()

参见list of CMake variables
注意前面命令中的“qcpp”,这是项目名称,应该与下面这行的开头匹配:

project ("qcpp")

附录A -测试

为了验证,如果您使用mkdir x && cd x && cmake ..生成Visual Studio项目,您可以看到CMake已将生成后步骤添加到解决方案配置中:

nqwrtyyt

nqwrtyyt3#

从CMake 3.21+开始,$<TARGET_RUNTIME_DLLS:tgt>生成器表达式可以帮助将依赖DLL复制到构建树。
目标在运行时依赖的DLL列表。这由目标的可传递依赖项中所有SHAREDMODULE目标的位置确定。在可执行文件、SHARED库和MODULE库以外的目标上使用此生成器表达式是错误的。在非DLL平台上,它的计算结果为空字符串。
此生成器表达式可用于在POST_BUILD自定义命令中将目标所依赖的所有DLL复制到其输出目录中。
文档链接:https://cmake.org/cmake/help/latest/manual/cmake-generator-expressions.7.html#genex:TARGET_RUNTIME_DLLS
下面是一个如何使用它的示例(改编自文档):

find_package(foo REQUIRED)

add_executable(main main.cpp)
target_link_libraries(main PRIVATE foo::foo)

if (WIN32)
  add_custom_command(
    TARGET main POST_BUILD
    COMMAND ${CMAKE_COMMAND} -E copy_if_different
            $<TARGET_RUNTIME_DLLS:main> $<TARGET_FILE_DIR:main>
    COMMAND_EXPAND_LISTS
  )
endif ()

if (WIN32)检查确保$<TARGET_RUNTIME_DLLS:main>不会为空,否则会导致命令失败(而不是什么都不做)。COMMAND_EXPAND_LISTS确保$<TARGET_RUNTIME_DLLS:main>返回的分号分隔列表将被拆分为多个参数,而不是作为一个包含(转义)分号的单个参数传递。
还要注意UNKNOWN库将被这个生成器表达式忽略。当使用内置的Find模块而不是库的第一方CMake配置模式包时,这些库是常见的。在这些情况下,您必须手动检查模块变量以找到库路径,并为每个库添加自定义命令。
具体到Qt,我希望Qt6中新的CMake集成能“正常工作”,尽管我还没有测试过它,它可能也能在Qt5中工作,但我也没有测试过它。

相关问题