aboutsummaryrefslogtreecommitdiffstats
path: root/cmake
diff options
context:
space:
mode:
Diffstat (limited to 'cmake')
-rw-r--r--cmake/3rdparty/cmake/Copyright.txt136
-rw-r--r--cmake/3rdparty/cmake/QtIRRunCMake.cmake349
-rw-r--r--cmake/3rdparty/cmake/QtIRTestHelpers.cmake39
-rw-r--r--cmake/3rdparty/cmake/qt_attribution.json16
-rw-r--r--cmake/QtIRCommandLineHelpers.cmake404
-rw-r--r--cmake/QtIRGitHelpers.cmake1151
-rw-r--r--cmake/QtIRHelp.txt134
-rw-r--r--cmake/QtIRHelpers.cmake367
-rw-r--r--cmake/QtIROptionsHelpers.cmake48
-rw-r--r--cmake/QtIRParsingHelpers.cmake237
-rw-r--r--cmake/QtIRProcessHelpers.cmake165
-rw-r--r--cmake/QtIRScript.cmake17
-rw-r--r--cmake/QtSortModuleDependencies.cmake16
-rw-r--r--cmake/QtSynchronizeRepo.cmake16
-rw-r--r--cmake/QtTopLevelConfigureScript.cmake17
-rw-r--r--cmake/QtTopLevelHelpers.cmake514
-rw-r--r--cmake/QtWriteArgsFile.cmake92
17 files changed, 3646 insertions, 72 deletions
diff --git a/cmake/3rdparty/cmake/Copyright.txt b/cmake/3rdparty/cmake/Copyright.txt
new file mode 100644
index 00000000..2074109b
--- /dev/null
+++ b/cmake/3rdparty/cmake/Copyright.txt
@@ -0,0 +1,136 @@
+CMake - Cross Platform Makefile Generator
+Copyright 2000-2024 Kitware, Inc. and Contributors
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+* Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+* Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+* Neither the name of Kitware, Inc. nor the names of Contributors
+ may be used to endorse or promote products derived from this
+ software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+------------------------------------------------------------------------------
+
+The following individuals and institutions are among the Contributors:
+
+* Aaron C. Meadows <cmake@shadowguarddev.com>
+* Adriaan de Groot <groot@kde.org>
+* Aleksey Avdeev <solo@altlinux.ru>
+* Alexander Neundorf <neundorf@kde.org>
+* Alexander Smorkalov <alexander.smorkalov@itseez.com>
+* Alexey Sokolov <sokolov@google.com>
+* Alex Merry <alex.merry@kde.org>
+* Alex Turbov <i.zaufi@gmail.com>
+* Andreas Pakulat <apaku@gmx.de>
+* Andreas Schneider <asn@cryptomilk.org>
+* André Rigland Brodtkorb <Andre.Brodtkorb@ifi.uio.no>
+* Axel Huebl, Helmholtz-Zentrum Dresden - Rossendorf
+* Benjamin Eikel
+* Bjoern Ricks <bjoern.ricks@gmail.com>
+* Brad Hards <bradh@kde.org>
+* Christopher Harvey
+* Christoph Grüninger <foss@grueninger.de>
+* Clement Creusot <creusot@cs.york.ac.uk>
+* Daniel Blezek <blezek@gmail.com>
+* Daniel Pfeifer <daniel@pfeifer-mail.de>
+* Dawid Wróbel <me@dawidwrobel.com>
+* Enrico Scholz <enrico.scholz@informatik.tu-chemnitz.de>
+* Eran Ifrah <eran.ifrah@gmail.com>
+* Esben Mose Hansen, Ange Optimization ApS
+* Geoffrey Viola <geoffrey.viola@asirobots.com>
+* Google Inc
+* Gregor Jasny
+* Helio Chissini de Castro <helio@kde.org>
+* Ilya Lavrenov <ilya.lavrenov@itseez.com>
+* Insight Software Consortium <insightsoftwareconsortium.org>
+* Intel Corporation <www.intel.com>
+* Jan Woetzel
+* Jordan Williams <jordan@jwillikers.com>
+* Julien Schueller
+* Kelly Thompson <kgt@lanl.gov>
+* Konstantin Podsvirov <konstantin@podsvirov.pro>
+* Laurent Montel <montel@kde.org>
+* Mario Bensi <mbensi@ipsquad.net>
+* Martin Gräßlin <mgraesslin@kde.org>
+* Mathieu Malaterre <mathieu.malaterre@gmail.com>
+* Matthaeus G. Chajdas
+* Matthias Kretz <kretz@kde.org>
+* Matthias Maennich <matthias@maennich.net>
+* Michael Hirsch, Ph.D. <www.scivision.co>
+* Michael Stürmer
+* Miguel A. Figueroa-Villanueva
+* Mike Durso <rbprogrammer@gmail.com>
+* Mike Jackson
+* Mike McQuaid <mike@mikemcquaid.com>
+* Nicolas Bock <nicolasbock@gmail.com>
+* Nicolas Despres <nicolas.despres@gmail.com>
+* Nikita Krupen'ko <krnekit@gmail.com>
+* NVIDIA Corporation <www.nvidia.com>
+* OpenGamma Ltd. <opengamma.com>
+* Patrick Stotko <stotko@cs.uni-bonn.de>
+* Per Øyvind Karlsen <peroyvind@mandriva.org>
+* Peter Collingbourne <peter@pcc.me.uk>
+* Petr Gotthard <gotthard@honeywell.com>
+* Philip Lowman <philip@yhbt.com>
+* Philippe Proulx <pproulx@efficios.com>
+* Raffi Enficiaud, Max Planck Society
+* Raumfeld <raumfeld.com>
+* Roger Leigh <rleigh@codelibre.net>
+* Rolf Eike Beer <eike@sf-mail.de>
+* Roman Donchenko <roman.donchenko@itseez.com>
+* Roman Kharitonov <roman.kharitonov@itseez.com>
+* Ruslan Baratov
+* Sebastian Holtermann <sebholt@xwmw.org>
+* Stephen Kelly <steveire@gmail.com>
+* Sylvain Joubert <joubert.sy@gmail.com>
+* The Qt Company Ltd.
+* Thomas Sondergaard <ts@medical-insight.com>
+* Tobias Hunger <tobias.hunger@qt.io>
+* Todd Gamblin <tgamblin@llnl.gov>
+* Tristan Carel
+* University of Dundee
+* Vadim Zhukov
+* Will Dicharry <wdicharry@stellarscience.com>
+
+See version control history for details of individual contributions.
+
+The above copyright and license notice applies to distributions of
+CMake in source and binary form. Third-party software packages supplied
+with CMake under compatible licenses provide their own copyright notices
+documented in corresponding subdirectories or source files.
+
+------------------------------------------------------------------------------
+
+CMake was initially developed by Kitware with the following sponsorship:
+
+ * National Library of Medicine at the National Institutes of Health
+ as part of the Insight Segmentation and Registration Toolkit (ITK).
+
+ * US National Labs (Los Alamos, Livermore, Sandia) ASC Parallel
+ Visualization Initiative.
+
+ * National Alliance for Medical Image Computing (NAMIC) is funded by the
+ National Institutes of Health through the NIH Roadmap for Medical Research,
+ Grant U54 EB005149.
+
+ * Kitware, Inc.
diff --git a/cmake/3rdparty/cmake/QtIRRunCMake.cmake b/cmake/3rdparty/cmake/QtIRRunCMake.cmake
new file mode 100644
index 00000000..dd6a10de
--- /dev/null
+++ b/cmake/3rdparty/cmake/QtIRRunCMake.cmake
@@ -0,0 +1,349 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+#
+# Original file location was Tests/RunCMake/RunCMake.cmake
+
+foreach(
+ arg
+ IN ITEMS
+ RunCMake_GENERATOR
+ RunCMake_SOURCE_DIR
+ RunCMake_BINARY_DIR
+ )
+ if(NOT DEFINED ${arg})
+ message(FATAL_ERROR "${arg} not given!")
+ endif()
+endforeach()
+
+function(run_cmake test)
+ if(DEFINED ENV{RunCMake_TEST_FILTER})
+ set(test_and_variant "${test}${RunCMake_TEST_VARIANT_DESCRIPTION}")
+ if(NOT test_and_variant MATCHES "$ENV{RunCMake_TEST_FILTER}")
+ return()
+ endif()
+ unset(test_and_variant)
+ endif()
+
+ set(top_src "${RunCMake_SOURCE_DIR}")
+ set(top_bin "${RunCMake_BINARY_DIR}")
+ if(EXISTS ${top_src}/${test}-result.txt)
+ file(READ ${top_src}/${test}-result.txt expect_result)
+ string(REGEX REPLACE "\n+$" "" expect_result "${expect_result}")
+ elseif(DEFINED RunCMake_TEST_EXPECT_RESULT)
+ set(expect_result "${RunCMake_TEST_EXPECT_RESULT}")
+ else()
+ set(expect_result 0)
+ endif()
+
+ string(TOLOWER ${CMAKE_HOST_SYSTEM_NAME} platform_name)
+ #remove all additional bits from cygwin/msys name
+ if(platform_name MATCHES cygwin)
+ set(platform_name cygwin)
+ endif()
+ if(platform_name MATCHES msys)
+ set(platform_name msys)
+ endif()
+
+ foreach(o IN ITEMS stdout stderr config)
+ if(RunCMake-${o}-file AND EXISTS ${top_src}/${RunCMake-${o}-file})
+ file(READ ${top_src}/${RunCMake-${o}-file} expect_${o})
+ string(REGEX REPLACE "\n+$" "" expect_${o} "${expect_${o}}")
+ elseif(EXISTS ${top_src}/${test}-${o}-${platform_name}.txt)
+ file(READ ${top_src}/${test}-${o}-${platform_name}.txt expect_${o})
+ string(REGEX REPLACE "\n+$" "" expect_${o} "${expect_${o}}")
+ elseif(EXISTS ${top_src}/${test}-${o}.txt)
+ file(READ ${top_src}/${test}-${o}.txt expect_${o})
+ string(REGEX REPLACE "\n+$" "" expect_${o} "${expect_${o}}")
+ elseif(DEFINED RunCMake_TEST_EXPECT_${o})
+ string(REGEX REPLACE "\n+$" "" expect_${o} "${RunCMake_TEST_EXPECT_${o}}")
+ else()
+ unset(expect_${o})
+ endif()
+ endforeach()
+ foreach(o IN ITEMS stdout stderr config)
+ if(DEFINED RunCMake_TEST_NOT_EXPECT_${o})
+ string(REGEX REPLACE "\n+$" "" not_expect_${o} "${RunCMake_TEST_NOT_EXPECT_${o}}")
+ endif()
+ endforeach()
+ if (NOT expect_stderr)
+ if (NOT RunCMake_DEFAULT_stderr)
+ set(RunCMake_DEFAULT_stderr "^$")
+ endif()
+ set(expect_stderr ${RunCMake_DEFAULT_stderr})
+ endif()
+
+ if (NOT RunCMake_TEST_SOURCE_DIR)
+ set(RunCMake_TEST_SOURCE_DIR "${top_src}")
+ endif()
+ if(NOT RunCMake_TEST_BINARY_DIR)
+ set(RunCMake_TEST_BINARY_DIR "${top_bin}/${test}-build")
+ endif()
+ if(NOT RunCMake_TEST_NO_CLEAN)
+ file(REMOVE_RECURSE "${RunCMake_TEST_BINARY_DIR}")
+ endif()
+ file(MAKE_DIRECTORY "${RunCMake_TEST_BINARY_DIR}")
+ if(RunCMake-prep-file AND EXISTS ${top_src}/${RunCMake-prep-file})
+ include(${top_src}/${RunCMake-prep-file})
+ else()
+ include(${top_src}/${test}-prep.cmake OPTIONAL)
+ endif()
+ if(RunCMake_TEST_OUTPUT_MERGE)
+ set(actual_stderr_var actual_stdout)
+ set(actual_stderr "")
+ else()
+ set(actual_stderr_var actual_stderr)
+ endif()
+ if(DEFINED RunCMake_TEST_TIMEOUT)
+ set(maybe_timeout TIMEOUT ${RunCMake_TEST_TIMEOUT})
+ else()
+ set(maybe_timeout "")
+ endif()
+ if(RunCMake-stdin-file AND EXISTS ${top_src}/${RunCMake-stdin-file})
+ set(maybe_input_file INPUT_FILE ${top_src}/${RunCMake-stdin-file})
+ elseif(EXISTS ${top_src}/${test}-stdin.txt)
+ set(maybe_input_file INPUT_FILE ${top_src}/${test}-stdin.txt)
+ else()
+ set(maybe_input_file "")
+ endif()
+ if(NOT RunCMake_TEST_COMMAND)
+ if(NOT DEFINED RunCMake_TEST_OPTIONS)
+ set(RunCMake_TEST_OPTIONS "")
+ endif()
+ if(APPLE)
+ list(APPEND RunCMake_TEST_OPTIONS -DCMAKE_POLICY_DEFAULT_CMP0025=NEW)
+ endif()
+ if(RunCMake_TEST_LCC AND NOT RunCMake_TEST_NO_CMP0129)
+ list(APPEND RunCMake_TEST_OPTIONS -DCMAKE_POLICY_DEFAULT_CMP0129=NEW)
+ endif()
+ if(RunCMake_MAKE_PROGRAM)
+ list(APPEND RunCMake_TEST_OPTIONS "-DCMAKE_MAKE_PROGRAM=${RunCMake_MAKE_PROGRAM}")
+ endif()
+ set(RunCMake_TEST_COMMAND ${CMAKE_COMMAND})
+ if(NOT RunCMake_TEST_NO_SOURCE_DIR)
+ list(APPEND RunCMake_TEST_COMMAND "${RunCMake_TEST_SOURCE_DIR}")
+ endif()
+ list(APPEND RunCMake_TEST_COMMAND -G "${RunCMake_GENERATOR}")
+ if(RunCMake_GENERATOR_PLATFORM)
+ list(APPEND RunCMake_TEST_COMMAND -A "${RunCMake_GENERATOR_PLATFORM}")
+ endif()
+ if(RunCMake_GENERATOR_TOOLSET)
+ list(APPEND RunCMake_TEST_COMMAND -T "${RunCMake_GENERATOR_TOOLSET}")
+ endif()
+ if(RunCMake_GENERATOR_INSTANCE)
+ list(APPEND RunCMake_TEST_COMMAND "-DCMAKE_GENERATOR_INSTANCE=${RunCMake_GENERATOR_INSTANCE}")
+ endif()
+ list(APPEND RunCMake_TEST_COMMAND
+ -DRunCMake_TEST=${test}
+ --no-warn-unused-cli
+ )
+ else()
+ set(RunCMake_TEST_OPTIONS "")
+ endif()
+ if(NOT DEFINED RunCMake_TEST_RAW_ARGS)
+ set(RunCMake_TEST_RAW_ARGS "")
+ endif()
+ if(NOT RunCMake_TEST_COMMAND_WORKING_DIRECTORY)
+ set(RunCMake_TEST_COMMAND_WORKING_DIRECTORY "${RunCMake_TEST_BINARY_DIR}")
+ endif()
+ string(CONCAT _code [[execute_process(
+ COMMAND ${RunCMake_TEST_COMMAND}
+ ${RunCMake_TEST_OPTIONS}
+ ]] "${RunCMake_TEST_RAW_ARGS}\n" [[
+ WORKING_DIRECTORY "${RunCMake_TEST_COMMAND_WORKING_DIRECTORY}"
+ OUTPUT_VARIABLE actual_stdout
+ ERROR_VARIABLE ${actual_stderr_var}
+ RESULT_VARIABLE actual_result
+ ENCODING UTF8
+ ${maybe_timeout}
+ ${maybe_input_file}
+ )]])
+ if(DEFINED ENV{PWD})
+ set(old_pwd "$ENV{PWD}")
+ else()
+ set(old_pwd)
+ endif()
+ # Emulate a shell using this directory.
+ set(ENV{PWD} "${RunCMake_TEST_COMMAND_WORKING_DIRECTORY}")
+ cmake_language(EVAL CODE "${_code}")
+ if(DEFINED old_pwd)
+ set(ENV{PWD} "${old_pwd}")
+ else()
+ set(ENV{PWD})
+ endif()
+ set(msg "")
+ if(NOT "${actual_result}" MATCHES "${expect_result}")
+ string(APPEND msg "Result is [${actual_result}], not [${expect_result}].\n")
+ endif()
+ set(config_file "${RunCMake_TEST_COMMAND_WORKING_DIRECTORY}/CMakeFiles/CMakeConfigureLog.yaml")
+ if(EXISTS "${config_file}")
+ file(READ "${config_file}" actual_config)
+ else()
+ set(actual_config "")
+ endif()
+
+ # Special case: remove ninja no-op line from stderr, but not stdout.
+ # Test cases that look for it should use RunCMake_TEST_OUTPUT_MERGE.
+ string(REGEX REPLACE "(^|\r?\n)ninja: no work to do\\.\r?\n" "\\1" actual_stderr "${actual_stderr}")
+
+ # Remove incidental content from both stdout and stderr.
+ string(CONCAT ignore_line_regex
+ "(^|\n)((==[0-9]+=="
+ "|BullseyeCoverage"
+ "|[a-z]+\\([0-9]+\\) malloc:"
+ "|clang[^:]*: warning: the object size sanitizer has no effect at -O0, but is explicitly enabled:"
+ "|flang-new: warning: argument unused during compilation: .-flang-experimental-exec."
+ "|icp?x: remark: Note that use of .-g. without any optimization-level option will turn off most compiler optimizations"
+ "|ifx: remark #10440: Note that use of a debug option without any optimization-level option will turnoff most compiler optimizations"
+ "|lld-link: warning: procedure symbol record for .* refers to PDB item index [0-9A-Fa-fx]+ which is not a valid function ID record"
+ "|Error kstat returned"
+ "|Hit xcodebuild bug"
+ "|Recompacting log\\.\\.\\."
+
+ "|LICENSE WARNING:"
+ "|Your license to use PGI[^\n]*expired"
+ "|Please obtain a new version at"
+ "|contact PGI Sales at"
+ "|ic(p?c|l): remark #10441: The Intel\\(R\\) C\\+\\+ Compiler Classic \\(ICC\\) is deprecated"
+
+ "|[^\n]*install_name_tool: warning: changes being made to the file will invalidate the code signature in:"
+ "|[^\n]*(createItemModels|_NSMainThread|Please file a bug at)"
+ "|[^\n]*xcodebuild[^\n]*DVTAssertions: Warning"
+ "|[^\n]*xcodebuild[^\n]*DVTCoreDeviceEnabledState: DVTCoreDeviceEnabledState_Disabled set via user default"
+ "|[^\n]*xcodebuild[^\n]*DVTPlugInManager"
+ "|[^\n]*xcodebuild[^\n]*DVTSDK: Warning: SDK path collision for path"
+ "|[^\n]*xcodebuild[^\n]*Requested but did not find extension point with identifier"
+ "|[^\n]*xcodebuild[^\n]*nil host used in call to allows.*HTTPSCertificateForHost"
+ "|[^\n]*xcodebuild[^\n]*warning: file type[^\n]*is based on missing file type"
+ "|[^\n]*objc[^\n]*: Class [^\n]* One of the two will be used. Which one is undefined."
+ "|[^\n]*is a member of multiple groups"
+ "|[^\n]*offset in archive not a multiple of 8"
+ "|[^\n]*from Time Machine by path"
+ "|[^\n]*Bullseye Testing Technology"
+ ${RunCMake_TEST_EXTRA_IGNORE_LINE_REGEX}
+ ")[^\n]*\n)+"
+ )
+ if(RunCMake_IGNORE_POLICY_VERSION_DEPRECATION)
+ string(REGEX REPLACE [[
+^CMake Deprecation Warning at [^
+]*CMakeLists.txt:1 \(cmake_minimum_required\):
+ Compatibility with CMake < 3\.5 will be removed from a future version of
+ CMake.
+
+ Update the VERSION argument <min> value or use a \.\.\.<max> suffix to tell
+ CMake that the project does not need compatibility with older versions\.
++
+]] "" actual_stderr "${actual_stderr}")
+ endif()
+ foreach(o IN ITEMS stdout stderr config)
+ string(REGEX REPLACE "\r\n" "\n" actual_${o} "${actual_${o}}")
+ string(REGEX REPLACE "${ignore_line_regex}" "\\1" actual_${o} "${actual_${o}}")
+ string(REGEX REPLACE "\n+$" "" actual_${o} "${actual_${o}}")
+ if(DEFINED expect_${o})
+ if(NOT "${actual_${o}}" MATCHES "${expect_${o}}")
+ string(APPEND msg "${o} does not match that expected.\n")
+ endif()
+ endif()
+ if(DEFINED not_expect_${o})
+ if("${actual_${o}}" MATCHES "${not_expect_${o}}")
+ string(APPEND msg "${o} matches that not expected.\n")
+ endif()
+ endif()
+ endforeach()
+ unset(RunCMake_TEST_FAILED)
+ if(RunCMake-check-file AND EXISTS ${top_src}/${RunCMake-check-file})
+ include(${top_src}/${RunCMake-check-file})
+ else()
+ include(${top_src}/${test}-check.cmake OPTIONAL)
+ endif()
+ if(RunCMake_TEST_FAILED)
+ set(msg "${RunCMake_TEST_FAILED}\n${msg}")
+ endif()
+ if(msg)
+ string(REPLACE ";" "\" \"" command "\"${RunCMake_TEST_COMMAND}\"")
+ if(RunCMake_TEST_OPTIONS)
+ string(REPLACE ";" "\" \"" options "\"${RunCMake_TEST_OPTIONS}\"")
+ string(APPEND command " ${options}")
+ endif()
+ if(RunCMake_TEST_RAW_ARGS)
+ string(APPEND command " ${RunCMake_TEST_RAW_ARGS}")
+ endif()
+ string(APPEND msg "Command was:\n command> ${command}\n")
+ endif()
+ if(msg)
+ foreach(o IN ITEMS stdout stderr config)
+ if(DEFINED expect_${o})
+ string(REGEX REPLACE "\n" "\n expect-${o}> " expect_${o} " expect-${o}> ${expect_${o}}")
+ string(APPEND msg "Expected ${o} to match:\n${expect_${o}}\n")
+ endif()
+ if(NOT o STREQUAL "config" OR DEFINED expect_${o})
+ string(REGEX REPLACE "\n" "\n actual-${o}> " actual_${o} " actual-${o}> ${actual_${o}}")
+ string(APPEND msg "Actual ${o}:\n${actual_${o}}\n")
+ endif()
+ endforeach()
+ message(SEND_ERROR "${test}${RunCMake_TEST_VARIANT_DESCRIPTION} - FAILED:\n${msg}")
+ else()
+ message(STATUS "${test}${RunCMake_TEST_VARIANT_DESCRIPTION} - PASSED")
+ endif()
+endfunction()
+
+function(run_cmake_command test)
+ set(RunCMake_TEST_COMMAND "${ARGN}")
+ run_cmake(${test})
+endfunction()
+
+function(run_cmake_script test)
+ set(RunCMake_TEST_COMMAND ${CMAKE_COMMAND} ${ARGN} -P ${RunCMake_SOURCE_DIR}/${test}.cmake)
+ run_cmake(${test})
+endfunction()
+
+function(run_cmake_with_options test)
+ set(RunCMake_TEST_OPTIONS "${ARGN}")
+ run_cmake(${test})
+endfunction()
+
+function(run_cmake_with_raw_args test args)
+ set(RunCMake_TEST_RAW_ARGS "${args}")
+ run_cmake(${test})
+endfunction()
+
+function(ensure_files_match expected_file actual_file)
+ if(NOT EXISTS "${expected_file}")
+ message(FATAL_ERROR "Expected file does not exist:\n ${expected_file}")
+ endif()
+ if(NOT EXISTS "${actual_file}")
+ message(FATAL_ERROR "Actual file does not exist:\n ${actual_file}")
+ endif()
+ file(READ "${expected_file}" expected_file_content)
+ file(READ "${actual_file}" actual_file_content)
+ if(NOT "${expected_file_content}" STREQUAL "${actual_file_content}")
+ message(FATAL_ERROR "Actual file content does not match expected:\n
+ \n
+ expected file: ${expected_file}\n
+ expected content:\n
+ ${expected_file_content}\n
+ \n
+ actual file: ${actual_file}\n
+ actual content:\n
+ ${actual_file_content}\n
+ ")
+ endif()
+endfunction()
+
+# Get the user id on unix if possible.
+function(get_unix_uid var)
+ set("${var}" "" PARENT_SCOPE)
+ if(UNIX)
+ set(ID "id")
+ if(CMAKE_SYSTEM_NAME STREQUAL "SunOS" AND EXISTS "/usr/xpg4/bin/id")
+ set (ID "/usr/xpg4/bin/id")
+ endif()
+ execute_process(COMMAND ${ID} -u $ENV{USER} OUTPUT_VARIABLE uid ERROR_QUIET
+ RESULT_VARIABLE status OUTPUT_STRIP_TRAILING_WHITESPACE)
+ if(status EQUAL 0)
+ set("${var}" "${uid}" PARENT_SCOPE)
+ endif()
+ endif()
+endfunction()
+
+# Protect RunCMake tests from calling environment.
+unset(ENV{MAKEFLAGS})
diff --git a/cmake/3rdparty/cmake/QtIRTestHelpers.cmake b/cmake/3rdparty/cmake/QtIRTestHelpers.cmake
new file mode 100644
index 00000000..804e20f0
--- /dev/null
+++ b/cmake/3rdparty/cmake/QtIRTestHelpers.cmake
@@ -0,0 +1,39 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+#
+# Original file location was Tests/RunCMake/CMakeLists.txt
+
+macro(add_RunCMake_test test)
+ set(TEST_ARGS ${ARGN})
+ if ("${ARGV1}" STREQUAL "TEST_DIR")
+ if ("${ARGV2}" STREQUAL "")
+ message(FATAL_ERROR "Invalid args")
+ endif()
+ set(Test_Dir ${ARGV2})
+ list(REMOVE_AT TEST_ARGS 0)
+ list(REMOVE_AT TEST_ARGS 0)
+ else()
+ set(Test_Dir ${test})
+ endif()
+ if(CMAKE_C_COMPILER_ID STREQUAL "LCC")
+ list(APPEND TEST_ARGS -DRunCMake_TEST_LCC=1)
+ endif()
+ add_test(NAME RunCMake.${test} COMMAND ${CMAKE_CMAKE_COMMAND}
+ -DCMAKE_MODULE_PATH=${CMAKE_CURRENT_SOURCE_DIR}
+ -DRunCMake_GENERATOR_IS_MULTI_CONFIG=${_isMultiConfig}
+ -DRunCMake_GENERATOR=${CMAKE_GENERATOR}
+ -DRunCMake_GENERATOR_INSTANCE=${CMAKE_GENERATOR_INSTANCE}
+ -DRunCMake_GENERATOR_PLATFORM=${CMAKE_GENERATOR_PLATFORM}
+ -DRunCMake_GENERATOR_TOOLSET=${CMAKE_GENERATOR_TOOLSET}
+ -DRunCMake_MAKE_PROGRAM=${CMake_TEST_EXPLICIT_MAKE_PROGRAM}
+ -DRunCMake_SOURCE_DIR=${CMAKE_CURRENT_SOURCE_DIR}/${Test_Dir}
+ -DRunCMake_BINARY_DIR=${CMAKE_CURRENT_BINARY_DIR}/${test}
+ ${${test}_ARGS}
+ ${TEST_ARGS}
+ -P "${CMAKE_CURRENT_SOURCE_DIR}/${Test_Dir}/RunCMakeTest.cmake"
+ )
+ set_tests_properties("RunCMake.${test}" PROPERTIES LABELS "CMake;run")
+ if(${test} MATCHES ^CMP)
+ set_property(TEST "RunCMake.${test}" APPEND PROPERTY LABELS "policy")
+ endif()
+endmacro()
diff --git a/cmake/3rdparty/cmake/qt_attribution.json b/cmake/3rdparty/cmake/qt_attribution.json
new file mode 100644
index 00000000..8ba8a1e7
--- /dev/null
+++ b/cmake/3rdparty/cmake/qt_attribution.json
@@ -0,0 +1,16 @@
+{
+ "Id": "cmake-test-modules",
+ "Name": "cmake-test-modules",
+ "QDocModule": "qtcore",
+ "QtUsage": "Used as part of the build system.",
+ "QtParts" : [ "tests" ],
+
+ "Description": "CMake helpers for running CMake tests.",
+ "Homepage": "https://cmake.org/",
+ "Version": "3.29.0",
+
+ "License": "BSD 3-Clause \"New\" or \"Revised\" License",
+ "LicenseId": "BSD-3-Clause",
+ "LicenseFile": "Copyright.txt",
+ "Copyright": "Copyright © 2000-2024 Kitware, Inc. and Contributors"
+}
diff --git a/cmake/QtIRCommandLineHelpers.cmake b/cmake/QtIRCommandLineHelpers.cmake
new file mode 100644
index 00000000..465a994b
--- /dev/null
+++ b/cmake/QtIRCommandLineHelpers.cmake
@@ -0,0 +1,404 @@
+# 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)
+ 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()
diff --git a/cmake/QtIRGitHelpers.cmake b/cmake/QtIRGitHelpers.cmake
new file mode 100644
index 00000000..288f4ac7
--- /dev/null
+++ b/cmake/QtIRGitHelpers.cmake
@@ -0,0 +1,1151 @@
+# Copyright (C) 2024 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+# Returns the git version.
+function(qt_ir_get_git_version out_var)
+ qt_ir_get_option_value(perl-identical-output perl_identical_output_for_tests)
+
+ set(extra_args "")
+ if(perl_identical_output_for_tests)
+ set(extra_args FORCE_QUIET)
+ endif()
+
+ qt_ir_execute_process_and_log_and_handle_error(
+ COMMAND_ARGS git version ${extra_args}
+ OUT_OUTPUT_VAR git_output
+ ERROR_MESSAGE "Failed to retrieve git version")
+
+ string(REGEX REPLACE "^git version ([0-9]+)\\.([0-9]+)\\.([0-9]+).*$" "\\1.\\2.\\3"
+ version "${git_output}")
+ if(NOT version)
+ message(FATAL_ERROR "Failed to parse git version: ${git_output}, expected [d]+.[d]+.[d]+")
+ endif()
+
+ set(${out_var} "${version}" PARENT_SCOPE)
+endfunction()
+
+# Returns the git version, but caches the result in a global property.
+function(qt_ir_get_git_version_cached out_var)
+ get_property(version GLOBAL PROPERTY _qt_git_version)
+ if(NOT version)
+ qt_ir_get_git_version(version)
+ endif()
+
+ set_property(GLOBAL PROPERTY _qt_git_version "${version}")
+
+ set(${out_var} "${version}" PARENT_SCOPE)
+endfunction()
+
+# Returns whether git supports the git submodule --progress option.
+function(qt_ir_is_git_progress_supported out_var)
+ qt_ir_get_git_version_cached(version)
+ if(version VERSION_GREATER_EQUAL "2.11")
+ set(${out_var} TRUE PARENT_SCOPE)
+ else()
+ set(${out_var} FALSE PARENT_SCOPE)
+ endif()
+endfunction()
+
+# Get the mirror with trailing slashes removed.
+function(qt_ir_get_mirror out_var)
+ qt_ir_get_option_value(mirror mirror)
+ qt_ir_get_option_value(berlin berlin)
+ qt_ir_get_option_value(oslo oslo)
+
+ if(berlin)
+ set(mirror "git://hegel/qt/")
+ elseif(oslo)
+ set(mirror "git://qilin/qt/")
+ endif()
+
+ # Replace any double trailing slashes from end of mirror
+ string(REGEX REPLACE "//+$" "/" mirror "${mirror}")
+
+ set(${out_var} "${mirror}" PARENT_SCOPE)
+endfunction()
+
+# Sets up the commit template for a submodule.
+function(qt_ir_setup_commit_template commit_template_dir working_directory)
+ set(template "${commit_template_dir}/.commit-template")
+ if(NOT EXISTS "${template}")
+ return()
+ endif()
+
+ qt_ir_execute_process_and_log_and_handle_error(
+ COMMAND_ARGS git config commit.template "${template}"
+ ERROR_MESSAGE "Failed to setup commit template"
+ WORKING_DIRECTORY "${working_directory}")
+endfunction()
+
+# Initializes a list of submodules. This does not them, but just
+# sets up the .git/config file submodule.$submodule_name.url based on the .gitmodules template file.
+function(qt_ir_run_git_submodule_init submodules working_directory)
+ set(submodule_dirs "")
+ foreach(submodule_name IN LISTS submodules)
+ set(submodule_path "${${prefix}_${submodule_name}_path}")
+ list(APPEND submodule_dirs "${submodule_name}")
+ endforeach()
+ qt_ir_execute_process_and_log_and_handle_error(
+ COMMAND_ARGS git submodule init ${submodule_dirs}
+ ERROR_MESSAGE "Failed to git submodule init ${submodule_dirs}"
+ WORKING_DIRECTORY "${working_directory}")
+
+ qt_ir_setup_commit_template("${working_directory}" "${working_directory}")
+endfunction()
+
+# Add gerrit remotes to the repository.
+function(qt_ir_add_git_remotes repo_name working_directory)
+ set(gerrit_ssh_base "ssh://@USER@codereview.qt-project.org@PORT@/qt/")
+ set(gerrit_repo_url "${gerrit_ssh_base}")
+
+ qt_ir_get_option_value(codereview-username username)
+
+ # If given a username, make a "verbose" remote.
+ # Otherwise, rely on proper SSH configuration.
+ if(username)
+ string(REPLACE "@USER@" "${username}@" gerrit_repo_url "${gerrit_repo_url}")
+ string(REPLACE "@PORT@" ":29418" gerrit_repo_url "${gerrit_repo_url}")
+ else()
+ string(REPLACE "@USER@" "" gerrit_repo_url "${gerrit_repo_url}")
+ string(REPLACE "@PORT@" "" gerrit_repo_url "${gerrit_repo_url}")
+ endif()
+
+ string(APPEND gerrit_repo_url "${repo_name}")
+
+ qt_ir_execute_process_and_log_and_handle_error(
+ COMMAND_ARGS git config remote.gerrit.url "${gerrit_repo_url}"
+ ERROR_MESSAGE "Failed to set gerrit repo url"
+ WORKING_DIRECTORY "${working_directory}")
+
+ qt_ir_execute_process_and_log_and_handle_error(
+ COMMAND_ARGS
+ git config remote.gerrit.fetch "+refs/heads/*:refs/remotes/gerrit/*" "/heads/"
+ ERROR_MESSAGE "Failed to set gerrit repo fetch refspec"
+ WORKING_DIRECTORY "${working_directory}")
+endfunction()
+
+# Handles the copy-objects option, which is used to detach alternates.
+# A copy of all git objects are made from the alternate repository to the current repository.
+# Then the alternates reference is removed.
+function(qt_ir_handle_detach_alternates working_directory)
+ qt_ir_get_option_value(copy-objects should_detach)
+ if(NOT should_detach)
+ return()
+ endif()
+
+ qt_ir_execute_process_and_log_and_handle_error(
+ COMMAND_ARGS git repack -a
+ ERROR_MESSAGE "Failed to repack objects to detach alternates"
+ WORKING_DIRECTORY "${working_directory}")
+
+ set(alternates_path "${working_directory}/.git/objects/info/alternates")
+ if(EXISTS "${alternates_path}")
+ file(REMOVE "${alternates_path}")
+ if(EXISTS "${alternates_path}")
+ message(FATAL_ERROR "Failed to remove alternates file: ${alternates_path}")
+ endif()
+ endif()
+endfunction()
+
+# Clones a submodule, unless it was previously cloned.
+# When cloning, checks out a specific branch if requested, otherwise does not
+# checkout any files yet, mimicking a bare repo.
+# Sets up an alternates link if requested.
+# Detaches alternates if requested.
+# Fetches refs if requested.
+# Adds a gerrit git remote.
+# Sets up the commit template for the submodule.
+function(qt_ir_clone_one_submodule submodule_name)
+ set(options
+ CHECKOUT_BRANCH
+ FETCH
+ )
+ set(oneValueArgs
+ ALTERNATES
+ BASE_URL
+ WORKING_DIRECTORY
+ )
+ set(multiValueArgs "")
+ cmake_parse_arguments(arg "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
+
+ qt_ir_get_working_directory_from_arg(working_directory)
+
+ set(clone_args "")
+ set(submodule_path "${${prefix}_${submodule_name}_path}")
+
+ if(arg_ALTERNATES)
+ # alternates is a qt5 repo, so the submodule will be under that.
+ set(alternates_dir "${arg_ALTERNATES}/${submodule_path}/.git")
+ if(EXISTS "${alternates_dir}")
+ list(APPEND clone_args --reference "${arg_ALTERNATES}/${submodule_path}")
+ else()
+ message(WARNING "'${arg_ALTERNATES}/${submodule_path}' not found, "
+ "ignoring alternate for this submodule")
+ endif()
+ endif()
+
+ if(NOT EXISTS "${working_directory}/${submodule_path}/.git")
+ set(should_clone TRUE)
+ else()
+ set(should_clone FALSE)
+ endif()
+
+ set(submodule_base_git_path "${${prefix}_${submodule_name}_base_git_path}")
+
+ set(submodule_url "${submodule_base_git_path}")
+ qt_ir_has_url_scheme("${submodule_url}" has_url_scheme)
+ if(NOT has_url_scheme AND arg_BASE_URL)
+ set(submodule_url "${arg_BASE_URL}${submodule_url}")
+ endif()
+
+ qt_ir_get_mirror(mirror_url)
+ set(mirror "")
+ if(NOT has_url_scheme AND mirror_url AND (should_clone OR arg_FETCH))
+ set(mirror "${mirror_url}${submodule_base_git_path}")
+ endif()
+
+ set(mirror_or_original_url "${submodule_url}")
+ if(mirror)
+ # Only use the mirror if it can be reached.
+ # Access a non-existing ref so no output is shown. It should still
+ # succeed if the mirror is accessible.
+ qt_ir_execute_process_and_log_and_handle_error(
+ COMMAND_ARGS git ls-remote "${mirror}" "test/if/mirror/exists"
+ WORKING_DIRECTORY "${working_directory}"
+ NO_HANDLE_ERROR
+ OUT_RESULT_VAR proc_result)
+ if(NOT proc_result EQUAL 0)
+ message("mirror [${mirror}] is not accessible; ${submodule_url} will be used")
+ set(mirror "")
+ else()
+ set(mirror_or_original_url "${mirror}")
+ endif()
+ endif()
+
+ set(submodule_branch "${${prefix}_${submodule_name}_branch}")
+
+ qt_ir_is_git_progress_supported(is_git_progress_supported)
+ qt_ir_get_option_value(quiet quiet)
+ qt_ir_get_option_value(perl-identical-output perl_identical_output_for_tests)
+
+ set(progress_args "")
+ if(is_git_progress_supported AND NOT quiet AND NOT perl_identical_output_for_tests)
+ set(progress_args --progress)
+ endif()
+
+ if(should_clone)
+ if(arg_CHECKOUT_BRANCH)
+ list(APPEND clone_args --branch "${submodule_branch}")
+ else()
+ list(APPEND clone_args --no-checkout)
+ endif()
+ list(APPEND clone_args ${progress_args})
+ qt_ir_execute_process_and_log_and_handle_error(
+ COMMAND_ARGS git clone ${clone_args} "${mirror_or_original_url}" "${submodule_path}"
+ ERROR_MESSAGE "Failed to clone submodule '${submodule_name}'"
+ WORKING_DIRECTORY "${working_directory}")
+ endif()
+
+ set(submodule_working_dir "${working_directory}/${submodule_path}")
+
+ if(mirror)
+ # This is only for the user's convenience - we make no use of it.
+ qt_ir_execute_process_and_log_and_handle_error(
+ COMMAND_ARGS git config "remote.mirror.url" "${mirror}"
+ ERROR_MESSAGE "Failed to set git config remote.mirror.url to ${mirror}"
+ WORKING_DIRECTORY "${submodule_working_dir}")
+ qt_ir_execute_process_and_log_and_handle_error(
+ COMMAND_ARGS git config "remote.mirror.fetch" "+refs/heads/*:refs/remotes/mirror/*"
+ ERROR_MESSAGE "Failed to set git config remote.mirror.fetch"
+ WORKING_DIRECTORY "${submodule_working_dir}")
+ endif()
+
+ if(NOT should_clone AND arg_FETCH)
+ # If we didn't clone, fetch from the right location. We always update
+ # the origin remote, so that submodule update --remote works.
+ qt_ir_execute_process_and_log_and_handle_error(
+ COMMAND_ARGS git config remote.origin.url "${mirror_or_original_url}"
+ ERROR_MESSAGE "Failed to set remote origin url"
+ WORKING_DIRECTORY "${submodule_working_dir}")
+ qt_ir_execute_process_and_log_and_handle_error(
+ COMMAND_ARGS git fetch origin ${progress_args}
+ ERROR_MESSAGE "Failed to fetch origin"
+ WORKING_DIRECTORY "${submodule_working_dir}")
+ endif()
+
+ if(NOT (should_clone OR arg_FETCH) OR mirror)
+ # Leave the origin configured to the canonical URL. It's already correct
+ # if we cloned/fetched without a mirror; otherwise it may be anything.
+ qt_ir_execute_process_and_log_and_handle_error(
+ COMMAND_ARGS git config remote.origin.url "${submodule_url}"
+ ERROR_MESSAGE "Failed to set remote origin url"
+ WORKING_DIRECTORY "${submodule_working_dir}")
+endif()
+
+ set(commit_template_dir "${working_directory}")
+ qt_ir_setup_commit_template("${commit_template_dir}" "${submodule_working_dir}")
+
+ if(NOT has_url_scheme)
+ qt_ir_add_git_remotes("${submodule_base_git_path}" "${submodule_working_dir}")
+ endif()
+
+ qt_ir_handle_detach_alternates("${submodule_working_dir}")
+endfunction()
+
+# Get list of submodules that were previously initialized, by looking at the .git/config file.
+function(qt_ir_get_already_initialized_submodules prefix
+ out_var_already_initialized_submodules
+ parent_repo_base_git_path
+ working_directory
+ )
+
+ qt_ir_parse_git_config_file_contents("${prefix}"
+ READ_GIT_CONFIG
+ PARENT_REPO_BASE_GIT_PATH "${parent_repo_base_git_path}"
+ WORKING_DIRECTORY "${working_directory}"
+ )
+
+ set(${out_var_already_initialized_submodules} "${${prefix}_submodules}" PARENT_SCOPE)
+endfunction()
+
+# If init-repository --force is called with a different subset, remove
+# previously initialized submodules from the .git/config file.
+# Also mark submodules as ignored if requested.
+function(qt_ir_handle_submodule_removal_and_ignoring prefix
+ included_submodules
+ parent_repo_base_git_path
+ working_directory
+ )
+
+ qt_ir_get_option_value(ignore-submodules ignore_submodules)
+
+ qt_ir_get_already_initialized_submodules("${prefix}"
+ already_initialized_submodules
+ "${parent_repo_base_git_path}"
+ "${working_directory}")
+
+ foreach(submodule_name IN LISTS already_initialized_submodules)
+ if(NOT submodule_name IN_LIST included_submodules)
+ # If a submodule is not included in the list of submodules to be initialized,
+ # and it was previously initialized, then remove it from the config.
+ qt_ir_execute_process_and_log_and_handle_error(
+ COMMAND_ARGS git config --remove-section "submodule.${submodule_name}"
+ ERROR_MESSAGE "Failed to deinit submodule '${submodule_name}'"
+ WORKING_DIRECTORY "${working_directory}")
+ continue()
+ endif()
+ if(ignore_submodules)
+ qt_ir_execute_process_and_log_and_handle_error(
+ COMMAND_ARGS git config "submodule.${submodule_name}.ignore" all
+ ERROR_MESSAGE "Failed to ignore submodule '${submodule_name}'"
+ WORKING_DIRECTORY "${working_directory}")
+ endif()
+ endforeach()
+endfunction()
+
+# Checks if the submodule is dirty (has uncommited changes).
+function(qt_ir_check_if_dirty_submodule submodule_name working_directory out_is_dirty)
+ set(submodule_path "${working_directory}/${${prefix}_${submodule_name}_path}")
+ if(NOT EXISTS "${submodule_path}/.git")
+ return()
+ endif()
+
+ qt_ir_execute_process_and_log_and_handle_error(
+ FORCE_QUIET
+ COMMAND_ARGS git status --porcelain --untracked=no --ignore-submodules=all
+ WORKING_DIRECTORY "${submodule_path}"
+ ERROR_MESSAGE "Failed to get dirty status for '${submodule_name}'"
+ OUT_OUTPUT_VAR git_output)
+
+ string(STRIP "${git_output}" git_output)
+ string(REPLACE "\n" ";" git_lines "${git_output}")
+
+ # After a git clone --no-checkout, git status reports all files as
+ # staged for deletion, but we still want to update the submodule.
+ # It's unlikely that a genuinely dirty index would have _only_ this
+ # type of modifications, and it doesn't seem like a horribly big deal
+ # to lose them anyway, so ignore them.
+ # @sts = grep(!/^D /, @sts);
+ # Filter list that starts with the regex
+ list(FILTER git_lines EXCLUDE REGEX "^D ")
+
+ if(git_lines)
+ message(STATUS "${submodule_name} is dirty.")
+ set(is_dirty TRUE)
+ else()
+ set(is_dirty FALSE)
+ endif()
+
+ set(${out_is_dirty} "${is_dirty}" PARENT_SCOPE)
+endfunction()
+
+# Checks if any submodules are dirty and exits early if any are.
+function(qt_ir_handle_dirty_submodule submodules working_directory)
+ set(any_is_dirty FALSE)
+ foreach(submodule_name IN LISTS submodules)
+ qt_ir_check_if_dirty_submodule("${submodule_name}" "${working_directory}" is_dirty)
+ if(is_dirty)
+ set(any_is_dirty TRUE)
+ endif()
+ endforeach()
+
+ if(any_is_dirty)
+ message(FATAL_ERROR "Dirty submodule(s) present; cannot proceed.")
+ endif()
+endfunction()
+
+# If the branch option is set, checkout the branch specified in the .gitmodules file.
+function(qt_ir_handle_branch_option prefix submodule_name working_directory)
+ set(branch_name "${${prefix}_${submodule_name}_branch}")
+ if(NOT branch_name)
+ message(FATAL_ERROR "No branch defined for submodule '${submodule_name}'")
+ endif()
+
+ set(repo_dir "${working_directory}/${${prefix}_${submodule_name}_path}")
+ qt_ir_execute_process_and_log_and_handle_error(
+ FORCE_QUIET
+ COMMAND_ARGS git rev-parse -q --verify ${branch_name}
+ WORKING_DIRECTORY "${repo_dir}"
+ NO_HANDLE_ERROR
+ OUT_RESULT_VAR proc_result)
+
+ # If the branch exists locally, check it out.
+ # Otherwise check it out from origin and create a local branch.
+ if(proc_result EQUAL 0)
+ qt_ir_execute_process_and_log_and_handle_error(
+ COMMAND_ARGS git checkout ${branch_name}
+ WORKING_DIRECTORY "${repo_dir}"
+ ERROR_MESSAGE
+ "Failed to checkout branch '${branch_name}' in submodule '${submodule_name}'")
+ else()
+ qt_ir_execute_process_and_log_and_handle_error(
+ COMMAND_ARGS git checkout -b ${branch_name} origin/${branch_name}
+ WORKING_DIRECTORY "${repo_dir}"
+ ERROR_MESSAGE
+ "Failed to checkout branch '${branch_name}' in submodule '${submodule_name}'")
+ endif()
+endfunction()
+
+# If the update option is set, update the submodules, without fetching.
+function(qt_ir_handle_update_option will_checkout_branch working_directory)
+ set(extra_args "")
+ if(will_checkout_branch)
+ list(APPEND extra_args --remote --rebase)
+ endif()
+
+ qt_ir_execute_process_and_log_and_handle_error(
+ COMMAND_ARGS git submodule update --force --no-fetch ${extra_args}
+ ERROR_MESSAGE "Failed to update submodule '${submodule_name}'"
+ WORKING_DIRECTORY "${working_directory}")
+endfunction()
+
+# Looks for the 'default' and 'existing' keys, and replaces them with appropriate
+# values, while making sure to prepend '-' to the values if the original key had it.
+function(qt_ir_handle_dash_in_module_subset_expansion out_var
+ module_subset already_initialized_submodules)
+
+ set(expanded_module_subset "")
+ foreach(submodule_name IN LISTS module_subset)
+ set(has_dash FALSE)
+ string(REGEX REPLACE "^(-)" "" submodule_name "${submodule_name}")
+ if(CMAKE_MATCH_1)
+ set(has_dash TRUE)
+ endif()
+
+ # Replace the default keyword in the input, with the the list of default submodules types,
+ # which will be further replaced.
+ if(submodule_name STREQUAL "default")
+ set(replacement "preview;essential;addon;deprecated")
+ # Replace the existing keyword, with the list of already initialized submodules
+ # from a previous run.
+ elseif(submodule_name STREQUAL "existing")
+ set(replacement "${already_initialized_submodules}")
+
+ if(has_dash)
+ # We can't properly support this with the existing algorithm, because we will
+ # then exclude it also after dependency resolution, and it can cause an empty list
+ # of submodules in certain situations.
+ message(FATAL_ERROR "Excluding existing submodules with '-existing' "
+ "is not supported, just don't include them.")
+ endif()
+ else()
+ set(replacement "${submodule_name}")
+ endif()
+
+ # Prepend dash to all expanded values
+ if(has_dash)
+ list(TRANSFORM replacement PREPEND "-")
+ endif()
+
+ list(APPEND expanded_module_subset "${replacement}")
+ endforeach()
+
+ set(${out_var} "${expanded_module_subset}" PARENT_SCOPE)
+endfunction()
+
+# Processes the given module subset using values that were set by parsing the .gitmodules file.
+#
+# The module subset is a comma-separated list of module names, with an optional '-' at the start.
+# If a - is present, the module (or special expanded keyword) is excluded from the subset.
+# If the value is empty, the default subset is used on initial runs, or the previously
+# existing submodules are used on subsequent runs.
+# If the value is "all", all known submodules are included.
+# If the value is a status like 'addon' or 'essential', only submodules with that status are
+# included.
+# If the value is 'existing', only submodules that were previously initialized are included.
+# This evaluates to an empty list for the first script run.
+# If the value is a module name, only that module is included.
+# The modules to exclude are also set separately, so they can be excluded even after dependency
+# resolution which is done later.
+function(qt_ir_process_module_subset_values prefix)
+ set(options
+ PREVIOUSLY_INITIALIZED
+ )
+ set(oneValueArgs
+ OUT_VAR_INCLUDE
+ OUT_VAR_EXCLUDE
+ )
+ set(multiValueArgs
+ ALREADY_INITIALIZED_SUBMODULES
+ EXTRA_IMPLICIT_SUBMODULES
+ MODULE_SUBSET
+ )
+ cmake_parse_arguments(arg "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
+
+ string(REPLACE "," ";" module_subset "${arg_MODULE_SUBSET}")
+
+ # If a module subset is not specified, either use the default list for the very first run,
+ # or use the previously initialized submodules for a subsequent run.
+ #
+ # If the are no previously initialized submodules, and 'existing' is specified, default
+ # to 'default'. This handles the case when someone runs git submodule deinit --all --force,
+ # where git initrepository.initialized config key is still true, and then runs
+ # configure -init-submodules. Without defaulting to default, we would end up with an empty
+ # subset and configure would fail.
+ if(NOT module_subset)
+ if(arg_PREVIOUSLY_INITIALIZED)
+ if(arg_ALREADY_INITIALIZED_SUBMODULES)
+ set(module_subset "existing")
+ else()
+ message(DEBUG "No previously initialized submodules detected even though "
+ "'existing' was specified, defaulting to 'default'")
+ set(module_subset "default")
+ endif()
+ else()
+ set(module_subset "default")
+ endif()
+ endif()
+
+
+ qt_ir_handle_dash_in_module_subset_expansion(
+ expanded_module_subset "${module_subset}" "${arg_ALREADY_INITIALIZED_SUBMODULES}")
+
+ set(include_modules "")
+ set(exclude_modules "")
+
+ if(arg_EXTRA_IMPLICIT_SUBMODULES)
+ list(APPEND include_modules ${arg_EXTRA_IMPLICIT_SUBMODULES})
+ endif()
+
+ foreach(value IN LISTS expanded_module_subset ${prefix}_submodules_to_remove)
+ # An '-' at the start means we should exclude those modules.
+ string(REGEX REPLACE "^(-)" "" value "${value}")
+ set(list_op "APPEND")
+ if(CMAKE_MATCH_1)
+ set(list_op "REMOVE_ITEM")
+ endif()
+
+ if(value STREQUAL "all")
+ list(${list_op} include_modules "${${prefix}_submodules}")
+ if("${list_op}" STREQUAL "REMOVE_ITEM")
+ list(APPEND exclude_modules "${${prefix}_submodules}")
+ endif()
+ elseif(value IN_LIST ${prefix}_statuses)
+ list(${list_op} include_modules "${${prefix}_status_${value}_submodules}")
+ if("${list_op}" STREQUAL "REMOVE_ITEM")
+ list(APPEND exclude_modules "${${prefix}_status_${value}_submodules}")
+ endif()
+ elseif(NOT "${${prefix}_${value}_path}" STREQUAL "")
+ list(${list_op} include_modules "${value}")
+ if("${list_op}" STREQUAL "REMOVE_ITEM")
+ list(APPEND exclude_modules "${value}")
+ endif()
+ else()
+ if(list_op STREQUAL "REMOVE_ITEM")
+ message(WARNING "Excluding non-existent module: ${value}")
+ else()
+ message(FATAL_ERROR
+ "Invalid module subset specified, module name is non-existent: ${value}")
+ endif()
+ endif()
+ endforeach()
+
+ set(${arg_OUT_VAR_INCLUDE} "${include_modules}" PARENT_SCOPE)
+ set(${arg_OUT_VAR_EXCLUDE} "${exclude_modules}" PARENT_SCOPE)
+endfunction()
+
+# Sort the modules and add dependencies if dependency resolving is enabled.
+function(qt_ir_get_module_subset_including_deps prefix out_var initial_modules)
+ qt_ir_get_option_value(resolve-deps resolve_deps)
+ qt_ir_get_option_value(optional-deps include_optional_deps)
+ if(resolve_deps)
+ set(exclude_optional_deps "")
+ if(NOT include_optional_deps)
+ set(exclude_optional_deps EXCLUDE_OPTIONAL_DEPS)
+ endif()
+
+ qt_internal_sort_module_dependencies("${initial_modules}" out_repos
+ ${exclude_optional_deps}
+ PARSE_GITMODULES
+ GITMODULES_PREFIX_VAR "${prefix}"
+ )
+ else()
+ set(out_repos "${initial_modules}")
+ endif()
+
+ qt_ir_get_option_value(perl-identical-output perl_identical_output_for_tests)
+ if(NOT perl_identical_output_for_tests)
+ message(DEBUG "repos that will be initialized after dependency handling: ${out_repos}")
+ endif()
+
+ set(${out_var} "${out_repos}" PARENT_SCOPE)
+endfunction()
+
+# Check whether init-repository has been run before, perl style.
+# We assume that if the submodule qtbase has been initialized, then init-repository has been run.
+function(qt_ir_check_if_already_initialized_perl_style out_var_is_initialized working_directory)
+ set(cmd git config --get submodule.qtbase.url)
+
+ set(extra_args "")
+ qt_ir_get_option_value(perl-identical-output perl_identical_output_for_tests)
+ if(perl_identical_output_for_tests)
+ list(APPEND extra_args FORCE_QUIET)
+ endif()
+
+ qt_ir_execute_process_and_log_and_handle_error(
+ COMMAND_ARGS ${cmd}
+ OUT_RESULT_VAR git_result
+ OUT_OUTPUT_VAR git_output
+ OUT_ERROR_VAR git_error
+ ${extra_args}
+ NO_HANDLE_ERROR
+ WORKING_DIRECTORY "${working_directory}")
+
+ if(git_result EQUAL 1 AND NOT git_output)
+ set(is_initialized FALSE)
+ elseif(git_result EQUAL 0 AND git_output)
+ set(is_initialized TRUE)
+ else()
+ message(FATAL_ERROR "Failed to get result of ${cmd}: ${git_output}")
+ endif()
+
+ set(${out_var_is_initialized} "${is_initialized}" PARENT_SCOPE)
+endfunction()
+
+# Check whether init-repository has been run before, cmake style.
+# Check for the presence of the initrepository.initialized git config key.
+function(qt_ir_check_if_already_initialized_cmake_style out_var_is_initialized working_directory)
+ set(options
+ FORCE_QUIET
+ )
+ set(oneValueArgs "")
+ set(multiValueArgs "")
+ cmake_parse_arguments(arg "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
+
+ set(cmd git config --get initrepository.initialized)
+
+ set(extra_args "")
+ if(arg_FORCE_QUIET)
+ list(APPEND extra_args FORCE_QUIET)
+ endif()
+
+ qt_ir_execute_process_and_log_and_handle_error(
+ COMMAND_ARGS ${cmd}
+ OUT_RESULT_VAR git_result
+ OUT_OUTPUT_VAR git_output
+ OUT_ERROR_VAR git_error
+ ${extra_args}
+ NO_HANDLE_ERROR
+ WORKING_DIRECTORY "${working_directory}")
+
+ if(git_result EQUAL 1 AND NOT git_output)
+ set(is_initialized FALSE)
+ elseif(git_result EQUAL 0 AND git_output)
+ set(is_initialized TRUE)
+ else()
+ message(FATAL_ERROR "Failed to get result of ${cmd}: ${git_output}")
+ endif()
+
+ set(${out_var_is_initialized} "${is_initialized}" PARENT_SCOPE)
+endfunction()
+
+# Check whether init-repository has been run before.
+# The CMake and perl script do it differently, choose which way to do it based
+# on the active options.
+function(qt_ir_check_if_already_initialized out_var_is_initialized working_directory)
+ qt_ir_get_option_value(perl-init-check perl_init_check)
+ if(perl_init_check)
+ qt_ir_check_if_already_initialized_perl_style(is_initialized "${working_directory}")
+ else()
+ qt_ir_check_if_already_initialized_cmake_style(is_initialized "${working_directory}")
+ endif()
+
+ set(${out_var_is_initialized} "${is_initialized}" PARENT_SCOPE)
+endfunction()
+
+# Marks the repository as initialized.
+# The perl script used to determine this by checking whether the qtbase submodule was initialized.
+# In the CMake script, we instead opt to set an explicit marker in the repository.
+function(qt_ir_set_is_initialized working_directory)
+ # If emulating perl style initialization check, don't set the marker and exit early.
+ qt_ir_get_option_value(perl-init-check perl_init_check)
+ if(perl_init_check)
+ return()
+ endif()
+
+ set(cmd git config initrepository.initialized true)
+
+ set(extra_args "")
+ qt_ir_get_option_value(perl-identical-output perl_identical_output_for_tests)
+ if(perl_identical_output_for_tests)
+ list(APPEND extra_args FORCE_QUIET)
+ endif()
+
+ qt_ir_execute_process_and_log_and_handle_error(
+ COMMAND_ARGS ${cmd}
+ ERROR_MESSAGE "Failed to mark repository as initialized"
+ ${extra_args}
+ WORKING_DIRECTORY "${working_directory}")
+endfunction()
+
+# If the repository has already been initialized, exit early.
+function(qt_ir_handle_if_already_initialized out_var_should_exit working_directory)
+ set(should_exit FALSE)
+
+ qt_ir_check_if_already_initialized(is_initialized "${working_directory}")
+ qt_ir_get_option_value(force force)
+ qt_ir_get_option_value(quiet quiet)
+ qt_ir_is_called_from_configure(is_called_from_configure)
+
+ if(is_initialized)
+ if(NOT force)
+ set(should_exit TRUE)
+ if(NOT quiet AND NOT is_called_from_configure)
+ message(
+ "Will not reinitialize already initialized repository (use -f to force)!")
+ endif()
+ endif()
+ endif()
+
+ set(${out_var_should_exit} ${should_exit} PARENT_SCOPE)
+endfunction()
+
+# Parses git remote.origin.url and extracts the base url and the repository name.
+#
+# base_url example: git://code.qt.io/qt
+# repo name example: qt5 or tqtc-qt5
+function(qt_ir_get_qt5_repo_name_and_base_url)
+ set(options "")
+ set(oneValueArgs
+ OUT_VAR_QT5_REPO_NAME
+ OUT_VAR_BASE_URL
+ WORKING_DIRECTORY
+ )
+ set(multiValueArgs "")
+ cmake_parse_arguments(arg "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
+
+ if(NOT arg_WORKING_DIRECTORY)
+ message(FATAL_ERROR "qt_ir_get_qt5_repo_name_and_base_url: No working directory specified")
+ endif()
+ set(working_directory "${arg_WORKING_DIRECTORY}")
+
+ qt_ir_get_option_value(perl-identical-output perl_identical_output_for_tests)
+
+ set(extra_args "")
+ if(perl_identical_output_for_tests)
+ set(extra_args FORCE_QUIET)
+ endif()
+
+ qt_ir_execute_process_and_log_and_handle_error(
+ COMMAND_ARGS git config remote.origin.url ${extra_args}
+ ERROR_MESSAGE "No origin remote found for qt5 repository"
+ OUT_OUTPUT_VAR git_output
+ WORKING_DIRECTORY "${working_directory}")
+
+ string(STRIP "${git_output}" git_output)
+
+ # Remove the .git at the end, with an optional slash
+ string(REGEX REPLACE ".git/?$" "" qt5_repo_name "${git_output}")
+
+ # Remove the tqtc- prefix, if it exists, and the qt5 suffix and that will be the base_url
+ # The qt5_repo_name is qt5 or tqtc-qt5.
+ string(REGEX REPLACE "((tqtc-)?qt5)$" "" base_url "${qt5_repo_name}")
+ set(qt5_repo_name "${CMAKE_MATCH_1}")
+
+ if(NOT qt5_repo_name)
+ set(qt5_repo_name "qt5")
+ endif()
+
+ if(NOT base_url)
+ message(FATAL_ERROR "Failed to parse base url from origin remote: ${git_output}")
+ endif()
+
+ set(${arg_OUT_VAR_QT5_REPO_NAME} "${qt5_repo_name}" PARENT_SCOPE)
+ set(${arg_OUT_VAR_BASE_URL} "${base_url}" PARENT_SCOPE)
+endfunction()
+
+# Creates a symlink or a forwarding script to the target path.
+# Use for setting up git hooks.
+function(qt_ir_ensure_link source_path target_path)
+ qt_ir_get_option_value(force-hooks force_hooks)
+ if(EXISTS "${target_path}" AND NOT force_hooks)
+ return()
+ endif()
+
+ # In case we have a dead symlink or pre-existing hook
+ file(REMOVE "${target_path}")
+
+ qt_ir_get_option_value(quiet quiet)
+ if(NOT quiet)
+ message("Aliasing ${source_path}\n as ${target_path} ...")
+ endif()
+
+ if(NOT CMAKE_HOST_WIN32)
+ file(CREATE_LINK "${source_path}" "${target_path}" RESULT result SYMBOLIC)
+ # Don't continue upon success. If symlinking failed, fallthrough to creating
+ # a forwarding script.
+ if(result EQUAL 0)
+ return()
+ endif()
+ endif()
+
+ # Windows doesn't do (proper) symlinks. As the post_commit script needs
+ # them to locate itself, we write a forwarding script instead.
+
+ # Make the path palatable for MSYS.
+ string(REGEX REPLACE "^(.):/" "/\\1/" source_path "${source_path}")
+
+ set(contents "#!/bin/sh\nexec ${source_path} \"$@\"\n")
+ file(WRITE "${target_path}" "${contents}")
+endfunction()
+
+# Installs the git hooks from the qtrepotools module.
+function(qt_ir_install_git_hooks)
+ set(options "")
+ set(oneValueArgs
+ PARENT_REPO_BASE_GIT_PATH
+ TOP_LEVEL_SRC_PATH
+ WORKING_DIRECTORY
+ )
+ set(multiValueArgs "")
+ cmake_parse_arguments(arg "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
+
+ if(NOT arg_WORKING_DIRECTORY)
+ message(FATAL_ERROR "qt_ir_install_git_hooks: No working directory specified")
+ endif()
+ set(working_directory "${arg_WORKING_DIRECTORY}")
+
+ if(NOT arg_PARENT_REPO_BASE_GIT_PATH)
+ message(FATAL_ERROR "qt_ir_install_git_hooks: No PARENT_REPO_BASE_GIT_PATH specified")
+ endif()
+ set(parent_repo_base_git_path "${arg_PARENT_REPO_BASE_GIT_PATH}")
+
+ if(NOT arg_TOP_LEVEL_SRC_PATH)
+ message(FATAL_ERROR "qt_ir_install_git_hooks: No TOP_LEVEL_SRC_PATH specified")
+ endif()
+ set(top_level_src_path "${arg_TOP_LEVEL_SRC_PATH}")
+
+ set(hooks_dir "${top_level_src_path}/qtrepotools/git-hooks")
+ if(NOT EXISTS "${hooks_dir}")
+ message("Warning: cannot find Git hooks, qtrepotools module might be absent")
+ return()
+ endif()
+
+ set(prefix ir_hooks)
+ qt_ir_parse_git_config_file_contents("${prefix}"
+ READ_GIT_CONFIG_LOCAL
+ PARENT_REPO_BASE_GIT_PATH "${parent_repo_base_git_path}"
+ WORKING_DIRECTORY "${working_directory}"
+ )
+
+ foreach(submodule_name IN LISTS ${prefix}_submodules)
+ set(submodule_git_dir "${working_directory}/${submodule_name}/.git")
+ if(NOT IS_DIRECTORY "${submodule_git_dir}")
+ # Get first line
+ file(STRINGS "${submodule_git_dir}" submodule_git_dir_contents LIMIT_COUNT 1)
+
+ # Remove the gitdir: prefix
+ string(REGEX REPLACE "^(gitdir: )" "" submodule_git_dir
+ "${submodule_git_dir_contents}")
+ if("${CMAKE_MATCH_1}" STREQUAL "")
+ message(FATAL_ERROR "Malformed .git file ${submodule_git_dir}")
+ endif()
+
+ # Make it an absolute path, because gitdir: is usually relative to the submodule
+ get_filename_component(submodule_git_dir "${submodule_git_dir}"
+ ABSOLUTE BASE_DIR "${working_directory}/${submodule_name}")
+
+ # Untested
+ set(common_dir "${submodule_git_dir}/commondir")
+ if(EXISTS "${common_dir}")
+ file(STRINGS "${common_dir}" common_dir_contents LIMIT_COUNT 1)
+ string(STRIP "${common_dir_contents}" common_dir_path)
+ set(submodule_git_dir "${submodule_git_dir}/${common_dir_path}")
+ get_filename_component(submodule_git_dir "${submodule_git_dir}" ABSOLUTE)
+ endif()
+ endif()
+ qt_ir_ensure_link("${hooks_dir}/gerrit_commit_msg_hook"
+ "${submodule_git_dir}/hooks/commit-msg")
+ qt_ir_ensure_link("${hooks_dir}/git_post_commit_hook"
+ "${submodule_git_dir}/hooks/post-commit")
+ qt_ir_ensure_link("${hooks_dir}/clang-format-pre-commit"
+ "${submodule_git_dir}/hooks/pre-commit")
+ endforeach()
+endfunction()
+
+# Saves the list of top-level submodules that should be included and excluded.
+# Will be used to pass these values to the top-level configure script.
+function(qt_ir_set_top_level_submodules included_submodules excluded_submodules)
+ set_property(GLOBAL PROPERTY _qt_ir_top_level_included_submodules "${included_submodules}")
+ set_property(GLOBAL PROPERTY _qt_ir_top_level_excluded_submodules "${excluded_submodules}")
+endfunction()
+
+# Gets the list of top-level submodules that should be included and excluded.
+function(qt_ir_get_top_level_submodules out_included_submodules out_excluded_submodules)
+ get_property(included GLOBAL PROPERTY _qt_ir_top_level_included_submodules)
+ get_property(excluded GLOBAL PROPERTY _qt_ir_top_level_excluded_submodules)
+
+ set(${out_included_submodules} "${included}" PARENT_SCOPE)
+ set(${out_excluded_submodules} "${excluded}" PARENT_SCOPE)
+endfunction()
+
+# Parses the .gitmodules file and proceses the submodules based on the module-subset option
+# or the given SUBMODULES argument.
+# Also adds dependencies if requested.
+#
+# This is a macro because we want the variables set by
+# qt_ir_parse_gitmodules_file_contents to be available in the calling scope, because it's
+# essentially setting a dictionarty, and we don't want to propagate all the variables manually.
+macro(qt_ir_get_submodules prefix out_var_submodules)
+ set(options
+ PREVIOUSLY_INITIALIZED
+ PROCESS_SUBMODULES_FROM_COMMAND_LINE
+ )
+ set(oneValueArgs
+ PARENT_REPO_BASE_GIT_PATH
+ WORKING_DIRECTORY
+ )
+ set(multiValueArgs
+ ALREADY_INITIALIZED_SUBMODULES
+ SUBMODULES
+ )
+ cmake_parse_arguments(arg "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
+
+ qt_ir_get_working_directory_from_arg(working_directory)
+
+ # Parse the .gitmodules content here, so the parsed data is available downstream
+ # in other functions and recursive calls of the same function.
+ qt_ir_parse_git_config_file_contents("${prefix}"
+ READ_GITMODULES
+ PARENT_REPO_BASE_GIT_PATH "${arg_PARENT_REPO_BASE_GIT_PATH}"
+ WORKING_DIRECTORY "${working_directory}"
+ )
+
+ qt_ir_get_option_value(perl-identical-output perl_identical_output_for_tests)
+ set(extra_implict_submodules "")
+
+ # Get which modules should be initialized, based on the module-subset option.
+ if(arg_PROCESS_SUBMODULES_FROM_COMMAND_LINE)
+ qt_ir_get_option_value(module-subset initial_module_subset)
+
+ # Implicitly add qtrepotools, so we can install git hooks and don't get the
+ # missing qtrepotools warning.
+ if(NOT perl_identical_output_for_tests)
+ list(APPEND extra_implict_submodules "qtrepotools")
+ qt_ir_is_verbose(verbose)
+ if(verbose)
+ message("Implicitly adding qtrepotools to the list of submodules "
+ "to initialize for access to git commit hooks, etc. "
+ "(use --module-subset=<values>,-qtrepotools to exclude it)")
+ endif()
+ endif()
+
+ if(NOT perl_identical_output_for_tests)
+ message(DEBUG "module-subset from command line: ${initial_module_subset}")
+ endif()
+ elseif(arg_SUBMODULES)
+ set(initial_module_subset "${arg_SUBMODULES}")
+ if(NOT perl_identical_output_for_tests)
+ message(DEBUG "module-subset from args: ${initial_module_subset}")
+ endif()
+ else()
+ message(FATAL_ERROR "No submodules specified")
+ endif()
+
+ qt_ir_get_cmake_flag(PREVIOUSLY_INITIALIZED previously_initialized_opt)
+ qt_ir_process_module_subset_values("${prefix}"
+ ${previously_initialized_opt}
+ ${perl_identical_output_opt}
+ ALREADY_INITIALIZED_SUBMODULES ${arg_ALREADY_INITIALIZED_SUBMODULES}
+ EXTRA_IMPLICIT_SUBMODULES ${extra_implict_submodules}
+ MODULE_SUBSET "${initial_module_subset}"
+ OUT_VAR_INCLUDE processed_module_subset
+ OUT_VAR_EXCLUDE modules_to_exclude
+ )
+ if(NOT perl_identical_output_for_tests)
+ message(DEBUG "Processed module subset: ${processed_module_subset}")
+ endif()
+
+ # We only resolve dependencies for the top-level call, not for recursive calls.
+ if(arg_PROCESS_SUBMODULES_FROM_COMMAND_LINE)
+ # Resolve which submodules should be initialized, including dependencies.
+ qt_ir_get_module_subset_including_deps("${prefix}"
+ submodules_with_deps "${processed_module_subset}")
+
+ # Then remove any explicitly specified submodules.
+ set(submodules_with_deps_and_excluded "${submodules_with_deps}")
+ if(modules_to_exclude)
+ list(REMOVE_ITEM submodules_with_deps_and_excluded ${modules_to_exclude})
+ endif()
+
+ if(NOT perl_identical_output_for_tests AND modules_to_exclude)
+ message(DEBUG "Repos that will be excluded after dependency handling: ${modules_to_exclude}")
+ endif()
+
+ set(submodules "${submodules_with_deps_and_excluded}")
+ qt_ir_set_top_level_submodules("${submodules}" "${modules_to_exclude}")
+ else()
+ set(submodules "${processed_module_subset}")
+ endif()
+
+ # Remove duplicates
+ set(submodules_maybe_duplicates "${submodules}")
+ list(REMOVE_DUPLICATES submodules)
+ if(NOT perl_identical_output_for_tests AND NOT submodules STREQUAL submodules_maybe_duplicates)
+ message(DEBUG "Removed duplicates from submodules, final list: ${submodules}")
+ endif()
+
+ set(${out_var_submodules} "${submodules}" PARENT_SCOPE)
+endmacro()
+
+# Recursively initialize submodules starting from the given current working directory.
+# This is the equivalent of the perl script's git_clone_all_submodules function.
+function(qt_ir_handle_init_submodules prefix)
+ set(options
+ CHECKOUT_BRANCH
+ PREVIOUSLY_INITIALIZED
+ PROCESS_SUBMODULES_FROM_COMMAND_LINE
+ )
+ set(oneValueArgs
+ ALTERNATES
+ BASE_URL
+ PARENT_REPO_BASE_GIT_PATH
+ WORKING_DIRECTORY
+ )
+ set(multiValueArgs
+ ALREADY_INITIALIZED_SUBMODULES
+ SUBMODULES
+ )
+ cmake_parse_arguments(arg "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
+
+ qt_ir_get_working_directory_from_arg(working_directory)
+
+ # Get the submodules that should be initialized.
+ qt_ir_get_cmake_flag(PROCESS_SUBMODULES_FROM_COMMAND_LINE
+ process_submodules_from_command_line_opt)
+ qt_ir_get_cmake_flag(PREVIOUSLY_INITIALIZED
+ previously_initialized_opt)
+ qt_ir_get_submodules(${prefix} submodules
+ ${process_submodules_from_command_line_opt}
+ ${previously_initialized_opt}
+ ALREADY_INITIALIZED_SUBMODULES ${arg_ALREADY_INITIALIZED_SUBMODULES}
+ PARENT_REPO_BASE_GIT_PATH "${arg_PARENT_REPO_BASE_GIT_PATH}"
+ SUBMODULES "${arg_SUBMODULES}"
+ WORKING_DIRECTORY "${working_directory}"
+ )
+
+ qt_ir_get_option_value(perl-identical-output perl_identical_output_for_tests)
+ if(NOT submodules AND NOT perl_identical_output_for_tests)
+ message("No submodules were given to initialize or they were all excluded.")
+ return()
+ endif()
+
+ # Initialize the submodules, but don't clone them yet.
+ qt_ir_run_git_submodule_init("${submodules}" "${working_directory}")
+
+ # Deinit submodules that are not in the list of submodules to be initialized.
+ qt_ir_handle_submodule_removal_and_ignoring("${prefix}"
+ "${submodules}" "${arg_PARENT_REPO_BASE_GIT_PATH}" "${working_directory}")
+
+ # Check for dirty submodules.
+ qt_ir_handle_dirty_submodule("${submodules}" "${working_directory}")
+
+ qt_ir_get_cmake_flag(CHECKOUT_BRANCH branch_flag)
+ qt_ir_get_option_as_cmake_flag_option(fetch "FETCH" fetch_flag)
+
+ # Manually clone each submodule if it was not previously cloned, so we can easily
+ # use reference (alternates) repos, mirrors, etc.
+ # If already cloned, just fetch new data.
+ #
+ # Note that manually cloning the submodules, as opposed to running git submodule update,
+ # places the .git directories inside the submodule directories, but latest git versions
+ # expect it in $super_repo/.git/modules.
+ # When de-initializing submodules manually, git will absorb the .git directories into the super
+ # repo.
+ # In case if the super repo already has a copy of the submodule .git dir, git will fail
+ # to absorb the .git dir and error out. In that case the already existing .git dir needs to be
+ # removed manually, there is no git command to do it afaik.
+ foreach(submodule_name IN LISTS submodules)
+ qt_ir_clone_one_submodule(${submodule_name}
+ ALTERNATES ${arg_ALTERNATES}
+ BASE_URL ${arg_BASE_URL}
+ WORKING_DIRECTORY "${working_directory}"
+ ${branch_flag}
+ ${fetch_flag}
+ )
+ endforeach()
+
+ # Checkout branches instead of the default detached HEAD.
+ if(branch_flag)
+ foreach(submodule_name IN LISTS submodules)
+ qt_ir_handle_branch_option("${prefix}" ${submodule_name} "${working_directory}")
+ endforeach()
+ endif()
+
+ qt_ir_get_option_value(update will_update)
+ if(will_update)
+
+ # Update the checked out refs without fetching.
+ qt_ir_handle_update_option("${branch_flag}" "${working_directory}")
+
+ # Recursively initialize submodules of submodules.
+ foreach(submodule_name IN LISTS submodules)
+ set(submodule_path "${${prefix}_${submodule_name}_path}")
+ set(submodule_gitmodules_path "${working_directory}/${submodule_path}/.gitmodules")
+
+ if(EXISTS "${submodule_gitmodules_path}")
+ set(alternates_option "")
+ if(arg_ALTERNATES)
+ set(alternates_option ALTERNATES "${arg_ALTERNATES}/${submodule_name}")
+ endif()
+
+ set(submodule_base_git_path "${${prefix}_${submodule_name}_base_git_path}")
+
+ qt_ir_handle_init_submodules(
+ # Use a different prefix to store new gitmodules data
+ ir_sub_${submodule_name}
+
+ # Check out all submodules recursively
+ SUBMODULES "all"
+
+ BASE_URL "${base_url}"
+ PARENT_REPO_BASE_GIT_PATH "${submodule_base_git_path}"
+ WORKING_DIRECTORY "${working_directory}/${submodule_name}"
+
+ # The CHECKOUT_BRANCH option is not propagated on purpose
+ ${alternates_option}
+ )
+ endif()
+ endforeach()
+ endif()
+endfunction()
diff --git a/cmake/QtIRHelp.txt b/cmake/QtIRHelp.txt
new file mode 100644
index 00000000..9d6f5749
--- /dev/null
+++ b/cmake/QtIRHelp.txt
@@ -0,0 +1,134 @@
+Usage:
+ ./init-repository [options]
+
+ This script may be run after an initial `git clone' of the Qt supermodule
+ in order to check out all submodules. It fetches them from canonical URLs
+ inferred from the clone's origin.
+
+Options:
+ Global options:
+
+ --force, -f
+ Force initialization (even if the submodules are already checked
+ out).
+
+ --force-hooks
+ Force initialization of hooks (even if there are already hooks in
+ checked out submodules).
+
+ --quiet, -q
+ Be quiet. Will exit cleanly if the repository is already
+ initialized.
+
+ --verbose
+ Adds a bit more output when executing processes
+
+ --no-resolve-deps
+ By default, each submodule specified via the module-subset option
+ will have its required and optional dependencies also initialized.
+ This option can be passed to disable automatic initialization of
+ dependencies, so that the exact list passed to module-subset is
+ initialized.
+
+ --no-optional-deps
+ By default, each submodule specified via the module-subset option
+ will have its optional dependencies also initialized.
+ This option can be passed to initialize only required dependencies of
+ the given module-subset.
+
+ Module options:
+
+ --module-subset=<module1>,<module2>... / -submodules <module1>,<module2>...
+ Only initialize the specified subset of modules given as the
+ argument. Specified modules must already exist in .gitmodules. The
+ string "all" results in cloning all known modules. The strings
+ "essential", "addon", "preview", "deprecated", "obsolete",
+ "additionalLibrary", and "ignore" refer to classes of modules
+ identified by "status=" lines in the .gitmodules file.
+ You can use "existing" to to reference already initialized submodules.
+ Additionally, "qtrepotools" is implicitly always added to ensure
+ relevant git commit hooks are available. It can be excluded as described
+ below.
+ You can use "default" in the subset as a short-hand for
+ "essential,addon,preview,deprecated", which corresponds to the set of
+ maintained modules included in standard Qt releases; this is also the
+ default module subset when this option is not given when first running
+ init-repositoy. If init-repository is rerun a second time (with --force)
+ the default is to initialize the "existing" submodules, rather than the
+ default subset. Entries may be prefixed with a dash to exclude them
+ from a bigger set, e.g. "all,-ignore" or "existing,-qttools".
+ For compatibility with qt's configure script, -submodules is an alias
+ of --module-subset. Note the difference in dashes and the equal sign.
+
+ --no-update
+ Skip the `git submodule update' command.
+
+ --no-fetch
+ Skip the `git fetch' commands. Implied by --no-update.
+
+ --branch
+ Instead of checking out specific SHA1s, check out the submodule
+ branches that correspond with the current supermodule commit. By
+ default, this option will cause local commits in the submodules to
+ be rebased. With --no-update, the branches will be checked out, but
+ their heads will not move.
+
+ --ignore-submodules
+ Set git config to ignore submodules by default when doing operations
+ on the qt5 repo, such as `pull', `fetch', `diff' etc.
+
+ After using this option, pass `--ignore-submodules=none' to git to
+ override it as needed.
+
+ Repository options:
+
+ --berlin
+ Switch to internal URLs and make use of the Berlin git mirrors.
+ (Implies `--mirror').
+
+ --oslo
+ Switch to internal URLs and make use of the Oslo git mirrors.
+ (Implies `--mirror').
+
+ --codereview-username <Gerrit/JIRA username>
+ Specify the user name for the (potentially) writable `gerrit' remote
+ for each module, for use with the Gerrit code review tool.
+
+ If this option is omitted, the gerrit remote is created without a
+ username and port number, and thus relies on a correct SSH
+ configuration.
+
+ --alternates <path to other Qt5 repo>
+ Adds alternates for each submodule to another full qt5 checkout.
+ This makes this qt5 checkout very small, as it will use the object
+ store of the alternates before unique objects are stored in its own
+ object store.
+
+ This option has no effect when using `--no-update'.
+
+ NOTE: This will make this repo dependent on the alternate, which is
+ potentially dangerous! The dependency can be broken by also using
+ the `--copy-objects' option, or by running "git repack -a" in each
+ submodule, where required. Please read the note about the `--shared'
+ option in the documentation of `git clone' for more information.
+
+ --copy-objects
+ When `--alternates' is used, automatically do a "git repack -a" in
+ each submodule after cloning, to ensure that the repositories are
+ independent from the source used as a reference for cloning.
+
+ Note that this negates the disk usage benefits gained from the use
+ of `--alternates'.
+ --mirror <url-base>
+ Uses <url-base> as the base URL for submodule git mirrors.
+
+ For example:
+
+ --mirror user\@machine:/foo/bar/qt/
+
+ ...will use the following as a mirror for qtbase:
+
+ user\@machine:/foo/bar/qt/qtbase.git
+
+ The mirror is permitted to contain a subset of the submodules; any
+ missing modules will fall back to the canonical URLs.
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()
diff --git a/cmake/QtIROptionsHelpers.cmake b/cmake/QtIROptionsHelpers.cmake
new file mode 100644
index 00000000..d87c7463
--- /dev/null
+++ b/cmake/QtIROptionsHelpers.cmake
@@ -0,0 +1,48 @@
+# Copyright (C) 2024 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+# Declare command line options known to init-repository.
+macro(qt_ir_set_known_command_line_options)
+ # Implemented options
+
+ # Note alternates is a qt specific option name, but it uses
+ # git submodule's --reference option underneath which also implies --shared.
+ # It essentially uses the git object storage of another repo, to avoid
+ # cloning the same objects and thus saving space.
+ qt_ir_commandline_option(alternates TYPE string)
+
+ qt_ir_commandline_option(berlin TYPE boolean)
+ qt_ir_commandline_option(branch TYPE boolean)
+ qt_ir_commandline_option(codereview-username TYPE string)
+ qt_ir_commandline_option(copy-objects TYPE boolean)
+ qt_ir_commandline_option(fetch TYPE boolean DEFAULT_VALUE yes)
+ qt_ir_commandline_option(force SHORT_NAME f TYPE boolean)
+ qt_ir_commandline_option(force-hooks TYPE boolean)
+ qt_ir_commandline_option(help SHORT_NAME h TYPE boolean)
+ qt_ir_commandline_option(ignore-submodules TYPE boolean)
+ qt_ir_commandline_option(mirror TYPE string)
+ qt_ir_commandline_option(module-subset TYPE string)
+ qt_ir_commandline_option(optional-deps TYPE boolean DEFAULT_VALUE yes)
+ qt_ir_commandline_option(oslo TYPE boolean)
+ qt_ir_commandline_option(perl-identical-output TYPE boolean)
+ qt_ir_commandline_option(perl-init-check TYPE boolean)
+ qt_ir_commandline_option(quiet SHORT_NAME q TYPE boolean)
+ qt_ir_commandline_option(resolve-deps TYPE boolean DEFAULT_VALUE yes)
+ qt_ir_commandline_option(update TYPE boolean DEFAULT_VALUE yes)
+ qt_ir_commandline_option(verbose TYPE boolean)
+
+ # These are used when init-repository is called from configure.
+ qt_ir_commandline_option(from-configure TYPE boolean)
+ # Implies force.
+ qt_ir_commandline_option(init-submodules TYPE boolean)
+ # We alias qtbase's submodules option to init-repository module-subset.
+ qt_ir_commandline_option(submodules ALIAS module-subset TYPE string)
+
+ set_property(GLOBAL PROPERTY _qt_ir_known_command_line_options "${commandline_known_options}")
+endmacro()
+
+# Gets list of known command line options.
+function(qt_ir_get_known_command_line_options out_var)
+ get_property(values GLOBAL PROPERTY _qt_ir_known_command_line_options)
+ set(${out_var} "${values}" PARENT_SCOPE)
+endfunction()
diff --git a/cmake/QtIRParsingHelpers.cmake b/cmake/QtIRParsingHelpers.cmake
new file mode 100644
index 00000000..d7d3f20e
--- /dev/null
+++ b/cmake/QtIRParsingHelpers.cmake
@@ -0,0 +1,237 @@
+# Copyright (C) 2024 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+# Retrieves the contents of either .git/config or .gitmodules files for further parsing.
+function(qt_ir_get_git_config_contents out_var)
+ set(options
+ READ_GITMODULES
+ READ_GIT_CONFIG
+ READ_GIT_CONFIG_LOCAL
+ )
+ set(oneValueArgs
+ WORKING_DIRECTORY
+ )
+ set(multiValueArgs "")
+ cmake_parse_arguments(arg "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
+
+ if(arg_READ_GITMODULES)
+ set(args -f .gitmodules)
+ set(file_message ".gitmodules")
+ elseif(arg_READ_GIT_CONFIG)
+ set(args "")
+ set(file_message ".git/config")
+ elseif(arg_READ_GIT_CONFIG_LOCAL)
+ set(args "--local")
+ set(file_message ".local .git/config")
+ else()
+ message(FATAL_ERROR "qt_ir_get_git_config_contents: No option specified")
+ endif()
+
+ qt_ir_get_working_directory_from_arg(working_directory)
+
+ qt_ir_execute_process_and_log_and_handle_error(
+ FORCE_QUIET
+ COMMAND_ARGS git config --list ${args}
+ OUT_OUTPUT_VAR git_output
+ WORKING_DIRECTORY "${working_directory}"
+ ERROR_MESSAGE "Failed to get ${file_message} contents for parsing")
+
+ string(STRIP "${git_output}" git_output)
+ set(${out_var} "${git_output}" PARENT_SCOPE)
+endfunction()
+
+# Checks whether the given url has a scheme like https:// or is just a
+# relative path.
+function(qt_ir_has_url_scheme url out_var)
+ string(REGEX MATCH "^[a-z][a-z0-9+\-.]*://" has_url_scheme "${url}")
+
+ if(has_url_scheme)
+ set(${out_var} TRUE PARENT_SCOPE)
+ else()
+ set(${out_var} FALSE PARENT_SCOPE)
+ endif()
+endfunction()
+
+# Parses a key-value line from a .git/config or .gitmodules file
+macro(qt_ir_parse_git_key_value)
+ string(REGEX REPLACE "^submodule\\.([^.=]+)\\.([^.=]+)=(.*)$" "\\1;\\2;\\3"
+ parsed_line "${line}")
+
+ list(LENGTH parsed_line parsed_line_length)
+ set(submodule_name "")
+ set(key "")
+ set(value "")
+ if(parsed_line_length EQUAL 3)
+ list(GET parsed_line 0 submodule_name)
+ list(GET parsed_line 1 key)
+ list(GET parsed_line 2 value)
+ endif()
+endmacro()
+
+# Parses a url line from a .gitmodules file
+# e.g. line - 'submodule.qtbase.url=../qtbase.git'
+#
+# Arguments
+#
+# submodule_name
+# submodule name, the key in 'submodule.${submodule_name}.url'
+# e.g. 'qtbase'
+# url_value
+# the url where to clone a repo from
+# in perl script it was called $base
+# e.g. '../qtbase.git', 'https://code.qt.io/playground/qlitehtml.git'
+# parent_repo_base_git_path
+# the base git path of the parent of the submodule
+# it is either a relative dir or a full url
+# in the perl script it was called $my_repo_base,
+# it was passed as first arg to git_clone_all_submodules,
+# it was passed the value of $subbases{$module} when doing recursive submodule cloning
+# e.g. 'qt5', 'tqtc-qt5', 'qtdeclarative.git', 'https://code.qt.io/playground/qlitehtml.git'
+#
+# Outputs
+#
+# ${out_var_prefix}_${submodule_name}_url
+# just the value of ${url_value}
+# ${out_var_prefix}_${submodule_name}_base_git_path
+# the whole url if it has a scheme, otherwise it's the value of
+# ${url_value} relative to ${parent_repo_base_git_path}, so all the ../ are collapsed
+# e.g. 'qtdeclarative.git'
+# 'https://code.qt.io/playground/qlitehtml.git',
+macro(qt_ir_parse_git_url_key out_var_prefix submodule_name url_value parent_repo_base_git_path)
+ qt_ir_has_url_scheme("${url_value}" has_url_scheme)
+ if(NOT has_url_scheme)
+ set(base_git_path "${parent_repo_base_git_path}/${url_value}")
+
+ # The exact code perl code was while ($base =~ s,(?!\.\./)[^/]+/\.\./,,g) {}
+ # That got rid of ../ and ../../ in the path, but it broke down
+ # when more than two ../ were present.
+ # We just use ABSOLUTE to resolve the path and get rid of all ../
+ # Note the empty BASE_DIR is important, otherwise the path is relative to
+ # ${CMAKE_CURRENT_SOURCE_DIR}.
+ get_filename_component(base_git_path "${base_git_path}" ABSOLUTE BASE_DIR "")
+ else()
+ set(base_git_path "${url_value}")
+ endif()
+
+ set(${out_var_prefix}_${submodule_name}_url "${url_value}" PARENT_SCOPE)
+ set(${out_var_prefix}_${submodule_name}_base_git_path "${base_git_path}" PARENT_SCOPE)
+endmacro()
+
+# Parses a .git/config or .gitmodules file contents and sets variables for each submodule
+# starting with ${out_var_prefix}_
+# These include:
+# ${out_var_prefix}_${submodule_name}_path
+# the path to the submodule relative to the parent repo
+# ${out_var_prefix}_${submodule_name}_branch
+# the branch that should be checked out when the branch option is used
+# ${out_var_prefix}_${submodule_name}_url
+# the url key as encountered in the config
+# ${out_var_prefix}_${submodule_name}_base_git_path
+# the git base path of the submodule, either a full url or a relative path
+# ${out_var_prefix}_${submodule_name}_update
+# the status of the submodule, can be 'none'
+# ${out_var_prefix}_${submodule_name}_status
+# the status of the submodule, can be 'essential', 'addon', etc
+# ${out_var_prefix}_${submodule_name}_depends
+# the list of submodules that this submodule depends on
+# ${out_var_prefix}_${submodule_name}_recommends
+# the list of submodules that this submodule recommends to be used with
+# ${out_var_prefix}_submodules
+# a list of all known submodule names encountered in the file
+# ${out_var_prefix}_submodules_to_remove
+# a list of all submodules to remove due to update == 'none'
+# ${out_var_prefix}_statuses to
+# a list of all known submodule statuses like 'essential', 'addon', etc
+# ${out_var_prefix}_status_${status}_submodules
+# a list of all submodules with the specific status
+function(qt_ir_parse_git_config_file_contents out_var_prefix)
+ set(options
+ READ_GITMODULES
+ READ_GIT_CONFIG
+ READ_GIT_CONFIG_LOCAL
+ )
+ set(oneValueArgs
+ PARENT_REPO_BASE_GIT_PATH
+ WORKING_DIRECTORY
+ )
+ set(multiValueArgs "")
+ cmake_parse_arguments(arg "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
+
+ qt_ir_get_working_directory_from_arg(working_directory)
+
+ if(NOT arg_PARENT_REPO_BASE_GIT_PATH)
+ message(FATAL_ERROR
+ "qt_ir_parse_git_config_file_contents: No base PARENT_REPO_BASE_GIT_PATH specified")
+ endif()
+ set(parent_repo_base_git_path "${arg_PARENT_REPO_BASE_GIT_PATH}")
+
+ if(arg_READ_GITMODULES)
+ set(read_git_config READ_GITMODULES)
+ elseif(arg_READ_GIT_CONFIG)
+ set(read_git_config READ_GIT_CONFIG)
+ elseif(arg_READ_GIT_CONFIG_LOCAL)
+ set(read_git_config READ_GIT_CONFIG_LOCAL)
+ else()
+ message(FATAL_ERROR
+ "qt_ir_parse_gitmodules_file_contents: No valid git config file specified")
+ endif()
+
+ qt_ir_get_git_config_contents(contents
+ ${read_git_config}
+ WORKING_DIRECTORY "${working_directory}"
+ )
+ string(REPLACE "\n" ";" lines "${contents}")
+
+ set(known_submodules "")
+ set(statuses "")
+ set(submodules_to_remove "")
+
+ foreach(line IN LISTS lines)
+ qt_ir_parse_git_key_value()
+ if(NOT submodule_name OR NOT key OR value STREQUAL "")
+ continue()
+ endif()
+
+ list(APPEND known_submodules "${submodule_name}")
+
+ if(key STREQUAL "path")
+ set(${out_var_prefix}_${submodule_name}_path "${value}" PARENT_SCOPE)
+ elseif(key STREQUAL "branch")
+ set(${out_var_prefix}_${submodule_name}_branch "${value}" PARENT_SCOPE)
+ elseif(key STREQUAL "url")
+ qt_ir_parse_git_url_key(
+ "${out_var_prefix}" "${submodule_name}" "${value}" "${parent_repo_base_git_path}")
+ elseif(key STREQUAL "update")
+ # Some repo submodules had a update = none key in their .gitmodules
+ # in which case we're supposed to skip initialzing those submodules,
+ # which the perl script did by adding -${submodule_name} to the subset.
+ # See qtdeclarative Change-Id: I633404f1c00d83dcbdca06a1d287623190323028
+ set(${out_var_prefix}_${submodule_name}_update "${value}" PARENT_SCOPE)
+ if(value STREQUAL "none")
+ list(APPEND submodules_to_remove "-${submodule_name}")
+ endif()
+ elseif(key STREQUAL "status")
+ set(status_submodules "${${out_var_prefix}_status_${value}_submodules}")
+ list(APPEND status_submodules "${submodule_name}")
+ list(REMOVE_DUPLICATES status_submodules)
+ list(APPEND statuses "${value}")
+
+ set(${out_var_prefix}_status_${value}_submodules "${status_submodules}")
+ set(${out_var_prefix}_status_${value}_submodules "${status_submodules}" PARENT_SCOPE)
+ set(${out_var_prefix}_${submodule_name}_status "${value}" PARENT_SCOPE)
+ elseif(key STREQUAL "depends")
+ string(REPLACE " " ";" value "${value}")
+ set(${out_var_prefix}_${submodule_name}_depends "${value}" PARENT_SCOPE)
+ elseif(key STREQUAL "recommends")
+ string(REPLACE " " ";" value "${value}")
+ set(${out_var_prefix}_${submodule_name}_recommends "${value}" PARENT_SCOPE)
+ endif()
+ endforeach()
+
+ list(REMOVE_DUPLICATES known_submodules)
+ list(REMOVE_DUPLICATES submodules_to_remove)
+ list(REMOVE_DUPLICATES statuses)
+ set(${out_var_prefix}_submodules "${known_submodules}" PARENT_SCOPE)
+ set(${out_var_prefix}_submodules_to_remove "${submodules_to_remove}" PARENT_SCOPE)
+ set(${out_var_prefix}_statuses "${statuses}" PARENT_SCOPE)
+endfunction()
diff --git a/cmake/QtIRProcessHelpers.cmake b/cmake/QtIRProcessHelpers.cmake
new file mode 100644
index 00000000..db7bf2cb
--- /dev/null
+++ b/cmake/QtIRProcessHelpers.cmake
@@ -0,0 +1,165 @@
+# Copyright (C) 2024 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+# A low-level execute_process wrapper that can be used to execute a single command
+# while controlling the verbosity and error handling.
+function(qt_ir_execute_process)
+ set(options
+ QUIET
+ )
+ set(oneValueArgs
+ WORKING_DIRECTORY
+ OUT_RESULT_VAR
+ OUT_OUTPUT_VAR
+ OUT_ERROR_VAR
+ )
+ set(multiValueArgs
+ COMMAND_ARGS
+ EP_EXTRA_ARGS
+ )
+ cmake_parse_arguments(arg "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
+
+ if(NOT arg_COMMAND_ARGS)
+ message(FATAL_ERROR "Missing arguments to qt_ir_execute_process")
+ endif()
+
+ if(arg_WORKING_DIRECTORY)
+ set(working_dir_value "${arg_WORKING_DIRECTORY}")
+ else()
+ set(working_dir_value ".")
+ endif()
+ set(working_dir WORKING_DIRECTORY "${working_dir_value}")
+
+ set(result_variable "")
+ if(arg_OUT_RESULT_VAR)
+ set(result_variable RESULT_VARIABLE proc_result)
+ endif()
+
+ set(swallow_output "")
+ if(arg_OUT_OUTPUT_VAR OR arg_QUIET)
+ list(APPEND swallow_output OUTPUT_VARIABLE proc_output)
+ endif()
+ if(arg_OUT_ERROR_VAR OR arg_QUIET)
+ list(APPEND swallow_output ERROR_VARIABLE proc_error)
+ endif()
+ if(NOT arg_QUIET)
+ set(working_dir_message "")
+
+ qt_ir_is_verbose(verbose)
+ if(verbose)
+ set(working_dir_message " current working dir: ")
+ if(NOT working_dir_value STREQUAL ".")
+ string(APPEND working_dir_message "${working_dir_value}")
+ endif()
+ endif()
+
+ string(REPLACE ";" " " command_args_string "${arg_COMMAND_ARGS}")
+ message("+ ${command_args_string}${working_dir_message}")
+ endif()
+
+ execute_process(
+ COMMAND ${arg_COMMAND_ARGS}
+ ${working_dir}
+ ${result_variable}
+ ${swallow_output}
+ ${arg_EP_EXTRA_ARGS}
+ )
+
+ if(arg_OUT_RESULT_VAR)
+ set(${arg_OUT_RESULT_VAR} "${proc_result}" PARENT_SCOPE)
+ endif()
+ if(arg_OUT_OUTPUT_VAR)
+ set(${arg_OUT_OUTPUT_VAR} "${proc_output}" PARENT_SCOPE)
+ endif()
+ if(arg_OUT_ERROR_VAR)
+ set(${arg_OUT_ERROR_VAR} "${proc_error}" PARENT_SCOPE)
+ endif()
+endfunction()
+
+# A higher level execute_process wrapper that can be used to execute a single command
+# that is a bit more opinionated and expects options related to init-repository
+# functionality.
+# It handles queietness, error handling and logging.
+# It also allows for slightly more compact syntax for calling processes.
+function(qt_ir_execute_process_and_log_and_handle_error)
+ set(options
+ NO_HANDLE_ERROR
+ FORCE_VERBOSE
+ FORCE_QUIET
+ )
+ set(oneValueArgs
+ WORKING_DIRECTORY
+ OUT_RESULT_VAR
+ OUT_OUTPUT_VAR
+ OUT_ERROR_VAR
+ ERROR_MESSAGE
+ )
+ set(multiValueArgs
+ COMMAND_ARGS
+ EP_EXTRA_ARGS
+ )
+ cmake_parse_arguments(arg "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
+
+ qt_ir_get_option_value(quiet quiet)
+ set(quiet_option "")
+ if((quiet OR arg_FORCE_QUIET) AND NOT arg_FORCE_VERBOSE)
+ set(quiet_option "QUIET")
+ endif()
+
+ set(working_dir "")
+ if(arg_WORKING_DIRECTORY)
+ set(working_dir WORKING_DIRECTORY "${arg_WORKING_DIRECTORY}")
+ endif()
+
+ set(extra_args "")
+ if(arg_EP_EXTRA_ARGS)
+ set(extra_args EP_EXTRA_ARGS "${arg_EP_EXTRA_ARGS}")
+ endif()
+
+ set(out_output_var "")
+ if(arg_OUT_OUTPUT_VAR OR quiet)
+ set(out_output_var OUT_OUTPUT_VAR proc_output)
+ endif()
+
+ set(out_error_var "")
+ if(arg_OUT_ERROR_VAR OR quiet)
+ set(out_error_var OUT_ERROR_VAR proc_error)
+ endif()
+
+ qt_ir_execute_process(
+ ${quiet_option}
+ COMMAND_ARGS ${arg_COMMAND_ARGS}
+ OUT_RESULT_VAR proc_result
+ ${extra_args}
+ ${working_dir}
+ ${out_output_var}
+ ${out_error_var}
+ )
+
+ if(NOT proc_result EQUAL 0 AND NOT arg_NO_HANDLE_ERROR)
+ set(error_message "")
+ if(arg_ERROR_MESSAGE)
+ set(error_message "${arg_ERROR_MESSAGE}\n")
+ endif()
+
+ string(REPLACE ";" " " cmd "${arg_COMMAND_ARGS}")
+ string(APPEND error_message "${cmd} exited with status: ${proc_result}\n")
+ if(proc_output)
+ string(APPEND error_message "stdout: ${proc_output}\n")
+ endif()
+ if(proc_error)
+ string(APPEND error_message "stderr: ${proc_error}\n")
+ endif()
+ message(FATAL_ERROR "${error_message}")
+ endif()
+
+ if(arg_OUT_RESULT_VAR)
+ set(${arg_OUT_RESULT_VAR} "${proc_result}" PARENT_SCOPE)
+ endif()
+ if(arg_OUT_OUTPUT_VAR)
+ set(${arg_OUT_OUTPUT_VAR} "${proc_output}" PARENT_SCOPE)
+ endif()
+ if(arg_OUT_ERROR_VAR)
+ set(${arg_OUT_ERROR_VAR} "${proc_error}" PARENT_SCOPE)
+ endif()
+endfunction()
diff --git a/cmake/QtIRScript.cmake b/cmake/QtIRScript.cmake
new file mode 100644
index 00000000..fc5ffba9
--- /dev/null
+++ b/cmake/QtIRScript.cmake
@@ -0,0 +1,17 @@
+# Copyright (C) 2024 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+cmake_minimum_required(VERSION 3.16)
+
+# Sets up the include paths for all the helpers init-repository uses.
+macro(qt_ir_setup_include_paths)
+ list(APPEND CMAKE_MODULE_PATH
+ "${CMAKE_CURRENT_LIST_DIR}"
+ "${CMAKE_CURRENT_LIST_DIR}/3rdparty/cmake"
+ )
+ include(QtIRHelpers)
+endmacro()
+
+qt_ir_setup_include_paths()
+qt_ir_include_all_helpers()
+qt_ir_run_main_script("${CMAKE_CURRENT_SOURCE_DIR}" exit_reason)
diff --git a/cmake/QtSortModuleDependencies.cmake b/cmake/QtSortModuleDependencies.cmake
new file mode 100644
index 00000000..2f8cdb59
--- /dev/null
+++ b/cmake/QtSortModuleDependencies.cmake
@@ -0,0 +1,16 @@
+# Copyright (C) 2024 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+# The script produces the list of qt submodules that are required to build the submodules listed
+# in the QT_BUILD_SUBMODULES variable. The resulting list preserves the required build order.
+# Usage:
+# cmake [-DQT_BUILD_SUBMODULES="<repo;..>"] [-BUILD_<repo>=<TRUE|FALSE>] \
+# -P <path/to>/qt6/cmake/QtSortModuleDependencies.cmake
+cmake_minimum_required(VERSION 3.16)
+
+include(${CMAKE_CURRENT_LIST_DIR}/QtTopLevelHelpers.cmake)
+
+qt_internal_collect_modules_only(result "${QT_BUILD_SUBMODULES}")
+
+list(JOIN result " " result)
+message("${result}")
diff --git a/cmake/QtSynchronizeRepo.cmake b/cmake/QtSynchronizeRepo.cmake
index 522ea76e..eabd5c7c 100644
--- a/cmake/QtSynchronizeRepo.cmake
+++ b/cmake/QtSynchronizeRepo.cmake
@@ -1,3 +1,15 @@
-include(cmake/QtTopLevelHelpers.cmake)
+# Copyright (C) 2024 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+# This script is to be called (ideally from a git-sync-to alias script):
+# cmake -DSYNC_TO_MODULE="$1" -DSYNC_TO_BRANCH="$2" -P cmake/QtSynchronizeRepo.cmake
+# Or as follows (ideally from a git-qt-foreach alias script):
+# cmake -DQT_FOREACH=TRUE "-DARGS=$*" -P cmake/QtSynchronizeRepo.cmake
-qt_internal_sync_to(${SYNC_TO_MODULE} ${SYNC_TO_BRANCH})
+cmake_policy(VERSION 3.16)
+include(cmake/QtTopLevelHelpers.cmake)
+if(QT_FOREACH)
+ qt_internal_foreach_repo_run(ARGS ${ARGS})
+else()
+ qt_internal_sync_to(${SYNC_TO_MODULE} ${SYNC_TO_BRANCH})
+endif()
diff --git a/cmake/QtTopLevelConfigureScript.cmake b/cmake/QtTopLevelConfigureScript.cmake
new file mode 100644
index 00000000..304bf7b7
--- /dev/null
+++ b/cmake/QtTopLevelConfigureScript.cmake
@@ -0,0 +1,17 @@
+# Copyright (C) 2024 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+cmake_minimum_required(VERSION 3.16)
+
+# Sets up the include paths for all the helpers configure uses.
+macro(qt_tl_setup_include_paths)
+ list(APPEND CMAKE_MODULE_PATH
+ "${CMAKE_CURRENT_LIST_DIR}"
+ "${CMAKE_CURRENT_LIST_DIR}/3rdparty/cmake"
+ )
+ include(QtTopLevelHelpers)
+endmacro()
+
+qt_tl_setup_include_paths()
+qt_tl_include_all_helpers()
+qt_tl_run_main_script()
diff --git a/cmake/QtTopLevelHelpers.cmake b/cmake/QtTopLevelHelpers.cmake
index 2d06a8fd..7fe21e4f 100644
--- a/cmake/QtTopLevelHelpers.cmake
+++ b/cmake/QtTopLevelHelpers.cmake
@@ -1,3 +1,62 @@
+# Copyright (C) 2024 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+macro(qt_tl_include_all_helpers)
+ include(QtIRHelpers)
+ qt_ir_include_all_helpers()
+endmacro()
+
+function(qt_tl_run_toplevel_configure top_level_src_path)
+ cmake_parse_arguments(arg "ALREADY_INITIALIZED" "" "" ${ARGV})
+
+ qt_ir_get_cmake_flag(ALREADY_INITIALIZED arg_ALREADY_INITIALIZED)
+
+ # Filter out init-repository specific arguments before passing them to
+ # configure.
+ qt_ir_get_args_from_optfile_configure_filtered("${OPTFILE}" configure_args
+ ${arg_ALREADY_INITIALIZED})
+ # Get the path to the qtbase configure script.
+ set(qtbase_dir_name "qtbase")
+ set(configure_path "${top_level_src_path}/${qtbase_dir_name}/configure")
+ if(CMAKE_HOST_WIN32)
+ string(APPEND configure_path ".bat")
+ endif()
+
+ if(NOT EXISTS "${configure_path}")
+ message(FATAL_ERROR
+ "The required qtbase/configure script was not found: ${configure_path}\n"
+ "Try re-running configure with --init-submodules")
+ endif()
+
+ # Make a build directory for qtbase in the current build directory.
+ set(qtbase_build_dir "${CMAKE_CURRENT_BINARY_DIR}/${qtbase_dir_name}")
+ file(MAKE_DIRECTORY "${qtbase_build_dir}")
+
+ qt_ir_execute_process_and_log_and_handle_error(
+ COMMAND_ARGS "${configure_path}" -top-level ${configure_args}
+ WORKING_DIRECTORY "${qtbase_build_dir}"
+ FORCE_VERBOSE
+ )
+endfunction()
+
+function(qt_tl_run_main_script)
+ if(NOT TOP_LEVEL_SRC_PATH)
+ message(FATAL_ERROR "Assertion: configure TOP_LEVEL_SRC_PATH is not set")
+ endif()
+
+ # Tell init-repository it is called from configure.
+ qt_ir_set_option_value(from-configure TRUE)
+
+ # Run init-repository in-process.
+ qt_ir_run_main_script("${TOP_LEVEL_SRC_PATH}" exit_reason)
+ if(exit_reason AND NOT exit_reason STREQUAL "ALREADY_INITIALIZED")
+ return()
+ endif()
+
+ # Then run configure out-of-process.
+ qt_tl_run_toplevel_configure("${TOP_LEVEL_SRC_PATH}" ${exit_reason})
+endfunction()
+
# Populates $out_module_list with all subdirectories that have a CMakeLists.txt file
function(qt_internal_find_modules out_module_list)
set(module_list "")
@@ -14,8 +73,8 @@ endfunction()
# poor man's yaml parser, populating $out_dependencies with all dependencies
# in the $depends_file
-# Each entry will be in the format dependency/sha1
-function(qt_internal_parse_dependencies depends_file out_dependencies)
+# Each entry will be in the format dependency/sha1/required
+function(qt_internal_parse_dependencies_yaml depends_file out_dependencies)
file(STRINGS "${depends_file}" lines)
set(eof_marker "---EOF---")
list(APPEND lines "${eof_marker}")
@@ -47,91 +106,276 @@ function(qt_internal_parse_dependencies depends_file out_dependencies)
string(TOUPPER "${CMAKE_MATCH_1}" required)
endif()
endforeach()
- message(DEBUG "qt_internal_parse_dependencies for ${depends_file}: ${dependencies} ${revisions}")
+ message(DEBUG
+ "qt_internal_parse_dependencies_yaml for ${depends_file}\n dependencies: ${dependencies}")
set(${out_dependencies} "${dependencies}" PARENT_SCOPE)
endfunction()
-# Load $module and populate $out_ordered with the submodules based on their dependencies
-# $ordered carries already sorted dependencies; $out_has_dependencies is left empty
-# if there are no dependencies, otherwise set to 1; Save list of dependencies for $module into
-# $out_module_dependencies. List may contain duplicates, since function checks max depth
-# dependencies.
-# Function calls itself recursively if a dependency is found that is not yet in $ordered.
-function(qt_internal_add_module_dependencies module ordered out_ordered out_has_dependencies
- out_module_dependencies out_revisions)
- set(depends_file "${CMAKE_CURRENT_SOURCE_DIR}/${module}/dependencies.yaml")
- if(NOT EXISTS "${depends_file}")
- set(${out_has_dependencies} "" PARENT_SCOPE)
+# Helper macro for qt_internal_resolve_module_dependencies.
+macro(qt_internal_resolve_module_dependencies_set_skipped value)
+ if(DEFINED arg_SKIPPED_VAR)
+ set(${arg_SKIPPED_VAR} ${value} PARENT_SCOPE)
+ endif()
+endmacro()
+
+# Strips tqtc- prefix from a repo name.
+function(qt_internal_normalize_repo_name repo_name out_var)
+ string(REGEX REPLACE "^tqtc-" "" normalized "${repo_name}")
+ set(${out_var} "${normalized}" PARENT_SCOPE)
+endfunction()
+
+# Checks if a directory with the given repo name exists in the current
+# source / working directory. If it doesn't, it strips the tqtc- prefix.
+function(qt_internal_use_normalized_repo_name_if_needed repo_name out_var)
+ set(base_dir "${CMAKE_CURRENT_SOURCE_DIR}")
+ set(repo_dir "${base_dir}/${repo_name}")
+ if(NOT IS_DIRECTORY "${repo_dir}")
+ qt_internal_normalize_repo_name("${repo_name}" repo_name)
+ endif()
+ set(${out_var} "${repo_name}" PARENT_SCOPE)
+endfunction()
+
+
+# Resolve the dependencies of the given module.
+# "Module" in the sense of Qt repository.
+#
+# Side effects: Sets the global properties QT_DEPS_FOR_${module} and QT_REQUIRED_DEPS_FOR_${module}
+# with the direct (required) dependencies of module.
+#
+#
+# Positional arguments:
+#
+# module is the Qt repository.
+#
+# out_ordered is where the result is stored. This is a list of all dependencies, including
+# transitive ones, in topologically sorted order. Note that ${module} itself is also part of
+# out_ordered.
+#
+# out_revisions is a list of git commit IDs for each of the dependencies in ${out_ordered}. This
+# list has the same length as ${out_ordered}.
+#
+#
+# Keyword arguments:
+#
+# PARSED_DEPENDENCIES is a list of dependencies of module in the format that
+# qt_internal_parse_dependencies_yaml returns.
+# If this argument is not provided, either a module's dependencies.yaml or .gitmodules file is
+# used as the source of dependencies, depending on whether PARSE_GITMODULES option is enabled.
+#
+# PARSE_GITMODULES is a boolean that controls whether the .gitmodules or the dependencies.yaml
+# file of the repo are used for extracting dependencies. Defaults to FALSE, so uses
+# dependencies.yaml by default.
+#
+# EXCLUDE_OPTIONAL_DEPS is a boolean that controls whether optional dependencies are excluded from
+# the final result.
+#
+# GITMODULES_PREFIX_VAR is the prefix of all the variables containing dependencies for the
+# PARSE_GITMODULES mode.
+# The function expects the following variables to be set in the parent scope
+# ${arg_GITMODULES_PREFIX_VAR}_${submodule_name}_depends
+# ${arg_GITMODULES_PREFIX_VAR}_${submodule_name}_recommends
+#
+# IN_RECURSION is an internal option that is set when the function is in recursion.
+#
+# REVISION is an internal value with the git commit ID that belongs to ${module}.
+#
+# SKIPPED_VAR is an output variable name that is set to TRUE if the module was skipped, to FALSE
+# otherwise.
+#
+# NORMALIZE_REPO_NAME_IF_NEEDED Will remove 'tqtc-' from the beginning of submodule dependencies
+# if a tqtc- named directory does not exist.
+#
+# SKIP_MODULES Modules that should be skipped from evaluation completely.
+function(qt_internal_resolve_module_dependencies module out_ordered out_revisions)
+ set(options IN_RECURSION NORMALIZE_REPO_NAME_IF_NEEDED PARSE_GITMODULES
+ EXCLUDE_OPTIONAL_DEPS)
+ set(oneValueArgs REVISION SKIPPED_VAR GITMODULES_PREFIX_VAR)
+ set(multiValueArgs PARSED_DEPENDENCIES SKIP_MODULES)
+ cmake_parse_arguments(arg "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
+
+ # Clear the property that stores the repositories we've already seen.
+ if(NOT arg_IN_RECURSION)
+ set_property(GLOBAL PROPERTY _qt_internal_seen_repos)
+ endif()
+
+ # Bail out if we've seen the module already or it was skipped explicitly from command line.
+ qt_internal_resolve_module_dependencies_set_skipped(FALSE)
+ get_property(seen GLOBAL PROPERTY _qt_internal_seen_repos)
+ if(module IN_LIST seen OR module IN_LIST arg_SKIP_MODULES)
+ qt_internal_resolve_module_dependencies_set_skipped(TRUE)
return()
endif()
- set(${out_has_dependencies} "1" PARENT_SCOPE)
- set(dependencies "")
- qt_internal_parse_dependencies("${depends_file}" dependencies)
- # module hasn't been seen yet, append it
- list(FIND ordered "${module}" pindex)
- if (pindex EQUAL -1)
- list(LENGTH ordered pindex)
- list(APPEND ordered "${module}")
- list(APPEND revisions "HEAD")
+
+ set_property(GLOBAL APPEND PROPERTY _qt_internal_seen_repos ${module})
+
+ # Set a default REVISION.
+ if("${arg_REVISION}" STREQUAL "")
+ set(arg_REVISION HEAD)
endif()
- set(modules_dependencies "")
+
+ # Retrieve the dependencies.
+ if(DEFINED arg_PARSED_DEPENDENCIES)
+ set(dependencies "${arg_PARSED_DEPENDENCIES}")
+ else()
+ set(dependencies "")
+
+ if(NOT arg_PARSE_GITMODULES)
+ set(depends_file "${CMAKE_CURRENT_SOURCE_DIR}/${module}/dependencies.yaml")
+ if(EXISTS "${depends_file}")
+ qt_internal_parse_dependencies_yaml("${depends_file}" dependencies)
+
+ if(arg_EXCLUDE_OPTIONAL_DEPS)
+ set(filtered_dependencies "")
+ foreach(dependency IN LISTS dependencies)
+ string(REPLACE "/" ";" dependency_split "${dependency}")
+ list(GET dependency_split 2 required)
+ if(required)
+ list(APPEND filtered_dependencies "${dependency}")
+ endif()
+ endforeach()
+ set(dependencies "${filtered_dependencies}")
+ endif()
+ endif()
+ else()
+ set(depends "${${arg_GITMODULES_PREFIX_VAR}_${dependency}_depends}")
+ foreach(dependency IN LISTS depends)
+ if(dependency)
+ # The HEAD value is not really used, but we need to add something.
+ list(APPEND dependencies "${dependency}/HEAD/TRUE")
+ endif()
+ endforeach()
+
+ set(recommends "${${arg_GITMODULES_PREFIX_VAR}_${dependency}_recommends}")
+ if(NOT arg_EXCLUDE_OPTIONAL_DEPS)
+ foreach(dependency IN LISTS recommends)
+ if(dependency)
+ list(APPEND dependencies "${dependency}/HEAD/FALSE")
+ endif()
+ endforeach()
+ endif()
+ endif()
+ endif()
+
+ # Traverse the dependencies.
+ set(ordered)
+ set(revisions)
foreach(dependency IN LISTS dependencies)
if(dependency MATCHES "(.*)/([^/]+)/([^/]+)")
set(dependency "${CMAKE_MATCH_1}")
set(revision "${CMAKE_MATCH_2}")
set(required "${CMAKE_MATCH_3}")
- if(required)
- set_property(GLOBAL APPEND PROPERTY QT_REQUIRED_DEPS_FOR_${module} ${dependency})
- endif()
else()
message(FATAL_ERROR "Internal Error: wrong dependency format ${dependency}")
endif()
- list(APPEND modules_dependencies "${dependency}")
- list(FIND ordered "${dependency}" dindex)
- if (dindex EQUAL -1)
- # dependency hasnt' been seen yet - load it
- list(INSERT ordered ${pindex} "${dependency}")
- list(INSERT revisions ${pindex} "${revision}")
- qt_internal_add_module_dependencies(${dependency} "${ordered}" ordered has_dependency
- "${out_module_dependencies}" revisions)
- elseif(dindex GREATER pindex)
- # otherwise, make sure it is before module
- list(REMOVE_AT ordered ${dindex})
- list(REMOVE_AT revisions ${dindex})
- list(INSERT ordered ${pindex} "${dependency}")
- list(INSERT revisions ${pindex} "${revision}")
+
+ set(normalize_arg "")
+ if(arg_NORMALIZE_REPO_NAME_IF_NEEDED)
+ qt_internal_use_normalized_repo_name_if_needed("${dependency}" dependency)
+ set(normalize_arg "NORMALIZE_REPO_NAME_IF_NEEDED")
+ endif()
+
+ set_property(GLOBAL APPEND PROPERTY QT_DEPS_FOR_${module} ${dependency})
+ if(required)
+ set_property(GLOBAL APPEND PROPERTY QT_REQUIRED_DEPS_FOR_${module} ${dependency})
+ endif()
+
+ set(parse_gitmodules "")
+ if(arg_PARSE_GITMODULES)
+ set(parse_gitmodules "PARSE_GITMODULES")
+ endif()
+
+ set(exclude_optional_deps "")
+ if(arg_EXCLUDE_OPTIONAL_DEPS)
+ set(exclude_optional_deps "EXCLUDE_OPTIONAL_DEPS")
+ endif()
+
+ set(extra_options "")
+ if(arg_SKIP_MODULES)
+ list(APPEND extra_options SKIP_MODULES ${arg_SKIP_MODULES})
+ endif()
+
+ qt_internal_resolve_module_dependencies(${dependency} dep_ordered dep_revisions
+ REVISION "${revision}"
+ SKIPPED_VAR skipped
+ IN_RECURSION
+ ${normalize_arg}
+ ${parse_gitmodules}
+ ${exclude_optional_deps}
+ GITMODULES_PREFIX_VAR ${arg_GITMODULES_PREFIX_VAR}
+ ${extra_options}
+ )
+ if(NOT skipped)
+ list(APPEND ordered ${dep_ordered})
+ list(APPEND revisions ${dep_revisions})
endif()
endforeach()
+
+ list(APPEND ordered ${module})
+ list(APPEND revisions ${arg_REVISION})
set(${out_ordered} "${ordered}" PARENT_SCOPE)
- set(${out_module_dependencies} ${${out_module_dependencies}} ${modules_dependencies} PARENT_SCOPE)
set(${out_revisions} "${revisions}" PARENT_SCOPE)
endfunction()
-# populates $out_all_ordered with the sequence of the modules that need
-# to be built in order to build $modules; dependencies for each module are populated
-# in variables with specified in $dependencies_map_prefix prefix
-function(qt_internal_sort_module_dependencies modules out_all_ordered dependencies_map_prefix)
- set(ordered "")
+# Resolves the dependencies of the given modules.
+# "Module" is here used in the sense of Qt repository.
+#
+# Returns all dependencies, including transitive ones, in topologically sorted order.
+#
+# Arguments:
+# modules is the initial list of repos.
+# out_all_ordered is the variable name where the result is stored.
+# PARSE_GITMODULES and GITMODULES_PREFIX_VAR are keyowrd arguments that change the
+# source of dependencies parsing from dependencies.yaml to .gitmodules.
+# EXCLUDE_OPTIONAL_DEPS is a keyword argument that excludes optional dependencies from the result.
+# See qt_internal_resolve_module_dependencies for details.
+#
+# SKIP_MODULES Modules that should be skipped from evaluation completely.
+#
+# See qt_internal_resolve_module_dependencies for side effects.
+function(qt_internal_sort_module_dependencies modules out_all_ordered)
+ set(options PARSE_GITMODULES EXCLUDE_OPTIONAL_DEPS)
+ set(oneValueArgs GITMODULES_PREFIX_VAR)
+ set(multiValueArgs SKIP_MODULES)
+ cmake_parse_arguments(arg "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
+
+ set(parse_gitmodules "")
+ if(arg_PARSE_GITMODULES)
+ set(parse_gitmodules "PARSE_GITMODULES")
+ endif()
+
+ set(exclude_optional_deps "")
+ if(arg_EXCLUDE_OPTIONAL_DEPS)
+ set(exclude_optional_deps "EXCLUDE_OPTIONAL_DEPS")
+ endif()
+
+ # Create a fake repository "all_selected_repos" that has all repositories from the input as
+ # required dependency. The format must match what qt_internal_parse_dependencies_yaml produces.
+ set(all_selected_repos_as_parsed_dependencies)
foreach(module IN LISTS modules)
- set(out_ordered "")
- if(NOT dependencies_map_prefix)
- message(FATAL_ERROR "dependencies_map_prefix is not provided")
- endif()
- set(module_dependencies_list_var_name "${dependencies_map_prefix}${module}")
- qt_internal_add_module_dependencies(${module} "${ordered}" out_ordered module_depends
- "${module_dependencies_list_var_name}" revisions)
- set(${module_dependencies_list_var_name}
- "${${module_dependencies_list_var_name}}" PARENT_SCOPE)
- if(NOT module_depends)
- list(APPEND no_dependencies "${module}")
- else()
- set(ordered "${out_ordered}")
- endif()
+ list(APPEND all_selected_repos_as_parsed_dependencies "${module}/HEAD/FALSE")
endforeach()
- if (no_dependencies)
- list(APPEND ordered "${no_dependencies}")
+
+ set(extra_args "")
+ if(arg_SKIP_MODULES)
+ set(extra_args SKIP_MODULES ${arg_SKIP_MODULES})
endif()
- message(DEBUG "qt_internal_parse_dependencies sorted ${modules}: ${ordered}")
+
+ qt_internal_resolve_module_dependencies(all_selected_repos ordered unused_revisions
+ PARSED_DEPENDENCIES ${all_selected_repos_as_parsed_dependencies}
+ NORMALIZE_REPO_NAME_IF_NEEDED
+ ${exclude_optional_deps}
+ ${parse_gitmodules}
+ GITMODULES_PREFIX_VAR ${arg_GITMODULES_PREFIX_VAR}
+ ${extra_args}
+ )
+
+ # Drop "all_selected_repos" from the output. It depends on all selected repos, thus it must be
+ # the last element in the topologically sorted list.
+ list(REMOVE_AT ordered -1)
+
+ message(DEBUG
+ "qt_internal_sort_module_dependencies
+ input modules: ${modules}\n topo-sorted: ${ordered}")
set(${out_all_ordered} "${ordered}" PARENT_SCOPE)
endfunction()
@@ -268,6 +512,17 @@ function(qt_internal_sync_to module)
endif()
qt_internal_checkout("${module}" "${revision}")
+ qt_internal_resolve_module_dependencies(${module} initial_dependencies initial_revisions)
+ if(initial_dependencies)
+ foreach(dependency ${initial_dependencies})
+ if(dependency MATCHES "^tqtc-")
+ message(WARNING
+ "Handling of tqtc- repos will likely fail. Fixing this is non-trivial.")
+ break()
+ endif()
+ endforeach()
+ endif()
+
set(revision "")
set(checkedout "1")
# Load all dependencies for $module, then iterate over the dependencies in reverse order,
@@ -275,19 +530,16 @@ function(qt_internal_sync_to module)
# Repeat everything (we need to reload dependencies after each checkout) until no more checkouts
# are done.
while(${checkedout})
- set(dependencies "")
- set(revisions "")
- set(prefix "")
- qt_internal_add_module_dependencies(${module} "${dependencies}" dependencies has_dependencies prefix revisions)
+ qt_internal_resolve_module_dependencies(${module} dependencies revisions)
message(DEBUG "${module} dependencies: ${dependencies}")
message(DEBUG "${module} revisions : ${revisions}")
- if (NOT has_dependencies)
+ list(LENGTH dependencies count)
+ if (count EQUAL "0")
message(NOTICE "Module ${module} has no dependencies")
return()
endif()
- list(LENGTH dependencies count)
math(EXPR count "${count} - 1")
set(checkedout 0)
foreach(i RANGE ${count} 0 -1 )
@@ -325,3 +577,125 @@ function(qt_internal_sync_to module)
endforeach()
endwhile()
endfunction()
+
+# Runs user specified command for all qt repositories in qt directory.
+# Similar to git submodule foreach, except without relying on .gitmodules existing.
+# Useful for worktree checkouts.
+function(qt_internal_foreach_repo_run)
+ cmake_parse_arguments(PARSE_ARGV 0 arg
+ ""
+ ""
+ "ARGS"
+ )
+ if(NOT arg_ARGS)
+ message(FATAL_ERROR "No arguments specified to qt_internal_foreach_repo_run")
+ endif()
+ separate_arguments(args NATIVE_COMMAND "${arg_ARGS}")
+
+ # Find the qt repos
+ qt_internal_find_modules(modules)
+
+ # Hack to support color output on unix systems
+ # https://stackoverflow.com/questions/18968979/how-to-make-colorized-message-with-cmake
+ execute_process(COMMAND
+ /usr/bin/tty
+ OUTPUT_VARIABLE tty_name
+ RESULT_VARIABLE tty_exit_code
+ OUTPUT_STRIP_TRAILING_WHITESPACE
+ )
+
+ set(color_supported FALSE)
+ set(output_goes_where "")
+ if(NOT tty_exit_CODE AND tty_name)
+ set(color_supported TRUE)
+ set(output_goes_where "OUTPUT_FILE" "${tty_name}")
+ endif()
+
+ # Count successes and failures.
+ set(count_success "0")
+ set(count_failure "0")
+
+ # Show colored error markers.
+ set(color "--normal")
+ if(color_supported)
+ set(color "--red")
+ endif()
+
+ foreach(module IN LISTS modules)
+ message("Entering '${module}'")
+ execute_process(
+ COMMAND ${args}
+ WORKING_DIRECTORY "${module}"
+ ${output_goes_where}
+ RESULT_VARIABLE cmd_result
+ )
+ if(cmd_result)
+ math(EXPR count_failure "${count_failure}+1")
+ # cmake_echo_color is undocumented, but lets us output colors and control newlines.
+ execute_process(
+ COMMAND
+ ${CMAKE_COMMAND} -E env CLICOLOR_FORCE=1
+ ${CMAKE_COMMAND} -E cmake_echo_color "${color}"
+ "Process execution failed here ^^^^^^^^^^^^^^^^^^^^"
+ )
+ else()
+ math(EXPR count_success "${count_success}+1")
+ endif()
+ endforeach()
+
+ # Show summary with colors.
+ set(color "--normal")
+ if(count_failure AND color_supported)
+ set(color "--red")
+ endif()
+
+ message("\nSummary\n=======\n")
+ execute_process(
+ COMMAND
+ ${CMAKE_COMMAND} -E cmake_echo_color --normal --no-newline "Failures: "
+ )
+ execute_process(
+ COMMAND
+ ${CMAKE_COMMAND} -E env CLICOLOR_FORCE=1
+ ${CMAKE_COMMAND} -E cmake_echo_color "${color}" "${count_failure}"
+ )
+ message("Successes: ${count_success}")
+endfunction()
+
+# The function collects repos and dependencies that are required to build
+# repos listed in ARGN. If the BUILD_<repo> is defined the 'repo' will be
+# excluded from the list.
+function(qt_internal_collect_modules_only out_repos)
+ set(initial_modules "${ARGN}")
+ get_filename_component(qt5_repo_dir "${CMAKE_CURRENT_LIST_DIR}/.." ABSOLUTE)
+
+ # Overriding CMAKE_CURRENT_SOURCE_DIR is ugly but works
+ set(CMAKE_CURRENT_SOURCE_DIR "${qt5_repo_dir}")
+ if(NOT initial_modules)
+ qt_internal_find_modules(initial_modules)
+ endif()
+
+ qt_internal_sort_module_dependencies("${initial_modules}" ${out_repos})
+ foreach(module IN LISTS ${out_repos})
+ # Check for unmet dependencies
+ if(DEFINED BUILD_${module} AND NOT BUILD_${module})
+ list(REMOVE_ITEM ${out_repos} ${module})
+ continue()
+ endif()
+ get_property(required_deps GLOBAL PROPERTY QT_REQUIRED_DEPS_FOR_${module})
+ get_property(dependencies GLOBAL PROPERTY QT_DEPS_FOR_${module})
+ foreach(dep IN LISTS dependencies)
+ set(required FALSE)
+ if(dep IN_LIST required_deps)
+ set(required TRUE)
+ endif()
+ if(required AND DEFINED BUILD_${dep} AND NOT BUILD_${dep})
+ set(BUILD_${module} FALSE)
+ list(REMOVE_ITEM ${out_repos} ${module})
+ break()
+ endif()
+ endforeach()
+ endforeach()
+
+ set(${out_repos} "${${out_repos}}" PARENT_SCOPE)
+endfunction()
diff --git a/cmake/QtWriteArgsFile.cmake b/cmake/QtWriteArgsFile.cmake
new file mode 100644
index 00000000..336f8550
--- /dev/null
+++ b/cmake/QtWriteArgsFile.cmake
@@ -0,0 +1,92 @@
+# Copyright (C) 2024 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+# This script writes its arguments to the file determined by OUT_FILE.
+# Each argument appears on a separate line.
+# This is used for writing the init-repository.opt file.
+#
+# This script takes the following arguments:
+# IN_FILE: The input file. The whole command line as one string, or one argument per line.
+# REDO_FILE: A file containing extra commands to be joined with IN_FILE.
+# OUT_FILE: The output file. One argument per line.
+# SKIP_ARGS: Number of arguments to skip from the front of the arguments list.
+# IGNORE_ARGS: List of arguments to be ignored, i.e. that are not written.
+#
+# If the REDO_FILE is given, its parameters will be merged with IN_FILE parameters
+# and be written into the OUT_FILE.
+
+cmake_minimum_required(VERSION 3.16)
+
+# Read arguments from IN_FILE and separate them.
+file(READ "${IN_FILE}" raw_args)
+# To catch cases where the path ends with an `\`, e.g., `-prefix "C:\Path\"`
+string(REPLACE "\\\"" "\"" raw_args "${raw_args}")
+string(REPLACE ";" "[[;]]" raw_args "${raw_args}")
+
+separate_arguments(args NATIVE_COMMAND "${raw_args}")
+
+string(REPLACE "\;" ";" args "${args}")
+string(REPLACE "[[;]]" "\;" args "${args}")
+
+if(DEFINED REDO_FILE)
+ file(READ "${REDO_FILE}" raw_redo_args)
+ separate_arguments(redo_args NATIVE_COMMAND "${raw_redo_args}")
+
+ if(args)
+ list(FIND args "--" args_ddash_loc)
+ list(FIND redo_args "--" redo_ddash_loc)
+ if("${redo_ddash_loc}" STREQUAL "-1")
+ if("${args_ddash_loc}" STREQUAL "-1")
+ list(LENGTH args args_ddash_loc)
+ endif()
+ # Avoid adding an empty line for an empty -redo
+ if(NOT "${redo_args}" STREQUAL "")
+ list(INSERT args ${args_ddash_loc} "${redo_args}")
+ endif()
+ else()
+ # Handling redo's configure options
+ list(SUBLIST redo_args 0 ${redo_ddash_loc} redo_config_args)
+ if(redo_config_args)
+ if("${args_ddash_loc}" STREQUAL "-1")
+ list(APPEND args "${redo_config_args}")
+ else()
+ list(INSERT args ${args_ddash_loc} "${redo_config_args}")
+ endif()
+ endif()
+
+ # Handling redo's CMake options
+ list(LENGTH redo_args redo_args_len)
+ math(EXPR redo_ddash_loc "${redo_ddash_loc} + 1")
+ # Catch an unlikely case of -redo being called with an empty --, ie., `-redo --`
+ if(NOT ${redo_ddash_loc} STREQUAL ${redo_args_len})
+ list(SUBLIST redo_args ${redo_ddash_loc} -1 redo_cmake_args)
+ endif()
+
+ if(DEFINED redo_cmake_args)
+ if("${args_ddash_loc}" STREQUAL "-1")
+ list(APPEND args "--")
+ endif()
+ list(APPEND args "${redo_cmake_args}")
+ endif()
+ endif()
+ else()
+ list(APPEND args "${redo_args}")
+ endif()
+endif()
+
+# Skip arguments if requested
+if(DEFINED SKIP_ARGS)
+ foreach(i RANGE 1 ${SKIP_ARGS})
+ list(POP_FRONT args)
+ endforeach()
+endif()
+
+# Write config.opt
+set(content "")
+foreach(arg IN LISTS args)
+ if(NOT arg IN_LIST IGNORE_ARGS)
+ string(APPEND content "${arg}\n")
+ endif()
+endforeach()
+
+file(WRITE "${OUT_FILE}" "${content}")