cmake

How can I copy all build type parameters from an existing build configuration type to a new build type?


In CMake (ver. 3.8+), I'd like to copy all the settings for a build type to my custom build type.

I define a custom build type as:

# Add new configuration
set(CMAKE_CONFIGURATION_TYPES ${CMAKE_CONFIGURATION_TYPES} Deploy)
message("generated with config types:" ${CMAKE_CONFIGURATION_TYPES})

Ideally, I would not like to copy manually flags etc. because I may for example copy the CXX and linker flags, but forget C flags.

Is that possible?


Solution

  • You'd need to copy all the the variables with <CONFIG> in their template name in the documentation.

    You could hardcode it, or you could be fancy and write a function that does it based on the documented list of such variables. The following function takes the name of a source and destination ("from" and "to") build type names, and uses the output of cmake --help-variable-list to copy those source variables to the destination variables:

    execute_process(
      COMMAND ${CMAKE_COMMAND} --help-variable-list
      OUTPUT_FILE "${CMAKE_CURRENT_BINARY_DIR}/cmake_var_full_list.txt"
    )
    file(STRINGS "${CMAKE_CURRENT_BINARY_DIR}/cmake_var_full_list.txt" VAR_FULL_LIST)
    foreach(var ${VAR_FULL_LIST})
      if("${var}" MATCHES "<CONFIG>")
        if("${var}" MATCHES "<LANG>")
          foreach(lang C CXX CSharp CUDA OBJC OBJCXX Fortran HIP ISPC Swift ASM ASM_NASM ASM_MARMASM ASM_MASM ASM-ATT)
            # (supported languages list from https://cmake.org/cmake/help/latest/command/project.html)
            string(REPLACE "<LANG>" "${lang}" lang_var "${var}")
            list(APPEND CONFIG_VAR_LIST "${lang_var}")
          endforeach()
        else()
          list(APPEND CONFIG_VAR_LIST "${var}")
        endif()
      endif()
    endforeach()
    unset(VAR_FULL_LIST)
    
    function(copy_configuration_type config_from config_to)
      string(TOUPPER "${config_from}" config_from)
      string(TOUPPER "${config_to}" config_to)
      foreach(config_var ${CONFIG_VAR_LIST})
        string(REPLACE "<CONFIG>" "${config_from}" config_var_from "${config_var}")
        string(REPLACE "<CONFIG>" "${config_to}"   config_var_to   "${config_var}")
        set("${config_var_to}" "${${config_var_from}}" PARENT_SCOPE)
      endforeach()
    endfunction()
    

    Example usage:

    copy_configuration_type(DEBUG DEBUG2)
    message("CMAKE_CXX_FLAGS_DEBUG2: ${CMAKE_CXX_FLAGS_DEBUG2}")
    

    The wiki page sets these as cache variables (see the related CMake wiki entry). I didn't do that here, but you could adjust the call to set() to do so. If you do, you might also want to add logic for copying whether the cache variable is marked as advanced.

    You might need to put this before the first call to project().

    You may also want to copy whether the config is considered a debug configuration (see the DEBUG_CONFIGURATIONS global property (currently only used for a lesser-known feature of target_link_libraries, so you might not need to for your use-case)).

    You may also want to set/modify the CMAKE_MAP_IMPORTED_CONFIG_<CONFIG> setting.

    Related questions: How to add a custom build type to CMake? (targeting make) and How to create a CMake configuration type that inherits from Release.

    I raised an issue ticket to Kitware requesting that a standard function be added to do this here: https://gitlab.kitware.com/cmake/cmake/-/issues/24632.