单个文件
首先添加一个复制的规则。 OUTPUT
指定生成的文件,DEPENDS
创建一个依赖关系,所以当输入发生变化时,该规则会再次运行。
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}
)
然后将“结果文件”作为目标所需的依赖项添加进去。
add_executable(main_executable
${CMAKE_CURRENT_BINARY_DIR}/${MY_RESOURCE_FILE}
src/main.cpp
)
这是一个现代而干净的CMake解决方案,所有依赖都是基于目标定义的,并根据需要向上传递到依赖树。我们不会改变任何全局状态。它还会跟踪文件本身,只有在过时时才会复制。这也使它成为一个强大而高效的解决方案。
如果多个目标需要它,将它们添加到所有目标中。这是一个好的实践,因为依赖关系被明确地指定在需要它们的地方。
多个文件
由于这里有人要求复制多个文件,我也在这里添加了一些内容,因为还需要考虑一些其他事项。
定义文件有两种可能性,可以手动列出它们,类似于上面的方法。或者我们可以创建一个递归的glob规则,自动发现它们。第一种方法非常直接,使用相对路径到CMAKE_CURRENT_SOURCE_DIR。
set(MY_RESOURCE_FILES
resources/font.ttf
resources/icon.svg
)
我还展示了第二个
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
)
指定
CONFIGURE_DEPENDS
会在任何目标过期时重新运行构建开始时的全局。而
RELATIVE
给出了相对于我们源目录的路径。并且使用两个星号
**.svg
可以递归搜索所有子目录。
现在我们再次创建一个单独的规则来制作每个资源文件。
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()
这样做还可以确保只复制缺失或更改的资源。
最后,我们将所有这些添加到我们的可执行文件中。为此,我们只需要调整到二进制目录的路径。
list(TRANSFORM MY_RESOURCE_FILES PREPEND ${CMAKE_CURRENT_BINARY_DIR}/)
add_executable(${MAIN_TARGET}
${MY_RESOURCE_FILES}
src/main.cpp
)
configure_file
也无法处理子目录中的文件。 - Tarantula