Copy resources to build folder

I’m doing an OpenGL project where I mostly write shaders and have several texture files. Is there a way I can copy it to the build folder so the binary can access it?

configure_file(COPYONLY) should be able to do it. You can also run it from a script via add_custom_command so that it gets copied at build time and CMake doesn’t need to rerun on any shader/texture changes.

I’ve tackled almost the same issue a dozen times with OpenCL, where I’d need to copy device code next to the executables in both single-config and multi-config cases. I’ve not been able to cook up a robust and simple solution yet. I tried doing my best in the OpenCL-SDK here but it’s both a mouthful and invokes the custom commands more times then strictly necessary (once for each config, no matter which one I’m building). How does one copy source files to build tree when they are likely to change throughout development?

Without requiring 3.20 for genex support in custom command outputs, what you have looks pretty close to what I’d do.

I ultimately managed to come up with something simpler than that, which I’ve yet to upstream to the OpenCL-SDK.

# The following CMake snippet copies kernel files next to the executable in the build tree.
# It does the following steps:
#
# 1. Checks whether the generator at hand is a multi-config generator or not.
#
#    This is needed because add_custom_command & add_custom_target don't accept target-dependent
#    generator expressions, so we can't use $<TARGET_FILE_DIR:tgt> to ask our tagrget which
#    folder the executable goes to. Therefore we handle the folder difference between single-
#    and multi-config generators ourselves. We assemble the path using CMAKE_RUNTIME_OUTPUT_DIRECTORY
#    which is the variable used as the default for TARGET_FILE_DIR. If we alter TARGET_FILE_DIR to
#    differ from the default, this snippet won't work without modification.
#
# 2. Sets up helper vars for a) what TO_COPY b) where we COPY_TO c) OUTPUTs the helper target
#    DEPENDS on.
#
#    CMake stores/formats lists as a semi-colon delimited string. The helper vars transform the
#    ${Kernels} variable which for eg. may be k1.cl;k2.cl . This works because add_executable awaits
#    source files either via absolute path or relative paths to CMAKE_CURRENT_SOURCE_DIR. We want to
#    transform k1.cl;k2.cl to <dir>/k1.cl;<dir>/k2.cl where <dir> may be CMAKE_RUNTIME_OUTPUT_DIRECTORY or
#    CMAKE_CURRENT_SOURCE_DIR depending on whether we're assembling paths to sources or destinations.
#    $<JOIN:list,delimiter> will join the elements of 'list' using the string 'delimiter'. The delimiter
#    isn't prepended to the first item, we have to specify that outselves, hence the complete expression
#    takes the form <dir>/$<JOIN:list,;<dir>/>.
#
# 3. Registers a custom command which copies all files in ${Kernels} to the proper build tree folder
#
# 4. Registers a custom target which DEPENDS on the OUTPUT of the custom command
#
# 5. Sets up the executable to depend on kernel code deployment, so building our target also copies
#    potentially updated kernel code, therefore if someone isn't building the 'all' meta-target, but
#    the executable only, they won't miss kernel-code updates.
get_property(GENERATOR_IS_MULTI_CONFIG GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
set(TO_COPY "${CMAKE_CURRENT_SOURCE_DIR}/$<JOIN:${Kernels},;${CMAKE_CURRENT_SOURCE_DIR}/>")
set(COPY_TO "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/$<$<BOOL:${GENERATOR_IS_MULTI_CONFIG}>:$<CONFIG>>")
set(OUTPUT_AND_DEPENDS "${COPY_TO}/$<JOIN:${Kernels},;${COPY_TO}/>")
add_custom_command(
  OUTPUT "${OUTPUT_AND_DEPENDS}"
  COMMAND ${CMAKE_COMMAND}
    ARGS
      -E copy_if_different
      "${TO_COPY}"
      "${COPY_TO}"
  COMMENT "Copying CL kernels for ${PROJECT_NAME}"
  COMMAND_EXPAND_LISTS
  DEPENDS ${Kernels}
)
add_custom_target(${PROJECT_NAME}-device-code
  DEPENDS "${OUTPUT_AND_DEPENDS}"
)
add_dependencies(${PROJECT_NAME}
  ${PROJECT_NAME}-device-code
)