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.
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. Furthermore the files are tracked, so are only copied when they are out-of-date or missing. This makes it also a robust and efficient solution.
If the file is needed by multiple targets, add them to all of them. This is good practice, as dependencies are explicitly specified, exactly where they are needed. And copied when those targets are build.
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.
There are two options to list the files, manually listing them and using recursive glob rule, that discovers them automatically. The first is very straight forward, using relative paths to CMAKE_CURRENT_SOURCE_DIR.
set(MY_RESOURCE_FILES
resources/font.ttf
resources/icon.svg
)
The auto-discovery rules is not much longer, however it requires more explanations.
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. This is needed, as otherwise the build system once configured will not look new files that would match the glob. And RELATIVE gives us relative path to our source directory. Note that stars **.svg recursively searches all sub-directories as well, a common glob rule.
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
)