这个问题询问类似的问题,但只需要手动指定要复制哪些dll。我的问题是:有没有一种方法可以简单地让 CMake 复制链接到可执行库的所有 dll,而无需手动告诉 CMake 要复制哪些文件?有时 CMake 更了解是否需要 dll。例如,在安装了同一库(例如Boost)的dll和静态库的系统中,并且我们选择静态链接到Boost,那么我们不需要复制dll。因此,与手动指定要复制哪些文件相比,CMake 可以做出更好的决定。另一个例子是,我的QT库链接到ICU库,并且在编写CMakeLists.txt时,我对此一无所知,所以我不可能告诉CMake复制ICU dll,所以这应该由CMake而不是完成人类。
假设操作系统是Windows。
$<TARGET_RUNTIME_DLLS:...>
很有帮助。它扩展到其传递依赖项中所有 SHARED
库的位置的路径列表(以未指定的顺序)。
add_library(lib1 ...)
add_library(lib2 ...)
find_package(lib3 REQUIRED)
add_executable(exe ...)
target_link_libraries(exe PRIVATE lib1 lib2 imported::lib3)
# The following variable is defined only on DLL systems
if (CMAKE_IMPORT_LIBRARY_SUFFIX)
add_custom_command(
TARGET exe POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_RUNTIME_DLLS:exe> $<TARGET_FILE_DIR:exe>
COMMAND_EXPAND_LISTS
)
endif ()
上面的代码假设
$<TARGET_RUNTIME_DLLS:...>
不会为空,因此检查我们是否在DLL系统上(CMAKE_IMPORT_LIBRARY_SUFFIX
仅在这种情况下定义)。如果它为空,则该命令将失败,因为没有足够的参数提供给cmake -E copy
。我个人提出了一个关于其不良人体工程学的问题。 https://gitlab.kitware.com/cmake/cmake/-/issues/23543
请注意,
$<TARGET_RUNTIME_DLLS:...>
仅捕获CMake目标。这是一个很好的例子,说明了为什么“仅”链接到 CMake 目标通常是一个好主意,即使这意味着您自己创建一个导入的目标。
如果你发现自己写了很多,你可以将它包装成一个函数:function(copy_runtime_dlls TARGET)
get_property(already_applied TARGET "${TARGET}" PROPERTY _copy_runtime_dlls_applied)
if (CMAKE_IMPORT_LIBRARY_SUFFIX AND NOT already_applied)
add_custom_command(
TARGET "${TARGET}" POST_BUILD
COMMAND "${CMAKE_COMMAND}" -E copy
"$<TARGET_RUNTIME_DLLS:${TARGET}>" "$<TARGET_FILE_DIR:${TARGET}>"
COMMAND_EXPAND_LISTS
)
set_property(TARGET "${TARGET}" PROPERTY _copy_runtime_dlls_applied 1)
endif ()
endfunction()
然后只需拨打上面的
copy_runtime_dlls(exe)
即可。