【问题标题】:Copy file from source directory to binary directory using CMake使用 CMake 将文件从源目录复制到二进制目录
【发布时间】:2016-04-20 09:19:39
【问题描述】:

我正在尝试在 CLion 上创建一个简单的项目。它使用 CMake(我是新来的)生成 Makefile 来构建项目(或某种项目)

每次运行我的代码时,我只需要将一些非项目文件(某种资源文件)转移到二进制目录。

该文件包含测试数据,应用程序打开它来读取它们。我尝试了几种方法:

  • 通过file(COPY ...

    file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/input.txt
            DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/input.txt
    

    看起来不错,但它只工作一次,下次运行后不会重新复制文件。

  • 通过add_custom_command

    • OUTPUT版本

      add_custom_command(
              OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/input.txt
              COMMAND ${CMAKE_COMMAND} -E copy
                      ${CMAKE_CURRENT_SOURCE_DIR}/input.txt
                      ${CMAKE_CURRENT_BINARY_DIR}/input.txt)
      
    • TARGET版本

      add_custom_target(foo)
      add_custom_command(
              TARGET foo
              COMMAND ${CMAKE_COMMAND} copy
                      ${CMAKE_CURRENT_BINARY_DIR}/test/input.txt
                      ${CMAKE_SOURCE_DIR})
      

    但没有一个有效。

我做错了什么?

【问题讨论】:

    标签: cmake


    【解决方案1】:

    您可以考虑将configure_fileCOPYONLY 选项一起使用:

    configure_file(<input> <output> COPYONLY)
    

    file(COPY ...)不同,它在输入和输出之间创建了文件级依赖关系,即:

    如果输入文件被修改,构建系统将重新运行 CMake 重新配置文件并再次生成构建系统。

    【讨论】:

    • 请注意configure_file 不能用于子目录,即使您使用 GLOB 创建文件列表。
    • 另请注意,这不是输入和输出之间的“文件级依赖关系”:它是输入和cmake 配置步骤 之间的依赖关系。因此,更改源文件仅重建相应的目标文件的常规构建依赖关系,这会导致整个 cmake 重新配置,这可能会产生其他副作用。
    【解决方案2】:

    这两个选项都有效,并且针对构建的两个不同步骤:

    1. file(COPY ... 在配置步骤中复制文件,并且仅在此步骤中。当您在未更改 cmake 配置的情况下重建项目时,将不会执行此命令。
    2. 当您想在每个构建步骤中复制文件时,add_custom_command 是首选。

    适合您任务的版本是:

    add_custom_command(
            TARGET foo POST_BUILD
            COMMAND ${CMAKE_COMMAND} -E copy
                    ${CMAKE_SOURCE_DIR}/test/input.txt
                    ${CMAKE_CURRENT_BINARY_DIR}/input.txt)
    

    您可以在PRE_BUILDPRE_LINKPOST_BUILD 之间进行选择 最好是你阅读add_custom_command 的文档

    可以在此处找到有关如何使用第一个版本的示例:Use CMake add_custom_command to generate source for another target

    【讨论】:

    • 是CMAKE_SOURCE_DIR还是CMAKE_CURRENT_SOURCE_DIR?
    • @SyaifulNizamYahya 如果test/input.txt 文件相对于当前CMakeLists.txt 文件,则使用CMAKE_CURRENT_SOURCE_DIR。如果它相对于根CMakeLists.txt,则使用CMAKE_SOURCE_DIR
    • 有没有办法在 cmake 中获取目标文件名?没有硬编码文件名?例如我正在构建一个 lib 文件,cmake 是否有一个变量来获取目标文件名?喜欢libSomething.so?
    • 注意:要递归复制目录而不是文件,请使用${CMAKE_COMMAND} -E copy_directory
    • @jorisv92 如果使用 copy_directory 或其他递归操作不同,您将如何强制复制或复制?
    【解决方案3】:

    您尝试的第一个选项不起作用有两个原因。

    首先,您忘记关闭括号。

    其次,DESTINATION 应该是一个目录,而不是文件名。假设您关闭了括号,该文件最终将位于名为 input.txt 的文件夹中。

    要使其工作,只需将其更改为

    file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/input.txt
         DESTINATION ${CMAKE_CURRENT_BINARY_DIR})
    

    【讨论】:

      【解决方案4】:

      建议的 configure_file 可能是最简单的解决方案。但是,如果您从构建目录中手动删除该文件,它不会重新运行复制命令。为了也处理这种情况,以下对我有用:

      add_custom_target(copy-test-makefile ALL DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/input.txt)
      add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/input.txt
                         COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/input.txt
                                                          ${CMAKE_CURRENT_BINARY_DIR}/input.txt
                         DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/input.txt)
      

      【讨论】:

      • IMO 这是这里唯一正确的解决方案。第一个命令告诉 cmake 你需要存在哪些文件,第二个命令告诉 cmake 如何创建它们。
      【解决方案5】:

      这是我用来复制一些资源文件的: 复制文件是忽略错误的空目标

       add_custom_target(copy-files ALL
          COMMAND ${CMAKE_COMMAND} -E copy_directory
          ${CMAKE_BINARY_DIR}/SOURCEDIRECTORY
          ${CMAKE_BINARY_DIR}/DESTINATIONDIRECTORY
          )
      

      【讨论】:

      • 我还要添加add_dependencies(MainTarget copy-files) 让它在我构建 MainTarget 时自动运行
      • 这似乎是最好的答案(+Herrgott 的评论),因为它实际上确保源的当前版本始终在目标后期构建中。对于小型复印工作,这很好用,谢谢。将add_dependencies(MainTarget copy-files) 放在根CMakeLists.txt 文件中意味着可以在整个项目中使用。
      【解决方案6】:

      如果您希望将该文件复制到与您的 .exe 文件相同的文件夹中,我建议您使用 TARGET_FILE_DIR

      $ 主文件目录(.exe、.so.1.2、.a)。

      add_custom_command(
        TARGET ${PROJECT_NAME} POST_BUILD
        COMMAND ${CMAKE_COMMAND} -E copy 
          ${CMAKE_CURRENT_SOURCE_DIR}/input.txt 
          $<TARGET_FILE_DIR:${PROJECT_NAME}>)
      

      在 VS 中,无论是调试还是发布,此 cmake 脚本都会将 input.txt 复制到与最终 exe 相同的文件中。

      【讨论】:

        【解决方案7】:

        如果要将文件夹从 currant 目录复制到二进制(构建文件夹)文件夹

        file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/yourFolder/ DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/yourFolder/)
        

        那么语法是:

        file(COPY pathSource DESTINATION pathDistination)
        

        【讨论】:

          【解决方案8】:

          如果你想在构建后将example的内容放入install文件夹中:

          code/
            src/
            example/
            CMakeLists.txt
          

          尝试将以下内容添加到您的CMakeLists.txt

          install(DIRECTORY example/ DESTINATION example)
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多