32b596b7b1
Introduce a new -no-prefix option that can be used to build Qt without having to install it. Currently, -no-prefix is already implied by -developer-build, but -developer-build also implies -warnings-are-errors and -feature-private-tests, which not everyone might want to use. Some Qt builders likely use -developer-build for the no-prefix behavior, hence we introduce a standalone -no-prefix option to offer a nicer user experience without -Werror and friends. Previously it was possible to achieve the same by specifying -prefix $PWD, but that relies on $PWD expanding property in the used shell. The new -no-prefix doesn't depend on the type of the shell and is shorter to type. Internally this gets passed by configure as -DINPUT_no_prefix=yes to CMake, and transformed into a -DQT_FEATURE_no_prefix=ON feature. The feature also gets automatically auto-detected to ON if developer-build is set, -prefix is either unset or $PWD. CMake code should still query QT_WILL_INSTALL to decide whether files need to be installed or not. As a drive-by, we now also export QT_FEATURE_developer_build to be available for querying during configuration of other repos (previously it was only possible to query FEATURE_developer_build). Pick-to: 6.2 6.3 Change-Id: Iaa6c8d8ae2b736282e9949d2a5d7f412e290a253 Reviewed-by: Alexey Edelev <alexey.edelev@qt.io> Reviewed-by: Kai Koehne <kai.koehne@qt.io>
967 lines
33 KiB
CMake
967 lines
33 KiB
CMake
# This script reads Qt configure arguments from config.opt,
|
|
# translates the arguments to CMake arguments and calls CMake.
|
|
#
|
|
# This file is to be used in CMake script mode with the following variables set:
|
|
# OPTFILE: A text file containing the options that were passed to configure
|
|
# with one option per line.
|
|
# MODULE_ROOT: The source directory of the module to be built.
|
|
# If empty, qtbase/top-level is assumed.
|
|
# TOP_LEVEL: TRUE, if this is a top-level build.
|
|
|
|
include(${CMAKE_CURRENT_LIST_DIR}/QtFeatureCommon.cmake)
|
|
include(${CMAKE_CURRENT_LIST_DIR}/QtBuildInformation.cmake)
|
|
|
|
cmake_policy(SET CMP0007 NEW)
|
|
cmake_policy(SET CMP0057 NEW)
|
|
|
|
set(cmake_args "")
|
|
macro(push)
|
|
list(APPEND cmake_args ${ARGN})
|
|
endmacro()
|
|
|
|
macro(pop_path_argument)
|
|
list(POP_FRONT configure_args path)
|
|
string(REGEX REPLACE "^\"(.*)\"$" "\\1" path "${path}")
|
|
file(TO_CMAKE_PATH "${path}" path)
|
|
endmacro()
|
|
|
|
function(is_non_empty_valid_arg arg value)
|
|
if(value STREQUAL "")
|
|
message(FATAL_ERROR "Value supplied to command line option '${arg}' is empty.")
|
|
elseif(value MATCHES "^-.*")
|
|
message(FATAL_ERROR
|
|
"Value supplied to command line option '${arg}' is invalid: ${value}")
|
|
endif()
|
|
endfunction()
|
|
|
|
function(warn_in_per_repo_build arg)
|
|
if(NOT TOP_LEVEL)
|
|
message(WARNING "Command line option ${arg} is only effective in top-level builds")
|
|
endif()
|
|
endfunction()
|
|
|
|
if("${MODULE_ROOT}" STREQUAL "")
|
|
# If MODULE_ROOT is not set, assume that we want to build qtbase or top-level.
|
|
get_filename_component(MODULE_ROOT ".." ABSOLUTE BASE_DIR "${CMAKE_CURRENT_LIST_DIR}")
|
|
set(qtbase_or_top_level_build TRUE)
|
|
else()
|
|
file(TO_CMAKE_PATH "${MODULE_ROOT}" MODULE_ROOT)
|
|
set(qtbase_or_top_level_build FALSE)
|
|
endif()
|
|
set(configure_filename "configure.cmake")
|
|
set(commandline_filename "qt_cmdline.cmake")
|
|
if(TOP_LEVEL)
|
|
get_filename_component(MODULE_ROOT "../.." ABSOLUTE BASE_DIR "${CMAKE_CURRENT_LIST_DIR}")
|
|
file(GLOB commandline_files "${MODULE_ROOT}/*/${commandline_filename}")
|
|
if(EXISTS "${MODULE_ROOT}/${commandline_filename}")
|
|
list(PREPEND commandline_files "${MODULE_ROOT}/${commandline_filename}")
|
|
endif()
|
|
else()
|
|
set(commandline_files "${MODULE_ROOT}/${commandline_filename}")
|
|
endif()
|
|
file(STRINGS "${OPTFILE}" configure_args)
|
|
|
|
# list(TRANSFORM ...) unexpectedly removes semicolon escaping in list items. So the list arguments
|
|
# seem to be broken. The 'bracket argument' suppresses this behavior. Right before forwarding
|
|
# command line arguments to the cmake call, 'bracket arguments' are replaced by escaped semicolons
|
|
# back.
|
|
list(TRANSFORM configure_args REPLACE ";" "[[;]]")
|
|
|
|
list(FILTER configure_args EXCLUDE REGEX "^[ \t]*$")
|
|
list(TRANSFORM configure_args STRIP)
|
|
list(TRANSFORM configure_args REPLACE "\\\\" "\\\\\\\\")
|
|
unset(generator)
|
|
set(auto_detect_compiler TRUE)
|
|
set(auto_detect_generator ${qtbase_or_top_level_build})
|
|
unset(device_options)
|
|
unset(options_json_file)
|
|
set_property(GLOBAL PROPERTY UNHANDLED_ARGS "")
|
|
while(NOT "${configure_args}" STREQUAL "")
|
|
list(POP_FRONT configure_args arg)
|
|
if(arg STREQUAL "-cmake-generator")
|
|
list(POP_FRONT configure_args generator)
|
|
elseif(arg STREQUAL "-cmake-use-default-generator")
|
|
set(auto_detect_generator FALSE)
|
|
elseif(arg STREQUAL "-no-guess-compiler")
|
|
set(auto_detect_compiler FALSE)
|
|
elseif(arg STREQUAL "-list-features")
|
|
set(list_features TRUE)
|
|
elseif(arg MATCHES "^-h(elp)?$")
|
|
set(display_module_help TRUE)
|
|
elseif(arg STREQUAL "-write-options-for-conan")
|
|
list(POP_FRONT configure_args options_json_file)
|
|
elseif(arg STREQUAL "-skip")
|
|
warn_in_per_repo_build("${arg}")
|
|
list(POP_FRONT configure_args qtrepos)
|
|
is_non_empty_valid_arg("${arg}" "${qtrepos}")
|
|
list(TRANSFORM qtrepos REPLACE "," ";")
|
|
foreach(qtrepo IN LISTS qtrepos)
|
|
push("-DBUILD_${qtrepo}=OFF")
|
|
endforeach()
|
|
elseif(arg STREQUAL "-submodules")
|
|
warn_in_per_repo_build("${arg}")
|
|
list(POP_FRONT configure_args submodules)
|
|
is_non_empty_valid_arg("${arg}" "${submodules}")
|
|
list(TRANSFORM submodules REPLACE "," "[[;]]")
|
|
push("-DQT_BUILD_SUBMODULES=${submodules}")
|
|
elseif(arg STREQUAL "-qt-host-path")
|
|
pop_path_argument()
|
|
push("-DQT_HOST_PATH=${path}")
|
|
elseif(arg STREQUAL "-hostdatadir")
|
|
pop_path_argument()
|
|
if(NOT path MATCHES "(^|/)mkspecs$")
|
|
string(APPEND path "/mkspecs")
|
|
endif()
|
|
push("-DINSTALL_MKSPECSDIR=${path}")
|
|
elseif(arg STREQUAL "-developer-build")
|
|
set(developer_build TRUE)
|
|
# Treat this argument as "unhandled" to process it further.
|
|
set_property(GLOBAL APPEND PROPERTY UNHANDLED_ARGS "${arg}")
|
|
elseif(arg STREQUAL "-cmake-file-api")
|
|
set(cmake_file_api TRUE)
|
|
elseif(arg STREQUAL "-no-cmake-file-api")
|
|
set(cmake_file_api FALSE)
|
|
elseif(arg STREQUAL "--")
|
|
# Everything after this argument will be passed to CMake verbatim.
|
|
list(APPEND cmake_args "${configure_args}")
|
|
break()
|
|
else()
|
|
set_property(GLOBAL APPEND PROPERTY UNHANDLED_ARGS "${arg}")
|
|
endif()
|
|
endwhile()
|
|
|
|
|
|
####################################################################################################
|
|
# Define functions/macros that are called in configure.cmake files
|
|
#
|
|
# Every function that's called in a configure.cmake file must be defined here.
|
|
# Most are empty stubs.
|
|
####################################################################################################
|
|
|
|
set_property(GLOBAL PROPERTY COMMANDLINE_KNOWN_FEATURES "")
|
|
|
|
function(qt_feature feature)
|
|
cmake_parse_arguments(arg "" "PURPOSE;SECTION;" "" ${ARGN})
|
|
set_property(GLOBAL APPEND PROPERTY COMMANDLINE_KNOWN_FEATURES "${feature}")
|
|
set_property(GLOBAL PROPERTY COMMANDLINE_FEATURE_PURPOSE_${feature} "${arg_PURPOSE}")
|
|
set_property(GLOBAL PROPERTY COMMANDLINE_FEATURE_SECTION_${feature} "${arg_SECTION}")
|
|
endfunction()
|
|
|
|
function(find_package)
|
|
message(FATAL_ERROR "find_package must not be used directly in configure.cmake. "
|
|
"Use qt_find_package or guard the call with an if(NOT QT_CONFIGURE_RUNNING) block.")
|
|
endfunction()
|
|
|
|
macro(defstub name)
|
|
function(${name})
|
|
endfunction()
|
|
endmacro()
|
|
|
|
defstub(qt_add_qmake_lib_dependency)
|
|
defstub(qt_config_compile_test)
|
|
defstub(qt_config_compile_test_machine_tuple)
|
|
defstub(qt_config_compile_test_x86simd)
|
|
defstub(qt_config_compiler_supports_flag_test)
|
|
defstub(qt_config_linker_supports_flag_test)
|
|
defstub(qt_configure_add_report_entry)
|
|
defstub(qt_configure_add_summary_build_mode)
|
|
defstub(qt_configure_add_summary_build_parts)
|
|
defstub(qt_configure_add_summary_build_type_and_config)
|
|
defstub(qt_configure_add_summary_entry)
|
|
defstub(qt_configure_add_summary_section)
|
|
defstub(qt_configure_end_summary_section)
|
|
defstub(qt_extra_definition)
|
|
defstub(qt_feature_config)
|
|
defstub(qt_feature_definition)
|
|
defstub(qt_find_package)
|
|
defstub(set_package_properties)
|
|
defstub(qt_qml_find_python)
|
|
defstub(qt_set01)
|
|
defstub(qt_internal_check_if_linker_is_available)
|
|
|
|
####################################################################################################
|
|
# Define functions/macros that are called in qt_cmdline.cmake files
|
|
####################################################################################################
|
|
|
|
unset(commandline_known_options)
|
|
unset(commandline_custom_handlers)
|
|
set(commandline_nr_of_prefixes 0)
|
|
|
|
macro(qt_commandline_subconfig subconfig)
|
|
list(APPEND commandline_subconfigs "${subconfig}")
|
|
endmacro()
|
|
|
|
macro(qt_commandline_custom handler)
|
|
list(APPEND commandline_custom_handlers ${handler})
|
|
endmacro()
|
|
|
|
function(qt_commandline_option name)
|
|
set(options)
|
|
set(oneValueArgs TYPE NAME VALUE)
|
|
set(multiValueArgs VALUES MAPPING)
|
|
cmake_parse_arguments(arg "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
|
|
|
|
set(commandline_known_options "${commandline_known_options};${name}" PARENT_SCOPE)
|
|
set(commandline_option_${name} "${arg_TYPE}" PARENT_SCOPE)
|
|
if(NOT "${arg_NAME}" STREQUAL "")
|
|
set(commandline_option_${name}_variable "${arg_NAME}" PARENT_SCOPE)
|
|
endif()
|
|
if(NOT "${arg_VALUE}" STREQUAL "")
|
|
set(commandline_option_${name}_value "${arg_VALUE}" PARENT_SCOPE)
|
|
endif()
|
|
if(arg_VALUES)
|
|
set(commandline_option_${name}_values ${arg_VALUES} PARENT_SCOPE)
|
|
elseif(arg_MAPPING)
|
|
set(commandline_option_${name}_mapping ${arg_MAPPING} PARENT_SCOPE)
|
|
endif()
|
|
endfunction()
|
|
|
|
function(qt_commandline_prefix arg var)
|
|
set(idx ${commandline_nr_of_prefixes})
|
|
set(commandline_prefix_${idx} "${arg}" "${var}" PARENT_SCOPE)
|
|
math(EXPR n "${commandline_nr_of_prefixes} + 1")
|
|
set(commandline_nr_of_prefixes ${n} PARENT_SCOPE)
|
|
endfunction()
|
|
|
|
# Check the following variable in configure.cmake files to guard code that is not covered by the
|
|
# stub functions above.
|
|
set(QT_CONFIGURE_RUNNING ON)
|
|
|
|
|
|
####################################################################################################
|
|
# Load qt_cmdline.cmake files
|
|
####################################################################################################
|
|
|
|
while(commandline_files)
|
|
list(POP_FRONT commandline_files commandline_file)
|
|
get_filename_component(commandline_file_directory "${commandline_file}" DIRECTORY)
|
|
set(configure_file "${commandline_file_directory}/${configure_filename}")
|
|
unset(commandline_subconfigs)
|
|
if(EXISTS "${configure_file}")
|
|
include("${configure_file}")
|
|
endif()
|
|
if(EXISTS "${commandline_file}")
|
|
include("${commandline_file}")
|
|
endif()
|
|
|
|
if(commandline_subconfigs)
|
|
list(TRANSFORM commandline_subconfigs PREPEND "${commandline_file_directory}/")
|
|
list(TRANSFORM commandline_subconfigs APPEND "/${commandline_filename}")
|
|
list(PREPEND commandline_files "${commandline_subconfigs}")
|
|
endif()
|
|
endwhile()
|
|
|
|
get_property(commandline_known_features GLOBAL PROPERTY COMMANDLINE_KNOWN_FEATURES)
|
|
|
|
####################################################################################################
|
|
# Process the data from the qt_cmdline.cmake files
|
|
####################################################################################################
|
|
|
|
function(qtConfAddNote)
|
|
message(${ARGV})
|
|
endfunction()
|
|
|
|
function(qtConfAddWarning)
|
|
message(WARNING ${ARGV})
|
|
endfunction()
|
|
|
|
function(qtConfAddError)
|
|
message(FATAL_ERROR ${ARGV})
|
|
endfunction()
|
|
|
|
set_property(GLOBAL PROPERTY CONFIG_INPUTS "")
|
|
|
|
function(qtConfCommandlineSetInput name val)
|
|
if(NOT "${commandline_option_${name}_variable}" STREQUAL "")
|
|
set(name "${commandline_option_${name}_variable}")
|
|
endif()
|
|
if(NOT "${INPUT_${name}}" STREQUAL "")
|
|
set(oldval "${INPUT_${name}}")
|
|
if("${oldval}" STREQUAL "${val}")
|
|
qtConfAddNote("Option '${name}' with value '${val}' was specified twice")
|
|
else()
|
|
qtConfAddNote("Overriding option '${name}' with '${val}' (was: '${oldval}')")
|
|
endif()
|
|
endif()
|
|
|
|
set_property(GLOBAL PROPERTY INPUT_${name} "${val}")
|
|
set_property(GLOBAL APPEND PROPERTY CONFIG_INPUTS ${name})
|
|
endfunction()
|
|
|
|
function(qtConfCommandlineAppendInput name val)
|
|
get_property(oldval GLOBAL PROPERTY INPUT_${name})
|
|
if(NOT "${oldval}" STREQUAL "")
|
|
string(PREPEND val "${oldval};")
|
|
endif()
|
|
qtConfCommandlineSetInput(${name} "${val}")
|
|
endfunction()
|
|
|
|
function(qtConfValidateValue opt val out_var)
|
|
set(${out_var} TRUE PARENT_SCOPE)
|
|
|
|
set(valid_values ${commandline_option_${arg}_values})
|
|
list(LENGTH valid_values n)
|
|
if(n EQUAL 0)
|
|
return()
|
|
endif()
|
|
|
|
foreach(v ${valid_values})
|
|
if(val STREQUAL v)
|
|
return()
|
|
endif()
|
|
endforeach()
|
|
|
|
set(${out_var} FALSE PARENT_SCOPE)
|
|
qtConfAddError("Invalid value '${val}' supplied to command line option '${opt}'.")
|
|
endfunction()
|
|
|
|
function(qt_commandline_mapped_enum_value opt key out_var)
|
|
unset(result)
|
|
set(mapping ${commandline_option_${opt}_mapping})
|
|
while(mapping)
|
|
list(POP_FRONT mapping mapping_key)
|
|
list(POP_FRONT mapping mapping_value)
|
|
if(mapping_key STREQUAL key)
|
|
set(result "${mapping_value}")
|
|
break()
|
|
endif()
|
|
endwhile()
|
|
set(${out_var} "${result}" PARENT_SCOPE)
|
|
endfunction()
|
|
|
|
function(qtConfHasNextCommandlineArg out_var)
|
|
get_property(args GLOBAL PROPERTY UNHANDLED_ARGS)
|
|
list(LENGTH args n)
|
|
if(n GREATER 0)
|
|
set(result TRUE)
|
|
else()
|
|
set(result FALSE)
|
|
endif()
|
|
set(${out_var} ${result} PARENT_SCOPE)
|
|
endfunction()
|
|
|
|
function(qtConfPeekNextCommandlineArg out_var)
|
|
get_property(args GLOBAL PROPERTY UNHANDLED_ARGS)
|
|
list(GET args 0 result)
|
|
set(${out_var} ${result} PARENT_SCOPE)
|
|
endfunction()
|
|
|
|
function(qtConfGetNextCommandlineArg out_var)
|
|
get_property(args GLOBAL PROPERTY UNHANDLED_ARGS)
|
|
list(POP_FRONT args result)
|
|
set_property(GLOBAL PROPERTY UNHANDLED_ARGS ${args})
|
|
set(${out_var} ${result} PARENT_SCOPE)
|
|
endfunction()
|
|
|
|
function(qt_commandline_boolean arg val nextok)
|
|
if("${val}" STREQUAL "")
|
|
set(val "yes")
|
|
endif()
|
|
if(NOT val STREQUAL "yes" AND NOT val STREQUAL "no")
|
|
message(FATAL_ERROR "Invalid value '${val}' given for boolean command line option '${arg}'.")
|
|
endif()
|
|
qtConfCommandlineSetInput("${arg}" "${val}")
|
|
endfunction()
|
|
|
|
function(qt_commandline_string arg val nextok)
|
|
if(nextok)
|
|
qtConfGetNextCommandlineArg(val)
|
|
if("${val}" MATCHES "^-")
|
|
qtConfAddError("No value supplied to command line options '${opt}'.")
|
|
endif()
|
|
endif()
|
|
qtConfValidateValue("${opt}" "${val}" success)
|
|
if(success)
|
|
qtConfCommandlineSetInput("${opt}" "${val}")
|
|
endif()
|
|
endfunction()
|
|
|
|
function(qt_commandline_optionalString arg val nextok)
|
|
if("${val}" STREQUAL "")
|
|
if(nextok)
|
|
qtConfPeekNextCommandlineArg(val)
|
|
endif()
|
|
if(val MATCHES "^-.*|[A-Z0-9_+]=.*" OR val STREQUAL "")
|
|
set(val "yes")
|
|
else()
|
|
qtConfGetNextCommandlineArg(val)
|
|
endif()
|
|
endif()
|
|
qtConfValidateValue("${arg}" "${val}" success)
|
|
if(success)
|
|
qtConfCommandlineSetInput("${arg}" "${val}")
|
|
endif()
|
|
endfunction()
|
|
|
|
function(qt_commandline_addString arg val nextok)
|
|
if("${val}" STREQUAL "" AND nextok)
|
|
qtConfGetNextCommandlineArg(val)
|
|
endif()
|
|
if(val MATCHES "^-.*" OR val STREQUAL "")
|
|
qtConfAddError("No value supplied to command line option '${arg}'.")
|
|
endif()
|
|
qtConfValidateValue("${arg}" "${val}" success)
|
|
if(success)
|
|
if(DEFINED command_line_option_${arg}_variable)
|
|
set(arg ${command_line_option_${arg}_variable})
|
|
endif()
|
|
set_property(GLOBAL APPEND PROPERTY "INPUT_${arg}" "${val}")
|
|
set_property(GLOBAL APPEND PROPERTY CONFIG_INPUTS ${arg})
|
|
endif()
|
|
endfunction()
|
|
|
|
function(qt_commandline_enum arg val nextok)
|
|
if("${val}" STREQUAL "")
|
|
set(val "yes")
|
|
endif()
|
|
unset(mapped)
|
|
if(DEFINED "commandline_option_${arg}_mapping")
|
|
qt_commandline_mapped_enum_value("${arg}" "${val}" mapped)
|
|
elseif(DEFINED "commandline_option_${arg}_values")
|
|
if(val IN_LIST commandline_option_${arg}_values)
|
|
set(mapped ${val})
|
|
endif()
|
|
endif()
|
|
if("${mapped}" STREQUAL "")
|
|
qtConfAddError("Invalid value '${val}' supplied to command line option '${arg}'.")
|
|
endif()
|
|
qtConfCommandlineSetInput("${arg}" "${mapped}")
|
|
endfunction()
|
|
|
|
function(qt_commandline_void arg val nextok)
|
|
if(NOT "${val}" STREQUAL "")
|
|
qtConfAddError("Command line option '${arg}' expects no argument ('${val}' given).")
|
|
endif()
|
|
if(DEFINED commandline_option_${arg}_value)
|
|
set(val ${commandline_option_${arg}_value})
|
|
endif()
|
|
if("${val}" STREQUAL "")
|
|
set(val yes)
|
|
endif()
|
|
qtConfCommandlineSetInput("${arg}" "${val}")
|
|
endfunction()
|
|
|
|
function(qt_call_function func)
|
|
set(call_code "${func}(")
|
|
math(EXPR n "${ARGC} - 1")
|
|
foreach(i RANGE 1 ${n})
|
|
string(APPEND call_code "\"${ARGV${i}}\" ")
|
|
endforeach()
|
|
string(APPEND call_code ")")
|
|
string(REPLACE "\\" "\\\\" call_code "${call_code}")
|
|
if(${CMAKE_VERSION} VERSION_LESS "3.18.0")
|
|
set(incfile qt_tmp_func_call.cmake)
|
|
file(WRITE "${incfile}" "${call_code}")
|
|
include(${incfile})
|
|
file(REMOVE "${incfile}")
|
|
else()
|
|
cmake_language(EVAL CODE "${call_code}")
|
|
endif()
|
|
endfunction()
|
|
|
|
if(display_module_help)
|
|
message([[
|
|
Options:
|
|
-help, -h ............ Display this help screen
|
|
|
|
-feature-<feature> ... Enable <feature>
|
|
-no-feature-<feature> Disable <feature> [none]
|
|
-list-features ....... List available features. Note that some features
|
|
have dedicated command line options as well.
|
|
]])
|
|
|
|
set(help_file "${MODULE_ROOT}/config_help.txt")
|
|
if(EXISTS "${help_file}")
|
|
file(READ "${help_file}" content)
|
|
message("${content}")
|
|
endif()
|
|
|
|
return()
|
|
endif()
|
|
|
|
if(list_features)
|
|
unset(lines)
|
|
foreach(feature ${commandline_known_features})
|
|
get_property(section GLOBAL PROPERTY COMMANDLINE_FEATURE_SECTION_${feature})
|
|
get_property(purpose GLOBAL PROPERTY COMMANDLINE_FEATURE_PURPOSE_${feature})
|
|
if(purpose)
|
|
if(NOT "${section}" STREQUAL "")
|
|
string(APPEND section ": ")
|
|
endif()
|
|
qt_configure_get_padded_string("${feature}" "${section}${purpose}" line
|
|
PADDING_LENGTH 25 MIN_PADDING 1)
|
|
list(APPEND lines "${line}")
|
|
endif()
|
|
endforeach()
|
|
list(SORT lines)
|
|
list(JOIN lines "\n" lines)
|
|
message("${lines}")
|
|
return()
|
|
endif()
|
|
|
|
function(write_options_json_file)
|
|
if(qtbase_or_top_level_build)
|
|
# Add options that are handled directly by this script.
|
|
qt_commandline_option(qt-host-path TYPE string)
|
|
qt_commandline_option(no-guess-compiler TYPE void)
|
|
endif()
|
|
|
|
set(indent " ")
|
|
set(content
|
|
"{"
|
|
"${indent}\"options\": {")
|
|
string(APPEND indent " ")
|
|
list(LENGTH commandline_known_options commandline_known_options_length)
|
|
set(i 1)
|
|
foreach(opt ${commandline_known_options})
|
|
list(APPEND content "${indent}\"${opt}\": {")
|
|
string(APPEND indent " ")
|
|
list(APPEND content "${indent}\"type\": \"${commandline_option_${opt}}\",")
|
|
if(NOT "${commandline_option_${opt}_values}" STREQUAL "")
|
|
set(values "${commandline_option_${opt}_values}")
|
|
list(TRANSFORM values PREPEND "\"")
|
|
list(TRANSFORM values APPEND "\"")
|
|
list(JOIN values ", " values)
|
|
list(APPEND content "${indent}\"values\": [${values}]")
|
|
elseif(NOT "${commandline_option_${opt}_mapping}" STREQUAL "")
|
|
list(LENGTH commandline_option_${opt}_mapping last)
|
|
math(EXPR last "${last} - 1")
|
|
set(values "")
|
|
list(APPEND content "${indent}\"values\": [")
|
|
foreach(k RANGE 0 "${last}" 2)
|
|
list(GET commandline_option_${opt}_mapping ${k} value)
|
|
list(APPEND values ${value})
|
|
endforeach()
|
|
list(TRANSFORM values PREPEND "\"")
|
|
list(TRANSFORM values APPEND "\"")
|
|
list(JOIN values ", " values)
|
|
list(APPEND content
|
|
"${indent} ${values}"
|
|
"${indent}]")
|
|
else()
|
|
list(APPEND content "${indent}\"values\": []")
|
|
endif()
|
|
string(SUBSTRING "${indent}" 4 -1 indent)
|
|
math(EXPR i "${i} + 1")
|
|
if(i LESS commandline_known_options_length)
|
|
list(APPEND content "${indent}},")
|
|
else()
|
|
list(APPEND content "${indent}}")
|
|
endif()
|
|
endforeach()
|
|
string(SUBSTRING "${indent}" 4 -1 indent)
|
|
|
|
set(features ${commandline_known_features})
|
|
list(TRANSFORM features PREPEND "\"")
|
|
list(TRANSFORM features APPEND "\"")
|
|
list(JOIN features ", " features)
|
|
|
|
list(APPEND content
|
|
"${indent}},"
|
|
"${indent}\"features\": [${features}]"
|
|
"}")
|
|
string(REPLACE ";" "\n" content "${content}")
|
|
file(WRITE "${options_json_file}" "${content}")
|
|
endfunction()
|
|
|
|
if(options_json_file)
|
|
write_options_json_file()
|
|
return()
|
|
endif()
|
|
|
|
set(cmake_var_assignments)
|
|
|
|
while(1)
|
|
qtConfHasNextCommandlineArg(has_next)
|
|
if(NOT has_next)
|
|
break()
|
|
endif()
|
|
qtConfGetNextCommandlineArg(arg)
|
|
|
|
set(handled FALSE)
|
|
foreach(func ${commandline_custom_handlers})
|
|
qt_call_function("qt_commandline_${func}" handled "${arg}")
|
|
if(handled)
|
|
break()
|
|
endif()
|
|
endforeach()
|
|
if(handled)
|
|
continue()
|
|
endif()
|
|
|
|
# Handle variable assignments
|
|
if(arg MATCHES "^([a-zA-Z0-9_][a-zA-Z0-9_-]*)=(.*)")
|
|
list(APPEND cmake_var_assignments "${arg}")
|
|
continue()
|
|
endif()
|
|
|
|
# parse out opt and val
|
|
set(nextok FALSE)
|
|
if(arg MATCHES "^--?enable-(.*)")
|
|
set(opt "${CMAKE_MATCH_1}")
|
|
set(val "yes")
|
|
# Handle -no-prefix so it's not interpreted as the negation of -prefix
|
|
elseif(arg MATCHES "-(no-prefix)")
|
|
set(opt "${CMAKE_MATCH_1}")
|
|
set(val "")
|
|
elseif(arg MATCHES "^--?(disable|no)-(.*)")
|
|
set(opt "${CMAKE_MATCH_2}")
|
|
set(val "no")
|
|
elseif(arg MATCHES "^--([^=]+)=(.*)")
|
|
set(opt "${CMAKE_MATCH_1}")
|
|
set(val "${CMAKE_MATCH_2}")
|
|
elseif(arg MATCHES "^--(.*)")
|
|
set(opt "${CMAKE_MATCH_1}")
|
|
unset(val)
|
|
elseif(arg MATCHES "^-(.*)")
|
|
set(nextok TRUE)
|
|
set(opt "${CMAKE_MATCH_1}")
|
|
unset(val)
|
|
if(NOT DEFINED commandline_option_${opt} AND opt MATCHES "(qt|system)-(.*)")
|
|
set(opt "${CMAKE_MATCH_2}")
|
|
set(val "${CMAKE_MATCH_1}")
|
|
message("opt: ${opt} val: ${val}")
|
|
endif()
|
|
else()
|
|
qtConfAddError("Invalid command line parameter '${arg}'.")
|
|
endif()
|
|
|
|
set(type ${commandline_option_${opt}})
|
|
if("${type}" STREQUAL "")
|
|
# No match in the regular options, try matching the prefixes
|
|
math(EXPR n "${commandline_nr_of_prefixes} - 1")
|
|
foreach(i RANGE ${n})
|
|
list(GET commandline_prefix_${i} 0 pfx)
|
|
if(arg MATCHES "^-${pfx}(.*)")
|
|
list(GET commandline_prefix_${i} 1 opt)
|
|
set(val "${CMAKE_MATCH_1}")
|
|
set(type addString)
|
|
break()
|
|
endif()
|
|
endforeach()
|
|
endif()
|
|
|
|
# Handle builtin [-no]-feature-xxx
|
|
if("${type}" STREQUAL "" AND opt MATCHES "^feature-(.*)")
|
|
set(opt "${CMAKE_MATCH_1}")
|
|
if(NOT opt IN_LIST commandline_known_features)
|
|
qtConfAddError("Enabling/Disabling unknown feature '${opt}'.")
|
|
endif()
|
|
set(type boolean)
|
|
endif()
|
|
|
|
if("${type}" STREQUAL "")
|
|
qtConfAddError("Unknown command line option '${arg}'.")
|
|
endif()
|
|
|
|
if(NOT COMMAND "qt_commandline_${type}")
|
|
qtConfAddError("Unknown type '${type}' for command line option '${opt}'.")
|
|
endif()
|
|
qt_call_function("qt_commandline_${type}" "${opt}" "${val}" "${nextok}")
|
|
endwhile()
|
|
|
|
####################################################################################################
|
|
# Translate some of the INPUT_xxx values to CMake arguments
|
|
####################################################################################################
|
|
|
|
# Turn the global properties into proper variables
|
|
get_property(config_inputs GLOBAL PROPERTY CONFIG_INPUTS)
|
|
list(REMOVE_DUPLICATES config_inputs)
|
|
foreach(var ${config_inputs})
|
|
get_property(INPUT_${var} GLOBAL PROPERTY INPUT_${var})
|
|
endforeach()
|
|
|
|
macro(drop_input name)
|
|
list(REMOVE_ITEM config_inputs ${name})
|
|
endmacro()
|
|
|
|
macro(translate_boolean_input name cmake_var)
|
|
if("${INPUT_${name}}" STREQUAL "yes")
|
|
push("-D${cmake_var}=ON")
|
|
drop_input(${name})
|
|
elseif("${INPUT_${name}}" STREQUAL "no")
|
|
push("-D${cmake_var}=OFF")
|
|
drop_input(${name})
|
|
endif()
|
|
endmacro()
|
|
|
|
macro(translate_string_input name cmake_var)
|
|
if(DEFINED INPUT_${name})
|
|
push("-D${cmake_var}=${INPUT_${name}}")
|
|
drop_input(${name})
|
|
endif()
|
|
endmacro()
|
|
|
|
macro(translate_path_input name cmake_var)
|
|
if(DEFINED INPUT_${name})
|
|
set(path "${INPUT_${name}}")
|
|
string(REGEX REPLACE "^\"(.*)\"$" "\\1" path "${path}")
|
|
file(TO_CMAKE_PATH "${path}" path)
|
|
push("-D${cmake_var}=${path}")
|
|
drop_input(${name})
|
|
endif()
|
|
endmacro()
|
|
|
|
macro(translate_list_input name cmake_var)
|
|
if(DEFINED INPUT_${name})
|
|
list(JOIN INPUT_${name} "[[;]]" value)
|
|
list(APPEND cmake_args "-D${cmake_var}=${value}")
|
|
drop_input(${name})
|
|
endif()
|
|
endmacro()
|
|
|
|
# Check whether to guess the compiler for the given language.
|
|
#
|
|
# Sets ${out_var} to FALSE if one of the following holds:
|
|
# - the environment variable ${env_var} is non-empty
|
|
# - the CMake variable ${cmake_var} is set on the command line
|
|
#
|
|
# Otherwise, ${out_var} is set to TRUE.
|
|
function(check_whether_to_guess_compiler out_var env_var cmake_var)
|
|
set(result TRUE)
|
|
if(NOT "$ENV{${env_var}}" STREQUAL "")
|
|
set(result FALSE)
|
|
else()
|
|
set(filtered_args ${cmake_args})
|
|
list(FILTER filtered_args INCLUDE REGEX "^(-D)?${cmake_var}=")
|
|
if(NOT "${filtered_args}" STREQUAL "")
|
|
set(result FALSE)
|
|
endif()
|
|
endif()
|
|
set(${out_var} ${result} PARENT_SCOPE)
|
|
endfunction()
|
|
|
|
# Try to guess the mkspec from the -platform configure argument.
|
|
function(guess_compiler_from_mkspec)
|
|
if(NOT auto_detect_compiler)
|
|
return()
|
|
endif()
|
|
|
|
check_whether_to_guess_compiler(guess_c_compiler CC CMAKE_C_COMPILER)
|
|
check_whether_to_guess_compiler(guess_cxx_compiler CXX CMAKE_CXX_COMPILER)
|
|
if(NOT guess_c_compiler AND NOT guess_cxx_compiler)
|
|
return()
|
|
endif()
|
|
|
|
string(REGEX MATCH "(^|;)-DQT_QMAKE_TARGET_MKSPEC=\([^;]+\)" m "${cmake_args}")
|
|
set(mkspec ${CMAKE_MATCH_2})
|
|
set(c_compiler "")
|
|
set(cxx_compiler "")
|
|
if(mkspec MATCHES "-clang-msvc$")
|
|
set(c_compiler "clang-cl")
|
|
set(cxx_compiler "clang-cl")
|
|
elseif(mkspec MATCHES "-clang(-|$)" AND NOT mkspec MATCHES "android")
|
|
set(c_compiler "clang")
|
|
set(cxx_compiler "clang++")
|
|
elseif(mkspec MATCHES "-msvc(-|$)")
|
|
set(c_compiler "cl")
|
|
set(cxx_compiler "cl")
|
|
endif()
|
|
if(guess_c_compiler AND NOT c_compiler STREQUAL "")
|
|
push("-DCMAKE_C_COMPILER=${c_compiler}")
|
|
endif()
|
|
if(guess_cxx_compiler AND NOT cxx_compiler STREQUAL "")
|
|
push("-DCMAKE_CXX_COMPILER=${cxx_compiler}")
|
|
endif()
|
|
if(mkspec MATCHES "-libc\\+\\+$")
|
|
push("-DINPUT_stdlib_libcpp=ON")
|
|
endif()
|
|
set(cmake_args "${cmake_args}" PARENT_SCOPE)
|
|
endfunction()
|
|
|
|
function(check_qt_build_parts type)
|
|
set(input "INPUT_${type}")
|
|
set(buildFlag "TRUE")
|
|
if("${type}" STREQUAL "nomake")
|
|
set(buildFlag "FALSE")
|
|
endif()
|
|
|
|
list(APPEND knownParts "tests" "examples" "benchmarks" "manual-tests" "minimal-static-tests")
|
|
|
|
foreach(part ${${input}})
|
|
if(part IN_LIST knownParts)
|
|
qt_feature_normalize_name("${part}" partUpperCase)
|
|
string(TOUPPER "${partUpperCase}" partUpperCase)
|
|
push("-DQT_BUILD_${partUpperCase}=${buildFlag}")
|
|
continue()
|
|
elseif("${part}" STREQUAL "tools" AND "${type}" STREQUAL "make")
|
|
# default true ignored
|
|
continue()
|
|
endif()
|
|
qtConfAddWarning("'-${type} ${part}' is not implemented yet.")
|
|
endforeach()
|
|
set(cmake_args "${cmake_args}" PARENT_SCOPE)
|
|
endfunction()
|
|
|
|
drop_input(commercial)
|
|
drop_input(confirm-license)
|
|
translate_boolean_input(precompile_header BUILD_WITH_PCH)
|
|
translate_boolean_input(ccache QT_USE_CCACHE)
|
|
translate_boolean_input(shared BUILD_SHARED_LIBS)
|
|
translate_boolean_input(warnings_are_errors WARNINGS_ARE_ERRORS)
|
|
translate_string_input(qt_namespace QT_NAMESPACE)
|
|
translate_string_input(qt_libinfix QT_LIBINFIX)
|
|
translate_string_input(qreal QT_COORD_TYPE)
|
|
translate_path_input(prefix CMAKE_INSTALL_PREFIX)
|
|
translate_path_input(extprefix CMAKE_STAGING_PREFIX)
|
|
foreach(kind bin lib archdata libexec qml data doc sysconf examples tests)
|
|
string(TOUPPER ${kind} uc_kind)
|
|
translate_path_input(${kind}dir INSTALL_${uc_kind}DIR)
|
|
endforeach()
|
|
translate_path_input(headerdir INSTALL_INCLUDEDIR)
|
|
translate_path_input(plugindir INSTALL_PLUGINSDIR)
|
|
translate_path_input(translationdir INSTALL_TRANSLATIONSDIR)
|
|
|
|
if(NOT "${INPUT_device}" STREQUAL "")
|
|
push("-DQT_QMAKE_TARGET_MKSPEC=devices/${INPUT_device}")
|
|
drop_input(device)
|
|
endif()
|
|
translate_string_input(platform QT_QMAKE_TARGET_MKSPEC)
|
|
translate_string_input(xplatform QT_QMAKE_TARGET_MKSPEC)
|
|
guess_compiler_from_mkspec()
|
|
translate_string_input(qpa_default_platform QT_QPA_DEFAULT_PLATFORM)
|
|
|
|
translate_path_input(android-sdk ANDROID_SDK_ROOT)
|
|
translate_path_input(android-ndk ANDROID_NDK_ROOT)
|
|
if(DEFINED INPUT_android-ndk-platform)
|
|
drop_input(android-ndk-platform)
|
|
string(REGEX REPLACE "^android-" "" INPUT_android-ndk-platform "${INPUT_android-ndk-platform}")
|
|
push("-DANDROID_NATIVE_API_LEVEL=${INPUT_android-ndk-platform}")
|
|
endif()
|
|
if(DEFINED INPUT_android-abis)
|
|
if(INPUT_android-abis MATCHES ",")
|
|
qtConfAddError("The -android-abis option cannot handle more than one ABI "
|
|
"when building with CMake.")
|
|
endif()
|
|
translate_string_input(android-abis ANDROID_ABI)
|
|
endif()
|
|
translate_string_input(android-javac-source QT_ANDROID_JAVAC_SOURCE)
|
|
translate_string_input(android-javac-target QT_ANDROID_JAVAC_TARGET)
|
|
|
|
# FIXME: config_help.txt says -sdk should apply to macOS as well.
|
|
translate_string_input(sdk QT_UIKIT_SDK)
|
|
if(DEFINED INPUT_sdk OR (DEFINED INPUT_xplatform AND INPUT_xplatform STREQUAL "macx-ios-clang")
|
|
OR (DEFINED INPUT_platform AND INPUT_platform STREQUAL "macx-ios-clang"))
|
|
push("-DCMAKE_SYSTEM_NAME=iOS")
|
|
endif()
|
|
|
|
drop_input(make)
|
|
drop_input(nomake)
|
|
|
|
check_qt_build_parts(nomake)
|
|
check_qt_build_parts(make)
|
|
|
|
drop_input(debug)
|
|
drop_input(release)
|
|
drop_input(debug_and_release)
|
|
drop_input(force_debug_info)
|
|
unset(build_configs)
|
|
if(INPUT_debug)
|
|
set(build_configs Debug)
|
|
elseif("${INPUT_debug}" STREQUAL "no")
|
|
set(build_configs Release)
|
|
elseif(INPUT_debug_and_release)
|
|
set(build_configs Release Debug)
|
|
endif()
|
|
if(INPUT_force_debug_info)
|
|
list(TRANSFORM build_configs REPLACE "^Release$" "RelWithDebInfo")
|
|
endif()
|
|
|
|
list(LENGTH build_configs nr_of_build_configs)
|
|
if(nr_of_build_configs EQUAL 1)
|
|
push("-DCMAKE_BUILD_TYPE=${build_configs}")
|
|
elseif(nr_of_build_configs GREATER 1)
|
|
set(multi_config ON)
|
|
string(REPLACE ";" "[[;]]" escaped_build_configs "${build_configs}")
|
|
# We must not use the push macro here to avoid variable expansion.
|
|
# That would destroy our escaping.
|
|
list(APPEND cmake_args "-DCMAKE_CONFIGURATION_TYPES=${escaped_build_configs}")
|
|
endif()
|
|
|
|
drop_input(ltcg)
|
|
if("${INPUT_ltcg}" STREQUAL "yes")
|
|
foreach(config ${build_configs})
|
|
string(TOUPPER "${config}" ucconfig)
|
|
if(NOT ucconfig STREQUAL "DEBUG")
|
|
push("-DCMAKE_INTERPROCEDURAL_OPTIMIZATION_${ucconfig}=ON")
|
|
endif()
|
|
endforeach()
|
|
endif()
|
|
|
|
translate_list_input(device-option QT_QMAKE_DEVICE_OPTIONS)
|
|
translate_list_input(defines QT_EXTRA_DEFINES)
|
|
translate_list_input(fpaths QT_EXTRA_FRAMEWORKPATHS)
|
|
translate_list_input(includes QT_EXTRA_INCLUDEPATHS)
|
|
translate_list_input(lpaths QT_EXTRA_LIBDIRS)
|
|
translate_list_input(rpaths QT_EXTRA_RPATHS)
|
|
|
|
if(cmake_file_api OR (developer_build AND NOT DEFINED cmake_file_api))
|
|
foreach(file cache-v2 cmakeFiles-v1 codemodel-v2 toolchains-v1)
|
|
file(WRITE "${CMAKE_BINARY_DIR}/.cmake/api/v1/query/${file}" "")
|
|
endforeach()
|
|
endif()
|
|
|
|
foreach(input ${config_inputs})
|
|
qt_feature_normalize_name("${input}" cmake_input)
|
|
push("-DINPUT_${cmake_input}=${INPUT_${input}}")
|
|
endforeach()
|
|
|
|
if(DEFINED INPUT_no-prefix AND DEFINED INPUT_prefix)
|
|
qtConfAddError("Can't specify both -prefix and -no-prefix options at the same time.")
|
|
endif()
|
|
|
|
if(NOT generator AND auto_detect_generator)
|
|
find_program(ninja ninja)
|
|
if(ninja)
|
|
set(generator Ninja)
|
|
if(multi_config)
|
|
string(APPEND generator " Multi-Config")
|
|
endif()
|
|
else()
|
|
if(CMAKE_HOST_UNIX)
|
|
set(generator "Unix Makefiles")
|
|
elseif(CMAKE_HOST_WIN32)
|
|
find_program(msvc_compiler cl.exe)
|
|
if(msvc_compiler)
|
|
set(generator "NMake Makefiles")
|
|
find_program(jom jom)
|
|
if(jom)
|
|
string(APPEND generator " JOM")
|
|
endif()
|
|
else()
|
|
set(generator "MinGW Makefiles")
|
|
endif()
|
|
endif()
|
|
endif()
|
|
endif()
|
|
|
|
if(multi_config
|
|
AND NOT "${generator}" STREQUAL "Xcode"
|
|
AND NOT "${generator}" STREQUAL "Ninja Multi-Config"
|
|
AND NOT "${generator}" MATCHES "^Visual Studio")
|
|
message(FATAL_ERROR "Multi-config build is only supported by Xcode, Ninja Multi-Config and \
|
|
Visual Studio generators. Current generator is \"${generator}\".
|
|
Note: Use '-cmake-generator <generator name>' option to specify the generator manually.")
|
|
endif()
|
|
|
|
if(generator)
|
|
push(-G "${generator}")
|
|
endif()
|
|
|
|
# Add CMake variable assignments near the end to allow users to overwrite what configure sets.
|
|
foreach(arg IN LISTS cmake_var_assignments)
|
|
push("-D${arg}")
|
|
endforeach()
|
|
|
|
push("${MODULE_ROOT}")
|
|
|
|
# Restore the escaped semicolons in arguments that are lists
|
|
list(TRANSFORM cmake_args REPLACE "\\[\\[;\\]\\]" "\\\\;")
|
|
|
|
execute_process(COMMAND "${CMAKE_COMMAND}" ${cmake_args}
|
|
COMMAND_ECHO STDOUT
|
|
RESULT_VARIABLE exit_code)
|
|
if(NOT exit_code EQUAL 0)
|
|
message(FATAL_ERROR "CMake exited with code ${exit_code}.")
|
|
endif()
|