【问题标题】:CMake - Copy file only if it doesnt existCMake - 仅在文件不存在时复制文件
【发布时间】:2018-02-03 02:17:20
【问题描述】:

我想使用 cmake 将 postbuild 中的文件复制到构建目录,但前提是它们尚不存在。

我知道“add_custom_command”有一个“copy_if_different”开关,但我找不到类似“copy_if_doesnt_exist”的东西。

目前我被这个困住了:

file(GLOB CONFIGURATION_DATA ${PROJECT_SOURCE_DIR}/data/configurations/*)

foreach(data ${CONFIGURATION_DATA})
    #only copy if file doesnt exists
    if(NOT EXISTS ?? how to get same path as - $<TARGET_FILE_DIR:${PROJECT_NAME_STR}>/data/configurations) )
        add_custom_command(TARGET ${PROJECT_NAME_STR} POST_BUILD 
        COMMAND ${CMAKE_COMMAND} -E copy 
        ${data}
        $<TARGET_FILE_DIR:${PROJECT_NAME_STR}>/data/configurations)
    endif()
endforeach()

我不知道如何获取目标文件路径的地方

$<TARGET_FILE_DIR:${PROJECT_NAME_STR}>/data/configurations

为了把它放到if语句中

【问题讨论】:

    标签: visual-studio cmake


    【解决方案1】:

    对于不直接支持的情况,file(GENERATE ...) 命令非常有用(因为它确实评估了generator expressions)。

    所以在你的情况下,我已经成功测试了以下代码示例:

    cmake_minimum_required(VERSION 2.8.12)
    
    if (POLICY CMP0070)
        cmake_policy(SET CMP0070 NEW)
    endif()
    
    project(CopyFileIfNotExists)
    
    file(
        GENERATE 
            OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/CopyConfigurationData$<CONFIG>.cmake"
            CONTENT 
                "if (NOT EXISTS \"$<TARGET_FILE_DIR:${PROJECT_NAME}>/data/configurations\")
                    execute_process(
                         COMMAND \"${CMAKE_COMMAND}\" -E copy_directory
                             \"${PROJECT_SOURCE_DIR}/data/configurations\"
                             \"$<TARGET_FILE_DIR:${PROJECT_NAME}>/data/configurations\"
                    )
                endif()"
    )
    
    file(WRITE "main.cpp" "int main() { return 0; }")
    
    add_executable(${PROJECT_NAME} "main.cpp")
    
    add_custom_command(
        TARGET ${PROJECT_NAME} 
        POST_BUILD 
        COMMAND "${CMAKE_COMMAND}" -P "CopyConfigurationData$<CONFIG>.cmake"
        WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}"
    )
    

    替代方案

    或者,如果可以使用每个 CMake(重新)配置运行,只需添加以下内容而不是构建后步骤:

    file(
        GLOB 
            CONFIGURATION_DATA 
            RELATIVE "${PROJECT_SOURCE_DIR}"
            "${PROJECT_SOURCE_DIR}/data/configurations/*"
     )
    
    foreach(data IN LISTS CONFIGURATION_DATA)
        file(
            GENERATE 
                OUTPUT "$<TARGET_FILE_DIR:${PROJECT_NAME}>/${data}"
                INPUT  "${PROJECT_SOURCE_DIR}/${data}"
        )
    endforeach()
    

    替代方案:优化版

    利用file(COPY ...)我能想到的最短的基于脚本的版本,它也优化了已经存在的项目

    “复制会保留输入文件的时间戳,如果文件存在于目标位置且具有相同的时间戳,则会对其进行优化。”

    看起来像这样:

    file(
        GENERATE 
            OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/CopyConfigurationData$<CONFIG>.cmake"
            CONTENT "file(
                        COPY \"${PROJECT_SOURCE_DIR}/data/configurations\"
                        DESTINATION \"$<TARGET_FILE_DIR:${PROJECT_NAME}>/data\"
                     )"
    )
    

    【讨论】:

    • 很好的答案!为了更好地理解事情,我还有两个问题。是否可以在不创建新的cmake文件的情况下实现第一个选项,是否可以检查特定文件而不是文件夹的存在?
    • @GpG 不客气。不,您需要生成脚本文件,因为“如果不存在则复制”不能作为单行 shell 命令使用。是的,在脚本文件中,您可以进行任何您想要的操作。可能最好检查单个文件以将 file(GLOB ... 表达式放入脚本中。如果脚本变得更复杂,我更喜欢INPUT 源文件而不是所示的内联CONTENT 方法。
    • @GpG 添加了file(COPY ...) 的替代方案,它不会复制已经存在的文件。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-04-16
    • 2020-05-03
    • 2017-10-11
    • 1970-01-01
    • 1970-01-01
    • 2013-02-17
    • 2014-01-04
    相关资源
    最近更新 更多