简体   繁体   English

将 assets 目录从源代码复制到 CMake 中的构建目录

[英]Copying assets directory from source to build directory in CMake

I am trying to write a game for practice in C++. I am using CMake for this, and my project gets built in a separate build directory automatically by my IDE. However, my assets folder is not being copied over to the new directory.我正在尝试在 C++ 中编写一个练习游戏。我为此使用 CMake,我的项目由我的 IDE 自动构建在一个单独的构建目录中。但是,我的assets文件夹没有被复制到新目录。

Currently, I am attempting to resolve this with the following:目前,我正在尝试通过以下方式解决此问题:

add_custom_command(TARGET ${PROJECT_NAME}
    POST_BUILD
    COMMAND cp -r ${PROJECT_SOURCE_DIR}/assets ${CMAKE_BINARY_DIR}
    )

However, this seems to have absolutely no effect on the outcome and the assets directory is still not present in my build directory.但是,这似乎对结果完全没有影响,资产目录仍然存在于我的构建目录中。

How can I actually make it copy this asset directory to my build location?我怎样才能真正让它把这个资产目录复制到我的构建位置? Is there a smarter way to point my program to my assets location (perhaps one that will also work with assets in /usr/share?)有没有一种更聪明的方法可以将我的程序指向我的资产位置(也许也可以与 /usr/share 中的资产一起使用?)

经过一段时间的搜索,我设法找到了file(COPY {files} DESTINATION {directory})命令:

file(COPY assets DESTINATION ${CMAKE_BINARY_DIR})

Two ways I've found, both ensuring that it copies on target build and stays up to date even if the target doesn't need to re-build.我发现了两种方法,既可以确保它在目标构建上复制,并且即使目标不需要重新构建也能保持最新。


The first uses the CMake command line tool copy_directory .第一个使用 CMake 命令行工具copy_directory It's unclear from the documentation whether this copy always happens, regardless if files in the assets directory were updated or not, or if it only copies when the asset files don't exist or an asset file was updated:从文档中不清楚此副本是否总是发生,无论assets目录中的文件是否已更新,或者仅在资产文件不存在或资产文件已更新时才进行复制:

add_custom_target(copy_assets
    COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_CURRENT_LIST_DIR}/assets ${CMAKE_CURRENT_BINARY_DIR}/assets
)
add_dependencies(mytarget copy_assets)

The second requires a small additional CMake script file, but it allows us to use the file(COPY ...) CMake comamnd, which states in the documentation that "copying preserves input file timestamps, and optimizes out a file if it exists at the destination with the same timestamp."第二个需要一个小的额外 CMake 脚本文件,但它允许我们使用file(COPY ...) CMake comamnd,它在文档中指出“复制保留输入文件时间戳,并优化文件,如果它存在于具有相同时间戳的目的地。”

First, create the CMake script file copy-assets.cmake in the same directory as your CMakeLists.txt , with the contents being (similar to Ethan McTague's answer)首先,在与CMakeLists.txt相同的目录中创建 CMake 脚本文件copy-assets.cmake ,内容为(类似于 Ethan McTague 的回答)

file(COPY ${CMAKE_CURRENT_LIST_DIR}/assets DESTINATION ${CMAKE_CURRENT_BINARY_DIR})

And then in your CMakeLists.txt , add the following:然后在您的CMakeLists.txt ,添加以下内容:

add_custom_target(copy_assets
    COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_LIST_DIR}/copy-resources.cmake
)
add_dependencies(mytarget copy_assets)

The solution above using add_custom_target is suitable for most cases, but has a few problems.上面使用add_custom_target的解决方案适用于大多数情况,但有一些问题。

  • Does not support dependent generator expressions (eg $<TARGET_FILE_DIR:tgt>)不支持依赖生成器表达式(例如 $<TARGET_FILE_DIR:tgt>)
  • Re-copies every build (slow for numerous/large files)重新复制每个构建(对于大量/大文件很慢)
  • Is not particularly readable, especially for copying from multiple locations不是特别可读,尤其是从多个位置复制

Instead, I've been usingfile GENERATE相反,我一直在使用文件 GENERATE

set(ASSETS
    assetfile
    ...)
foreach(ASSET ${ASSETS})
    file(GENERATE OUTPUT ${ASSET} INPUT ${ASSET})
endforeach()

Note I haven't needed generator expressions yet, but it looks like the latest version of CMake (3.19) adds generator expression support to this function.注意我还不需要生成器表达式,但看起来最新版本的 CMake (3.19) 为这个函数添加了生成器表达式支持。

Here is what I do with vulkan shaders.这是我对 Vulkan 着色器所做的。 Simply replace the compilation step with a copy command:只需用复制命令替换编译步骤:

macro(add_shaders)
    cmake_parse_arguments("MY" "TARGET" "SOURCES" ${ARGN})

    foreach(src ${MY_SOURCES})
        set(OUTF "${CMAKE_CURRENT_BINARY_DIR}/shaders/${src}.spv")
        get_filename_component(PARENT_DIR "${OUTF}" DIRECTORY)
        add_custom_command(
            OUTPUT "${OUTF}"
            COMMAND ${CMAKE_COMMAND} -E make_directory "${PARENT_DIR}"
            COMMAND "${Vulkan_GLSLC_EXECUTABLE}" "${CMAKE_CURRENT_SOURCE_DIR}/${src}" -o "${OUTF}"
            DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/${src}"
            VERBATIM
        )
        # src in order to get listed in the IDE, OUTF to declare the build relationship
        target_sources("${MY_TARGET}" PRIVATE "${src}" "${OUTF}")
    endforeach()
endmacro()
add_shaders(TARGET my_target SOURCES asset1 asset2 asset3 ...)

You'll have to specify each asset on its own (or loop over a list).您必须单独指定每个资产(或遍历列表)。 Including wildcards into a build is a bad idea [tm].在构建中包含通配符是个坏主意 [tm]。 This will also only copy/process stuff if it has changed.这也只会复制/处理已更改的内容。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM