我正在尝试使用该${CMAKE_COMMAND} -E copy <from> <to>
格式复制多个文件,但我想知道是否有办法提供许多文件以复制到特定目录。似乎 cmake 副本一次只允许复制一个文件。当我宁愿提供要复制的文件列表作为第一个参数时,我真的不想重复使用复制命令。
我认为最简单的解决方案是使用平台相关的“cp”命令。虽然这绝对不利于可移植性,但我们的系统保证构建在 Linux 上。一个简单的、独立于平台的解决方案会更好。
我正在尝试使用该${CMAKE_COMMAND} -E copy <from> <to>
格式复制多个文件,但我想知道是否有办法提供许多文件以复制到特定目录。似乎 cmake 副本一次只允许复制一个文件。当我宁愿提供要复制的文件列表作为第一个参数时,我真的不想重复使用复制命令。
我认为最简单的解决方案是使用平台相关的“cp”命令。虽然这绝对不利于可移植性,但我们的系统保证构建在 Linux 上。一个简单的、独立于平台的解决方案会更好。
我用循环做到了
# create a list of files to copy
set( THIRD_PARTY_DLLS
C:/DLLFOLDER/my_dll_1.dll
C:/DLLFOLDER/my_dll_2.dll
)
# do the copying
foreach( file_i ${THIRD_PARTY_DLLS})
add_custom_command(
TARGET ${VIEWER_NAME}
POST_BUILD
COMMAND ${CMAKE_COMMAND}
ARGS -E copy ${file_i} "C:/TargetDirectory"
)
endforeach( file_i )
一个相对简单的解决方法是使用${CMAKE_COMMAND} -E tar
捆绑源、移动 tarball 并将其解压缩到目标目录中。
如果您的资源分散在许多不同的目录中,这可能会带来更多麻烦,因为提取会保留原始目录结构(与 using 不同cp
)。但是,如果所有文件都在一个目录中,则只需 2 次add_custom_command
调用即可完成复制。
假设您要移动的源都在 中${CMAKE_SOURCE_DIR}/source_dir
,目标是${CMAKE_SOURCE_DIR}/destination_dir
并且您的文件名列表(不是完整路径)在${FileList}
. 你可以这样做:
add_custom_command(
TARGET MyExe POST_BUILD
COMMAND ${CMAKE_COMMAND} -E tar cfj ${CMAKE_BINARY_DIR}/temp.tar ${FileList}
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/source_dir)
add_custom_command(
TARGET MyExe POST_BUILD
COMMAND ${CMAKE_COMMAND} -E rename ${CMAKE_BINARY_DIR}/temp.tar temp.tar
COMMAND ${CMAKE_COMMAND} -E tar xfj temp.tar ${FileList}
COMMAND ${CMAKE_COMMAND} -E remove temp.tar
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/destination_dir)
由于我或多或少有完全相同的问题并且不喜欢上面的解决方案,我最终想出了这个。它不仅仅是复制文件,但我想我会发布整个内容,因为它显示了该技术的灵活性以及生成器表达式,允许根据构建变体使用不同的文件和目录。我相信 COMMAND_EXPAND_LISTS 对这里的功能至关重要。这个函数不仅将一些文件复制到一个新目录,而且在每个文件上运行一个命令。在这种情况下,它使用 microsoft signtool 程序为每个文件添加数字签名。
cmake_minimum_required (VERSION 3.12)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
SET(ALL_3RD_PARTY_DLLS_DEBUG "${CMAKE_CURRENT_SOURCE_DIR}/file1.dll" "${CMAKE_CURRENT_SOURCE_DIR}/file2.dll")
SET(ALL_3RD_PARTY_DLLS_RELEASE "${CMAKE_CURRENT_SOURCE_DIR}/file3.dll" "${CMAKE_CURRENT_SOURCE_DIR}/file4.dll")
STRING(REPLACE "${CMAKE_CURRENT_SOURCE_DIR}" ";${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/Debug" ALL_OUTPUT_3RD_PARTY_DLLS_DEBUG ${ALL_3RD_PARTY_DLLS_DEBUG})
LIST(REMOVE_AT ALL_OUTPUT_3RD_PARTY_DLLS_DEBUG 0)
STRING(REPLACE "${CMAKE_CURRENT_SOURCE_DIR}" ";${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/Release" ALL_OUTPUT_3RD_PARTY_DLLS_RELEASE ${ALL_3RD_PARTY_DLLS_RELEASE})
LIST(REMOVE_AT ALL_OUTPUT_3RD_PARTY_DLLS_RELEASE 0)
FILE(TO_NATIVE_PATH "C:\\Program\ Files\ (x86)\\Windows\ Kits\\10\\bin\\10.0.17763.0\\x86\\signtool.exe" SIGNTOOL_COMMAND)
add_custom_target(Copy3rdPartyDLLs ALL
COMMENT "Copying and signing 3rd Party DLLs"
VERBATIM
COMMAND_EXPAND_LISTS
COMMAND ${CMAKE_COMMAND} -E
make_directory "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/$<$<CONFIG:Release>:Release>$<$<CONFIG:Debug>:Debug>/"
COMMAND ${CMAKE_COMMAND} -E
copy_if_different
"$<$<CONFIG:Release>:${ALL_3RD_PARTY_DLLS_RELEASE}>"
"$<$<CONFIG:Debug>:${ALL_3RD_PARTY_DLLS_DEBUG}>"
"${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/$<$<CONFIG:Release>:Release>$<$<CONFIG:Debug>:Debug>/"
COMMAND ${SIGNTOOL_COMMAND} sign
"$<$<CONFIG:Release>:${ALL_OUTPUT_3RD_PARTY_DLLS_RELEASE}>"
"$<$<CONFIG:Debug>:${ALL_OUTPUT_3RD_PARTY_DLLS_DEBUG}>"
)
我希望这可以节省一天的时间,或者我花了很多时间才弄清楚这一点。