You may consider using configure_file with the COPYONLY
option:
您可以考虑将CONFIGURE_FILE与COPYONLY选项一起使用:
configure_file(<input> <output> COPYONLY)
Unlike file(COPY ...)
it creates a file-level dependency between input and output, that is:
不同于文件(复制...)它在输入和输出之间创建了文件级依赖关系,即:
If the input file is modified the build system will re-run CMake to re-configure the file and generate the build system again.
Both option are valid and targeting two different steps of your build:
这两个选项都是有效的,并且针对构建的两个不同步骤:
file(COPY ...
copies the file during the configuration step and only in this step. When you rebuild your project without having changed your cmake configuration, this command won't be executed.
add_custom_command
is the preferred choice when you want to copy the file around on each build step.
The right version for your task would be:
适合您的任务的版本应该是:
add_custom_command(
TARGET foo POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy
${CMAKE_SOURCE_DIR}/test/input.txt
${CMAKE_CURRENT_BINARY_DIR}/input.txt)
you can choose between PRE_BUILD
, PRE_LINK
, POST_BUILD
best is you read the documentation of add_custom_command
你可以在PRE_BUILD、PRE_LINK、POST_BUILD之间选择,最好是阅读add_custom_command的文档。
An example on how to use the first version can be found here: Use CMake add_custom_command to generate source for another target
有关如何使用第一个版本的示例可在此处找到:使用CMake添加自定义命令为另一个目标生成源
The first of option you tried doesn't work for two reasons.
您尝试的第一个选项不起作用,原因有两个。
First, you forgot to close the parenthesis.
首先,你忘了把括号括起来。
Second, the DESTINATION
should be a directory, not a file name. Assuming that you closed the parenthesis, the file would end up in a folder called input.txt
.
其次,目标应该是目录,而不是文件名。假设您结束了括号,文件将最终保存在名为input.txt的文件夹中。
To make it work, just change it to
要使其工作,只需将其更改为
file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/input.txt
DESTINATION ${CMAKE_CURRENT_BINARY_DIR})
I would suggest TARGET_FILE_DIR
if you want the file to be copied to the same folder as your .exe file.
如果您希望将文件复制到与.exe文件相同的文件夹中,我建议使用TARGET_FILE_DIR。
$
Directory of main file (.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}>)
In VS, this cmake script will copy input.txt to the same file as your final exe, no matter it's debug or release.
在VS中,此cmake脚本会将input.txt复制到与最终exe相同的文件中,无论它是调试还是发布。
The suggested configure_file is probably the easiest solution. However, it will not rerun the copy command to if you manually deleted the file from the build directory. To also handle this case, the following works for me:
建议的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)
if you want to copy folder from currant directory to binary (build folder) folder
如果要将文件夹从Currant目录复制到二进制(Build文件夹)文件夹
file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/yourFolder/ DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/yourFolder/)
then the syntexe is :
那么syntexe是:
file(COPY pathSource DESTINATION pathDistination)
This is what I used to copy some resource files:
the copy-files is an empty target to ignore errors
这是我用来复制一些资源文件的方法:复制文件是一个空目标,用于忽略错误
add_custom_target(copy-files ALL
COMMAND ${CMAKE_COMMAND} -E copy_directory
${CMAKE_BINARY_DIR}/SOURCEDIRECTORY
${CMAKE_BINARY_DIR}/DESTINATIONDIRECTORY
)
Single File
First add a rule for the copying. OUTPUT
specifies the produced file and DEPENDS
creates a dependency, so when the input changes this rule is run again.
首先添加一条复制规则。OUTPUT指定生成的文件,Dependent创建依赖项,因此当输入更改时,此规则将再次运行。
set(MY_RESOURCE_FILE input.txt)
add_custom_command(
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${MY_RESOURCE_FILE}
COMMAND ${CMAKE_COMMAND} -E copy
${CMAKE_CURRENT_SOURCE_DIR}/${MY_RESOURCE_FILE}
${CMAKE_CURRENT_BINARY_DIR}/${MY_RESOURCE_FILE}
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/${MY_RESOURCE_FILE}
)
Then add the 'result file' as a dependency to the target that needs it.
然后将“结果文件”作为依赖项添加到需要它的目标。
add_executable(main_executable
${CMAKE_CURRENT_BINARY_DIR}/${MY_RESOURCE_FILE}
src/main.cpp
)
This is a modern and clean CMake solution, as all dependencies are defined target based, and are propagated up-wards the dependency tree as needed. We are not changing any global state. Also tracks the files itself, so it is only copied when its out-of-date. This makes it also a robust and efficient solution.
这是一个现代而干净的CMake解决方案,因为所有依赖项都是基于目标定义的,并根据需要向上传播到依赖项树。我们不会改变任何全球国家。还会跟踪文件本身,因此只有在文件过期时才会进行复制。这也使其成为一种强大而高效的解决方案。
In case its needed by multiple targets, add them to all of them. This is good practice, as dependencies are explicitly specified, exactly where they are needed.
如果多个目标需要,则将它们添加到所有目标中。这是一种很好的实践,因为依赖关系是明确指定的,并且正好在需要它们的地方。
Multiple Files
As some people here asked for copying multiple files, I am adding this here as well, as a few more things need to be considered.
由于这里的一些人要求复制多个文件,我在这里也添加了这一点,因为需要考虑更多的事情。
Defining the files one has 2 possibilities, one can manually list them, similar to above. Or we can create a recursive glob
rule, that discovers them automatically. The first is very straight forward, using relative paths to CMAKE_CURRENT_SOURCE_DIR
.
定义文件有两种可能,一种是手动列出,类似于上面。或者我们可以创建一个递归全局规则,自动发现它们。第一种方法非常简单,使用CMAKE_CURRENT_SOURCE_DIR的相对路径。
set(MY_RESOURCE_FILES
resources/font.ttf
resources/icon.svg
)
I am also showing the second glob
case, at requires a bit more consideration.
我还展示了第二个GLOB案例,需要更多考虑。
file(GLOB_RECURSE
MY_RESOURCE_FILES
RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
CONFIGURE_DEPENDS
${CMAKE_CURRENT_SOURCE_DIR}/resources/**.ttf # adapt these to your needs
${CMAKE_CURRENT_SOURCE_DIR}/resources/**.svg
)
Specifying CONFIGURE_DEPENDS
re-runs the glob at the beginning the build when any target is out-of date. And RELATIVE
gives us relative path to our source directory. And using two stars **.svg
recursively searches all sub-directories as well.
当任何目标过期时,指定CONFIGURE_Dependers将在构建开始时重新运行GLOB。而Relative为我们提供了源目录的相对路径。并使用两个星号**.svg递归搜索所有子目录。
Now we create again a separate rule to make each resource file.
现在,我们再次创建一个单独的规则来创建每个资源文件。
FOREACH(MY_RESOURCE_FILE ${MY_RESOURCE_FILES})
add_custom_command(
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${MY_RESOURCE_FILE}
COMMAND ${CMAKE_COMMAND} -E copy
${CMAKE_CURRENT_SOURCE_DIR}/${MY_RESOURCE_FILE}
${CMAKE_CURRENT_BINARY_DIR}/${MY_RESOURCE_FILE}
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/${MY_RESOURCE_FILE}
)
ENDFOREACH()
This will also make it that only the resources missing or changed are copied.
这还将使其仅复制丢失或更改的资源。
And finally we add all of them to our executable. For that we just need to adjust the paths to the binary dir.
最后,我们将它们全部添加到我们的可执行文件中。为此,我们只需调整指向二进制目录的路径。
list(TRANSFORM MY_RESOURCE_FILES PREPEND ${CMAKE_CURRENT_BINARY_DIR}/)
add_executable(${MAIN_TARGET}
${MY_RESOURCE_FILES}
src/main.cpp
)
If you don't expect modifications to be made to the file in the binary directory, you could just save the complication of writing custom commands / targets for re-copying upon file changes and just use symlinks. CMake supports creating symlinks (or pretty much equivalent things on Windows). It has the file(CREATE_LINK <original> <linkname> [RESULT <result>] [COPY_ON_ERROR] [SYMBOLIC])
command, and the create_symlink <old> <new>
commandline command.
如果您不希望对二进制目录中的文件进行修改,则只需省去编写定制命令/目标以在文件更改时重新复制的复杂性,而只需使用符号链接即可。CMake支持创建符号链接(或者在Windows上创建几乎等同的东西)。它具有FILE(CREATE_LINK<原始>
[RESULT
][COPY_ON_ERROR][符号])命令和create_symlink
命令行命令。
If you don't expect the copy from the source directory to ever change / or are okay with re-configuring manually every time it changes, you can use the file(COPY_FILE <oldname> <newname> [RESULT <result>] [ONLY_IF_DIFFERENT] [INPUT_MAY_BE_RECENT])
or the file(COPY [...])
commands.
如果您不希望源目录中的副本发生更改,或者可以在每次更改时手动重新配置,则可以使用文件(Copy_FILE
[Result>][Only_If_Different][Input_May_Be_Recent])或文件(Copy[...])命令。
If you want to put the content of example
into install
folder after build:
如果您想在构建后将示例内容放入Install文件夹:
code/
src/
example/
CMakeLists.txt
try add the following to your CMakeLists.txt
:
尝试将以下内容添加到您的CMakeLists.txt:
install(DIRECTORY example/ DESTINATION example)
更多回答
Please note that configure_file
isn't going to work with sub-directories, even if you use GLOB to create a list of files.
请注意,CONFIGURE_FILE不适用于子目录,即使您使用GLOB创建文件列表也是如此。
Also note that this isn't a "file-level dependency" between input and output: it's a dependency between the input and the cmake configure step. So instead of a regular build dependency where changing a source file rebuilds only the corresponding object file, this causes the whole of cmake to reconfigure, which may have other side effects.
还要注意,这不是输入和输出之间的“文件级依赖关系”:它是输入和cmake配置步骤之间的依赖关系。因此,与更改源文件仅重新构建相应的目标文件的常规构建依赖关系不同,这会导致整个cmake重新配置,这可能会产生其他副作用。
how we use this command to copy recursive directory files?
我们如何使用这个命令来复制递归目录文件?
Is it CMAKE_SOURCE_DIR or CMAKE_CURRENT_SOURCE_DIR?
是CMAKE_SOURCE_DIR还是CMAKE_CURRENT_SOURCE_DIR?
@SyaifulNizamYahya use CMAKE_CURRENT_SOURCE_DIR
if the test/input.txt
file is relative to the current CMakeLists.txt
file. If it's relative to the root CMakeLists.txt
, then use CMAKE_SOURCE_DIR
.
如果测试/input.txt文件相对于当前的CMakeLists.txt文件,@SyaifulNizamYahya使用CMAKE_CURRENT_SOURCE_DIR。如果它相对于根CMakeLists.txt,则使用CMAKE_SOURCE_DIR。
Is there a way to get the targets filename in cmake? without hardcoding the filename? e.g. I'm building a lib file, does cmake have a variable to get the targte filename? like libSomething.so
?
有没有办法在cmake中获得目标文件名?而不对文件名进行硬编码?例如,我正在构建一个lib文件,cmake是否有一个变量来获取targte文件名?就像libSomething。那又怎样?
Note: to copy a directory recursively instead of a file, use ${CMAKE_COMMAND} -E copy_directory
注意:要递归复制目录而不是文件,请使用${CMAKE_COMMAND}-E COPY_DIRECTORY
@jorisv92 how would you force copy or copy if different using copy_directory or some other recursive operation?
@jorisv92如果使用COPY_DIRECTORY或其他递归操作,您将如何强制复制或复制?
This and only this worked for me. I am migrating a legacy library from autoconf to CMake. This setup works when using both gcc and msvc.
这个,而且只有这个对我有效。我正在将旧库从Autoconf迁移到CMake。当同时使用GCC和MSVC时,此设置可以正常工作。
IMO this is the only correct solution here. The first command tells cmake what files you need to exist and the second command tells cmake how to create them.
我想这是这里唯一正确的解决方案。第一个命令告诉cmake需要存在哪些文件,第二个命令告诉cmake如何创建这些文件。
I would also add add_dependencies(MainTarget copy-files)
to make it run automatically when I build MainTarget
我还会添加添加依赖项(MainTarget复制文件),使其在构建MainTarget时自动运行
This seems like the best answer (+Herrgott's comment) as it actually ensures that the current version of the source is always in the destination post build. For small copy jobs this works well, thanks. Putting add_dependencies(MainTarget copy-files)
in the root CMakeLists.txt
file means that this can be used throughout the project.
这似乎是最好的答案(+Herrgot的评论),因为它实际上确保了源代码的当前版本始终在目标构建后。对于小型复印作业,此功能运行良好,谢谢。将Add_Dependency(MainTarget复制文件)放在根CMakeLists.txt文件中意味着可以在整个项目中使用它。
But the 'install' command has a side effect: the installed files will appear in the cpack package . . .
但是‘Install’命令有一个副作用:已安装的文件将出现在cpack包中。。。
This is a correct answer to a different question. :) Build (cmake --build ...
) is a separate stage from install (cmake --install...
). In particular, VSCode normally runs only the build command and debugs the program directly from CMAKE_BINARY_DIR
. The question is kinda mushy at which stage, configure or build, the file needs to be copied, but the install phase is certainly too late. Yes the files will require separate install description with the install()
command, best using target properties in the Modern CMake framework, but that's out of scope.
这是对另一个问题的正确回答。:)构建(cmake--构建...)是一个独立于安装的阶段(cmake--Install...)。特别是,VSCode通常只运行BUILD命令,并直接从CMAKE_BINARY_DIR调试程序。问题有点模糊,在哪个阶段,无论是配置还是构建,需要复制文件,但安装阶段肯定太晚了。是的,这些文件将需要使用Install()命令进行单独的安装描述,最好使用现代CMake框架中的目标属性,但这超出了讨论范围。
我是一名优秀的程序员,十分优秀!