aboutsummaryrefslogtreecommitdiffstats
path: root/cmake/QtIRHelpers.cmake
diff options
context:
space:
mode:
Diffstat (limited to 'cmake/QtIRHelpers.cmake')
-rw-r--r--cmake/QtIRHelpers.cmake367
1 files changed, 367 insertions, 0 deletions
diff --git a/cmake/QtIRHelpers.cmake b/cmake/QtIRHelpers.cmake
new file mode 100644
index 00000000..9f372932
--- /dev/null
+++ b/cmake/QtIRHelpers.cmake
@@ -0,0 +1,367 @@
+# Copyright (C) 2024 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+# Includes all helper files for access to necessary functions.
+macro(qt_ir_include_all_helpers)
+ include(QtIRCommandLineHelpers)
+ include(QtIRGitHelpers)
+ include(QtIROptionsHelpers)
+ include(QtIRParsingHelpers)
+ include(QtIRProcessHelpers)
+ include(QtIRTestHelpers)
+ include(QtTopLevelHelpers)
+endmacro()
+
+# Convenience macro to get the working directory from the arguments passed to
+# cmake_parse_arguments. Saves a few lines and makes reading the code slightly
+# easier.
+macro(qt_ir_get_working_directory_from_arg out_var)
+ if(NOT arg_WORKING_DIRECTORY)
+ message(FATAL_ERROR "No working directory specified")
+ endif()
+ set(${out_var} "${arg_WORKING_DIRECTORY}")
+endmacro()
+
+# Convenience function to set the variable to the name of cmake_parse_arguments
+# flag option if it is active.
+function(qt_ir_get_cmake_flag flag_name out_var)
+ if(arg_${flag_name})
+ set(${out_var} "${flag_name}" PARENT_SCOPE)
+ else()
+ set(${out_var} "" PARENT_SCOPE)
+ endif()
+endfunction()
+
+# There are some init-repository options that we do not want to allow when called from
+# configure. Make sure we error out when they are set by the user.
+function(qt_ir_validate_options_for_configure)
+ set(disallowed_options
+ # Disallow mirror options, because users should set up a proper git mirror manually,
+ # not via configure.
+ mirror
+ oslo
+ berlin
+ )
+ foreach(disallowed_option IN LISTS disallowed_options)
+ qt_ir_get_option_value(${disallowed_option} value)
+ if(value)
+ set(msg
+ "Initialization option '${disallowed_option}' is not supported by configure. "
+ "If you think this option should be supported, please let us know at "
+ "https://bugreports.qt.io/"
+ )
+ message(FATAL_ERROR ${msg})
+ endif()
+ endforeach()
+endfunction()
+
+# Handle the case when init-repository is called from the configure script.
+function(qt_ir_handle_called_from_configure top_level_src_path out_var_exit_reason)
+ # Nothing special to do if we're not called from configure.
+ qt_ir_is_called_from_configure(is_called_from_configure)
+ if(NOT is_called_from_configure)
+ set(${out_var_exit_reason} FALSE PARENT_SCOPE)
+ return()
+ endif()
+
+ # Check whether qtbase was cloned, if not, tell the user how to initialize
+ # the repos as part of the configure script.
+ qt_ir_get_option_value(init-submodules init_submodules)
+ set(configure_script "${top_level_src_path}/qtbase/configure")
+ if(NOT EXISTS "${configure_script}" AND NOT init_submodules)
+ set(msg "Oops. It looks like you didn't initialize any submodules yet.\nCall configure "
+ "with the -init-submodules option to automatically clone a default set of "
+ "submodules before configuring Qt.\nYou can also pass "
+ "-submodules submodule2,submodule3 to clone a particular set of submodules "
+ "and their dependencies. See ./init-repository --help for more information on values "
+ "accepted by --module-subset (which gets its values from -submodules).")
+ message(${msg})
+ set(${out_var_exit_reason} NEED_INIT_SUBMODULES PARENT_SCOPE)
+ return()
+ endif()
+
+ # Don't do init-repository things when called from configure, qtbase exists and the
+ # -init-submodules option is not passed. We assume the repo was already
+ # initialized.
+ if(NOT init_submodules)
+ set(${out_var_exit_reason} ALREADY_INITIALIZED PARENT_SCOPE)
+ return()
+ endif()
+
+ qt_ir_validate_options_for_configure()
+
+ # -init_submodules implies --force
+ qt_ir_set_option_value(force TRUE)
+
+ set(${out_var_exit_reason} FALSE PARENT_SCOPE)
+endfunction()
+
+# Returns a list of command line arguments with the init-repository specific
+# options removed, which are not recognized by configure.
+# It also handles -submodules values like 'essential', 'existing' and '-qtsvg' and transforms them
+# into the final list of submodules to be included and excluded, which are then translated
+# to configure -submodules and -skip options.
+function(qt_ir_get_args_from_optfile_configure_filtered optfile_path out_var)
+ cmake_parse_arguments(arg "ALREADY_INITIALIZED" "" "" ${ARGV})
+
+ # Get args unknown to init-repository, and pass them to configure as-is.
+ qt_ir_get_unknown_args(unknown_args)
+
+ set(filtered_args ${unknown_args})
+ set(extra_configure_args "")
+ set(extra_cmake_args "")
+
+ # If the -submodules or --module-subset options were specified, transform
+ # the values into something configure understands and pass them to configure.
+ qt_ir_get_option_value(module-subset submodules)
+ if(submodules)
+ qt_ir_get_top_level_submodules(include_submodules exclude_submodules)
+ if(NOT include_submodules AND arg_ALREADY_INITIALIZED)
+ set(include_submodules "${submodules}")
+ endif()
+
+ # qtrepotools is always implicitly cloned, but it doesn't actually
+ # have a CMakeLists.txt, so remove it.
+ list(REMOVE_ITEM include_submodules "qtrepotools")
+
+ # Make sure to explicitly pass -DBUILD_<module>=ON, in case they were
+ # skipped before, otherwise configure might fail.
+ if(include_submodules)
+ set(explicit_build_submodules "${include_submodules}")
+ list(TRANSFORM explicit_build_submodules PREPEND "-DBUILD_")
+ list(TRANSFORM explicit_build_submodules APPEND "=ON")
+ list(APPEND extra_cmake_args ${explicit_build_submodules})
+ endif()
+
+ list(JOIN include_submodules "," include_submodules)
+ list(JOIN exclude_submodules "," exclude_submodules)
+
+ # Handle case when the -skip argument is already passed.
+ # In that case read the passed values, merge with new ones,
+ # remove both the -skip and its values, and re-add it later.
+ list(FIND filtered_args "-skip" skip_index)
+ if(exclude_submodules AND skip_index GREATER -1)
+ list(LENGTH filtered_args filtered_args_length)
+ math(EXPR skip_args_index "${skip_index} + 1")
+
+ if(skip_args_index LESS filtered_args_length)
+ list(GET filtered_args "${skip_args_index}" skip_args)
+ string(REPLACE "," ";" skip_args "${skip_args}")
+ list(APPEND skip_args ${exclude_submodules})
+ list(REMOVE_DUPLICATES skip_args)
+ list(JOIN skip_args "," exclude_submodules)
+ list(REMOVE_AT filtered_args "${skip_args_index}")
+ list(REMOVE_AT filtered_args "${skip_index}")
+ endif()
+ endif()
+
+ # Handle case when only '-submodules existing' is passed and the
+ # subset ends up empty.
+ if(include_submodules)
+ list(APPEND extra_configure_args "-submodules" "${include_submodules}")
+ endif()
+ if(exclude_submodules)
+ list(APPEND extra_configure_args "-skip" "${exclude_submodules}")
+ endif()
+ endif()
+
+ # Insert the extra arguments into the proper positions before and after '--'.
+ list(FIND filtered_args "--" cmake_args_index)
+
+ # -- is not found
+ if(cmake_args_index EQUAL -1)
+ # Append extra configure args if present
+ if(extra_configure_args)
+ list(APPEND filtered_args ${extra_configure_args})
+ endif()
+ # Append extra cmake args if present, but make sure to add -- first at the end
+ if(extra_cmake_args)
+ list(APPEND filtered_args "--")
+ list(APPEND filtered_args ${extra_cmake_args})
+ endif()
+ else()
+ # -- is found, that means we probably have cmake args
+ # Insert extra configure args if present, before the -- index.
+ if(extra_configure_args)
+ list(INSERT filtered_args "${cmake_args_index}" ${extra_configure_args})
+ endif()
+ # Find the -- index again, because it might have moved
+ list(FIND filtered_args "--" cmake_args_index)
+ # Compute the index of the argument after the --.
+ math(EXPR cmake_args_index "${cmake_args_index} + 1")
+ # Insert extra cmake args if present, after the -- index.
+ if(extra_cmake_args)
+ list(INSERT filtered_args "${cmake_args_index}" ${extra_cmake_args})
+ endif()
+ endif()
+
+ # Pass --help if it was requested.
+ qt_ir_is_help_requested(show_help)
+ if(show_help)
+ list(APPEND filtered_args "-help")
+ endif()
+
+ set(${out_var} "${filtered_args}" PARENT_SCOPE)
+endfunction()
+
+# Checks whether any of the arguments passed on the command line are options
+# that are marked as unsupported in the cmake port of init-repository.
+function(qt_ir_check_if_unsupported_options_used out_var out_var_option_name)
+ qt_ir_get_unsupported_options(unsupported_options)
+
+ set(unsupported_options_used FALSE)
+ foreach(unsupported_option IN LISTS unsupported_options)
+ qt_ir_get_option_value(${unsupported_option} value)
+ if(value)
+ set(${out_var_option_name} "${unsupported_option}" PARENT_SCOPE)
+ set(unsupported_options_used TRUE)
+ break()
+ endif()
+ endforeach()
+ set(${out_var} "${unsupported_options_used}" PARENT_SCOPE)
+endfunction()
+
+# When an unsupported option is used, show an error message and tell the user
+# to run the perly script manually.
+function(qt_ir_show_error_how_to_run_perl opt_file unsupported_option_name)
+ qt_ir_get_raw_args_from_optfile("${opt_file}" args)
+ string(REPLACE ";" " " args "${args}")
+
+ set(perl_cmd "perl ./init-repository.pl ${args}")
+
+ message(FATAL_ERROR
+ "Option '${unsupported_option_name}' is not implemented in the cmake "
+ "port of init-repository. Please let us know if this option is really "
+ "important for you at https://bugreports.qt.io/. Meanwhile, you can "
+ "still run the perl script directly. \n ${perl_cmd}")
+endfunction()
+
+# Check whether help was requested.
+function(qt_ir_is_help_requested out_var)
+ qt_ir_get_option_value(help value)
+ set(${out_var} "${value}" PARENT_SCOPE)
+endfunction()
+
+# Check whether the verbose option was used.
+function(qt_ir_is_verbose out_var)
+ qt_ir_get_option_value(verbose value)
+ set(${out_var} "${value}" PARENT_SCOPE)
+endfunction()
+
+function(qt_ir_is_called_from_configure out_var)
+ qt_ir_get_option_value(from-configure value)
+ set(${out_var} "${value}" PARENT_SCOPE)
+endfunction()
+
+# Main logic of the script.
+function(qt_ir_run_after_args_parsed top_level_src_path out_var_exit_reason)
+ set(${out_var_exit_reason} FALSE PARENT_SCOPE)
+
+ qt_ir_is_called_from_configure(is_called_from_configure)
+
+ qt_ir_is_help_requested(show_help)
+ if(show_help AND NOT is_called_from_configure)
+ qt_ir_show_help()
+ set(${out_var_exit_reason} SHOWED_HELP PARENT_SCOPE)
+ return()
+ endif()
+
+ set(working_directory "${top_level_src_path}")
+
+ qt_ir_handle_if_already_initialized(already_initialized "${working_directory}")
+ if(already_initialized)
+ set(${out_var_exit_reason} ALREADY_INITIALIZED PARENT_SCOPE)
+ return()
+ endif()
+
+ # This will be used by the module subset processing to determine whether we
+ # should re-initialize the previously initialized (existing) subset.
+ qt_ir_check_if_already_initialized_cmake_style(is_initialized
+ "${working_directory}" FORCE_QUIET)
+ set(previously_initialized_option "")
+ if(is_initialized)
+ set(previously_initialized_option PREVIOUSLY_INITIALIZED)
+ endif()
+
+
+ # Ge the name of the qt5 repo (tqtc- or not) and the base url for all other repos
+ qt_ir_get_qt5_repo_name_and_base_url(
+ OUT_VAR_QT5_REPO_NAME qt5_repo_name
+ OUT_VAR_BASE_URL base_url
+ WORKING_DIRECTORY "${working_directory}")
+
+ qt_ir_get_already_initialized_submodules("${prefix}"
+ already_initialized_submodules
+ "${qt5_repo_name}"
+ "${working_directory}")
+
+ # Get some additional options to pass down.
+ qt_ir_get_option_value(alternates alternates)
+ qt_ir_get_option_as_cmake_flag_option(branch "CHECKOUT_BRANCH" checkout_branch_option)
+
+ # The prefix for the cmake-style 'dictionary' that will be used by various functions.
+ set(prefix "ir_top")
+
+ # Initialize and clone the submodules
+ qt_ir_handle_init_submodules("${prefix}"
+ ALTERNATES "${alternates}"
+ ALREADY_INITIALIZED_SUBMODULES "${already_initialized_submodules}"
+ BASE_URL "${base_url}"
+ PARENT_REPO_BASE_GIT_PATH "${qt5_repo_name}"
+ PROCESS_SUBMODULES_FROM_COMMAND_LINE
+ WORKING_DIRECTORY "${working_directory}"
+ ${checkout_branch_option}
+ ${previously_initialized_option}
+ )
+
+ # Add gerrit remotes.
+ qt_ir_add_git_remotes("${qt5_repo_name}" "${working_directory}")
+
+ # Install commit and other various hooks.
+ qt_ir_install_git_hooks(
+ PARENT_REPO_BASE_GIT_PATH "${qt5_repo_name}"
+ TOP_LEVEL_SRC_PATH "${top_level_src_path}"
+ WORKING_DIRECTORY "${working_directory}"
+ )
+
+ # Mark the repo as being initialized.
+ qt_ir_set_is_initialized("${working_directory}")
+endfunction()
+
+# Entrypoint of the init-repository script.
+function(qt_ir_run_main_script top_level_src_path out_var_exit_reason)
+ set(${out_var_exit_reason} FALSE PARENT_SCOPE)
+
+ # Windows passes backslash paths.
+ file(TO_CMAKE_PATH "${top_level_src_path}" top_level_src_path)
+
+ qt_ir_set_known_command_line_options()
+
+ # If called from configure, there might be arguments that init-repository doesn't know about
+ # because they are meant for configure. In that case ignore unknown arguments.
+ qt_ir_get_option_value(from-configure from_configure)
+ if(from_configure)
+ set(ignore_unknown_args "IGNORE_UNKNOWN_ARGS")
+ else()
+ set(ignore_unknown_args "")
+ endif()
+
+ qt_ir_process_args_from_optfile("${OPTFILE}" "${ignore_unknown_args}")
+
+ qt_ir_handle_called_from_configure("${top_level_src_path}" exit_reason)
+ if(exit_reason)
+ set(${out_var_exit_reason} "${exit_reason}" PARENT_SCOPE)
+ return()
+ endif()
+
+ qt_ir_check_if_unsupported_options_used(
+ unsupported_options_used option_name)
+ if(unsupported_options_used)
+ qt_ir_show_error_how_to_run_perl("${OPTFILE}" "${option_name}")
+ endif()
+
+ qt_ir_run_after_args_parsed("${top_level_src_path}" exit_reason)
+ set(${out_var_exit_reason} "${exit_reason}" PARENT_SCOPE)
+
+ # TODO: Consider using cmake_language(EXIT <exit-code>) when cmake 3.29 is released.
+endfunction()