Copying config-specific paths at build time

I’m trying to figure out how to optionally copy a directory, whose path depends on whether I’m doing a debug or release build, at build time (NOT install time, which is easy).

By ‘optionally’, I mean copy the directory if a particular file in the target location either doesn’t exist, or isn’t identical to the version of the same file in the source directory. As the target location is configuration-specific, it is described using a generator expression of the form:

suitename/$<IF:$<CONFIG:Debug>,win10_64_d,win10_64_r>)

Since the check needs to be done at build time (because the debug/release configuration isn’t known at configuration time), the natural approach is to use add_custom_command with a script, viz.

add_custom_command(TARGET MyApp POST_BUILD
                   COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_BINARY_DIR}/copydir.cmake)

…with copydir.cmake having the content:

set(SRC_PATH  suitename/$<IF:$<CONFIG:Debug>,win10_64_d,win10_64_r>)
set(DEST_PATH resources_$<IF:$<CONFIG:Debug>,dbg,opt>/x86_64-windows)

execute_process(COMMAND ${CMAKE_COMMAND} -E compare_files ${SRC_PATH}/resource.exe ${DEST_PATH}/resources/resource.exe
                RESULT_VARIABLE compare_result)

if (NOT compare_result EQUAL 0)
    message("Copying the resource from ${SRC_PATH} to ${DEST_PATH}/resources for use while debugging")
    execute_process(COMMAND ${CMAKE_COMMAND} -E remove_directory ${DEST_PATH}/resources)
    execute_process(COMMAND ${CMAKE_COMMAND} -E copy_directory ${SRC_PATH} ${DEST_PATH}/resources)
endif()

However, at build time I see the following messages in the Visual Studio output console:

Files "suitename/$<IF:$<CONFIG:Debug>,win10_64_d,win10_64_r>/resource.exe" to "resources_$<IF:$<CONFIG:Debug>,dbg,opt>/x86_64-windows/resource.exe" are different.
Copying the resource from suitename/$<IF:$<CONFIG:Debug>,win10_64_d,win10_64_r> to resources_$<IF:$<CONFIG:Debug>,dbg,opt>/x86_64-windows for use while debugging
Error copying directory from "suitename/$<IF:$<CONFIG:Debug>,win10_64_d,win10_64_r>" to "resources_$<IF:$<CONFIG:Debug>,dbg,opt>/x86_64-windows".

… which suggest to me that, even though the copydir.cmake script is being executed at build time when the configuration is known, yet still the generator expressions aren’t being expanded properly.

What am I doing wrong?

CMake knows how to expand generator expressions at generate time. At build time, no such information is known. I would recommend doing:

file(GENERATE
  INPUT "${CMAKE_CURRENT_SOURCE_DIR}/script.cmake"
  OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/script.$<CONFIG>.cmake")

and then run -P "${CMAKE_CURRENT_BINARY_DIR}/script.$<CONFIG>.cmake" to run the per-config script code.

Alternatively, you can pass the config via -Dconfig=$<CONFIG> to the script and do regular if conditions on the value.

CMake can only resolve generator expressions in a custom custom if they are directly part of the COMMAND argument and not hidden in a script file. You have to resolve those manually using file(GENERATE) and then point your custom command to execute the generated script:

file(GENERATE
  OUTPUT "copydir-$<CONFIG>.cmake"
  INPUT "path/to/copydir.cmake"
)
add_custom_command(TARGET MyApp POST_BUILD
  COMMAND ${CMAKE_COMMAND} -P "${CMAKE_CURRENT_BINARY_DIR}/copydir-$<CONFIG>.cmake"
)

Thank you; yes, this was the solution but I accepted the other answer because it contained a little bit of extra information.