CMake Custom Command复制多个文件

时间:2013-01-16 22:17:42

标签: cmake

我正在尝试使用${CMAKE_COMMAND} -E copy <from> <to>格式复制多个文件,但我想知道是否有办法提供一些文件复制到特定目录。似乎cmake副本只允许一次复制一个文件。当我宁愿提供要复制的文件列表作为第一个参数时,我真的不想重复使用复制命令。

我认为最简单的解决方案是使用平台相关的“cp”命令。虽然这对于便携性肯定不好,但我们的系统保证在Linux上构建。一个简单的,独立于平台的解决方案会更好。

4 个答案:

答案 0 :(得分:10)

我用循环

做了
# 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 )

答案 1 :(得分:8)

可以从CMake 3.5

获取复制多个文件
cmake -E copy <file>... <destination>

"cmake -E copy" support for multiple files

Command-Line Tool Mode

答案 2 :(得分:6)

一个相对简单的解决方法是使用${CMAKE_COMMAND} -E tar捆绑源,移动tarball并将其解压缩到目标目录中。

如果您的源分散在许多不同的目录中,这可能比它的价值更麻烦,因为提取将保留原始目录结构(与使用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)

答案 3 :(得分:0)

由于我遇到了几乎相同的问题,并且不喜欢上面的解决方案,所以我最终提出了这个问题。它不仅可以复制文件,还可以完成整个工作,因为它显示了该技术的灵活性,并结合了生成器表达式,生成器表达式允许根据构建变体使用不同的文件和目录。我相信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}>"
)

我希望这可以为某人节省一天的时间,以便我花点时间解决这个问题。