cmake

How to find files with $<CONFIG> in file(GLOB ...)?


I'm trying to locate a specific file in my CMake build using file(GLOB ...) while accounting for $<CONFIG> to ensure the correct version of the file is selected based on the build configuration. Specifically, I need to find the vc*-mtd.lib file, where the * represents a version number that varies.

file(GLOB LIB "${BINARY_DIR}/lib/$<CONFIG>/vc*-mtd.lib")
add_custom_command(
    TARGET MyTarget POST_BUILD
    COMMAND ${CMAKE_COMMAND} -E copy_if_different
        ${LIB}
        ${CMAKE_BINARY_DIR}/lib/$<CONFIG>
)

However, this approach isn't working because $<CONFIG> doesn't seem to exist properly within file(GLOB ...). As a result, the glob doesn't resolve correctly, and I can't find a straightforward solution to make it work.
If file(GLOB ...) can't handle $<CONFIG>, what is the recommended way to achieve this dynamically in CMake?


Solution

  • The command file(GLOB) searches files immediately, when the command is processed by CMake inside CMakeLists.txt. However, $<CONFIG> (and any other generator expression) is resolved only at the end of configuration process, so file(GLOB) cannot use configuration name.

    You may call file(GLOB) several times, for every configuration you want to support:

    # Search libraries for Release configuration
    file(GLOB LIB_Release "${BINARY_DIR}/lib/Release/vc*-mtd.lib")
    # Search libraries for Debug configuration
    file(GLOB LIB_Debug "${BINARY_DIR}/lib/Debug/vc*-mtd.lib")
    

    and inside custom command use generator expression for select libraries needed for specific configuration

    add_custom_command(
        TARGET MyTarget POST_BUILD
        COMMAND ${CMAKE_COMMAND} -E copy_if_different
            "$<$<CONFIG:Release>:${LIB_Release}>"
            "$<$<CONFIG:Debug>:${LIB_Debug}>"
            ${CMAKE_BINARY_DIR}/lib/$<CONFIG>
        COMMAND_EXPAND_LIST # Automatically expands lists inside double quotes
    )
    

    Assuming GLOB may return several files, combining resulted list with $<CONFIG> generator expression cannot be performed unquoted. Quoted variant will produce a single string with semicolon-separated paths, so additional option COMMAND_EXPAND_LIST is used for transform such strings into proper list (see that answer).


    Alternative approach is preparing a script which accepts a configuration name and by itself searches all libraries and copies them into corresponding location. That script could be called from add_custom_command.

    E.g. you could write a CMake script for that purpose:

    # The script expects following parameters:
    #
    # - source_dir - directory from which copy libraries
    # - destination_dir - directory to which copy libraries
    
    file(GLOB LIB "${source_dir}/vc*-mtd.lib")
    execute_process(COMMAND ${CMAKE_COMMAND} -E copy_if_different
            ${LIB}
            ${destination_dir}
            COMMAND_ERROR_IS_FATAL ANY # Fail the CMake script if the subprocess fails
    )
    

    and call it that way:

    add_custom_command(
        TARGET MyTarget POST_BUILD
        COMMAND ${CMAKE_COMMAND}
            -Dsource_dir=${BINARY_DIR}/lib/$<CONFIG>
            -Ddestination_dir=${CMAKE_BINARY_DIR}/lib/$<CONFIG>
            -P /path/to/script
    )