function(qt_print_feature_summary)
    include(FeatureSummary)
    # Show which packages were found.
    feature_summary(WHAT PACKAGES_FOUND
                         REQUIRED_PACKAGES_NOT_FOUND
                         RECOMMENDED_PACKAGES_NOT_FOUND
                         OPTIONAL_PACKAGES_NOT_FOUND
                         RUNTIME_PACKAGES_NOT_FOUND
                         FATAL_ON_MISSING_REQUIRED_PACKAGES)
    qt_configure_print_summary()
endfunction()

function(qt_print_build_instructions)
    if((NOT PROJECT_NAME STREQUAL "QtBase" AND
        NOT PROJECT_NAME STREQUAL "Qt") OR
       QT_BUILD_STANDALONE_TESTS)

        return()
    endif()

    set(build_command "cmake --build . --parallel")
    set(install_command "cmake --install .")
    set(configure_module_command "qt-configure-module")
    if(CMAKE_HOST_WIN32)
        string(APPEND configure_module_command ".bat")
    endif()
    if("${CMAKE_STAGING_PREFIX}" STREQUAL "")
        set(local_install_prefix "${CMAKE_INSTALL_PREFIX}")
    else()
        set(local_install_prefix "${CMAKE_STAGING_PREFIX}")
    endif()

    message("Qt is now configured for building. Just run '${build_command}'\n")
    if(QT_WILL_INSTALL)
        message("Once everything is built, you must run '${install_command}'")
        message("Qt will be installed into '${CMAKE_INSTALL_PREFIX}'")
    else()
        message("Once everything is built, Qt is installed. You should NOT run '${install_command}'")
        message("Note that this build cannot be deployed to other machines or devices.")
    endif()
    message("\nTo configure and build other Qt modules, you can use the following convenience script:
        ${local_install_prefix}/${INSTALL_BINDIR}/${configure_module_command}")
    message("\nIf reconfiguration fails for some reason, try to remove 'CMakeCache.txt' \
from the build directory \n")
endfunction()

function(qt_configure_print_summary)
    # Evaluate all recorded commands.
    qt_configure_eval_commands()

    set(summary_file "${CMAKE_BINARY_DIR}/config.summary")
    file(WRITE "${summary_file}" "")
    # Show Qt-specific configure summary and any notes, wranings, etc.
    if(__qt_configure_reports)
        message("Configure summary:\n${__qt_configure_reports}")
        file(APPEND "${summary_file}" "${__qt_configure_reports}")
    endif()
    if(__qt_configure_notes)
        message("${__qt_configure_notes}")
        file(APPEND "${summary_file}" "${__qt_configure_notes}")
    endif()
    if(__qt_configure_warnings)
        message("${__qt_configure_warnings}")
        file(APPEND "${summary_file}" "${__qt_configure_warnings}")
    endif()
    if(__qt_configure_errors)
        message("${__qt_configure_errors}")
        file(APPEND "${summary_file}" "${__qt_configure_errors}")
    endif()
    message("")
    if(__qt_configure_an_error_occurred)
        message(FATAL_ERROR "Check the configuration messages for an error that has occurred.")
    endif()
    file(APPEND "${summary_file}" "\n")
endfunction()

# Takes a list of arguments, and saves them to be evaluated at the end of the configuration
# phase when the configuration summary is shown.
function(qt_configure_record_command)
    # Don't record commands when only evaluating features of a configure.cmake file.
    if(__QtFeature_only_evaluate_features)
        return()
    endif()

    get_property(command_count GLOBAL PROPERTY qt_configure_command_count)

    if(NOT DEFINED command_count)
        set(command_count 0)
    endif()

    set_property(GLOBAL PROPERTY qt_configure_command_${command_count} "${ARGV}")

    math(EXPR command_count "${command_count}+1")
    set_property(GLOBAL PROPERTY qt_configure_command_count "${command_count}")
endfunction()

function(qt_configure_eval_commands)
    get_property(command_count GLOBAL PROPERTY qt_configure_command_count)
    if(NOT command_count)
        set(command_count 0)
    endif()
    set(command_index 0)

    while(command_index LESS command_count)
        get_property(command_args GLOBAL PROPERTY qt_configure_command_${command_index})
        if(NOT command_args)
            message(FATAL_ERROR
                "Empty arguments encountered while processing qt configure reports.")
        endif()

        list(POP_FRONT command_args command_name)
        if(command_name STREQUAL ADD_SUMMARY_SECTION)
            qt_configure_process_add_summary_section(${command_args})
        elseif(command_name STREQUAL END_SUMMARY_SECTION)
            qt_configure_process_end_summary_section(${command_args})
        elseif(command_name STREQUAL ADD_REPORT_ENTRY)
            qt_configure_process_add_report_entry(${command_args})
        elseif(command_name STREQUAL ADD_SUMMARY_ENTRY)
            qt_configure_process_add_summary_entry(${command_args})
        elseif(command_name STREQUAL ADD_BUILD_TYPE_AND_CONFIG)
            qt_configure_process_add_summary_build_type_and_config(${command_args})
        elseif(command_name STREQUAL ADD_BUILD_MODE)
            qt_configure_process_add_summary_build_mode(${command_args})
        elseif(command_name STREQUAL ADD_BUILD_PARTS)
            qt_configure_process_add_summary_build_parts(${command_args})
        endif()

        math(EXPR command_index "${command_index}+1")
    endwhile()

    # Propagate content to parent.
    set(__qt_configure_reports "${__qt_configure_reports}" PARENT_SCOPE)
    set(__qt_configure_notes "${__qt_configure_notes}" PARENT_SCOPE)
    set(__qt_configure_warnings "${__qt_configure_warnings}" PARENT_SCOPE)
    set(__qt_configure_errors "${__qt_configure_errors}" PARENT_SCOPE)
    set(__qt_configure_an_error_occurred "${__qt_configure_an_error_occurred}" PARENT_SCOPE)
endfunction()

macro(qt_configure_add_report message)
    string(APPEND __qt_configure_reports "\n${message}")
    set(__qt_configure_reports "${__qt_configure_reports}" PARENT_SCOPE)
endmacro()

macro(qt_configure_add_report_padded label message)
    qt_configure_get_padded_string("${__qt_configure_indent}${label}" "${message}" padded_message)
    string(APPEND __qt_configure_reports "\n${padded_message}")
    set(__qt_configure_reports "${__qt_configure_reports}" PARENT_SCOPE)
endmacro()

# Pad 'label' and 'value' with dots like this:
# "label ............... value"
#
# PADDING_LENGTH specifies the number of characters from the start to the last dot.
#                Default is 30.
# MIN_PADDING    specifies the minimum number of dots that are used for the padding.
#                Default is 0.
function(qt_configure_get_padded_string label value out_var)
    cmake_parse_arguments(arg "" "PADDING_LENGTH;MIN_PADDING" "" ${ARGN})
    if("${arg_MIN_PADDING}" STREQUAL "")
        set(arg_MIN_PADDING 0)
    endif()
    if(arg_PADDING_LENGTH)
        set(pad_string "")
        math(EXPR n "${arg_PADDING_LENGTH} - 1")
        foreach(i RANGE ${n})
            string(APPEND pad_string ".")
        endforeach()
    else()
        set(pad_string ".........................................")
    endif()
    string(LENGTH "${label}" label_len)
    string(LENGTH "${pad_string}" pad_len)
    math(EXPR pad_len "${pad_len}-${label_len}")
    if(pad_len LESS "0")
        set(pad_len ${arg_MIN_PADDING})
    endif()
    string(SUBSTRING "${pad_string}" 0 "${pad_len}" pad_string)
    set(output "${label} ${pad_string} ${value}")
    set("${out_var}" "${output}" PARENT_SCOPE)
endfunction()

function(qt_configure_add_summary_entry)
    qt_configure_record_command(ADD_SUMMARY_ENTRY ${ARGV})
endfunction()

function(qt_configure_process_add_summary_entry)
    qt_parse_all_arguments(arg "qt_configure_add_summary_entry"
        ""
        "ARGS;TYPE;MESSAGE" "CONDITION" ${ARGN})

    if(NOT arg_TYPE)
        set(arg_TYPE "feature")
    endif()

    if(NOT "${arg_CONDITION}" STREQUAL "")
        qt_evaluate_config_expression(condition_result ${arg_CONDITION})
        if(NOT condition_result)
            return()
        endif()
    endif()

    if(arg_TYPE STREQUAL "firstAvailableFeature")
        set(first_feature_found FALSE)
        set(message "")
        string(REPLACE " " ";" args_list "${arg_ARGS}")
        foreach(feature ${args_list})
            qt_feature_normalize_name("${feature}" feature)
            if(NOT DEFINED QT_FEATURE_${feature})
                message(FATAL_ERROR "Asking for a report on undefined feature ${feature}.")
            endif()
            if(QT_FEATURE_${feature})
                set(first_feature_found TRUE)
                set(message "${QT_FEATURE_LABEL_${feature}}")
                break()
            endif()
        endforeach()

        if(NOT first_feature_found)
            set(message "<none>")
        endif()
        qt_configure_add_report_padded("${arg_MESSAGE}" "${message}")
    elseif(arg_TYPE STREQUAL "featureList")
        set(available_features "")
        string(REPLACE " " ";" args_list "${arg_ARGS}")

        foreach(feature ${args_list})
            qt_feature_normalize_name("${feature}" feature)
            if(NOT DEFINED QT_FEATURE_${feature})
                message(FATAL_ERROR "Asking for a report on undefined feature ${feature}.")
            endif()
            if(QT_FEATURE_${feature})
                list(APPEND available_features "${QT_FEATURE_LABEL_${feature}}")
            endif()
        endforeach()

        if(NOT available_features)
            set(message "<none>")
        else()
            list(JOIN available_features " " message)
        endif()
        qt_configure_add_report_padded("${arg_MESSAGE}" "${message}")
    elseif(arg_TYPE STREQUAL "feature")
        qt_feature_normalize_name("${arg_ARGS}" feature)

        set(label "${QT_FEATURE_LABEL_${feature}}")

        if(NOT label)
            set(label "${feature}")
        endif()

        if(QT_FEATURE_${feature})
            set(value "yes")
        else()
            set(value "no")
        endif()

        qt_configure_add_report_padded("${label}" "${value}")
    endif()
endfunction()

function(qt_configure_add_summary_build_type_and_config)
    qt_configure_record_command(ADD_BUILD_TYPE_AND_CONFIG ${ARGV})
endfunction()

function(qt_configure_process_add_summary_build_type_and_config)
    get_property(subarch_summary GLOBAL PROPERTY qt_configure_subarch_summary)
    set(message
        "Building for: ${QT_QMAKE_TARGET_MKSPEC} (${TEST_architecture_arch}, CPU features: ${subarch_summary})")
    qt_configure_add_report("${message}")

    set(message "Compiler: ")
    if(CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang")
        string(APPEND message "clang (Apple)")
    elseif(CLANG)
        string(APPEND message "clang")
    elseif(ICC)
        string(APPEND message "intel_icc")
    elseif(QCC)
        string(APPEND message "rim_qcc")
    elseif(GCC)
        string(APPEND message "gcc")
    elseif(MSVC)
        string(APPEND message "msvc")
    elseif(CMAKE_CXX_COMPILER_ID STREQUAL "GHS")
        string(APPEND message "ghs")
    else()
        string(APPEND message "unknown (${CMAKE_CXX_COMPILER_ID})")
    endif()
    string(APPEND message " ${CMAKE_CXX_COMPILER_VERSION}")
    qt_configure_add_report("${message}")
endfunction()

function(qt_configure_add_summary_build_mode)
    qt_configure_record_command(ADD_BUILD_MODE ${ARGV})
endfunction()

function(qt_configure_process_add_summary_build_mode label)
    set(message "")
    if(DEFINED CMAKE_BUILD_TYPE)
        if(CMAKE_BUILD_TYPE STREQUAL "Debug")
            string(APPEND message "debug")
        elseif(CMAKE_BUILD_TYPE STREQUAL "Release")
            string(APPEND message "release")
        elseif(CMAKE_BUILD_TYPE STREQUAL "RelWithDebInfo")
            string(APPEND message "release (with debug info)")
        else()
            string(APPEND message "${CMAKE_BUILD_TYPE}")
        endif()
    elseif(DEFINED CMAKE_CONFIGURATION_TYPES)
        if("Release" IN_LIST CMAKE_CONFIGURATION_TYPES
                AND "Debug" IN_LIST CMAKE_CONFIGURATION_TYPES)
            string(APPEND message "debug and release")
        elseif("RelWithDebInfo" IN_LIST CMAKE_CONFIGURATION_TYPES
                AND "Debug" IN_LIST CMAKE_CONFIGURATION_TYPES)
            string(APPEND message "debug and release (with debug info)")
        else()
            string(APPEND message "${CMAKE_CONFIGURATION_TYPES}")
        endif()
    endif()

    qt_configure_add_report_padded("${label}" "${message}")
endfunction()

function(qt_configure_add_summary_build_parts)
    qt_configure_record_command(ADD_BUILD_PARTS ${ARGV})
endfunction()

function(qt_configure_process_add_summary_build_parts label)
    qt_get_build_parts(parts)
    string(REPLACE ";" " " message "${parts}")
    qt_configure_add_report_padded("${label}" "${message}")
endfunction()

function(qt_configure_add_summary_section)
    qt_configure_record_command(ADD_SUMMARY_SECTION ${ARGV})
endfunction()

function(qt_configure_process_add_summary_section)
    qt_parse_all_arguments(arg "qt_configure_add_summary_section"
        "" "NAME" "" ${ARGN})

    qt_configure_add_report("${__qt_configure_indent}${arg_NAME}:")
    if(NOT DEFINED __qt_configure_indent)
        set(__qt_configure_indent "  " PARENT_SCOPE)
    else()
        set(__qt_configure_indent "${__qt_configure_indent}  " PARENT_SCOPE)
    endif()
endfunction()

function(qt_configure_end_summary_section)
    qt_configure_record_command(END_SUMMARY_SECTION ${ARGV})
endfunction()

function(qt_configure_process_end_summary_section)
    string(LENGTH "${__qt_configure_indent}" indent_len)
    if(indent_len GREATER_EQUAL 2)
        string(SUBSTRING "${__qt_configure_indent}" 2 -1 __qt_configure_indent)
        set(__qt_configure_indent "${__qt_configure_indent}" PARENT_SCOPE)
    endif()
endfunction()

function(qt_configure_add_report_entry)
    qt_configure_record_command(ADD_REPORT_ENTRY ${ARGV})
endfunction()

function(qt_configure_process_add_report_entry)
    qt_parse_all_arguments(arg "qt_configure_add_report_entry"
        ""
        "TYPE;MESSAGE" "CONDITION" ${ARGN})

    set(possible_types NOTE WARNING ERROR FATAL_ERROR)
    if(NOT "${arg_TYPE}" IN_LIST possible_types)
        message(FATAL_ERROR "qt_configure_add_report_entry: '${arg_TYPE}' is not a valid type.")
    endif()

    if(NOT arg_MESSAGE)
        message(FATAL_ERROR "qt_configure_add_report_entry: Empty message given.")
    endif()

    if(arg_TYPE STREQUAL "NOTE")
        set(contents_var "__qt_configure_notes")
        set(prefix "Note: ")
    elseif(arg_TYPE STREQUAL "WARNING")
        set(contents_var "__qt_configure_warnings")
        set(prefix "WARNING: ")
    elseif(arg_TYPE STREQUAL "ERROR")
        set(contents_var "__qt_configure_errors")
        set(prefix "ERROR: ")
    elseif(arg_TYPE STREQUAL "FATAL_ERROR")
        set(contents_var "__qt_configure_errors")
        set(prefix "FATAL ERROR: ")
    endif()

    if(NOT "${arg_CONDITION}" STREQUAL "")
        qt_evaluate_config_expression(condition_result ${arg_CONDITION})
    endif()

    if("${arg_CONDITION}" STREQUAL "" OR condition_result)
        set(new_report "${prefix}${arg_MESSAGE}")
        string(APPEND "${contents_var}" "\n${new_report}")

        if(arg_TYPE STREQUAL "ERROR" OR arg_TYPE STREQUAL "FATAL_ERROR")
            set(__qt_configure_an_error_occurred "TRUE" PARENT_SCOPE)
        endif()
    endif()

    set("${contents_var}" "${${contents_var}}" PARENT_SCOPE)
endfunction()
