diff options
Diffstat (limited to 'cmake/QtIRCommandLineHelpers.cmake')
-rw-r--r-- | cmake/QtIRCommandLineHelpers.cmake | 405 |
1 files changed, 405 insertions, 0 deletions
diff --git a/cmake/QtIRCommandLineHelpers.cmake b/cmake/QtIRCommandLineHelpers.cmake new file mode 100644 index 00000000..65c5d6aa --- /dev/null +++ b/cmake/QtIRCommandLineHelpers.cmake @@ -0,0 +1,405 @@ +# Copyright (C) 2024 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause + +# This file contains a modified subset of the qtbase/QtProcessConfigureArgs.cmake commands +# with renamed functions, because we need similar logic for init-repository, but +# we can't access qtbase before we clone it. + +# Call a function with the given arguments. +function(qt_ir_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() + +# Show an error. +function(qt_ir_add_error) + message(FATAL_ERROR ${ARGV}) +endfunction() + +# Check if there are still unhandled command line arguments. +function(qt_ir_args_has_next_command_line_arg out_var) + qt_ir_get_unhandled_args(args) + + list(LENGTH args n) + if(n GREATER 0) + set(result TRUE) + else() + set(result FALSE) + endif() + set(${out_var} ${result} PARENT_SCOPE) +endfunction() + +# Get the next unhandled command line argument without popping it. +function(qt_ir_args_peek_next_command_line_arg out_var) + qt_ir_get_unhandled_args(args) + list(GET args 0 result) + set(${out_var} ${result} PARENT_SCOPE) +endfunction() + +# Get the next unhandled command line argument. +function(qt_ir_args_get_next_command_line_arg out_var) + qt_ir_get_unhandled_args(args) + list(POP_FRONT args result) + qt_ir_set_unhandled_args("${args}") + set(${out_var} ${result} PARENT_SCOPE) +endfunction() + +# Helper macro to parse the arguments for the command line options. +macro(qt_ir_commandline_option_parse_arguments) + set(options UNSUPPORTED) + set(oneValueArgs TYPE NAME SHORT_NAME ALIAS VALUE DEFAULT_VALUE) + set(multiValueArgs VALUES MAPPING) + cmake_parse_arguments(arg "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) +endmacro() + +# We use this to define the command line options that init-repository accepts. +# Arguments +# name - name of the long form option +# e.g. 'module-subset' will parse '--module-subset' +# UNSUPPORTED - mark the option as unsupported in the cmake port of init-repository, +# which means we will fall back to calling the perl script instead +# TYPE - the type of the option, currently we support boolean, string and void +# VALUE - the value to be set for a 'void' type option +# VALUES - the valid values for an option +# MAPPING - currently unused +# SHORT_NAME - an alternative short name flag, +# e.g. 'f' will parse -f for --force +# ALIAS - mark the option as an alias of another option, both will have the +# same value when retrieved. +# DEFAULT_VALUE - the default value to be set for the option when it's not specified +# on the command line +# +# NOTE: Make sure to update the SHORT_NAME code path when adding new options. +function(qt_ir_commandline_option_helper name) + qt_ir_commandline_option_parse_arguments(${ARGN}) + + set(unsupported_options "${commandline_known_unsupported_options}") + if(arg_UNSUPPORTED) + set(commandline_option_${name}_unsupported + "${arg_UNSUPPORTED}" PARENT_SCOPE) + list(APPEND unsupported_options "${name}") + endif() + set(commandline_known_unsupported_options "${unsupported_options}" PARENT_SCOPE) + + set(commandline_known_options + "${commandline_known_options};${name}" PARENT_SCOPE) + + set(commandline_option_${name}_type "${arg_TYPE}" PARENT_SCOPE) + + 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() + + if(NOT "${arg_SHORT_NAME}" STREQUAL "") + set(commandline_option_${name}_short_name "${arg_SHORT_NAME}" PARENT_SCOPE) + endif() + + if(NOT "${arg_ALIAS}" STREQUAL "") + set(commandline_option_${name}_alias "${arg_ALIAS}" PARENT_SCOPE) + endif() + + # Should be last, in case alias was specified + if(NOT "${arg_DEFAULT_VALUE}" STREQUAL "") + set(commandline_option_${name}_default_value "${arg_DEFAULT_VALUE}" PARENT_SCOPE) + qt_ir_command_line_set_input("${name}" "${arg_DEFAULT_VALUE}") + endif() +endfunction() + +# Defines an option that init-repository understands. +# Uses qt_ir_commandline_option_helper to define both long and short option names. +macro(qt_ir_commandline_option name) + # Define the main option + qt_ir_commandline_option_helper("${name}" ${ARGN}) + + qt_ir_commandline_option_parse_arguments(${ARGN}) + + # Define the short name option if it's requested + if(NOT "${arg_SHORT_NAME}" STREQUAL "" + AND "${commandline_option_${arg_SHORT_NAME}_type}" STREQUAL "") + set(unsupported "") + if(arg_UNSUPPORTED) + set(unsupported "${arg_UNSUPPORTED}") + endif() + + qt_ir_commandline_option_helper("${arg_SHORT_NAME}" + TYPE "${arg_TYPE}" + ALIAS "${name}" + VALUE "${arg_VALUE}" + VALUES ${arg_VALUES} + MAPPING ${arg_MAPPING} + DEFAULT_VALUE ${arg_DEFAULT_VALUE} + ${unsupported} + ) + endif() +endmacro() + +# Saves the value of a command line option into a global property. +function(qt_ir_command_line_set_input name val) + if(NOT "${commandline_option_${name}_alias}" STREQUAL "") + set(name "${commandline_option_${name}_alias}") + endif() + + set_property(GLOBAL PROPERTY _qt_ir_input_${name} "${val}") + set_property(GLOBAL APPEND PROPERTY _qt_ir_inputs ${name}) +endfunction() + +# Appends a value of a command line option into a global property. +# Currently unused +function(qt_ir_command_line_append_input name val) + if(NOT "${commandline_option_${name}_alias}" STREQUAL "") + set(name "${commandline_option_${name}_alias}") + endif() + + get_property(oldval GLOBAL PROPERTY _qt_ir_input_${name}) + if(NOT "${oldval}" STREQUAL "") + string(PREPEND val "${oldval};") + endif() + qt_ir_command_line_set_input(${name} "${val}" ) +endfunction() + +# Checks if the value of a command line option is valid. +function(qt_ir_validate_value 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) + list(JOIN valid_values " " valid_values_str) + qt_ir_add_error("Invalid value '${val}' supplied to command line option '${opt}'." + "\nAllowed values: ${valid_values_str}\n") +endfunction() + +# Sets / handles the value of a command line boolean option. +function(qt_ir_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() + qt_ir_command_line_set_input("${arg}" "${val}") +endfunction() + +# Sets / handles the value of a command line string option. +function(qt_ir_commandline_string arg val nextok) + if(nextok) + qt_ir_args_get_next_command_line_arg(val) + + if("${val}" MATCHES "^-") + qt_ir_add_error("No value supplied to command line options '${arg}'.") + endif() + endif() + qt_ir_validate_value("${arg}" "${val}" success) + if(success) + qt_ir_command_line_set_input("${arg}" "${val}") + endif() +endfunction() + +# Sets / handles the value of a command line void option. +# This is an option like --force, which doesn't take any arguments. +# Currently unused +function(qt_ir_commandline_void arg val nextok) + if(NOT "${val}" STREQUAL "") + qt_i_add_error("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() + qt_ir_command_line_set_input("${arg}" "${val}") +endfunction() + +# Reads the command line arguments from the optfile_path. +function(qt_ir_get_raw_args_from_optfile optfile_path out_var) + file(STRINGS "${optfile_path}" args) + qt_ir_escape_semicolons(args "${args}") + set(${out_var} "${args}" PARENT_SCOPE) +endfunction() + +# Reads the optfile_path, iterates over the given command line arguments, +# sets the input for recongized options. +# +# Handles the following styles of CLI arguments: +# --no-foo / --disable-foo +# -no-foo / -disable-foo +# --foo=<values> +# --foo <values> +# -foo <values> +# --foo +# -foo +# --f +# -f +# +# Currently handles the following types of CLI arguments: +# string +# boolean +# void +# +# IGNORE_UNKNOWN_ARGS tells the function not to fail if it encounters an unknown +# option, and instead append it to a global list of unknown options. +# It is needed when the script is called from the configure script with +# configure-only-known options. +function(qt_ir_process_args_from_optfile optfile_path) + set(options IGNORE_UNKNOWN_ARGS) + set(oneValueArgs "") + set(multiValueArgs "") + cmake_parse_arguments(arg "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) + + qt_ir_get_raw_args_from_optfile("${optfile_path}" configure_args) + qt_ir_set_unhandled_args("${configure_args}") + + while(1) + qt_ir_args_has_next_command_line_arg(has_next) + if(NOT has_next) + break() + endif() + qt_ir_args_get_next_command_line_arg(arg) + + # parse out opt and val + set(nextok FALSE) + if(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(nextok TRUE) + set(opt "${CMAKE_MATCH_1}") + unset(val) + elseif(arg MATCHES "^-(.*)") + set(nextok TRUE) + set(opt "${CMAKE_MATCH_1}") + unset(val) + else() + if(NOT arg_IGNORE_UNKNOWN_ARGS) + qt_ir_add_error("Invalid command line parameter '${arg}'.") + else() + message(DEBUG "Unknown command line parameter '${arg}'. Collecting.") + qt_ir_append_unknown_args("${arg}") + continue() + endif() + endif() + + set(type "${commandline_option_${opt}_type}") + + if("${type}" STREQUAL "") + if(NOT arg_IGNORE_UNKNOWN_ARGS) + qt_ir_add_error("Unknown command line option '${arg}'.") + else() + message(DEBUG "Unknown command line option '${arg}'. Collecting.") + qt_ir_append_unknown_args("${arg}") + continue() + endif() + endif() + + if(NOT COMMAND "qt_ir_commandline_${type}") + qt_ir_add_error("Unknown type '${type}' for command line option '${opt}'.") + endif() + qt_ir_call_function("qt_ir_commandline_${type}" "${opt}" "${val}" "${nextok}") + endwhile() +endfunction() + +# Shows help for the command line options. +function(qt_ir_show_help) + set(help_file "${CMAKE_CURRENT_LIST_DIR}/QtIRHelp.txt") + if(EXISTS "${help_file}") + file(READ "${help_file}" content) + message("${content}") + endif() + + message([[ +General Options: +-help, -h ............ Display this help screen +]]) +endfunction() + +# Gets the unhandled command line args. +function(qt_ir_get_unhandled_args out_var) + get_property(args GLOBAL PROPERTY _qt_ir_unhandled_args) + set(${out_var} "${args}" PARENT_SCOPE) +endfunction() + +# Sets the unhandled command line args. +function(qt_ir_set_unhandled_args args) + set_property(GLOBAL PROPERTY _qt_ir_unhandled_args "${args}") +endfunction() + +# Adds to the unknown command line args. +function(qt_ir_append_unknown_args args) + set_property(GLOBAL APPEND PROPERTY _qt_ir_unknown_args ${args}) +endfunction() + +# Gets the unhandled command line args. +function(qt_ir_get_unknown_args out_var) + get_property(args GLOBAL PROPERTY _qt_ir_unknown_args) + set(${out_var} "${args}" PARENT_SCOPE) +endfunction() + +# Gets the unsupported options that init-repository.pl supports, but the cmake port does +# not support. +function(qt_ir_get_unsupported_options out_var) + set(${out_var} "${commandline_known_unsupported_options}" PARENT_SCOPE) +endfunction() + +# Get the value of a command line option. +function(qt_ir_get_option_value name out_var) + if(NOT "${commandline_option_${name}_alias}" STREQUAL "") + set(name "${commandline_option_${name}_alias}") + endif() + + get_property(value GLOBAL PROPERTY _qt_ir_input_${name}) + set(${out_var} "${value}" PARENT_SCOPE) +endfunction() + +# Set the value of a command line option manually. +function(qt_ir_set_option_value name value) + if(NOT "${commandline_option_${name}_alias}" STREQUAL "") + set(name "${commandline_option_${name}_alias}") + endif() + + qt_ir_command_line_set_input("${name}" "${value}") +endfunction() + +# Get the value of a command line option as a cmakke flag option, to be passed +# to functions that use cmake_parse_arguments. +function(qt_ir_get_option_as_cmake_flag_option cli_name cmake_option_name out_var) + qt_ir_get_option_value("${cli_name}" bool_value) + set(cmake_option "") + if(bool_value) + set(cmake_option "${cmake_option_name}") + endif() + set(${out_var} "${cmake_option}" PARENT_SCOPE) +endfunction() |