使用CMake将文件从源目录复制到二进制目录


100

我正在尝试在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})
      

    但是,没有人能奏效。

我究竟做错了什么?

Answers:


127

您可以考虑将configure_file与以下COPYONLY选项一起使用:

configure_file(<input> <output> COPYONLY)

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

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


12
请注意configure_file,即使您使用GLOB创建文件列表,该功能也不适用于子目录。
塔兰图拉毒蛛

63

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

  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_BUILD,,之间进行选择PRE_LINKPOST_BUILD 最好是阅读add_custom_command的文档

有关如何使用第一个版本的示例,请参见此处:使用CMake add_custom_command生成另一个目标的源


1
是CMAKE_SOURCE_DIR还是CMAKE_CURRENT_SOURCE_DIR?
Syaiful Nizam Yahya,

1
@SyaifulNizamYahya CMAKE_CURRENT_SOURCE_DIR如果test/input.txt文件相对于当前CMakeLists.txt文件使用。如果相对于根CMakeLists.txt,请使用CMAKE_SOURCE_DIR
马克·英格拉姆

16

您尝试的第一个选项由于两个原因而无法使用。

首先,您忘记了右括号。

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

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

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

4

我建议TARGET_FILE_DIR您是否要将文件复制到.exe文件所在的文件夹中。

$主文件目录(.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相同的文件中。


3

这就是我用来复制一些资源文件的方式:复制文件是一个空目标,可以忽略错误

 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

这似乎是最好的答案(+ Herrgott的评论),因为它实际上确保了源的当前版本始终在目标发布版本中。对于小批量作业,效果很好,谢谢。把add_dependencies(MainTarget copy-files)CMakeLists.txt文件意味着,这可以在整个项目中使用。
6

1

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

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

那么syntexe是:

file(COPY pathSource DESTINATION pathDistination)

0

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

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)
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.