summaryrefslogtreecommitdiffstats
path: root/cmake
diff options
context:
space:
mode:
Diffstat (limited to 'cmake')
-rw-r--r--cmake/3rdparty/extra-cmake-modules/find-modules/FindEGL.cmake10
-rw-r--r--cmake/3rdparty/extra-cmake-modules/find-modules/FindGLIB2.cmake72
-rw-r--r--cmake/3rdparty/extra-cmake-modules/find-modules/FindWaylandScanner.cmake3
-rw-r--r--cmake/3rdparty/extra-cmake-modules/find-modules/FindXCB.cmake14
-rw-r--r--cmake/3rdparty/extra-cmake-modules/modules/ECMEnableSanitizers.cmake219
-rw-r--r--cmake/3rdparty/extra-cmake-modules/modules/ECMFindModuleHelpers.cmake4
-rw-r--r--cmake/3rdparty/extra-cmake-modules/qt_attribution.json4
-rw-r--r--cmake/3rdparty/kwin/FindLibdrm.cmake16
-rw-r--r--cmake/3rdparty/kwin/qt_attribution.json2
-rw-r--r--cmake/CODESTYLE.md197
-rw-r--r--cmake/FindATSPI2.cmake5
-rw-r--r--cmake/FindCups.cmake98
-rw-r--r--cmake/FindDB2.cmake34
-rw-r--r--cmake/FindDirectFB.cmake5
-rw-r--r--cmake/FindGLESv2.cmake24
-rw-r--r--cmake/FindGSSAPI.cmake31
-rw-r--r--cmake/FindGTK3.cmake10
-rw-r--r--cmake/FindInterbase.cmake55
-rw-r--r--cmake/FindLibb2.cmake39
-rw-r--r--cmake/FindLibproxy.cmake5
-rw-r--r--cmake/FindLibsystemd.cmake5
-rw-r--r--cmake/FindLibudev.cmake5
-rw-r--r--cmake/FindMimer.cmake98
-rw-r--r--cmake/FindMtdev.cmake5
-rw-r--r--cmake/FindMySQL.cmake84
-rw-r--r--cmake/FindOracle.cmake33
-rw-r--r--cmake/FindPPS.cmake15
-rw-r--r--cmake/FindPostgreSQL.cmake321
-rw-r--r--cmake/FindRenderDoc.cmake20
-rw-r--r--cmake/FindSlog2.cmake7
-rw-r--r--cmake/FindTslib.cmake5
-rw-r--r--cmake/FindWrapAtomic.cmake41
-rw-r--r--cmake/FindWrapBacktrace.cmake20
-rw-r--r--cmake/FindWrapBrotli.cmake100
-rw-r--r--cmake/FindWrapDBus1.cmake9
-rw-r--r--cmake/FindWrapDoubleConversion.cmake22
-rw-r--r--cmake/FindWrapFreetype.cmake3
-rw-r--r--cmake/FindWrapHarfbuzz.cmake3
-rw-r--r--cmake/FindWrapJpeg.cmake14
-rw-r--r--cmake/FindWrapOpenGL.cmake21
-rw-r--r--cmake/FindWrapOpenSSL.cmake25
-rw-r--r--cmake/FindWrapOpenSSLHeaders.cmake13
-rw-r--r--cmake/FindWrapPCRE2.cmake3
-rw-r--r--cmake/FindWrapPNG.cmake3
-rw-r--r--cmake/FindWrapResolv.cmake53
-rw-r--r--cmake/FindWrapRt.cmake33
-rw-r--r--cmake/FindWrapSystemDoubleConversion.cmake85
-rw-r--r--cmake/FindWrapSystemFreetype.cmake50
-rw-r--r--cmake/FindWrapSystemHarfbuzz.cmake67
-rw-r--r--cmake/FindWrapSystemJpeg.cmake35
-rw-r--r--cmake/FindWrapSystemMd4c.cmake43
-rw-r--r--cmake/FindWrapSystemPCRE2.cmake62
-rw-r--r--cmake/FindWrapSystemPNG.cmake49
-rw-r--r--cmake/FindWrapSystemZLIB.cmake32
-rw-r--r--cmake/FindWrapVulkan.cmake23
-rw-r--r--cmake/FindWrapVulkanHeaders.cmake75
-rw-r--r--cmake/FindWrapZLIB.cmake14
-rw-r--r--cmake/FindWrapZSTD.cmake91
-rw-r--r--cmake/FindXKB_COMMON_X11.cmake5
-rw-r--r--cmake/FindXRender.cmake5
-rw-r--r--cmake/FindZSTD.cmake50
-rw-r--r--cmake/Finddouble-conversion.cmake32
-rw-r--r--cmake/ModuleDescription.json.in10
-rw-r--r--cmake/PkgConfigLibrary.pc.in14
-rw-r--r--cmake/Qt3rdPartyLibraryConfig.cmake.in12
-rw-r--r--cmake/Qt3rdPartyLibraryHelpers.cmake386
-rw-r--r--cmake/QtAndroidHelpers.cmake280
-rw-r--r--cmake/QtApp.cmake92
-rw-r--r--cmake/QtAppHelpers.cmake148
-rw-r--r--cmake/QtAutoDetect.cmake289
-rw-r--r--cmake/QtAutoDetectHelpers.cmake487
-rw-r--r--cmake/QtAutogenHelpers.cmake216
-rw-r--r--cmake/QtBaseCMakeTesting.cmake3
-rw-r--r--cmake/QtBaseConfigureTests.cmake139
-rw-r--r--cmake/QtBaseGlobalTargets.cmake555
-rw-r--r--cmake/QtBaseHelpers.cmake222
-rw-r--r--cmake/QtBaseTopLevelHelpers.cmake96
-rw-r--r--cmake/QtBuild.cmake6145
-rw-r--r--cmake/QtBuildHelpers.cmake458
-rw-r--r--cmake/QtBuildInformation.cmake271
-rw-r--r--cmake/QtBuildInternals/QtBuildInternalsAndroid.cmake216
-rw-r--r--cmake/QtBuildInternals/QtBuildInternalsConfig.cmake458
-rw-r--r--cmake/QtBuildInternals/QtStandaloneTestTemplateProject/CMakeLists.txt44
-rw-r--r--cmake/QtBuildInternals/QtStandaloneTestTemplateProject/Main.cmake27
-rw-r--r--cmake/QtBuildInternalsExtra.cmake.in98
-rw-r--r--cmake/QtBuildOptionsHelpers.cmake383
-rw-r--r--cmake/QtBuildPathsHelpers.cmake247
-rw-r--r--cmake/QtBuildRepoExamplesHelpers.cmake652
-rw-r--r--cmake/QtBuildRepoHelpers.cmake1079
-rw-r--r--cmake/QtCMakeHelpers.cmake235
-rw-r--r--cmake/QtCMakePackageVersionFile.cmake.in68
-rw-r--r--cmake/QtCMakeVersionHelpers.cmake236
-rw-r--r--cmake/QtCompilerFlags.cmake32
-rw-r--r--cmake/QtCompilerOptimization.cmake182
-rw-r--r--cmake/QtConfig.cmake.in220
-rw-r--r--cmake/QtConfigDependencies.cmake.in27
-rw-r--r--cmake/QtConfigExtras.cmake.in7
-rw-r--r--cmake/QtConfigureTimeExecutableCMakeLists.txt.in26
-rw-r--r--cmake/QtCopyFileIfDifferent.cmake18
-rw-r--r--cmake/QtDbusHelpers.cmake70
-rw-r--r--cmake/QtDeferredDependenciesHelpers.cmake31
-rw-r--r--cmake/QtDocsHelpers.cmake282
-rw-r--r--cmake/QtExecutableHelpers.cmake537
-rw-r--r--cmake/QtFeature.cmake763
-rw-r--r--cmake/QtFeatureCommon.cmake12
-rw-r--r--cmake/QtFindPackageHelpers.cmake572
-rw-r--r--cmake/QtFindWrapConfigExtra.cmake.in3
-rw-r--r--cmake/QtFindWrapHelper.cmake3
-rw-r--r--cmake/QtFinishPkgConfigFile.cmake31
-rw-r--r--cmake/QtFinishPrlFile.cmake81
-rw-r--r--cmake/QtFlagHandlingHelpers.cmake1139
-rw-r--r--cmake/QtFrameworkHelpers.cmake228
-rw-r--r--cmake/QtGenerateExtPri.cmake3
-rw-r--r--cmake/QtGenerateLibHelpers.cmake37
-rw-r--r--cmake/QtGenerateLibPri.cmake22
-rw-r--r--cmake/QtGenerateVersionScript.cmake15
-rw-r--r--cmake/QtGlobalStateHelpers.cmake88
-rw-r--r--cmake/QtHeadersClean.cmake282
-rw-r--r--cmake/QtHostInfoConfig.cmake.in4
-rw-r--r--cmake/QtInitProject.cmake214
-rw-r--r--cmake/QtInstallHelpers.cmake249
-rw-r--r--cmake/QtInstallPaths.cmake.in16
-rw-r--r--cmake/QtInternalTargets.cmake385
-rw-r--r--cmake/QtJavaHelpers.cmake30
-rw-r--r--cmake/QtLalrHelpers.cmake77
-rw-r--r--cmake/QtMkspecHelpers.cmake146
-rw-r--r--cmake/QtModuleConfig.cmake.in102
-rw-r--r--cmake/QtModuleDependencies.cmake.in116
-rw-r--r--cmake/QtModuleHeadersCheck.cmake34
-rw-r--r--cmake/QtModuleHelpers.cmake1410
-rw-r--r--cmake/QtModuleToolsConfig.cmake.in26
-rw-r--r--cmake/QtModuleToolsDependencies.cmake.in22
-rw-r--r--cmake/QtModuleToolsVersionlessTargets.cmake.in5
-rw-r--r--cmake/QtNoLinkTargetHelpers.cmake58
-rw-r--r--cmake/QtPkgConfigHelpers.cmake164
-rw-r--r--cmake/QtPlatformAndroid.cmake378
-rw-r--r--cmake/QtPlatformSupport.cmake24
-rw-r--r--cmake/QtPlatformTargetHelpers.cmake98
-rw-r--r--cmake/QtPluginConfig.cmake.in19
-rw-r--r--cmake/QtPluginDependencies.cmake.in51
-rw-r--r--cmake/QtPluginHelpers.cmake625
-rw-r--r--cmake/QtPlugins.cmake.in135
-rw-r--r--cmake/QtPostProcess.cmake579
-rw-r--r--cmake/QtPostProcessHelpers.cmake881
-rw-r--r--cmake/QtPrecompiledHeadersHelpers.cmake34
-rw-r--r--cmake/QtPriHelpers.cmake1055
-rw-r--r--cmake/QtPrlHelpers.cmake216
-rw-r--r--cmake/QtProcessConfigureArgs.cmake1155
-rw-r--r--cmake/QtProperties.cmake13
-rw-r--r--cmake/QtPublicAppleHelpers.cmake954
-rw-r--r--cmake/QtPublicCMakeHelpers.cmake510
-rw-r--r--cmake/QtPublicCMakeVersionHelpers.cmake72
-rw-r--r--cmake/QtPublicDependencyHelpers.cmake294
-rw-r--r--cmake/QtPublicExternalProjectHelpers.cmake86
-rw-r--r--cmake/QtPublicFinalizerHelpers.cmake35
-rw-r--r--cmake/QtPublicFindPackageHelpers.cmake6
-rw-r--r--cmake/QtPublicPluginHelpers.cmake562
-rw-r--r--cmake/QtPublicTargetHelpers.cmake337
-rw-r--r--cmake/QtPublicTestHelpers.cmake108
-rw-r--r--cmake/QtPublicToolHelpers.cmake116
-rw-r--r--cmake/QtPublicWalkLibsHelpers.cmake334
-rw-r--r--cmake/QtPublicWasmToolchainHelpers.cmake108
-rw-r--r--cmake/QtQmakeHelpers.cmake251
-rw-r--r--cmake/QtResourceHelpers.cmake133
-rw-r--r--cmake/QtRpathHelpers.cmake289
-rw-r--r--cmake/QtSanitizerHelpers.cmake60
-rw-r--r--cmake/QtScopeFinalizerHelpers.cmake104
-rw-r--r--cmake/QtSeparateDebugInfo.Info.plist.in5
-rw-r--r--cmake/QtSeparateDebugInfo.cmake260
-rw-r--r--cmake/QtSetup.cmake214
-rw-r--r--cmake/QtSimdHelpers.cmake110
-rw-r--r--cmake/QtSingleRepoTargetSetBuildHelpers.cmake14
-rw-r--r--cmake/QtStandaloneTestsConfig.cmake.in10
-rw-r--r--cmake/QtSyncQtHelpers.cmake324
-rw-r--r--cmake/QtTargetHelpers.cmake1671
-rw-r--r--cmake/QtTestHelpers.cmake1091
-rw-r--r--cmake/QtToolHelpers.cmake769
-rw-r--r--cmake/QtToolchainHelpers.cmake310
-rw-r--r--cmake/QtUnityBuildHelpers.cmake24
-rw-r--r--cmake/QtVersionlessAliasTargets.cmake.in7
-rw-r--r--cmake/QtVersionlessTargets.cmake.in7
-rw-r--r--cmake/QtWasmHelpers.cmake127
-rw-r--r--cmake/QtWrapperScriptHelpers.cmake333
-rw-r--r--cmake/QtWriteArgsFile.cmake92
-rw-r--r--cmake/README.md163
-rw-r--r--cmake/configure-cmake-mapping.md296
-rw-r--r--cmake/ios/Info.plist.app.in54
-rw-r--r--cmake/ios/LaunchScreen.storyboard31
-rw-r--r--cmake/ios/PrivacyInfo.xcprivacy14
-rw-r--r--cmake/macos/Info.plist.app.in (renamed from cmake/macos/MacOSXBundleInfo.plist.in)8
-rw-r--r--cmake/macos/PrivacyInfo.xcprivacy12
-rw-r--r--cmake/modulecppexports.h.in50
-rw-r--r--cmake/platforms/FindIntegrityPlatformGraphics.cmake29
-rw-r--r--cmake/platforms/Platform/Integrity.cmake11
-rw-r--r--cmake/qbatchedtestrunner.in.cpp18
-rw-r--r--cmake/qt.toolchain.cmake.in134
-rw-r--r--cmake/tests/CMakeLists.txt3
-rw-r--r--cmake/tests/features/CMakeLists.txt5
-rw-r--r--cmake/tests/features/configure.cmake3
-rw-r--r--cmake/tests/features/src/CMakeLists.txt3
-rw-r--r--cmake/tests/qt_make_output_file/CMakeLists.txt5
-rw-r--r--cmake/tests/test.cmake3
-rw-r--r--cmake/visionos/Info.plist.app.in42
-rw-r--r--cmake/visionos/PrivacyInfo.xcprivacy14
204 files changed, 29665 insertions, 10084 deletions
diff --git a/cmake/3rdparty/extra-cmake-modules/find-modules/FindEGL.cmake b/cmake/3rdparty/extra-cmake-modules/find-modules/FindEGL.cmake
index 55ca2a99bd..9ac8e2fa0c 100644
--- a/cmake/3rdparty/extra-cmake-modules/find-modules/FindEGL.cmake
+++ b/cmake/3rdparty/extra-cmake-modules/find-modules/FindEGL.cmake
@@ -118,12 +118,18 @@ endif()
cmake_push_check_state(RESET)
list(APPEND CMAKE_REQUIRED_LIBRARIES "${EGL_LIBRARY}")
list(APPEND CMAKE_REQUIRED_INCLUDES "${EGL_INCLUDE_DIR}")
+list(APPEND CMAKE_REQUIRED_DEFINITIONS "${EGL_DEFINITIONS}")
+
+if(_qt_igy_gui_libs)
+ list(APPEND CMAKE_REQUIRED_LIBRARIES "${_qt_igy_gui_libs}")
+endif()
check_cxx_source_compiles("
#include <EGL/egl.h>
-int main(int argc, char *argv[]) {
- EGLint x = 0; EGLDisplay dpy = 0; EGLContext ctx = 0;
+int main(int, char **) {
+ [[maybe_unused]] EGLint x = 0;
+ EGLDisplay dpy = 0; EGLContext ctx = 0;
eglDestroyContext(dpy, ctx);
}" HAVE_EGL)
diff --git a/cmake/3rdparty/extra-cmake-modules/find-modules/FindGLIB2.cmake b/cmake/3rdparty/extra-cmake-modules/find-modules/FindGLIB2.cmake
index 1e13104187..24a194c9cb 100644
--- a/cmake/3rdparty/extra-cmake-modules/find-modules/FindGLIB2.cmake
+++ b/cmake/3rdparty/extra-cmake-modules/find-modules/FindGLIB2.cmake
@@ -64,6 +64,37 @@ find_library(GLIB2_LIBRARIES
HINTS ${PC_GLIB2_LIBDIR}
)
+pkg_check_modules(PC_GTHREAD2 QUIET gthread-2.0)
+
+find_library(GTHREAD2_LIBRARIES
+ NAMES gthread-2.0
+ HINTS ${PC_GTHREAD2_LIBDIR}
+)
+
+pkg_check_modules(PC_GOBJECT QUIET gobject-2.0)
+
+find_path(GLIB2_GOBJECT_INCLUDE_DIRS
+ NAMES glib-object.h
+ HINTS ${PC_GOBJECT_INCLUDEDIR}
+ PATH_SUFFIXES glib-2.0)
+
+find_library(GLIB2_GOBJECT_LIBRARIES
+ NAMES gobject-2.0
+ HINTS ${PC_GOBJECT_LIBDIR}
+)
+
+pkg_check_modules(PC_GIO QUIET gio-2.0)
+
+find_path(GLIB2_GIO_INCLUDE_DIRS
+ NAMES gio/gio.h
+ HINTS ${PC_GIO_INCLUDEDIR}
+ PATH_SUFFIXES glib-2.0)
+
+find_library(GLIB2_GIO_LIBRARIES
+ NAMES gio-2.0
+ HINTS ${PC_GIO_LIBDIR}
+)
+
# search the glibconfig.h include dir under the same root where the library is found
get_filename_component(glib2LibDir "${GLIB2_LIBRARIES}" PATH)
@@ -75,24 +106,59 @@ find_path(GLIB2_INTERNAL_INCLUDE_DIR glibconfig.h
# for now it is optional
if(GLIB2_INTERNAL_INCLUDE_DIR)
list(APPEND GLIB2_INCLUDE_DIRS "${GLIB2_INTERNAL_INCLUDE_DIR}")
+ list(APPEND GLIB2_GOBJECT_INCLUDE_DIRS "${GLIB2_INTERNAL_INCLUDE_DIR}")
+ list(APPEND GLIB2_GIO_INCLUDE_DIRS "${GLIB2_INTERNAL_INCLUDE_DIR}")
endif()
# Deprecated synonyms
set(GLIB2_INCLUDE_DIR "${GLIB2_INCLUDE_DIRS}")
set(GLIB2_LIBRARY "${GLIB2_LIBRARIES}")
+set(GLIB2_GOBJECT_INCLUDE_DIR "${GLIB2_GOBJECT_INCLUDE_DIRS}")
+set(GLIB2_GOBJECT_LIBRARY "${GLIB2_GOBJECT_LIBRARIES}")
+set(GLIB2_GIO_INCLUDE_DIR "${GLIB2_GIO_INCLUDE_DIRS}")
+set(GLIB2_GIO_LIBRARY "${GLIB2_GIO_LIBRARIES}")
+
+if(GLIB2_GOBJECT_LIBRARIES AND GLIB2_GOBJECT_INCLUDE_DIRS)
+ set(GLIB2_GOBJECT_FOUND TRUE)
+endif()
+
+if(GLIB2_GIO_LIBRARIES AND GLIB2_GIO_INCLUDE_DIRS)
+ set(GLIB2_GIO_FOUND TRUE)
+endif()
include(FindPackageHandleStandardArgs)
-find_package_handle_standard_args(GLIB2 DEFAULT_MSG GLIB2_LIBRARIES GLIB2_INCLUDE_DIRS)
+find_package_handle_standard_args(GLIB2
+ REQUIRED_VARS GLIB2_LIBRARIES GTHREAD2_LIBRARIES GLIB2_INCLUDE_DIRS
+ HANDLE_COMPONENTS)
if(GLIB2_FOUND AND NOT TARGET GLIB2::GLIB2)
add_library(GLIB2::GLIB2 UNKNOWN IMPORTED)
set_target_properties(GLIB2::GLIB2 PROPERTIES
IMPORTED_LOCATION "${GLIB2_LIBRARIES}"
- INTERFACE_INCLUDE_DIRECTORIES "${GLIB2_INCLUDE_DIRS}")
+ INTERFACE_LINK_LIBRARIES "${GTHREAD2_LIBRARIES}"
+ INTERFACE_INCLUDE_DIRECTORIES "${GLIB2_INCLUDE_DIRS}")
+endif()
+
+if(GLIB2_GOBJECT_FOUND AND NOT TARGET GLIB2::GOBJECT)
+ add_library(GLIB2::GOBJECT UNKNOWN IMPORTED)
+ set_target_properties(GLIB2::GOBJECT PROPERTIES
+ IMPORTED_LOCATION "${GLIB2_GOBJECT_LIBRARIES}"
+ INTERFACE_INCLUDE_DIRECTORIES "${GLIB2_GOBJECT_INCLUDE_DIRS}")
+endif()
+
+if(GLIB2_GIO_FOUND AND NOT TARGET GLIB2::GIO)
+ add_library(GLIB2::GIO UNKNOWN IMPORTED)
+ set_target_properties(GLIB2::GIO PROPERTIES
+ IMPORTED_LOCATION "${GLIB2_GIO_LIBRARIES}"
+ INTERFACE_INCLUDE_DIRECTORIES "${GLIB2_GIO_INCLUDE_DIRS}")
endif()
mark_as_advanced(GLIB2_INCLUDE_DIRS GLIB2_INCLUDE_DIR
- GLIB2_LIBRARIES GLIB2_LIBRARY)
+ GLIB2_LIBRARIES GLIB2_LIBRARY
+ GLIB2_GOBJECT_INCLUDE_DIRS GLIB2_GOBJECT_INCLUDE_DIR
+ GLIB2_GOBJECT_LIBRARIES GLIB2_GOBJECT_LIBRARY
+ GLIB2_GIO_INCLUDE_DIRS GLIB2_GIO_INCLUDE_DIR
+ GLIB2_GIO_LIBRARIES GLIB2_GIO_LIBRARY)
include(FeatureSummary)
set_package_properties(GLIB2 PROPERTIES
diff --git a/cmake/3rdparty/extra-cmake-modules/find-modules/FindWaylandScanner.cmake b/cmake/3rdparty/extra-cmake-modules/find-modules/FindWaylandScanner.cmake
index 13291afcda..60adaf4184 100644
--- a/cmake/3rdparty/extra-cmake-modules/find-modules/FindWaylandScanner.cmake
+++ b/cmake/3rdparty/extra-cmake-modules/find-modules/FindWaylandScanner.cmake
@@ -107,9 +107,6 @@ set_package_properties(WaylandScanner PROPERTIES
DESCRIPTION "Executable that converts XML protocol files to C code"
)
-
-include(CMakeParseArguments)
-
function(ecm_add_wayland_client_protocol out_var)
# Parse arguments
set(oneValueArgs PROTOCOL BASENAME)
diff --git a/cmake/3rdparty/extra-cmake-modules/find-modules/FindXCB.cmake b/cmake/3rdparty/extra-cmake-modules/find-modules/FindXCB.cmake
index d530d2d7f4..26b9bf8963 100644
--- a/cmake/3rdparty/extra-cmake-modules/find-modules/FindXCB.cmake
+++ b/cmake/3rdparty/extra-cmake-modules/find-modules/FindXCB.cmake
@@ -129,10 +129,6 @@ set(XCB_known_components
XVMC
)
-# XINPUT is unstable; do not include it by default
-set(XCB_default_components ${XCB_known_components})
-list(REMOVE_ITEM XCB_default_components "XINPUT")
-
# default component info: xcb components have fairly predictable
# header files, library names and pkg-config names
foreach(_comp ${XCB_known_components})
@@ -141,6 +137,9 @@ foreach(_comp ${XCB_known_components})
set(XCB_${_comp}_pkg_config "xcb-${_lc_comp}")
set(XCB_${_comp}_lib "xcb-${_lc_comp}")
set(XCB_${_comp}_header "xcb/${_lc_comp}.h")
+ if(USE_XCB_${_comp}_STATIC)
+ set(XCB_${_comp}_lib "lib${XCB_${_comp}_lib}.a")
+ endif()
endforeach()
# exceptions
set(XCB_XCB_component_deps)
@@ -175,11 +174,6 @@ ecm_find_package_parse_components(XCB
DEFAULT_COMPONENTS ${XCB_default_components}
)
-list(FIND XCB_components "XINPUT" _XCB_XINPUT_index)
-if (NOT _XCB_XINPUT_index EQUAL -1)
- message(AUTHOR_WARNING "XINPUT from XCB was requested: this is EXPERIMENTAL and is likely to unavailable on many systems!")
-endif()
-
ecm_find_package_handle_library_components(XCB
COMPONENTS ${XCB_components}
)
@@ -196,6 +190,6 @@ find_package_handle_standard_args(XCB
include(FeatureSummary)
set_package_properties(XCB PROPERTIES
- URL "http://xcb.freedesktop.org"
+ URL "https://xcb.freedesktop.org/"
DESCRIPTION "X protocol C-language Binding"
)
diff --git a/cmake/3rdparty/extra-cmake-modules/modules/ECMEnableSanitizers.cmake b/cmake/3rdparty/extra-cmake-modules/modules/ECMEnableSanitizers.cmake
index 06cc0b66d8..15610587bd 100644
--- a/cmake/3rdparty/extra-cmake-modules/modules/ECMEnableSanitizers.cmake
+++ b/cmake/3rdparty/extra-cmake-modules/modules/ECMEnableSanitizers.cmake
@@ -1,102 +1,83 @@
-#.rst:
-# ECMEnableSanitizers
-# -------------------
+# SPDX-FileCopyrightText: 2014 Mathieu Tarral <mathieu.tarral@gmail.com>
#
-# Enable compiler sanitizer flags.
-#
-# The following sanitizers are supported:
-#
-# - Address Sanitizer
-# - Memory Sanitizer
-# - Thread Sanitizer
-# - Leak Sanitizer
-# - Undefined Behaviour Sanitizer
-#
-# All of them are implemented in Clang, depending on your version, and
-# there is an work in progress in GCC, where some of them are currently
-# implemented.
-#
-# This module will check your current compiler version to see if it
-# supports the sanitizers that you want to enable
-#
-# Usage
-# =====
-#
-# Simply add::
-#
-# include(ECMEnableSanitizers)
-#
-# to your ``CMakeLists.txt``. Note that this module is included in
-# KDECompilerSettings, so projects using that module do not need to also
-# include this one.
-#
-# The sanitizers are not enabled by default. Instead, you must set
-# ``ECM_ENABLE_SANITIZERS`` (either in your ``CMakeLists.txt`` or on the
-# command line) to a semicolon-separated list of sanitizers you wish to enable.
-# The options are:
-#
-# - address
-# - memory
-# - thread
-# - leak
-# - undefined
-#
-# The sanitizers "address", "memory" and "thread" are mutually exclusive. You
-# cannot enable two of them in the same build.
-#
-# "leak" requires the "address" sanitizer.
-#
-# .. note::
-#
-# To reduce the overhead induced by the instrumentation of the sanitizers, it
-# is advised to enable compiler optimizations (``-O1`` or higher).
-#
-# Example
-# =======
-#
-# This is an example of usage::
-#
-# mkdir build
-# cd build
-# cmake -DECM_ENABLE_SANITIZERS='address;leak;undefined' ..
-#
-# .. note::
-#
-# Most of the sanitizers will require Clang. To enable it, use::
-#
-# -DCMAKE_CXX_COMPILER=clang++
-#
-# Since 1.3.0.
+# SPDX-License-Identifier: BSD-3-Clause
-#=============================================================================
-# Copyright 2014 Mathieu Tarral <mathieu.tarral@gmail.com>
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions
-# are met:
-#
-# 1. Redistributions of source code must retain the copyright
-# notice, this list of conditions and the following disclaimer.
-# 2. Redistributions in binary form must reproduce the copyright
-# notice, this list of conditions and the following disclaimer in the
-# documentation and/or other materials provided with the distribution.
-# 3. The name of the author may not be used to endorse or promote products
-# derived from this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+#[=======================================================================[.rst:
+ECMEnableSanitizers
+-------------------
+
+Enable compiler sanitizer flags.
+
+The following sanitizers are supported:
+
+- Address Sanitizer
+- Memory Sanitizer
+- Thread Sanitizer
+- Leak Sanitizer
+- Undefined Behaviour Sanitizer
+
+All of them are implemented in Clang, depending on your version, and
+there is an work in progress in GCC, where some of them are currently
+implemented.
+
+This module will check your current compiler version to see if it
+supports the sanitizers that you want to enable
+
+Usage
+=====
+
+Simply add::
+
+ include(ECMEnableSanitizers)
+
+to your ``CMakeLists.txt``. Note that this module is included in
+KDECompilerSettings, so projects using that module do not need to also
+include this one.
+
+The sanitizers are not enabled by default. Instead, you must set
+``ECM_ENABLE_SANITIZERS`` (either in your ``CMakeLists.txt`` or on the
+command line) to a semicolon-separated list of sanitizers you wish to enable.
+The options are:
+
+- address
+- memory
+- thread
+- leak
+- undefined
+- fuzzer-no-link
+- fuzzer
+
+The sanitizers "address", "memory" and "thread" are mutually exclusive. You
+cannot enable two of them in the same build.
+
+"leak" requires the "address" sanitizer.
+
+.. note::
+
+ To reduce the overhead induced by the instrumentation of the sanitizers, it
+ is advised to enable compiler optimizations (``-O1`` or higher).
+
+Example
+=======
+
+This is an example of usage::
+
+ mkdir build
+ cd build
+ cmake -DECM_ENABLE_SANITIZERS='address;leak;undefined' ..
+
+.. note::
+
+ Most of the sanitizers will require Clang. To enable it, use::
+
+ -DCMAKE_CXX_COMPILER=clang++
+
+Since 1.3.0.
+#]=======================================================================]
# MACRO check_compiler_version
#-----------------------------
-macro (check_compiler_version gcc_required_version clang_required_version)
+macro (check_compiler_version gcc_required_version clang_required_version msvc_required_version)
if (
(
CMAKE_CXX_COMPILER_ID MATCHES "GNU"
@@ -109,12 +90,19 @@ macro (check_compiler_version gcc_required_version clang_required_version)
AND
CMAKE_CXX_COMPILER_VERSION VERSION_LESS ${clang_required_version}
)
+ OR
+ (
+ CMAKE_CXX_COMPILER_ID MATCHES "MSVC"
+ AND
+ CMAKE_CXX_COMPILER_VERSION VERSION_LESS ${msvc_required_version}
+ )
)
# error !
message(FATAL_ERROR "You ask to enable the sanitizer ${CUR_SANITIZER},
but your compiler ${CMAKE_CXX_COMPILER_ID} version ${CMAKE_CXX_COMPILER_VERSION}
does not support it !
- You should use at least GCC ${gcc_required_version} or Clang ${clang_required_version}
+ You should use at least GCC ${gcc_required_version}, Clang ${clang_required_version}
+ or MSVC ${msvc_required_version}
(99.99 means not implemented yet)")
endif ()
endmacro ()
@@ -123,30 +111,41 @@ endmacro ()
#------------------------------
macro (enable_sanitizer_flags sanitize_option)
if (${sanitize_option} MATCHES "address")
- check_compiler_version("4.8" "3.1")
- set(XSAN_COMPILE_FLAGS "-fsanitize=address -fno-omit-frame-pointer -fno-optimize-sibling-calls")
- set(XSAN_LINKER_FLAGS "asan")
+ check_compiler_version("4.8" "3.1" "19.28")
+ if (CMAKE_CXX_COMPILER_ID MATCHES "MSVC")
+ set(XSAN_COMPILE_FLAGS "-fsanitize=address")
+ else()
+ set(XSAN_COMPILE_FLAGS "-fsanitize=address -fno-omit-frame-pointer -fno-optimize-sibling-calls")
+ set(XSAN_LINKER_FLAGS "asan")
+ endif()
elseif (${sanitize_option} MATCHES "thread")
- check_compiler_version("4.8" "3.1")
+ check_compiler_version("4.8" "3.1" "99.99")
set(XSAN_COMPILE_FLAGS "-fsanitize=thread")
set(XSAN_LINKER_FLAGS "tsan")
elseif (${sanitize_option} MATCHES "memory")
- check_compiler_version("99.99" "3.1")
+ check_compiler_version("99.99" "3.1" "99.99")
set(XSAN_COMPILE_FLAGS "-fsanitize=memory")
elseif (${sanitize_option} MATCHES "leak")
- check_compiler_version("4.9" "3.4")
+ check_compiler_version("4.9" "3.4" "99.99")
set(XSAN_COMPILE_FLAGS "-fsanitize=leak")
set(XSAN_LINKER_FLAGS "lsan")
elseif (${sanitize_option} MATCHES "undefined")
- check_compiler_version("4.9" "3.1")
- set(XSAN_COMPILE_FLAGS "-fsanitize=undefined -fno-omit-frame-pointer -fno-optimize-sibling-calls")
+ check_compiler_version("4.9" "3.1" "99.99")
+ set(XSAN_COMPILE_FLAGS "-fsanitize=undefined -fsanitize=float-divide-by-zero -fno-omit-frame-pointer -fno-optimize-sibling-calls")
+ elseif (${sanitize_option} MATCHES "fuzzer-no-link")
+ check_compiler_version("99.99" "6.0" "99.99")
+ set(XSAN_COMPILE_FLAGS "-fsanitize=fuzzer-no-link")
+ set(XSAN_LINKER_FLAGS "-fsanitize=fuzzer-no-link")
+ elseif (${sanitize_option} MATCHES "fuzzer")
+ check_compiler_version("99.99" "6.0" "99.99")
+ set(XSAN_COMPILE_FLAGS "-fsanitize=fuzzer")
else ()
message(FATAL_ERROR "Compiler sanitizer option \"${sanitize_option}\" not supported.")
endif ()
endmacro ()
if (ECM_ENABLE_SANITIZERS)
- if (CMAKE_CXX_COMPILER_ID MATCHES "GNU" OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
+ if (CMAKE_CXX_COMPILER_ID MATCHES "GNU" OR CMAKE_CXX_COMPILER_ID MATCHES "Clang" OR CMAKE_CXX_COMPILER_ID MATCHES "MSVC")
# for each element of the ECM_ENABLE_SANITIZERS list
foreach ( CUR_SANITIZER ${ECM_ENABLE_SANITIZERS} )
# lowercase filter
@@ -159,9 +158,17 @@ if (ECM_ENABLE_SANITIZERS)
endif()
set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${XSAN_COMPILE_FLAGS}" )
if(CMAKE_CXX_COMPILER_ID MATCHES "GNU")
- link_libraries(${XSAN_LINKER_FLAGS})
+ string(JOIN "" linker_flags
+ "$<"
+ "$<NOT:"
+ "$<BOOL:$<TARGET_PROPERTY:SKIP_SANITIZER>>"
+ ">:"
+ "${XSAN_LINKER_FLAGS}"
+ ">"
+ )
+ link_libraries("${linker_flags}")
endif()
- if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
+ if (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
string(REPLACE "-Wl,--no-undefined" "" CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS}")
string(REPLACE "-Wl,--no-undefined" "" CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS}")
endif ()
diff --git a/cmake/3rdparty/extra-cmake-modules/modules/ECMFindModuleHelpers.cmake b/cmake/3rdparty/extra-cmake-modules/modules/ECMFindModuleHelpers.cmake
index c1df19d504..a5dabb1074 100644
--- a/cmake/3rdparty/extra-cmake-modules/modules/ECMFindModuleHelpers.cmake
+++ b/cmake/3rdparty/extra-cmake-modules/modules/ECMFindModuleHelpers.cmake
@@ -68,7 +68,7 @@
# If SKIP_DEPENDENCY_HANDLING is not set, the INTERFACE_LINK_LIBRARIES property
# of the imported target for <component> will be set to contain the imported
# targets for the components listed in <name>_<component>_component_deps.
-# <component>_FOUND will also be set to false if any of the compoments in
+# <component>_FOUND will also be set to false if any of the components in
# <name>_<component>_component_deps are not found. This requires the components
# in <name>_<component>_component_deps to be listed before <component> in the
# COMPONENTS argument.
@@ -123,8 +123,6 @@
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-include(CMakeParseArguments)
-
macro(ecm_find_package_version_check module_name)
if(CMAKE_VERSION VERSION_LESS 2.8.12)
message(FATAL_ERROR "CMake 2.8.12 is required by Find${module_name}.cmake")
diff --git a/cmake/3rdparty/extra-cmake-modules/qt_attribution.json b/cmake/3rdparty/extra-cmake-modules/qt_attribution.json
index cebebf82eb..1839af3690 100644
--- a/cmake/3rdparty/extra-cmake-modules/qt_attribution.json
+++ b/cmake/3rdparty/extra-cmake-modules/qt_attribution.json
@@ -6,10 +6,10 @@
"Description": "Additional CMake modules.",
"Homepage": "https://api.kde.org/ecm/",
- "Version": "5.50.0",
+ "Version": "5.84.0",
"License": "BSD-3-Clause",
- "LicenseId": "BSD 3-Clause License",
+ "LicenseId": "BSD-3-Clause",
"LicenseFile": "COPYING-CMAKE-SCRIPTS",
"Copyright": "Copyright © 2011-2018 The KDE community"
}
diff --git a/cmake/3rdparty/kwin/FindLibdrm.cmake b/cmake/3rdparty/kwin/FindLibdrm.cmake
index 48598e061b..a94e7fbcb6 100644
--- a/cmake/3rdparty/kwin/FindLibdrm.cmake
+++ b/cmake/3rdparty/kwin/FindLibdrm.cmake
@@ -78,6 +78,8 @@ if(NOT WIN32)
xf86drm.h
HINTS
${PKG_Libdrm_INCLUDE_DIRS}
+ PATH_SUFFIXES
+ libdrm
)
find_library(Libdrm_LIBRARY
NAMES
@@ -103,14 +105,14 @@ if(NOT WIN32)
IMPORTED_LOCATION "${Libdrm_LIBRARY}"
INTERFACE_COMPILE_OPTIONS "${Libdrm_DEFINITIONS}"
INTERFACE_INCLUDE_DIRECTORIES "${Libdrm_INCLUDE_DIR}"
- INTERFACE_INCLUDE_DIRECTORIES "${Libdrm_INCLUDE_DIR}/libdrm"
)
- if(EXISTS "${Libdrm_INCLUDE_DIR}/drm")
- set_property(TARGET Libdrm::Libdrm APPEND PROPERTY
- INTERFACE_INCLUDE_DIRECTORIES "${Libdrm_INCLUDE_DIR}/drm"
- )
- endif()
-
+ foreach(suffix libdrm drm)
+ if(EXISTS "${Libdrm_INCLUDE_DIR}/${suffix}")
+ set_property(TARGET Libdrm::Libdrm APPEND PROPERTY
+ INTERFACE_INCLUDE_DIRECTORIES "${Libdrm_INCLUDE_DIR}/${suffix}"
+ )
+ endif()
+ endforeach()
endif()
mark_as_advanced(Libdrm_LIBRARY Libdrm_INCLUDE_DIR)
diff --git a/cmake/3rdparty/kwin/qt_attribution.json b/cmake/3rdparty/kwin/qt_attribution.json
index 5c22641132..fef6bbe4c3 100644
--- a/cmake/3rdparty/kwin/qt_attribution.json
+++ b/cmake/3rdparty/kwin/qt_attribution.json
@@ -9,7 +9,7 @@
"Version": "5.13.4",
"License": "BSD-3-Clause",
- "LicenseId": "BSD 3-Clause License",
+ "LicenseId": "BSD-3-Clause",
"LicenseFile": "COPYING-CMAKE-SCRIPTS",
"Copyright": "Copyright 2014 Alex Merry <alex.merry@kde.org>
Copyright 2014 Martin Gräßlin <mgraesslin@kde.org>,
diff --git a/cmake/CODESTYLE.md b/cmake/CODESTYLE.md
new file mode 100644
index 0000000000..6dfc676d16
--- /dev/null
+++ b/cmake/CODESTYLE.md
@@ -0,0 +1,197 @@
+# Unofficial Qt CMake Coding Style
+
+CMake scripts are a bit of a wild west. Depending on when the code was written, there were
+different conventions as well as syntax facilities available. It's also unfortunate that there is
+no agreed upon CMake code formatter similar to clang-format.
+https://github.com/cheshirekow/cmake_format exists, but appears abandoned. We might look into
+using it at some point.
+
+It's hard to convince people to use a certain code style for a language like CMake.
+
+Nevertheless this short document aims to be a guideline for formatting CMake code within the Qt
+project.
+
+## Common conventions
+
+* When in doubt, prefer the local code conventions of the function or file you are editing.
+* Prefer functions over macros (macros have certain problems with parameter escaping)
+* Prefix macro local variables to avoid naming collisions
+
+## Case Styles
+
+For CMake identifiers we refer to following case styles in the text below.
+
+| Case style name | Example identifier |
+|-------------------|----------------------------|
+| Snake case | `moc_options` |
+| Shouty case | `INTERFACE_LINK_LIBRARIES` |
+| Pascal case | `QmlModels` |
+
+## Indentation
+
+* When in doubt, follow local indentation
+* Prefer indenting with 4 spaces, e.g.
+
+```
+if(1)
+ if(2)
+ message("3")
+ endif()
+endif()
+
+```
+
+## Variables
+
+* local variables inside a function should be snake cased => `list_of_arguments`
+* local variables inside a macro should be snake cased and have a unique prefix =>
+ `__qt_list_of_packages`
+ * If your macro is recursively called, you might need to prepend a dynamically computed prefix
+ to avoid overriding the same variable in nested calls =>
+ `__qt_${dependency_name}_list_of_packages`
+* cache variables should be shouty cased => `BUILD_SHARED_LIBS`
+ * Qt cache variables should be prefixed with `QT_`
+
+## Properties
+
+Currently the Qt property naming is a bit of a mess. The upstream issue
+https://gitlab.kitware.com/cmake/cmake/-/issues/19261 mentions that properties prefixed with
+`INTERFACE_` are reserved for CMake use.
+
+Prefer to use snake case for new property names.
+
+* Most upstream CMake properties are shouty cased => `INTERFACE_LINK_LIBRARIES`
+* Properties created in Qt 5 times follow the same CMake convention => `QT_ENABLED_PUBLIC_FEATURES`
+ No such new properties should be added.
+* New Qt properties should be snake cased and prefixed with `qt_` => `qt_qmake_module_name`
+* Other internal Qt properties should be snake cased and prefixed with `_qt_` => `_qt_target_deps`
+
+## Functions
+
+* Function names should be snake cased => `qt_add_module`
+ * public Qt functions should be prefixed with `qt_`
+ * internal Qt functions should be prefixed with `qt_internal_`
+ * internal Qt functions that live in public CMake API files should be prefixed with
+ `_qt_internal_`
+ * some internal functions that live in public CMake API files are prefixed with
+ `__qt_internal_`, prefer not to introduce such functions for now
+* If a public function takes more than 1 parameter, consider using `cmake_parse_arguments`
+* If an internal Qt function takes more than 1 parameter, consider using `qt_parse_all_arguments`
+* Public functions should usually have both a version-full and version-less name => `qt_add_plugin`
+ and `qt6_add_plugin`
+
+### Macros
+
+* Try to avoid macros where a function can be used instead
+ * A common case when a macro can not be avoided is when it wraps a CMake macro e.g
+ `find_package` => `qt_find_package`
+* Macro names should be snake cased => `qt_find_package`
+* Prefix macro local variables to avoid naming collisions => `__qt_find_package_arguments`
+
+## Commands
+
+Command names in CMake are case-insensitive, therefore:
+* Only use lower case command names e.g `add_executable(app main.cpp)` not `ADD_EXECUTABLE(app
+ main.cpp)`
+* Command flags / options are usually shouty cased => `file(GENERATE OUTPUT "foo" CONTENT "bar")`
+
+## 'If' command
+
+* Keep the parenthesis next to the `if()`, so don't write `if ()`. `if` is a command name and like
+ other command names e.g. `find_package(foo bar)` the parenethesis are next to the name.
+
+* To check that a variable is an empty string (and not just a falsy value, think Javascript's
+ `foo === ""`) use the following snippet
+```
+if(var_name STREQUAL "")
+ message("${var_name}")
+endif()
+```
+
+If you are not sure if the variable is defined, make sure to evaluate the variable name
+```
+if("${var_name}" STREQUAL "")
+ message("${var_name}")
+endif()
+```
+
+
+* Falsy values are `0`, `OFF`, `NO`, `FALSE`, `N`, `IGNORE`, `NOTFOUND`, the empty string `""`, or
+ a string ending in `-NOTFOUND`. To check that a variable is NOT falsy use the first suggested
+ code snippet
+```
+# Nice and clean
+if(var_name)
+ message("${var_name}")
+endif()
+
+# Wrong, can lead to problems due to double variable evaluation
+if(${var_name})
+ message("${var_name}")
+endif()
+
+# Incorrect if you want to check for all falsy values. This only checks for string emptiness.
+if("${var_name}" STREQUAL "")
+ message("${var_name}")
+endif()
+```
+
+* To check if a variable is defined, use
+```
+if(DEFINED var_name)
+endif()
+```
+
+* To compare a defined variable's contents to a string, use
+```
+if(var_name STREQUAL "my_string")
+endif()
+```
+
+* To compare a defined variable's contents to another defined variable's contents, use
+```
+if(var_name STREQUAL var_name_2)
+endif()
+```
+
+* To compare a possibly undefined variable make sure to explicitly evaluate it first
+```
+if("${var_name}" STREQUAL "my_string")
+endif()
+
+if("${var_name}" STREQUAL "${var_name_2}")
+endif()
+```
+
+## find_package
+
+* Inside Qt module projects, use the private Qt-specific `qt_find_package` macro to look for
+ dependencies.
+ * Make sure to specify the `PROVIDED_TARGETS` option to properly register 3rd party target
+ dependencies with Qt's internal build system.
+* Inside examples / projects (which only use public CMake API) use the regular `find_package`
+ command.
+
+## CMake Target names
+
+* Qt target names should be pascal cased => `QuickParticles`.
+* When Qt is installed, the Qt CMake targets are put inside the `Qt6::` namespace. Associated
+ versionless targets in the `Qt::` namespace are usually automatically created by appropriate
+ functions (`qt_internal_add_module`, `qt_internal_add_tool`)
+* Wrapper 3rd party system libraries usually repeat the target name as the namespace e.g.
+ ```WrapSystemHarfbuzz::WrapSystemHarfbuzz```
+
+## Finding 3rd party libraries via Find modules (FindWrapFoo.cmake)
+
+qmake-Qt uses `configure.json` and `configure.pri` and `QT_LIBS_FOO` variables to implement a
+mechnism that searches for system 3rd party libraries.
+
+The equivalent CMake mechanism are Find modules (and CMake package Config files; not to be confused
+with pkg-config). Usually Qt provides wrapper Find modules that use any available upstream Find
+modules or Config package files.
+
+The naming convention for the files are:
+
+* `FindWrapFoo.cmake` => `FindWrapPCRE2.cmake`
+* `FindWrapSystemFoo.cmake` => `FindWrapSystemPCRE2.cmake`
+
diff --git a/cmake/FindATSPI2.cmake b/cmake/FindATSPI2.cmake
index 68c541cca3..80176db579 100644
--- a/cmake/FindATSPI2.cmake
+++ b/cmake/FindATSPI2.cmake
@@ -1,6 +1,9 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
find_package(PkgConfig QUIET)
-pkg_check_modules(ATSPI2 atspi-2 IMPORTED_TARGET)
+pkg_check_modules(ATSPI2 IMPORTED_TARGET "atspi-2")
if (NOT TARGET PkgConfig::ATSPI2)
set(ATSPI2_FOUND 0)
diff --git a/cmake/FindCups.cmake b/cmake/FindCups.cmake
deleted file mode 100644
index 7a78100aae..0000000000
--- a/cmake/FindCups.cmake
+++ /dev/null
@@ -1,98 +0,0 @@
-# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
-# file Copyright.txt or https://cmake.org/licensing for details.
-
-#[=======================================================================[.rst:
-FindCups
---------
-
-Find the CUPS printing system.
-
-Set CUPS_REQUIRE_IPP_DELETE_ATTRIBUTE to TRUE if you need a version which
-features this function (i.e. at least 1.1.19)
-
-Imported targets
-^^^^^^^^^^^^^^^^
-
-This module defines :prop_tgt:`IMPORTED` target ``Cups::Cups``, if Cups has
-been found.
-
-Result variables
-^^^^^^^^^^^^^^^^
-
-This module will set the following variables in your project:
-
-``CUPS_FOUND``
- true if CUPS headers and libraries were found
-``CUPS_INCLUDE_DIRS``
- the directory containing the Cups headers
-``CUPS_LIBRARIES``
- the libraries to link against to use CUPS.
-``CUPS_VERSION_STRING``
- the version of CUPS found (since CMake 2.8.8)
-
-Cache variables
-^^^^^^^^^^^^^^^
-
-The following cache variables may also be set:
-
-``CUPS_INCLUDE_DIR``
- the directory containing the Cups headers
-#]=======================================================================]
-
-find_path(CUPS_INCLUDE_DIR cups/cups.h )
-
-find_library(CUPS_LIBRARIES NAMES cups )
-
-if (CUPS_INCLUDE_DIR AND CUPS_LIBRARIES AND CUPS_REQUIRE_IPP_DELETE_ATTRIBUTE)
- include(${CMAKE_CURRENT_LIST_DIR}/CheckLibraryExists.cmake)
- include(${CMAKE_CURRENT_LIST_DIR}/CMakePushCheckState.cmake)
- cmake_push_check_state()
- set(CMAKE_REQUIRED_QUIET ${Cups_FIND_QUIETLY})
-
- # ippDeleteAttribute is new in cups-1.1.19 (and used by kdeprint)
- CHECK_LIBRARY_EXISTS(cups ippDeleteAttribute "" CUPS_HAS_IPP_DELETE_ATTRIBUTE)
- cmake_pop_check_state()
-endif ()
-
-if (CUPS_INCLUDE_DIR AND EXISTS "${CUPS_INCLUDE_DIR}/cups/cups.h")
- file(STRINGS "${CUPS_INCLUDE_DIR}/cups/cups.h" cups_version_str
- REGEX "^#[\t ]*define[\t ]+CUPS_VERSION_(MAJOR|MINOR|PATCH)[\t ]+[0-9]+$")
-
- unset(CUPS_VERSION_STRING)
- foreach(VPART MAJOR MINOR PATCH)
- foreach(VLINE ${cups_version_str})
- if(VLINE MATCHES "^#[\t ]*define[\t ]+CUPS_VERSION_${VPART}[\t ]+([0-9]+)$")
- set(CUPS_VERSION_PART "${CMAKE_MATCH_1}")
- if(CUPS_VERSION_STRING)
- string(APPEND CUPS_VERSION_STRING ".${CUPS_VERSION_PART}")
- else()
- set(CUPS_VERSION_STRING "${CUPS_VERSION_PART}")
- endif()
- endif()
- endforeach()
- endforeach()
-endif ()
-
-include(FindPackageHandleStandardArgs)
-
-if (CUPS_REQUIRE_IPP_DELETE_ATTRIBUTE)
- FIND_PACKAGE_HANDLE_STANDARD_ARGS(Cups
- REQUIRED_VARS CUPS_LIBRARIES CUPS_INCLUDE_DIR CUPS_HAS_IPP_DELETE_ATTRIBUTE
- VERSION_VAR CUPS_VERSION_STRING)
-else ()
- FIND_PACKAGE_HANDLE_STANDARD_ARGS(Cups
- REQUIRED_VARS CUPS_LIBRARIES CUPS_INCLUDE_DIR
- VERSION_VAR CUPS_VERSION_STRING)
-endif ()
-
-mark_as_advanced(CUPS_INCLUDE_DIR CUPS_LIBRARIES)
-
-if (CUPS_FOUND)
- set(CUPS_INCLUDE_DIRS "${CUPS_INCLUDE_DIR}")
- if (NOT TARGET Cups::Cups)
- add_library(Cups::Cups INTERFACE IMPORTED)
- set_target_properties(Cups::Cups PROPERTIES
- INTERFACE_LINK_LIBRARIES "${CUPS_LIBRARIES}"
- INTERFACE_INCLUDE_DIRECTORIES "${CUPS_INCLUDE_DIR}")
- endif ()
-endif ()
diff --git a/cmake/FindDB2.cmake b/cmake/FindDB2.cmake
index f2decb6809..31f7bbcae9 100644
--- a/cmake/FindDB2.cmake
+++ b/cmake/FindDB2.cmake
@@ -1,3 +1,6 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
#.rst:
# FindDB2
# ---------
@@ -19,43 +22,44 @@
# The db2 client library
if (NOT DEFINED DB2_INCLUDE_DIR)
- find_path(DB2_INCLUDE_DIRS
+ find_path(DB2_INCLUDE_DIR
NAMES sqlcli1.h
HINTS ENV DB2_HOME
PATH_SUFFIXES include)
else()
- find_path(DB2_INCLUDE_DIRS
+ find_path(DB2_INCLUDE_DIR
NAMES sqlcli1.h
HINTS ${DB2_INCLUDE_DIR})
endif()
if (NOT DEFINED DB2_LIBRARY_DIR)
- find_library(DB2_LIBRARIES
+ find_library(DB2_LIBRARY
NAMES db2
HINTS ENV DB2LIB)
else()
- find_library(DB2_LIBRARIES
+ find_library(DB2_LIBRARY
NAMES db2
HINTS ${DB2_LIBRARY_DIR})
endif()
-if (NOT DB2_INCLUDE_DIRS STREQUAL "DB2_INCLUDE_DIRS-NOTFOUND" AND NOT DB2_LIBRARIES STREQUAL "DB2_LIBRARIES-NOTFOUND")
- set(DB2_FOUND ON)
-endif()
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(DB2 DEFAULT_MSG DB2_INCLUDE_DIR DB2_LIBRARY)
-if(DB2_FOUND AND NOT TARGET DB2::DB2)
- add_library(DB2::DB2 UNKNOWN IMPORTED)
- set_target_properties(DB2::DB2 PROPERTIES
- IMPORTED_LOCATION "${DB2_LIBRARIES}"
- INTERFACE_INCLUDE_DIRECTORIES "${DB2_INCLUDE_DIRS}")
+if(DB2_FOUND)
+ set(DB2_INCLUDE_DIRS "${DB2_INCLUDE_DIR}")
+ set(DB2_LIBRARIES "${DB2_LIBRARY}")
+ if(NOT TARGET DB2::DB2)
+ add_library(DB2::DB2 UNKNOWN IMPORTED)
+ set_target_properties(DB2::DB2 PROPERTIES
+ IMPORTED_LOCATION "${DB2_LIBRARIES}"
+ INTERFACE_INCLUDE_DIRECTORIES "${DB2_INCLUDE_DIRS}")
+ endif()
endif()
-mark_as_advanced(DB2_INCLUDE_DIRS DB2_LIBRARIES)
+mark_as_advanced(DB2_INCLUDE_DIR DB2_LIBRARY)
include(FeatureSummary)
set_package_properties(DB2 PROPERTIES
URL "https://www.ibm.com"
DESCRIPTION "IBM DB2 client library")
-include(FindPackageHandleStandardArgs)
-find_package_handle_standard_args(DB2 DEFAULT_MSG DB2_INCLUDE_DIRS DB2_LIBRARIES)
diff --git a/cmake/FindDirectFB.cmake b/cmake/FindDirectFB.cmake
index 9d2e74c169..8c5711f178 100644
--- a/cmake/FindDirectFB.cmake
+++ b/cmake/FindDirectFB.cmake
@@ -1,6 +1,9 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
find_package(PkgConfig QUIET)
-pkg_check_modules(DirectFB directfb IMPORTED_TARGET)
+pkg_check_modules(DirectFB IMPORTED_TARGET "directfb")
if (NOT TARGET PkgConfig::DirectFB)
set(DirectFB_FOUND 0)
diff --git a/cmake/FindGLESv2.cmake b/cmake/FindGLESv2.cmake
index e934170196..4730418209 100644
--- a/cmake/FindGLESv2.cmake
+++ b/cmake/FindGLESv2.cmake
@@ -1,3 +1,6 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
include(CheckCXXSourceCompiles)
# No library linkage is necessary to use GLESv2 with Emscripten. The headers are also
@@ -7,8 +10,17 @@ if(EMSCRIPTEN)
else()
find_library(GLESv2_LIBRARY NAMES GLESv2 OpenGLES)
find_path(GLESv2_INCLUDE_DIR NAMES "GLES2/gl2.h" "OpenGLES/ES2/gl.h" DOC "The OpenGLES 2 include path")
+ find_package(EGL)
set(_libraries "${CMAKE_REQUIRED_LIBRARIES}")
- list(APPEND CMAKE_REQUIRED_LIBRARIES "${GLESv2_LIBRARY}")
+ if(GLESv2_LIBRARY)
+ list(APPEND CMAKE_REQUIRED_LIBRARIES "${GLESv2_LIBRARY}")
+ endif ()
+ if(EGL_LIBRARY)
+ list(APPEND CMAKE_REQUIRED_LIBRARIES "${EGL_LIBRARY}")
+ endif()
+ if(_qt_igy_gui_libs)
+ list(APPEND CMAKE_REQUIRED_LIBRARIES "${_qt_igy_gui_libs}")
+ endif()
set(_includes "${CMAKE_REQUIRED_INCLUDES}")
list(APPEND CMAKE_REQUIRED_INCLUDES "${GLESv2_INCLUDE_DIR}")
@@ -20,7 +32,7 @@ else()
# include <GLES2/gl2.h>
#endif
-int main(int argc, char *argv[]) {
+int main(int, char **) {
glUniform1f(1, GLfloat(1.0));
glClear(GL_COLOR_BUFFER_BIT);
}" HAVE_GLESv2)
@@ -54,9 +66,9 @@ find_package_handle_standard_args(GLESv2 DEFAULT_MSG ${package_args})
mark_as_advanced(${package_args})
if(GLESv2_FOUND AND NOT TARGET GLESv2::GLESv2)
- if(EMSCRIPTEN OR UIKIT)
+ if(EMSCRIPTEN OR IOS)
add_library(GLESv2::GLESv2 INTERFACE IMPORTED)
- if(UIKIT)
+ if(IOS)
# For simulator_and_device builds we can't specify the full library path, because
# it's specific to either the device or the simulator. Resort to passing a link
# flag instead.
@@ -67,5 +79,9 @@ if(GLESv2_FOUND AND NOT TARGET GLESv2::GLESv2)
set_target_properties(GLESv2::GLESv2 PROPERTIES
IMPORTED_LOCATION "${GLESv2_LIBRARY}"
INTERFACE_INCLUDE_DIRECTORIES "${GLESv2_INCLUDE_DIR}")
+
+ if(EGL_LIBRARY)
+ target_link_libraries(GLESv2::GLESv2 INTERFACE "${EGL_LIBRARY}")
+ endif()
endif()
endif()
diff --git a/cmake/FindGSSAPI.cmake b/cmake/FindGSSAPI.cmake
index 90f1c62c99..44594941e3 100644
--- a/cmake/FindGSSAPI.cmake
+++ b/cmake/FindGSSAPI.cmake
@@ -1,16 +1,36 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
find_package(PkgConfig QUIET)
-pkg_check_modules(PC_GSSAPI QUIET krb5-gssapi)
+pkg_check_modules(PC_GSSAPI QUIET "krb5-gssapi")
+if (NOT PC_GSSAPI_FOUND)
+ pkg_check_modules(PC_GSSAPI QUIET "mit-krb5-gssapi")
+endif()
find_path(GSSAPI_INCLUDE_DIRS
NAMES gssapi/gssapi.h
HINTS ${PC_GSSAPI_INCLUDEDIR}
- PATH_SUFFIXES gssapi)
+)
+
+# On macOS, vcpkg opts for finding frameworks LAST. This is generally fine;
+# however, in the case of GSSAPI, `usr/lib/libgssapi_krb5.tbd` which is a
+# symlink to `Kerberos.framework` misses a few symols, e.g.,
+# `___gss_c_nt_hostbased_service_oid_desc`, and it causes build failure.
+# So, we need to make sure that we find `GSS.framework`.
+set(gssapi_library_names
+ GSS # framework
+ gss # solaris
+ gssapi # FreeBSD
+ gssapi_krb5
+)
+if(APPLE)
+ list(REMOVE_ITEM gssapi_library_names "gssapi_krb5")
+endif()
find_library(GSSAPI_LIBRARIES
NAMES
- GSS # framework
- gssapi_krb5
- HINTS ${PC_GSSAPILIBDIR}
+ ${gssapi_library_names}
+ HINTS ${PC_GSSAPI_LIBDIR}
)
include(FindPackageHandleStandardArgs)
@@ -36,4 +56,3 @@ mark_as_advanced(GSSAPI_INCLUDE_DIRS GSSAPI_LIBRARIES)
include(FeatureSummary)
set_package_properties(GSSAPI PROPERTIES
DESCRIPTION "Generic Security Services Application Program Interface")
-
diff --git a/cmake/FindGTK3.cmake b/cmake/FindGTK3.cmake
index 62800eee97..221d5a34d1 100644
--- a/cmake/FindGTK3.cmake
+++ b/cmake/FindGTK3.cmake
@@ -1,7 +1,15 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
find_package(PkgConfig QUIET)
-pkg_check_modules(GTK3 "gtk+-3.0 >= 3.6" IMPORTED_TARGET)
+set(__gtk3_required_version "${${CMAKE_FIND_PACKAGE_NAME}_FIND_VERSION}")
+if(__gtk3_required_version)
+ set(__gtk3_required_version " >= ${__gtk3_required_version}")
+endif()
+pkg_check_modules(GTK3 IMPORTED_TARGET "gtk+-3.0${__gtk3_required_version}")
if (NOT TARGET PkgConfig::GTK3)
set(GTK3_FOUND 0)
endif()
+unset(__gtk3_required_version)
diff --git a/cmake/FindInterbase.cmake b/cmake/FindInterbase.cmake
new file mode 100644
index 0000000000..95b735e56a
--- /dev/null
+++ b/cmake/FindInterbase.cmake
@@ -0,0 +1,55 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+#.rst:
+# FindInterbase
+# ---------
+#
+# Try to locate the Interbase client library.
+# If found, this will define the following variables:
+#
+# ``Interbase_FOUND``
+# True if the Interbase library is available
+# ``Interbase_INCLUDE_DIR``
+# The Interbase include directories
+# ``Interbase_LIBRARY``
+# The Interbase libraries for linking
+#
+# If ``Interbase_FOUND`` is TRUE, it will also define the following
+# imported target:
+#
+# ``Interbase::Interbase``
+# The Interbase client library
+
+find_path(Interbase_INCLUDE_DIR
+ NAMES ibase.h
+ HINTS ${Interbase_INCLUDEDIR}
+ PATH_SUFFIXES firebird
+)
+
+find_library(Interbase_LIBRARY
+ NAMES firebase_ms fbclient gds
+ HINTS ${Interbase_LIBDIR}
+)
+
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(Interbase DEFAULT_MSG Interbase_LIBRARY Interbase_INCLUDE_DIR)
+
+if(Interbase_FOUND)
+ set(Interbase_INCLUDE_DIRS "${Interbase_INCLUDE_DIR}")
+ set(Interbase_LIBRARIES "${Interbase_LIBRARY}")
+ if(NOT TARGET Interbase::Interbase)
+ add_library(Interbase::Interbase UNKNOWN IMPORTED)
+ set_target_properties(Interbase::Interbase PROPERTIES
+ IMPORTED_LOCATION "${Interbase_LIBRARIES}"
+ INTERFACE_INCLUDE_DIRECTORIES "${Interbase_INCLUDE_DIRS};")
+ endif()
+endif()
+
+mark_as_advanced(Interbase_INCLUDE_DIR Interbase_LIBRARY)
+
+include(FeatureSummary)
+set_package_properties(Interbase PROPERTIES
+ URL "https://www.embarcadero.com/products/interbase"
+ DESCRIPTION "Interbase client library")
+
diff --git a/cmake/FindLibb2.cmake b/cmake/FindLibb2.cmake
index 18b6e4df04..bf51c37aed 100644
--- a/cmake/FindLibb2.cmake
+++ b/cmake/FindLibb2.cmake
@@ -1,7 +1,40 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+# Blake2 contains a reference implementation, libb2 is a more efficient
+# implementation of a subset of Blake2 functions and should be preferred.
+# This Find module only searches for libb2 for that reason.
+
+if(TARGET Libb2::Libb2)
+ set(Libb2_FOUND TRUE)
+ return()
+endif()
+
find_package(PkgConfig QUIET)
-pkg_check_modules(Libb2 libb2 IMPORTED_TARGET)
+if(PkgConfig_FOUND)
+ pkg_check_modules(Libb2 IMPORTED_TARGET "libb2")
+
+ if (TARGET PkgConfig::Libb2)
+ add_library(Libb2::Libb2 INTERFACE IMPORTED)
+ target_link_libraries(Libb2::Libb2 INTERFACE PkgConfig::Libb2)
+ set(Libb2_FOUND TRUE)
+ endif()
+else()
+ find_path(LIBB2_INCLUDE_DIR NAMES blake2.h)
+ find_library(LIBB2_LIBRARY NAMES b2)
+
+ if(LIBB2_LIBRARY AND LIBB2_INCLUDE_DIR)
+ add_library(Libb2::Libb2 UNKNOWN IMPORTED)
+ set_target_properties(Libb2::Libb2 PROPERTIES
+ IMPORTED_LOCATION ${LIBB2_LIBRARY}
+ INTERFACE_INCLUDE_DIRECTORIES ${LIBB2_INCLUDE_DIR}
+ )
+ endif()
-if (NOT TARGET PkgConfig::Libb2)
- set(Libb2_FOUND 0)
+ include(FindPackageHandleStandardArgs)
+ find_package_handle_standard_args(Libb2 REQUIRED_VARS
+ LIBB2_LIBRARY
+ LIBB2_INCLUDE_DIR
+ )
endif()
diff --git a/cmake/FindLibproxy.cmake b/cmake/FindLibproxy.cmake
index b6542575e0..4ee3943220 100644
--- a/cmake/FindLibproxy.cmake
+++ b/cmake/FindLibproxy.cmake
@@ -1,6 +1,9 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
find_package(PkgConfig QUIET)
-pkg_check_modules(Libproxy libproxy-1.0 IMPORTED_TARGET)
+pkg_check_modules(Libproxy IMPORTED_TARGET "libproxy-1.0")
if (NOT TARGET PkgConfig::Libproxy)
set(Libproxy_FOUND 0)
diff --git a/cmake/FindLibsystemd.cmake b/cmake/FindLibsystemd.cmake
index 7479c15b8e..372a718027 100644
--- a/cmake/FindLibsystemd.cmake
+++ b/cmake/FindLibsystemd.cmake
@@ -1,6 +1,9 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
find_package(PkgConfig QUIET)
-pkg_check_modules(Libsystemd libsystemd IMPORTED_TARGET)
+pkg_check_modules(Libsystemd IMPORTED_TARGET "libsystemd")
if (NOT TARGET PkgConfig::Libsystemd)
set(Libsystemd_FOUND 0)
diff --git a/cmake/FindLibudev.cmake b/cmake/FindLibudev.cmake
index 98477fb038..57e34659d1 100644
--- a/cmake/FindLibudev.cmake
+++ b/cmake/FindLibudev.cmake
@@ -1,6 +1,9 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
find_package(PkgConfig QUIET)
-pkg_check_modules(Libudev libudev IMPORTED_TARGET)
+pkg_check_modules(Libudev IMPORTED_TARGET "libudev")
if (NOT TARGET PkgConfig::Libudev)
set(Libudev_FOUND 0)
diff --git a/cmake/FindMimer.cmake b/cmake/FindMimer.cmake
new file mode 100644
index 0000000000..5cbc6e6907
--- /dev/null
+++ b/cmake/FindMimer.cmake
@@ -0,0 +1,98 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# Copyright (C) 2022 Mimer Information Technology
+# SPDX-License-Identifier: BSD-3-Clause
+
+# FindMimer
+# ---------
+# Try to locate the Mimer SQL client library
+if(NOT DEFINED MimerSQL_ROOT)
+ if(DEFINED ENV{MIMERSQL_DEV_ROOT})
+ set(MimerSQL_ROOT "$ENV{MIMERSQL_DEV_ROOT}")
+ endif()
+endif()
+
+if(NOT DEFINED MimerSQL_ROOT)
+ find_package(PkgConfig QUIET)
+endif()
+if(PkgConfig_FOUND AND NOT DEFINED MimerSQL_ROOT)
+ pkg_check_modules(PC_Mimer QUIET mimcontrol)
+ set(MimerSQL_include_dir_hints "${PC_MimerSQL_INCLUDEDIR}")
+ set(MimerSQL_library_hints "${PC_MimerSQL_LIBDIR}")
+else()
+ if(DEFINED MimerSQL_ROOT)
+ if(WIN32)
+ set(MimerSQL_include_dir_hints "${MimerSQL_ROOT}\\include")
+ if(CMAKE_SYSTEM_PROCESSOR MATCHES "^(x86|X86)$")
+ set(MimerSQL_library_hints "${MimerSQL_ROOT}\\lib\\x86")
+ elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^(amd64|AMD64)$")
+ set(MimerSQL_library_hints "${MimerSQL_ROOT}\\lib\\amd64")
+ else()
+ set(MimerSQL_library_hints "")
+ endif()
+ else()
+ set(MimerSQL_include_dir_hints "${MimerSQL_ROOT}/include")
+ set(MimerSQL_library_hints "${MimerSQL_ROOT}/lib")
+ endif()
+ else()
+ if(WIN32)
+ set(MimerSQL_include_dir_hints "C:\\MimerSQLDev\\include")
+ if(CMAKE_SYSTEM_PROCESSOR MATCHES "^(x86|X86)$")
+ set(MimerSQL_library_hints "C:\\MimerSQLDev\\lib\\x86")
+ elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^(amd64|AMD64)$")
+ set(MimerSQL_library_hints "C:\\MimerSQLDev\\lib\\amd64")
+ else()
+ set(MimerSQL_library_hints "")
+ endif()
+ elseif(APPLE AND ${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
+ set(MimerSQL_library_hints "/usr/local/lib")
+ set(MimerSQL_include_dir_hints "/usr/local/include")
+ else()
+ set(MimerSQL_include_dir_hints "")
+ set(MimerSQL_library_hints "")
+ endif()
+ endif()
+endif()
+
+find_path(Mimer_INCLUDE_DIR
+ NAMES mimerapi.h
+ HINTS ${MimerSQL_include_dir_hints})
+
+if(WIN32)
+ if(CMAKE_SYSTEM_PROCESSOR MATCHES "^(x86|X86)$")
+ set(MIMER_LIBS_NAMES mimapi32)
+ elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^(amd64|AMD64)$")
+ set(MIMER_LIBS_NAMES mimapi64)
+ endif()
+else()
+ set(MIMER_LIBS_NAMES mimerapi)
+endif()
+
+find_library(Mimer_LIBRARIES
+ NAMES ${MIMER_LIBS_NAMES}
+ HINTS ${MimerSQL_library_hints})
+
+include(FindPackageHandleStandardArgs)
+
+find_package_handle_standard_args(Mimer
+ REQUIRED_VARS Mimer_LIBRARIES Mimer_INCLUDE_DIR)
+
+
+
+# Now try to get the include and library path.
+if(Mimer_FOUND)
+ set(Mimer_INCLUDE_DIRS ${Mimer_INCLUDE_DIR})
+ set(Mimer_LIBRARY_DIRS ${Mimer_LIBRARIES})
+ if (NOT TARGET MimerSQL::MimerSQL)
+ add_library(MimerSQL::MimerSQL UNKNOWN IMPORTED)
+ set_target_properties(MimerSQL::MimerSQL PROPERTIES
+ IMPORTED_LOCATION "${Mimer_LIBRARY_DIRS}"
+ INTERFACE_INCLUDE_DIRECTORIES "${Mimer_INCLUDE_DIRS}")
+ endif ()
+endif()
+
+mark_as_advanced(Mimer_INCLUDE_DIR Mimer_LIBRARIES)
+
+include(FeatureSummary)
+set_package_properties(MimerSQL PROPERTIES
+ URL "https://www.mimer.com"
+ DESCRIPTION "Mimer client library")
diff --git a/cmake/FindMtdev.cmake b/cmake/FindMtdev.cmake
index c404e3bf72..489a87f48b 100644
--- a/cmake/FindMtdev.cmake
+++ b/cmake/FindMtdev.cmake
@@ -1,6 +1,9 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
find_package(PkgConfig QUIET)
-pkg_check_modules(Mtdev mtdev IMPORTED_TARGET)
+pkg_check_modules(Mtdev IMPORTED_TARGET "mtdev")
if (NOT TARGET PkgConfig::Mtdev)
set(Mtdev_FOUND 0)
diff --git a/cmake/FindMySQL.cmake b/cmake/FindMySQL.cmake
index 54c94b8a2f..d191d1ac0a 100644
--- a/cmake/FindMySQL.cmake
+++ b/cmake/FindMySQL.cmake
@@ -1,9 +1,30 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
#.rst:
# FindMySQL
# ---------
#
# Try to locate the mysql client library.
-# If found, this will define the following variables:
+#
+# By default, pkg-config is used, if available.
+# If pkg-config is not available or if you want to disable it, set the ``MySQL_ROOT`` variable.
+# The following variables can be set to control the behavior of this find module.
+#
+# ``MySQL_ROOT``
+# The root directory of the mysql client library's installation.
+# ``MySQL_INCLUDE_DIR``
+# The directory containing the include files of the mysql client library.
+# If not set, the directory is detected within ``MySQL_ROOT`` using find_path.
+# ``MySQL_LIBRARY_DIR``
+# The directory containing the binaries of the mysql client library.
+# This is used to detect ``MySQL_LIBRARY`` and passed as HINT to find_library.
+# ``MySQL_LIBRARY``
+# The file path to the mysql client library.
+# ``MySQL_LIBRARY_DEBUG``
+# The file path to the mysql client library for the DEBUG configuration.
+#
+# If the mysql client library is found, this will define the following variables:
#
# ``MySQL_FOUND``
# True if the mysql library is available
@@ -18,30 +39,59 @@
# ``MySQL::MySQL``
# The mysql client library
-find_package(PkgConfig QUIET)
-pkg_check_modules(PC_MySQL QUIET mysqlclient)
+if(NOT DEFINED MySQL_ROOT)
+ find_package(PkgConfig QUIET)
+endif()
+if(PkgConfig_FOUND AND NOT DEFINED MySQL_ROOT)
+ pkg_check_modules(PC_MySQL QUIET "mysqlclient")
+ set(MySQL_include_dir_hints ${PC_MySQL_INCLUDEDIR})
+ set(MySQL_library_hints ${PC_MySQL_LIBDIR})
+ set(MySQL_library_hints_debug "")
+else()
+ set(MySQL_include_dir_hints "")
+ if(NOT DEFINED MySQL_LIBRARY_DIR)
+ set(MySQL_LIBRARY_DIR "${MySQL_ROOT}/lib")
+ endif()
+ set(MySQL_library_hints "${MySQL_LIBRARY_DIR}")
+ set(MySQL_library_hints_debug "${MySQL_LIBRARY_DIR}/debug")
+endif()
-find_path(MySQL_INCLUDE_DIRS
+find_path(MySQL_INCLUDE_DIR
NAMES mysql.h
- HINTS ${PC_MySQL_INCLUDEDIR}
- PATH_SUFFIXES mysql)
+ HINTS "${MySQL_include_dir_hints}"
+ PATH_SUFFIXES mysql mariadb)
-find_library(MySQL_LIBRARIES
- NAMES mysqlclient
- HINTS ${PC_MySQL_LIBDIR}
-)
+find_library(MySQL_LIBRARY
+ NO_PACKAGE_ROOT_PATH
+ NAMES libmysql mysql mysqlclient libmariadb mariadb
+ HINTS ${MySQL_library_hints})
+
+if(MySQL_library_hints_debug)
+ find_library(MySQL_LIBRARY_DEBUG
+ NO_PACKAGE_ROOT_PATH
+ NAMES libmysql mysql mysqlclient libmariadb mariadb
+ HINTS ${MySQL_library_hints_debug})
+endif()
include(FindPackageHandleStandardArgs)
-find_package_handle_standard_args(MySQL DEFAULT_MSG MySQL_LIBRARIES MySQL_INCLUDE_DIRS)
+find_package_handle_standard_args(MySQL DEFAULT_MSG MySQL_LIBRARY MySQL_INCLUDE_DIR)
-if(MySQL_FOUND AND NOT TARGET MySQL::MySQL)
- add_library(MySQL::MySQL UNKNOWN IMPORTED)
- set_target_properties(MySQL::MySQL PROPERTIES
- IMPORTED_LOCATION "${MySQL_LIBRARIES}"
- INTERFACE_INCLUDE_DIRECTORIES "${MySQL_INCLUDE_DIRS}")
+if(MySQL_FOUND)
+ set(MySQL_INCLUDE_DIRS "${MySQL_INCLUDE_DIR}")
+ set(MySQL_LIBRARIES "${MySQL_LIBRARY}")
+ if(NOT TARGET MySQL::MySQL)
+ add_library(MySQL::MySQL UNKNOWN IMPORTED)
+ set_target_properties(MySQL::MySQL PROPERTIES
+ IMPORTED_LOCATION "${MySQL_LIBRARIES}"
+ INTERFACE_INCLUDE_DIRECTORIES "${MySQL_INCLUDE_DIRS}")
+ if(MySQL_LIBRARY_DEBUG)
+ set_target_properties(MySQL::MySQL PROPERTIES
+ IMPORTED_LOCATION_DEBUG "${MySQL_LIBRARY_DEBUG}")
+ endif()
+ endif()
endif()
-mark_as_advanced(MySQL_INCLUDE_DIRS MySQL_LIBRARIES)
+mark_as_advanced(MySQL_INCLUDE_DIR MySQL_LIBRARY)
include(FeatureSummary)
set_package_properties(MySQL PROPERTIES
diff --git a/cmake/FindOracle.cmake b/cmake/FindOracle.cmake
index b294f1793e..e05bdd749e 100644
--- a/cmake/FindOracle.cmake
+++ b/cmake/FindOracle.cmake
@@ -1,3 +1,6 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
#.rst:
# FindOracle
# ---------
@@ -18,33 +21,33 @@
# ``Oracle::Oracle``
# The oracle instant client library
-find_path(Oracle_INCLUDE_DIRS
+find_path(Oracle_INCLUDE_DIR
NAMES oci.h
HINTS ${Oracle_INCLUDE_DIR})
-set(ORACLE_OCI_NAMES clntsh ociei oraociei12)
+set(ORACLE_OCI_NAMES clntsh ociei oraociei12 oci)
-find_library(Oracle_LIBRARIES
- NAMES NAMES ${ORACLE_OCI_NAMES}
+find_library(Oracle_LIBRARY
+ NAMES ${ORACLE_OCI_NAMES}
HINTS ${Oracle_LIBRARY_DIR})
-if (NOT Oracle_INCLUDE_DIRS STREQUAL "Oracle_INCLUDE_DIRS-NOTFOUND" AND NOT Oracle_LIBRARIES STREQUAL "Oracle_LIBRARIES-NOTFOUND")
- set(Oracle_FOUND ON)
-endif()
-
-if(Oracle_FOUND AND NOT TARGET Oracle::OCI)
- add_library(Oracle::OCI UNKNOWN IMPORTED)
- set_target_properties(Oracle::OCI PROPERTIES
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(Oracle DEFAULT_MSG Oracle_LIBRARY Oracle_INCLUDE_DIR)
+
+if(Oracle_FOUND)
+ set(Oracle_INCLUDE_DIRS "${Oracle_INCLUDE_DIR}")
+ set(Oracle_LIBRARIES "${Oracle_LIBRARY}")
+ if(NOT TARGET Oracle::OCI)
+ add_library(Oracle::OCI UNKNOWN IMPORTED)
+ set_target_properties(Oracle::OCI PROPERTIES
IMPORTED_LOCATION "${Oracle_LIBRARIES}"
INTERFACE_INCLUDE_DIRECTORIES "${Oracle_INCLUDE_DIRS}")
+ endif()
endif()
-mark_as_advanced(Oracle_INCLUDE_DIRS Oracle_LIBRARIES)
+mark_as_advanced(Oracle_INCLUDE_DIR Oracle_LIBRARY)
include(FeatureSummary)
set_package_properties(Oracle PROPERTIES
URL "https://www.oracle.com"
DESCRIPTION "Oracle client library")
-
-include(FindPackageHandleStandardArgs)
-find_package_handle_standard_args(Oracle DEFAULT_MSG Oracle_INCLUDE_DIRS Oracle_LIBRARIES)
diff --git a/cmake/FindPPS.cmake b/cmake/FindPPS.cmake
index c3360fa82c..099019243c 100644
--- a/cmake/FindPPS.cmake
+++ b/cmake/FindPPS.cmake
@@ -1,6 +1,13 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Find the PPS library
# Will make the target PPS::PPS available when found.
+if(TARGET PPS::PPS)
+ set(PPS_FOUND TRUE)
+ return()
+endif()
find_library(PPS_LIBRARY NAMES "pps")
find_path(PPS_INCLUDE_DIR NAMES "sys/pps.h" DOC "The PPS Include path")
@@ -11,9 +18,7 @@ find_package_handle_standard_args(PPS DEFAULT_MSG PPS_INCLUDE_DIR PPS_LIBRARY)
mark_as_advanced(PPS_INCLUDE_DIR PPS_LIBRARY)
if(PPS_FOUND)
- add_library(__PPS INTERFACE IMPORTED)
- target_link_libraries(__PPS INTERFACE ${PPS_LIBRARY})
- target_include_directories(__PPS INTERFACE ${PPS_INCLUDE_DIR})
-
- add_library(PPS::PPS ALIAS __PPS)
+ add_library(PPS::PPS INTERFACE IMPORTED)
+ target_link_libraries(PPS::PPS INTERFACE "${PPS_LIBRARY}")
+ target_include_directories(PPS::PPS INTERFACE "${PPS_INCLUDE_DIR}")
endif()
diff --git a/cmake/FindPostgreSQL.cmake b/cmake/FindPostgreSQL.cmake
new file mode 100644
index 0000000000..a61bec9337
--- /dev/null
+++ b/cmake/FindPostgreSQL.cmake
@@ -0,0 +1,321 @@
+# Copyright (C) 2000-2022 Kitware, Inc. and Contributors.
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+#[=======================================================================[.rst:
+FindPostgreSQL
+--------------
+
+Find the PostgreSQL installation.
+
+IMPORTED Targets
+^^^^^^^^^^^^^^^^
+
+.. versionadded:: 3.14
+
+This module defines :prop_tgt:`IMPORTED` target ``PostgreSQL::PostgreSQL``
+if PostgreSQL has been found.
+
+Result Variables
+^^^^^^^^^^^^^^^^
+
+This module will set the following variables in your project:
+
+``PostgreSQL_FOUND``
+ True if PostgreSQL is found.
+``PostgreSQL_LIBRARIES``
+ the PostgreSQL libraries needed for linking
+``PostgreSQL_INCLUDE_DIRS``
+ the directories of the PostgreSQL headers
+``PostgreSQL_LIBRARY_DIRS``
+ the link directories for PostgreSQL libraries
+``PostgreSQL_VERSION_STRING``
+ the version of PostgreSQL found
+``PostgreSQL_TYPE_INCLUDE_DIR``
+ the directories of the PostgreSQL server headers
+
+Components
+^^^^^^^^^^
+
+This module contains additional ``Server`` component, that forcibly checks
+for the presence of server headers. Note that ``PostgreSQL_TYPE_INCLUDE_DIR``
+is set regardless of the presence of the ``Server`` component in find_package call.
+
+#]=======================================================================]
+
+# ----------------------------------------------------------------------------
+# History:
+# This module is derived from the module originally found in the VTK source tree.
+#
+# ----------------------------------------------------------------------------
+# Note:
+# PostgreSQL_ADDITIONAL_VERSIONS is a variable that can be used to set the
+# version number of the implementation of PostgreSQL.
+# In Windows the default installation of PostgreSQL uses that as part of the path.
+# E.g C:\Program Files\PostgreSQL\8.4.
+# Currently, the following version numbers are known to this module:
+# "11" "10" "9.6" "9.5" "9.4" "9.3" "9.2" "9.1" "9.0" "8.4" "8.3" "8.2" "8.1" "8.0"
+#
+# To use this variable just do something like this:
+# set(PostgreSQL_ADDITIONAL_VERSIONS "9.2" "8.4.4")
+# before calling find_package(PostgreSQL) in your CMakeLists.txt file.
+# This will mean that the versions you set here will be found first in the order
+# specified before the default ones are searched.
+#
+# ----------------------------------------------------------------------------
+# You may need to manually set:
+# PostgreSQL_INCLUDE_DIR - the path to where the PostgreSQL include files are.
+# PostgreSQL_LIBRARY_DIR - The path to where the PostgreSQL library files are.
+# If FindPostgreSQL.cmake cannot find the include files or the library files.
+#
+# ----------------------------------------------------------------------------
+# The following variables are set if PostgreSQL is found:
+# PostgreSQL_FOUND - Set to true when PostgreSQL is found.
+# PostgreSQL_INCLUDE_DIRS - Include directories for PostgreSQL
+# PostgreSQL_LIBRARY_DIRS - Link directories for PostgreSQL libraries
+# PostgreSQL_LIBRARIES - The PostgreSQL libraries.
+#
+# The ``PostgreSQL::PostgreSQL`` imported target is also created.
+#
+# ----------------------------------------------------------------------------
+# If you have installed PostgreSQL in a non-standard location.
+# (Please note that in the following comments, it is assumed that <Your Path>
+# points to the root directory of the include directory of PostgreSQL.)
+# Then you have three options.
+# 1) After CMake runs, set PostgreSQL_INCLUDE_DIR to <Your Path>/include and
+# PostgreSQL_LIBRARY_DIR to wherever the library pq (or libpq in windows) is
+# 2) Use CMAKE_INCLUDE_PATH to set a path to <Your Path>/PostgreSQL<-version>. This will allow find_path()
+# to locate PostgreSQL_INCLUDE_DIR by utilizing the PATH_SUFFIXES option. e.g. In your CMakeLists.txt file
+# set(CMAKE_INCLUDE_PATH ${CMAKE_INCLUDE_PATH} "<Your Path>/include")
+# 3) Set an environment variable called ${PostgreSQL_ROOT} that points to the root of where you have
+# installed PostgreSQL, e.g. <Your Path>.
+#
+# ----------------------------------------------------------------------------
+
+if(CMAKE_VERSION VERSION_GREATER_EQUAL "3.20")
+ include("${CMAKE_ROOT}/Modules/FindPostgreSQL.cmake")
+ return()
+endif()
+
+cmake_policy(PUSH)
+cmake_policy(SET CMP0057 NEW) # if IN_LIST
+if(POLICY CMP0159)
+ cmake_policy(SET CMP0159 NEW)
+endif()
+
+set(PostgreSQL_INCLUDE_PATH_DESCRIPTION "top-level directory containing the PostgreSQL include directories. E.g /usr/local/include/PostgreSQL/8.4 or C:/Program Files/PostgreSQL/8.4/include")
+set(PostgreSQL_INCLUDE_DIR_MESSAGE "Set the PostgreSQL_INCLUDE_DIR cmake cache entry to the ${PostgreSQL_INCLUDE_PATH_DESCRIPTION}")
+set(PostgreSQL_LIBRARY_PATH_DESCRIPTION "top-level directory containing the PostgreSQL libraries.")
+set(PostgreSQL_LIBRARY_DIR_MESSAGE "Set the PostgreSQL_LIBRARY_DIR cmake cache entry to the ${PostgreSQL_LIBRARY_PATH_DESCRIPTION}")
+set(PostgreSQL_ROOT_DIR_MESSAGE "Set the PostgreSQL_ROOT system variable to where PostgreSQL is found on the machine E.g C:/Program Files/PostgreSQL/8.4")
+
+
+set(PostgreSQL_KNOWN_VERSIONS ${PostgreSQL_ADDITIONAL_VERSIONS}
+ "13" "12" "11" "10" "9.6" "9.5" "9.4" "9.3" "9.2" "9.1" "9.0" "8.4" "8.3" "8.2" "8.1" "8.0")
+
+# Define additional search paths for root directories.
+set( PostgreSQL_ROOT_DIRECTORIES
+ ENV PostgreSQL_ROOT
+ ${PostgreSQL_ROOT}
+)
+foreach(suffix ${PostgreSQL_KNOWN_VERSIONS})
+ if(WIN32)
+ list(APPEND PostgreSQL_LIBRARY_ADDITIONAL_SEARCH_SUFFIXES
+ "PostgreSQL/${suffix}/lib")
+ list(APPEND PostgreSQL_INCLUDE_ADDITIONAL_SEARCH_SUFFIXES
+ "PostgreSQL/${suffix}/include")
+ list(APPEND PostgreSQL_TYPE_ADDITIONAL_SEARCH_SUFFIXES
+ "PostgreSQL/${suffix}/include/server")
+ endif()
+ if(UNIX)
+ list(APPEND PostgreSQL_LIBRARY_ADDITIONAL_SEARCH_SUFFIXES
+ "postgresql${suffix}"
+ "pgsql-${suffix}/lib")
+ list(APPEND PostgreSQL_INCLUDE_ADDITIONAL_SEARCH_SUFFIXES
+ "postgresql${suffix}"
+ "postgresql/${suffix}"
+ "pgsql-${suffix}/include")
+ list(APPEND PostgreSQL_TYPE_ADDITIONAL_SEARCH_SUFFIXES
+ "postgresql${suffix}/server"
+ "postgresql/${suffix}/server"
+ "pgsql-${suffix}/include/server")
+ endif()
+endforeach()
+
+#
+# Look for an installation.
+#
+find_path(PostgreSQL_INCLUDE_DIR
+ NAMES libpq-fe.h
+ PATHS
+ # Look in other places.
+ ${PostgreSQL_ROOT_DIRECTORIES}
+ PATH_SUFFIXES
+ pgsql
+ postgresql
+ include
+ ${PostgreSQL_INCLUDE_ADDITIONAL_SEARCH_SUFFIXES}
+ # Help the user find it if we cannot.
+ DOC "The ${PostgreSQL_INCLUDE_DIR_MESSAGE}"
+)
+
+find_path(PostgreSQL_TYPE_INCLUDE_DIR
+ NAMES catalog/pg_type.h
+ PATHS
+ # Look in other places.
+ ${PostgreSQL_ROOT_DIRECTORIES}
+ PATH_SUFFIXES
+ postgresql
+ pgsql/server
+ postgresql/server
+ include/server
+ ${PostgreSQL_TYPE_ADDITIONAL_SEARCH_SUFFIXES}
+ # Help the user find it if we cannot.
+ DOC "The ${PostgreSQL_INCLUDE_DIR_MESSAGE}"
+)
+
+# The PostgreSQL library.
+set (PostgreSQL_LIBRARY_TO_FIND pq)
+# Setting some more prefixes for the library
+set (PostgreSQL_LIB_PREFIX "")
+if ( WIN32 )
+ set (PostgreSQL_LIB_PREFIX ${PostgreSQL_LIB_PREFIX} "lib")
+ set (PostgreSQL_LIBRARY_TO_FIND ${PostgreSQL_LIB_PREFIX}${PostgreSQL_LIBRARY_TO_FIND})
+endif()
+
+function(__postgresql_find_library _name)
+ find_library(${_name}
+ NAMES ${ARGN}
+ PATHS
+ ${PostgreSQL_ROOT_DIRECTORIES}
+ PATH_SUFFIXES
+ lib
+ ${PostgreSQL_LIBRARY_ADDITIONAL_SEARCH_SUFFIXES}
+ # Help the user find it if we cannot.
+ DOC "The ${PostgreSQL_LIBRARY_DIR_MESSAGE}"
+ )
+endfunction()
+
+# For compatibility with versions prior to this multi-config search, honor
+# any PostgreSQL_LIBRARY that is already specified and skip the search.
+if(PostgreSQL_LIBRARY)
+ set(PostgreSQL_LIBRARIES "${PostgreSQL_LIBRARY}")
+ get_filename_component(PostgreSQL_LIBRARY_DIR "${PostgreSQL_LIBRARY}" PATH)
+else()
+ __postgresql_find_library(PostgreSQL_LIBRARY_RELEASE ${PostgreSQL_LIBRARY_TO_FIND})
+ __postgresql_find_library(PostgreSQL_LIBRARY_DEBUG ${PostgreSQL_LIBRARY_TO_FIND}d)
+ include(SelectLibraryConfigurations)
+ select_library_configurations(PostgreSQL)
+ mark_as_advanced(PostgreSQL_LIBRARY_RELEASE PostgreSQL_LIBRARY_DEBUG)
+ if(PostgreSQL_LIBRARY_RELEASE)
+ get_filename_component(PostgreSQL_LIBRARY_DIR "${PostgreSQL_LIBRARY_RELEASE}" PATH)
+ elseif(PostgreSQL_LIBRARY_DEBUG)
+ get_filename_component(PostgreSQL_LIBRARY_DIR "${PostgreSQL_LIBRARY_DEBUG}" PATH)
+ else()
+ set(PostgreSQL_LIBRARY_DIR "")
+ endif()
+endif()
+
+if (PostgreSQL_INCLUDE_DIR)
+ # Some platforms include multiple pg_config.hs for multi-lib configurations
+ # This is a temporary workaround. A better solution would be to compile
+ # a dummy c file and extract the value of the symbol.
+ file(GLOB _PG_CONFIG_HEADERS "${PostgreSQL_INCLUDE_DIR}/pg_config*.h")
+ foreach(_PG_CONFIG_HEADER ${_PG_CONFIG_HEADERS})
+ if(EXISTS "${_PG_CONFIG_HEADER}")
+ file(STRINGS "${_PG_CONFIG_HEADER}" pgsql_version_str
+ REGEX "^#define[\t ]+PG_VERSION_NUM[\t ]+.*")
+ if(pgsql_version_str)
+ string(REGEX REPLACE "^#define[\t ]+PG_VERSION_NUM[\t ]+([0-9]*).*"
+ "\\1" _PostgreSQL_VERSION_NUM "${pgsql_version_str}")
+ break()
+ endif()
+ endif()
+ endforeach()
+ if (_PostgreSQL_VERSION_NUM)
+ # 9.x and older encoding
+ if (_PostgreSQL_VERSION_NUM LESS 100000)
+ math(EXPR _PostgreSQL_major_version "${_PostgreSQL_VERSION_NUM} / 10000")
+ math(EXPR _PostgreSQL_minor_version "${_PostgreSQL_VERSION_NUM} % 10000 / 100")
+ math(EXPR _PostgreSQL_patch_version "${_PostgreSQL_VERSION_NUM} % 100")
+ set(PostgreSQL_VERSION_STRING "${_PostgreSQL_major_version}.${_PostgreSQL_minor_version}.${_PostgreSQL_patch_version}")
+ unset(_PostgreSQL_major_version)
+ unset(_PostgreSQL_minor_version)
+ unset(_PostgreSQL_patch_version)
+ else ()
+ math(EXPR _PostgreSQL_major_version "${_PostgreSQL_VERSION_NUM} / 10000")
+ math(EXPR _PostgreSQL_minor_version "${_PostgreSQL_VERSION_NUM} % 10000")
+ set(PostgreSQL_VERSION_STRING "${_PostgreSQL_major_version}.${_PostgreSQL_minor_version}")
+ unset(_PostgreSQL_major_version)
+ unset(_PostgreSQL_minor_version)
+ endif ()
+ else ()
+ foreach(_PG_CONFIG_HEADER ${_PG_CONFIG_HEADERS})
+ if(EXISTS "${_PG_CONFIG_HEADER}")
+ file(STRINGS "${_PG_CONFIG_HEADER}" pgsql_version_str
+ REGEX "^#define[\t ]+PG_VERSION[\t ]+\".*\"")
+ if(pgsql_version_str)
+ string(REGEX REPLACE "^#define[\t ]+PG_VERSION[\t ]+\"([^\"]*)\".*"
+ "\\1" PostgreSQL_VERSION_STRING "${pgsql_version_str}")
+ break()
+ endif()
+ endif()
+ endforeach()
+ endif ()
+ unset(_PostgreSQL_VERSION_NUM)
+ unset(pgsql_version_str)
+endif()
+
+if("Server" IN_LIST PostgreSQL_FIND_COMPONENTS)
+ set(PostgreSQL_Server_FOUND TRUE)
+ if(NOT PostgreSQL_TYPE_INCLUDE_DIR)
+ set(PostgreSQL_Server_FOUND FALSE)
+ endif()
+endif()
+
+# Did we find anything?
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(PostgreSQL
+ REQUIRED_VARS PostgreSQL_LIBRARY PostgreSQL_INCLUDE_DIR
+ HANDLE_COMPONENTS
+ VERSION_VAR PostgreSQL_VERSION_STRING)
+set(PostgreSQL_FOUND ${POSTGRESQL_FOUND})
+
+function(__postgresql_import_library _target _var _config)
+ if(_config)
+ set(_config_suffix "_${_config}")
+ else()
+ set(_config_suffix "")
+ endif()
+
+ set(_lib "${${_var}${_config_suffix}}")
+ if(EXISTS "${_lib}")
+ if(_config)
+ set_property(TARGET ${_target} APPEND PROPERTY
+ IMPORTED_CONFIGURATIONS ${_config})
+ endif()
+ set_target_properties(${_target} PROPERTIES
+ IMPORTED_LOCATION${_config_suffix} "${_lib}")
+ endif()
+endfunction()
+
+# Now try to get the include and library path.
+if(PostgreSQL_FOUND)
+ set(PostgreSQL_INCLUDE_DIRS ${PostgreSQL_INCLUDE_DIR})
+ if(PostgreSQL_TYPE_INCLUDE_DIR)
+ list(APPEND PostgreSQL_INCLUDE_DIRS ${PostgreSQL_TYPE_INCLUDE_DIR})
+ endif()
+ set(PostgreSQL_LIBRARY_DIRS ${PostgreSQL_LIBRARY_DIR})
+ if (NOT TARGET PostgreSQL::PostgreSQL)
+ add_library(PostgreSQL::PostgreSQL UNKNOWN IMPORTED)
+ set_target_properties(PostgreSQL::PostgreSQL PROPERTIES
+ INTERFACE_INCLUDE_DIRECTORIES "${PostgreSQL_INCLUDE_DIRS}")
+ __postgresql_import_library(PostgreSQL::PostgreSQL PostgreSQL_LIBRARY "")
+ __postgresql_import_library(PostgreSQL::PostgreSQL PostgreSQL_LIBRARY "RELEASE")
+ __postgresql_import_library(PostgreSQL::PostgreSQL PostgreSQL_LIBRARY "DEBUG")
+ endif ()
+endif()
+
+mark_as_advanced(PostgreSQL_INCLUDE_DIR PostgreSQL_TYPE_INCLUDE_DIR)
+
+cmake_policy(POP)
diff --git a/cmake/FindRenderDoc.cmake b/cmake/FindRenderDoc.cmake
new file mode 100644
index 0000000000..02970fc7d6
--- /dev/null
+++ b/cmake/FindRenderDoc.cmake
@@ -0,0 +1,20 @@
+# Copyright (C) 2023 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+if(WIN32 OR UNIX)
+ find_path(RenderDoc_INCLUDE_DIR
+ NAMES renderdoc_app.h)
+endif()
+
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(RenderDoc
+ DEFAULT_MSG
+ RenderDoc_INCLUDE_DIR)
+
+mark_as_advanced(RenderDoc_INCLUDE_DIR)
+
+if(RenderDoc_FOUND AND NOT TARGET RenderDoc::RenderDoc)
+ add_library(RenderDoc::RenderDoc INTERFACE IMPORTED)
+ set_target_properties(RenderDoc::RenderDoc PROPERTIES
+ INTERFACE_INCLUDE_DIRECTORIES "${RenderDoc_INCLUDE_DIR}")
+endif()
diff --git a/cmake/FindSlog2.cmake b/cmake/FindSlog2.cmake
index 807ab6b12a..18c10773f9 100644
--- a/cmake/FindSlog2.cmake
+++ b/cmake/FindSlog2.cmake
@@ -1,6 +1,13 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Find the Slog2 library
# Will make the target Slog2::Slog2 available when found.
+if(TARGET Slog2::Slog2)
+ set(Slog2_FOUND TRUE)
+ return()
+endif()
find_library(Slog2_LIBRARY NAMES "slog2")
find_path(Slog2_INCLUDE_DIR NAMES "sys/slog2.h" DOC "The Slog2 Include path")
diff --git a/cmake/FindTslib.cmake b/cmake/FindTslib.cmake
index 01579071b3..f5243dfa7f 100644
--- a/cmake/FindTslib.cmake
+++ b/cmake/FindTslib.cmake
@@ -1,6 +1,9 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
find_package(PkgConfig QUIET)
-pkg_check_modules(Tslib tslib IMPORTED_TARGET)
+pkg_check_modules(Tslib IMPORTED_TARGET "tslib")
if (NOT TARGET PkgConfig::Tslib)
set(Tslib_FOUND 0)
diff --git a/cmake/FindWrapAtomic.cmake b/cmake/FindWrapAtomic.cmake
index 56aa7323bf..04768e6490 100644
--- a/cmake/FindWrapAtomic.cmake
+++ b/cmake/FindWrapAtomic.cmake
@@ -1,3 +1,6 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# We can't create the same interface imported target multiple times, CMake will complain if we do
# that. This can happen if the find_package call is done in multiple different subdirectories.
if(TARGET WrapAtomic::WrapAtomic)
@@ -10,35 +13,39 @@ include(CheckCXXSourceCompiles)
set (atomic_test_sources "#include <atomic>
#include <cstdint>
-void test(volatile std::atomic<std::int64_t> &a)
-{
- std::int64_t v = a.load(std::memory_order_acquire);
- while (!a.compare_exchange_strong(v, v + 1,
- std::memory_order_acq_rel,
- std::memory_order_acquire)) {
- v = a.exchange(v - 1);
- }
- a.store(v + 1, std::memory_order_release);
-}
-
int main(int, char **)
{
- void *ptr = (void*)0xffffffc0; // any random pointer
- test(*reinterpret_cast<std::atomic<std::int64_t> *>(ptr));
+ volatile std::atomic<char> size_1;
+ volatile std::atomic<short> size_2;
+ volatile std::atomic<int> size_4;
+ volatile std::atomic<int64_t> size_8;
+
+ ++size_1;
+ ++size_2;
+ ++size_4;
+ ++size_8;
+
+ (void)size_1.load(std::memory_order_relaxed);
+ (void)size_2.load(std::memory_order_relaxed);
+ (void)size_4.load(std::memory_order_relaxed);
+ (void)size_8.load(std::memory_order_relaxed);
+
return 0;
}")
check_cxx_source_compiles("${atomic_test_sources}" HAVE_STDATOMIC)
if(NOT HAVE_STDATOMIC)
- set(_req_libraries "${CMAKE_REQUIRE_LIBRARIES}")
- set(CMAKE_REQUIRE_LIBRARIES "atomic")
+ set(_req_libraries "${CMAKE_REQUIRED_LIBRARIES}")
+ set(atomic_LIB "-latomic")
+ set(CMAKE_REQUIRED_LIBRARIES ${atomic_LIB})
check_cxx_source_compiles("${atomic_test_sources}" HAVE_STDATOMIC_WITH_LIB)
- set(CMAKE_REQUIRE_LIBRARIES "${_req_libraries}")
+ set(CMAKE_REQUIRED_LIBRARIES "${_req_libraries}")
endif()
add_library(WrapAtomic::WrapAtomic INTERFACE IMPORTED)
if(HAVE_STDATOMIC_WITH_LIB)
- target_link_libraries(WrapAtomic::WrapAtomic INTERFACE atomic)
+ # atomic_LIB is already found above.
+ target_link_libraries(WrapAtomic::WrapAtomic INTERFACE ${atomic_LIB})
endif()
set(WrapAtomic_FOUND 1)
diff --git a/cmake/FindWrapBacktrace.cmake b/cmake/FindWrapBacktrace.cmake
new file mode 100644
index 0000000000..3cc5748dd1
--- /dev/null
+++ b/cmake/FindWrapBacktrace.cmake
@@ -0,0 +1,20 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+if(TARGET WrapBacktrace::WrapBacktrace)
+ set(WrapBacktrace_FOUND ON)
+ return()
+endif()
+
+find_package(Backtrace)
+
+if(Backtrace_FOUND)
+ add_library(WrapBacktrace::WrapBacktrace INTERFACE IMPORTED)
+ target_link_libraries(WrapBacktrace::WrapBacktrace
+ INTERFACE ${Backtrace_LIBRARY})
+ target_include_directories(WrapBacktrace::WrapBacktrace
+ INTERFACE ${Backtrace_INCLUDE_DIR})
+ set(WrapBacktrace_FOUND ON)
+else()
+ set(WrapBacktrace_FOUND OFF)
+endif()
diff --git a/cmake/FindWrapBrotli.cmake b/cmake/FindWrapBrotli.cmake
new file mode 100644
index 0000000000..e2d7b564f6
--- /dev/null
+++ b/cmake/FindWrapBrotli.cmake
@@ -0,0 +1,100 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+if(TARGET WrapBrotli::WrapBrotliDec)
+ set(WrapBrotli_FOUND ON)
+ return()
+endif()
+
+# From VCPKG
+find_package(unofficial-brotli CONFIG QUIET)
+if (unofficial-brotli_FOUND)
+ add_library(WrapBrotli::WrapBrotliDec INTERFACE IMPORTED)
+ target_link_libraries(WrapBrotli::WrapBrotliDec INTERFACE unofficial::brotli::brotlidec)
+
+ add_library(WrapBrotli::WrapBrotliEnc INTERFACE IMPORTED)
+ target_link_libraries(WrapBrotli::WrapBrotliEnc INTERFACE unofficial::brotli::brotlienc)
+
+ add_library(WrapBrotli::WrapBrotliCommon INTERFACE IMPORTED)
+ target_link_libraries(WrapBrotli::WrapBrotliCommon INTERFACE unofficial::brotli::brotlicommon)
+
+ set(WrapBrotli_FOUND ON)
+else()
+ find_package(PkgConfig QUIET)
+ if (PKG_CONFIG_FOUND)
+ pkg_check_modules(libbrotlidec QUIET IMPORTED_TARGET "libbrotlidec")
+ if (libbrotlidec_FOUND)
+ add_library(WrapBrotli::WrapBrotliDec INTERFACE IMPORTED)
+ target_link_libraries(WrapBrotli::WrapBrotliDec INTERFACE PkgConfig::libbrotlidec)
+ set(WrapBrotli_FOUND ON)
+ endif()
+
+ pkg_check_modules(libbrotlienc QUIET IMPORTED_TARGET "libbrotlienc")
+ if (libbrotlienc_FOUND)
+ add_library(WrapBrotli::WrapBrotliEnc INTERFACE IMPORTED)
+ target_link_libraries(WrapBrotli::WrapBrotliEnc INTERFACE PkgConfig::libbrotlienc)
+ set(WrapBrotli_FOUND ON)
+ endif()
+
+ pkg_check_modules(libbrotlicommon QUIET IMPORTED_TARGET "libbrotlicommon")
+ if (libbrotlicommon_FOUND)
+ add_library(WrapBrotli::WrapBrotliCommon INTERFACE IMPORTED)
+ target_link_libraries(WrapBrotli::WrapBrotliCommon INTERFACE PkgConfig::libbrotlicommon)
+ set(WrapBrotli_FOUND ON)
+ endif()
+ else()
+ find_path(BROTLI_INCLUDE_DIR NAMES "brotli/decode.h")
+
+ foreach(lib_name BrotliDec BrotliEnc BrotliCommon)
+ string(TOLOWER ${lib_name} lower_lib_name)
+
+ find_library(${lib_name}_LIBRARY_RELEASE
+ NAMES ${lower_lib_name} ${lower_lib_name}-static)
+
+ find_library(${lib_name}_LIBRARY_DEBUG
+ NAMES ${lower_lib_name}d ${lower_lib_name}-staticd
+ ${lower_lib_name} ${lower_lib_name}-static)
+
+ include(SelectLibraryConfigurations)
+ select_library_configurations(${lib_name})
+
+ if (BROTLI_INCLUDE_DIR AND ${lib_name}_LIBRARY)
+ set(${lib_name}_FOUND TRUE)
+ endif()
+
+ if (${lib_name}_FOUND AND NOT TARGET WrapBrotli::Wrap${lib_name})
+ add_library(WrapBrotli::Wrap${lib_name} UNKNOWN IMPORTED)
+ set_target_properties(WrapBrotli::Wrap${lib_name} PROPERTIES
+ INTERFACE_INCLUDE_DIRECTORIES "${BROTLI_INCLUDE_DIR}"
+ IMPORTED_LOCATION "${${lib_name}_LIBRARY}")
+
+ if(${lib_name}_LIBRARY_RELEASE)
+ foreach(config_name RELEASE RELWITHDEBINFO MINSIZEREL)
+ set_property(TARGET WrapBrotli::Wrap${lib_name} APPEND PROPERTY
+ IMPORTED_CONFIGURATIONS ${config_name})
+ set_target_properties(WrapBrotli::Wrap${lib_name} PROPERTIES
+ IMPORTED_LOCATION_${config_name} "${${lib_name}_LIBRARY_RELEASE}")
+ endforeach()
+ endif()
+
+ if(${lib_name}_LIBRARY_DEBUG)
+ set_property(TARGET WrapBrotli::Wrap${lib_name} APPEND PROPERTY
+ IMPORTED_CONFIGURATIONS DEBUG)
+ set_target_properties(WrapBrotli::Wrap${lib_name} PROPERTIES
+ IMPORTED_LOCATION_DEBUG "${${lib_name}_LIBRARY_DEBUG}")
+ endif()
+ endif()
+ endforeach()
+
+ include(FindPackageHandleStandardArgs)
+ find_package_handle_standard_args(WrapBrotli REQUIRED_VARS
+ BrotliDec_FOUND BrotliEnc_FOUND BrotliCommon_FOUND)
+
+ if (WrapBrotli_FOUND)
+ set_property(TARGET WrapBrotli::WrapBrotliDec APPEND PROPERTY
+ INTERFACE_LINK_LIBRARIES WrapBrotli::WrapBrotliCommon)
+ set_property(TARGET WrapBrotli::WrapBrotliEnc APPEND PROPERTY
+ INTERFACE_LINK_LIBRARIES WrapBrotli::WrapBrotliCommon)
+ endif()
+ endif()
+endif()
diff --git a/cmake/FindWrapDBus1.cmake b/cmake/FindWrapDBus1.cmake
index ee856e1de5..e2a58790c4 100644
--- a/cmake/FindWrapDBus1.cmake
+++ b/cmake/FindWrapDBus1.cmake
@@ -1,3 +1,6 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# DBus1 is buggy and breaks PKG_CONFIG environment.
# Work around that:-/
# See https://gitlab.freedesktop.org/dbus/dbus/issues/267 for more information
@@ -19,7 +22,7 @@ if(DEFINED ENV{PKG_CONFIG_LIBDIR})
set(__qt_dbus_pcl "$ENV{PKG_CONFIG_LIBDIR}")
endif()
-find_package(DBus1 QUIET)
+find_package(DBus1 ${${CMAKE_FIND_PACKAGE_NAME}_FIND_VERSION} QUIET)
if(DEFINED __qt_dbus_pcd)
set(ENV{PKG_CONFIG_DIR} "${__qt_dbus_pcd}")
@@ -42,4 +45,6 @@ if(DBus1_FOUND)
endif()
include(FindPackageHandleStandardArgs)
-find_package_handle_standard_args(WrapDBus1 DEFAULT_MSG WrapDBus1_FOUND)
+find_package_handle_standard_args(WrapDBus1 REQUIRED_VARS
+ DBus1_LIBRARY DBus1_INCLUDE_DIR WrapDBus1_FOUND
+ VERSION_VAR DBus1_VERSION)
diff --git a/cmake/FindWrapDoubleConversion.cmake b/cmake/FindWrapDoubleConversion.cmake
deleted file mode 100644
index 1908467086..0000000000
--- a/cmake/FindWrapDoubleConversion.cmake
+++ /dev/null
@@ -1,22 +0,0 @@
-# We can't create the same interface imported target multiple times, CMake will complain if we do
-# that. This can happen if the find_package call is done in multiple different subdirectories.
-if(TARGET WrapDoubleConversion::WrapDoubleConversion)
- set(WrapDoubleConversion_FOUND ON)
- return()
-endif()
-
-set(WrapDoubleConversion_FOUND OFF)
-
-find_package(double-conversion QUIET)
-if (double-conversion_FOUND)
- include(FeatureSummary)
- set_package_properties(double-conversion PROPERTIES TYPE REQUIRED)
- add_library(WrapDoubleConversion::WrapDoubleConversion INTERFACE IMPORTED)
- target_link_libraries(WrapDoubleConversion::WrapDoubleConversion
- INTERFACE double-conversion::double-conversion)
- set(WrapDoubleConversion_FOUND ON)
- return()
-endif()
-
-include(FindPackageHandleStandardArgs)
-find_package_handle_standard_args(WrapDoubleConversion DEFAULT_MSG WrapDoubleConversion_FOUND)
diff --git a/cmake/FindWrapFreetype.cmake b/cmake/FindWrapFreetype.cmake
index 59219df6c2..22ae040f62 100644
--- a/cmake/FindWrapFreetype.cmake
+++ b/cmake/FindWrapFreetype.cmake
@@ -1,3 +1,6 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
include(QtFindWrapHelper NO_POLICY_SCOPE)
qt_find_package_system_or_bundled(wrap_freetype
diff --git a/cmake/FindWrapHarfbuzz.cmake b/cmake/FindWrapHarfbuzz.cmake
index a66bb08d89..60b0a97195 100644
--- a/cmake/FindWrapHarfbuzz.cmake
+++ b/cmake/FindWrapHarfbuzz.cmake
@@ -1,3 +1,6 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
include(QtFindWrapHelper NO_POLICY_SCOPE)
qt_find_package_system_or_bundled(wrap_harfbuzz
diff --git a/cmake/FindWrapJpeg.cmake b/cmake/FindWrapJpeg.cmake
new file mode 100644
index 0000000000..5714c1dc34
--- /dev/null
+++ b/cmake/FindWrapJpeg.cmake
@@ -0,0 +1,14 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+include(QtFindWrapHelper NO_POLICY_SCOPE)
+
+qt_find_package_system_or_bundled(wrap_jpeg
+ FRIENDLY_PACKAGE_NAME "Jpeg"
+ WRAP_PACKAGE_TARGET "WrapJpeg::WrapJpeg"
+ WRAP_PACKAGE_FOUND_VAR_NAME "WrapJpeg_FOUND"
+ BUNDLED_PACKAGE_NAME "BundledLibjpeg"
+ BUNDLED_PACKAGE_TARGET "BundledLibjpeg"
+ SYSTEM_PACKAGE_NAME "WrapSystemJpeg"
+ SYSTEM_PACKAGE_TARGET "WrapSystemJpeg::WrapSystemJpeg"
+)
diff --git a/cmake/FindWrapOpenGL.cmake b/cmake/FindWrapOpenGL.cmake
index 91d8b77c12..7295a159ca 100644
--- a/cmake/FindWrapOpenGL.cmake
+++ b/cmake/FindWrapOpenGL.cmake
@@ -1,3 +1,6 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# We can't create the same interface imported target multiple times, CMake will complain if we do
# that. This can happen if the find_package call is done in multiple different subdirectories.
if(TARGET WrapOpenGL::WrapOpenGL)
@@ -14,14 +17,18 @@ if (OpenGL_FOUND)
add_library(WrapOpenGL::WrapOpenGL INTERFACE IMPORTED)
if(APPLE)
+ # CMake 3.27 and older:
# On Darwin platforms FindOpenGL sets IMPORTED_LOCATION to the absolute path of the library
# within the framework. This ends up as an absolute path link flag, which we don't want,
# because that makes our .prl files un-relocatable.
# Extract the framework path instead, and use that in INTERFACE_LINK_LIBRARIES,
- # which CMake ends up transforming into a reloctable -framework flag.
+ # which CMake ends up transforming into a relocatable -framework flag.
# See https://gitlab.kitware.com/cmake/cmake/-/issues/20871 for details.
+ #
+ # CMake 3.28 and above:
+ # IMPORTED_LOCATION is the absolute path the the OpenGL.framework folder.
get_target_property(__opengl_fw_lib_path OpenGL::GL IMPORTED_LOCATION)
- if(__opengl_fw_lib_path)
+ if(__opengl_fw_lib_path AND NOT __opengl_fw_lib_path MATCHES "/([^/]+)\\.framework$")
get_filename_component(__opengl_fw_path "${__opengl_fw_lib_path}" DIRECTORY)
endif()
@@ -43,6 +50,16 @@ if (OpenGL_FOUND)
else()
target_link_libraries(WrapOpenGL::WrapOpenGL INTERFACE OpenGL::GL)
endif()
+elseif(UNIX AND NOT APPLE AND NOT CMAKE_SYSTEM_NAME STREQUAL "Integrity")
+ # Requesting only the OpenGL component ensures CMake does not mark the package as
+ # not found if neither GLX nor libGL are available. This allows finding OpenGL
+ # on an X11-less Linux system.
+ find_package(OpenGL ${WrapOpenGL_FIND_VERSION} COMPONENTS OpenGL)
+ if (OpenGL_FOUND)
+ set(WrapOpenGL_FOUND ON)
+ add_library(WrapOpenGL::WrapOpenGL INTERFACE IMPORTED)
+ target_link_libraries(WrapOpenGL::WrapOpenGL INTERFACE OpenGL::OpenGL)
+ endif()
endif()
include(FindPackageHandleStandardArgs)
diff --git a/cmake/FindWrapOpenSSL.cmake b/cmake/FindWrapOpenSSL.cmake
index 6e80862258..a4341271fe 100644
--- a/cmake/FindWrapOpenSSL.cmake
+++ b/cmake/FindWrapOpenSSL.cmake
@@ -1,3 +1,6 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# We can't create the same interface imported target multiple times, CMake will complain if we do
# that. This can happen if the find_package call is done in multiple different subdirectories.
if(TARGET WrapOpenSSL::WrapOpenSSL)
@@ -10,7 +13,19 @@ set(WrapOpenSSL_FOUND OFF)
# Reuse logic from the headers find script.
find_package(WrapOpenSSLHeaders ${WrapOpenSSL_FIND_VERSION})
-if(OpenSSL_FOUND)
+if(TARGET OpenSSL::SSL)
+ if(WIN32)
+ get_target_property(libType OpenSSL::Crypto TYPE)
+ if(libType STREQUAL "ALIAS")
+ get_target_property(writableLib OpenSSL::Crypto ALIASED_TARGET)
+ else()
+ set(writableLib OpenSSL::Crypto)
+ endif()
+ set_property(TARGET ${writableLib} APPEND PROPERTY INTERFACE_LINK_LIBRARIES ws2_32 crypt32)
+ unset(libType)
+ unset(writableLib)
+ endif()
+
set(WrapOpenSSL_FOUND ON)
add_library(WrapOpenSSL::WrapOpenSSL INTERFACE IMPORTED)
@@ -18,4 +33,10 @@ if(OpenSSL_FOUND)
endif()
include(FindPackageHandleStandardArgs)
-find_package_handle_standard_args(WrapOpenSSL DEFAULT_MSG WrapOpenSSL_FOUND)
+find_package_handle_standard_args(WrapOpenSSL
+ REQUIRED_VARS
+ OPENSSL_CRYPTO_LIBRARY
+ OPENSSL_INCLUDE_DIR
+ VERSION_VAR
+ OPENSSL_VERSION
+)
diff --git a/cmake/FindWrapOpenSSLHeaders.cmake b/cmake/FindWrapOpenSSLHeaders.cmake
index 52e6df3b0a..510ae10854 100644
--- a/cmake/FindWrapOpenSSLHeaders.cmake
+++ b/cmake/FindWrapOpenSSLHeaders.cmake
@@ -1,3 +1,6 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# We can't create the same interface imported target multiple times, CMake will complain if we do
# that. This can happen if the find_package call is done in multiple different subdirectories.
if(TARGET WrapOpenSSLHeaders::WrapOpenSSLHeaders)
@@ -28,7 +31,15 @@ if(OPENSSL_INCLUDE_DIR)
add_library(WrapOpenSSLHeaders::WrapOpenSSLHeaders INTERFACE IMPORTED)
target_include_directories(WrapOpenSSLHeaders::WrapOpenSSLHeaders INTERFACE
${OPENSSL_INCLUDE_DIR})
+
+ set_target_properties(WrapOpenSSLHeaders::WrapOpenSSLHeaders PROPERTIES
+ _qt_is_nolink_target TRUE)
endif()
include(FindPackageHandleStandardArgs)
-find_package_handle_standard_args(WrapOpenSSLHeaders DEFAULT_MSG WrapOpenSSLHeaders_FOUND)
+find_package_handle_standard_args(WrapOpenSSLHeaders
+ REQUIRED_VARS
+ OPENSSL_INCLUDE_DIR
+ VERSION_VAR
+ OPENSSL_VERSION
+)
diff --git a/cmake/FindWrapPCRE2.cmake b/cmake/FindWrapPCRE2.cmake
index 08e12163ed..024a9f084a 100644
--- a/cmake/FindWrapPCRE2.cmake
+++ b/cmake/FindWrapPCRE2.cmake
@@ -1,3 +1,6 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
include(QtFindWrapHelper NO_POLICY_SCOPE)
qt_find_package_system_or_bundled(wrap_pcre2
diff --git a/cmake/FindWrapPNG.cmake b/cmake/FindWrapPNG.cmake
index 55bfbdcffd..ba69628ac1 100644
--- a/cmake/FindWrapPNG.cmake
+++ b/cmake/FindWrapPNG.cmake
@@ -1,3 +1,6 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
include(QtFindWrapHelper NO_POLICY_SCOPE)
qt_find_package_system_or_bundled(wrap_png
diff --git a/cmake/FindWrapResolv.cmake b/cmake/FindWrapResolv.cmake
new file mode 100644
index 0000000000..1afd253ee8
--- /dev/null
+++ b/cmake/FindWrapResolv.cmake
@@ -0,0 +1,53 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# Copyright (C) 2023 Intel Corpotation.
+# SPDX-License-Identifier: BSD-3-Clause
+
+# We can't create the same interface imported target multiple times, CMake will complain if we do
+# that. This can happen if the find_package call is done in multiple different subdirectories.
+if(TARGET WrapResolv::WrapResolv)
+ set(WrapResolv_FOUND ON)
+ return()
+endif()
+
+set(WrapResolv_FOUND OFF)
+
+include(CheckCXXSourceCompiles)
+include(CMakePushCheckState)
+
+if(QNX)
+ find_library(LIBRESOLV socket)
+else()
+ find_library(LIBRESOLV resolv)
+endif()
+
+cmake_push_check_state()
+if(LIBRESOLV)
+ list(APPEND CMAKE_REQUIRED_LIBRARIES "${LIBRESOLV}")
+endif()
+
+check_cxx_source_compiles("
+#include <netinet/in.h>
+#include <resolv.h>
+
+int main(int, char **argv)
+{
+ res_state statep = 0;
+ int n = res_nmkquery(statep, 0, argv[1], 0, 0, NULL, 0, NULL, NULL, 0);
+ n = res_nsend(statep, NULL, 0, NULL, 0);
+ n = dn_expand(NULL, NULL, NULL, NULL, 0);
+ return n;
+}
+" HAVE_LIBRESOLV_FUNCTIONS)
+
+cmake_pop_check_state()
+
+if(HAVE_LIBRESOLV_FUNCTIONS)
+ set(WrapResolv_FOUND ON)
+ add_library(WrapResolv::WrapResolv INTERFACE IMPORTED)
+ if(LIBRESOLV)
+ target_link_libraries(WrapResolv::WrapResolv INTERFACE "${LIBRESOLV}")
+ endif()
+endif()
+
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(WrapResolv DEFAULT_MSG WrapResolv_FOUND)
diff --git a/cmake/FindWrapRt.cmake b/cmake/FindWrapRt.cmake
index 98acf2c0f3..b394b062da 100644
--- a/cmake/FindWrapRt.cmake
+++ b/cmake/FindWrapRt.cmake
@@ -1,3 +1,6 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# We can't create the same interface imported target multiple times, CMake will complain if we do
# that. This can happen if the find_package call is done in multiple different subdirectories.
if(TARGET WrapRt::WrapRt)
@@ -13,25 +16,39 @@ include(CMakePushCheckState)
find_library(LIBRT rt)
cmake_push_check_state()
-if(LIBRT_FOUND)
+if(LIBRT)
list(APPEND CMAKE_REQUIRED_LIBRARIES "${LIBRT}")
endif()
check_cxx_source_compiles("
-#include <unistd.h>
#include <time.h>
+#include <unistd.h>
-int main(int argc, char *argv[]) {
- timespec ts; clock_gettime(CLOCK_REALTIME, &ts);
-}" HAVE_GETTIME)
+int main(int, char **) {
+ struct timespec ts;
+ clock_gettime(CLOCK_REALTIME, &ts);
+ return 0;
+}
+" HAVE_GETTIME)
-cmake_pop_check_state()
+check_cxx_source_compiles("
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <fcntl.h>
+
+int main(int, char **) {
+ shm_open(\"test\", O_RDWR | O_CREAT | O_EXCL, 0666);
+ shm_unlink(\"test\");
+ return 0;
+}
+" HAVE_SHM_OPEN_SHM_UNLINK)
+cmake_pop_check_state()
-if(HAVE_GETTIME)
+if(HAVE_GETTIME OR HAVE_SHM_OPEN_SHM_UNLINK)
set(WrapRt_FOUND ON)
add_library(WrapRt::WrapRt INTERFACE IMPORTED)
- if (LIBRT_FOUND)
+ if (LIBRT)
target_link_libraries(WrapRt::WrapRt INTERFACE "${LIBRT}")
endif()
endif()
diff --git a/cmake/FindWrapSystemDoubleConversion.cmake b/cmake/FindWrapSystemDoubleConversion.cmake
new file mode 100644
index 0000000000..e0cbc946df
--- /dev/null
+++ b/cmake/FindWrapSystemDoubleConversion.cmake
@@ -0,0 +1,85 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+# We can't create the same interface imported target multiple times, CMake will complain if we do
+# that. This can happen if the find_package call is done in multiple different subdirectories.
+if(TARGET WrapSystemDoubleConversion::WrapSystemDoubleConversion)
+ set(WrapSystemDoubleConversion_FOUND ON)
+ return()
+endif()
+
+set(WrapSystemDoubleConversion_REQUIRED_VARS "__double_conversion_found")
+
+# Find either Config package or Find module.
+# Upstream can be built either with CMake and then provides a Config file, or with Scons in which
+# case there's no Config file.
+# A Find module might be provided by a 3rd party, for example Conan might generate a Find module.
+find_package(double-conversion ${${CMAKE_FIND_PACKAGE_NAME}_FIND_VERSION} QUIET)
+set(__double_conversion_target_name "double-conversion::double-conversion")
+if(double-conversion_FOUND AND TARGET "${__double_conversion_target_name}")
+ set(__double_conversion_found TRUE)
+ # This ensures the Config file is shown in the fphsa message.
+ if(double-conversion_CONFIG)
+ list(PREPEND WrapSystemDoubleConversion_REQUIRED_VARS
+ double-conversion_CONFIG)
+ endif()
+endif()
+
+if(NOT __double_conversion_found)
+ list(PREPEND WrapSystemDoubleConversion_REQUIRED_VARS
+ DOUBLE_CONVERSION_LIBRARY DOUBLE_CONVERSION_INCLUDE_DIR)
+
+ find_path(DOUBLE_CONVERSION_INCLUDE_DIR
+ NAMES
+ double-conversion/double-conversion.h
+ )
+
+ find_library(DOUBLE_CONVERSION_LIBRARY_RELEASE NAMES double-conversion)
+
+ # We assume a possible debug build of this library to be named with a d suffix.
+ # Adjust accordingly if a different naming scheme is established.
+ find_library(DOUBLE_CONVERSION_LIBRARY_DEBUG NAMES double-conversiond)
+
+ include(SelectLibraryConfigurations)
+ select_library_configurations(DOUBLE_CONVERSION)
+ mark_as_advanced(DOUBLE_CONVERSION_INCLUDE_DIR DOUBLE_CONVERSION_LIBRARY)
+ set(DOUBLE_CONVERSION_INCLUDE_DIRS "${DOUBLE_CONVERSION_INCLUDE_DIR}")
+
+ if(DOUBLE_CONVERSION_LIBRARIES AND DOUBLE_CONVERSION_INCLUDE_DIRS)
+ set(__double_conversion_found TRUE)
+ endif()
+endif()
+
+include(FindPackageHandleStandardArgs)
+
+set(__double_conversion_fphsa_args "")
+if(double-conversion_VERSION)
+ set(WrapSystemDoubleConversion_VERSION "${double-conversion_VERSION}")
+ list(APPEND __double_conversion_fphsa_args VERSION_VAR WrapSystemDoubleConversion_VERSION)
+endif()
+
+find_package_handle_standard_args(WrapSystemDoubleConversion
+ REQUIRED_VARS ${WrapSystemDoubleConversion_REQUIRED_VARS}
+ ${__double_conversion_fphsa_args})
+
+if(WrapSystemDoubleConversion_FOUND)
+ add_library(WrapSystemDoubleConversion::WrapSystemDoubleConversion INTERFACE IMPORTED)
+ if(TARGET "${__double_conversion_target_name}")
+ target_link_libraries(WrapSystemDoubleConversion::WrapSystemDoubleConversion
+ INTERFACE "${__double_conversion_target_name}")
+ else()
+ target_link_libraries(WrapSystemDoubleConversion::WrapSystemDoubleConversion
+ INTERFACE ${DOUBLE_CONVERSION_LIBRARIES})
+ target_include_directories(WrapSystemDoubleConversion::WrapSystemDoubleConversion
+ INTERFACE ${DOUBLE_CONVERSION_INCLUDE_DIRS})
+ endif()
+endif()
+unset(__double_conversion_target_name)
+unset(__double_conversion_found)
+unset(__double_conversion_fphsa_args)
+
+include(FeatureSummary)
+set_package_properties(WrapSystemDoubleConversion PROPERTIES
+ URL "https://github.com/google/double-conversion"
+ DESCRIPTION "double-conversion library")
+
diff --git a/cmake/FindWrapSystemFreetype.cmake b/cmake/FindWrapSystemFreetype.cmake
index 41c669b973..d0c27a9f0f 100644
--- a/cmake/FindWrapSystemFreetype.cmake
+++ b/cmake/FindWrapSystemFreetype.cmake
@@ -1,37 +1,53 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# We can't create the same interface imported target multiple times, CMake will complain if we do
# that. This can happen if the find_package call is done in multiple different subdirectories.
if(TARGET WrapSystemFreetype::WrapSystemFreetype)
- set(WrapSystemFreetype_FOUND ON)
+ set(WrapSystemFreetype_FOUND TRUE)
return()
endif()
-
-set(WrapSystemFreetype_FOUND OFF)
+set(WrapSystemFreetype_REQUIRED_VARS __freetype_found)
# Hunter has the package named freetype, but exports the Freetype::Freetype target as upstream
# First try the CONFIG package, and afterwards the MODULE if not found
-
-find_package(Freetype QUIET CONFIG NAMES Freetype freetype QUIET)
+find_package(Freetype ${${CMAKE_FIND_PACKAGE_NAME}_FIND_VERSION}
+ CONFIG NAMES Freetype freetype QUIET)
if(NOT Freetype_FOUND)
- find_package(Freetype QUIET MODULE)
+ find_package(Freetype ${${CMAKE_FIND_PACKAGE_NAME}_FIND_VERSION} QUIET MODULE)
endif()
if(Freetype_FOUND)
# vcpkg defines a lower case target name, while upstream Find module defines a prefixed
# upper case name.
- set(potential_target_names Freetype::Freetype freetype)
- foreach(target_name ${potential_target_names})
- if(TARGET ${target_name})
- set(WrapSystemFreetype_FOUND ON)
- set(final_target_name ${target_name})
-
- add_library(WrapSystemFreetype::WrapSystemFreetype INTERFACE IMPORTED)
- target_link_libraries(WrapSystemFreetype::WrapSystemFreetype INTERFACE
- ${final_target_name})
-
+ set(__freetype_potential_target_names Freetype::Freetype freetype)
+ foreach(__freetype_potential_target_name ${__freetype_potential_target_names})
+ if(TARGET "${__freetype_potential_target_name}")
+ set(__freetype_target_name "${__freetype_potential_target_name}")
+ set(__freetype_found TRUE)
break()
endif()
endforeach()
endif()
+if(FREETYPE_LIBRARIES)
+ list(PREPEND WrapSystemFreetype_REQUIRED_VARS FREETYPE_LIBRARIES)
+endif()
+if(Freetype_VERSION)
+ set(WrapSystemFreetype_VERSION "${Freetype_VERSION}")
+elseif(FREETYPE_VERSION_STRING)
+ set(WrapSystemFreetype_VERSION "${FREETYPE_VERSION_STRING}")
+endif()
+
include(FindPackageHandleStandardArgs)
-find_package_handle_standard_args(WrapSystemFreetype DEFAULT_MSG WrapSystemFreetype_FOUND)
+find_package_handle_standard_args(WrapSystemFreetype
+ REQUIRED_VARS ${WrapSystemFreetype_REQUIRED_VARS}
+ VERSION_VAR WrapSystemFreetype_VERSION)
+
+if(WrapSystemFreetype_FOUND)
+ add_library(WrapSystemFreetype::WrapSystemFreetype INTERFACE IMPORTED)
+ target_link_libraries(WrapSystemFreetype::WrapSystemFreetype
+ INTERFACE "${__freetype_target_name}")
+endif()
+unset(__freetype_target_name)
+unset(__freetype_found)
diff --git a/cmake/FindWrapSystemHarfbuzz.cmake b/cmake/FindWrapSystemHarfbuzz.cmake
index 087c1b070b..07b3405bc0 100644
--- a/cmake/FindWrapSystemHarfbuzz.cmake
+++ b/cmake/FindWrapSystemHarfbuzz.cmake
@@ -1,13 +1,15 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# We can't create the same interface imported target multiple times, CMake will complain if we do
# that. This can happen if the find_package call is done in multiple different subdirectories.
if(TARGET WrapSystemHarfbuzz::WrapSystemHarfbuzz)
- set(WrapSystemHarfbuzz_FOUND ON)
+ set(WrapSystemHarfbuzz_FOUND TRUE)
return()
endif()
+set(WrapSystemHarfbuzz_REQUIRED_VARS __harfbuzz_found)
-set(WrapSystemHarfbuzz_FOUND OFF)
-
-find_package(harfbuzz QUIET)
+find_package(harfbuzz ${${CMAKE_FIND_PACKAGE_NAME}_FIND_VERSION} QUIET)
# Gentoo has some buggy version of a harfbuzz Config file. Check if include paths are valid.
set(__harfbuzz_target_name "harfbuzz::harfbuzz")
@@ -21,28 +23,61 @@ if(harfbuzz_FOUND AND TARGET "${__harfbuzz_target_name}")
break()
endif()
endforeach()
+
+ set(__harfbuzz_found TRUE)
+ if(harfbuzz_VERSION)
+ set(WrapSystemHarfbuzz_VERSION "${harfbuzz_VERSION}")
+ endif()
endif()
-if(__harfbuzz_broken_config_file)
+if(__harfbuzz_broken_config_file OR NOT __harfbuzz_found)
find_package(PkgConfig QUIET)
+ pkg_check_modules(PC_HARFBUZZ IMPORTED_TARGET "harfbuzz")
+ if(PC_HARFBUZZ_FOUND)
+ set(__harfbuzz_target_name "PkgConfig::PC_HARFBUZZ")
+ set(__harfbuzz_find_include_dirs_hints
+ HINTS ${PC_HARFBUZZ_INCLUDEDIR})
+ set(__harfbuzz_find_library_hints
+ HINTS ${PC_HARFBUZZ_LIBDIR})
+ if(PC_HARFBUZZ_VERSION)
+ set(WrapSystemHarfbuzz_VERSION "${PC_HARFBUZZ_VERSION}")
+ endif()
+ else()
+ set(__harfbuzz_target_name "Harfbuzz::Harfbuzz")
+ endif()
- pkg_check_modules(harfbuzz harfbuzz IMPORTED_TARGET)
- set(__harfbuzz_target_name "PkgConfig::harfbuzz")
+ find_path(HARFBUZZ_INCLUDE_DIRS
+ NAMES harfbuzz/hb.h
+ ${__harfbuzz_find_include_dirs_hints})
+ find_library(HARFBUZZ_LIBRARIES
+ NAMES harfbuzz
+ ${__harfbuzz_find_library_hints})
- if (NOT TARGET "${__harfbuzz_target_name}")
- set(harfbuzz_FOUND 0)
+ if(HARFBUZZ_INCLUDE_DIRS AND HARFBUZZ_LIBRARIES)
+ set(__harfbuzz_found TRUE)
+ if(NOT PC_HARFBUZZ_FOUND)
+ add_library(${__harfbuzz_target_name} UNKNOWN IMPORTED)
+ list(TRANSFORM HARFBUZZ_INCLUDE_DIRS APPEND "/harfbuzz")
+ set_target_properties(${__harfbuzz_target_name} PROPERTIES
+ IMPORTED_LOCATION "${HARFBUZZ_LIBRARIES}"
+ INTERFACE_INCLUDE_DIRECTORIES "${HARFBUZZ_INCLUDE_DIRS}"
+ )
+ endif()
endif()
endif()
-if(TARGET "${__harfbuzz_target_name}")
- set(WrapSystemHarfbuzz_FOUND ON)
-
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(WrapSystemHarfbuzz
+ REQUIRED_VARS ${WrapSystemHarfbuzz_REQUIRED_VARS}
+ VERSION_VAR WrapSystemHarfbuzz_VERSION)
+if(WrapSystemHarfbuzz_FOUND)
add_library(WrapSystemHarfbuzz::WrapSystemHarfbuzz INTERFACE IMPORTED)
- target_link_libraries(WrapSystemHarfbuzz::WrapSystemHarfbuzz INTERFACE ${__harfbuzz_target_name})
+ target_link_libraries(WrapSystemHarfbuzz::WrapSystemHarfbuzz
+ INTERFACE "${__harfbuzz_target_name}")
endif()
unset(__harfbuzz_target_name)
+unset(__harfbuzz_find_include_dirs_hints)
+unset(__harfbuzz_find_library_hints)
+unset(__harfbuzz_found)
unset(__harfbuzz_include_dir)
unset(__harfbuzz_broken_config_file)
-
-include(FindPackageHandleStandardArgs)
-find_package_handle_standard_args(WrapSystemHarfbuzz DEFAULT_MSG WrapSystemHarfbuzz_FOUND)
diff --git a/cmake/FindWrapSystemJpeg.cmake b/cmake/FindWrapSystemJpeg.cmake
new file mode 100644
index 0000000000..16a9e5ab23
--- /dev/null
+++ b/cmake/FindWrapSystemJpeg.cmake
@@ -0,0 +1,35 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+if(TARGET WrapSystemJpeg::WrapSystemJpeg)
+ set(WrapSystemJpeg_FOUND TRUE)
+ return()
+endif()
+set(WrapSystemJpeg_REQUIRED_VARS __jpeg_found)
+
+find_package(JPEG ${${CMAKE_FIND_PACKAGE_NAME}_FIND_VERSION} QUIET)
+
+set(__jpeg_target_name "JPEG::JPEG")
+if(JPEG_FOUND AND TARGET "${__jpeg_target_name}")
+ set(__jpeg_found TRUE)
+endif()
+
+if(JPEG_LIBRARIES)
+ list(PREPEND WrapSystemJpeg_REQUIRED_VARS JPEG_LIBRARIES)
+endif()
+if(JPEG_VERSION)
+ set(WrapSystemJpeg_VERSION "${JPEG_VERSION}")
+endif()
+
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(WrapSystemJpeg
+ REQUIRED_VARS ${WrapSystemJpeg_REQUIRED_VARS}
+ VERSION_VAR WrapSystemJpeg_VERSION)
+
+if(WrapSystemJpeg_FOUND)
+ add_library(WrapSystemJpeg::WrapSystemJpeg INTERFACE IMPORTED)
+ target_link_libraries(WrapSystemJpeg::WrapSystemJpeg
+ INTERFACE "${__jpeg_target_name}")
+endif()
+unset(__jpeg_target_name)
+unset(__jpeg_found)
diff --git a/cmake/FindWrapSystemMd4c.cmake b/cmake/FindWrapSystemMd4c.cmake
new file mode 100644
index 0000000000..5ac3ded975
--- /dev/null
+++ b/cmake/FindWrapSystemMd4c.cmake
@@ -0,0 +1,43 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+if(TARGET WrapSystemMd4c::WrapSystemMd4c)
+ set(WrapSystemMd4c_FOUND TRUE)
+ return()
+endif()
+set(WrapSystemMd4c_REQUIRED_VARS __md4c_found)
+
+find_package(md4c ${${CMAKE_FIND_PACKAGE_NAME}_FIND_VERSION} QUIET)
+
+set(__md4c_target_name "md4c::md4c")
+
+if(md4c_FOUND)
+ set(__md4c_found TRUE)
+
+ # md4c provides a md4c::md4c target but
+ # older versions create a md4c target without
+ # namespace. If we find the old variant create
+ # a namespaced target out of the md4c target.
+ if(TARGET md4c AND NOT TARGET ${__md4c_target_name})
+ add_library(${__md4c_target_name} INTERFACE IMPORTED)
+ target_link_libraries(${__md4c_target_name} INTERFACE md4c)
+ endif()
+
+ if(md4c_VERSION)
+ set(WrapSystemMd4c_VERSION "${md4c_VERSION}")
+ endif()
+endif()
+
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(WrapSystemMd4c
+ REQUIRED_VARS ${WrapSystemMd4c_REQUIRED_VARS}
+ VERSION_VAR WrapSystemMd4c_VERSION)
+
+if(WrapSystemMd4c_FOUND)
+ add_library(WrapSystemMd4c::WrapSystemMd4c INTERFACE IMPORTED)
+ target_link_libraries(WrapSystemMd4c::WrapSystemMd4c
+ INTERFACE "${__md4c_target_name}")
+endif()
+
+unset(__md4c_found)
+unset(__md4c_target_name)
diff --git a/cmake/FindWrapSystemPCRE2.cmake b/cmake/FindWrapSystemPCRE2.cmake
index 32966c2e30..61e0d2fb5b 100644
--- a/cmake/FindWrapSystemPCRE2.cmake
+++ b/cmake/FindWrapSystemPCRE2.cmake
@@ -1,26 +1,62 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
if(TARGET WrapSystemPCRE2::WrapSystemPCRE2)
set(WrapSystemPCRE2_FOUND TRUE)
return()
endif()
+set(WrapSystemPCRE2_REQUIRED_VARS __pcre2_found)
-find_package(PCRE2 CONFIG QUIET)
+find_package(PCRE2 ${${CMAKE_FIND_PACKAGE_NAME}_FIND_VERSION} COMPONENTS 16BIT QUIET)
-if(PCRE2_FOUND AND TARGET PCRE2::pcre2-16)
+set(__pcre2_target_name "PCRE2::16BIT")
+if(PCRE2_FOUND AND TARGET "${__pcre2_target_name}")
# Hunter case.
- add_library(WrapSystemPCRE2::WrapSystemPCRE2 INTERFACE IMPORTED)
- target_link_libraries(WrapSystemPCRE2::WrapSystemPCRE2 INTERFACE PCRE2::pcre2-16)
- set(WrapSystemPCRE2_FOUND TRUE)
-else()
- find_library(PCRE2_LIBRARIES NAMES pcre2-16)
- find_path(PCRE2_INCLUDE_DIRS pcre2.h)
+ set(__pcre2_found TRUE)
+ if(PCRE2_VERSION)
+ set(WrapSystemPCRE2_VERSION "${PCRE2_VERSION}")
+ endif()
+endif()
+
+if(NOT __pcre2_found)
+ list(PREPEND WrapSystemPCRE2_REQUIRED_VARS PCRE2_LIBRARIES PCRE2_INCLUDE_DIRS)
+
+ find_package(PkgConfig QUIET)
+ pkg_check_modules(PC_PCRE2 QUIET "libpcre2-16")
+
+ find_path(PCRE2_INCLUDE_DIRS
+ NAMES pcre2.h
+ HINTS ${PC_PCRE2_INCLUDEDIR})
+ find_library(PCRE2_LIBRARY_RELEASE
+ NAMES pcre2-16
+ HINTS ${PC_PCRE2_LIBDIR})
+ find_library(PCRE2_LIBRARY_DEBUG
+ NAMES pcre2-16d pcre2-16
+ HINTS ${PC_PCRE2_LIBDIR})
+ include(SelectLibraryConfigurations)
+ select_library_configurations(PCRE2)
+
+ if(PC_PCRE2_VERSION)
+ set(WrapSystemPCRE2_VERSION "${PC_PCRE2_VERSION}")
+ endif()
if (PCRE2_LIBRARIES AND PCRE2_INCLUDE_DIRS)
- add_library(WrapSystemPCRE2::WrapSystemPCRE2 INTERFACE IMPORTED)
- target_link_libraries(WrapSystemPCRE2::WrapSystemPCRE2 INTERFACE ${PCRE2_LIBRARIES})
- target_include_directories(WrapSystemPCRE2::WrapSystemPCRE2 INTERFACE ${PCRE2_INCLUDE_DIRS})
- set(WrapSystemPCRE2_FOUND TRUE)
+ set(__pcre2_found TRUE)
endif()
endif()
include(FindPackageHandleStandardArgs)
-find_package_handle_standard_args(WrapSystemPCRE2 DEFAULT_MSG WrapSystemPCRE2_FOUND)
+find_package_handle_standard_args(WrapSystemPCRE2
+ REQUIRED_VARS ${WrapSystemPCRE2_REQUIRED_VARS}
+ VERSION_VAR WrapSystemPCRE2_VERSION)
+if(WrapSystemPCRE2_FOUND)
+ add_library(WrapSystemPCRE2::WrapSystemPCRE2 INTERFACE IMPORTED)
+ if(TARGET "${__pcre2_target_name}")
+ target_link_libraries(WrapSystemPCRE2::WrapSystemPCRE2 INTERFACE "${__pcre2_target_name}")
+ else()
+ target_link_libraries(WrapSystemPCRE2::WrapSystemPCRE2 INTERFACE ${PCRE2_LIBRARIES})
+ target_include_directories(WrapSystemPCRE2::WrapSystemPCRE2 INTERFACE ${PCRE2_INCLUDE_DIRS})
+ endif()
+endif()
+unset(__pcre2_target_name)
+unset(__pcre2_found)
diff --git a/cmake/FindWrapSystemPNG.cmake b/cmake/FindWrapSystemPNG.cmake
index dc42c731fb..967ccc5c02 100644
--- a/cmake/FindWrapSystemPNG.cmake
+++ b/cmake/FindWrapSystemPNG.cmake
@@ -1,29 +1,42 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# We can't create the same interface imported target multiple times, CMake will complain if we do
# that. This can happen if the find_package call is done in multiple different subdirectories.
if(TARGET WrapSystemPNG::WrapSystemPNG)
- set(WrapSystemPNG_FOUND ON)
+ set(WrapSystemPNG_FOUND TRUE)
return()
endif()
+set(WrapSystemPNG_REQUIRED_VARS __png_found)
-set(WrapSystemPNG_FOUND OFF)
-
-find_package(PNG QUIET)
+find_package(PNG ${${CMAKE_FIND_PACKAGE_NAME}_FIND_VERSION} QUIET)
-if(PNG_FOUND)
- set(potential_target_names PNG::PNG)
- foreach(target_name ${potential_target_names})
- if(TARGET ${target_name})
- set(WrapSystemPNG_FOUND ON)
- set(final_target_name ${target_name})
-
- add_library(WrapSystemPNG::WrapSystemPNG INTERFACE IMPORTED)
- target_link_libraries(WrapSystemPNG::WrapSystemPNG INTERFACE
- ${final_target_name})
+set(__png_target_name "PNG::PNG")
+if(PNG_FOUND AND TARGET "${__png_target_name}")
+ set(__png_found TRUE)
+ if(PNG_VERSION)
+ set(WrapSystemPNG_VERSION "${PNG_VERSION}")
+ endif()
+endif()
- break()
- endif()
- endforeach()
+if(PNG_LIBRARIES)
+ list(PREPEND WrapSystemPNG_REQUIRED_VARS PNG_LIBRARIES)
+endif()
+if(PNG_VERSION)
+ set(WrapSystemPNG_VERSION "${PNG_VERSION}")
+elseif(PNG_VERSION_STRING)
+ set(WrapSystemPNG_VERSION "${PNG_VERSION_STRING}")
endif()
include(FindPackageHandleStandardArgs)
-find_package_handle_standard_args(WrapSystemPNG DEFAULT_MSG WrapSystemPNG_FOUND)
+find_package_handle_standard_args(WrapSystemPNG
+ REQUIRED_VARS ${WrapSystemPNG_REQUIRED_VARS}
+ VERSION_VAR WrapSystemPNG_VERSION)
+
+if(WrapSystemPNG_FOUND)
+ add_library(WrapSystemPNG::WrapSystemPNG INTERFACE IMPORTED)
+ target_link_libraries(WrapSystemPNG::WrapSystemPNG
+ INTERFACE "${__png_target_name}")
+endif()
+unset(__png_target_name)
+unset(__png_found)
diff --git a/cmake/FindWrapSystemZLIB.cmake b/cmake/FindWrapSystemZLIB.cmake
new file mode 100644
index 0000000000..5db43db626
--- /dev/null
+++ b/cmake/FindWrapSystemZLIB.cmake
@@ -0,0 +1,32 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+# We can't create the same interface imported target multiple times, CMake will complain if we do
+# that. This can happen if the find_package call is done in multiple different subdirectories.
+if(TARGET WrapSystemZLIB::WrapSystemZLIB)
+ set(WrapSystemZLIB_FOUND ON)
+ return()
+endif()
+
+set(WrapSystemZLIB_FOUND OFF)
+
+find_package(ZLIB ${${CMAKE_FIND_PACKAGE_NAME}_FIND_VERSION})
+
+if(ZLIB_FOUND)
+ set(WrapSystemZLIB_FOUND ON)
+
+ add_library(WrapSystemZLIB::WrapSystemZLIB INTERFACE IMPORTED)
+ if(APPLE)
+ # On Darwin platforms FindZLIB sets IMPORTED_LOCATION to the absolute path of the library
+ # within the framework. This ends up as an absolute path link flag, which we don't want,
+ # because that makes our .prl files un-relocatable and also breaks iOS simulator_and_device
+ # SDK switching in Xcode.
+ # Just pass a linker flag instead.
+ target_link_libraries(WrapSystemZLIB::WrapSystemZLIB INTERFACE "-lz")
+ else()
+ target_link_libraries(WrapSystemZLIB::WrapSystemZLIB INTERFACE ZLIB::ZLIB)
+ endif()
+endif()
+
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(WrapSystemZLIB DEFAULT_MSG WrapSystemZLIB_FOUND)
diff --git a/cmake/FindWrapVulkan.cmake b/cmake/FindWrapVulkan.cmake
new file mode 100644
index 0000000000..843ca4c202
--- /dev/null
+++ b/cmake/FindWrapVulkan.cmake
@@ -0,0 +1,23 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+# We can't create the same interface imported target multiple times, CMake will complain if we do
+# that. This can happen if the find_package call is done in multiple different subdirectories.
+if(TARGET WrapVulkan::WrapVulkan)
+ set(WrapVulkan_FOUND ON)
+ return()
+endif()
+
+set(WrapVulkan_FOUND OFF)
+
+find_package(Vulkan ${WrapVulkan_FIND_VERSION} QUIET)
+
+if(Vulkan_FOUND)
+ set(WrapVulkan_FOUND ON)
+
+ add_library(WrapVulkan::WrapVulkan INTERFACE IMPORTED)
+ target_link_libraries(WrapVulkan::WrapVulkan INTERFACE Vulkan::Vulkan)
+endif()
+
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(WrapVulkan DEFAULT_MSG Vulkan_LIBRARY Vulkan_INCLUDE_DIR)
diff --git a/cmake/FindWrapVulkanHeaders.cmake b/cmake/FindWrapVulkanHeaders.cmake
new file mode 100644
index 0000000000..92510ae000
--- /dev/null
+++ b/cmake/FindWrapVulkanHeaders.cmake
@@ -0,0 +1,75 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+# We can't create the same interface imported target multiple times, CMake will complain if we do
+# that. This can happen if the find_package call is done in multiple different subdirectories.
+if(TARGET WrapVulkanHeaders::WrapVulkanHeaders)
+ set(WrapVulkanHeaders_FOUND ON)
+ return()
+endif()
+
+set(WrapVulkanHeaders_FOUND OFF)
+
+find_package(Vulkan ${WrapVulkanHeaders_FIND_VERSION} QUIET)
+
+# We are interested only in include headers. The libraries might be missing, so we can't check the
+# _FOUND variable.
+if(Vulkan_INCLUDE_DIR)
+ set(WrapVulkanHeaders_FOUND ON)
+
+ add_library(WrapVulkanHeaders::WrapVulkanHeaders INTERFACE IMPORTED)
+ target_include_directories(WrapVulkanHeaders::WrapVulkanHeaders INTERFACE
+ ${Vulkan_INCLUDE_DIR})
+
+ set_target_properties(WrapVulkanHeaders::WrapVulkanHeaders PROPERTIES
+ _qt_is_nolink_target TRUE)
+
+ set_target_properties(WrapVulkanHeaders::WrapVulkanHeaders PROPERTIES
+ _qt_skip_include_dir_for_pri TRUE)
+
+ # Also propagate MoltenVK include directory on Apple platforms if found.
+ if(APPLE)
+ # Check for the LunarG Vulkan SDK folder structure.
+ set(__qt_molten_vk_include_path "${Vulkan_INCLUDE_DIR}/../../MoltenVK/include")
+ get_filename_component(
+ __qt_molten_vk_include_path
+ "${__qt_molten_vk_include_path}" ABSOLUTE)
+ if(EXISTS "${__qt_molten_vk_include_path}")
+ target_include_directories(WrapVulkanHeaders::WrapVulkanHeaders INTERFACE
+ ${__qt_molten_vk_include_path})
+ endif()
+
+ # Check for homebrew molten-vk folder structure
+ set(__qt_molten_vk_homebrew_include_path "${Vulkan_INCLUDE_DIR}/../../include")
+ get_filename_component(
+ __qt_molten_vk_homebrew_include_path
+ "${__qt_molten_vk_homebrew_include_path}" ABSOLUTE)
+ if(EXISTS "${__qt_molten_vk_homebrew_include_path}")
+ target_include_directories(WrapVulkanHeaders::WrapVulkanHeaders INTERFACE
+ ${__qt_molten_vk_homebrew_include_path})
+ endif()
+
+ # Check for homebrew vulkan-headers folder structure
+ # If instead of molten-vk folder, CMAKE_PREFIX_PATH points to Homebrew's
+ # vulkan-headers installation, then we will not be able to find molten-vk
+ # headers. If we assume that user has installed the molten-vk formula as
+ # well, then we might have a chance to pick it up like this.
+ if(Vulkan_INCLUDE_DIR MATCHES "/homebrew/Cellar/")
+ set(__qt_standalone_molten_vk_homebrew_include_path
+ "${Vulkan_INCLUDE_DIR}/../../../../opt/molten-vk/include")
+ else()
+ set(__qt_standalone_molten_vk_homebrew_include_path
+ "${Vulkan_INCLUDE_DIR}/../../molten-vk/include")
+ endif()
+ get_filename_component(
+ __qt_standalone_molten_vk_homebrew_include_path
+ "${__qt_standalone_molten_vk_homebrew_include_path}" ABSOLUTE)
+ if(EXISTS "${__qt_standalone_molten_vk_homebrew_include_path}")
+ target_include_directories(WrapVulkanHeaders::WrapVulkanHeaders INTERFACE
+ ${__qt_standalone_molten_vk_homebrew_include_path})
+ endif()
+ endif()
+endif()
+
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(WrapVulkanHeaders DEFAULT_MSG Vulkan_INCLUDE_DIR)
diff --git a/cmake/FindWrapZLIB.cmake b/cmake/FindWrapZLIB.cmake
new file mode 100644
index 0000000000..6cf60fab9f
--- /dev/null
+++ b/cmake/FindWrapZLIB.cmake
@@ -0,0 +1,14 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+include(QtFindWrapHelper NO_POLICY_SCOPE)
+
+qt_find_package_system_or_bundled(wrap_zlib
+ FRIENDLY_PACKAGE_NAME "ZLIB"
+ WRAP_PACKAGE_TARGET "WrapZLIB::WrapZLIB"
+ WRAP_PACKAGE_FOUND_VAR_NAME "WrapZLIB_FOUND"
+ BUNDLED_PACKAGE_NAME "BundledZLIB"
+ BUNDLED_PACKAGE_TARGET "BundledZLIB"
+ SYSTEM_PACKAGE_NAME "WrapSystemZLIB"
+ SYSTEM_PACKAGE_TARGET "WrapSystemZLIB::WrapSystemZLIB"
+)
diff --git a/cmake/FindWrapZSTD.cmake b/cmake/FindWrapZSTD.cmake
new file mode 100644
index 0000000000..fb424236b8
--- /dev/null
+++ b/cmake/FindWrapZSTD.cmake
@@ -0,0 +1,91 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+#.rst:
+# FindZstd
+# ---------
+#
+# Try to locate the Zstd library.
+# If found, this will define the following variables:
+#
+# ``WrapZSTD_FOUND``
+# True if the zstd library is available
+# ``ZSTD_INCLUDE_DIRS``
+# The zstd include directories
+# ``ZSTD_LIBRARIES``
+# The zstd libraries for linking
+#
+# If ``WrapZSTD_FOUND`` is TRUE, it will also define the following
+# imported target:
+#
+# ``WrapZSTD::WrapZSTD``
+# The zstd library
+
+find_package(zstd CONFIG QUIET)
+
+include(FindPackageHandleStandardArgs)
+
+if(TARGET zstd::libzstd_static OR TARGET zstd::libzstd_shared)
+ find_package_handle_standard_args(WrapZSTD
+ REQUIRED_VARS zstd_VERSION VERSION_VAR zstd_VERSION)
+ if(TARGET zstd::libzstd_shared)
+ set(zstdtargetsuffix "_shared")
+ else()
+ set(zstdtargetsuffix "_static")
+ endif()
+ if(NOT TARGET WrapZSTD::WrapZSTD)
+ add_library(WrapZSTD::WrapZSTD INTERFACE IMPORTED)
+ set_target_properties(WrapZSTD::WrapZSTD PROPERTIES
+ INTERFACE_LINK_LIBRARIES "zstd::libzstd${zstdtargetsuffix}")
+ endif()
+else()
+ find_package(PkgConfig QUIET)
+ pkg_check_modules(PC_ZSTD QUIET "libzstd")
+
+ find_path(ZSTD_INCLUDE_DIRS
+ NAMES zstd.h
+ HINTS ${PC_ZSTD_INCLUDEDIR}
+ PATH_SUFFIXES zstd)
+
+ find_library(ZSTD_LIBRARY_RELEASE
+ NAMES zstd zstd_static
+ HINTS ${PC_ZSTD_LIBDIR}
+ )
+ find_library(ZSTD_LIBRARY_DEBUG
+ NAMES zstdd zstd_staticd zstd zstd_static
+ HINTS ${PC_ZSTD_LIBDIR}
+ )
+
+ include(SelectLibraryConfigurations)
+ select_library_configurations(ZSTD)
+
+ if(PC_ZSTD_VERSION)
+ set(WrapZSTD_VERSION "${PC_ZSTD_VERSION}")
+ endif()
+ find_package_handle_standard_args(WrapZSTD
+ REQUIRED_VARS ZSTD_LIBRARIES ZSTD_INCLUDE_DIRS
+ VERSION_VAR WrapZSTD_VERSION)
+
+ if(WrapZSTD_FOUND AND NOT TARGET WrapZSTD::WrapZSTD)
+ add_library(WrapZSTD::WrapZSTD UNKNOWN IMPORTED)
+ set_target_properties(WrapZSTD::WrapZSTD PROPERTIES
+ INTERFACE_INCLUDE_DIRECTORIES "${ZSTD_INCLUDE_DIRS}")
+ set_target_properties(WrapZSTD::WrapZSTD PROPERTIES
+ IMPORTED_LOCATION "${ZSTD_LIBRARY}")
+ if(ZSTD_LIBRARY_RELEASE)
+ set_target_properties(WrapZSTD::WrapZSTD PROPERTIES
+ IMPORTED_LOCATION_RELEASE "${ZSTD_LIBRARY_RELEASE}")
+ endif()
+ if(ZSTD_LIBRARY_DEBUG)
+ set_target_properties(WrapZSTD::WrapZSTD PROPERTIES
+ IMPORTED_LOCATION_DEBUG "${ZSTD_LIBRARY_DEBUG}")
+ endif()
+ endif()
+
+ mark_as_advanced(ZSTD_INCLUDE_DIRS ZSTD_LIBRARIES ZSTD_LIBRARY_RELEASE ZSTD_LIBRARY_DEBUG)
+endif()
+include(FeatureSummary)
+set_package_properties(WrapZSTD PROPERTIES
+ URL "https://github.com/facebook/zstd"
+ DESCRIPTION "ZSTD compression library")
+
diff --git a/cmake/FindXKB_COMMON_X11.cmake b/cmake/FindXKB_COMMON_X11.cmake
index 330864c147..a00acb3cb0 100644
--- a/cmake/FindXKB_COMMON_X11.cmake
+++ b/cmake/FindXKB_COMMON_X11.cmake
@@ -1,6 +1,9 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
find_package(PkgConfig QUIET)
-pkg_check_modules(XKB_COMMON_X11 "xkbcommon-x11>=0.4.1" IMPORTED_TARGET)
+pkg_check_modules(XKB_COMMON_X11 IMPORTED_TARGET "xkbcommon-x11>=0.4.1")
if (NOT TARGET PkgConfig::XKB_COMMON_X11)
set(XKB_COMMON_X11_FOUND 0)
diff --git a/cmake/FindXRender.cmake b/cmake/FindXRender.cmake
index 98d84b28e6..6908cc45fb 100644
--- a/cmake/FindXRender.cmake
+++ b/cmake/FindXRender.cmake
@@ -1,7 +1,10 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
find_package(PkgConfig QUIET)
if(NOT TARGET PkgConfig::XRender)
- pkg_check_modules(XRender xrender IMPORTED_TARGET)
+ pkg_check_modules(XRender IMPORTED_TARGET "xrender")
if (NOT TARGET PkgConfig::XRender)
set(XRender_FOUND 0)
diff --git a/cmake/FindZSTD.cmake b/cmake/FindZSTD.cmake
deleted file mode 100644
index 57fe8d1c3a..0000000000
--- a/cmake/FindZSTD.cmake
+++ /dev/null
@@ -1,50 +0,0 @@
-#.rst:
-# FindZstd
-# ---------
-#
-# Try to locate the Zstd library.
-# If found, this will define the following variables:
-#
-# ``ZSTD_FOUND``
-# True if the zstd library is available
-# ``ZSTD_INCLUDE_DIRS``
-# The zstd include directories
-# ``ZSTD_LIBRARIES``
-# The zstd libraries for linking
-#
-# If ``ZSTD_FOUND`` is TRUE, it will also define the following
-# imported target:
-#
-# ``ZSTD::ZSTD``
-# The zstd library
-
-find_package(PkgConfig QUIET)
-pkg_check_modules(PC_ZSTD QUIET libzstd)
-
-find_path(ZSTD_INCLUDE_DIRS
- NAMES zstd.h
- HINTS ${PC_ZSTD_INCLUDEDIR}
- PATH_SUFFIXES zstd)
-
-find_library(ZSTD_LIBRARIES
- NAMES zstd zstd_static
- HINTS ${PC_ZSTD_LIBDIR}
-)
-
-include(FindPackageHandleStandardArgs)
-find_package_handle_standard_args(ZSTD DEFAULT_MSG ZSTD_LIBRARIES ZSTD_INCLUDE_DIRS)
-
-if(ZSTD_FOUND AND NOT TARGET ZSTD::ZSTD)
- add_library(ZSTD::ZSTD UNKNOWN IMPORTED)
- set_target_properties(ZSTD::ZSTD PROPERTIES
- IMPORTED_LOCATION "${ZSTD_LIBRARIES}"
- INTERFACE_INCLUDE_DIRECTORIES "${ZSTD_INCLUDE_DIRS}")
-endif()
-
-mark_as_advanced(ZSTD_INCLUDE_DIRS ZSTD_LIBRARIES)
-
-include(FeatureSummary)
-set_package_properties(ZSTD PROPERTIES
- URL "https://github.com/facebook/zstd"
- DESCRIPTION "ZSTD compression library")
-
diff --git a/cmake/Finddouble-conversion.cmake b/cmake/Finddouble-conversion.cmake
deleted file mode 100644
index 43d2076289..0000000000
--- a/cmake/Finddouble-conversion.cmake
+++ /dev/null
@@ -1,32 +0,0 @@
-# Fallback find module for double-conversion
-# if double-conversion is built with CMake it'll install a config module, which we prefer
-# if it's built with Scons (their default), we search ourselves
-
-find_package(double-conversion CONFIG)
-if (double-conversion_FOUND)
- if(TARGET double-conversion::double-conversion)
- return()
- endif()
-endif()
-
-find_path(DOUBLE_CONVERSION_INCLUDE_DIR
- NAMES
- double-conversion.h
- PATH_SUFFIXES
- double-conversion
-)
-find_library(DOUBLE_CONVERSION_LIBRARY NAMES double-conversion)
-
-include(FindPackageHandleStandardArgs)
-FIND_PACKAGE_HANDLE_STANDARD_ARGS(
- double-conversion DEFAULT_MSG
- DOUBLE_CONVERSION_LIBRARY DOUBLE_CONVERSION_INCLUDE_DIR)
-
-if(double-conversion_FOUND AND NOT TARGET double-conversion::double-conversion)
- add_library(double-conversion::double-conversion UNKNOWN IMPORTED)
- set_target_properties(double-conversion::double-conversion PROPERTIES
- IMPORTED_LOCATION "${DOUBLE_CONVERSION_LIBRARY}"
- INTERFACE_INCLUDE_DIRECTORIES "${DOUBLE_CONVERSION_INCLUDE_DIR}")
-endif()
-
-mark_as_advanced(DOUBLE_CONVERSION_INCLUDE_DIR DOUBLE_CONVERSION_LIBRARY)
diff --git a/cmake/ModuleDescription.json.in b/cmake/ModuleDescription.json.in
index e29f3f176d..93f9a5ed25 100644
--- a/cmake/ModuleDescription.json.in
+++ b/cmake/ModuleDescription.json.in
@@ -1,11 +1,13 @@
{
- "module_name": "${target}",
- "version": "${CMAKE_PROJECT_VERSION}",
- "built_with": {
+ "name": "${target}",
+ "repository": "${lower_case_project_name}",
+ "version": "${PROJECT_VERSION}",${extra_module_information}
+ "built_with": {${extra_build_information}
"compiler_id": "${CMAKE_CXX_COMPILER_ID}",
"compiler_target": "${CMAKE_CXX_COMPILER_TARGET}",
"compiler_version": "${CMAKE_CXX_COMPILER_VERSION}",
"cross_compiled": ${cross_compilation},
- "target_system": "${CMAKE_SYSTEM_NAME}"
+ "target_system": "${CMAKE_SYSTEM_NAME}",
+ "architecture": "${TEST_architecture_arch}"
}
}
diff --git a/cmake/PkgConfigLibrary.pc.in b/cmake/PkgConfigLibrary.pc.in
new file mode 100644
index 0000000000..9393cec0c5
--- /dev/null
+++ b/cmake/PkgConfigLibrary.pc.in
@@ -0,0 +1,14 @@
+prefix=@CMAKE_INSTALL_PREFIX@
+exec_prefix=${prefix}
+bindir=${prefix}/@INSTALL_BINDIR@
+libexecdir=${prefix}/@INSTALL_LIBEXECDIR@
+libdir=${prefix}/@INSTALL_LIBDIR@
+includedir=${prefix}/@INSTALL_INCLUDEDIR@
+$<$<BOOL:@contains_mkspecs@>:mkspecsdir=${prefix}/@INSTALL_MKSPECSDIR@>
+$<1: >
+Name: @pkgconfig_name@
+Description: @pkgconfig_description@
+Version: @PROJECT_VERSION@
+Libs: $<$<NOT:@is_interface_library@>:-L${libdir} -l@pkgconfig_file@> @link_options@
+Cflags: @include_dirs@ @compile_defs@
+Requires: $<JOIN:$<REMOVE_DUPLICATES:@target_requires@>, >
diff --git a/cmake/Qt3rdPartyLibraryConfig.cmake.in b/cmake/Qt3rdPartyLibraryConfig.cmake.in
index 0facce906f..869c67443f 100644
--- a/cmake/Qt3rdPartyLibraryConfig.cmake.in
+++ b/cmake/Qt3rdPartyLibraryConfig.cmake.in
@@ -1,5 +1,10 @@
+# Copyright (C) 2024 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
@PACKAGE_INIT@
+cmake_minimum_required(VERSION @min_new_policy_version@...@max_new_policy_version@)
+
include(CMakeFindDependencyMacro)
get_filename_component(_import_prefix "${CMAKE_CURRENT_LIST_FILE}" PATH)
@@ -16,8 +21,13 @@ endif()
if (NOT QT_NO_CREATE_TARGETS)
include("${CMAKE_CURRENT_LIST_DIR}/@INSTALL_CMAKE_NAMESPACE@@target@Targets.cmake")
+ include("${CMAKE_CURRENT_LIST_DIR}/@INSTALL_CMAKE_NAMESPACE@@target@AdditionalTargetInfo.cmake")
if(NOT QT_NO_CREATE_VERSIONLESS_TARGETS)
- include("${CMAKE_CURRENT_LIST_DIR}/@INSTALL_CMAKE_NAMESPACE@@target@VersionlessTargets.cmake")
+ if(CMAKE_VERSION VERSION_LESS 3.18 OR QT_USE_OLD_VERSION_LESS_TARGETS)
+ include("${CMAKE_CURRENT_LIST_DIR}/@INSTALL_CMAKE_NAMESPACE@@target@VersionlessTargets.cmake")
+ else()
+ include("${CMAKE_CURRENT_LIST_DIR}/@INSTALL_CMAKE_NAMESPACE@@target@VersionlessAliasTargets.cmake")
+ endif()
endif()
endif()
diff --git a/cmake/Qt3rdPartyLibraryHelpers.cmake b/cmake/Qt3rdPartyLibraryHelpers.cmake
new file mode 100644
index 0000000000..924db182be
--- /dev/null
+++ b/cmake/Qt3rdPartyLibraryHelpers.cmake
@@ -0,0 +1,386 @@
+macro(qt_internal_get_add_library_option_args option_args)
+ set(${option_args}
+ SHARED
+ STATIC
+ MODULE
+ INTERFACE
+ NO_UNITY_BUILD
+ )
+endmacro()
+
+# Helper to create a library using the public _qt_internal_add_library function.
+#
+# The difference to _qt_internal_add_library is that MODULE is replaced with STATIC in a static
+# Qt build.
+# Everything else is just prepation for option validating.
+function(qt_internal_add_common_qt_library_helper target)
+ qt_internal_get_add_library_option_args(option_args)
+ cmake_parse_arguments(PARSE_ARGV 1 arg
+ "${option_args}"
+ ""
+ ""
+ )
+ _qt_internal_validate_all_args_are_parsed(arg)
+
+ if(arg_SHARED)
+ set(arg_SHARED SHARED)
+ else()
+ set(arg_SHARED "")
+ endif()
+
+ if(arg_MODULE)
+ set(arg_MODULE MODULE)
+ else()
+ set(arg_MODULE "")
+ endif()
+
+ if(arg_STATIC)
+ set(arg_STATIC STATIC)
+ else()
+ set(arg_STATIC "")
+ endif()
+
+ if(arg_INTERFACE)
+ set(arg_INTERFACE INTERFACE)
+ else()
+ set(arg_INTERFACE "")
+ endif()
+
+ if(arg_MODULE AND NOT BUILD_SHARED_LIBS)
+ set(arg_MODULE STATIC)
+ endif()
+
+ _qt_internal_add_library(${target} ${arg_STATIC} ${arg_SHARED} ${arg_MODULE} ${arg_INTERFACE})
+
+ if(arg_NO_UNITY_BUILD)
+ set_property(TARGET "${target}" PROPERTY UNITY_BUILD OFF)
+ endif()
+
+ qt_internal_mark_as_internal_library(${target})
+endfunction()
+
+# Wrapper function to create a regular cmake target and forward all the
+# arguments collected by the conversion script.
+function(qt_internal_add_cmake_library target)
+ qt_internal_get_add_library_option_args(option_args)
+ set(single_args
+ OUTPUT_DIRECTORY
+ ARCHIVE_INSTALL_DIRECTORY
+ INSTALL_DIRECTORY
+ )
+ set(multi_args
+ ${__default_private_args}
+ ${__default_public_args}
+ )
+
+ cmake_parse_arguments(PARSE_ARGV 1 arg
+ "${option_args}"
+ "${single_args}"
+ "${multi_args}"
+ )
+ _qt_internal_validate_all_args_are_parsed(arg)
+ _qt_internal_validate_no_unity_build(arg)
+
+ qt_remove_args(library_helper_args
+ ARGS_TO_REMOVE
+ ${single_args}
+ ${multi_args}
+ ALL_ARGS
+ ${option_args}
+ ${single_args}
+ ${multi_args}
+ ARGS
+ ${ARGN}
+ )
+
+ qt_internal_add_common_qt_library_helper(${target} ${library_helper_args})
+
+ qt_skip_warnings_are_errors_when_repo_unclean("${target}")
+
+ if (arg_OUTPUT_DIRECTORY)
+ set_target_properties(${target} PROPERTIES
+ ARCHIVE_OUTPUT_DIRECTORY ${arg_OUTPUT_DIRECTORY}
+ RUNTIME_OUTPUT_DIRECTORY ${arg_OUTPUT_DIRECTORY}
+ LIBRARY_OUTPUT_DIRECTORY ${arg_OUTPUT_DIRECTORY}
+ )
+ endif()
+
+ qt_internal_extend_target("${target}"
+ SOURCES ${arg_SOURCES}
+ INCLUDE_DIRECTORIES
+ ${arg_INCLUDE_DIRECTORIES}
+ SYSTEM_INCLUDE_DIRECTORIES
+ ${arg_SYSTEM_INCLUDE_DIRECTORIES}
+ PUBLIC_INCLUDE_DIRECTORIES
+ ${arg_PUBLIC_INCLUDE_DIRECTORIES}
+ PUBLIC_DEFINES
+ ${arg_PUBLIC_DEFINES}
+ DEFINES
+ ${arg_DEFINES}
+ PUBLIC_LIBRARIES ${arg_PUBLIC_LIBRARIES}
+ LIBRARIES ${arg_LIBRARIES} Qt::PlatformCommonInternal
+ COMPILE_OPTIONS ${arg_COMPILE_OPTIONS}
+ PUBLIC_COMPILE_OPTIONS ${arg_PUBLIC_COMPILE_OPTIONS}
+ LINK_OPTIONS ${arg_LINK_OPTIONS}
+ PUBLIC_LINK_OPTIONS ${arg_PUBLIC_LINK_OPTIONS}
+ MOC_OPTIONS ${arg_MOC_OPTIONS}
+ ENABLE_AUTOGEN_TOOLS ${arg_ENABLE_AUTOGEN_TOOLS}
+ DISABLE_AUTOGEN_TOOLS ${arg_DISABLE_AUTOGEN_TOOLS}
+ NO_UNITY_BUILD # Disabled by default
+ )
+endfunction()
+
+# This function replaces qmake's qt_helper_lib feature. It is intended to
+# compile 3rdparty libraries as part of the build.
+#
+function(qt_internal_add_3rdparty_library target)
+ qt_internal_get_add_library_option_args(library_option_args)
+ set(option_args
+ EXCEPTIONS
+ INSTALL
+ SKIP_AUTOMOC
+ )
+ set(single_args
+ OUTPUT_DIRECTORY
+ QMAKE_LIB_NAME
+ )
+ set(multi_args
+ ${__default_private_args}
+ ${__default_public_args}
+ )
+
+ cmake_parse_arguments(PARSE_ARGV 1 arg
+ "${library_option_args};${option_args}"
+ "${single_args}"
+ "${multi_args}"
+ )
+ _qt_internal_validate_all_args_are_parsed(arg)
+ _qt_internal_validate_no_unity_build(arg)
+
+ qt_remove_args(library_helper_args
+ ARGS_TO_REMOVE
+ ${option_args}
+ ${single_args}
+ ${multi_args}
+ ALL_ARGS
+ ${library_option_args}
+ ${option_args}
+ ${single_args}
+ ${multi_args}
+ ARGS
+ ${ARGN}
+ )
+
+ qt_internal_add_common_qt_library_helper(${target} ${library_helper_args})
+
+ set_target_properties(${target} PROPERTIES
+ _qt_module_interface_name "${target}"
+ _qt_package_version "${PROJECT_VERSION}"
+ _qt_package_name "${INSTALL_CMAKE_NAMESPACE}${target}"
+ _qt_module_is_3rdparty_library TRUE
+ )
+
+ set(export_properties
+ "_qt_module_interface_name"
+ "_qt_package_version"
+ "_qt_package_name"
+ "_qt_module_is_3rdparty_library"
+ )
+
+ set_property(TARGET ${target}
+ APPEND PROPERTY
+ EXPORT_PROPERTIES "${export_properties}")
+
+ qt_internal_add_qt_repo_known_module(${target})
+ qt_internal_add_target_aliases(${target})
+ _qt_internal_apply_strict_cpp(${target})
+
+ qt_skip_warnings_are_errors_when_repo_unclean("${target}")
+
+ set_target_properties(${target} PROPERTIES
+ LIBRARY_OUTPUT_DIRECTORY "${QT_BUILD_DIR}/${INSTALL_LIBDIR}"
+ RUNTIME_OUTPUT_DIRECTORY "${QT_BUILD_DIR}/${INSTALL_BINDIR}"
+ ARCHIVE_OUTPUT_DIRECTORY "${QT_BUILD_DIR}/${INSTALL_LIBDIR}"
+ VERSION ${PROJECT_VERSION}
+ SOVERSION ${PROJECT_VERSION_MAJOR}
+ _qt_module_skip_depends_include TRUE
+ )
+ set_property(TARGET "${target}"
+ APPEND PROPERTY EXPORT_PROPERTIES _qt_module_is_3rdparty_library)
+ set_property(TARGET "${target}"
+ APPEND PROPERTY EXPORT_PROPERTIES _qt_module_skip_depends_include)
+
+ qt_handle_multi_config_output_dirs("${target}")
+
+ set_target_properties(${target} PROPERTIES
+ OUTPUT_NAME "${INSTALL_CMAKE_NAMESPACE}${target}"
+ )
+
+ if(NOT arg_INTERFACE)
+ qt_set_common_target_properties(${target})
+ endif()
+
+ if(NOT arg_SKIP_AUTOMOC)
+ qt_autogen_tools_initial_setup(${target})
+ endif()
+
+ if(NOT arg_EXCEPTIONS AND NOT arg_INTERFACE)
+ qt_internal_set_exceptions_flags("${target}" FALSE)
+ elseif(arg_EXCEPTIONS)
+ qt_internal_set_exceptions_flags("${target}" TRUE)
+ endif()
+
+ qt_internal_extend_target("${target}"
+ SOURCES ${arg_SOURCES}
+ INCLUDE_DIRECTORIES
+ ${arg_INCLUDE_DIRECTORIES}
+ PUBLIC_INCLUDE_DIRECTORIES
+ ${arg_PUBLIC_INCLUDE_DIRECTORIES}
+ PUBLIC_DEFINES
+ ${arg_PUBLIC_DEFINES}
+ DEFINES
+ ${arg_DEFINES}
+ PUBLIC_LIBRARIES ${arg_PUBLIC_LIBRARIES}
+ LIBRARIES ${arg_LIBRARIES} Qt::PlatformModuleInternal
+ COMPILE_OPTIONS ${arg_COMPILE_OPTIONS}
+ PUBLIC_COMPILE_OPTIONS ${arg_PUBLIC_COMPILE_OPTIONS}
+ LINK_OPTIONS ${arg_LINK_OPTIONS}
+ PUBLIC_LINK_OPTIONS ${arg_PUBLIC_LINK_OPTIONS}
+ MOC_OPTIONS ${arg_MOC_OPTIONS}
+ ENABLE_AUTOGEN_TOOLS ${arg_ENABLE_AUTOGEN_TOOLS}
+ DISABLE_AUTOGEN_TOOLS ${arg_DISABLE_AUTOGEN_TOOLS}
+ NO_UNITY_BUILD
+ )
+
+ if(NOT BUILD_SHARED_LIBS OR arg_INSTALL)
+ qt_generate_3rdparty_lib_pri_file("${target}" "${arg_QMAKE_LIB_NAME}" pri_file)
+ if(pri_file)
+ qt_install(FILES "${pri_file}" DESTINATION "${INSTALL_MKSPECSDIR}/modules")
+ endif()
+
+ set(path_suffix "${INSTALL_CMAKE_NAMESPACE}${target}")
+ qt_path_join(config_build_dir ${QT_CONFIG_BUILD_DIR} ${path_suffix})
+ qt_path_join(config_install_dir ${QT_CONFIG_INSTALL_DIR} ${path_suffix})
+ set(export_name "${INSTALL_CMAKE_NAMESPACE}${target}Targets")
+
+ qt_internal_get_min_new_policy_cmake_version(min_new_policy_version)
+ qt_internal_get_max_new_policy_cmake_version(max_new_policy_version)
+ configure_package_config_file(
+ "${QT_CMAKE_DIR}/Qt3rdPartyLibraryConfig.cmake.in"
+ "${config_build_dir}/${INSTALL_CMAKE_NAMESPACE}${target}Config.cmake"
+ INSTALL_DESTINATION "${config_install_dir}"
+ )
+
+ write_basic_package_version_file(
+ "${config_build_dir}/${INSTALL_CMAKE_NAMESPACE}${target}ConfigVersionImpl.cmake"
+ VERSION ${PROJECT_VERSION}
+ COMPATIBILITY AnyNewerVersion
+ )
+ qt_internal_write_qt_package_version_file(
+ "${INSTALL_CMAKE_NAMESPACE}${target}"
+ "${config_build_dir}/${INSTALL_CMAKE_NAMESPACE}${target}ConfigVersion.cmake"
+ )
+
+ qt_install(FILES
+ "${config_build_dir}/${INSTALL_CMAKE_NAMESPACE}${target}Config.cmake"
+ "${config_build_dir}/${INSTALL_CMAKE_NAMESPACE}${target}ConfigVersion.cmake"
+ "${config_build_dir}/${INSTALL_CMAKE_NAMESPACE}${target}ConfigVersionImpl.cmake"
+ DESTINATION "${config_install_dir}"
+ COMPONENT Devel
+ )
+
+ qt_install(TARGETS ${target}
+ EXPORT "${export_name}"
+ RUNTIME DESTINATION ${INSTALL_BINDIR}
+ LIBRARY DESTINATION ${INSTALL_LIBDIR}
+ ARCHIVE DESTINATION ${INSTALL_LIBDIR}
+ )
+
+ qt_install(EXPORT ${export_name}
+ NAMESPACE "${QT_CMAKE_EXPORT_NAMESPACE}::"
+ DESTINATION "${config_install_dir}"
+ )
+
+ qt_internal_export_additional_targets_file(
+ TARGETS ${target}
+ EXPORT_NAME_PREFIX ${INSTALL_CMAKE_NAMESPACE}${target}
+ CONFIG_INSTALL_DIR "${config_install_dir}"
+ )
+
+ qt_internal_export_modern_cmake_config_targets_file(
+ TARGETS ${target}
+ EXPORT_NAME_PREFIX ${INSTALL_CMAKE_NAMESPACE}${target}
+ CONFIG_BUILD_DIR "${config_build_dir}"
+ CONFIG_INSTALL_DIR "${config_install_dir}"
+ )
+
+ set(debug_install_dir "${INSTALL_LIBDIR}")
+ if (MINGW)
+ set(debug_install_dir "${INSTALL_BINDIR}")
+ endif()
+ qt_enable_separate_debug_info(${target} "${debug_install_dir}")
+ qt_internal_install_pdb_files(${target} "${INSTALL_LIBDIR}")
+ endif()
+
+ if(BUILD_SHARED_LIBS AND MSVC)
+ set_target_properties(${target} PROPERTIES
+ INTERPROCEDURAL_OPTIMIZATION OFF
+ )
+ endif()
+endfunction()
+
+function(qt_install_3rdparty_library_wrap_config_extra_file target)
+ if(TARGET "${target}")
+ set(use_bundled "ON")
+ else()
+ set(use_bundled "OFF")
+ endif()
+
+ set(QT_USE_BUNDLED_${target} "${use_bundled}" CACHE INTERNAL "")
+ set(extra_cmake_code "set(QT_USE_BUNDLED_${target} ${use_bundled} CACHE INTERNAL \"\")")
+ configure_file(
+ "${QT_CMAKE_DIR}/QtFindWrapConfigExtra.cmake.in"
+ "${QT_CONFIG_BUILD_DIR}/${INSTALL_CMAKE_NAMESPACE}/FindWrap${target}ConfigExtra.cmake"
+ @ONLY
+ )
+
+ qt_install(FILES
+ "${QT_CONFIG_BUILD_DIR}/${INSTALL_CMAKE_NAMESPACE}/FindWrap${target}ConfigExtra.cmake"
+ DESTINATION "${QT_CONFIG_INSTALL_DIR}/${INSTALL_CMAKE_NAMESPACE}"
+ COMPONENT Devel
+ )
+endfunction()
+
+# This function implements qmake's qt_helper_lib MODULE_EXT_HEADERS and MODULE_EXT_HEADERS_DIR features.
+# It creates a header-only module exposing a subset or all headers of a 3rd-party library.
+function(qt_internal_add_3rdparty_header_module target)
+ set(single_args
+ EXTERNAL_HEADERS_DIR
+ )
+ set(multi_args
+ EXTERNAL_HEADERS
+ )
+ cmake_parse_arguments(PARSE_ARGV 1 arg
+ "${option_args}"
+ "${single_args}"
+ "${multi_args}"
+ )
+ _qt_internal_validate_all_args_are_parsed(arg)
+
+ qt_internal_add_module(${target}
+ INTERNAL_MODULE
+ HEADER_MODULE
+ NO_CONFIG_HEADER_FILE
+ EXTERNAL_HEADERS ${arg_EXTERNAL_HEADERS}
+ EXTERNAL_HEADERS_DIR ${arg_EXTERNAL_HEADERS_DIR}
+ )
+
+ set_target_properties(${target} PROPERTIES
+ _qt_module_is_3rdparty_header_library TRUE
+ _qt_module_skip_depends_include TRUE
+ )
+ set_property(TARGET "${target}"
+ APPEND PROPERTY EXPORT_PROPERTIES _qt_module_is_3rdparty_header_library)
+ set_property(TARGET "${target}"
+ APPEND PROPERTY EXPORT_PROPERTIES _qt_module_skip_depends_include)
+endfunction()
diff --git a/cmake/QtAndroidHelpers.cmake b/cmake/QtAndroidHelpers.cmake
new file mode 100644
index 0000000000..0743fe41a9
--- /dev/null
+++ b/cmake/QtAndroidHelpers.cmake
@@ -0,0 +1,280 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+#
+# Android specific functions/macros/properties required for building Qt Modules
+#
+
+macro(qt_internal_setup_android_target_properties)
+ define_property(TARGET
+ PROPERTY
+ QT_ANDROID_MODULE_INSTALL_DIR
+ BRIEF_DOCS
+ "Recorded install location for a Qt Module."
+ FULL_DOCS
+ "Recorded install location for a Qt Module. Used by qt_internal_android_dependencies()."
+ )
+
+ define_property(TARGET
+ PROPERTY
+ QT_ANDROID_JAR_DEPENDENCIES
+ BRIEF_DOCS
+ "Qt Module Jar dependencies list."
+ FULL_DOCS
+ "Qt Module Jar dependencies list."
+ )
+
+ define_property(TARGET
+ PROPERTY
+ QT_ANDROID_BUNDLED_JAR_DEPENDENCIES
+ BRIEF_DOCS
+ "Qt Module Jars that should be bundled with it during packing."
+ FULL_DOCS
+ "Qt Module Jars that should be bundled with it during packing."
+ )
+
+ define_property(TARGET
+ PROPERTY
+ QT_ANDROID_LIB_DEPENDENCIES
+ BRIEF_DOCS
+ "Qt Module C++ libraries that should be bundled with it during packing."
+ FULL_DOCS
+ "Qt Module C++ libraries that should be bundled with it during packing."
+ )
+
+ define_property(TARGET
+ PROPERTY
+ QT_ANDROID_LIB_DEPENDENCY_REPLACEMENTS
+ BRIEF_DOCS
+ "Qt Module C++ libraries that can replace libraries declared with the QT_ANDROID_LIB_DEPENDENCIES property."
+ FULL_DOCS
+ "Qt Module C++ libraries that can replace libraries declared with the QT_ANDROID_LIB_DEPENDENCIES property."
+ )
+
+ define_property(TARGET
+ PROPERTY
+ QT_ANDROID_BUNDLED_FILES
+ BRIEF_DOCS
+ "Qt Module files that need to be bundled during packing."
+ FULL_DOCS
+ "Qt Module files that need to be bundled during packing."
+ )
+
+ define_property(TARGET
+ PROPERTY
+ QT_ANDROID_PERMISSIONS
+ BRIEF_DOCS
+ "Qt Module android permission list."
+ FULL_DOCS
+ "Qt Module android permission list."
+ )
+
+ define_property(TARGET
+ PROPERTY
+ QT_ANDROID_FEATURES
+ BRIEF_DOCS
+ "Qt Module android feature list."
+ FULL_DOCS
+ "Qt Module android feature list."
+ )
+
+ define_property(TARGET
+ PROPERTY
+ QT_ANDROID_ABIS
+ BRIEF_DOCS
+ "List of ABIs that the target packages are built with."
+ FULL_DOCS
+ "List of ABIs that the target packages are built with."
+ )
+endmacro()
+
+function(qt_internal_android_dependencies_content target file_content_out)
+ get_target_property(arg_JAR_DEPENDENCIES ${target} QT_ANDROID_JAR_DEPENDENCIES)
+ get_target_property(arg_BUNDLED_JAR_DEPENDENCIES ${target} QT_ANDROID_BUNDLED_JAR_DEPENDENCIES)
+ get_target_property(arg_LIB_DEPENDENCIES ${target} QT_ANDROID_LIB_DEPENDENCIES)
+ get_target_property(arg_LIB_DEPENDENCY_REPLACEMENTS ${target} QT_ANDROID_LIB_DEPENDENCY_REPLACEMENTS)
+ get_target_property(arg_BUNDLED_FILES ${target} QT_ANDROID_BUNDLED_FILES)
+ get_target_property(arg_PERMISSIONS ${target} QT_ANDROID_PERMISSIONS)
+ get_target_property(arg_FEATURES ${target} QT_ANDROID_FEATURES)
+
+ if ((NOT arg_JAR_DEPENDENCIES)
+ AND (NOT arg_BUNDLED_JAR_DEPENDENCIES)
+ AND (NOT arg_LIB_DEPENDENCIES)
+ AND (NOT arg_LIB_DEPENDENCY_REPLACEMENTS)
+ AND (NOT arg_BUNDLED_FILES)
+ AND (NOT arg_PERMISSIONS)
+ AND (NOT arg_FEATURES))
+ # None of the values were set, so there's nothing to do
+ return()
+ endif()
+
+ # mimic qmake's section and string splitting from
+ # mkspecs/feature/qt_android_deps.prf
+ macro(section string delimiter first second)
+ string(FIND ${string} ${delimiter} delimiter_location)
+ if (NOT ${delimiter_location} EQUAL -1)
+ string(SUBSTRING ${string} 0 ${delimiter_location} ${first})
+ math(EXPR delimiter_location "${delimiter_location} + 1")
+ string(SUBSTRING ${string} ${delimiter_location} -1 ${second})
+ else()
+ set(${first} ${string})
+ set(${second} "")
+ endif()
+ endmacro()
+
+ set(file_contents "")
+
+ # Jar Dependencies
+ if(arg_JAR_DEPENDENCIES)
+ foreach(jar_dependency IN LISTS arg_JAR_DEPENDENCIES)
+ section(${jar_dependency} ":" jar_file init_class)
+ if (init_class)
+ set(init_class "initClass=\"${init_class}\"")
+ endif()
+ # Use unix path to allow using files on any host platform.
+ file(TO_CMAKE_PATH ${jar_file} jar_file_unix_path)
+ string(APPEND file_contents "<jar file=\"${jar_file_unix_path}\" ${init_class} />\n")
+ endforeach()
+ endif()
+
+ # Bundled Jar Dependencies
+ if(arg_BUNDLED_JAR_DEPENDENCIES)
+ foreach(jar_bundle IN LISTS arg_BUNDLED_JAR_DEPENDENCIES)
+ section(${jar_bundle} ":" bundle_file init_class)
+ if (init_class)
+ set(init_class "initClass=\"${init_class}\"")
+ endif()
+ # Use unix path to allow using files on any host platform.
+ file(TO_CMAKE_PATH ${bundle_file} jar_bundle_unix_path)
+ string(APPEND file_contents
+ "<jar bundling=\"1\" file=\"${jar_bundle_unix_path}\" ${init_class} />\n")
+ endforeach()
+ endif()
+
+ # Lib Dependencies
+ if(arg_LIB_DEPENDENCIES)
+ foreach(lib IN LISTS arg_LIB_DEPENDENCIES)
+ string(REPLACE ".so" "_${CMAKE_ANDROID_ARCH_ABI}.so" lib ${lib})
+ section(${lib} ":" lib_file lib_extends)
+ if (lib_extends)
+ set(lib_extends "extends=\"${lib_extends}\"")
+ endif()
+ # Use unix path to allow using files on any host platform.
+ file(TO_CMAKE_PATH ${lib_file} lib_file_unix_path)
+ string(APPEND file_contents "<lib file=\"${lib_file_unix_path}\" ${lib_extends} />\n")
+ endforeach()
+ endif()
+
+ # Lib Dependencies Replacements
+ if(arg_LIB_DEPENDENCY_REPLACEMENTS)
+ foreach(lib IN LISTS arg_LIB_DEPENDENCY_REPLACEMENTS)
+ string(REPLACE ".so" "_${CMAKE_ANDROID_ARCH_ABI}.so" lib ${lib})
+ section(${lib} ":" lib_file lib_replacement)
+ if (lib_replacement)
+ # Use unix path to allow using files on any host platform.
+ file(TO_CMAKE_PATH ${lib_replacement} lib_replacement_unix_path)
+ set(lib_replacement "replaces=\"${lib_replacement_unix_path}\"")
+ endif()
+ # Use unix path to allow using files on any host platform.
+ file(TO_CMAKE_PATH ${lib_file} lib_file_unix_path)
+ string(APPEND file_contents
+ "<lib file=\"${lib_file_unix_path}\" ${lib_replacement} />\n")
+ endforeach()
+ endif()
+
+ # Bundled files
+ if(arg_BUNDLED_FILES)
+ foreach(bundled_file IN LISTS arg_BUNDLED_FILES)
+ # Use unix path to allow using files on any host platform.
+ file(TO_CMAKE_PATH ${bundled_file} file_unix_path)
+ string(APPEND file_contents "<bundled file=\"${file_unix_path}\" />\n")
+ endforeach()
+ endif()
+
+ # Android Permissions
+ if(arg_PERMISSIONS)
+ foreach(permission IN LISTS arg_PERMISSIONS)
+ string(APPEND file_contents "<permission name=\"${permission}\" />\n")
+ endforeach()
+ endif()
+
+ # Android Features
+ if(arg_FEATURES)
+ foreach(feature IN LISTS arg_FEATURES)
+ string(APPEND file_contents "<feature name=\"${feature}\" />\n")
+ endforeach()
+ endif()
+
+ set(${file_content_out} ${file_contents} PARENT_SCOPE)
+endfunction()
+
+# Generate Qt Module -android-dependencies.xml required by the
+# androiddeploytoolqt to successfully copy all the plugins and other dependent
+# items into the APK
+function(qt_internal_android_dependencies target)
+ get_target_property(target_type "${target}" TYPE)
+ if(target_type STREQUAL "INTERFACE_LIBRARY")
+ return()
+ endif()
+
+ # Get plugins for the current module
+ get_target_property(module_plugin_types ${target} MODULE_PLUGIN_TYPES)
+
+ # Get depends for the current module
+ qt_internal_android_dependencies_content(${target} file_contents)
+
+ # Get plugins from the module's plugin types and get their dependencies
+ foreach(plugin ${QT_KNOWN_PLUGINS})
+ get_target_property(iter_known_plugin_type ${plugin} QT_PLUGIN_TYPE)
+ foreach(plugin_type ${module_plugin_types})
+ if (plugin_type STREQUAL iter_known_plugin_type)
+ qt_internal_android_dependencies_content(${plugin} plugin_file_contents)
+ string(APPEND file_contents ${plugin_file_contents})
+ endif()
+ endforeach()
+ endforeach()
+
+ if ((NOT module_plugin_types)
+ AND (NOT file_contents))
+ # None of the values were set, so there's nothing to do
+ return()
+ endif()
+
+ get_target_property(target_output_name ${target} OUTPUT_NAME)
+ if (NOT target_output_name)
+ set(target_name ${target})
+ else()
+ set(target_name ${target_output_name})
+ endif()
+
+ string(PREPEND file_contents "<lib name=\"${target_name}_${CMAKE_ANDROID_ARCH_ABI}\"><depends>\n")
+ string(PREPEND file_contents "<rules><dependencies>\n")
+
+ # Module plugins
+ if(module_plugin_types)
+ foreach(plugin IN LISTS module_plugin_types)
+ string(APPEND file_contents
+ "<bundled file=\"${INSTALL_PLUGINSDIR}/${plugin}\" type=\"plugin_dir\"/>\n")
+ endforeach()
+ endif()
+
+ string(APPEND file_contents "</depends></lib>\n")
+ string(APPEND file_contents "</dependencies></rules>")
+
+ qt_path_join(dependency_file "${QT_BUILD_DIR}" "${INSTALL_LIBDIR}" "${target_name}_${CMAKE_ANDROID_ARCH_ABI}-android-dependencies.xml")
+ file(WRITE ${dependency_file} ${file_contents})
+
+ get_target_property(target_install_dir ${target} QT_ANDROID_MODULE_INSTALL_DIR)
+ if (NOT target_install_dir)
+ message(SEND_ERROR "qt_internal_android_dependencies: Target ${target} is either not a Qt Module or has no recorded install location")
+ return()
+ endif()
+
+ # Copy file into install directory, required by the androiddeployqt tool.
+ qt_install(FILES
+ ${dependency_file}
+ DESTINATION
+ ${target_install_dir}
+ COMPONENT
+ Devel)
+endfunction()
diff --git a/cmake/QtApp.cmake b/cmake/QtApp.cmake
deleted file mode 100644
index c54bb3e940..0000000000
--- a/cmake/QtApp.cmake
+++ /dev/null
@@ -1,92 +0,0 @@
-# This function creates a CMake target for a Qt internal app.
-# Such projects had a load(qt_app) command.
-function(qt_internal_add_app target)
- qt_parse_all_arguments(arg
- "qt_internal_add_app"
- "NO_INSTALL"
- "${__default_target_info_args}"
- "${__default_private_args}"
- ${ARGN})
-
- set(output_directory "${QT_BUILD_DIR}/${INSTALL_BINDIR}")
-
- set(no_install "")
- if(arg_NO_INSTALL)
- set(no_install NO_INSTALL)
- endif()
-
- qt_add_executable("${target}"
- DELAY_RC
- DELAY_TARGET_INFO
- OUTPUT_DIRECTORY "${output_directory}"
- ${no_install}
- SOURCES ${arg_SOURCES}
- INCLUDE_DIRECTORIES
- ${arg_INCLUDE_DIRECTORIES}
- DEFINES
- ${arg_DEFINES}
- LIBRARIES ${arg_LIBRARIES} Qt::PlatformAppInternal
- COMPILE_OPTIONS ${arg_COMPILE_OPTIONS}
- LINK_OPTIONS ${arg_LINK_OPTIONS}
- MOC_OPTIONS ${arg_MOC_OPTIONS}
- ENABLE_AUTOGEN_TOOLS ${arg_ENABLE_AUTOGEN_TOOLS}
- DISABLE_AUTOGEN_TOOLS ${arg_DISABLE_AUTOGEN_TOOLS}
- TARGET_VERSION "${arg_TARGET_VERSION}"
- TARGET_PRODUCT "${arg_TARGET_PRODUCT}"
- TARGET_DESCRIPTION "${arg_TARGET_DESCRIPTION}"
- TARGET_COMPANY "${arg_TARGET_COMPANY}"
- TARGET_COPYRIGHT "${arg_TARGET_COPYRIGHT}"
- )
- qt_internal_add_target_aliases("${target}")
-
- # To mimic the default behaviors of qt_app.prf, we by default enable GUI Windows applications,
- # but don't enable macOS bundles.
- # Bundles are enabled in a separate set_target_properties call if an Info.plist file
- # is provided.
- # Similary, the Windows GUI flag is disabled in a separate call
- # if CONFIG += console was encountered during conversion.
- set_target_properties("${target}" PROPERTIES WIN32_EXECUTABLE TRUE)
-
- qt_add_list_file_finalizer(qt_internal_finalize_app ${target})
-endfunction()
-
-function(qt_internal_get_title_case value out_var)
- if(NOT value)
- set(${out_var} "" PARENT_SCOPE)
- return()
- endif()
- string(SUBSTRING "${value}" 0 1 first_char)
- string(TOUPPER "${first_char}" first_char_upper)
- string(SUBSTRING "${target}" 1 -1 rest_of_value)
- set(title_value "${first_char_upper}${rest_of_value}")
- set(${out_var} "${title_value}" PARENT_SCOPE)
-endfunction()
-
-function(qt_internal_update_app_target_info_properties target)
- # First update the delayed properties with any values that might have been set after the
- # qt_internal_add_app() call.
- qt_internal_update_delayed_target_info_properties(${target})
-
- # Set defaults in case if no values were set.
- get_target_property(target_version ${target} QT_DELAYED_TARGET_VERSION)
- if(NOT target_version)
- set_target_properties(${target} PROPERTIES QT_DELAYED_TARGET_VERSION "${PROJECT_VERSION}")
- endif()
-
- get_target_property(target_description ${target} QT_DELAYED_TARGET_DESCRIPTION)
- if(NOT target_description)
- qt_internal_get_title_case("${target}" upper_name)
- set_target_properties(${target} PROPERTIES QT_DELAYED_TARGET_DESCRIPTION "Qt ${upper_name}")
- endif()
-
- # Finally set the final values.
- qt_internal_set_target_info_properties_from_delayed_properties("${target}")
-endfunction()
-
-function(qt_internal_finalize_app target)
- qt_internal_update_app_target_info_properties("${target}")
-
- if(WIN32)
- qt6_generate_win32_rc_file("${target}")
- endif()
-endfunction()
diff --git a/cmake/QtAppHelpers.cmake b/cmake/QtAppHelpers.cmake
new file mode 100644
index 0000000000..c0ad53ab9e
--- /dev/null
+++ b/cmake/QtAppHelpers.cmake
@@ -0,0 +1,148 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+# This function creates a CMake target for a Qt internal app.
+# Such projects had a load(qt_app) command.
+function(qt_internal_add_app target)
+ cmake_parse_arguments(PARSE_ARGV 1 arg
+ "NO_INSTALL;INSTALL_VERSIONED_LINK;EXCEPTIONS;NO_UNITY_BUILD"
+ "${__default_target_info_args};INSTALL_DIR"
+ "${__default_private_args};PUBLIC_LIBRARIES"
+ )
+ _qt_internal_validate_all_args_are_parsed(arg)
+
+ set(exceptions "")
+ if(arg_EXCEPTIONS)
+ set(exceptions EXCEPTIONS)
+ endif()
+
+ if(DEFINED arg_INSTALL_DIR)
+ set(forward_install_dir INSTALL_DIRECTORY ${arg_INSTALL_DIR})
+ else()
+ set(forward_install_dir "")
+ set(arg_INSTALL_DIR ${INSTALL_BINDIR})
+ endif()
+ set(output_directory "${QT_BUILD_DIR}/${arg_INSTALL_DIR}")
+
+ set(no_install "")
+ if(arg_NO_INSTALL)
+ set(no_install NO_INSTALL)
+ endif()
+
+ if(arg_PUBLIC_LIBRARIES)
+ message(WARNING
+ "qt_internal_add_app's PUBLIC_LIBRARIES option is deprecated, and will be removed in "
+ "a future Qt version. Use the LIBRARIES option instead.")
+ endif()
+
+ qt_internal_library_deprecation_level(deprecation_define)
+
+ if(arg_NO_UNITY_BUILD)
+ set(arg_NO_UNITY_BUILD "NO_UNITY_BUILD")
+ else()
+ set(arg_NO_UNITY_BUILD "")
+ endif()
+
+ qt_internal_add_executable("${target}"
+ QT_APP
+ DELAY_RC
+ DELAY_TARGET_INFO
+ OUTPUT_DIRECTORY "${output_directory}"
+ ${exceptions}
+ ${no_install}
+ ${arg_NO_UNITY_BUILD}
+ ${forward_install_dir}
+ SOURCES ${arg_SOURCES}
+ NO_PCH_SOURCES ${arg_NO_PCH_SOURCES}
+ NO_UNITY_BUILD_SOURCES ${arg_NO_UNITY_BUILD_SOURCES}
+ INCLUDE_DIRECTORIES
+ ${arg_INCLUDE_DIRECTORIES}
+ DEFINES
+ ${arg_DEFINES}
+ ${deprecation_define}
+ LIBRARIES
+ ${arg_LIBRARIES}
+ ${arg_PUBLIC_LIBRARIES}
+ Qt::PlatformAppInternal
+ COMPILE_OPTIONS ${arg_COMPILE_OPTIONS}
+ LINK_OPTIONS ${arg_LINK_OPTIONS}
+ MOC_OPTIONS ${arg_MOC_OPTIONS}
+ ENABLE_AUTOGEN_TOOLS ${arg_ENABLE_AUTOGEN_TOOLS}
+ DISABLE_AUTOGEN_TOOLS ${arg_DISABLE_AUTOGEN_TOOLS}
+ TARGET_VERSION ${arg_TARGET_VERSION}
+ TARGET_PRODUCT ${arg_TARGET_PRODUCT}
+ TARGET_DESCRIPTION ${arg_TARGET_DESCRIPTION}
+ TARGET_COMPANY ${arg_TARGET_COMPANY}
+ TARGET_COPYRIGHT ${arg_TARGET_COPYRIGHT}
+ # If you are putting anything after these, make sure that
+ # qt_set_target_info_properties knows how to process them
+ )
+ qt_internal_add_target_aliases("${target}")
+ _qt_internal_apply_strict_cpp("${target}")
+ qt_internal_adjust_main_config_runtime_output_dir("${target}" "${output_directory}")
+
+ # To mimic the default behaviors of qt_app.prf, we by default enable GUI Windows applications,
+ # but don't enable macOS bundles.
+ # Bundles are enabled in a separate set_target_properties call if an Info.plist file
+ # is provided.
+ # Similarly, the Windows GUI flag is disabled in a separate call
+ # if CONFIG += console was encountered during conversion.
+ set_target_properties("${target}" PROPERTIES WIN32_EXECUTABLE TRUE)
+
+ # Consider every app as user facing tool.
+ set_property(GLOBAL APPEND PROPERTY QT_USER_FACING_TOOL_TARGETS ${target})
+
+ # Install versioned link if requested.
+ if(NOT arg_NO_INSTALL AND arg_INSTALL_VERSIONED_LINK)
+ qt_internal_install_versioned_link(WORKING_DIRECTORY "${arg_INSTALL_DIR}"
+ TARGETS ${target})
+ endif()
+
+ qt_add_list_file_finalizer(qt_internal_finalize_app ${target})
+endfunction()
+
+function(qt_internal_get_title_case value out_var)
+ if(NOT value)
+ set(${out_var} "" PARENT_SCOPE)
+ return()
+ endif()
+ string(SUBSTRING "${value}" 0 1 first_char)
+ string(TOUPPER "${first_char}" first_char_upper)
+ string(SUBSTRING "${value}" 1 -1 rest_of_value)
+ set(title_value "${first_char_upper}${rest_of_value}")
+ set(${out_var} "${title_value}" PARENT_SCOPE)
+endfunction()
+
+function(qt_internal_update_app_target_info_properties target)
+ # First update the delayed properties with any values that might have been set after the
+ # qt_internal_add_app() call.
+ qt_internal_update_delayed_target_info_properties(${target})
+
+ # Set defaults in case if no values were set.
+ get_target_property(target_version ${target} QT_DELAYED_TARGET_VERSION)
+ if(NOT target_version)
+ set_target_properties(${target} PROPERTIES QT_DELAYED_TARGET_VERSION "${PROJECT_VERSION}")
+ endif()
+
+ get_target_property(target_description ${target} QT_DELAYED_TARGET_DESCRIPTION)
+ if(NOT target_description)
+ qt_internal_get_title_case("${target}" upper_name)
+ set_target_properties(${target} PROPERTIES QT_DELAYED_TARGET_DESCRIPTION "Qt ${upper_name}")
+ endif()
+
+ # Finally set the final values.
+ qt_internal_set_target_info_properties_from_delayed_properties("${target}")
+endfunction()
+
+function(qt_internal_finalize_app target)
+ qt_internal_update_app_target_info_properties("${target}")
+
+ if(WIN32)
+ _qt_internal_generate_win32_rc_file("${target}")
+ endif()
+
+ # Rpaths need to be applied in the finalizer, because the MACOSX_BUNDLE property might be
+ # set after a qt_internal_add_app call.
+ qt_apply_rpaths(TARGET "${target}" INSTALL_PATH "${INSTALL_BINDIR}" RELATIVE_RPATH)
+ qt_internal_apply_staging_prefix_build_rpath_workaround()
+endfunction()
diff --git a/cmake/QtAutoDetect.cmake b/cmake/QtAutoDetect.cmake
index 683978a65a..464e8e900b 100644
--- a/cmake/QtAutoDetect.cmake
+++ b/cmake/QtAutoDetect.cmake
@@ -1,286 +1,5 @@
-#
-# Collection of auto detection routines to improve the user experience when
-# building Qt from source.
-#
-# Make sure to not run detection when building standalone tests, because the detection was already
-# done when initially configuring qtbase.
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
-function(qt_auto_detect_android)
- if(DEFINED CMAKE_TOOLCHAIN_FILE AND NOT DEFINED QT_AUTODETECT_ANDROID)
-
- file(READ ${CMAKE_TOOLCHAIN_FILE} toolchain_file_content OFFSET 0 LIMIT 80)
- string(FIND ${toolchain_file_content} "The Android Open Source Project" find_result REVERSE)
- if (NOT ${find_result} EQUAL -1)
- set(android_detected TRUE)
- else()
- set(android_detected FALSE)
- endif()
-
- if(android_detected)
- message(STATUS "Android toolchain file detected, checking configuration defaults...")
- if(NOT DEFINED ANDROID_NATIVE_API_LEVEL)
- message(STATUS "ANDROID_NATIVE_API_LEVEL was not specified, using API level 21 as default")
- set(ANDROID_NATIVE_API_LEVEL 21 CACHE STRING "")
- endif()
- if(NOT DEFINED ANDROID_STL)
- set(ANDROID_STL "c++_shared" CACHE STRING "")
- endif()
- endif()
- set(QT_AUTODETECT_ANDROID ${android_detected} CACHE STRING "")
- elseif (QT_AUTODETECT_ANDROID)
- message(STATUS "Android toolchain file detected")
- endif()
-endfunction()
-
-function(qt_auto_detect_vpckg)
- if(DEFINED ENV{VCPKG_ROOT})
- set(vcpkg_toolchain_file "$ENV{VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake")
- get_filename_component(vcpkg_toolchain_file "${vcpkg_toolchain_file}" ABSOLUTE)
-
- if(DEFINED CMAKE_TOOLCHAIN_FILE)
- get_filename_component(supplied_toolchain_file "${CMAKE_TOOLCHAIN_FILE}" ABSOLUTE)
- if(NOT supplied_toolchain_file STREQUAL vcpkg_toolchain_file)
- set(VCPKG_CHAINLOAD_TOOLCHAIN_FILE "${CMAKE_TOOLCHAIN_FILE}" CACHE STRING "")
- endif()
- unset(supplied_toolchain_file)
- endif()
- set(CMAKE_TOOLCHAIN_FILE "${vcpkg_toolchain_file}" CACHE STRING "" FORCE)
- message(STATUS "Using vcpkg from $ENV{VCPKG_ROOT}")
- if(DEFINED ENV{VCPKG_DEFAULT_TRIPLET} AND NOT DEFINED VCPKG_TARGET_TRIPLET)
- set(VCPKG_TARGET_TRIPLET "$ENV{VCPKG_DEFAULT_TRIPLET}" CACHE STRING "")
- message(STATUS "Using vcpkg triplet ${VCPKG_TARGET_TRIPLET}")
- endif()
- unset(vcpkg_toolchain_file)
- message(STATUS "CMAKE_TOOLCHAIN_FILE is: ${CMAKE_TOOLCHAIN_FILE}")
- if(DEFINED VCPKG_CHAINLOAD_TOOLCHAIN_FILE)
- message(STATUS "VCPKG_CHAINLOAD_TOOLCHAIN_FILE is: ${VCPKG_CHAINLOAD_TOOLCHAIN_FILE}")
- endif()
- endif()
-endfunction()
-
-function(qt_auto_detect_ios)
- if(CMAKE_SYSTEM_NAME STREQUAL iOS
- OR CMAKE_SYSTEM_NAME STREQUAL watchOS
- OR CMAKE_SYSTEM_NAME STREQUAL tvOS)
- message(STATUS "Using internal CMake ${CMAKE_SYSTEM_NAME} toolchain file.")
-
- # The QT_UIKIT_SDK check simulates the input.sdk condition for simulator_and_device in
- # configure.json.
- # If the variable is explicitly provided, assume simulator_and_device to be off.
- if(QT_UIKIT_SDK)
- set(simulator_and_device OFF)
- elseif(QT_FORCE_SIMULATOR_AND_DEVICE)
- # TODO: Once we get simulator_and_device support in upstream CMake, only then allow
- # usage of simulator_and_device without forcing.
- set(simulator_and_device ON)
- else()
- # If QT_UIKIT_SDK is not provided, default to simulator.
- set(simulator_and_device OFF)
- set(QT_UIKIT_SDK "iphonesimulator" CACHE "STRING" "Chosen uikit SDK.")
- endif()
-
- message(STATUS "simulator_and_device set to: \"${simulator_and_device}\".")
-
- # Choose relevant architectures.
- # Using a non xcode generator requires explicit setting of the
- # architectures, otherwise compilation fails with unknown defines.
- if(CMAKE_SYSTEM_NAME STREQUAL iOS)
- if(simulator_and_device)
- set(osx_architectures "arm64;x86_64")
- elseif(QT_UIKIT_SDK STREQUAL "iphoneos")
- set(osx_architectures "arm64")
- elseif(QT_UIKIT_SDK STREQUAL "iphonesimulator")
- set(osx_architectures "x86_64")
- else()
- if(NOT DEFINED QT_UIKIT_SDK)
- message(FATAL_ERROR "Please proviude a value for -DQT_UIKIT_SDK."
- " Possible values: iphoneos, iphonesimulator.")
- else()
- message(FATAL_ERROR
- "Unknown SDK argument given to QT_UIKIT_SDK: ${QT_UIKIT_SDK}.")
- endif()
- endif()
- elseif(CMAKE_SYSTEM_NAME STREQUAL tvOS)
- if(simulator_and_device)
- set(osx_architectures "arm64;x86_64")
- elseif(QT_UIKIT_SDK STREQUAL "appletvos")
- set(osx_architectures "arm64")
- elseif(QT_UIKIT_SDK STREQUAL "appletvsimulator")
- set(osx_architectures "x86_64")
- else()
- if(NOT DEFINED QT_UIKIT_SDK)
- message(FATAL_ERROR "Please proviude a value for -DQT_UIKIT_SDK."
- " Possible values: appletvos, appletvsimulator.")
- else()
- message(FATAL_ERROR
- "Unknown SDK argument given to QT_UIKIT_SDK: ${QT_UIKIT_SDK}.")
- endif()
- endif()
- elseif(CMAKE_SYSTEM_NAME STREQUAL watchOS)
- if(simulator_and_device)
- set(osx_architectures "armv7k;i386")
- elseif(QT_UIKIT_SDK STREQUAL "watchos")
- set(osx_architectures "armv7k")
- elseif(QT_UIKIT_SDK STREQUAL "watchsimulator")
- set(osx_architectures "i386")
- else()
- if(NOT DEFINED QT_UIKIT_SDK)
- message(FATAL_ERROR "Please proviude a value for -DQT_UIKIT_SDK."
- " Possible values: watchos, watchsimulator.")
- else()
- message(FATAL_ERROR
- "Unknown SDK argument given to QT_UIKIT_SDK: ${QT_UIKIT_SDK}.")
- endif()
- endif()
- endif()
-
- # For non simulator_and_device builds, we need to explicitly set the SYSROOT aka the sdk
- # value.
- if(QT_UIKIT_SDK)
- set(CMAKE_OSX_SYSROOT "${QT_UIKIT_SDK}" CACHE STRING "")
- endif()
- set(CMAKE_OSX_ARCHITECTURES "${osx_architectures}" CACHE STRING "")
-
- if(NOT DEFINED BUILD_SHARED_LIBS)
- set(BUILD_SHARED_LIBS OFF CACHE BOOL "Build Qt statically or dynamically" FORCE)
- endif()
-
- if(BUILD_SHARED_LIBS)
- message(FATAL_ERROR
- "Building Qt for ${CMAKE_SYSTEM_NAME} as shared libraries is not supported.")
- endif()
-
- # Disable qt rpaths for iOS, just like mkspecs/common/uikit.conf does, due to those
- # bundles not being able to use paths outside the app bundle. Not sure this is strictly
- # needed though.
- set(QT_DISABLE_RPATH "OFF" CACHE BOOL "Disable automatic Qt rpath handling." FORCE)
- endif()
-endfunction()
-
-function(qt_auto_detect_cmake_config)
- if(CMAKE_CONFIGURATION_TYPES)
- # Allow users to specify this option.
- if(NOT QT_MULTI_CONFIG_FIRST_CONFIG)
- list(GET CMAKE_CONFIGURATION_TYPES 0 first_config_type)
- set(QT_MULTI_CONFIG_FIRST_CONFIG "${first_config_type}")
- set(QT_MULTI_CONFIG_FIRST_CONFIG "${first_config_type}" PARENT_SCOPE)
- endif()
-
- set(CMAKE_TRY_COMPILE_CONFIGURATION "${QT_MULTI_CONFIG_FIRST_CONFIG}" PARENT_SCOPE)
- if(CMAKE_GENERATOR STREQUAL "Ninja Multi-Config")
- # Create build-<config>.ninja files for all specified configurations.
- set(CMAKE_CROSS_CONFIGS "all" CACHE STRING "")
-
- # The configuration that will be considered the main one (for example when
- # configuring standalone tests with a single-config generator like Ninja).
- set(CMAKE_DEFAULT_BUILD_TYPE "${QT_MULTI_CONFIG_FIRST_CONFIG}" CACHE STRING "")
-
- # By default when ninja is called without parameters, it will build all configurations.
- set(CMAKE_DEFAULT_CONFIGS "all" CACHE STRING "")
- endif()
- endif()
-endfunction()
-
-function(qt_auto_detect_cyclic_toolchain)
- if(CMAKE_TOOLCHAIN_FILE AND CMAKE_TOOLCHAIN_FILE MATCHES "/qt.toolchain.cmake$")
- message(FATAL_ERROR
- "Woah there! You can't use the Qt generated qt.toolchain.cmake file to configure "
- "qtbase, because that will create a toolchain file that includes itself!\n"
- "Did you accidentally use qt-cmake to configure qtbase? Make sure to remove the "
- "CMakeCache.txt file, and configure qtbase with 'cmake' instead of 'qt-cmake'.")
- endif()
-endfunction()
-
-function(qt_internal_get_darwin_sdk_version out_var)
- if(APPLE)
- if(IOS)
- set(sdk_name "iphoneos")
- elseif(TVOS)
- set(sdk_name "appletvos")
- elseif(WATCHOS)
- set(sdk_name "watchos")
- else()
- # Default to macOS
- set(sdk_name "macosx")
- endif()
- set(xcrun_version_arg "--show-sdk-version")
- execute_process(COMMAND /usr/bin/xcrun --sdk ${sdk_name} ${xcrun_version_arg}
- OUTPUT_VARIABLE sdk_version
- ERROR_VARIABLE xcrun_error)
- if(NOT sdk_version)
- message(FATAL_ERROR
- "Can't determine darwin ${sdk_name} SDK version. Error: ${xcrun_error}")
- endif()
- string(STRIP "${sdk_version}" sdk_version)
- set(${out_var} "${sdk_version}" PARENT_SCOPE)
- endif()
-endfunction()
-
-function(qt_internal_get_xcode_version out_var)
- if(APPLE)
- execute_process(COMMAND /usr/bin/xcrun xcodebuild -version
- OUTPUT_VARIABLE xcode_version
- ERROR_VARIABLE xcrun_error)
- if(NOT xcode_version)
- message(WARNING "Can't determine Xcode version. Error: ${xcrun_error}")
- endif()
- string(REPLACE "\n" " " xcode_version "${xcode_version}")
- string(STRIP "${xcode_version}" xcode_version)
- set(${out_var} "${xcode_version}" PARENT_SCOPE)
- endif()
-endfunction()
-
-function(qt_auto_detect_darwin)
- if(APPLE)
- # If no CMAKE_OSX_DEPLOYMENT_TARGET is provided, default to a value that Qt defines.
- # This replicates the behavior in mkspecs/common/macx.conf where
- # QMAKE_MACOSX_DEPLOYMENT_TARGET is set.
- set(description
- "Minimum OS X version to target for deployment (at runtime); newer APIs weak linked. Set to empty string for default value.")
- if(NOT CMAKE_OSX_DEPLOYMENT_TARGET)
- if(NOT CMAKE_SYSTEM_NAME)
- # macOS
- set(version "10.14")
- elseif(CMAKE_SYSTEM_NAME STREQUAL iOS)
- set(version "12.0")
- elseif(CMAKE_SYSTEM_NAME STREQUAL watchOS)
- set(version "5.0")
- elseif(CMAKE_SYSTEM_NAME STREQUAL tvOS)
- set(version "12.0")
- endif()
- if(version)
- set(CMAKE_OSX_DEPLOYMENT_TARGET "${version}" CACHE STRING "${description}")
- endif()
- endif()
-
- qt_internal_get_darwin_sdk_version(darwin_sdk_version)
- set(QT_MAC_SDK_VERSION "${darwin_sdk_version}" CACHE STRING "Darwin SDK version.")
-
- qt_internal_get_xcode_version(xcode_version)
- set(QT_MAC_XCODE_VERSION "${xcode_version}" CACHE STRING "Xcode version.")
- endif()
-endfunction()
-
-function(qt_auto_detect_pch)
- set(default_value "ON")
-
- if(CMAKE_OSX_ARCHITECTURES AND CMAKE_VERSION VERSION_LESS 3.18.0 AND NOT QT_FORCE_PCH)
- list(LENGTH CMAKE_OSX_ARCHITECTURES arch_count)
- # CMake versions lower than 3.18 don't support PCH when multiple architectures are set.
- # This is the case for simulator_and_device builds.
- if(arch_count GREATER 1)
- set(default_value "OFF")
- message(WARNING "PCH support disabled due to usage of multiple architectures.")
- endif()
- endif()
-
- option(BUILD_WITH_PCH "Build Qt using precompiled headers?" "${default_value}")
-endfunction()
-
-qt_auto_detect_cyclic_toolchain()
-qt_auto_detect_cmake_config()
-qt_auto_detect_darwin()
-qt_auto_detect_ios()
-qt_auto_detect_android()
-qt_auto_detect_vpckg()
-qt_auto_detect_pch()
+include("${CMAKE_CURRENT_LIST_DIR}/QtAutoDetectHelpers.cmake")
+qt_internal_setup_autodetect()
diff --git a/cmake/QtAutoDetectHelpers.cmake b/cmake/QtAutoDetectHelpers.cmake
new file mode 100644
index 0000000000..ad0764b804
--- /dev/null
+++ b/cmake/QtAutoDetectHelpers.cmake
@@ -0,0 +1,487 @@
+# Copyright (C) 2023 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+# Collection of auto detection routines to improve the user experience when
+# building Qt from source.
+#
+# Make sure to not run detection when building standalone tests, because the detection was already
+# done when initially configuring qtbase.
+
+function(qt_internal_ensure_static_qt_config)
+ if(NOT DEFINED BUILD_SHARED_LIBS)
+ set(BUILD_SHARED_LIBS OFF CACHE BOOL "Build Qt statically or dynamically" FORCE)
+ endif()
+
+ if(BUILD_SHARED_LIBS)
+ message(FATAL_ERROR
+ "Building Qt for ${CMAKE_SYSTEM_NAME} as shared libraries is not supported.")
+ endif()
+endfunction()
+
+function(qt_auto_detect_wasm)
+ if("${QT_QMAKE_TARGET_MKSPEC}" STREQUAL "wasm-emscripten"
+ OR "${QT_QMAKE_TARGET_MKSPEC}" STREQUAL "wasm-emscripten-64")
+ if (NOT DEFINED ENV{EMSDK})
+ message(FATAL_ERROR
+ "Can't find an Emscripten SDK! Make sure the EMSDK environment variable is "
+ "available by activating and sourcing the emscripten sdk. Also ensure emcc is in "
+ "your path.")
+ endif()
+ if(NOT DEFINED QT_AUTODETECT_WASM_IS_DONE)
+ message(STATUS "Extracting Emscripten SDK info from EMSDK env var: $ENV{EMSDK}")
+ __qt_internal_get_emroot_path_suffix_from_emsdk_env(EMROOT_PATH)
+
+ __qt_internal_query_emsdk_version("${EMROOT_PATH}" TRUE CMAKE_EMSDK_REGEX_VERSION)
+ set(EMCC_VERSION "${CMAKE_EMSDK_REGEX_VERSION}" CACHE STRING INTERNAL FORCE)
+
+ if(NOT DEFINED BUILD_SHARED_LIBS)
+ qt_internal_ensure_static_qt_config()
+ endif()
+
+ # Find toolchain file
+ if(NOT DEFINED CMAKE_TOOLCHAIN_FILE)
+ __qt_internal_get_emscripten_cmake_toolchain_file_path_from_emsdk_env(
+ "${EMROOT_PATH}" wasm_toolchain_file)
+ set(CMAKE_TOOLCHAIN_FILE "${wasm_toolchain_file}" CACHE STRING "" FORCE)
+ endif()
+
+ if(EXISTS "${CMAKE_TOOLCHAIN_FILE}")
+ message(STATUS
+ "Emscripten ${EMCC_VERSION} toolchain file detected at ${CMAKE_TOOLCHAIN_FILE}")
+ else()
+ __qt_internal_show_error_no_emscripten_toolchain_file_found_when_building_qt()
+ endif()
+
+ __qt_internal_get_emcc_recommended_version(recommended_version)
+ set(QT_EMCC_RECOMMENDED_VERSION "${recommended_version}" CACHE STRING INTERNAL FORCE)
+
+ set(QT_AUTODETECT_WASM_IS_DONE TRUE CACHE BOOL "")
+ else()
+ message(STATUS
+ "Reusing cached Emscripten ${EMCC_VERSION} toolchain file detected at "
+ "${CMAKE_TOOLCHAIN_FILE}")
+ endif()
+ endif()
+endfunction()
+
+function(qt_auto_detect_android)
+ # We assume an Android build if any of the ANDROID_* cache variables are set.
+ if(DEFINED ANDROID_SDK_ROOT
+ OR DEFINED ANDROID_NDK_ROOT
+ OR DEFINED ANDROID_ABI
+ OR DEFINED ANDROID_NATIVE_ABI_LEVEL
+ OR DEFINED ANDROID_STL)
+ set(android_detected TRUE)
+ else()
+ set(android_detected FALSE)
+ endif()
+
+ # Auto-detect NDK root
+ if(NOT DEFINED ANDROID_NDK_ROOT AND DEFINED ANDROID_SDK_ROOT)
+ file(GLOB ndk_versions LIST_DIRECTORIES true RELATIVE "${ANDROID_SDK_ROOT}/ndk"
+ "${ANDROID_SDK_ROOT}/ndk/*")
+ unset(ndk_root)
+ if(NOT ndk_versions STREQUAL "")
+ # Use the NDK with the highest version number.
+ if(CMAKE_VERSION VERSION_LESS 3.18)
+ list(SORT ndk_versions)
+ list(REVERSE ndk_versions)
+ else()
+ list(SORT ndk_versions COMPARE NATURAL ORDER DESCENDING)
+ endif()
+ list(GET ndk_versions 0 ndk_root)
+ string(PREPEND ndk_root "${ANDROID_SDK_ROOT}/ndk/")
+ else()
+ # Fallback: use the deprecated "ndk-bundle" directory within the SDK root.
+ set(ndk_root "${ANDROID_SDK_ROOT}/ndk-bundle")
+ if(NOT IS_DIRECTORY "${ndk_root}")
+ unset(ndk_root)
+ endif()
+ endif()
+ if(DEFINED ndk_root)
+ message(STATUS "Android NDK detected: ${ndk_root}")
+ set(ANDROID_NDK_ROOT "${ndk_root}" CACHE STRING "")
+ endif()
+ endif()
+
+ # Auto-detect toolchain file
+ if(NOT DEFINED CMAKE_TOOLCHAIN_FILE AND DEFINED ANDROID_NDK_ROOT)
+ set(toolchain_file "${ANDROID_NDK_ROOT}/build/cmake/android.toolchain.cmake")
+ if(EXISTS "${toolchain_file}")
+ message(STATUS "Android toolchain file within NDK detected: ${toolchain_file}")
+ set(CMAKE_TOOLCHAIN_FILE "${toolchain_file}" CACHE STRING "")
+ else()
+ message(FATAL_ERROR "Cannot find the toolchain file '${toolchain_file}'. "
+ "Please specify the toolchain file with -DCMAKE_TOOLCHAIN_FILE=<file>.")
+ endif()
+ endif()
+
+ if(NOT DEFINED CMAKE_TOOLCHAIN_FILE AND android_detected)
+ message(FATAL_ERROR "An Android build was requested, but no Android toolchain file was "
+ "specified nor detected.")
+ endif()
+
+ if(DEFINED CMAKE_TOOLCHAIN_FILE AND NOT DEFINED QT_AUTODETECT_ANDROID)
+ # Peek into the toolchain file and check if it looks like an Android one.
+ if(NOT android_detected)
+ file(READ ${CMAKE_TOOLCHAIN_FILE} toolchain_file_content OFFSET 0 LIMIT 80)
+ string(FIND "${toolchain_file_content}" "The Android Open Source Project"
+ find_result REVERSE)
+ if(NOT ${find_result} EQUAL -1)
+ set(android_detected TRUE)
+ endif()
+ endif()
+
+ if(android_detected)
+ message(STATUS "Android build detected, checking configuration defaults...")
+ # ANDROID_NATIVE_API_LEVEL is an just an alias to ANDROID_PLATFORM, check for both
+ if(NOT DEFINED ANDROID_PLATFORM AND NOT DEFINED ANDROID_NATIVE_API_LEVEL)
+ message(STATUS "Neither ANDROID_PLATFORM nor ANDROID_NATIVE_API_LEVEL"
+ " were specified, using API level 23 as default")
+ set(ANDROID_PLATFORM "android-23" CACHE STRING "")
+ set(ANDROID_NATIVE_API_LEVEL 23 CACHE STRING "")
+ endif()
+ if(NOT DEFINED ANDROID_STL)
+ set(ANDROID_STL "c++_shared" CACHE STRING "")
+ endif()
+ endif()
+ set(QT_AUTODETECT_ANDROID ${android_detected} CACHE STRING "")
+ elseif (QT_AUTODETECT_ANDROID)
+ message(STATUS "Android build detected")
+ endif()
+endfunction()
+
+function(qt_auto_detect_vcpkg)
+ if(QT_USE_VCPKG AND DEFINED ENV{VCPKG_ROOT})
+ set(vcpkg_toolchain_file "$ENV{VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake")
+ get_filename_component(vcpkg_toolchain_file "${vcpkg_toolchain_file}" ABSOLUTE)
+
+ if(DEFINED CMAKE_TOOLCHAIN_FILE)
+ get_filename_component(supplied_toolchain_file "${CMAKE_TOOLCHAIN_FILE}" ABSOLUTE)
+ if(NOT supplied_toolchain_file STREQUAL vcpkg_toolchain_file)
+ set(VCPKG_CHAINLOAD_TOOLCHAIN_FILE "${supplied_toolchain_file}" CACHE STRING "")
+ endif()
+ unset(supplied_toolchain_file)
+ endif()
+ set(CMAKE_TOOLCHAIN_FILE "${vcpkg_toolchain_file}" CACHE STRING "" FORCE)
+ message(STATUS "Using vcpkg from $ENV{VCPKG_ROOT}")
+ if(DEFINED ENV{QT_VCPKG_TARGET_TRIPLET} AND NOT DEFINED VCPKG_TARGET_TRIPLET)
+ set(VCPKG_TARGET_TRIPLET "$ENV{QT_VCPKG_TARGET_TRIPLET}" CACHE STRING "")
+ message(STATUS "Using vcpkg triplet ${VCPKG_TARGET_TRIPLET}")
+ endif()
+ unset(vcpkg_toolchain_file)
+ message(STATUS "CMAKE_TOOLCHAIN_FILE is: ${CMAKE_TOOLCHAIN_FILE}")
+ if(DEFINED VCPKG_CHAINLOAD_TOOLCHAIN_FILE)
+ message(STATUS "VCPKG_CHAINLOAD_TOOLCHAIN_FILE is: ${VCPKG_CHAINLOAD_TOOLCHAIN_FILE}")
+ endif()
+ endif()
+endfunction()
+
+function(qt_auto_detect_apple)
+ if(NOT APPLE)
+ return()
+ endif()
+
+ if("${QT_QMAKE_TARGET_MKSPEC}" STREQUAL "macx-ios-clang")
+ set(CMAKE_SYSTEM_NAME "iOS" CACHE STRING "")
+ elseif("${QT_QMAKE_TARGET_MKSPEC}" STREQUAL "macx-visionos-clang")
+ set(CMAKE_SYSTEM_NAME "visionOS" CACHE STRING "")
+ endif()
+
+ if(CMAKE_SYSTEM_NAME STREQUAL iOS)
+ message(STATUS "Using internal CMake ${CMAKE_SYSTEM_NAME} toolchain file.")
+
+ # Pass on QT_UIKIT_SDK for compatibility
+ if(QT_UIKIT_SDK AND NOT QT_APPLE_SDK)
+ set(QT_APPLE_SDK "${QT_UIKIT_SDK}" CACHE STRING "")
+ endif()
+
+ # The QT_APPLE_SDK check simulates the input.sdk condition for simulator_and_device in
+ # configure.json.
+ # If the variable is explicitly provided, assume simulator_and_device to be off.
+ if(QT_APPLE_SDK)
+ set(simulator_and_device OFF)
+ else()
+ # Default to simulator_and_device when an explicit sdk is not requested.
+ # Requires CMake 3.17.0+.
+ set(simulator_and_device ON)
+ endif()
+
+ message(STATUS "simulator_and_device set to: \"${simulator_and_device}\".")
+
+ # Choose relevant architectures.
+ # Using a non Xcode generator requires explicit setting of the
+ # architectures, otherwise compilation fails with unknown defines.
+ if(simulator_and_device)
+ set(osx_architectures "arm64;x86_64")
+ elseif(QT_APPLE_SDK STREQUAL "iphoneos")
+ set(osx_architectures "arm64")
+ elseif(QT_APPLE_SDK STREQUAL "iphonesimulator")
+ set(osx_architectures "x86_64")
+ else()
+ if(NOT DEFINED QT_APPLE_SDK)
+ message(FATAL_ERROR "Please provide a value for -DQT_APPLE_SDK."
+ " Possible values: iphoneos, iphonesimulator.")
+ else()
+ message(FATAL_ERROR
+ "Unknown SDK argument given to QT_APPLE_SDK: ${QT_APPLE_SDK}.")
+ endif()
+ endif()
+
+ set(CMAKE_OSX_ARCHITECTURES "${osx_architectures}" CACHE STRING "")
+ endif()
+
+ if(QT_APPLE_SDK)
+ set(CMAKE_OSX_SYSROOT "${QT_APPLE_SDK}" CACHE STRING "")
+ endif()
+
+ if(CMAKE_SYSTEM_NAME STREQUAL iOS OR CMAKE_SYSTEM_NAME STREQUAL visionOS)
+ if(NOT DEFINED BUILD_SHARED_LIBS)
+ qt_internal_ensure_static_qt_config()
+ endif()
+
+ # Disable qt rpaths for iOS, just like mkspecs/common/uikit.conf does, due to those
+ # bundles not being able to use paths outside the app bundle. Not sure this is strictly
+ # needed though.
+ set(QT_DISABLE_RPATH "OFF" CACHE BOOL "Disable automatic Qt rpath handling." FORCE)
+ endif()
+
+ # If no CMAKE_OSX_DEPLOYMENT_TARGET is provided, default to a value that Qt defines.
+ # This replicates the behavior in mkspecs/common/macx.conf where
+ # QMAKE_MACOSX_DEPLOYMENT_TARGET is set.
+ set(description
+ "Minimum OS X version to target for deployment (at runtime); newer APIs weak linked."
+ " Set to empty string for default value.")
+ if(NOT CMAKE_OSX_DEPLOYMENT_TARGET)
+ if(NOT CMAKE_SYSTEM_NAME)
+ # macOS
+ set(version "12.0")
+ elseif(CMAKE_SYSTEM_NAME STREQUAL iOS)
+ set(version "16.0")
+ endif()
+ if(version)
+ set(CMAKE_OSX_DEPLOYMENT_TARGET "${version}" CACHE STRING "${description}")
+ endif()
+ endif()
+
+ _qt_internal_get_apple_sdk_version(apple_sdk_version)
+ set(QT_MAC_SDK_VERSION "${apple_sdk_version}" CACHE STRING "Darwin SDK version.")
+
+ _qt_internal_get_xcode_version_raw(xcode_version_raw)
+ set(QT_MAC_XCODE_VERSION "${xcode_version_raw}" CACHE STRING "Xcode version.")
+
+ if(NOT CMAKE_SYSTEM_NAME)
+ # macOS
+ list(LENGTH CMAKE_OSX_ARCHITECTURES arch_count)
+ if(arch_count GREATER 0)
+ foreach(arch ${CMAKE_OSX_ARCHITECTURES})
+ if(arch STREQUAL "arm64e")
+ message(WARNING "Applications built against an arm64e Qt architecture will "
+ "likely fail to run on Apple Silicon. Consider targeting "
+ "'arm64' instead.")
+ endif()
+ endforeach()
+ endif()
+
+ set(is_universal "OFF")
+ if(arch_count GREATER 1)
+ set(is_universal "ON")
+ endif()
+ set(QT_IS_MACOS_UNIVERSAL "${is_universal}" CACHE INTERNAL "Build universal Qt for macOS")
+ endif()
+endfunction()
+
+function(qt_auto_detect_cmake_config)
+ # If CMAKE_CONFIGURATION_TYPES are not set for the multi-config generator use Release and
+ # Debug configurations by default, instead of those are proposed by the CMake internal logic.
+ get_property(is_multi GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
+ if(is_multi)
+ if(NOT CMAKE_CONFIGURATION_TYPES)
+ set(CMAKE_CONFIGURATION_TYPES Release Debug)
+ set(CMAKE_CONFIGURATION_TYPES "${CMAKE_CONFIGURATION_TYPES}" PARENT_SCOPE)
+ endif()
+
+ # Allow users to specify this option.
+ if(NOT QT_MULTI_CONFIG_FIRST_CONFIG)
+ list(GET CMAKE_CONFIGURATION_TYPES 0 first_config_type)
+ set(QT_MULTI_CONFIG_FIRST_CONFIG "${first_config_type}")
+ set(QT_MULTI_CONFIG_FIRST_CONFIG "${first_config_type}" PARENT_SCOPE)
+ endif()
+
+ set(CMAKE_TRY_COMPILE_CONFIGURATION "${QT_MULTI_CONFIG_FIRST_CONFIG}" PARENT_SCOPE)
+ if(CMAKE_GENERATOR STREQUAL "Ninja Multi-Config")
+ # Create build-<config>.ninja files for all specified configurations.
+ set(CMAKE_CROSS_CONFIGS "all" CACHE STRING "")
+
+ # The configuration that will be considered the main one (for example when
+ # configuring standalone tests with a single-config generator like Ninja).
+ set(CMAKE_DEFAULT_BUILD_TYPE "${QT_MULTI_CONFIG_FIRST_CONFIG}" CACHE STRING "")
+
+ # By default when ninja is called without parameters, it will build all configurations.
+ set(CMAKE_DEFAULT_CONFIGS "all" CACHE STRING "")
+ endif()
+ endif()
+endfunction()
+
+function(qt_auto_detect_cyclic_toolchain)
+ if(CMAKE_TOOLCHAIN_FILE AND CMAKE_TOOLCHAIN_FILE MATCHES "/qt\\.toolchain\\.cmake$")
+ message(FATAL_ERROR
+ "Woah there! You can't use the Qt generated qt.toolchain.cmake file to configure "
+ "qtbase, because that will create a toolchain file that includes itself!\n"
+ "Did you accidentally use qt-cmake to configure qtbase? Make sure to remove the "
+ "CMakeCache.txt file, and configure qtbase with 'cmake' instead of 'qt-cmake'.")
+ endif()
+endfunction()
+
+function(qt_auto_detect_pch)
+ set(default_value "ON")
+
+ if(CMAKE_OSX_ARCHITECTURES AND CMAKE_VERSION VERSION_LESS 3.18.0 AND NOT QT_FORCE_PCH)
+ list(LENGTH CMAKE_OSX_ARCHITECTURES arch_count)
+ # CMake versions lower than 3.18 don't support PCH when multiple architectures are set.
+ # This is the case for simulator_and_device builds.
+ if(arch_count GREATER 1)
+ set(default_value "OFF")
+ message(WARNING "PCH support disabled due to usage of multiple architectures.")
+ endif()
+ endif()
+
+ option(BUILD_WITH_PCH "Build Qt using precompiled headers?" "${default_value}")
+endfunction()
+
+function(qt_auto_detect_win32_arm)
+ if("${QT_QMAKE_TARGET_MKSPEC}" STREQUAL "win32-arm64-msvc")
+ set(CMAKE_SYSTEM_NAME "Windows" CACHE STRING "")
+ set(CMAKE_SYSTEM_VERSION "10" CACHE STRING "")
+ set(CMAKE_SYSTEM_PROCESSOR "arm64" CACHE STRING "")
+ endif()
+endfunction()
+
+function(qt_auto_detect_linux_x86)
+ if("${QT_QMAKE_TARGET_MKSPEC}" STREQUAL "linux-g++-32" AND NOT QT_NO_AUTO_DETECT_LINUX_X86)
+
+ # Add flag to ensure code is compiled for 32bit x86 ABI aka i386 or its flavors.
+ set(__qt_toolchain_common_flags_init "-m32")
+
+ if(NOT QT_NO_OVERRIDE_LANG_FLAGS_INIT)
+ set(CMAKE_C_FLAGS_INIT "${__qt_toolchain_common_flags_init}" PARENT_SCOPE)
+ set(CMAKE_CXX_FLAGS_INIT "${__qt_toolchain_common_flags_init}" PARENT_SCOPE)
+ set(CMAKE_ASM_FLAGS_INIT "${__qt_toolchain_common_flags_init}" PARENT_SCOPE)
+ endif()
+
+ # Each distro places arch-specific libraries according to its own file system layout.
+ #
+ # https://wiki.debian.org/Multiarch/TheCaseForMultiarch
+ # https://wiki.ubuntu.com/MultiarchSpec
+ # https://wiki.gentoo.org/wiki/Project:AMD64/Multilib_layout
+ # https://wiki.archlinux.org/title/official_repositories#multilib
+ # https://documentation.suse.com/sles/15-SP3/html/SLES-all/cha-64bit.html
+ # https://pilotlogic.com/sitejoom/index.php/wiki?id=398
+ # https://unix.stackexchange.com/questions/458069/multilib-and-multiarch
+ #
+ # CMake can usually find 32 bit libraries just fine on its own.
+ # find_library will use prefixes from CMAKE_PREFIX_PATH / CMAKE_SYSTEM_PREFIX_PATH
+ # and add arch-specific lib folders like 'lib/i386-linux-gnu' on debian based systems
+ # or lib32/lib64 on other distros.
+ # The problem is that if no 32 bit library is found, a 64 bit one might get picked up.
+ # That's why we need to specify additional ignore paths.
+ #
+ # The paths used in the code below are Ubuntu specific.
+ # You can opt out of using them if you are using a different distro, but then you need to
+ # specify appropriate paths yourself in your own CMake toolchain file.
+ #
+ # Note that to absolutely ensure no x86_64 library is picked up on a multiarch /
+ # multilib-enabled system, you might need to specify extra directories in
+ # CMAKE_INGORE_PATH for each sub-directory containing a library.
+ #
+ # For example to exclude /usr/lib/x86_64-linux-gnu/mit-krb5/libgssapi_krb5.so
+ # you need to add /usr/lib/x86_64-linux-gnu/mit-krb5 explicitly to CMAKE_IGNORE_PATH.
+ # Adding just /usr/lib/x86_64-linux-gnu to either CMAKE_IGNORE_PATH or
+ # CMAKE_IGNORE_PREFIX_PATH is not enough.
+ #
+ # Another consideration are results returned by CMake's pkg_check_modules which uses
+ # pkg-config.
+ # CMAKE_IGNORE_PATH is not read by pkg_check_modules, but CMAKE_PREFIX_PATH
+ # values are passed as additional prefixes to look for .pc files, IN ADDITION to the default
+ # prefixes searched by pkg-config of each specific distro.
+ # For example on Ubuntu, the default searched paths on an x86_64 host are:
+ # /usr/local/lib/x86_64-linux-gnu/pkgconfig
+ # /usr/local/lib/pkgconfig
+ # /usr/local/share/pkgconfig
+ # /usr/lib/x86_64-linux-gnu/pkgconfig
+ # /usr/lib/pkgconfig
+ # /usr/share/pkgconfig
+ # To ensure the x86_64 packages are not picked up, the PKG_CONFIG_LIBDIR environment
+ # variable can be overridden with an explicit list of prefixes.
+ # Again, the paths below are Ubuntu specific.
+ if(NOT QT_NO_OVERRIDE_CMAKE_IGNORE_PATH)
+ set(linux_x86_ignore_path "/usr/lib/x86_64-linux-gnu;/lib/x86_64-linux-gnu")
+ set(CMAKE_IGNORE_PATH "${linux_x86_ignore_path}" PARENT_SCOPE)
+ set_property(GLOBAL PROPERTY
+ _qt_internal_linux_x86_ignore_path "${linux_x86_ignore_path}")
+ endif()
+ if(NOT QT_NO_OVERRIDE_PKG_CONFIG_LIBDIR)
+ set(pc_config_libdir "")
+ list(APPEND pc_config_libdir "/usr/local/lib/i386-linux-gnu/pkgconfig")
+ list(APPEND pc_config_libdir "/usr/local/lib/pkgconfig")
+ list(APPEND pc_config_libdir "/usr/local/share/pkgconfig")
+ list(APPEND pc_config_libdir "/usr/lib/i386-linux-gnu/pkgconfig")
+ list(APPEND pc_config_libdir "/usr/lib/pkgconfig")
+ list(APPEND pc_config_libdir "/usr/share/pkgconfig")
+ list(JOIN pc_config_libdir ":" pc_config_libdir)
+
+ set_property(GLOBAL PROPERTY
+ _qt_internal_linux_x86_pc_config_libdir "${pc_config_libdir}")
+
+ # Overrides the default prefix list.
+ set(ENV{PKG_CONFIG_LIBDIR} "${pc_config_libdir}")
+
+ # Overrides the additional prefixes list.
+ set(ENV{PKG_CONFIG_DIR} "")
+ endif()
+ endif()
+endfunction()
+
+function(qt_auto_detect_integrity)
+ if(
+ # Qt's custom CMake toolchain file sets this value.
+ CMAKE_SYSTEM_NAME STREQUAL "Integrity" OR
+
+ # Upstream CMake expects this name, but we don't currently use it in Qt.
+ CMAKE_SYSTEM_NAME STREQUAL "GHS-MULTI"
+ )
+ qt_internal_ensure_static_qt_config()
+ endif()
+endfunction()
+
+# Save the build type before project() might set one.
+# This allows us to determine if the user has set an explicit build type that we should use.
+function(qt_auto_detect_cmake_build_type)
+ set(__qt_auto_detect_cmake_build_type_before_project_call "${CMAKE_BUILD_TYPE}" PARENT_SCOPE)
+endfunction()
+
+macro(qt_internal_setup_autodetect)
+ # This needs to be here because QtAutoDetect loads before any other modules
+ option(QT_USE_VCPKG "Enable the use of vcpkg" OFF)
+
+ include("${CMAKE_CURRENT_LIST_DIR}/QtPublicAppleHelpers.cmake")
+ include("${CMAKE_CURRENT_LIST_DIR}/QtPublicWasmToolchainHelpers.cmake")
+
+ # Let CMake load our custom platform modules.
+ # CMake-provided platform modules take precedence.
+ if(NOT QT_AVOID_CUSTOM_PLATFORM_MODULES)
+ list(PREPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/platforms")
+ endif()
+
+ qt_auto_detect_cyclic_toolchain()
+ qt_auto_detect_cmake_config()
+ qt_auto_detect_apple()
+ qt_auto_detect_android()
+ qt_auto_detect_pch()
+ qt_auto_detect_wasm()
+ qt_auto_detect_win32_arm()
+ qt_auto_detect_linux_x86()
+ qt_auto_detect_integrity()
+ qt_auto_detect_cmake_build_type()
+ qt_auto_detect_vcpkg()
+endmacro()
diff --git a/cmake/QtAutogenHelpers.cmake b/cmake/QtAutogenHelpers.cmake
new file mode 100644
index 0000000000..029a709e90
--- /dev/null
+++ b/cmake/QtAutogenHelpers.cmake
@@ -0,0 +1,216 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+# Initial autogen setup for a target to specify certain CMake properties which are common
+# to all autogen tools. Also enable AUTOMOC by default.
+function(qt_autogen_tools_initial_setup target)
+ set_property(TARGET "${target}" PROPERTY INTERFACE_QT_MAJOR_VERSION ${PROJECT_VERSION_MAJOR})
+ set_property(TARGET "${target}" APPEND PROPERTY COMPATIBLE_INTERFACE_STRING QT_MAJOR_VERSION)
+
+ set_directory_properties(PROPERTIES
+ QT_VERSION_MAJOR ${PROJECT_VERSION_MAJOR}
+ QT_VERSION_MINOR ${PROJECT_VERSION_MINOR}
+ QT_VERSION_PATCH ${PROJECT_VERSION_PATCH}
+ )
+
+ qt_enable_autogen_tool(${target} "moc" ON)
+endfunction()
+
+# Enables or disables an autogen tool like moc, uic or rcc on ${target}.
+function(qt_enable_autogen_tool target tool enable)
+ string(TOUPPER "${tool}" captitalAutogenTool)
+
+ get_target_property(tool_enabled ${target} AUTO${captitalAutogenTool})
+ get_target_property(autogen_target_depends ${target} AUTOGEN_TARGET_DEPENDS)
+
+ if(NOT autogen_target_depends)
+ set(autogen_target_depends "")
+ endif()
+ set(tool_executable "$<TARGET_FILE:${QT_CMAKE_EXPORT_NAMESPACE}::${tool}>")
+ set(tool_target_name ${QT_CMAKE_EXPORT_NAMESPACE}::${tool})
+
+ if(enable)
+ list(APPEND autogen_target_depends ${tool_target_name})
+ else()
+ list(REMOVE_ITEM autogen_target_depends ${tool_target_name})
+ endif()
+
+ # f66c1db16c050c9d685a44a38ad7c5cf9f6fcc96 in qtbase introduced a new macro
+ # that the moc scanner has to look for. Inform the CMake moc scanner about it.
+ if(tool STREQUAL "moc" AND enable)
+ set_target_properties("${target}" PROPERTIES
+ AUTOMOC_MACRO_NAMES "${CMAKE_AUTOMOC_MACRO_NAMES};Q_ENUM_NS;Q_GADGET_EXPORT")
+ if (TARGET Qt::Platform)
+ get_target_property(_abi_tag Qt::Platform qt_libcpp_abi_tag)
+ if (_abi_tag)
+ set_property(TARGET "${target}" APPEND PROPERTY
+ AUTOMOC_MOC_OPTIONS --libcpp-abi-version "${_abi_tag}"
+ )
+ endif()
+ endif()
+ endif()
+
+ set_target_properties("${target}"
+ PROPERTIES
+ AUTO${captitalAutogenTool} "${enable}"
+ AUTO${captitalAutogenTool}_EXECUTABLE "${tool_executable}"
+ AUTOGEN_TARGET_DEPENDS "${autogen_target_depends}"
+ )
+endfunction()
+
+# This function adds or removes additional AUTOGEN tools to a target: AUTOMOC/UIC/RCC
+function(qt_autogen_tools target)
+ cmake_parse_arguments(PARSE_ARGV 1 arg "" "" "${__default_private_args}")
+ _qt_internal_validate_all_args_are_parsed(arg)
+
+ if(arg_ENABLE_AUTOGEN_TOOLS)
+ foreach(tool ${arg_ENABLE_AUTOGEN_TOOLS})
+ qt_enable_autogen_tool(${target} ${tool} ON)
+ endforeach()
+ endif()
+
+ if(arg_DISABLE_AUTOGEN_TOOLS)
+ foreach(tool ${arg_DISABLE_AUTOGEN_TOOLS})
+ qt_enable_autogen_tool(${target} ${tool} OFF)
+ endforeach()
+ endif()
+endfunction()
+
+# Complete manual moc invocation with full control.
+# Use AUTOMOC whenever possible.
+# Multi-value Arguments:
+# INCLUDE_DIRECTORIES
+# Specifies a list of include directories used by 'moc'.
+# INCLUDE_DIRECTORY_TARGETS
+# Specifies a list of targets to extract the INTERFACE_INCLUDE_DIRECTORIES
+# property and use it as the 'moc' include directories.(Deprecated use TARGETS instead)
+# DEFINITIONS
+# List of the definitions that should be added to the moc command line arguments.
+# Supports the syntax both with and without the prepending '-D'.
+# TARGETS
+# The list of targets that will be used to collect the INTERFACE_INCLUDE_DIRECTORIES,
+# INCLUDE_DIRECTORIES, and COMPILE_DEFINITIONS properties.
+function(qt_manual_moc result)
+ cmake_parse_arguments(arg
+ ""
+ "OUTPUT_MOC_JSON_FILES"
+ "FLAGS;INCLUDE_DIRECTORIES;INCLUDE_DIRECTORY_TARGETS;DEFINITIONS;TARGETS"
+ ${ARGN})
+ set(moc_files)
+ set(metatypes_json_list)
+ foreach(infile ${arg_UNPARSED_ARGUMENTS})
+ qt_make_output_file("${infile}" "moc_" ".cpp"
+ "${CMAKE_CURRENT_SOURCE_DIR}" "${CMAKE_CURRENT_BINARY_DIR}" outfile)
+ list(APPEND moc_files "${outfile}")
+
+ set(moc_parameters_file "${outfile}_parameters$<$<BOOL:$<CONFIG>>:_$<CONFIG>>")
+ set(moc_parameters ${arg_FLAGS} -o "${outfile}" "${infile}")
+
+ foreach(dir IN ITEMS ${arg_INCLUDE_DIRECTORIES})
+ list(APPEND moc_parameters
+ "-I\n${dir}")
+ endforeach()
+
+ foreach(dep IN LISTS arg_INCLUDE_DIRECTORY_TARGETS arg_TARGETS)
+ set(include_expr "$<TARGET_PROPERTY:${dep},INTERFACE_INCLUDE_DIRECTORIES>")
+ list(APPEND moc_parameters
+ "$<$<BOOL:${include_expr}>:-I\n$<JOIN:${include_expr},\n-I\n>>")
+
+ if(APPLE AND TARGET ${dep})
+ get_target_property(is_versionless ${dep} _qt_is_versionless_target)
+ if(is_versionless)
+ string(REGEX REPLACE "^Qt::(.*)" "\\1" dep "${dep}")
+ set(dep "${QT_CMAKE_EXPORT_NAMESPACE}::${dep}")
+ endif()
+
+ get_target_property(alias_dep ${dep} ALIASED_TARGET)
+ if(alias_dep)
+ set(dep ${alias_dep})
+ endif()
+
+ get_target_property(loc ${dep} IMPORTED_LOCATION)
+ string(REGEX REPLACE "(.*)/Qt[^/]+\\.framework.*" "\\1" loc "${loc}")
+
+ if(loc)
+ list(APPEND moc_parameters "\n-F\n${loc}\n")
+ endif()
+ endif()
+ endforeach()
+
+ foreach(dep IN LISTS arg_TARGETS)
+ set(include_property_expr
+ "$<TARGET_GENEX_EVAL:${dep},$<TARGET_PROPERTY:${dep},INCLUDE_DIRECTORIES>>")
+ list(APPEND moc_parameters
+ "$<$<BOOL:${include_property_expr}>:-I\n$<JOIN:${include_property_expr},\n-I\n>>")
+
+ set(defines_property_expr
+ "$<TARGET_GENEX_EVAL:${dep},$<TARGET_PROPERTY:${dep},COMPILE_DEFINITIONS>>")
+ set(defines_with_d "$<FILTER:${defines_property_expr},INCLUDE,^-D>")
+ set(defines_without_d "$<FILTER:${defines_property_expr},EXCLUDE,^-D>")
+ list(APPEND moc_parameters
+ "$<$<BOOL:${defines_with_d}>:$<JOIN:${defines_with_d},\n>>")
+ list(APPEND moc_parameters
+ "$<$<BOOL:${defines_without_d}>:-D\n$<JOIN:${defines_without_d},\n-D\n>>")
+ endforeach()
+
+ foreach(def IN LISTS arg_DEFINITIONS)
+ if(NOT def MATCHES "^-D")
+ list(APPEND moc_parameters "-D\n${def}")
+ else()
+ list(APPEND moc_parameters "${def}")
+ endif()
+ endforeach()
+
+ set(metatypes_byproducts)
+ if (arg_OUTPUT_MOC_JSON_FILES)
+ set(moc_json_file "${outfile}.json")
+ list(APPEND moc_parameters --output-json)
+ list(APPEND metatypes_json_list "${outfile}.json")
+ set(metatypes_byproducts "${outfile}.json")
+ endif()
+
+ if (TARGET Qt::Platform)
+ get_target_property(_abi_tag Qt::Platform qt_libcpp_abi_tag)
+ if (_abi_tag)
+ list(APPEND moc_parameters --libcpp-abi-version "${_abi_tag}")
+ endif()
+ endif()
+
+ string (REPLACE ";" "\n" moc_parameters "${moc_parameters}")
+
+ file(GENERATE OUTPUT "${moc_parameters_file}" CONTENT "${moc_parameters}\n")
+
+ add_custom_command(OUTPUT "${outfile}" ${metatypes_byproducts}
+ COMMAND ${QT_CMAKE_EXPORT_NAMESPACE}::moc "@${moc_parameters_file}"
+ DEPENDS "${infile}" ${moc_depends} ${QT_CMAKE_EXPORT_NAMESPACE}::moc
+ WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" VERBATIM)
+ endforeach()
+ set("${result}" ${moc_files} PARENT_SCOPE)
+
+ # Register generated json files
+ if (arg_OUTPUT_MOC_JSON_FILES)
+ set(${arg_OUTPUT_MOC_JSON_FILES} "${metatypes_json_list}" PARENT_SCOPE)
+ endif()
+endfunction()
+
+# From Qt6CoreMacros
+# Function used to create the names of output files preserving relative dirs
+function(qt_make_output_file infile prefix suffix source_dir binary_dir result)
+ get_filename_component(outfilename "${infile}" NAME_WE)
+
+ set(base_dir "${source_dir}")
+ string(FIND "${infile}" "${binary_dir}/" in_binary)
+ if (in_binary EQUAL 0)
+ set(base_dir "${binary_dir}")
+ endif()
+
+ get_filename_component(abs_infile "${infile}" ABSOLUTE BASE_DIR "${base_dir}")
+ file(RELATIVE_PATH rel_infile "${base_dir}" "${abs_infile}")
+ string(REPLACE "../" "__/" mapped_infile "${rel_infile}")
+
+ get_filename_component(abs_mapped_infile "${mapped_infile}" ABSOLUTE BASE_DIR "${binary_dir}")
+ get_filename_component(outpath "${abs_mapped_infile}" PATH)
+
+ file(MAKE_DIRECTORY "${outpath}")
+ set("${result}" "${outpath}/${prefix}${outfilename}${suffix}" PARENT_SCOPE)
+endfunction()
diff --git a/cmake/QtBaseCMakeTesting.cmake b/cmake/QtBaseCMakeTesting.cmake
index 662ac8f498..db64b49189 100644
--- a/cmake/QtBaseCMakeTesting.cmake
+++ b/cmake/QtBaseCMakeTesting.cmake
@@ -1,3 +1,6 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
## Test the cmake build system:
option(BUILD_CMAKE_TESTING "Build tests for the Qt build system" OFF)
mark_as_advanced(BUILD_CMAKE_TESTING)
diff --git a/cmake/QtBaseConfigureTests.cmake b/cmake/QtBaseConfigureTests.cmake
index c1aba357c2..66a0b3b6dd 100644
--- a/cmake/QtBaseConfigureTests.cmake
+++ b/cmake/QtBaseConfigureTests.cmake
@@ -1,3 +1,6 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
include(CheckCXXSourceCompiles)
function(qt_run_config_test_architecture)
@@ -9,23 +12,34 @@ function(qt_run_config_test_architecture)
qt_get_platform_try_compile_vars(platform_try_compile_vars)
list(APPEND flags ${platform_try_compile_vars})
+ list(TRANSFORM flags PREPEND " " OUTPUT_VARIABLE flags_indented)
+ list(JOIN flags_indented "\n" flags_indented)
+
+ message(STATUS
+ "Building architecture extraction project with the following CMake arguments:")
+ list(POP_BACK CMAKE_MESSAGE_CONTEXT _context)
+ message(NOTICE ${flags_indented})
+ list(APPEND CMAKE_MESSAGE_CONTEXT ${_context})
+
try_compile(
_arch_result
"${CMAKE_CURRENT_BINARY_DIR}/config.tests/arch"
"${CMAKE_CURRENT_SOURCE_DIR}/config.tests/arch"
arch
CMAKE_FLAGS ${flags}
+ OUTPUT_VARIABLE arch_test_output
)
if (NOT _arch_result)
- message(FATAL_ERROR "Failed to compile architecture detection file.")
+ message(FATAL_ERROR
+ "Failed to build architecture extraction project. Build output:\n ${arch_test_output}")
endif()
set(_arch_file_suffix "${CMAKE_EXECUTABLE_SUFFIX}")
# With emscripten the application entry point is a .js file (to be run with node for example),
# but the real "data" is in the .wasm file, so that's where we need to look for the ABI, etc.
# information.
- if (EMSCRIPTEN)
+ if (WASM)
set(_arch_file_suffix ".wasm")
endif()
@@ -34,15 +48,27 @@ function(qt_run_config_test_architecture)
string(APPEND arch_test_location "/${QT_MULTI_CONFIG_FIRST_CONFIG}")
endif()
+ set(arch_dir "${CMAKE_CURRENT_BINARY_DIR}/${arch_test_location}")
+ file(GLOB arch_dir_globbed_files RELATIVE "${arch_dir}" "${arch_dir}/*")
+ list(JOIN arch_dir_globbed_files "\n" arch_dir_globbed_files)
+
set(_arch_file
"${CMAKE_CURRENT_BINARY_DIR}/${arch_test_location}/architecture_test${_arch_file_suffix}")
if (NOT EXISTS "${_arch_file}")
message(FATAL_ERROR
- "Failed to find compiled architecture detection executable at ${_arch_file}.")
+ "Failed to find compiled architecture detection executable at ${_arch_file}. \
+ The following files were found at: ${arch_dir} \
+ ${arch_dir_globbed_files}")
endif()
message(STATUS "Extracting architecture info from ${_arch_file}.")
- file(STRINGS "${_arch_file}" _arch_lines LENGTH_MINIMUM 16 LENGTH_MAXIMUM 1024 ENCODING UTF-8)
+ cmake_policy(PUSH)
+ if(POLICY CMP0159)
+ cmake_policy(SET CMP0159 NEW)
+ endif()
+ file(STRINGS "${_arch_file}" _arch_lines LENGTH_MINIMUM 16 LENGTH_MAXIMUM 1024 ENCODING UTF-8
+ REGEX "==Qt=magic=Qt==")
+ cmake_policy(POP)
foreach (_line ${_arch_lines})
string(LENGTH "${_line}" lineLength)
@@ -52,7 +78,7 @@ function(qt_run_config_test_architecture)
string(SUBSTRING "${_line}" ${_pos} -1 _architecture)
endif()
string(FIND "${_line}" "==Qt=magic=Qt== Sub-architecture:" _pos)
- if (_pos GREATER -1 AND ${lineLength} GREATER 33)
+ if (_pos GREATER -1 AND NOT _line MATCHES "Sub-architecture:$")
math(EXPR _pos "${_pos}+34")
string(SUBSTRING "${_line}" ${_pos} -1 _sub_architecture)
string(REPLACE " " ";" _sub_architecture "${_sub_architecture}")
@@ -65,7 +91,12 @@ function(qt_run_config_test_architecture)
endforeach()
if (NOT _architecture OR NOT _build_abi)
- message(FATAL_ERROR "Failed to extract architecture data from file.")
+ list(SUBLIST _arch_lines 0 5 arch_lines_fewer)
+ list(JOIN arch_lines_fewer "\n" arch_lines_output)
+
+ message(FATAL_ERROR
+ "Failed to extract architecture data from file. \
+ Here are the first few lines extracted:\n${arch_lines_output}")
endif()
set(TEST_architecture 1 CACHE INTERNAL "Ran the architecture test")
@@ -89,35 +120,67 @@ endfunction()
function(qt_run_linker_version_script_support)
- file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/version_flag.map" "VERS_1 { global: sym; };
-VERS_2 { global: sym; }
-VERS_1;
-")
- if(DEFINED CMAKE_REQUIRED_FLAGS)
- set(CMAKE_REQUIRED_FLAGS_SAVE ${CMAKE_REQUIRED_FLAGS})
- else()
- set(CMAKE_REQUIRED_FLAGS "")
- endif()
- set(CMAKE_REQUIRED_FLAGS ${CMAKE_REQUIRED_FLAGS} "-Wl,--version-script=\"${CMAKE_CURRENT_BINARY_DIR}/version_flag.map\"")
- check_cxx_source_compiles("int main(void){return 0;}" HAVE_LD_VERSION_SCRIPT)
- if(DEFINED CMAKE_REQUIRED_FLAGS_SAVE)
- set(CMAKE_REQUIRED_FLAGS ${CMAKE_REQUIRED_FLAGS_SAVE})
- endif()
- file(REMOVE "${CMAKE_CURRENT_BINARY_DIR}/conftest.map")
-
# For some reason the linker command line written by the XCode generator, which is
# subsequently executed by xcodebuild, ignores the linker flag, and thus the test
# seemingly succeeds. Explicitly disable the version script test on darwin platforms.
- if(APPLE)
+ # Also makes no sense with MSVC-style command-line
+ if(NOT APPLE AND NOT MSVC)
+ file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/version_flag.map" [=[
+ VERS_1 { global: sym1; };
+ VERS_2 { global: sym2; } VERS_1;
+ ]=])
+ set(CMAKE_REQUIRED_LINK_OPTIONS "")
+ list(APPEND CMAKE_REQUIRED_LINK_OPTIONS
+ "-Wl,--version-script=${CMAKE_CURRENT_BINARY_DIR}/version_flag.map")
+ # Pass the linker that the main project uses to the version script compile test.
+ qt_internal_get_active_linker_flags(linker_flags)
+ if(linker_flags)
+ list(APPEND CMAKE_REQUIRED_LINK_OPTIONS ${linker_flags})
+ endif()
+ check_cxx_source_compiles([=[
+ int sym1;
+ int sym2;
+ int main(void) { return 0; }
+ ]=] HAVE_LD_VERSION_SCRIPT)
+ file(REMOVE "${CMAKE_CURRENT_BINARY_DIR}/version_flag.map")
+ else()
set(HAVE_LD_VERSION_SCRIPT OFF)
endif()
- set(TEST_ld_version_script "${HAVE_LD_VERSION_SCRIPT}" CACHE INTERNAL "linker version script support")
+ set(TEST_ld_version_script "${HAVE_LD_VERSION_SCRIPT}"
+ CACHE INTERNAL "linker version script support")
+ list(APPEND QT_BASE_CONFIGURE_TESTS_VARS_TO_EXPORT TEST_ld_version_script)
+ set(QT_BASE_CONFIGURE_TESTS_VARS_TO_EXPORT ${QT_BASE_CONFIGURE_TESTS_VARS_TO_EXPORT}
+ CACHE INTERNAL "Test variables that should be exported")
+endfunction()
+
+function(qt_internal_ensure_latest_win_nt_api)
+ if(NOT WIN32)
+ return()
+ endif()
+ check_cxx_source_compiles([=[
+ #include <windows.h>
+ #if !defined(_WIN32_WINNT) && !defined(WINVER)
+ #error "_WIN32_WINNT and WINVER are not defined"
+ #endif
+ #if defined(_WIN32_WINNT) && (_WIN32_WINNT < 0x0A00)
+ #error "_WIN32_WINNT version too low"
+ #endif
+ #if defined(WINVER) && (WINVER < 0x0A00)
+ #error "WINVER version too low"
+ #endif
+ int main() { return 0; }
+ ]=] HAVE_WIN10_WIN32_WINNT)
+ if(NOT HAVE_WIN10_WIN32_WINNT)
+ list(APPEND QT_PLATFORM_DEFINITIONS _WIN32_WINNT=0x0A00 WINVER=0x0A00)
+ set(QT_PLATFORM_DEFINITIONS ${QT_PLATFORM_DEFINITIONS}
+ CACHE STRING "Qt platform specific pre-processor defines" FORCE)
+ endif()
endfunction()
function(qt_run_qtbase_config_tests)
qt_run_config_test_architecture()
- qt_run_linker_version_script_support()
+ qt_internal_ensure_latest_win_nt_api()
endfunction()
# The qmake build of android does not perform the right architecture tests and
@@ -137,18 +200,27 @@ function(qt_internal_print_cmake_darwin_info)
set(default_osx_arch " (defaults to ${CMAKE_SYSTEM_PROCESSOR})")
endif()
message(STATUS "CMAKE_OSX_ARCHITECTURES: \"${CMAKE_OSX_ARCHITECTURES}\"${default_osx_arch}")
- message(STATUS "CMAKE_OSX_SYSROOT: \"${CMAKE_OSX_SYSROOT}\"")
+ message(STATUS "CMAKE_OSX_SYSROOT: \"$CACHE{CMAKE_OSX_SYSROOT}\" / \"${CMAKE_OSX_SYSROOT}\"")
message(STATUS "CMAKE_OSX_DEPLOYMENT_TARGET: \"${CMAKE_OSX_DEPLOYMENT_TARGET}\"")
message(STATUS "QT_MAC_SDK_VERSION: \"${QT_MAC_SDK_VERSION}\"")
message(STATUS "QT_MAC_XCODE_VERSION: \"${QT_MAC_XCODE_VERSION}\"")
- if(QT_UIKIT_SDK)
- message(STATUS "QT_UIKIT_SDK: \"${QT_UIKIT_SDK}\"")
+
+ if(DEFINED CACHE{QT_IS_MACOS_UNIVERSAL})
+ message(STATUS "QT_IS_MACOS_UNIVERSAL: \"${QT_IS_MACOS_UNIVERSAL}\"")
+ endif()
+ if(QT_APPLE_SDK)
+ message(STATUS "QT_APPLE_SDK: \"${QT_APPLE_SDK}\"")
+ endif()
+ qt_internal_get_first_osx_arch(osx_first_arch)
+ if(osx_first_arch)
+ message(STATUS "Configure tests main architecture (in multi-arch build): \"${osx_first_arch}\"")
endif()
endif()
endfunction()
qt_internal_print_cmake_darwin_info()
function(qt_internal_print_cmake_host_and_target_info)
+ message(STATUS "CMAKE_VERSION: \"${CMAKE_VERSION}\"")
message(STATUS "CMAKE_HOST_SYSTEM: \"${CMAKE_HOST_SYSTEM}\"")
message(STATUS "CMAKE_HOST_SYSTEM_NAME: \"${CMAKE_HOST_SYSTEM_NAME}\"")
message(STATUS "CMAKE_HOST_SYSTEM_VERSION: \"${CMAKE_HOST_SYSTEM_VERSION}\"")
@@ -163,6 +235,15 @@ function(qt_internal_print_cmake_host_and_target_info)
endfunction()
qt_internal_print_cmake_host_and_target_info()
+function(qt_internal_print_prefix_info)
+ message(STATUS "CMAKE_INSTALL_PREFIX: \"${CMAKE_INSTALL_PREFIX}\"")
+ message(STATUS "CMAKE_STAGING_PREFIX: \"${CMAKE_STAGING_PREFIX}\"")
+ message(STATUS "QT_BUILD_DIR: \"${QT_BUILD_DIR}\"")
+ message(STATUS "QT_INSTALL_DIR: \"${QT_INSTALL_DIR}\"")
+ message(STATUS "QT_WILL_INSTALL: \"${QT_WILL_INSTALL}\"")
+endfunction()
+qt_internal_print_prefix_info()
+
function(qt_internal_print_cmake_compiler_info)
message(STATUS "CMAKE_C_COMPILER: \"${CMAKE_C_COMPILER}\" (${CMAKE_C_COMPILER_VERSION})")
message(STATUS "CMAKE_CXX_COMPILER: \"${CMAKE_CXX_COMPILER}\" (${CMAKE_CXX_COMPILER_VERSION})")
@@ -191,6 +272,7 @@ function(qt_internal_print_cmake_android_info)
message(STATUS "ANDROID_NDK: \"${ANDROID_NDK}\"")
message(STATUS "ANDROID_ABI: \"${ANDROID_ABI}\"")
message(STATUS "ANDROID_PLATFORM: \"${ANDROID_PLATFORM}\"")
+ message(STATUS "ANDROID_NATIVE_API_LEVEL: \"${ANDROID_NATIVE_API_LEVEL}\"")
message(STATUS "ANDROID_STL: \"${ANDROID_STL}\"")
message(STATUS "ANDROID_PIE: \"${ANDROID_PIE}\"")
message(STATUS "ANDROID_CPP_FEATURES: \"${ANDROID_CPP_FEATURES}\"")
@@ -198,7 +280,6 @@ function(qt_internal_print_cmake_android_info)
message(STATUS "ANDROID_ARM_MODE: \"${ANDROID_ARM_MODE}\"")
message(STATUS "ANDROID_ARM_NEON: \"${ANDROID_ARM_NEON}\"")
message(STATUS "ANDROID_DISABLE_FORMAT_STRING_CHECKS: \"${ANDROID_DISABLE_FORMAT_STRING_CHECKS}\"")
- message(STATUS "ANDROID_NATIVE_API_LEVEL: \"${ANDROID_NATIVE_API_LEVEL}\"")
message(STATUS "ANDROID_LLVM_TRIPLE: \"${ANDROID_LLVM_TRIPLE}\"")
endif()
endfunction()
diff --git a/cmake/QtBaseGlobalTargets.cmake b/cmake/QtBaseGlobalTargets.cmake
index 1e5de239d6..1e604559ed 100644
--- a/cmake/QtBaseGlobalTargets.cmake
+++ b/cmake/QtBaseGlobalTargets.cmake
@@ -1,29 +1,12 @@
-## QtPlatform Target:
-add_library(Platform INTERFACE)
-add_library(Qt::Platform ALIAS Platform)
-target_include_directories(Platform
- INTERFACE
- $<BUILD_INTERFACE:${QT_PLATFORM_DEFINITION_DIR_ABSOLUTE}>
- $<BUILD_INTERFACE:${PROJECT_BINARY_DIR}/${INSTALL_INCLUDEDIR}>
- $<INSTALL_INTERFACE:${QT_PLATFORM_DEFINITION_DIR}>
- $<INSTALL_INTERFACE:${INSTALL_INCLUDEDIR}>
- )
-target_compile_definitions(Platform INTERFACE ${QT_PLATFORM_DEFINITIONS})
-
-# When building on android we need to link against the logging library
-# in order to satisfy linker dependencies. Both of these libraries are part of
-# the NDK.
-if (ANDROID)
- target_link_libraries(Platform INTERFACE log)
-endif()
-
-qt_enable_msvc_cplusplus_define(Platform INTERFACE)
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
set(__GlobalConfig_path_suffix "${INSTALL_CMAKE_NAMESPACE}")
qt_path_join(__GlobalConfig_build_dir ${QT_CONFIG_BUILD_DIR} ${__GlobalConfig_path_suffix})
qt_path_join(__GlobalConfig_install_dir ${QT_CONFIG_INSTALL_DIR} ${__GlobalConfig_path_suffix})
set(__GlobalConfig_install_dir_absolute "${__GlobalConfig_install_dir}")
set(__qt_bin_dir_absolute "${QT_INSTALL_DIR}/${INSTALL_BINDIR}")
+set(__qt_libexec_dir_absolute "${QT_INSTALL_DIR}/${INSTALL_LIBEXECDIR}")
if(QT_WILL_INSTALL)
# Need to prepend the install prefix when doing prefix builds, because the config install dir
# is relative then.
@@ -32,6 +15,8 @@ if(QT_WILL_INSTALL)
${__GlobalConfig_install_dir_absolute})
qt_path_join(__qt_bin_dir_absolute
${QT_BUILD_INTERNALS_RELOCATABLE_INSTALL_PREFIX} ${__qt_bin_dir_absolute})
+ qt_path_join(__qt_libexec_dir_absolute
+ ${QT_BUILD_INTERNALS_RELOCATABLE_INSTALL_PREFIX} ${__qt_libexec_dir_absolute})
endif()
# Compute relative path from $qt_prefix/bin dir to global CMake config install dir, to use in the
# unix-y qt-cmake shell script, to make it work even if the installed Qt is relocated.
@@ -39,26 +24,6 @@ file(RELATIVE_PATH
__GlobalConfig_relative_path_from_bin_dir_to_cmake_config_dir
${__qt_bin_dir_absolute} ${__GlobalConfig_install_dir_absolute})
-# Generate and install Qt6 config file.
-configure_package_config_file(
- "${PROJECT_SOURCE_DIR}/cmake/QtConfig.cmake.in"
- "${__GlobalConfig_build_dir}/${INSTALL_CMAKE_NAMESPACE}Config.cmake"
- INSTALL_DESTINATION "${__GlobalConfig_install_dir}"
-)
-
-write_basic_package_version_file(
- ${__GlobalConfig_build_dir}/${INSTALL_CMAKE_NAMESPACE}ConfigVersion.cmake
- VERSION ${PROJECT_VERSION}
- COMPATIBILITY AnyNewerVersion
-)
-
-qt_install(FILES
- "${__GlobalConfig_build_dir}/${INSTALL_CMAKE_NAMESPACE}Config.cmake"
- "${__GlobalConfig_build_dir}/${INSTALL_CMAKE_NAMESPACE}ConfigVersion.cmake"
- DESTINATION "${__GlobalConfig_install_dir}"
- COMPONENT Devel
-)
-
# Configure and install the QtBuildInternals package.
set(__build_internals_path_suffix "${INSTALL_CMAKE_NAMESPACE}BuildInternals")
qt_path_join(__build_internals_build_dir ${QT_CONFIG_BUILD_DIR} ${__build_internals_path_suffix})
@@ -72,17 +37,25 @@ configure_file(
@ONLY
)
+write_basic_package_version_file(
+ "${__build_internals_build_dir}/${INSTALL_CMAKE_NAMESPACE}BuildInternalsConfigVersionImpl.cmake"
+ VERSION ${PROJECT_VERSION}
+ COMPATIBILITY AnyNewerVersion
+)
+qt_internal_write_qt_package_version_file(
+ "${INSTALL_CMAKE_NAMESPACE}BuildInternals"
+ "${__build_internals_build_dir}/${INSTALL_CMAKE_NAMESPACE}BuildInternalsConfigVersion.cmake"
+)
+
qt_install(FILES
"${__build_internals_build_dir}/${INSTALL_CMAKE_NAMESPACE}BuildInternalsConfig.cmake"
+ "${__build_internals_build_dir}/${INSTALL_CMAKE_NAMESPACE}BuildInternalsConfigVersion.cmake"
+ "${__build_internals_build_dir}/${INSTALL_CMAKE_NAMESPACE}BuildInternalsConfigVersionImpl.cmake"
"${__build_internals_build_dir}/QtBuildInternalsExtra.cmake"
DESTINATION "${__build_internals_install_dir}"
COMPONENT Devel
)
qt_copy_or_install(
- FILES
- "${CMAKE_CURRENT_SOURCE_DIR}/cmake/QtBuildInternals/QtBuildInternalsAndroid.cmake"
- DESTINATION "${__build_internals_install_dir}")
-qt_copy_or_install(
DIRECTORY
"${CMAKE_CURRENT_SOURCE_DIR}/cmake/QtBuildInternals/${__build_internals_standalone_test_template_dir}"
DESTINATION "${__build_internals_install_dir}")
@@ -90,194 +63,15 @@ qt_copy_or_install(
set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS
"${CMAKE_CURRENT_SOURCE_DIR}/cmake/QtBuildInternals/${__build_internals_standalone_test_template_dir}/CMakeLists.txt")
-# Generate toolchain file for convenience
-if(QT_HOST_PATH)
- get_filename_component(init_qt_host_path "${QT_HOST_PATH}" ABSOLUTE)
- # TODO: Figure out how to make these relocatable.
- set(init_qt_host_path "set(QT_HOST_PATH \"${init_qt_host_path}\" CACHE PATH \"\" FORCE)")
- get_filename_component(QT_HOST_PATH_CMAKE_DIR
- "${Qt${PROJECT_VERSION_MAJOR}HostInfo_DIR}/.." ABSOLUTE)
- set(init_qt_host_path_cmake_dir
- "set(QT_HOST_PATH_CMAKE_DIR \"${QT_HOST_PATH_CMAKE_DIR}\" CACHE PATH \"\" FORCE)")
-endif()
-
-if(CMAKE_TOOLCHAIN_FILE)
- set(init_original_toolchain_file "set(__qt_chainload_toolchain_file \"${CMAKE_TOOLCHAIN_FILE}\")")
-endif()
-
-if(VCPKG_CHAINLOAD_TOOLCHAIN_FILE)
- list(APPEND init_vcpkg "set(VCPKG_CHAINLOAD_TOOLCHAIN_FILE \"${VCPKG_CHAINLOAD_TOOLCHAIN_FILE}\")")
-endif()
-
-if(VCPKG_TARGET_TRIPLET)
- list(APPEND init_vcpkg "set(VCPKG_TARGET_TRIPLET \"${VCPKG_TARGET_TRIPLET}\" CACHE STRING \"\")")
-endif()
-
-# By default we don't want to allow mixing compilers for building different repositories, so we
-# embed the initially chosen compilers into the toolchain.
-# This is because on Windows compilers aren't easily mixed.
-# We want to avoid that qtbase is built using cl.exe for example, and then for another repo
-# gcc is picked up from %PATH%.
-# The same goes when using a custom compiler on other platforms, such as ICC.
-#
-# There are a few exceptions though.
-#
-# When crosscompiling using Boot2Qt, the environment setup shell script sets up the CXX env var,
-# which is used by CMake to determine the initial compiler that should be used.
-# Unfortunately, the CXX env var contains not only the compiler name, but also a few required
-# arch-specific compiler flags. This means that when building qtsvg, if the Qt created toolchain
-# file sets the CMAKE_CXX_COMPILER variable, the CXX env var is ignored and thus the extra
-# arch specific compiler flags are not picked up anymore, leading to a configuration failure.
-#
-# To avoid this issue, disable automatic embedding of the compilers into the qt toolchain when
-# cross compiling. This is merely a heuristic, becacuse we don't have enough data to decide
-# when to do it or not.
-# For example on Linux one might want to allow mixing of clang and gcc (maybe).
-#
-# To allow such use cases when the default is wrong, one can provide a flag to explicitly opt-in
-# or opt-out of the compiler embedding into the Qt toolchain.
-#
-# Passing -DQT_EMBED_TOOLCHAIN_COMPILER=ON will force embedding of the compilers.
-# Passing -DQT_EMBED_TOOLCHAIN_COMPILER=OFF will disable embedding of the compilers.
-set(__qt_embed_toolchain_compilers TRUE)
-if(CMAKE_CROSSCOMPILING)
- set(__qt_embed_toolchain_compilers FALSE)
-endif()
-if(DEFINED QT_EMBED_TOOLCHAIN_COMPILER)
- if(QT_EMBED_TOOLCHAIN_COMPILER)
- set(__qt_embed_toolchain_compilers TRUE)
- else()
- set(__qt_embed_toolchain_compilers FALSE)
- endif()
-endif()
-if(__qt_embed_toolchain_compilers)
- list(APPEND init_platform "set(CMAKE_CXX_COMPILER \"${CMAKE_CXX_COMPILER}\" CACHE STRING \"\")")
- list(APPEND init_platform "set(CMAKE_C_COMPILER \"${CMAKE_C_COMPILER}\" CACHE STRING \"\")")
-endif()
-unset(__qt_embed_toolchain_compilers)
-
-if(APPLE)
- # For simulator_and_device build, we should not explicitly set the sysroot.
- list(LENGTH CMAKE_OSX_ARCHITECTURES _qt_osx_architectures_count)
- if(CMAKE_OSX_SYSROOT AND NOT _qt_osx_architectures_count GREATER 1 AND UIKIT)
- list(APPEND init_platform "set(CMAKE_OSX_SYSROOT \"${CMAKE_OSX_SYSROOT}\" CACHE PATH \"\")")
- endif()
- unset(_qt_osx_architectures_count)
-
- if(CMAKE_OSX_DEPLOYMENT_TARGET)
- list(APPEND init_platform
- "set(CMAKE_OSX_DEPLOYMENT_TARGET \"${CMAKE_OSX_DEPLOYMENT_TARGET}\" CACHE STRING \"\")")
- endif()
-
- if(UIKIT)
- list(APPEND init_platform
- "set(CMAKE_SYSTEM_NAME \"${CMAKE_SYSTEM_NAME}\" CACHE STRING \"\")")
- set(_qt_osx_architectures_escaped "${CMAKE_OSX_ARCHITECTURES}")
- string(REPLACE ";" "LITERAL_SEMICOLON"
- _qt_osx_architectures_escaped "${_qt_osx_architectures_escaped}")
- list(APPEND init_platform
- "set(CMAKE_OSX_ARCHITECTURES \"${_qt_osx_architectures_escaped}\" CACHE STRING \"\")")
- unset(_qt_osx_architectures_escaped)
- endif()
-elseif(ANDROID)
- list(APPEND init_platform "set(ANDROID_NATIVE_API_LEVEL \"${ANDROID_NATIVE_API_LEVEL}\" CACHE STRING \"\")")
- list(APPEND init_platform "set(ANDROID_STL \"${ANDROID_STL}\" CACHE STRING \"\")")
- list(APPEND init_platform "set(ANDROID_ABI \"${ANDROID_ABI}\" CACHE STRING \"\")")
- list(APPEND init_platform "if (NOT DEFINED ANDROID_SDK_ROOT)")
- list(APPEND init_platform " set(ANDROID_SDK_ROOT \"${ANDROID_SDK_ROOT}\" CACHE STRING \"\")")
- list(APPEND init_platform "endif()")
-endif()
-
-string(REPLACE ";" "\n" init_vcpkg "${init_vcpkg}")
-string(REPLACE ";" "\n" init_platform "${init_platform}")
-string(REPLACE "LITERAL_SEMICOLON" ";" init_platform "${init_platform}")
-qt_compute_relative_path_from_cmake_config_dir_to_prefix()
-configure_file("${CMAKE_CURRENT_SOURCE_DIR}/cmake/qt.toolchain.cmake.in" "${__GlobalConfig_build_dir}/qt.toolchain.cmake" @ONLY)
-unset(qt_path_from_cmake_config_dir_to_prefix)
-qt_install(FILES "${__GlobalConfig_build_dir}/qt.toolchain.cmake" DESTINATION "${__GlobalConfig_install_dir}" COMPONENT Devel)
-
-# Also provide a convenience cmake wrapper
-if(UNIX)
- configure_file("${CMAKE_CURRENT_SOURCE_DIR}/bin/qt-cmake.in" "${QT_BUILD_DIR}/${INSTALL_BINDIR}/qt-cmake" @ONLY)
- qt_install(PROGRAMS "${QT_BUILD_DIR}/${INSTALL_BINDIR}/qt-cmake" DESTINATION "${INSTALL_BINDIR}")
-else()
- configure_file("${CMAKE_CURRENT_SOURCE_DIR}/bin/qt-cmake.bat.in" "${QT_BUILD_DIR}/${INSTALL_BINDIR}/qt-cmake.bat" @ONLY)
- qt_install(PROGRAMS "${QT_BUILD_DIR}/${INSTALL_BINDIR}/qt-cmake.bat" DESTINATION "${INSTALL_BINDIR}")
-endif()
-
-# Provide a private convenience wrapper with options which should not be propagated via the public
-# qt-cmake wrapper e.g. CMAKE_GENERATOR.
-# These options can not be set in a toolchain file, but only on the command line.
-# These options should not be in the public wrapper, because a consumer of Qt might want to build
-# their CMake app with the Unix Makefiles generator, while Qt should be built with the Ninja
-# generator.
-# The private wrapper is more conveient for building Qt itself, because a developer doesn't need
-# to specify the same options for each qt module built.
-set(__qt_cmake_extra "-G\"${CMAKE_GENERATOR}\"")
-if(UNIX)
- configure_file("${CMAKE_CURRENT_SOURCE_DIR}/bin/qt-cmake.in"
- "${QT_BUILD_DIR}/${INSTALL_BINDIR}/qt-cmake-private" @ONLY)
-qt_install(PROGRAMS "${QT_BUILD_DIR}/${INSTALL_BINDIR}/qt-cmake-private" DESTINATION "${INSTALL_BINDIR}")
-else()
- configure_file("${CMAKE_CURRENT_SOURCE_DIR}/bin/qt-cmake.bat.in"
- "${QT_BUILD_DIR}/${INSTALL_BINDIR}/qt-cmake-private.bat" @ONLY)
-qt_install(PROGRAMS "${QT_BUILD_DIR}/${INSTALL_BINDIR}/qt-cmake-private.bat" DESTINATION "${INSTALL_BINDIR}")
-endif()
-unset(__qt_cmake_extra)
-
-# Provide a private convenience wrapper to configure and build one or more standalone tests.
-# Calling CMake directly on a Qt test project won't work because the project does not call
-# find_package(Qt...) to get all dependencies like examples do.
-# Instead a template CMakeLists.txt project is used which sets up all the necessary private bits
-# and then calls add_subdirectory on the provided project path.
-set(__qt_cmake_standalone_test_bin_name "qt-cmake-standalone-test")
-set(__qt_cmake_private_path
- "${QT_STAGING_PREFIX}/${INSTALL_BINDIR}/qt-cmake-private")
-set(__qt_cmake_standalone_test_path
- "${__build_internals_install_dir}/${__build_internals_standalone_test_template_dir}")
-
-if(QT_WILL_INSTALL)
- # Need to prepend the staging prefix when doing prefix builds, because the build internals
- # install dir is relative in that case..
- qt_path_join(__qt_cmake_standalone_test_path
- "${QT_STAGING_PREFIX}"
- "${__qt_cmake_standalone_test_path}")
-endif()
-if(UNIX)
- set(__qt_cmake_standalone_test_os_prelude "#!/bin/sh")
- string(PREPEND __qt_cmake_private_path "exec ")
- set(__qt_cmake_standalone_passed_args "\"$@\" -DPWD=\"$PWD\"")
-else()
- set(__qt_cmake_standalone_test_os_prelude "@echo off")
- string(APPEND __qt_cmake_standalone_test_bin_name ".bat")
- string(APPEND __qt_cmake_private_path ".bat")
- set(__qt_cmake_standalone_passed_args "%* -DPWD=\"%CD%\"")
-endif()
-configure_file("${CMAKE_CURRENT_SOURCE_DIR}/bin/qt-cmake-standalone-test.in"
- "${QT_BUILD_DIR}/${INSTALL_BINDIR}/${__qt_cmake_standalone_test_bin_name}")
-qt_install(PROGRAMS "${QT_BUILD_DIR}/${INSTALL_BINDIR}/${__qt_cmake_standalone_test_bin_name}"
- DESTINATION "${INSTALL_BINDIR}")
-
-# Create an installation script that the CI can use to handle installation for both
-# single and multiple configurations.
-set(__qt_cmake_install_script_name "qt-cmake-private-install.cmake")
-if(CMAKE_CONFIGURATION_TYPES)
- set(__qt_configured_configs "${CMAKE_CONFIGURATION_TYPES}")
-elseif(CMAKE_BUILD_TYPE)
- set(__qt_configured_configs "${CMAKE_BUILD_TYPE}")
-endif()
-configure_file("${CMAKE_CURRENT_SOURCE_DIR}/bin/${__qt_cmake_install_script_name}.in"
- "${QT_BUILD_DIR}/${INSTALL_BINDIR}/${__qt_cmake_install_script_name}" @ONLY)
-qt_install(PROGRAMS "${QT_BUILD_DIR}/${INSTALL_BINDIR}/${__qt_cmake_install_script_name}"
- DESTINATION "${INSTALL_BINDIR}")
+qt_internal_create_toolchain_file()
## Library to hold global features:
## These features are stored and accessed via Qt::GlobalConfig, but the
## files always lived in Qt::Core, so we keep it that way
add_library(GlobalConfig INTERFACE)
target_include_directories(GlobalConfig INTERFACE
- $<BUILD_INTERFACE:${PROJECT_BINARY_DIR}/${INSTALL_INCLUDEDIR}>
- $<BUILD_INTERFACE:${PROJECT_BINARY_DIR}/${INSTALL_INCLUDEDIR}/QtCore>
+ $<BUILD_INTERFACE:${PROJECT_BINARY_DIR}/include>
+ $<BUILD_INTERFACE:${PROJECT_BINARY_DIR}/include/QtCore>
$<INSTALL_INTERFACE:${INSTALL_INCLUDEDIR}>
$<INSTALL_INTERFACE:${INSTALL_INCLUDEDIR}/QtCore>
)
@@ -289,41 +83,66 @@ include("${CMAKE_CURRENT_SOURCE_DIR}/configure.cmake")
# Do what mkspecs/features/uikit/default_pre.prf does, aka enable sse2 for
# simulator_and_device_builds.
-if(UIKIT AND NOT QT_UIKIT_SDK)
+
+qt_internal_get_first_osx_arch(__qt_osx_first_arch)
+set(__qt_apple_silicon_arches "arm64;arm64e")
+if(MACOS AND QT_IS_MACOS_UNIVERSAL
+ AND __qt_osx_first_arch IN_LIST __qt_apple_silicon_arches)
+ # The test in configure.cmake will not be run, but we know that
+ # the compiler supports these intrinsics
+ set(QT_FORCE_FEATURE_x86intrin ON CACHE INTERNAL "Force-enable x86 intrinsics due to platform requirements.")
set(__QtFeature_custom_enabled_cache_variables
- TEST_subarch_sse2
- FEATURE_sse2
- QT_FEATURE_sse2)
+ TEST_x86intrin
+ FEATURE_x86intrin
+ QT_FEATURE_x86intrin)
+endif()
+
+if(MACOS AND QT_IS_MACOS_UNIVERSAL AND
+ (__qt_osx_first_arch STREQUAL "x86_64" OR __qt_osx_first_arch STREQUAL "x86_64h"))
+ set(QT_FORCE_FEATURE_neon ON CACHE INTERNAL "Force enable neon due to platform requirements.")
+ set(__QtFeature_custom_enabled_cache_variables
+ TEST_subarch_neon
+ FEATURE_neon
+ QT_FEATURE_neon)
endif()
qt_feature_module_end(GlobalConfig OUT_VAR_PREFIX "__GlobalConfig_")
+# The version script support check has to happen after we determined which linker is going
+# to be used. The linker decision happens in the qtbase/configure.cmake file that is processed
+# above.
+qt_run_linker_version_script_support()
+
qt_generate_global_config_pri_file()
qt_generate_global_module_pri_file()
qt_generate_global_device_pri_file()
-qt_generate_qmake_wrapper_for_target()
+qt_generate_qmake_and_qtpaths_wrapper_for_target()
+
+# Depends on the global features being evaluated.
+qt_internal_create_wrapper_scripts()
add_library(Qt::GlobalConfig ALIAS GlobalConfig)
add_library(GlobalConfigPrivate INTERFACE)
target_link_libraries(GlobalConfigPrivate INTERFACE GlobalConfig)
target_include_directories(GlobalConfigPrivate INTERFACE
- $<BUILD_INTERFACE:${PROJECT_BINARY_DIR}/${INSTALL_INCLUDEDIR}/QtCore/${PROJECT_VERSION}>
- $<BUILD_INTERFACE:${PROJECT_BINARY_DIR}/${INSTALL_INCLUDEDIR}/QtCore/${PROJECT_VERSION}/QtCore>
+ $<BUILD_INTERFACE:${PROJECT_BINARY_DIR}/include/QtCore/${PROJECT_VERSION}>
+ $<BUILD_INTERFACE:${PROJECT_BINARY_DIR}/include/QtCore/${PROJECT_VERSION}/QtCore>
$<INSTALL_INTERFACE:${INSTALL_INCLUDEDIR}/QtCore/${PROJECT_VERSION}>
$<INSTALL_INTERFACE:${INSTALL_INCLUDEDIR}/QtCore/${PROJECT_VERSION}/QtCore>
)
add_library(Qt::GlobalConfigPrivate ALIAS GlobalConfigPrivate)
+add_library(${QT_CMAKE_EXPORT_NAMESPACE}::GlobalConfigPrivate ALIAS GlobalConfigPrivate)
-# Propagate minimum C++ 17 via Platform to Qt consumers (apps), after the global features
-# are computed.
-qt_set_language_standards_interface_compile_features(Platform)
-
-# By default enable utf8 sources for both Qt and Qt consumers. Can be opted out.
-qt_enable_utf8_sources(Platform)
+qt_internal_setup_public_platform_target()
# defines PlatformCommonInternal PlatformModuleInternal PlatformPluginInternal PlatformToolInternal
include(QtInternalTargets)
+qt_internal_run_common_config_tests()
+
+# Setup sanitizer options for qtbase directory scope based on features computed above.
+qt_internal_set_up_sanitizer_options()
+include("${CMAKE_CURRENT_LIST_DIR}/3rdparty/extra-cmake-modules/modules/ECMEnableSanitizers.cmake")
set(__export_targets Platform
GlobalConfig
@@ -340,49 +159,158 @@ qt_install(EXPORT ${__export_name}
DESTINATION "${__GlobalConfig_install_dir}")
qt_internal_export_modern_cmake_config_targets_file(TARGETS ${__export_targets}
- EXPORT_NAME_PREFIX ${INSTALL_CMAKE_NAMESPACE}
- CONFIG_INSTALL_DIR
- ${__GlobalConfig_install_dir})
+ EXPORT_NAME_PREFIX ${INSTALL_CMAKE_NAMESPACE}
+ CONFIG_BUILD_DIR "${__GlobalConfig_build_dir}"
+ CONFIG_INSTALL_DIR "${__GlobalConfig_install_dir}"
+)
+
+# Save minimum required CMake version to use Qt.
+qt_internal_get_supported_min_cmake_version_for_using_qt(supported_min_version_for_using_qt)
+qt_internal_get_computed_min_cmake_version_for_using_qt(computed_min_version_for_using_qt)
-## Install some QtBase specific CMake files:
+# Get the lower and upper policy range to embed into the Qt6 config file.
+qt_internal_get_min_new_policy_cmake_version(min_new_policy_version)
+qt_internal_get_max_new_policy_cmake_version(max_new_policy_version)
+
+# Get the list of public helper files that should be automatically included in Qt6Config.cmake.
+# Used in QtConfig.cmake.in template and further down for installation purposes.
+qt_internal_get_qt_build_public_helpers(__qt_cmake_public_helpers)
+list(JOIN __qt_cmake_public_helpers "\n " QT_PUBLIC_FILES_TO_INCLUDE)
+
+# Generate and install Qt6 config file. Make sure it happens after the global feature evaluation so
+# they can be accessed in the Config file if needed.
+configure_package_config_file(
+ "${PROJECT_SOURCE_DIR}/cmake/QtConfig.cmake.in"
+ "${__GlobalConfig_build_dir}/${INSTALL_CMAKE_NAMESPACE}Config.cmake"
+ INSTALL_DESTINATION "${__GlobalConfig_install_dir}"
+)
+
+_qt_internal_export_apple_sdk_and_xcode_version_requirements(QT_CONFIG_EXTRAS_CODE)
+
+configure_file(
+ "${PROJECT_SOURCE_DIR}/cmake/QtConfigExtras.cmake.in"
+ "${__GlobalConfig_build_dir}/${INSTALL_CMAKE_NAMESPACE}ConfigExtras.cmake"
+ @ONLY
+)
+
+write_basic_package_version_file(
+ "${__GlobalConfig_build_dir}/${INSTALL_CMAKE_NAMESPACE}ConfigVersionImpl.cmake"
+ VERSION ${PROJECT_VERSION}
+ COMPATIBILITY AnyNewerVersion
+)
+qt_internal_write_qt_package_version_file(
+ "${INSTALL_CMAKE_NAMESPACE}"
+ "${__GlobalConfig_build_dir}/${INSTALL_CMAKE_NAMESPACE}ConfigVersion.cmake"
+)
+
+# Compute the reverse relative path from QtConfig.cmake to the install prefix
+# this is used in QtInstallPaths to make the install paths relocatable
+if(QT_WILL_INSTALL)
+ get_filename_component(_clean_prefix
+ "${QT_BUILD_INTERNALS_RELOCATABLE_INSTALL_PREFIX}/${QT_CONFIG_INSTALL_DIR}" ABSOLUTE)
+else()
+ get_filename_component(_clean_prefix "${QT_CONFIG_BUILD_DIR}" ABSOLUTE)
+endif()
+file(RELATIVE_PATH QT_INVERSE_CONFIG_INSTALL_DIR
+ "${_clean_prefix}" "${QT_BUILD_INTERNALS_RELOCATABLE_INSTALL_PREFIX}")
+configure_file(
+ "${PROJECT_SOURCE_DIR}/cmake/QtInstallPaths.cmake.in"
+ "${__GlobalConfig_build_dir}/QtInstallPaths.cmake"
+ @ONLY
+)
+
+qt_install(FILES
+ "${__GlobalConfig_build_dir}/${INSTALL_CMAKE_NAMESPACE}Config.cmake"
+ "${__GlobalConfig_build_dir}/${INSTALL_CMAKE_NAMESPACE}ConfigExtras.cmake"
+ "${__GlobalConfig_build_dir}/${INSTALL_CMAKE_NAMESPACE}ConfigVersion.cmake"
+ "${__GlobalConfig_build_dir}/${INSTALL_CMAKE_NAMESPACE}ConfigVersionImpl.cmake"
+ "${__GlobalConfig_build_dir}/QtInstallPaths.cmake"
+ DESTINATION "${__GlobalConfig_install_dir}"
+ COMPONENT Devel
+)
+
+qt_internal_get_qt_build_private_helpers(__qt_cmake_private_helpers)
+list(TRANSFORM __qt_cmake_private_helpers PREPEND "cmake/")
+list(TRANSFORM __qt_cmake_private_helpers APPEND ".cmake")
+
+qt_internal_get_qt_build_private_files_to_install(__qt_private_files_to_install)
+list(TRANSFORM __qt_private_files_to_install PREPEND "cmake/")
+
+# Install internal CMake files.
+# The functions defined inside can not be used in public projects.
+# They can only be used while building Qt itself.
+set(__private_files
+ ${__qt_cmake_private_helpers}
+ ${__qt_private_files_to_install}
+)
qt_copy_or_install(FILES
- cmake/ModuleDescription.json.in
- cmake/Qt3rdPartyLibraryConfig.cmake.in
- cmake/QtApp.cmake
- cmake/QtBuild.cmake
- cmake/QtBuildInformation.cmake
- cmake/QtCompilerFlags.cmake
- cmake/QtCompilerOptimization.cmake
- cmake/QtFeature.cmake
- cmake/QtFinishPrlFile.cmake
- cmake/QtFindWrapHelper.cmake
- cmake/QtFindWrapConfigExtra.cmake.in
- cmake/QtFileConfigure.txt.in
- cmake/QtGenerateExtPri.cmake
- cmake/QtGenerateLibPri.cmake
- cmake/QtGenerateLibHelpers.cmake
- cmake/QtPlatformSupport.cmake
- cmake/QtPlatformAndroid.cmake
- cmake/QtPostProcess.cmake
- cmake/QtSeparateDebugInfo.Info.plist.in
- cmake/QtSeparateDebugInfo.cmake
- cmake/QtSetup.cmake
- cmake/QtModuleConfig.cmake.in
- cmake/QtModuleDependencies.cmake.in
- cmake/QtModuleToolsDependencies.cmake.in
- cmake/QtModuleToolsConfig.cmake.in
- cmake/QtModuleToolsVersionlessTargets.cmake.in
- cmake/QtStandaloneTestsConfig.cmake.in
- cmake/QtPlugins.cmake.in
- cmake/QtPluginConfig.cmake.in
- cmake/QtPluginDependencies.cmake.in
+ ${__private_files}
DESTINATION "${__GlobalConfig_install_dir}"
)
-file(COPY cmake/QtFeature.cmake DESTINATION "${__GlobalConfig_build_dir}")
+# Install our custom platform modules.
+qt_copy_or_install(DIRECTORY cmake/platforms
+ DESTINATION "${__GlobalConfig_install_dir}"
+)
+
+# Install public config.tests files.
+qt_copy_or_install(DIRECTORY
+ "config.tests/static_link_order"
+ "config.tests/binary_for_strip"
+ DESTINATION "${__GlobalConfig_install_dir}/config.tests"
+)
+
+# Install qt-internal-strip and qt-internal-ninja files.
+set(__qt_internal_strip_wrappers
+ libexec/qt-internal-strip.in
+ libexec/qt-internal-strip.bat.in
+ libexec/qt-internal-ninja.in
+ libexec/qt-internal-ninja.bat.in
+)
+qt_copy_or_install(PROGRAMS
+ ${__qt_internal_strip_wrappers}
+ DESTINATION "${__GlobalConfig_install_dir}/libexec"
+)
+if(QT_WILL_INSTALL)
+ foreach(__qt_internal_strip_wrapper ${__qt_internal_strip_wrappers})
+ file(COPY "${__qt_internal_strip_wrapper}"
+ DESTINATION "${__GlobalConfig_build_dir}/libexec")
+ endforeach()
+endif()
+
+# Wrap previously queried helpers file.
+list(TRANSFORM __qt_cmake_public_helpers PREPEND "cmake/")
+list(TRANSFORM __qt_cmake_public_helpers APPEND ".cmake")
+
+qt_internal_get_qt_build_public_files_to_install(__qt_public_files_to_install)
+list(TRANSFORM __qt_public_files_to_install PREPEND "cmake/")
+
+# Install public CMake files.
+# The functions defined inside can be used in both public projects and while building Qt.
+# Usually we put such functions into Qt6CoreMacros.cmake, but that's getting bloated.
+# These files will be included by Qt6Config.cmake.
+set(__public_files
+ ${__qt_cmake_public_helpers}
+ ${__qt_public_files_to_install}
+)
+
+qt_copy_or_install(FILES ${__public_files} DESTINATION "${__GlobalConfig_install_dir}")
+
+# In prefix builds we also need to copy the files into the build config directory, so that the
+# build-dir Qt6Config.cmake finds the files when building examples in-tree.
+if(QT_WILL_INSTALL)
+ foreach(_public_file ${__public_files})
+ file(COPY "${_public_file}" DESTINATION "${__GlobalConfig_build_dir}")
+ endforeach()
+endif()
+
+qt_copy_or_install(DIRECTORY "cmake/3rdparty" DESTINATION "${__GlobalConfig_install_dir}")
-# TODO: Check whether this is the right place to install these
-qt_copy_or_install(DIRECTORY cmake/3rdparty DESTINATION "${__GlobalConfig_install_dir}")
+# In prefix builds we also need to copy the files into the build config directory, so that the
+# build-dir Qt6Config.cmake finds the files when building other repos in a top-level build.
+if(QT_WILL_INSTALL)
+ file(COPY "cmake/3rdparty" DESTINATION "${__GlobalConfig_build_dir}")
+endif()
# Install our custom Find modules, which will be used by the find_dependency() calls
# inside the generated ModuleDependencies cmake files.
@@ -391,11 +319,78 @@ qt_copy_or_install(DIRECTORY cmake/
FILES_MATCHING PATTERN "Find*.cmake"
PATTERN "tests" EXCLUDE
PATTERN "3rdparty" EXCLUDE
+ PATTERN "macos" EXCLUDE
+ PATTERN "ios" EXCLUDE
+ PATTERN "visionos" EXCLUDE
+ PATTERN "platforms" EXCLUDE
+ PATTERN "QtBuildInternals" EXCLUDE
)
-if(MACOS)
- qt_copy_or_install(FILES
- cmake/macos/MacOSXBundleInfo.plist.in
- DESTINATION "${__GlobalConfig_install_dir}/macos"
+# In prefix builds we also need to copy the files into the build config directory, so that the
+# build-dir Qt6Config.cmake finds the files when building examples as ExternalProjects.
+if(QT_WILL_INSTALL)
+ file(COPY cmake/
+ DESTINATION "${__GlobalConfig_build_dir}"
+ FILES_MATCHING PATTERN "Find*.cmake"
+ PATTERN "tests" EXCLUDE
+ PATTERN "3rdparty" EXCLUDE
+ PATTERN "macos" EXCLUDE
+ PATTERN "ios" EXCLUDE
+ PATTERN "visionos" EXCLUDE
+ PATTERN "platforms" EXCLUDE
+ PATTERN "QtBuildInternals" EXCLUDE
+ )
+endif()
+
+if(APPLE)
+ if(MACOS)
+ set(platform_shortname "macos")
+ elseif(IOS)
+ set(platform_shortname "ios")
+ elseif(VISIONOS)
+ set(platform_shortname "visionos")
+ endif()
+
+ # Info.plist
+ qt_copy_or_install(FILES "cmake/${platform_shortname}/Info.plist.app.in"
+ DESTINATION "${__GlobalConfig_install_dir}/${platform_shortname}"
+ )
+ # For examples built as part of prefix build before install
+ file(COPY "cmake/${platform_shortname}/Info.plist.app.in"
+ DESTINATION "${__GlobalConfig_build_dir}/${platform_shortname}"
+ )
+
+ # Privacy manifest
+ qt_copy_or_install(FILES "cmake/${platform_shortname}/PrivacyInfo.xcprivacy"
+ DESTINATION "${__GlobalConfig_install_dir}/${platform_shortname}"
+ )
+ # For examples built as part of prefix build before install
+ file(COPY "cmake/${platform_shortname}/PrivacyInfo.xcprivacy"
+ DESTINATION "${__GlobalConfig_build_dir}/${platform_shortname}"
)
+
+ if(IOS)
+ qt_copy_or_install(FILES "cmake/ios/LaunchScreen.storyboard"
+ DESTINATION "${__GlobalConfig_install_dir}/ios"
+ )
+ # For examples built as part of prefix build before install
+ file(COPY "cmake/ios/LaunchScreen.storyboard"
+ DESTINATION "${__GlobalConfig_build_dir}/ios"
+ )
+ endif()
+elseif(WASM)
+ configure_file("${CMAKE_CURRENT_SOURCE_DIR}/util/wasm/wasmtestrunner/qt-wasmtestrunner.py"
+ "${QT_BUILD_DIR}/${INSTALL_LIBEXECDIR}/qt-wasmtestrunner.py" @ONLY)
+
+ qt_install(PROGRAMS "${QT_BUILD_DIR}/${INSTALL_LIBEXECDIR}/qt-wasmtestrunner.py"
+ DESTINATION "${INSTALL_LIBEXECDIR}")
endif()
+
+# Install CI support files to libexec.
+qt_path_join(__qt_libexec_install_dir "${QT_INSTALL_DIR}" "${INSTALL_LIBEXECDIR}")
+qt_copy_or_install(FILES coin/instructions/qmake/ensure_pro_file.cmake
+ DESTINATION "${__qt_libexec_install_dir}")
+qt_copy_or_install(PROGRAMS "util/testrunner/qt-testrunner.py"
+ DESTINATION "${__qt_libexec_install_dir}")
+qt_copy_or_install(PROGRAMS "util/testrunner/sanitizer-testrunner.py"
+ DESTINATION "${__qt_libexec_install_dir}")
diff --git a/cmake/QtBaseHelpers.cmake b/cmake/QtBaseHelpers.cmake
new file mode 100644
index 0000000000..a16f6987b4
--- /dev/null
+++ b/cmake/QtBaseHelpers.cmake
@@ -0,0 +1,222 @@
+# Copyright (C) 2024 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+#
+# Note that this file is not installed.
+
+# Bail out if any part of the build directory's path is symlinked.
+function(qt_internal_check_if_path_has_symlinks path)
+ get_filename_component(dir "${path}" ABSOLUTE)
+ set(is_symlink FALSE)
+ if(CMAKE_HOST_WIN32)
+ # CMake marks Windows mount points as symbolic links, so use simplified REALPATH check
+ # on Windows platforms instead of IS_SYMLINK.
+ get_filename_component(dir_realpath "${dir}" REALPATH)
+ if(NOT dir STREQUAL dir_realpath)
+ set(is_symlink TRUE)
+ endif()
+ else()
+ while(TRUE)
+ if(IS_SYMLINK "${dir}")
+ set(is_symlink TRUE)
+ break()
+ endif()
+
+ set(prev_dir "${dir}")
+ get_filename_component(dir "${dir}" DIRECTORY)
+ if("${dir}" STREQUAL "${prev_dir}")
+ return()
+ endif()
+ endwhile()
+ endif()
+ if(is_symlink)
+ set(possible_solutions_for_resolving_symlink [[
+ - Map directories using a transparent mechanism such as mount --bind
+ - Pass the real path of the build directory to CMake, e.g. using
+ cd $(realpath <path>) before invoking cmake <source_dir>.
+ ]])
+ if(QT_ALLOW_SYMLINK_IN_PATHS)
+ # In some cases, e.g., Homebrew, it is beneficial to skip this check.
+ # Before this, Homebrew had to patch this out to be able to get their build.
+ message(WARNING
+ "The path \"${path}\" contains symlinks. "
+ "This is not recommended, and it may lead to unexpected issues. If you do "
+ "not have a good reason for enabling 'QT_ALLOW_SYMLINK_IN_PATHS', disable "
+ "it, and follow one of the following solutions: \n"
+ "${possible_solutions_for_resolving_symlink} ")
+ else()
+ message(FATAL_ERROR
+ "The path \"${path}\" contains symlinks. "
+ "This is not supported. Possible solutions: \n"
+ "${possible_solutions_for_resolving_symlink} ")
+ endif()
+ endif()
+endfunction()
+
+# There are three necessary copies of this macro in
+# qtbase/cmake/QtBaseHelpers.cmake
+# qtbase/cmake/QtBaseTopLevelHelpers.cmake
+# qtbase/cmake/QtBuildRepoHelpers.cmake
+macro(qt_internal_qtbase_setup_standalone_parts)
+ # A generic marker for any kind of standalone builds, either tests or examples.
+ if(NOT DEFINED QT_INTERNAL_BUILD_STANDALONE_PARTS
+ AND (QT_BUILD_STANDALONE_TESTS OR QT_BUILD_STANDALONE_EXAMPLES))
+ set(QT_INTERNAL_BUILD_STANDALONE_PARTS TRUE CACHE INTERNAL
+ "Whether standalone tests or examples are being built")
+ endif()
+endmacro()
+
+macro(qt_internal_qtbase_run_autodetect)
+ qt_internal_qtbase_setup_standalone_parts()
+
+ # Run auto detection routines, but not when doing standalone tests or standalone examples.
+ # In that case, the detection
+ # results are taken from either QtBuildInternals or the qt.toolchain.cmake file. Also, inhibit
+ # auto-detection in a top-level build, because the top-level project file already includes it.
+ if(NOT QT_INTERNAL_BUILD_STANDALONE_PARTS AND NOT QT_SUPERBUILD)
+ include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/QtAutoDetect.cmake)
+ endif()
+endmacro()
+
+macro(qt_internal_qtbase_pre_project_setup)
+ if(NOT QT_INTERNAL_BUILD_STANDALONE_PARTS)
+ # Should this Qt be static or dynamically linked?
+ option(BUILD_SHARED_LIBS "Build Qt statically or dynamically" ON)
+ set(QT_BUILD_SHARED_LIBS ${BUILD_SHARED_LIBS})
+
+ # This variable is also set in Qt6CoreConfigExtras.cmake, but it's not loaded when building
+ # qtbase. Set it here so qt_add_plugin can compute the proper plugin flavor.
+ set(QT6_IS_SHARED_LIBS_BUILD ${BUILD_SHARED_LIBS})
+
+ # BUILD_SHARED_LIBS influences the minimum required CMake version. The value is set either
+ # by:
+ # a cache variable provided on the configure command line
+ # or set by QtAutoDetect.cmake depending on the platform
+ # or specified via a toolchain file that is loaded by the project() call
+ # or set by the option() call above
+ include("${CMAKE_CURRENT_SOURCE_DIR}/cmake/QtCMakeVersionHelpers.cmake")
+ include("${CMAKE_CURRENT_SOURCE_DIR}/cmake/QtPublicCMakeVersionHelpers.cmake")
+ qt_internal_check_and_warn_about_unsuitable_cmake_version()
+
+ ## Add some paths to check for cmake modules:
+ list(PREPEND CMAKE_MODULE_PATH
+ "${CMAKE_CURRENT_SOURCE_DIR}/cmake"
+ "${CMAKE_CURRENT_SOURCE_DIR}/cmake/3rdparty/extra-cmake-modules/find-modules"
+ "${CMAKE_CURRENT_SOURCE_DIR}/cmake/3rdparty/kwin"
+ )
+
+ if(MACOS)
+ # Add module directory to pick up custom Info.plist template
+ list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/macos")
+ elseif(IOS)
+ # Add module directory to pick up custom Info.plist template
+ list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/ios")
+ endif()
+
+ ## Find the build internals package.
+ set(QT_BUILD_INTERNALS_SKIP_CMAKE_MODULE_PATH_ADDITION TRUE)
+ list(PREPEND CMAKE_PREFIX_PATH
+ "${CMAKE_CURRENT_SOURCE_DIR}/cmake"
+ )
+ find_package(QtBuildInternals CMAKE_FIND_ROOT_PATH_BOTH)
+ unset(QT_BUILD_INTERNALS_SKIP_CMAKE_MODULE_PATH_ADDITION)
+ else()
+ # When building standalone parts, an istalled BuildInternals package already exists.
+ find_package(Qt6 REQUIRED COMPONENTS BuildInternals CMAKE_FIND_ROOT_PATH_BOTH)
+ endif()
+endmacro()
+
+macro(qt_internal_qtbase_install_mkspecs)
+ # As long as we use the mkspecs (for qplatformdefs.h), we need to always
+ # install it, especially when cross-compiling.
+ set(mkspecs_install_dir "${INSTALL_MKSPECSDIR}")
+ qt_path_join(mkspecs_install_dir ${QT_INSTALL_DIR} ${mkspecs_install_dir})
+
+ file(GLOB mkspecs_subdirs
+ LIST_DIRECTORIES TRUE
+ "${PROJECT_SOURCE_DIR}/mkspecs/*")
+ foreach(entry IN LISTS mkspecs_subdirs)
+ if (IS_DIRECTORY ${entry})
+ qt_copy_or_install(DIRECTORY "${entry}"
+ DESTINATION ${mkspecs_install_dir}
+ USE_SOURCE_PERMISSIONS)
+ else()
+ qt_copy_or_install(FILES "${entry}"
+ DESTINATION ${mkspecs_install_dir})
+ endif()
+ endforeach()
+endmacro()
+
+macro(qt_internal_qtbase_build_repo)
+ qt_internal_qtbase_pre_project_setup()
+
+ qt_internal_project_setup()
+
+ qt_build_repo_begin()
+
+ if(NOT QT_INTERNAL_BUILD_STANDALONE_PARTS)
+ ## Should this Qt be built with Werror?
+ option(WARNINGS_ARE_ERRORS "Build Qt with warnings as errors" ${FEATURE_developer_build})
+
+ ## Should this Qt create versioned hard link for some tools?
+ option(QT_CREATE_VERSIONED_HARD_LINK "Enable the use of versioned hard link" ON)
+
+ ## QtBase specific configure tests:
+ include(QtBaseConfigureTests)
+
+ ## Build System tests:
+ include(QtBaseCMakeTesting)
+
+ ## Targets for global features, etc.:
+ include(QtBaseGlobalTargets)
+
+ ## Set language standards after QtBaseGlobalTargets, because that's when the relevant
+ ## feature variables are available.
+ qt_set_language_standards()
+
+ #include CoreMacros() for qt6_generate_meta_types()
+ set(QT_DEFAULT_MAJOR_VERSION 6)
+ include(src/corelib/Qt6CoreMacros.cmake)
+
+ # Needed when building qtbase for android.
+ if(ANDROID)
+ include(src/corelib/Qt6AndroidMacros.cmake)
+ _qt_internal_create_global_android_targets()
+ endif()
+
+ if(WASM)
+ # Needed when building for WebAssembly.
+ include(cmake/QtWasmHelpers.cmake)
+ include(src/corelib/Qt6WasmMacros.cmake)
+ qt_internal_setup_wasm_target_properties(Platform)
+ endif()
+
+ # Set up optimization flags like in qmake.
+ # This function must be called after the global QT_FEATURE_xxx variables have been set up,
+ # aka after QtBaseGlobalTargets is processed.
+ # It also has to be called /before/ adding add_subdirectory(src), so that per-directory
+ # modifications can still be applied if necessary (like in done in Core and Gui).
+ qt_internal_set_up_config_optimizations_like_in_qmake()
+
+ ## Setup documentation
+ add_subdirectory(doc)
+
+ ## Visit all the directories:
+ add_subdirectory(src)
+ endif()
+
+ if(NOT QT_INTERNAL_BUILD_STANDALONE_PARTS)
+ if(QT_WILL_BUILD_TOOLS AND QT_FEATURE_settings)
+ add_subdirectory(qmake)
+ endif()
+
+ qt_internal_qtbase_install_mkspecs()
+ endif()
+
+ qt_build_repo_post_process()
+
+ qt_build_repo_impl_tests()
+
+ qt_build_repo_end()
+
+ qt_build_repo_impl_examples()
+endmacro()
diff --git a/cmake/QtBaseTopLevelHelpers.cmake b/cmake/QtBaseTopLevelHelpers.cmake
new file mode 100644
index 0000000000..07893b6cec
--- /dev/null
+++ b/cmake/QtBaseTopLevelHelpers.cmake
@@ -0,0 +1,96 @@
+# Copyright (C) 2023 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+# There are three necessary copies of this macro in
+# qtbase/cmake/QtBaseHelpers.cmake
+# qtbase/cmake/QtBaseTopLevelHelpers.cmake
+# qtbase/cmake/QtBuildRepoHelpers.cmake
+macro(qt_internal_top_level_setup_standalone_parts)
+ # A generic marker for any kind of standalone builds, either tests or examples.
+ if(NOT DEFINED QT_INTERNAL_BUILD_STANDALONE_PARTS
+ AND (QT_BUILD_STANDALONE_TESTS OR QT_BUILD_STANDALONE_EXAMPLES))
+ set(QT_INTERNAL_BUILD_STANDALONE_PARTS TRUE CACHE INTERNAL
+ "Whether standalone tests or examples are being built")
+ endif()
+endmacro()
+
+# Depends on __qt6_qtbase_src_path being set in the top-level dir.
+macro(qt_internal_top_level_setup_autodetect)
+ qt_internal_top_level_setup_standalone_parts()
+
+ # Run platform auto-detection /before/ the first project() call and thus
+ # before the toolchain file is loaded.
+ # Don't run auto-detection when doing standalone tests. In that case, the detection
+ # results are taken from either QtBuildInternals or the qt.toolchain.cmake file.
+
+ if(NOT QT_INTERNAL_BUILD_STANDALONE_PARTS)
+ set(__qt6_auto_detect_path "${__qt6_qtbase_src_path}/cmake/QtAutoDetect.cmake")
+ if(NOT EXISTS "${__qt6_auto_detect_path}")
+ message(FATAL_ERROR "Required file does not exist: '${__qt6_auto_detect_path}'")
+ endif()
+ include("${__qt6_auto_detect_path}")
+ endif()
+endmacro()
+
+macro(qt_internal_top_level_setup_after_project)
+ qt_internal_top_level_setup_testing()
+endmacro()
+
+macro(qt_internal_top_level_setup_testing)
+ # Required so we can call ctest from the root build directory
+ enable_testing()
+endmacro()
+
+# Depends on __qt6_qtbase_src_path being set in the top-level dir.
+macro(qt_internal_top_level_setup_cmake_module_path)
+ if (NOT QT_INTERNAL_BUILD_STANDALONE_PARTS)
+ set(__qt6_cmake_module_path "${__qt6_qtbase_src_path}/cmake")
+ if(NOT EXISTS "${__qt6_cmake_module_path}")
+ message(FATAL_ERROR "Required directory does not exist: '${__qt6_cmake_module_path}'")
+ endif()
+
+ list(APPEND CMAKE_MODULE_PATH "${__qt6_cmake_module_path}")
+
+ list(APPEND CMAKE_MODULE_PATH
+ "${__qt6_cmake_module_path}/3rdparty/extra-cmake-modules/find-modules")
+ list(APPEND CMAKE_MODULE_PATH "${__qt6_cmake_module_path}/3rdparty/kwin")
+ endif()
+endmacro()
+
+macro(qt_internal_top_level_before_build_submodules)
+ qt_internal_top_level_setup_no_create_targets()
+endmacro()
+
+macro(qt_internal_top_level_setup_no_create_targets)
+ # Also make sure the CMake config files do not recreate the already-existing targets
+ if (NOT QT_INTERNAL_BUILD_STANDALONE_PARTS)
+ set(QT_NO_CREATE_TARGETS TRUE)
+ endif()
+endmacro()
+
+macro(qt_internal_top_level_end)
+ qt_internal_print_top_level_info()
+
+ # Depends on QtBuildInternalsConfig being included, which is the case whenver any repo is
+ # configured.
+ qt_internal_qt_configure_end()
+endmacro()
+
+function(qt_internal_print_top_level_info)
+ if(NOT QT_INTERNAL_BUILD_STANDALONE_PARTS)
+ # Display a summary of everything
+ include(QtBuildInformation)
+ include(QtPlatformSupport)
+ qt_print_feature_summary()
+ qt_print_build_instructions()
+ endif()
+endfunction()
+
+macro(qt_internal_top_level_after_add_subdirectory)
+ if(module STREQUAL "qtbase")
+ if (NOT QT_INTERNAL_BUILD_STANDALONE_PARTS)
+ list(APPEND CMAKE_PREFIX_PATH "${QtBase_BINARY_DIR}/${INSTALL_LIBDIR}/cmake")
+ list(APPEND CMAKE_FIND_ROOT_PATH "${QtBase_BINARY_DIR}")
+ endif()
+ endif()
+endmacro()
diff --git a/cmake/QtBuild.cmake b/cmake/QtBuild.cmake
index f957d87332..ee24ba188e 100644
--- a/cmake/QtBuild.cmake
+++ b/cmake/QtBuild.cmake
@@ -1,6143 +1,4 @@
-include(CMakePackageConfigHelpers)
-include(QtSeparateDebugInfo)
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
-function(qt_configure_process_path name default docstring)
- # Values are computed once for qtbase, and then exported and reused for other projects.
- if(NOT PROJECT_NAME STREQUAL "QtBase")
- return()
- endif()
-
- # No value provided, set the default.
- if(NOT DEFINED "${name}")
- set("${name}" "${default}" CACHE STRING "${docstring}")
- else()
- get_filename_component(given_path_as_abs "${${name}}" ABSOLUTE BASE_DIR
- "${CMAKE_INSTALL_PREFIX}")
- file(RELATIVE_PATH rel_path "${CMAKE_INSTALL_PREFIX}"
- "${given_path_as_abs}")
-
- # If absolute path given, check that it's inside the prefix (error out if not).
- # TODO: Figure out if we need to support paths that are outside the prefix.
- #
- # If relative path given, it's relative to the install prefix (rather than the binary dir,
- # which is what qmake does for some reason).
- # In both cases, store the value as a relative path.
- if("${rel_path}" STREQUAL "")
- # file(RELATIVE_PATH) returns an empty string if the given absolute paths are equal
- set(rel_path ".")
- elseif(rel_path MATCHES "^\.\./")
- message(FATAL_ERROR
- "Path component '${name}' is outside computed install prefix: ${rel_path} ")
- endif()
- set("${name}" "${rel_path}" CACHE STRING "${docstring}" FORCE)
- endif()
-endfunction()
-
-# Install locations:
-qt_configure_process_path(INSTALL_BINDIR "bin" "Executables [PREFIX/bin]")
-qt_configure_process_path(INSTALL_INCLUDEDIR "include" "Header files [PREFIX/include]")
-qt_configure_process_path(INSTALL_LIBDIR "lib" "Libraries [PREFIX/lib]")
-qt_configure_process_path(INSTALL_MKSPECSDIR "mkspecs" "Mkspecs files [PREFIX/mkspecs]")
-qt_configure_process_path(INSTALL_ARCHDATADIR "." "Arch-dependent data [PREFIX]")
-qt_configure_process_path(INSTALL_PLUGINSDIR
- "${INSTALL_ARCHDATADIR}/plugins"
- "Plugins [ARCHDATADIR/plugins]")
-
-# Given CMAKE_CONFIG and ALL_CMAKE_CONFIGS, determines if a directory suffix needs to be appended
-# to each destination, and sets the computed install target destination arguments in OUT_VAR.
-# Defaults used for each of the destination types, and can be configured per destination type.
-function(qt_get_install_target_default_args)
- qt_parse_all_arguments(arg "qt_get_install_target_default_args"
- "" "OUT_VAR;CMAKE_CONFIG;RUNTIME;LIBRARY;ARCHIVE;INCLUDES;BUNDLE"
- "ALL_CMAKE_CONFIGS" ${ARGN})
-
- if(NOT arg_CMAKE_CONFIG)
- message(FATAL_ERROR "No value given for CMAKE_CONFIG.")
- endif()
- if(NOT arg_ALL_CMAKE_CONFIGS)
- message(FATAL_ERROR "No value given for ALL_CMAKE_CONFIGS.")
- endif()
- list(LENGTH arg_ALL_CMAKE_CONFIGS all_configs_count)
- list(GET arg_ALL_CMAKE_CONFIGS 0 first_config)
-
- set(suffix "")
- if(all_configs_count GREATER 1 AND NOT arg_CMAKE_CONFIG STREQUAL first_config)
- set(suffix "/${arg_CMAKE_CONFIG}")
- endif()
-
- set(runtime "${INSTALL_BINDIR}")
- if(arg_RUNTIME)
- set(runtime "${arg_RUNTIME}")
- endif()
-
- set(library "${INSTALL_LIBDIR}")
- if(arg_LIBRARY)
- set(library "${arg_LIBRARY}")
- endif()
-
- set(archive "${INSTALL_LIBDIR}")
- if(arg_ARCHIVE)
- set(archive "${arg_ARCHIVE}")
- endif()
-
- set(includes "${INSTALL_INCLUDEDIR}")
- if(arg_INCLUDES)
- set(includes "${arg_INCLUDES}")
- endif()
-
- set(bundle "${INSTALL_BINDIR}")
- if(arg_BUNDLE)
- set(bundle "${arg_BUNDLE}")
- endif()
-
- set(args
- RUNTIME DESTINATION "${runtime}${suffix}"
- LIBRARY DESTINATION "${library}${suffix}"
- ARCHIVE DESTINATION "${archive}${suffix}" COMPONENT Devel
- BUNDLE DESTINATION "${bundle}${suffix}"
- INCLUDES DESTINATION "${includes}${suffix}")
- set(${arg_OUT_VAR} "${args}" PARENT_SCOPE)
-endfunction()
-
-if (WIN32)
- set(_default_libexec "${INSTALL_ARCHDATADIR}/bin")
-else()
- set(_default_libexec "${INSTALL_ARCHDATADIR}/libexec")
-endif()
-
-qt_configure_process_path(
- INSTALL_LIBEXECDIR
- "${_default_libexec}"
- "Helper programs [ARCHDATADIR/bin on Windows, ARCHDATADIR/libexec otherwise]")
-qt_configure_process_path(INSTALL_QMLDIR
- "${INSTALL_ARCHDATADIR}/qml"
- "QML2 imports [ARCHDATADIR/qml]")
-qt_configure_process_path(INSTALL_DATADIR "." "Arch-independent data [PREFIX]")
-qt_configure_process_path(INSTALL_DOCDIR "${INSTALL_DATADIR}/doc" "Documentation [DATADIR/doc]")
-qt_configure_process_path(INSTALL_TRANSLATIONSDIR "${INSTALL_DATADIR}/translations"
- "Translations [DATADIR/translations]")
-qt_configure_process_path(INSTALL_SYSCONFDIR
- "etc/xdg"
- "Settings used by Qt programs [PREFIX/etc/xdg]")
-qt_configure_process_path(INSTALL_EXAMPLESDIR "examples" "Examples [PREFIX/examples]")
-qt_configure_process_path(INSTALL_TESTSDIR "tests" "Tests [PREFIX/tests]")
-qt_configure_process_path(INSTALL_DESCRIPTIONSDIR
- "${INSTALL_DATADIR}/modules"
- "Module description files directory")
-
-if(CMAKE_CROSSCOMPILING AND NOT "${CMAKE_STAGING_PREFIX}" STREQUAL "")
- set(QT_STAGING_PREFIX "${CMAKE_STAGING_PREFIX}")
-else()
- set(QT_STAGING_PREFIX "${CMAKE_INSTALL_PREFIX}")
-endif()
-
-function(qt_internal_set_up_global_paths)
- # Compute the values of QT_BUILD_DIR, QT_INSTALL_DIR, QT_CONFIG_BUILD_DIR, QT_CONFIG_INSTALL_DIR
- # taking into account whether the current build is a prefix build or a non-prefix build,
- # and whether it is a superbuild or non-superbuild.
- # A third case is when another module or standalone tests are built against a super-built Qt.
- # The layout for the third case is the same as for non-superbuilds.
- #
- # These values should be prepended to file paths in commands or properties,
- # in order to correctly place generated Config files, generated Targets files,
- # excutables / libraries, when copying / installing files, etc.
- #
- # The build dir variables will always be absolute paths.
- # The QT_INSTALL_DIR variable will have a relative path in a prefix build,
- # which means that it can be empty, so use qt_join_path to prevent accidental absolute paths.
- if(QT_SUPERBUILD)
- # In this case, we always copy all the build products in qtbase/{bin,lib,...}
- if(QT_WILL_INSTALL)
- set(QT_BUILD_DIR "${QtBase_BINARY_DIR}")
- set(QT_INSTALL_DIR "")
- else()
- if("${CMAKE_STAGING_PREFIX}" STREQUAL "")
- set(QT_BUILD_DIR "${QtBase_BINARY_DIR}")
- set(QT_INSTALL_DIR "${QtBase_BINARY_DIR}")
- else()
- set(QT_BUILD_DIR "${CMAKE_STAGING_PREFIX}")
- set(QT_INSTALL_DIR "${CMAKE_STAGING_PREFIX}")
- endif()
- endif()
- else()
- if(QT_WILL_INSTALL)
- # In the usual prefix build case, the build dir is the current module build dir,
- # and the install dir is the prefix, so we don't set it.
- set(QT_BUILD_DIR "${CMAKE_BINARY_DIR}")
- set(QT_INSTALL_DIR "")
- else()
- # When doing a non-prefix build, both the build dir and install dir are the same,
- # pointing to the qtbase build dir.
- set(QT_BUILD_DIR "${QT_STAGING_PREFIX}")
- set(QT_INSTALL_DIR "${QT_BUILD_DIR}")
- endif()
- endif()
-
- set(__config_path_part "${INSTALL_LIBDIR}/cmake")
- set(QT_CONFIG_BUILD_DIR "${QT_BUILD_DIR}/${__config_path_part}")
- set(QT_CONFIG_INSTALL_DIR "${QT_INSTALL_DIR}")
- if(QT_CONFIG_INSTALL_DIR)
- string(APPEND QT_CONFIG_INSTALL_DIR "/")
- endif()
- string(APPEND QT_CONFIG_INSTALL_DIR ${__config_path_part})
-
- set(QT_BUILD_DIR "${QT_BUILD_DIR}" PARENT_SCOPE)
- set(QT_INSTALL_DIR "${QT_INSTALL_DIR}" PARENT_SCOPE)
- set(QT_CONFIG_BUILD_DIR "${QT_CONFIG_BUILD_DIR}" PARENT_SCOPE)
- set(QT_CONFIG_INSTALL_DIR "${QT_CONFIG_INSTALL_DIR}" PARENT_SCOPE)
-endfunction()
-qt_internal_set_up_global_paths()
-qt_get_relocatable_install_prefix(QT_BUILD_INTERNALS_RELOCATABLE_INSTALL_PREFIX)
-
-# The variables might have already been set in QtBuildInternalsExtra.cmake if the file is included
-# while building a new module and not QtBase. In that case, stop overriding the value.
-if(NOT INSTALL_CMAKE_NAMESPACE)
- set(INSTALL_CMAKE_NAMESPACE "Qt${PROJECT_VERSION_MAJOR}"
- CACHE STRING "CMake namespace [Qt${PROJECT_VERSION_MAJOR}]")
-endif()
-if(NOT QT_CMAKE_EXPORT_NAMESPACE)
- set(QT_CMAKE_EXPORT_NAMESPACE "Qt${PROJECT_VERSION_MAJOR}"
- CACHE STRING "CMake namespace used when exporting targets [Qt${PROJECT_VERSION_MAJOR}]")
-endif()
-
-set(QT_CMAKE_DIR "${CMAKE_CURRENT_LIST_DIR}")
-
-# Find the path to mkspecs/, depending on whether we are building as part of a standard qtbuild,
-# or a module against an already installed version of qt.
-if(NOT QT_MKSPECS_DIR)
- if("${QT_BUILD_INTERNALS_PATH}" STREQUAL "")
- get_filename_component(QT_MKSPECS_DIR "${CMAKE_CURRENT_LIST_DIR}/../mkspecs" ABSOLUTE)
- else()
- # We can rely on QT_BUILD_INTERNALS_RELOCATABLE_INSTALL_PREFIX being set by
- # QtBuildInternalsExtra.cmake.
- get_filename_component(
- QT_MKSPECS_DIR
- "${QT_BUILD_INTERNALS_RELOCATABLE_INSTALL_PREFIX}/${INSTALL_MKSPECSDIR}" ABSOLUTE)
- endif()
- set(QT_MKSPECS_DIR "${QT_MKSPECS_DIR}" CACHE INTERNAL "")
-endif()
-
-# the default RPATH to be used when installing, but only if it's not a system directory
-list(FIND CMAKE_PLATFORM_IMPLICIT_LINK_DIRECTORIES "${CMAKE_INSTALL_PREFIX}/${INSTALL_LIBDIR}" isSystemDir)
-if("${isSystemDir}" STREQUAL "-1")
- set(_default_install_rpath "${CMAKE_INSTALL_PREFIX}/${INSTALL_LIBDIR}")
-endif("${isSystemDir}" STREQUAL "-1")
-
-# The default rpath settings for installed targets is empty.
-# The rpaths will instead be computed for each target separately using qt_apply_rpaths().
-# Additional rpaths can be passed via QT_EXTRA_RPATHS.
-# By default this will include $ORIGIN / @loader_path, so the installation is relocatable.
-# Bottom line: No need to pass anything to CMAKE_INSTALL_RPATH.
-set(CMAKE_INSTALL_RPATH "" CACHE STRING "RPATH for installed binaries")
-
-# add the automatically determined parts of the RPATH
-# which point to directories outside the build tree to the install RPATH
-set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE)
-
-# Generate a module description file based on the template in ModuleDescription.json.in
-function(qt_describe_module target)
- set(path_suffix "${INSTALL_DESCRIPTIONSDIR}")
- qt_path_join(build_dir ${QT_BUILD_DIR} ${path_suffix})
- qt_path_join(install_dir ${QT_INSTALL_DIR} ${path_suffix})
-
- set(descfile_in "${QT_CMAKE_DIR}/ModuleDescription.json.in")
- set(descfile_out "${build_dir}/${target}.json")
- set(cross_compilation "false")
- if(CMAKE_CROSSCOMPILING)
- set(cross_compilation "true")
- endif()
- configure_file("${descfile_in}" "${descfile_out}")
-
- qt_install(FILES "${descfile_out}" DESTINATION "${install_dir}")
-endfunction()
-
-function(qt_setup_tool_path_command)
- if(NOT WIN32)
- return()
- endif()
- set(bindir "${QT_BUILD_INTERNALS_RELOCATABLE_INSTALL_PREFIX}/${INSTALL_BINDIR}")
- file(TO_NATIVE_PATH "${bindir}" bindir)
- list(APPEND command COMMAND)
- list(APPEND command set \"PATH=${bindir}$<SEMICOLON>%PATH%\")
- set(QT_TOOL_PATH_SETUP_COMMAND "${command}" CACHE INTERNAL "internal command prefix for tool invocations" FORCE)
-endfunction()
-qt_setup_tool_path_command()
-
-# Platform define path, etc.
-if(WIN32)
- set(QT_DEFAULT_PLATFORM_DEFINITIONS UNICODE _UNICODE WIN32 _ENABLE_EXTENDED_ALIGNED_STORAGE)
- if(CMAKE_SIZEOF_VOID_P EQUAL 8)
- list(APPEND QT_DEFAULT_PLATFORM_DEFINITIONS WIN64 _WIN64)
- endif()
- if(MSVC)
- set(QT_DEFAULT_MKSPEC win32-msvc)
- elseif(CLANG AND MINGW)
- set(QT_DEFAULT_MKSPEC win32-clang-g++)
- elseif(MINGW)
- set(QT_DEFAULT_MKSPEC win32-g++)
- endif()
-
- if (MINGW)
- list(APPEND QT_DEFAULT_PLATFORM_DEFINITIONS _WIN32_WINNT=0x0601 MINGW_HAS_SECURE_API=1)
- endif()
-elseif(LINUX)
- if(GCC)
- set(QT_DEFAULT_MKSPEC linux-g++)
- elseif(CLANG)
- set(QT_DEFAULT_MKSPEC linux-clang)
- elseif(ICC)
- set(QT_DEFAULT_MKSPEC linux-icc-64)
- endif()
-elseif(ANDROID)
- if(GCC)
- set(QT_DEFAULT_MKSPEC android-g++)
- elseif(CLANG)
- set(QT_DEFAULT_MKSPEC android-clang)
- endif()
-elseif(APPLE)
- set(QT_DEFAULT_MKSPEC macx-clang)
-elseif(EMSCRIPTEN)
- set(QT_DEFAULT_MKSPEC wasm-emscripten)
-endif()
-
-if(NOT QT_QMAKE_TARGET_MKSPEC)
- set(QT_QMAKE_TARGET_MKSPEC "${QT_DEFAULT_MKSPEC}" CACHE STRING "QMake target mkspec")
-endif()
-
-if(CMAKE_CROSSCOMPILING)
- set(QT_QMAKE_HOST_MKSPEC "${QT${PROJECT_VERSION_MAJOR}_HOST_INFO_QMAKE_MKSPEC}")
-else()
- set(QT_QMAKE_HOST_MKSPEC "${QT_QMAKE_TARGET_MKSPEC}")
-endif()
-
-# Platform definition dir provided by user on command line.
-# Derive the absolute one relative to the current source dir.
-if(QT_PLATFORM_DEFINITION_DIR)
- set(QT_DEFAULT_PLATFORM_DEFINITION_DIR "${QT_PLATFORM_DEFINITION_DIR}")
- get_filename_component(
- QT_DEFAULT_PLATFORM_DEFINITION_DIR_ABSOLUTE
- "${QT_PLATFORM_DEFINITION_DIR}"
- ABSOLUTE)
-elseif(QT_QMAKE_TARGET_MKSPEC)
- # Used by consumers of prefix builds via INSTALL_INTERFACE (relative path).
- set(QT_DEFAULT_PLATFORM_DEFINITION_DIR "${INSTALL_MKSPECSDIR}/${QT_QMAKE_TARGET_MKSPEC}")
- # Used by qtbase itself and consumers of non-prefix builds via BUILD_INTERFACE (absolute path).
- set(QT_DEFAULT_PLATFORM_DEFINITION_DIR_ABSOLUTE "${QT_MKSPECS_DIR}/${QT_QMAKE_TARGET_MKSPEC}")
-endif()
-
-if(NOT DEFINED QT_DEFAULT_PLATFORM_DEFINITIONS)
- set(QT_DEFAULT_PLATFORM_DEFINITIONS "")
-endif()
-
-set(QT_PLATFORM_DEFINITIONS ${QT_DEFAULT_PLATFORM_DEFINITIONS}
- CACHE STRING "Qt platform specific pre-processor defines")
-set(QT_PLATFORM_DEFINITION_DIR "${QT_DEFAULT_PLATFORM_DEFINITION_DIR}"
- CACHE PATH "Path to directory that contains qplatformdefs.h")
-set(QT_PLATFORM_DEFINITION_DIR_ABSOLUTE "${QT_DEFAULT_PLATFORM_DEFINITION_DIR_ABSOLUTE}"
- CACHE INTERNAL "Path to directory that contains qplatformdefs.h")
-set(QT_NAMESPACE "" CACHE STRING "Qt Namespace")
-if(QT_NAMESPACE STREQUAL "")
- set(QT_HAS_NAMESPACE OFF)
-else()
- set(QT_HAS_NAMESPACE ON)
-endif()
-
-
-function(qt_internal_clear_qt_repo_known_modules)
- set(QT_REPO_KNOWN_MODULES "" CACHE INTERNAL "Known current repo Qt modules" FORCE)
-endfunction()
-
-function(qt_internal_add_qt_repo_known_module)
- set(QT_REPO_KNOWN_MODULES ${QT_REPO_KNOWN_MODULES} ${ARGN}
- CACHE INTERNAL "Known current repo Qt modules" FORCE)
-endfunction()
-
-function(qt_internal_get_qt_repo_known_modules out_var)
- set("${out_var}" "${QT_REPO_KNOWN_MODULES}" PARENT_SCOPE)
-endfunction()
-
-# Gets the list of all known Qt modules both found and that were built as part of the
-# current project.
-function(qt_internal_get_qt_all_known_modules out_var)
- qt_internal_get_qt_repo_known_modules(repo_known_modules)
- set(known_modules ${QT_ALL_MODULES_FOUND_VIA_FIND_PACKAGE} ${repo_known_modules})
- list(REMOVE_DUPLICATES known_modules)
- set("${out_var}" "${known_modules}" PARENT_SCOPE)
-endfunction()
-
-macro(qt_internal_set_qt_known_plugins)
- set(QT_KNOWN_PLUGINS ${ARGN} CACHE INTERNAL "Known Qt plugins" FORCE)
-endmacro()
-
-### Global plug-in types handling ###
-# QT_REPO_KNOWN_PLUGIN_TYPES and QT_ALL_PLUGIN_TYPES_FOUND_VIA_FIND_PACKAGE
-# hold a list of plug-in types (e.G. "imageformats;bearer")
-function(qt_internal_clear_qt_repo_known_plugin_types)
- set(QT_REPO_KNOWN_PLUGIN_TYPES "" CACHE INTERNAL "Known current repo Qt plug-in types" FORCE)
-endfunction()
-
-function(qt_internal_add_qt_repo_known_plugin_types)
- set(QT_REPO_KNOWN_PLUGIN_TYPES ${QT_REPO_KNOWN_PLUGIN_TYPES} ${ARGN}
- CACHE INTERNAL "Known current repo Qt plug-in types" FORCE)
-endfunction()
-
-function(qt_internal_get_qt_repo_known_plugin_types out_var)
- set("${out_var}" "${QT_REPO_KNOWN_PLUGIN_TYPES}" PARENT_SCOPE)
-endfunction()
-
-function(qt_internal_get_qt_all_known_plugin_types out_var)
- qt_internal_get_qt_repo_known_plugin_types(repo_known_plugin_types)
- set(known ${QT_ALL_PLUGIN_TYPES_FOUND_VIA_FIND_PACKAGE} ${repo_known_plugin_types})
- list(REMOVE_DUPLICATES known)
- set("${out_var}" "${known}" PARENT_SCOPE)
-endfunction()
-
-# Reset:
-qt_internal_clear_qt_repo_known_modules()
-qt_internal_clear_qt_repo_known_plugin_types()
-qt_internal_set_qt_known_plugins("")
-
-set(QT_KNOWN_MODULES_WITH_TOOLS "" CACHE INTERNAL "Known Qt modules with tools" FORCE)
-macro(qt_internal_append_known_modules_with_tools module)
- if(NOT ${module} IN_LIST QT_KNOWN_MODULES_WITH_TOOLS)
- set(QT_KNOWN_MODULES_WITH_TOOLS "${QT_KNOWN_MODULES_WITH_TOOLS};${module}"
- CACHE INTERNAL "Known Qt modules with tools" FORCE)
- set(QT_KNOWN_MODULE_${module}_TOOLS ""
- CACHE INTERNAL "Known Qt module ${module} tools" FORCE)
- endif()
-endmacro()
-
-macro(qt_internal_append_known_module_tool module tool)
- if(NOT ${tool} IN_LIST QT_KNOWN_MODULE_${module}_TOOLS)
- list(APPEND QT_KNOWN_MODULE_${module}_TOOLS "${tool}")
- set(QT_KNOWN_MODULE_${module}_TOOLS "${QT_KNOWN_MODULE_${module}_TOOLS}"
- CACHE INTERNAL "Known Qt module ${module} tools" FORCE)
- endif()
-endmacro()
-
-# Reset syncqt cache variable, to make sure it gets recomputed on reconfiguration, otherwise
-# it might not get installed.
-unset(QT_SYNCQT CACHE)
-
-# For adjusting variables when running tests, we need to know what
-# the correct variable is for separating entries in PATH-alike
-# variables.
-if(CMAKE_HOST_SYSTEM_NAME STREQUAL "Windows")
- set(QT_PATH_SEPARATOR "\\;")
-else()
- set(QT_PATH_SEPARATOR ":")
-endif()
-
-# This is used to hold extra cmake code that should be put into QtBuildInternalsExtra.cmake file
-# at the QtPostProcess stage.
-set(QT_BUILD_INTERNALS_EXTRA_CMAKE_CODE "")
-
-# Save the value of the current first project source dir.
-# This will be /path/to/qtbase for qtbase both in a super-build and a non super-build.
-# This will be /path/to/qtbase/tests when building standalone tests.
-set(QT_TOP_LEVEL_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}")
-
-# Prevent warnings about object files without any symbols. This is a common
-# thing in Qt as we tend to build files unconditionally, and then use ifdefs
-# to compile out parts that are not relevant.
-if(CMAKE_HOST_APPLE AND APPLE)
- foreach(lang ASM C CXX)
- # We have to tell 'ar' to not run ranlib by itself, by passing the 'S' option
- set(CMAKE_${lang}_ARCHIVE_CREATE "<CMAKE_AR> qcS <TARGET> <LINK_FLAGS> <OBJECTS>")
- set(CMAKE_${lang}_ARCHIVE_APPEND "<CMAKE_AR> qS <TARGET> <LINK_FLAGS> <OBJECTS>")
- set(CMAKE_${lang}_ARCHIVE_FINISH "<CMAKE_RANLIB> -no_warning_for_no_symbols <TARGET>")
- endforeach()
-endif()
-
-# Functions and macros:
-
-# qt_remove_args can remove arguments from an existing list of function
-# arguments in order to pass a filtered list of arguments to a different function.
-# Parameters:
-# out_var: result of remove all arguments specified by ARGS_TO_REMOVE from ALL_ARGS
-# ARGS_TO_REMOVE: Arguments to remove.
-# ALL_ARGS: All arguments supplied to cmake_parse_arguments or
-# qt_parse_all_arguments
-# from which ARGS_TO_REMOVE should be removed from. We require all the
-# arguments or we can't properly identify the range of the arguments detailed
-# in ARGS_TO_REMOVE.
-# ARGS: Arguments passed into the function, usually ${ARGV}
-#
-# E.g.:
-# We want to forward all arguments from foo to bar, execpt ZZZ since it will
-# trigger an error in bar.
-#
-# foo(target BAR .... ZZZ .... WWW ...)
-# bar(target BAR.... WWW...)
-#
-# function(foo target)
-# qt_parse_all_arguments(arg "" "" "BAR;ZZZ;WWW ${ARGV})
-# qt_remove_args(forward_args
-# ARGS_TO_REMOVE ${target} ZZZ
-# ALL_ARGS ${target} BAR ZZZ WWW
-# ARGS ${ARGV}
-# )
-# bar(${target} ${forward_args})
-# endfunction()
-#
-function(qt_remove_args out_var)
- cmake_parse_arguments(arg "" "" "ARGS_TO_REMOVE;ALL_ARGS;ARGS" ${ARGN})
- set(result ${arg_ARGS})
- foreach(arg IN LISTS arg_ARGS_TO_REMOVE)
- # find arg
- list(FIND result ${arg} find_result)
- if (NOT find_result EQUAL -1)
- # remove arg
- list(REMOVE_AT result ${find_result})
- list(LENGTH result result_len)
- list(GET result ${find_result} arg_current)
- # remove values until we hit another arg
- while(NOT ${arg_current} IN_LIST arg_ALL_ARGS AND find_result LESS result_len)
- list(REMOVE_AT result ${find_result})
- list(GET result ${find_result} arg_current)
- list(LENGTH result result_len)
- endwhile()
- endif()
- endforeach()
- set(${out_var} "${result}" PARENT_SCOPE)
-endfunction()
-# Wraps install() command. In a prefix build, simply passes along arguments to install().
-# In a non-prefix build, handles association of targets to export names, and also calls export().
-function(qt_install)
- set(flags)
- set(options EXPORT DESTINATION NAMESPACE)
- set(multiopts TARGETS)
- cmake_parse_arguments(arg "${flags}" "${options}" "${multiopts}" ${ARGN})
-
- if(arg_TARGETS)
- set(is_install_targets TRUE)
- endif()
-
- # In a prefix build, always invoke install() without modification.
- # In a non-prefix build, pass install(TARGETS) commands to allow
- # association of targets to export names, so we can later use the export names
- # in export() commands.
- if(QT_WILL_INSTALL OR is_install_targets)
- install(${ARGV})
- endif()
-
- # Exit early if this is a prefix build.
- if(QT_WILL_INSTALL)
- return()
- endif()
-
- # In a non-prefix build, when install(EXPORT) is called,
- # also call export(EXPORT) to generate build tree target files.
- if(NOT is_install_targets AND arg_EXPORT)
- set(namespace_option "")
- if(arg_NAMESPACE)
- set(namespace_option NAMESPACE ${arg_NAMESPACE})
- endif()
- export(EXPORT ${arg_EXPORT}
- ${namespace_option}
- FILE "${arg_DESTINATION}/${arg_EXPORT}.cmake")
- endif()
-endfunction()
-
-# Copies files using file(COPY) signature in non-prefix builds.
-function(qt_non_prefix_copy)
- if(NOT QT_WILL_INSTALL)
- file(${ARGV})
- endif()
-endfunction()
-
-# Retrieve the permissions that are set by install(PROGRAMS).
-function(qt_get_install_executable_permissions out_var)
- set(default_permissions ${CMAKE_INSTALL_DEFAULT_DIRECTORY_PERMISSIONS})
- if(NOT default_permissions)
- set(default_permissions OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ)
- endif()
- set(executable_permissions ${default_permissions} OWNER_EXECUTE)
- if(GROUP_READ IN_LIST default_permissions)
- list(APPEND executable_permissions GROUP_EXECUTE)
- endif()
- if(WORLD_READ IN_LIST default_permissions)
- list(APPEND executable_permissions WORLD_EXECUTE)
- endif()
- set(${out_var} ${executable_permissions} PARENT_SCOPE)
-endfunction()
-
-# Use case is installing files in a prefix build, or copying them to the correct build dir
-# in a non-prefix build.
-# Pass along arguments as you would pass them to install().
-# Only supports FILES, PROGRAMS and DIRECTORY signature, and without fancy things
-# like OPTIONAL or RENAME or COMPONENT.
-function(qt_copy_or_install)
- set(flags FILES PROGRAMS DIRECTORY)
- set(options)
- set(multiopts)
- cmake_parse_arguments(arg "${flags}" "${options}" "${multiopts}" ${ARGN})
-
- # Remember which option has to be passed to the install command.
- set(copy_arguments "")
- set(argv_copy ${ARGV})
- if(arg_FILES)
- set(install_option "FILES")
- elseif(arg_PROGRAMS)
- set(install_option "PROGRAMS")
- qt_get_install_executable_permissions(executable_permissions)
- list(APPEND copy_arguments FILE_PERMISSIONS ${executable_permissions})
- elseif(arg_DIRECTORY)
- set(install_option "DIRECTORY")
- endif()
-
- list(REMOVE_AT argv_copy 0)
- qt_install(${install_option} ${argv_copy})
- qt_non_prefix_copy(COPY ${argv_copy} ${copy_arguments})
-endfunction()
-
-# Hacky way to remove the install target in non-prefix builds.
-# We need to associate targets with export names, and that is only possible to do with the
-# install(TARGETS) command. But in a non-prefix build, we don't want to install anything.
-# To make sure that developers don't accidentally run make install, replace the generated
-# cmake_install.cmake file with an empty file. To do this, always create a new temporary file
-# at CMake configuration step, and use it as an input to a custom command that replaces the
-# cmake_install.cmake file with an empty one. This means we will always replace the file on
-# every reconfiguration, but not when doing null builds.
-function(qt_remove_install_target)
- # On superbuilds we only do this for qtbase - it will correctly remove the
- # cmake_install.cmake at the root of the repository.
- if(QT_SUPERBUILD)
- if(NOT (PROJECT_NAME STREQUAL "QtBase"))
- return()
- endif()
- endif()
-
- set(file_in "${CMAKE_BINARY_DIR}/.remove_cmake_install_in.txt")
- set(file_generated "${CMAKE_BINARY_DIR}/.remove_cmake_install_generated.txt")
- set(cmake_install_file "${CMAKE_BINARY_DIR}/cmake_install.cmake")
- file(WRITE ${file_in} "")
-
- add_custom_command(OUTPUT ${file_generated}
- COMMAND ${CMAKE_COMMAND} -E copy ${file_in} ${file_generated}
- COMMAND ${CMAKE_COMMAND} -E remove ${cmake_install_file}
- COMMAND ${CMAKE_COMMAND} -E touch ${cmake_install_file}
- COMMENT "Removing cmake_install.cmake"
- MAIN_DEPENDENCY ${file_in})
-
- add_custom_target(remove_cmake_install ALL DEPENDS ${file_generated})
-endfunction()
-
-function(qt_set_up_nonprefix_build)
- if(NOT QT_WILL_INSTALL)
- qt_remove_install_target()
- endif()
-endfunction()
-
-function(qt_is_imported_target target out_var)
- if(NOT TARGET "${target}")
- set(target "${QT_CMAKE_EXPORT_NAMESPACE}::${target}")
- endif()
- if(NOT TARGET "${target}")
- message(FATAL_ERROR "Invalid target given to qt_is_imported_target: ${target}")
- endif()
- get_target_property(is_imported "${target}" IMPORTED)
- set(${out_var} "${is_imported}" PARENT_SCOPE)
-endfunction()
-
-# Creates a regular expression that exactly matches the given string
-# Found in https://gitlab.kitware.com/cmake/cmake/issues/18580
-function(qt_re_escape out_var str)
- string(REGEX REPLACE "([][+.*()^])" "\\\\\\1" regex "${str}")
- set(${out_var} ${regex} PARENT_SCOPE)
-endfunction()
-
-# Extracts the 3rdparty libraries for the module ${module_name}
-# and stores the information in cmake language in
-# ${output_root_dir}/$<CONFIG>/${output_file_name}.
-#
-# This function "follows" INTERFACE_LIBRARY targets to "real" targets
-# and collects defines, include dirs and lib dirs on the way.
-function(qt_generate_qmake_libraries_pri_content module_name output_root_dir output_file_name)
- set(content "")
-
- # Set up a regular expression that matches all implicit include dirs
- set(implicit_include_dirs_regex "")
- foreach(dir ${CMAKE_CXX_IMPLICIT_INCLUDE_DIRECTORIES})
- qt_re_escape(regex "${dir}")
- list(APPEND implicit_include_dirs_regex ${regex})
- endforeach()
- list(JOIN implicit_include_dirs_regex "|" implicit_include_dirs_regex)
-
- foreach(lib ${QT_QMAKE_LIBS_FOR_${module_name}})
- set(lib_targets ${QT_QMAKE_LIB_TARGETS_${lib}})
- string(TOUPPER ${lib} uclib)
- set(lib_defines "")
- set(lib_incdir "")
- set(lib_libdir "")
- set(lib_libs "")
- while(lib_targets)
- list(POP_BACK lib_targets lib_target)
- if(TARGET ${lib_target})
- get_target_property(lib_target_type ${lib_target} TYPE)
- if(lib_target_type STREQUAL "INTERFACE_LIBRARY")
- get_target_property(iface_libs ${lib_target} INTERFACE_LINK_LIBRARIES)
- if(iface_libs)
- list(PREPEND lib_targets ${iface_libs})
- endif()
- else()
- list(APPEND lib_libs "$<TARGET_LINKER_FILE:${lib_target}>")
- endif()
- list(APPEND lib_libdir "$<TARGET_PROPERTY:${lib_target},INTERFACE_LINK_DIRECTORIES>")
- list(APPEND lib_incdir "$<TARGET_PROPERTY:${lib_target},INTERFACE_INCLUDE_DIRECTORIES>")
- list(APPEND lib_defines "$<TARGET_PROPERTY:${lib_target},INTERFACE_COMPILE_DEFINITIONS>")
- else()
- if(lib_target MATCHES "/([^/]+).framework$")
- list(APPEND lib_libs "-framework" "${CMAKE_MATCH_1}")
- else()
- list(APPEND lib_libs "${lib_target}")
- endif()
- endif()
- endwhile()
-
- # Wrap in $<REMOVE_DUPLICATES:...> but not the libs, because
- # we would have to preserve the right order for the linker.
- foreach(sfx libdir incdir defines)
- string(PREPEND lib_${sfx} "$<REMOVE_DUPLICATES:")
- string(APPEND lib_${sfx} ">")
- endforeach()
-
- # Filter out implicit include directories
- string(PREPEND lib_incdir "$<FILTER:")
- string(APPEND lib_incdir ",EXCLUDE,${implicit_include_dirs_regex}>")
-
- set(uccfg $<UPPER_CASE:$<CONFIG>>)
- string(APPEND content "list(APPEND known_libs ${uclib})
-set(QMAKE_LIBS_${uclib}_${uccfg} \"${lib_libs}\")
-set(QMAKE_LIBDIR_${uclib}_${uccfg} \"${lib_libdir}\")
-set(QMAKE_INCDIR_${uclib}_${uccfg} \"${lib_incdir}\")
-set(QMAKE_DEFINES_${uclib}_${uccfg} \"${lib_defines}\")
-")
- if(QT_QMAKE_LIB_DEPS_${lib})
- string(APPEND content "set(QMAKE_DEPENDS_${uclib}_CC, ${deps})
-set(QMAKE_DEPENDS_${uclib}_LD, ${deps})
-")
- endif()
- endforeach()
-
- file(GENERATE
- OUTPUT "${output_root_dir}/$<CONFIG>/${output_file_name}"
- CONTENT "${content}"
- )
-endfunction()
-
-# Retrieves the public Qt module dependencies of the given Qt module or Qt Private module.
-function(qt_get_direct_module_dependencies target out_var)
- set(dependencies "")
- get_target_property(libs ${target} INTERFACE_LINK_LIBRARIES)
- if(NOT libs)
- set(libs "")
- endif()
- get_target_property(target_type ${target} TYPE)
- while(libs)
- list(POP_FRONT libs lib)
- string(GENEX_STRIP "${lib}" lib)
- if(NOT lib OR NOT TARGET "${lib}")
- continue()
- endif()
- get_target_property(lib_type ${lib} TYPE)
- get_target_property(is_versionless_target ${lib} _qt_is_versionless_target)
- if (lib_type STREQUAL "INTERFACE_LIBRARY" AND is_versionless_target)
- # Found a version-less target like Qt::Core outside of qtbase.
- # Skip this one and use what this target points to, e.g. Qt6::Core.
- # Make sure to process Private interface libraries as-is.
- get_target_property(ifacelibs ${lib} INTERFACE_LINK_LIBRARIES)
- list(PREPEND libs ${ifacelibs})
- continue()
- endif()
- if(lib_type STREQUAL "OBJECT_LIBRARY")
- # Skip object libraries, because they're already part of ${target}.
- continue()
- elseif(lib_type STREQUAL "STATIC_LIBRARY" AND target_type STREQUAL "SHARED_LIBRARY")
- # Skip static libraries if ${target} is a shared library.
- continue()
- endif()
- get_target_property(lib_config_module_name ${lib} "_qt_config_module_name")
- if(lib_config_module_name)
- list(APPEND dependencies ${lib_config_module_name})
- endif()
- endwhile()
- set(${out_var} ${dependencies} PARENT_SCOPE)
-endfunction()
-
-# Generates module .pri files for consumption by qmake
-function(qt_generate_module_pri_file target)
- set(flags INTERNAL_MODULE HEADER_MODULE)
- set(options)
- set(multiopts)
- cmake_parse_arguments(arg "${flags}" "${options}" "${multiopts}" ${ARGN})
-
- qt_internal_module_info(module "${target}")
- set(pri_files)
-
- set(property_prefix)
- if(arg_HEADER_MODULE)
- set(property_prefix "INTERFACE_")
- endif()
-
- get_target_property(enabled_features "${target}"
- "${property_prefix}QT_ENABLED_PUBLIC_FEATURES")
- get_target_property(disabled_features "${target}"
- "${property_prefix}QT_DISABLED_PUBLIC_FEATURES")
- get_target_property(enabled_private_features "${target}"
- "${property_prefix}QT_ENABLED_PRIVATE_FEATURES")
- get_target_property(disabled_private_features "${target}"
- "${property_prefix}QT_DISABLED_PRIVATE_FEATURES")
- qt_correct_features(enabled_features "${enabled_features}")
- qt_correct_features(disabled_features "${disabled_features}")
- qt_correct_features(enabled_private_features "${enabled_private_features}")
- qt_correct_features(disabled_private_features "${disabled_private_features}")
-
- foreach(var enabled_features disabled_features enabled_private_features disabled_private_features)
- if(${var} STREQUAL "${var}-NOTFOUND")
- set(${var} "")
- else()
- string (REPLACE ";" " " ${var} "${${var}}")
- endif()
- endforeach()
-
- set(module_internal_config v2)
- if(NOT QT_FEATURE_shared)
- list(APPEND module_internal_config staticlib)
- endif()
- if(arg_INTERNAL_MODULE)
- list(APPEND module_internal_config internal_module)
- endif()
-
- get_target_property(target_type ${target} TYPE)
- if (NOT target_type STREQUAL "INTERFACE_LIBRARY")
- get_target_property(is_fw ${target} FRAMEWORK)
- if(is_fw)
- list(APPEND module_internal_config lib_bundle)
- endif()
- endif()
-
- # TODO: Add the value 'ltcg' to module_internal_config if LTCG is turned on.
-
- list(JOIN module_internal_config " " joined_module_internal_config)
-
- get_target_property(config_module_name ${target} _qt_config_module_name)
- get_target_property(qmake_module_config ${target} ${property_prefix}QT_QMAKE_MODULE_CONFIG)
- if(qmake_module_config)
- string(REPLACE ";" " " module_build_config "${qmake_module_config}")
- set(module_build_config "\nQT.${config_module_name}.CONFIG = ${module_build_config}")
- else()
- set(module_build_config "")
- endif()
-
- if(is_fw)
- set(framework_base_path "$$QT_MODULE_LIB_BASE/${module}.framework/Headers")
- set(public_module_includes "${framework_base_path}")
- set(public_module_frameworks "$$QT_MODULE_LIB_BASE")
- set(private_module_includes "${framework_base_path}/${PROJECT_VERSION} ${framework_base_path}/${PROJECT_VERSION}/${module}")
- set(module_name_in_pri "${module}")
- else()
- set(public_module_includes "$$QT_MODULE_INCLUDE_BASE $$QT_MODULE_INCLUDE_BASE/${module}")
- set(public_module_frameworks "")
- set(private_module_includes "$$QT_MODULE_INCLUDE_BASE/${module}/${PROJECT_VERSION} $$QT_MODULE_INCLUDE_BASE/${module}/${PROJECT_VERSION}/${module}")
- set(module_name_in_pri "${module_versioned}")
- endif()
-
- qt_path_join(target_path ${QT_BUILD_DIR} ${INSTALL_MKSPECSDIR}/modules)
- if (arg_INTERNAL_MODULE)
- string(PREPEND private_module_includes "${public_module_includes} ")
- set(private_module_frameworks ${public_module_frameworks})
- else()
- unset(private_module_frameworks)
- if(arg_HEADER_MODULE)
- set(module_plugin_types "")
- else()
- get_target_property(module_plugin_types ${target} QMAKE_MODULE_PLUGIN_TYPES)
- if(module_plugin_types)
- list(JOIN module_plugin_types " " module_plugin_types)
- else()
- set(module_plugin_types "")
- endif()
- endif()
-
- qt_get_direct_module_dependencies(${target} public_module_dependencies)
- list(JOIN public_module_dependencies " " public_module_dependencies)
-
- qt_path_join(pri_file_name "${target_path}" "qt_lib_${config_module_name}.pri")
- list(APPEND pri_files "${pri_file_name}")
-
- # Don't use $<TARGET_PROPERTY:${target},INTERFACE_COMPILE_DEFINITIONS> genex because that
- # will compute the transitive list of all defines for a module (so Gui would get Core
- #defines too). Instead query just the public defines on the target.
- get_target_property(target_defines "${target}" INTERFACE_COMPILE_DEFINITIONS)
-
- # We must filter out expressions of the form $<TARGET_PROPERTY:name>, because
- # 1. They cannot be used in file(GENERATE) content.
- # 2. They refer to the consuming target we have no access to here.
- list(FILTER target_defines EXCLUDE REGEX "\\$<TARGET_PROPERTY:[^,>]+>")
- list(JOIN target_defines " " joined_target_defines)
-
- file(GENERATE
- OUTPUT "${pri_file_name}"
- CONTENT
- "QT.${config_module_name}.VERSION = ${PROJECT_VERSION}
-QT.${config_module_name}.name = ${module}
-QT.${config_module_name}.module = ${module_name_in_pri}
-QT.${config_module_name}.libs = $$QT_MODULE_LIB_BASE
-QT.${config_module_name}.includes = ${public_module_includes}
-QT.${config_module_name}.frameworks = ${public_module_frameworks}
-QT.${config_module_name}.bins = $$QT_MODULE_BIN_BASE
-QT.${config_module_name}.plugin_types = ${module_plugin_types}
-QT.${config_module_name}.depends = ${public_module_dependencies}
-QT.${config_module_name}.uses =
-QT.${config_module_name}.module_config = ${joined_module_internal_config}
-QT.${config_module_name}.DEFINES = ${joined_target_defines}
-QT.${config_module_name}.enabled_features = ${enabled_features}
-QT.${config_module_name}.disabled_features = ${disabled_features}${module_build_config}
-QT_CONFIG += ${enabled_features}
-QT_MODULES += ${config_module_name}
-"
- )
- endif()
-
- set(pri_data_cmake_file "qt_lib_${config_module_name}_private.cmake")
- qt_generate_qmake_libraries_pri_content(${config_module_name} "${CMAKE_CURRENT_BINARY_DIR}"
- ${pri_data_cmake_file})
-
- set(private_pri_file_name "qt_lib_${config_module_name}_private.pri")
-
- set(private_module_dependencies "")
- if(NOT arg_HEADER_MODULE)
- qt_get_direct_module_dependencies(${target}Private private_module_dependencies)
- endif()
- list(JOIN private_module_dependencies " " private_module_dependencies)
-
- # Generate a preliminary qt_lib_XXX_private.pri file
- file(GENERATE
- OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/${private_pri_file_name}"
- CONTENT
- "QT.${config_module_name}_private.VERSION = ${PROJECT_VERSION}
-QT.${config_module_name}_private.name = ${module}
-QT.${config_module_name}_private.module =
-QT.${config_module_name}_private.libs = $$QT_MODULE_LIB_BASE
-QT.${config_module_name}_private.includes = ${private_module_includes}
-QT.${config_module_name}_private.frameworks = ${private_module_frameworks}
-QT.${config_module_name}_private.depends = ${private_module_dependencies}
-QT.${config_module_name}_private.uses =
-QT.${config_module_name}_private.module_config = ${joined_module_internal_config}
-QT.${config_module_name}_private.enabled_features = ${enabled_private_features}
-QT.${config_module_name}_private.disabled_features = ${disabled_private_features}"
- )
-
- if(QT_GENERATOR_IS_MULTI_CONFIG)
- set(configs ${CMAKE_CONFIGURATION_TYPES})
- else()
- set(configs ${CMAKE_BUILD_TYPE})
- endif()
- set(inputs "${CMAKE_CURRENT_BINARY_DIR}/${private_pri_file_name}")
- foreach(cfg ${configs})
- list(APPEND inputs "${CMAKE_CURRENT_BINARY_DIR}/${cfg}/${pri_data_cmake_file}")
- endforeach()
-
- qt_path_join(private_pri_file_path "${target_path}" "${private_pri_file_name}")
- list(APPEND pri_files "${private_pri_file_path}")
-
- set(library_prefixes ${CMAKE_SHARED_LIBRARY_PREFIX} ${CMAKE_STATIC_LIBRARY_PREFIX})
- set(library_suffixes
- ${CMAKE_SHARED_LIBRARY_SUFFIX}
- ${CMAKE_EXTRA_SHARED_LIBRARY_SUFFIXES}
- ${CMAKE_STATIC_LIBRARY_SUFFIX})
- add_custom_command(
- OUTPUT "${private_pri_file_path}"
- DEPENDS ${inputs}
- "${QT_CMAKE_DIR}/QtGenerateLibPri.cmake"
- "${QT_CMAKE_DIR}/QtGenerateLibHelpers.cmake"
- COMMAND ${CMAKE_COMMAND} "-DIN_FILES=${inputs}" "-DOUT_FILE=${private_pri_file_path}"
- "-DLIBRARY_PREFIXES=${library_prefixes}"
- "-DLIBRARY_SUFFIXES=${library_suffixes}"
- "-DLINK_LIBRARY_FLAG=${CMAKE_LINK_LIBRARY_FLAG}"
- "-DCONFIGS=${configs}"
- -P "${QT_CMAKE_DIR}/QtGenerateLibPri.cmake"
- VERBATIM)
- add_custom_target(${target}_lib_pri DEPENDS "${private_pri_file_path}")
- if(arg_HEADER_MODULE)
- add_dependencies(${target}_timestamp ${target}_lib_pri)
- else()
- add_dependencies(${target} ${target}_lib_pri)
- endif()
- qt_install(FILES "${pri_files}" DESTINATION ${INSTALL_MKSPECSDIR}/modules)
-endfunction()
-
-# Generates qt_ext_XXX.pri files for consumption by qmake
-function(qt_generate_3rdparty_lib_pri_file target lib pri_file_var)
- if(NOT lib)
- # Don't write a pri file for projects that don't set QMAKE_LIB_NAME yet.
- return()
- endif()
-
- if(QT_GENERATOR_IS_MULTI_CONFIG)
- set(configs ${CMAKE_CONFIGURATION_TYPES})
- else()
- set(configs ${CMAKE_BUILD_TYPE})
- endif()
-
- file(GENERATE
- OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/$<CONFIG>/qt_ext_${lib}.cmake"
- CONTENT "set(cfg $<CONFIG>)
-set(incdir $<TARGET_PROPERTY:${target},INTERFACE_INCLUDE_DIRECTORIES>)
-set(defines $<TARGET_PROPERTY:${target},INTERFACE_COMPILE_DEFINITIONS>)
-set(libs $<TARGET_FILE:${target}>)
-")
-
- set(inputs "")
- foreach(cfg ${configs})
- list(APPEND inputs "${CMAKE_CURRENT_BINARY_DIR}/${cfg}/qt_ext_${lib}.cmake")
- endforeach()
-
- qt_path_join(pri_target_path ${QT_BUILD_DIR} ${INSTALL_MKSPECSDIR}/modules)
- qt_path_join(pri_file "${pri_target_path}" "qt_ext_${lib}.pri")
- qt_path_join(qt_build_libdir ${QT_BUILD_DIR} ${INSTALL_LIBDIR})
- add_custom_command(
- OUTPUT "${pri_file}"
- DEPENDS ${inputs} "${QT_CMAKE_DIR}/QtGenerateExtPri.cmake"
- COMMAND ${CMAKE_COMMAND} "-DIN_FILES=${inputs}" "-DOUT_FILE=${pri_file}" -DLIB=${lib}
- "-DCONFIGS=${configs}"
- "-DQT_BUILD_LIBDIR=${qt_build_libdir}"
- -P "${QT_CMAKE_DIR}/QtGenerateExtPri.cmake"
- VERBATIM)
- add_custom_target(${target}_ext_pri DEPENDS "${pri_file}")
- add_dependencies(${target} ${target}_ext_pri)
- set(${pri_file_var} ${pri_file} PARENT_SCOPE)
-endfunction()
-
-# Transforms a CMake Qt module name to a qmake Qt module name.
-# Example: Qt6FooPrivate becomes foo_private
-function(qt_get_qmake_module_name result module)
- string(REGEX REPLACE "^Qt6" "" module "${module}")
- string(REGEX REPLACE "Private$" "_private" module "${module}")
- string(REGEX REPLACE "Qpa$" "_qpa_lib_private" module "${module}")
- string(TOLOWER "${module}" module)
- set(${result} ${module} PARENT_SCOPE)
-endfunction()
-
-# Generates qt_plugin_XXX.pri files for consumption by qmake
-#
-# QT_PLUGIN.XXX.EXTENDS is set to "-" for the following plugin types:
-# - generic
-# - platform, if the plugin is not the default QPA plugin
-# Otherwise, this variable is empty.
-function(qt_generate_plugin_pri_file target pri_file_var)
- get_target_property(plugin_name ${target} OUTPUT_NAME)
- get_target_property(plugin_type ${target} QT_PLUGIN_TYPE)
- get_target_property(qmake_plugin_type ${target} QT_QMAKE_PLUGIN_TYPE)
- get_target_property(default_plugin ${target} QT_DEFAULT_PLUGIN)
- get_target_property(plugin_class_name ${target} QT_PLUGIN_CLASS_NAME)
-
- set(plugin_extends "")
- if(NOT default_plugin AND (plugin_type STREQUAL "generic" OR plugin_type STREQUAL "platforms"))
- set(plugin_extends "-")
- endif()
-
- set(plugin_deps "")
- get_target_property(target_deps ${target} _qt_target_deps)
- foreach(dep ${target_deps})
- list(GET dep 0 dep_name)
- qt_get_qmake_module_name(dep_name ${dep_name})
- list(APPEND plugin_deps ${dep_name})
- endforeach()
- list(REMOVE_DUPLICATES plugin_deps)
- list(JOIN plugin_deps " " plugin_deps)
-
- qt_path_join(pri_target_path ${QT_BUILD_DIR} ${INSTALL_MKSPECSDIR}/modules)
- qt_path_join(pri_file "${pri_target_path}" "qt_plugin_${plugin_name}.pri")
- qt_configure_file(OUTPUT "${pri_file}"
- CONTENT "QT_PLUGIN.${plugin_name}.TYPE = ${qmake_plugin_type}
-QT_PLUGIN.${plugin_name}.EXTENDS = ${plugin_extends}
-QT_PLUGIN.${plugin_name}.DEPENDS = ${plugin_deps}
-QT_PLUGIN.${plugin_name}.CLASS_NAME = ${plugin_class_name}
-QT_PLUGINS += ${plugin_name}
-")
- set(${pri_file_var} "${pri_file}" PARENT_SCOPE)
-endfunction()
-
-function(qt_cmake_build_type_to_qmake_build_config out_var build_type)
- if(build_type STREQUAL "Debug")
- set(cfg debug)
- else()
- set(cfg release)
- endif()
- set(${out_var} ${cfg} PARENT_SCOPE)
-endfunction()
-
-function(qt_guess_qmake_build_config out_var)
- if(QT_GENERATOR_IS_MULTI_CONFIG)
- unset(cfg)
- foreach(config_type ${CMAKE_CONFIGURATION_TYPES})
- qt_cmake_build_type_to_qmake_build_config(tmp ${config_type})
- list(APPEND cfg ${tmp})
- endforeach()
- if(cfg)
- list(REMOVE_DUPLICATES cfg)
- else()
- set(cfg debug)
- endif()
- else()
- qt_cmake_build_type_to_qmake_build_config(cfg ${CMAKE_BUILD_TYPE})
- endif()
- set(${out_var} ${cfg} PARENT_SCOPE)
-endfunction()
-
-function(qt_correct_features out_var features)
- set(corrected_features "")
- foreach(feature ${features})
- get_property(feature_original_name GLOBAL PROPERTY "QT_FEATURE_ORIGINAL_NAME_${feature}")
- list(APPEND corrected_features "${feature_original_name}")
- endforeach()
- set(${out_var} ${corrected_features} PARENT_SCOPE)
-endfunction()
-
-# Get original names for config values (which correspond to feature names) and use them if they
-# exist, otherwise just use the config value (which might be the case when a config value has
-# a custom name).
-function(qt_correct_config out_var config)
- set(corrected_config "")
- foreach(name ${config})
- # Is the config value a known feature?
- get_property(feature_original_name GLOBAL PROPERTY "QT_FEATURE_ORIGINAL_NAME_${name}")
- if(feature_original_name)
- list(APPEND corrected_config "${feature_original_name}")
- continue()
- endif()
-
- # Is the config value a negated known feature, e.g. no_foo?
- # Then add the config value no-foo.
- if(name MATCHES "^no_(.*)")
- get_property(feature_original_name GLOBAL PROPERTY
- "QT_FEATURE_ORIGINAL_NAME_${CMAKE_MATCH_1}")
- if(feature_original_name)
- list(APPEND corrected_config "no-${feature_original_name}")
- continue()
- endif()
- endif()
-
- # The config value is no known feature. Add the value as is.
- list(APPEND corrected_config "${name}")
- endforeach()
- set(${out_var} ${corrected_config} PARENT_SCOPE)
-endfunction()
-
-# Creates mkspecs/qconfig.pri which contains public global features among other things.
-function(qt_generate_global_config_pri_file)
- qt_path_join(qconfig_pri_target_path ${PROJECT_BINARY_DIR} ${INSTALL_MKSPECSDIR})
- qt_path_join(qconfig_pri_target_path "${qconfig_pri_target_path}" "qconfig.pri")
-
- get_target_property(enabled_features GlobalConfig INTERFACE_QT_ENABLED_PUBLIC_FEATURES)
- get_target_property(disabled_features GlobalConfig INTERFACE_QT_DISABLED_PUBLIC_FEATURES)
-
- qt_correct_features(corrected_enabled_features "${enabled_features}")
- qt_correct_features(corrected_disabled_features "${disabled_features}")
-
- string (REPLACE ";" " " corrected_enabled_features "${corrected_enabled_features}")
- string (REPLACE ";" " " corrected_disabled_features "${corrected_disabled_features}")
-
- # Add some required CONFIG entries.
- set(config_entries "")
- if(CMAKE_BUILD_TYPE STREQUAL Debug)
- list(APPEND config_entries "debug")
- elseif(CMAKE_BUILD_TYPE STREQUAL Release)
- list(APPEND config_entries "release")
- endif()
- list(APPEND config_entries "${qt_build_config_type}")
- string (REPLACE ";" " " config_entries "${config_entries}")
-
- get_target_property(public_config GlobalConfig INTERFACE_QT_QMAKE_PUBLIC_CONFIG)
- get_target_property(qt_public_config GlobalConfig INTERFACE_QT_QMAKE_PUBLIC_QT_CONFIG)
- qt_correct_config(corrected_public_config "${public_config}")
- qt_correct_config(corrected_qt_public_config "${qt_public_config}")
- qt_guess_qmake_build_config(qmake_build_config)
- list(APPEND corrected_qt_public_config ${qmake_build_config})
-
- list(JOIN corrected_public_config " " public_config_joined)
- list(JOIN corrected_qt_public_config " " qt_public_config_joined)
-
- set(content "")
- if(GCC OR CLANG AND NOT "${CMAKE_SYSROOT}" STREQUAL "")
- string(APPEND content "!host_build {
- QMAKE_CFLAGS += --sysroot=\$\$[QT_SYSROOT]
- QMAKE_CXXFLAGS += --sysroot=\$\$[QT_SYSROOT]
- QMAKE_LFLAGS += --sysroot=\$\$[QT_SYSROOT]
-}
-")
- endif()
-
- if(CMAKE_CROSSCOMPILING)
- string(APPEND content "host_build {
- QT_ARCH = ${QT${PROJECT_VERSION_MAJOR}_HOST_INFO_ARCH}
- QT_BUILDABI = ${QT${PROJECT_VERSION_MAJOR}_HOST_INFO_BUILDABI}
- QT_TARGET_ARCH = ${TEST_architecture_arch}
- QT_TARGET_BUILDABI = ${TEST_buildAbi}
-} else {
- QT_ARCH = ${TEST_architecture_arch}
- QT_BUILDABI = ${TEST_buildAbi}
-}
-")
- else()
- string(APPEND content "QT_ARCH = ${TEST_architecture_arch}
-QT_BUILDABI = ${TEST_buildAbi}
-")
- endif()
-
- string(APPEND content "QT.global.enabled_features = ${corrected_enabled_features}
-QT.global.disabled_features = ${corrected_disabled_features}
-QT.global.disabled_features += release build_all
-QT_CONFIG += ${qt_public_config_joined}
-CONFIG += ${config_entries} ${public_config_joined}
-QT_VERSION = ${PROJECT_VERSION}
-QT_MAJOR_VERSION = ${PROJECT_VERSION_MAJOR}
-QT_MINOR_VERSION = ${PROJECT_VERSION_MINOR}
-QT_PATCH_VERSION = ${PROJECT_VERSION_PATCH}
-")
-
- set(extra_statements "")
- if(QT_NAMESPACE)
- list(APPEND extra_statements "QT_NAMESPACE = ${QT_NAMESPACE}")
- endif()
- # TODO: Add libinfix support.
-
- # TODO: Add QT_EMCC_VERSION when WASM is ported over.
- if(APPLECLANG)
- set(compiler_version_major_var_name "QT_APPLE_CLANG_MAJOR_VERSION")
- set(compiler_version_minor_var_name "QT_APPLE_CLANG_MINOR_VERSION")
- set(compiler_version_patch_var_name "QT_APPLE_CLANG_PATCH_VERSION")
- elseif(CLANG)
- set(compiler_version_major_var_name "QT_CLANG_MAJOR_VERSION")
- set(compiler_version_minor_var_name "QT_CLANG_MINOR_VERSION")
- set(compiler_version_patch_var_name "QT_CLANG_PATCH_VERSION")
- elseif(GCC)
- set(compiler_version_major_var_name "QT_GCC_MAJOR_VERSION")
- set(compiler_version_minor_var_name "QT_GCC_MINOR_VERSION")
- set(compiler_version_patch_var_name "QT_GCC_PATCH_VERSION")
- elseif(ICC)
- set(compiler_version_major_var_name "QT_ICC_MAJOR_VERSION")
- set(compiler_version_minor_var_name "QT_ICC_MINOR_VERSION")
- set(compiler_version_patch_var_name "QT_ICC_PATCH_VERSION")
- elseif(MSVC)
- set(compiler_version_major_var_name "QT_MSVC_MAJOR_VERSION")
- set(compiler_version_minor_var_name "QT_MSVC_MINOR_VERSION")
- set(compiler_version_patch_var_name "QT_MSVC_PATCH_VERSION")
- endif()
-
- if(compiler_version_major_var_name)
- list(APPEND extra_statements
- "${compiler_version_major_var_name} = ${QT_COMPILER_VERSION_MAJOR}")
- list(APPEND extra_statements
- "${compiler_version_minor_var_name} = ${QT_COMPILER_VERSION_MINOR}")
- list(APPEND extra_statements
- "${compiler_version_patch_var_name} = ${QT_COMPILER_VERSION_PATCH}")
- endif()
-
- if(APPLE)
- list(APPEND extra_statements "QT_MAC_SDK_VERSION = ${QT_MAC_SDK_VERSION}")
- endif()
-
- list(APPEND extra_statements "QT_EDITION = Open Source")
-
- if(extra_statements)
- string(REPLACE ";" "\n" extra_statements "${extra_statements}")
- string(APPEND content "\n${extra_statements}")
- endif()
-
- file(GENERATE
- OUTPUT "${qconfig_pri_target_path}"
- CONTENT "${content}"
- )
- qt_install(FILES "${qconfig_pri_target_path}" DESTINATION ${INSTALL_MKSPECSDIR})
-endfunction()
-
-# Creates mkspecs/qdevice.pri which contains target device information for cross-builds.
-# The content of QT_QMAKE_DEVICE_OPTIONS is written verbatim into qdevice.pri.
-function(qt_generate_global_device_pri_file)
- if(NOT CMAKE_CROSSCOMPILING)
- return()
- endif()
-
- qt_path_join(qdevice_pri_target_path ${PROJECT_BINARY_DIR} ${INSTALL_MKSPECSDIR} "qdevice.pri")
-
- set(content "")
- foreach(opt ${QT_QMAKE_DEVICE_OPTIONS})
- string(APPEND content "${opt}\n")
- endforeach()
-
- # Write android specific device info.
- if(ANDROID)
- string(APPEND content "DEFAULT_ANDROID_SDK_ROOT = ${ANDROID_SDK_ROOT}\n")
- string(APPEND content "DEFAULT_ANDROID_NDK_ROOT = ${ANDROID_NDK}\n")
-
- set(android_platform "android-23")
- if(ANDROID_NATIVE_API_LEVEL)
- set(android_platform "android-${ANDROID_NATIVE_API_LEVEL}")
- endif()
- string(APPEND content "DEFAULT_ANDROID_PLATFORM = ${android_platform}\n")
-
- string(APPEND content "DEFAULT_ANDROID_NDK_HOST = ${ANDROID_HOST_TAG}\n")
-
- # TODO: QTBUG-80943 When we eventually support Android multi-abi, this should be changed.
- string(APPEND content "DEFAULT_ANDROID_ABIS = ${ANDROID_ABI}\n")
- endif()
-
- set(gcc_machine_dump "")
- if(TEST_machine_tuple)
- set(gcc_machine_dump "${TEST_machine_tuple}")
- endif()
- string(APPEND content "GCC_MACHINE_DUMP = ${gcc_machine_dump}\n")
-
- file(GENERATE OUTPUT "${qdevice_pri_target_path}" CONTENT "${content}")
- qt_install(FILES "${qdevice_pri_target_path}" DESTINATION ${INSTALL_MKSPECSDIR})
-endfunction()
-
-function(qt_get_build_parts out_var)
- set(parts "libs")
-
- if(BUILD_EXAMPLES AND NOT QT_NO_MAKE_EXAMPLES)
- list(APPEND parts "examples")
- endif()
-
- if(BUILD_TESTING AND NOT QT_NO_MAKE_TESTS)
- list(APPEND parts "tests")
- endif()
-
- if(NOT CMAKE_CROSSCOMPILING OR QT_BUILD_TOOLS_WHEN_CROSSCOMPILING)
- list(APPEND parts "tools")
- endif()
-
- set(${out_var} ${parts} PARENT_SCOPE)
-endfunction()
-
-# Creates mkspecs/qmodule.pri which contains private global features among other things.
-function(qt_generate_global_module_pri_file)
- qt_path_join(qmodule_pri_target_path ${PROJECT_BINARY_DIR} ${INSTALL_MKSPECSDIR})
- qt_path_join(qmodule_pri_target_path "${qmodule_pri_target_path}" "qmodule.pri")
-
- get_target_property(enabled_features GlobalConfig INTERFACE_QT_ENABLED_PRIVATE_FEATURES)
- get_target_property(disabled_features GlobalConfig INTERFACE_QT_DISABLED_PRIVATE_FEATURES)
-
- qt_correct_features(corrected_enabled_features "${enabled_features}")
- qt_correct_features(corrected_disabled_features "${disabled_features}")
-
- string (REPLACE ";" " " corrected_enabled_features "${corrected_enabled_features}")
- string (REPLACE ";" " " corrected_disabled_features "${corrected_disabled_features}")
-
- set(corrected_private_config "")
- get_target_property(private_config GlobalConfig INTERFACE_QT_QMAKE_PRIVATE_CONFIG)
- qt_correct_config(corrected_private_config "${private_config}")
- list(JOIN corrected_private_config " " private_config_joined)
-
- set(content "")
- set(arch "${TEST_architecture_arch}")
- list(JOIN TEST_subarch_result " " subarchs)
- if(CMAKE_CROSSCOMPILING)
- set(host_arch "${QT${PROJECT_VERSION_MAJOR}_HOST_INFO_ARCH}")
- list(JOIN QT${PROJECT_VERSION_MAJOR}_HOST_INFO_SUBARCHS " " host_subarchs)
- string(APPEND content "host_build {
- QT_CPU_FEATURES.${host_arch} = ${host_subarchs}
-} else {
- QT_CPU_FEATURES.${arch} = ${subarchs}
-}
-")
- else()
- string(APPEND content "QT_CPU_FEATURES.${arch} = ${subarchs}\n")
- endif()
-
- string(APPEND content "QT.global_private.enabled_features = ${corrected_enabled_features}
-QT.global_private.disabled_features = ${corrected_disabled_features}
-CONFIG += ${private_config_joined}
-")
- if(PKG_CONFIG_FOUND)
- string(APPEND content "PKG_CONFIG_EXECUTABLE = ${PKG_CONFIG_EXECUTABLE}\n")
- endif()
-
- # TODO: Write QT_COORD_TYPE once we support setting it.
-
- qt_get_build_parts(build_parts)
- string(REPLACE ";" " " build_parts "${build_parts}")
- string(APPEND content "QT_BUILD_PARTS = ${build_parts}\n")
-
- if(QT_EXTRA_RPATHS)
- list(JOIN QT_EXTRA_RPATHS " " extra_rpaths)
- string(APPEND content "EXTRA_RPATHS += ${extra_rpaths}")
- endif()
-
- set(preliminary_pri_root "${CMAKE_CURRENT_BINARY_DIR}/mkspecs/preliminary")
- set(pri_data_cmake_file "qmodule.cmake")
- qt_generate_qmake_libraries_pri_content(global ${preliminary_pri_root} ${pri_data_cmake_file})
-
- # Generate a preliminary qmodule.pri file
- set(preliminary_pri_file_path "${preliminary_pri_root}/qmodule.pri")
- file(GENERATE
- OUTPUT ${preliminary_pri_file_path}
- CONTENT "${content}"
- )
-
- if(QT_GENERATOR_IS_MULTI_CONFIG)
- set(configs ${CMAKE_CONFIGURATION_TYPES})
- else()
- set(configs ${CMAKE_BUILD_TYPE})
- endif()
- set(inputs ${preliminary_pri_file_path})
- foreach(cfg ${configs})
- list(APPEND inputs "${preliminary_pri_root}/${cfg}/${pri_data_cmake_file}")
- endforeach()
-
- set(library_prefixes ${CMAKE_SHARED_LIBRARY_PREFIX} ${CMAKE_STATIC_LIBRARY_PREFIX})
- set(library_suffixes
- ${CMAKE_SHARED_LIBRARY_SUFFIX}
- ${CMAKE_EXTRA_SHARED_LIBRARY_SUFFIXES}
- ${CMAKE_STATIC_LIBRARY_SUFFIX})
- add_custom_command(
- OUTPUT "${qmodule_pri_target_path}"
- DEPENDS ${inputs}
- "${QT_CMAKE_DIR}/QtGenerateLibPri.cmake"
- "${QT_CMAKE_DIR}/QtGenerateLibHelpers.cmake"
- COMMAND ${CMAKE_COMMAND} "-DIN_FILES=${inputs}" "-DOUT_FILE=${qmodule_pri_target_path}"
- "-DLIBRARY_PREFIXES=${library_prefixes}"
- "-DLIBRARY_SUFFIXES=${library_suffixes}"
- "-DLINK_LIBRARY_FLAG=${CMAKE_LINK_LIBRARY_FLAG}"
- "-DCONFIGS=${configs}"
- -P "${QT_CMAKE_DIR}/QtGenerateLibPri.cmake"
- VERBATIM)
- add_custom_target(qmodule_pri DEPENDS "${qmodule_pri_target_path}")
- qt_install(FILES "${qmodule_pri_target_path}" DESTINATION ${INSTALL_MKSPECSDIR})
-endfunction()
-
-# In the cross-compiling case, creates a wrapper around the host Qt's
-# qmake executable. Also creates a qmake configuration file that sets
-# up the host qmake's properties for cross-compiling with this Qt
-# build.
-function(qt_generate_qmake_wrapper_for_target)
- if(NOT CMAKE_CROSSCOMPILING)
- return()
- endif()
-
- # Call the configuration file something else but qt.conf to avoid
- # being picked up by the qmake executable that's created if
- # QT_BUILD_TOOLS_WHEN_CROSSCOMPILING is enabled.
- qt_path_join(qt_conf_path "${INSTALL_BINDIR}" "target_qt.conf")
-
- set(prefix "${CMAKE_INSTALL_PREFIX}")
- set(ext_prefix "${QT_STAGING_PREFIX}")
- set(host_prefix "${QT_HOST_PATH}")
- file(RELATIVE_PATH host_prefix_relative_to_conf_file "${ext_prefix}/${INSTALL_BINDIR}"
- "${host_prefix}")
- file(RELATIVE_PATH ext_prefix_relative_to_conf_file "${ext_prefix}/${INSTALL_BINDIR}"
- "${ext_prefix}")
- file(RELATIVE_PATH ext_prefix_relative_to_host_prefix "${host_prefix}" "${ext_prefix}")
-
- set(content "")
- if(ext_prefix STREQUAL prefix)
- set(sysrootify_prefix true)
- else()
- set(sysrootify_prefix false)
- string(APPEND content "[DevicePaths]
-Prefix=${prefix}
-")
- endif()
-
- if(NOT QT_WILL_INSTALL)
- # The shadow build directory of a non-prefix build does not contain a copy of the mkspecs
- # directory. Let $$[QT_HOST_DATA/src] point to the qtbase source directory.
- string(APPEND content "[EffectiveSourcePaths]
-HostData=${CMAKE_CURRENT_SOURCE_DIR}
-")
-
- # Set $$[QT_HOST_DATA/get] to avoid falling back to the source dir where it isn't explicitly
- # requested.
- # Also make sure to specif the Prefix as well, because it doesn't get inherited from the
- # [Paths] section.
- string(APPEND content "[EffectivePaths]
-HostData=${ext_prefix}
-Prefix=${ext_prefix_relative_to_conf_file}
-")
- endif()
-
- # On Android CMAKE_SYSROOT is set, but for Qt's purposes it should not be set, because then
- # qmake generates incorrect Qt module include flags (among other things). Do the same for darwin
- # cross-compilation.
- set(sysroot "")
- if(CMAKE_SYSROOT AND NOT ANDROID AND NOT UIKIT)
- set(sysroot "${CMAKE_SYSROOT}")
- endif()
-
- string(APPEND content
- "[Paths]
-Prefix=${ext_prefix_relative_to_conf_file}
-HostPrefix=${host_prefix_relative_to_conf_file}
-HostData=${ext_prefix_relative_to_host_prefix}
-Sysroot=${sysroot}
-SysrootifyPrefix=${sysrootify_prefix}
-TargetSpec=${QT_QMAKE_TARGET_MKSPEC}
-HostSpec=${QT_QMAKE_HOST_MKSPEC}
-")
- file(GENERATE OUTPUT "${qt_conf_path}" CONTENT "${content}")
-
- qt_path_join(qmake_wrapper_in_file "${CMAKE_CURRENT_SOURCE_DIR}/bin/qmake-wrapper-for-target")
- qt_path_join(qmake_wrapper "preliminary" "qmake")
- if(QT_BUILD_TOOLS_WHEN_CROSSCOMPILING)
- # Avoid collisions with the cross-compiled qmake binary.
- string(PREPEND qmake_wrapper "host-")
- endif()
- if(CMAKE_HOST_SYSTEM_NAME STREQUAL "Windows")
- string(APPEND qmake_wrapper_in_file ".bat")
- string(APPEND qmake_wrapper ".bat")
- endif()
- string(APPEND qmake_wrapper_in_file ".in")
-
- set(host_qt_bindir "${host_prefix}/${QT${PROJECT_VERSION_MAJOR}_HOST_INFO_BINDIR}")
-
- configure_file("${qmake_wrapper_in_file}" "${qmake_wrapper}" @ONLY)
- qt_install(FILES "${CMAKE_CURRENT_BINARY_DIR}/${qt_conf_path}"
- DESTINATION "${INSTALL_BINDIR}")
- qt_copy_or_install(PROGRAMS "${CMAKE_CURRENT_BINARY_DIR}/${qmake_wrapper}"
- DESTINATION "${INSTALL_BINDIR}")
-endfunction()
-
-# Takes a list of path components and joins them into one path separated by forward slashes "/",
-# and saves the path in out_var.
-function(qt_path_join out_var)
- string(JOIN "/" path ${ARGN})
- set(${out_var} ${path} PARENT_SCOPE)
-endfunction()
-
-function(qt_internal_export_modern_cmake_config_targets_file)
- cmake_parse_arguments(__arg "" "EXPORT_NAME_PREFIX;CONFIG_INSTALL_DIR" "TARGETS" ${ARGN})
-
- set(export_name "${__arg_EXPORT_NAME_PREFIX}VersionlessTargets")
- foreach(target ${__arg_TARGETS})
- if (TARGET "${target}Versionless")
- continue()
- endif()
-
- add_library("${target}Versionless" INTERFACE)
- target_link_libraries("${target}Versionless" INTERFACE "${target}")
- set_target_properties("${target}Versionless" PROPERTIES
- EXPORT_NAME "${target}"
- _qt_is_versionless_target "TRUE")
- set_property(TARGET "${target}Versionless"
- APPEND PROPERTY EXPORT_PROPERTIES _qt_is_versionless_target)
-
- qt_install(TARGETS "${target}Versionless" EXPORT ${export_name})
- endforeach()
- qt_install(EXPORT ${export_name} NAMESPACE Qt:: DESTINATION "${__arg_CONFIG_INSTALL_DIR}")
-endfunction()
-
-# Print all variables defined in the current scope.
-macro(qt_debug_print_variables)
- cmake_parse_arguments(__arg "DEDUP" "" "MATCH;IGNORE" ${ARGN})
- message("Known Variables:")
- get_cmake_property(__variableNames VARIABLES)
- list (SORT __variableNames)
- if (__arg_DEDUP)
- list(REMOVE_DUPLICATES __variableNames)
- endif()
-
- foreach(__var ${__variableNames})
- set(__ignore OFF)
- foreach(__i ${__arg_IGNORE})
- if(__var MATCHES "${__i}")
- set(__ignore ON)
- break()
- endif()
- endforeach()
-
- if (__ignore)
- continue()
- endif()
-
- set(__show OFF)
- foreach(__i ${__arg_MATCH})
- if(__var MATCHES "${__i}")
- set(__show ON)
- break()
- endif()
- endforeach()
-
- if (__show)
- message(" ${__var}=${${__var}}.")
- endif()
- endforeach()
-endmacro()
-
-
-macro(assert)
- if (${ARGN})
- else()
- message(FATAL_ERROR "ASSERT: ${ARGN}.")
- endif()
-endmacro()
-
-
-function(qt_create_nolink_target target dependee_target)
- if(NOT TARGET "${target}")
- message(FATAL_ERROR "${target} does not exist when trying to build a nolink target.")
- endif()
- get_target_property(type "${target}" TYPE)
- if(type STREQUAL EXECUTABLE)
- message(FATAL_ERROR "${target} must be a library of some kind.")
- endif()
- if(type STREQUAL OBJECT_LIBRARY)
- message(FATAL_ERROR "${target} must not be an object library.")
- endif()
-
- # Strip off the namespace prefix, so from Vulkan::Vulkan to Vulkan, and then append _nolink.
- string(REGEX REPLACE "^.*::" "" non_prefixed_target ${target})
- set(nolink_target "${non_prefixed_target}_nolink")
-
- # Create the nolink interface target, assign the properties from the original target,
- # associate the nolink target with the same export which contains
- # the target that uses the _nolink target.
- # Also create a namespaced alias of the form ${target}::${target}_nolink which is used by
- # our modules.
- # Also create a Qt namespaced alias target, because when exporting via install(EXPORT)
- # Vulkan::Vulkan_nolink transforms into Qt6::Vulkan_nolink, and the latter needs to be an
- # accessible alias for standalone tests.
- if(NOT TARGET "${nolink_target}")
- add_library("${nolink_target}" INTERFACE)
- set(prefixed_nolink_target "${target}_nolink")
-
- # Whe configuring an example with qmake, if QtGui is built with Vulkan support but the
- # user's machine where Qt is installed doesn't have Vulkan, qmake doesn't fail saying
- # that vulkan is not installed. Instead it silently configures and just doesn't add
- # the include headers.
- # To mimic that in CMake, if the Vulkan CMake package is not found, we shouldn't fail
- # at generation time saying that the Vulkan target does not exist. Instead check with a
- # genex that the target exists to query the properties, otherwise just silently continue.
- # FIXME: If we figure out that such behavior should only be applied to Vulkan, and not the
- # other _nolink targets, we'll have to modify this to be configurable.
- set(target_exists_genex "$<TARGET_EXISTS:${target}>")
- set(props_to_set INTERFACE_INCLUDE_DIRECTORIES INTERFACE_SYSTEM_INCLUDE_DIRECTORIES
- INTERFACE_COMPILE_DEFINITIONS INTERFACE_COMPILE_OPTIONS
- INTERFACE_COMPILE_FEATURES)
- foreach(prop ${props_to_set})
- set_target_properties(
- "${nolink_target}" PROPERTIES
- ${prop} $<${target_exists_genex}:$<TARGET_PROPERTY:${target},${prop}>>
- )
- endforeach()
-
- add_library(${prefixed_nolink_target} ALIAS ${nolink_target})
- add_library("${INSTALL_CMAKE_NAMESPACE}::${nolink_target}" ALIAS ${nolink_target})
-
- set(export_name "${INSTALL_CMAKE_NAMESPACE}${dependee_target}Targets")
- qt_install(TARGETS ${nolink_target} EXPORT ${export_name})
- endif()
-endfunction()
-
-function(qt_ensure_perl)
- if(DEFINED HOST_PERL)
- return()
- endif()
- find_program(HOST_PERL "perl" DOC "Perl binary")
- if (NOT HOST_PERL)
- message(FATAL_ERROR "Perl needs to be available to build Qt.")
- endif()
-endfunction()
-
-
-function(qt_ensure_sync_qt)
- qt_ensure_perl()
- if(DEFINED QT_SYNCQT)
- return()
- endif()
-
- # When building qtbase, use the source syncqt, otherwise use the installed one.
- set(SYNCQT_FROM_SOURCE "${QtBase_SOURCE_DIR}/bin/syncqt.pl")
- if(NOT ("${QtBase_SOURCE_DIR}" STREQUAL "") AND EXISTS "${SYNCQT_FROM_SOURCE}")
- set(QT_SYNCQT "${SYNCQT_FROM_SOURCE}" CACHE FILEPATH "syncqt script")
- message(STATUS "Using source syncqt found at: ${QT_SYNCQT}")
-
- qt_path_join(syncqt_install_dir ${QT_INSTALL_DIR} ${INSTALL_LIBEXECDIR})
- qt_copy_or_install(PROGRAMS "${SYNCQT_FROM_SOURCE}"
- DESTINATION "${syncqt_install_dir}")
-
- qt_path_join(syncqt_install_dir ${QT_INSTALL_DIR} ${INSTALL_BINDIR})
- qt_copy_or_install(PROGRAMS "${SYNCQT_FROM_SOURCE}"
- DESTINATION "${syncqt_install_dir}")
- elseif(QT_HOST_PATH)
- get_filename_component(syncqt_absolute_path
- "${QT_HOST_PATH}/${INSTALL_LIBEXECDIR}/syncqt.pl"
- ABSOLUTE)
- set(QT_SYNCQT "${syncqt_absolute_path}" CACHE FILEPATH "syncqt script")
- message(STATUS "Using host syncqt found at: ${QT_SYNCQT}")
- else()
- get_filename_component(syncqt_absolute_path
- "${QT_BUILD_INTERNALS_RELOCATABLE_INSTALL_PREFIX}/${INSTALL_LIBEXECDIR}/syncqt.pl"
- ABSOLUTE)
- set(QT_SYNCQT "${syncqt_absolute_path}" CACHE FILEPATH "syncqt script")
- message(STATUS "Using installed syncqt found at: ${QT_SYNCQT}")
- endif()
-endfunction()
-
-# A version of cmake_parse_arguments that makes sure all arguments are processed and errors out
-# with a message about ${type} having received unknown arguments.
-macro(qt_parse_all_arguments result type flags options multiopts)
- cmake_parse_arguments(${result} "${flags}" "${options}" "${multiopts}" ${ARGN})
- if(DEFINED ${result}_UNPARSED_ARGUMENTS)
- message(FATAL_ERROR "Unknown arguments were passed to ${type} (${${result}_UNPARSED_ARGUMENTS}).")
- endif()
-endmacro()
-
-include(CheckCXXSourceCompiles)
-
-function(qt_internal_add_link_flags_no_undefined target)
- if (NOT QT_BUILD_SHARED_LIBS)
- return()
- endif()
- if (GCC OR CLANG)
- set(previous_CMAKE_REQUIRED_LINK_OPTIONS ${CMAKE_REQUIRED_LINK_OPTIONS})
-
- set(CMAKE_REQUIRED_LINK_OPTIONS "-Wl,-undefined,error")
- check_cxx_source_compiles("int main() {}" HAVE_DASH_UNDEFINED_SYMBOLS)
- if(HAVE_DASH_UNDEFINED_SYMBOLS)
- set(no_undefined_flag "-Wl,-undefined,error")
- endif()
-
- set(CMAKE_REQUIRED_LINK_OPTIONS "-Wl,--no-undefined")
- check_cxx_source_compiles("int main() {}" HAVE_DASH_DASH_NO_UNDEFINED)
- if(HAVE_DASH_DASH_NO_UNDEFINED)
- set(no_undefined_flag "-Wl,--no-undefined")
- endif()
-
- set(CMAKE_REQUIRED_LINK_OPTIONS ${previous_CMAKE_REQUIRED_LINK_OPTIONS})
-
- if (NOT HAVE_DASH_UNDEFINED_SYMBOLS AND NOT HAVE_DASH_DASH_NO_UNDEFINED)
- message(FATAL_ERROR "Platform linker doesn't support erroring upon encountering undefined symbols. Target:\"${target}\".")
- endif()
- target_link_options("${target}" PRIVATE "${no_undefined_flag}")
- endif()
-endfunction()
-
-function(qt_internal_apply_gc_binaries_conditional target visibility)
- # Should only be applied when the feature is enabled, aka for static builds.
- if(NOT QT_FEATURE_gc_binaries)
- return()
- endif()
- qt_internal_apply_gc_binaries("${target}" "${visibility}")
-endfunction()
-
-function(qt_internal_apply_gc_binaries target visibility)
- set(possible_visibilities PRIVATE INTERFACE PUBLIC)
- list(FIND possible_visibilities "${visibility}" known_visibility)
- if (known_visibility EQUAL "-1")
- message(FATAL_ERROR "Visibitily setting must be one of PRIVATE, INTERFACE or PUBLIC.")
- endif()
-
- if ((GCC OR CLANG) AND NOT EMSCRIPTEN AND NOT UIKIT)
- if(APPLE)
- set(gc_sections_flag "-Wl,-dead_strip")
- elseif(SOLARIS)
- set(gc_sections_flag "-Wl,-z,ignore")
- elseif(LINUX OR BSD OR WIN32 OR ANDROID)
- set(gc_sections_flag "-Wl,--gc-sections")
- endif()
- endif()
- if(gc_sections_flag)
- target_link_options("${target}" ${visibility} "${gc_sections_flag}")
- endif()
-
- if((GCC OR CLANG OR ICC) AND NOT EMSCRIPTEN AND NOT UIKIT)
- set(split_sections_flags "-ffunction-sections" "-fdata-sections")
- endif()
- if(split_sections_flags)
- target_compile_options("${target}" ${visibility} ${split_sections_flags})
- endif()
-endfunction()
-
-function(qt_internal_apply_intel_cet target visibility)
- if(NOT QT_FEATURE_intelcet)
- return()
- endif()
-
- set(possible_visibilities PRIVATE INTERFACE PUBLIC)
- list(FIND possible_visibilities "${visibility}" known_visibility)
- if (known_visibility EQUAL "-1")
- message(FATAL_ERROR "Visibitily setting must be one of PRIVATE, INTERFACE or PUBLIC.")
- endif()
-
- if(GCC)
- set(flags "-mshstk")
- endif()
- if(flags)
- target_compile_options("${target}" ${visibility} "${flags}")
- endif()
-endfunction()
-
-function(qt_internal_add_linker_version_script target)
- qt_parse_all_arguments(arg "qt_internal_add_linker" "INTERNAL" "" "PRIVATE_HEADERS" ${ARGN})
-
- if (TEST_ld_version_script)
- if (arg_INTERNAL)
- set(contents "Qt_${PROJECT_VERSION_MAJOR}_PRIVATE_API { *; };")
- else()
- set(contents "Qt_${PROJECT_VERSION_MAJOR}_PRIVATE_API {\n qt_private_api_tag*;\n")
- foreach(ph ${arg_PRIVATE_HEADERS})
- string(APPEND contents " @FILE:${ph}@\n")
- endforeach()
- string(APPEND contents "};\n")
- set(current "Qt_${PROJECT_VERSION_MAJOR}")
- if (QT_NAMESPACE STREQUAL "")
- set(tag_symbol "qt_version_tag")
- else()
- set(tag_symbol "qt_version_tag_${QT_NAMESPACE}")
- endif()
- string(APPEND contents "${current} { *; };\n")
-
- foreach(minor_version RANGE ${PROJECT_VERSION_MINOR})
- set(previous "${current}")
- set(current "Qt_${PROJECT_VERSION_MAJOR}.${minor_version}")
- if (minor_version EQUAL ${PROJECT_VERSION_MINOR})
- string(APPEND contents "${current} { ${tag_symbol}; } ${previous};\n")
- else()
- string(APPEND contents "${current} {} ${previous};\n")
- endif()
- endforeach()
-
- set(infile "${CMAKE_CURRENT_BINARY_DIR}/${target}.version.in")
- set(outfile "${CMAKE_CURRENT_BINARY_DIR}/${target}.version")
-
- file(GENERATE OUTPUT "${infile}" CONTENT "${contents}")
-
- qt_ensure_perl()
-
- add_custom_command(TARGET "${target}" PRE_LINK
- COMMAND "${HOST_PERL}" "${QT_MKSPECS_DIR}/features/data/unix/findclasslist.pl" < "${infile}" > "${outfile}"
- BYPRODUCTS "${outfile}" DEPENDS "${infile}"
- WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
- COMMENT "Generating version linker script"
- )
- target_link_options("${target}" PRIVATE "-Wl,--version-script,${outfile}")
- endif()
- endif()
-endfunction()
-
-
-# Get a set of Qt module related values based on the target name.
-# When doing qt_internal_module_info(foo Core) this method will set
-# the following variables in the caller's scope:
-# * foo with the value "QtCore"
-# * foo_versioned with the value "Qt6Core" (based on major Qt version)
-# * foo_upper with the value "CORE"
-# * foo_lower with the value "core"
-# * foo_repo_include_dir with the module's include directory
-# e.g for QtQuick it would be qtdeclarative_build_dir/include for a prefix build or
-# qtbase_build_dir/include for a non-prefix build
-# * foo_include_dir with the module's include directory
-# e.g for QtQuick it would be qtdeclarative_build_dir/include/QtQuick for a prefix build or
-# qtbase_build_dir/include/QtQuick for a non-prefix build
-# * foo_define same as foo_uper but with - replaced as _
-function(qt_internal_module_info result target)
- set(module "Qt${target}")
- set("${result}" "${module}" PARENT_SCOPE)
- set("${result}_versioned" "Qt${PROJECT_VERSION_MAJOR}${target}" PARENT_SCOPE)
- string(TOUPPER "${target}" upper)
- string(TOLOWER "${target}" lower)# * foo_upper with the value "CORE"
- string(REPLACE "-" "_" define "${upper}")
- string(REPLACE "." "_" define "${define}")
- set("${result}_upper" "${upper}" PARENT_SCOPE)
- set("${result}_lower" "${lower}" PARENT_SCOPE)
- set("${result}_repo_include_dir" "${QT_BUILD_DIR}/${INSTALL_INCLUDEDIR}" PARENT_SCOPE)
- set("${result}_include_dir" "${QT_BUILD_DIR}/${INSTALL_INCLUDEDIR}/${module}" PARENT_SCOPE)
- set("${result}_define" "${define}" PARENT_SCOPE)
-endfunction()
-
-
-set(__default_private_args "SOURCES;LIBRARIES;INCLUDE_DIRECTORIES;DEFINES;DBUS_ADAPTOR_BASENAME;DBUS_ADAPTOR_FLAGS;DBUS_ADAPTOR_SOURCES;DBUS_INTERFACE_BASENAME;DBUS_INTERFACE_FLAGS;DBUS_INTERFACE_SOURCES;FEATURE_DEPENDENCIES;COMPILE_OPTIONS;LINK_OPTIONS;MOC_OPTIONS;DISABLE_AUTOGEN_TOOLS;ENABLE_AUTOGEN_TOOLS;PLUGIN_TYPES")
-
-set(__default_public_args "PUBLIC_LIBRARIES;PUBLIC_INCLUDE_DIRECTORIES;PUBLIC_DEFINES;PUBLIC_COMPILE_OPTIONS;PUBLIC_LINK_OPTIONS")
-set(__default_private_module_args "PRIVATE_MODULE_INTERFACE")
-set(__default_target_info_args TARGET_VERSION TARGET_PRODUCT TARGET_DESCRIPTION TARGET_COMPANY
- TARGET_COPYRIGHT)
-
-option(QT_CMAKE_DEBUG_EXTEND_TARGET "Debug extend_target calls in Qt's build system" OFF)
-
-# Initial autogen setup for a target to specify certain CMake properties which are common
-# to all autogen tools. Also enable AUTOMOC by default.
-function(qt_autogen_tools_initial_setup target)
- set_property(TARGET "${target}" PROPERTY INTERFACE_QT_MAJOR_VERSION ${PROJECT_VERSION_MAJOR})
- set_property(TARGET "${target}" APPEND PROPERTY COMPATIBLE_INTERFACE_STRING QT_MAJOR_VERSION)
-
- set_directory_properties(PROPERTIES
- QT_VERSION_MAJOR ${PROJECT_VERSION_MAJOR}
- QT_VERSION_MINOR ${PROJECT_VERSION_MINOR}
- QT_VERSION_PATCH ${PROJECT_VERSION_PATCH}
- )
-
- qt_enable_autogen_tool(${target} "moc" ON)
-endfunction()
-
-# Enables or disables an autogen tool like moc, uic or rcc on ${target}.
-function(qt_enable_autogen_tool target tool enable)
- string(TOUPPER "${tool}" captitalAutogenTool)
-
- get_target_property(tool_enabled ${target} AUTO${captitalAutogenTool})
- get_target_property(autogen_target_depends ${target} AUTOGEN_TARGET_DEPENDS)
-
- if(NOT autogen_target_depends)
- set(autogen_target_depends "")
- endif()
- set(tool_executable "$<TARGET_FILE:${QT_CMAKE_EXPORT_NAMESPACE}::${tool}>")
- set(tool_target_name ${QT_CMAKE_EXPORT_NAMESPACE}::${tool})
-
- if(enable)
- list(APPEND autogen_target_depends ${tool_target_name})
- else()
- list(REMOVE_ITEM autogen_target_depends ${tool_target_name})
- endif()
-
- # f66c1db16c050c9d685a44a38ad7c5cf9f6fcc96 in qtbase introduced a new macro
- # that the moc scanner has to look for. Inform the CMake moc scanner about it.
- if(tool STREQUAL "moc" AND enable)
- set_target_properties("${target}" PROPERTIES
- AUTOMOC_MACRO_NAMES "Q_OBJECT;Q_GADGET;Q_NAMESPACE;Q_NAMESPACE_EXPORT;Q_ENUM_NS")
- endif()
-
- set_target_properties("${target}"
- PROPERTIES
- AUTO${captitalAutogenTool} "${enable}"
- AUTO${captitalAutogenTool}_EXECUTABLE "${tool_executable}"
- AUTOGEN_TARGET_DEPENDS "${autogen_target_depends}"
- )
-endfunction()
-
-# This function adds or removes additional AUTOGEN tools to a target: AUTOMOC/UIC/RCC
-function(qt_autogen_tools target)
- qt_parse_all_arguments(arg "qt_autogen_tools" "" "" "${__default_private_args}" ${ARGN})
-
- if (arg_ENABLE_AUTOGEN_TOOLS)
- foreach(tool ${arg_ENABLE_AUTOGEN_TOOLS})
- qt_enable_autogen_tool(${target} ${tool} ON)
- endforeach()
- endif()
-
- if (arg_DISABLE_AUTOGEN_TOOLS)
- foreach(tool ${arg_DISABLE_AUTOGEN_TOOLS})
- qt_enable_autogen_tool(${target} ${tool} OFF)
- endforeach()
- endif()
-endfunction()
-
-# This function stores the list of Qt modules a library depend on,
-# along with their version info, for usage in ${target}Depends.cmake file
-function(qt_register_target_dependencies target public_libs private_libs)
- get_target_property(target_deps "${target}" _qt_target_deps)
- if(NOT target_deps)
- set(target_deps "")
- endif()
-
- # Only process private dependencies if target is a static library
- get_target_property(target_type ${target} TYPE)
- set(lib_list ${public_libs})
- if (target_type STREQUAL "STATIC_LIBRARY")
- list(APPEND lib_list ${private_libs})
- endif()
-
- foreach(lib IN LISTS lib_list)
- if ("${lib}" MATCHES "^Qt::(.*)")
- set(lib "${CMAKE_MATCH_1}")
- if (lib STREQUAL Platform
- OR lib STREQUAL GlobalConfig
- OR lib STREQUAL GlobalConfigPrivate
- OR lib STREQUAL PlatformModuleInternal
- OR lib STREQUAL PlatformPluginInternal
- OR lib STREQUAL PlatformToolInternal)
- list(APPEND target_deps "Qt6\;${PROJECT_VERSION}")
- elseif ("${lib}" MATCHES "(.*)Private")
- list(APPEND target_deps "${INSTALL_CMAKE_NAMESPACE}${CMAKE_MATCH_1}\;${PROJECT_VERSION}")
- else()
- list(APPEND target_deps "${INSTALL_CMAKE_NAMESPACE}${lib}\;${PROJECT_VERSION}")
- endif()
- endif()
- endforeach()
-
- set_target_properties("${target}" PROPERTIES _qt_target_deps "${target_deps}")
-endfunction()
-
-function(qt_update_precompiled_header target precompiled_header)
- if (precompiled_header AND BUILD_WITH_PCH)
- set_property(TARGET "${target}" APPEND PROPERTY "PRECOMPILE_HEADERS" "$<$<OR:$<COMPILE_LANGUAGE:CXX>,$<COMPILE_LANGUAGE:OBJCXX>>:${precompiled_header}>")
- endif()
-endfunction()
-
-function(qt_update_precompiled_header_with_library target library)
- if (TARGET "${library}")
- get_target_property(TARGET_TYPE "${library}" TYPE)
- if (NOT TARGET_TYPE STREQUAL "INTERFACE_LIBRARY")
- get_target_property(HEADER "${library}" MODULE_HEADER)
- qt_update_precompiled_header("${target}" "${HEADER}")
- endif()
- endif()
-endfunction()
-
-function(qt_update_ignore_pch_source target sources)
- if (sources)
- set_source_files_properties(${sources} PROPERTIES SKIP_PRECOMPILE_HEADERS ON)
- endif()
-endfunction()
-
-function(qt_ignore_pch_obj_c_sources target sources)
- # No obj-cxx PCH support for versions lower than 3.16.
- if(CMAKE_VERSION VERSION_LESS 3.16.0)
- list(FILTER sources INCLUDE REGEX "\\.mm$")
- qt_update_ignore_pch_source("${target}" "${sources}")
- endif()
-endfunction()
-
-# This function can be used to add sources/libraries/etc. to the specified CMake target
-# if the provided CONDITION evaluates to true.
-function(qt_extend_target target)
- # Don't try to extend_target when cross compiling an imported host target (like a tool).
- qt_is_imported_target("${target}" is_imported)
- if(is_imported)
- return()
- endif()
-
- if (NOT TARGET "${target}")
- message(FATAL_ERROR "Trying to extend non-existing target \"${target}\".")
- endif()
- qt_parse_all_arguments(arg "qt_extend_target" "HEADER_MODULE" "PRECOMPILED_HEADER"
- "CONDITION;${__default_public_args};${__default_private_args};${__default_private_module_args};COMPILE_FLAGS;NO_PCH_SOURCES" ${ARGN})
- if ("x${arg_CONDITION}" STREQUAL x)
- set(arg_CONDITION ON)
- endif()
-
- qt_evaluate_config_expression(result ${arg_CONDITION})
- if (${result})
- if(QT_CMAKE_DEBUG_EXTEND_TARGET)
- message("qt_extend_target(${target} CONDITION ${arg_CONDITION} ...): Evaluated")
- endif()
- set(dbus_sources "")
- foreach(adaptor ${arg_DBUS_ADAPTOR_SOURCES})
- qt_create_qdbusxml2cpp_command("${target}" "${adaptor}" ADAPTOR BASENAME "${arg_DBUS_ADAPTOR_BASENAME}" FLAGS "${arg_DBUS_ADAPTOR_FLAGS}")
- list(APPEND dbus_sources "${sources}")
- endforeach()
-
- foreach(interface ${arg_DBUS_INTERFACE_SOURCES})
- qt_create_qdbusxml2cpp_command("${target}" "${interface}" INTERFACE BASENAME "${arg_DBUS_INTERFACE_BASENAME}" FLAGS "${arg_DBUS_INTERFACE_FLAGS}")
- list(APPEND dbus_sources "${sources}")
- endforeach()
-
- get_target_property(target_type ${target} TYPE)
- set(is_library FALSE)
- if (${target_type} STREQUAL "STATIC_LIBRARY" OR ${target_type} STREQUAL "SHARED_LIBRARY")
- set(is_library TRUE)
- endif()
- foreach(lib ${arg_PUBLIC_LIBRARIES} ${arg_LIBRARIES})
- # Automatically generate PCH for 'target' using dependencies
- # if 'target' is a library/module!
- if (${is_library})
- qt_update_precompiled_header_with_library("${target}" "${lib}")
- endif()
-
- string(REGEX REPLACE "_nolink$" "" base_lib "${lib}")
- if(NOT base_lib STREQUAL lib)
- qt_create_nolink_target("${base_lib}" ${target})
- endif()
- endforeach()
-
- # Set-up the target
- target_sources("${target}" PRIVATE ${arg_SOURCES} ${dbus_sources})
- if (arg_COMPILE_FLAGS)
- set_source_files_properties(${arg_SOURCES} PROPERTIES COMPILE_FLAGS "${arg_COMPILE_FLAGS}")
- endif()
-
- set(public_visibility_option "PUBLIC")
- set(private_visibility_option "PRIVATE")
- if(arg_HEADER_MODULE)
- set(public_visibility_option "INTERFACE")
- set(private_visibility_option "INTERFACE")
- endif()
- target_include_directories("${target}"
- ${public_visibility_option} ${arg_PUBLIC_INCLUDE_DIRECTORIES}
- ${private_visibility_option} ${arg_INCLUDE_DIRECTORIES})
- target_compile_definitions("${target}"
- ${public_visibility_option} ${arg_PUBLIC_DEFINES}
- ${private_visibility_option} ${arg_DEFINES})
- target_link_libraries("${target}"
- ${public_visibility_option} ${arg_PUBLIC_LIBRARIES}
- ${private_visibility_option} ${arg_LIBRARIES})
- target_compile_options("${target}"
- ${public_visibility_option} ${arg_PUBLIC_COMPILE_OPTIONS}
- ${private_visibility_option} ${arg_COMPILE_OPTIONS})
- target_link_options("${target}"
- ${public_visibility_option} ${arg_PUBLIC_LINK_OPTIONS}
- ${private_visibility_option} ${arg_LINK_OPTIONS})
-
- if(NOT arg_HEADER_MODULE)
- set_property (TARGET "${target}" APPEND PROPERTY
- AUTOMOC_MOC_OPTIONS "${arg_MOC_OPTIONS}"
- )
- endif()
-
- # When computing the private library dependencies, we need to check not only the known
- # modules added by this repo's qt_build_repo(), but also all module dependencies that
- # were found via find_package().
- qt_internal_get_qt_all_known_modules(known_modules)
-
- # When a public module depends on a private module (Gui on CorePrivate)
- # make its private module depend on the other private module (GuiPrivate will depend on
- # CorePrivate).
- set(qt_libs_private "")
- foreach(it ${known_modules})
- list(FIND arg_LIBRARIES "Qt::${it}Private" pos)
- if(pos GREATER -1)
- list(APPEND qt_libs_private "Qt::${it}Private")
- endif()
- endforeach()
-
- set(target_private "${target}Private")
- if(TARGET "${target_private}")
- target_link_libraries("${target_private}"
- INTERFACE ${arg_PRIVATE_MODULE_INTERFACE})
- endif()
- qt_register_target_dependencies("${target}"
- "${arg_PUBLIC_LIBRARIES}"
- "${qt_libs_private};${arg_LIBRARIES}")
-
-
- qt_autogen_tools(${target}
- ENABLE_AUTOGEN_TOOLS ${arg_ENABLE_AUTOGEN_TOOLS}
- DISABLE_AUTOGEN_TOOLS ${arg_DISABLE_AUTOGEN_TOOLS})
-
- qt_update_precompiled_header("${target}" "${arg_PRECOMPILED_HEADER}")
- qt_update_ignore_pch_source("${target}" "${arg_NO_PCH_SOURCES}")
- ## Ignore objective-c files for PCH (not supported atm)
- qt_ignore_pch_obj_c_sources("${target}" "${arg_SOURCES}")
-
- else()
- if(QT_CMAKE_DEBUG_EXTEND_TARGET)
- message("qt_extend_target(${target} CONDITION ${arg_CONDITION} ...): Skipped")
- endif()
- endif()
-endfunction()
-
-
-function(qt_internal_library_deprecation_level result)
- if(WIN32)
- # On Windows, due to the way DLLs work, we need to export all functions,
- # including the inlines
- list(APPEND deprecations "QT_DISABLE_DEPRECATED_BEFORE=0x040800")
- else()
- # On other platforms, Qt's own compilation goes needs to compile the Qt 5.0 API
- list(APPEND deprecations "QT_DISABLE_DEPRECATED_BEFORE=0x050000")
- endif()
- list(APPEND deprecations "QT_DEPRECATED_WARNINGS_SINCE=0x060000")
- set("${result}" deprecations PARENT_SCOPE)
-endfunction()
-
-
-function(qt_install_injections target build_dir install_dir)
- set(injections ${ARGN})
- set(module "Qt${target}")
- get_target_property(target_type ${target} TYPE)
- if (target_type STREQUAL "INTERFACE_LIBRARY")
- set(is_framework FALSE)
- else()
- get_target_property(is_framework ${target} FRAMEWORK)
- endif()
- # examples:
- # SYNCQT.INJECTIONS = src/corelib/global/qconfig.h:qconfig.h:QtConfig src/corelib/global/qconfig_p.h:5.12.0/QtCore/private/qconfig_p.h
- # SYNCQT.INJECTIONS = src/gui/vulkan/qvulkanfunctions.h:^qvulkanfunctions.h:QVulkanFunctions:QVulkanDeviceFunctions src/gui/vulkan/qvulkanfunctions_p.h:^5.12.0/QtGui/private/qvulkanfunctions_p.h
- # The are 3 parts to the assignment, divded by colons ':'.
- # The first part contains a path to a generated file in a build folder.
- # The second part contains the file name that the forwarding header should have, which points
- # to the file in the first part.
- # The third part contains multiple UpperCaseFileNames that should be forwarding headers to the
- # header specified in the second part.
- separate_arguments(injections UNIX_COMMAND "${injections}")
- foreach(injection ${injections})
- string(REPLACE ":" ";" injection ${injection})
- # Part 1.
- list(GET injection 0 file)
- # Part 2.
- list(GET injection 1 destination)
- string(REGEX REPLACE "^\\^" "" destination "${destination}")
- list(REMOVE_AT injection 0 1)
- # Part 3.
- set(fwd_hdrs ${injection})
- get_filename_component(destinationdir ${destination} DIRECTORY)
- get_filename_component(destinationname ${destination} NAME)
- get_filename_component(original_file_name ${file} NAME)
-
- # This describes a concrete example for easier comprehension:
- # A file 'qtqml-config.h' is generated by qt_internal_feature_write_file into
- # ${qtdeclarative_build_dir}/src/{module}/qtqml-config.h (part 1).
- #
- # Generate a lower case forwarding header (part 2) 'qtqml-config.h' at the following
- # location:
- # ${some_prefix}/include/${module}/qtqml-config.h.
- #
- # Inside this file, we #include the originally generated file,
- # ${qtdeclarative_build_dir}/src/{module}/qtqml-config.h.
- #
- # ${some_prefix}'s value depends on the build type.
- # If doing a prefix build, it should point to
- # ${current_repo_build_dir} which is ${qtdeclarative_build_dir}.
- # If doing a non-prefix build, it should point to
- # ${qtbase_build_dir}.
- #
- # In the code below, ${some_prefix} == ${build_dir}.
- set(lower_case_forwarding_header_path "${build_dir}/${INSTALL_INCLUDEDIR}/${module}")
- if(destinationdir)
- string(APPEND lower_case_forwarding_header_path "/${destinationdir}")
- endif()
- set(current_repo_build_dir "${PROJECT_BINARY_DIR}")
-
- file(RELATIVE_PATH relpath
- "${lower_case_forwarding_header_path}"
- "${current_repo_build_dir}/${file}")
- set(main_contents "#include \"${relpath}\"")
-
- qt_configure_file(OUTPUT "${lower_case_forwarding_header_path}/${original_file_name}"
- CONTENT "${main_contents}")
-
- if(is_framework)
- if(file MATCHES "_p\\.h$")
- set(header_type PRIVATE)
- else()
- set(header_type PUBLIC)
- endif()
- qt_copy_framework_headers(${target} ${header_type}
- ${current_repo_build_dir}/${file})
- else()
- # Copy the actual injected (generated) header file (not the just created forwarding one)
- # to its install location when doing a prefix build. In an non-prefix build, the qt_install
- # will be a no-op.
- qt_path_join(install_destination
- ${install_dir} ${INSTALL_INCLUDEDIR} ${module} ${destinationdir})
- qt_install(FILES ${current_repo_build_dir}/${file}
- DESTINATION ${install_destination}
- RENAME ${destinationname} OPTIONAL)
- endif()
-
- # Generate UpperCaseNamed forwarding headers (part 3).
- foreach(fwd_hdr ${fwd_hdrs})
- set(upper_case_forwarding_header_path "${INSTALL_INCLUDEDIR}/${module}")
- if(destinationdir)
- string(APPEND upper_case_forwarding_header_path "/${destinationdir}")
- endif()
-
- # Generate upper case forwarding header like QVulkanFunctions or QtConfig.
- qt_configure_file(OUTPUT "${build_dir}/${upper_case_forwarding_header_path}/${fwd_hdr}"
- CONTENT "#include \"${destinationname}\"\n")
-
- if(is_framework)
- # Copy the forwarding header to the framework's Headers directory.
- qt_copy_framework_headers(${target} PUBLIC
- "${build_dir}/${upper_case_forwarding_header_path}/${fwd_hdr}")
- else()
- # Install the forwarding header.
- qt_path_join(install_destination
- ${install_dir} ${upper_case_forwarding_header_path})
- qt_install(FILES "${build_dir}/${upper_case_forwarding_header_path}/${fwd_hdr}"
- DESTINATION ${install_destination} OPTIONAL)
- endif()
- endforeach()
- endforeach()
-endfunction()
-
-
-function(qt_read_headers_pri module_include_dir resultVarPrefix)
- file(STRINGS "${module_include_dir}/headers.pri" headers_pri_contents)
- foreach(line ${headers_pri_contents})
- if("${line}" MATCHES "SYNCQT.HEADER_FILES = (.*)")
- set(public_module_headers "${CMAKE_MATCH_1}")
- separate_arguments(public_module_headers UNIX_COMMAND "${public_module_headers}")
- elseif("${line}" MATCHES "SYNCQT.PRIVATE_HEADER_FILES = (.*)")
- set(private_module_headers "${CMAKE_MATCH_1}")
- separate_arguments(private_module_headers UNIX_COMMAND "${private_module_headers}")
- elseif("${line}" MATCHES "SYNCQT.GENERATED_HEADER_FILES = (.*)")
- set(generated_module_headers "${CMAKE_MATCH_1}")
- separate_arguments(generated_module_headers UNIX_COMMAND "${generated_module_headers}")
- foreach(generated_header ${generated_module_headers})
- list(APPEND public_module_headers "${module_include_dir}/${generated_header}")
- endforeach()
- elseif("${line}" MATCHES "SYNCQT.INJECTIONS = (.*)")
- set(injections "${CMAKE_MATCH_1}")
- elseif("${line}" MATCHES "SYNCQT.([A-Z_]+)_HEADER_FILES = (.+)")
- set(prefix "${CMAKE_MATCH_1}")
- string(TOLOWER "${prefix}" prefix)
- set(entries "${CMAKE_MATCH_2}")
- separate_arguments(entries UNIX_COMMAND "${entries}")
- set("${resultVarPrefix}_${prefix}" "${entries}" PARENT_SCOPE)
- endif()
- endforeach()
- set(${resultVarPrefix}_public "${public_module_headers}" PARENT_SCOPE)
- set(${resultVarPrefix}_private "${private_module_headers}" PARENT_SCOPE)
- set(${resultVarPrefix}_injections "${injections}" PARENT_SCOPE)
-endfunction()
-
-
-# Add Qt::target and Qt6::target as aliases for the target
-function(qt_internal_add_target_aliases target)
- get_target_property(type "${target}" TYPE)
- if (type STREQUAL EXECUTABLE)
- add_executable("Qt::${target}" ALIAS "${target}")
- add_executable("Qt${PROJECT_VERSION_MAJOR}::${target}" ALIAS "${target}")
- else()
- add_library("Qt::${target}" ALIAS "${target}")
- add_library("Qt${PROJECT_VERSION_MAJOR}::${target}" ALIAS "${target}")
- endif()
-endfunction()
-
-# Sets the exceptions flags for the given target
-function(qt_internal_set_no_exceptions_flags target)
- target_compile_definitions("${target}" PRIVATE "QT_NO_EXCEPTIONS")
- if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
- target_compile_options("${target}" PRIVATE "/wd4530" "/wd4577")
- elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
- target_compile_options("${target}" PRIVATE "-fno-exceptions")
- elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "AppleClang")
- target_compile_options("${target}" PRIVATE "-fno-exceptions")
- elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
- target_compile_options("${target}" PRIVATE "-fno-exceptions")
- elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Intel")
- target_compile_options("${target}" PRIVATE "-fno-exceptions")
- endif()
-endfunction()
-
-function(qt_skip_warnings_are_errors target)
- get_target_property(target_type "${target}" TYPE)
- if(target_type STREQUAL "INTERFACE_LIBRARY")
- return()
- endif()
- set_target_properties("${target}" PROPERTIES QT_SKIP_WARNINGS_ARE_ERRORS ON)
-endfunction()
-
-function(qt_skip_warnings_are_errors_when_repo_unclean target)
- if(QT_REPO_NOT_WARNINGS_CLEAN)
- qt_skip_warnings_are_errors("${target}")
- endif()
-endfunction()
-
-function(qt_disable_warnings target)
- get_target_property(target_type "${target}" TYPE)
- if(target_type STREQUAL "INTERFACE_LIBRARY")
- return()
- endif()
- set_target_properties("${target}" PROPERTIES QT_COMPILE_OPTIONS_DISABLE_WARNINGS ON)
-endfunction()
-
-function(qt_set_symbol_visibility_preset target value)
- get_target_property(target_type "${target}" TYPE)
- if(target_type STREQUAL "INTERFACE_LIBRARY")
- return()
- endif()
-
- set_target_properties("${target}" PROPERTIES C_VISIBILITY_PRESET "${value}")
- set_target_properties("${target}" PROPERTIES CXX_VISIBILITY_PRESET "${value}")
- set_target_properties("${target}" PROPERTIES OBJC_VISIBILITY_PRESET "${value}")
- set_target_properties("${target}" PROPERTIES OBJCXX_VISIBILITY_PRESET "${value}")
-endfunction()
-
-function(qt_set_symbol_visibility_hidden target)
- qt_set_symbol_visibility_preset("${target}" "hidden")
-endfunction()
-
-function(qt_get_sanitized_plugin_type plugin_type out_var)
- # Used to handle some edge cases such as platforms/darwin
- string(REGEX REPLACE "[-/]" "_" plugin_type "${plugin_type}")
- set("${out_var}" "${plugin_type}" PARENT_SCOPE)
-endfunction()
-
-# Copy header files to QtXYZ.framework/Versions/6/Headers/
-# Use this function for header files that
-# - are not added as source files to the target
-# - are not marked as PUBLIC_HEADER
-# - or are private and supposed to end up in the 6.7.8/QtXYZ/private subdir.
-function(qt_copy_framework_headers target)
- get_target_property(is_fw ${target} FRAMEWORK)
- if(NOT "${is_fw}")
- return()
- endif()
-
- set(options PUBLIC PRIVATE QPA)
- set(oneValueArgs)
- set(multiValueArgs)
- cmake_parse_arguments(ARG "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
-
- get_target_property(fw_version ${target} FRAMEWORK_VERSION)
- get_target_property(fw_bundle_version ${target} MACOSX_FRAMEWORK_BUNDLE_VERSION)
- get_target_property(fw_dir ${target} LIBRARY_OUTPUT_DIRECTORY)
- get_target_property(fw_name ${target} OUTPUT_NAME)
- set(fw_headers_dir ${fw_dir}/${fw_name}.framework/Versions/${fw_version}/Headers/)
- if(ARG_PRIVATE)
- string(APPEND fw_headers_dir "${fw_bundle_version}/Qt${target}/private/")
- elseif(ARG_QPA)
- string(APPEND fw_headers_dir "${fw_bundle_version}/Qt${target}/qpa/")
- endif()
-
- set(out_files)
- foreach(hdr IN LISTS ARG_UNPARSED_ARGUMENTS)
- get_filename_component(in_file_path ${hdr} ABSOLUTE)
- get_filename_component(in_file_name ${hdr} NAME)
- set(out_file_path ${fw_headers_dir}${in_file_name})
- add_custom_command(
- OUTPUT ${out_file_path}
- DEPENDS ${in_file_path}
- COMMAND ${CMAKE_COMMAND} -E make_directory "${fw_headers_dir}"
- COMMAND ${CMAKE_COMMAND} -E copy "${in_file_path}" "${fw_headers_dir}")
- list(APPEND out_files ${out_file_path})
- endforeach()
-
- get_target_property(fw_copied_headers ${target} QT_COPIED_FRAMEWORK_HEADERS)
- if(NOT fw_copied_headers)
- set(fw_copied_headers "")
- endif()
- list(APPEND fw_copied_headers ${out_files})
- set_target_properties(${target} PROPERTIES QT_COPIED_FRAMEWORK_HEADERS "${fw_copied_headers}")
-endfunction()
-
-function(qt_finalize_framework_headers_copy target)
- get_target_property(target_type ${target} TYPE)
- if(${target_type} STREQUAL "INTERFACE_LIBRARY")
- return()
- endif()
- get_target_property(is_fw ${target} FRAMEWORK)
- if(NOT "${is_fw}")
- return()
- endif()
- get_target_property(headers ${target} QT_COPIED_FRAMEWORK_HEADERS)
- if(headers)
- # Hack to create the "Headers" symlink in the framework:
- # Create a fake header file and copy it into the framework by marking it as PUBLIC_HEADER.
- # CMake now takes care of creating the symlink.
- set(fake_header ${target}_fake_header.h)
- qt_get_main_cmake_configuration(main_config)
- file(GENERATE OUTPUT ${fake_header} CONTENT "// ignore this file\n"
- CONDITION "$<CONFIG:${main_config}>")
- string(PREPEND fake_header "${CMAKE_CURRENT_BINARY_DIR}/")
- target_sources(${target} PRIVATE ${fake_header})
- set_source_files_properties(${fake_header} PROPERTIES GENERATED ON)
- set_property(TARGET ${target} APPEND PROPERTY PUBLIC_HEADER ${fake_header})
-
- # Add a target, e.g. Core_framework_headers, that triggers the header copy.
- add_custom_target(${target}_framework_headers DEPENDS ${headers})
- add_dependencies(${target} ${target}_framework_headers)
- endif()
-endfunction()
-
-function(qt_get_cmake_configurations out_var)
- set(possible_configs "${CMAKE_BUILD_TYPE}")
- if(CMAKE_CONFIGURATION_TYPES)
- set(possible_configs "${CMAKE_CONFIGURATION_TYPES}")
- endif()
- set(${out_var} "${possible_configs}" PARENT_SCOPE)
-endfunction()
-
-function(qt_clone_property_for_configs target property configs)
- get_target_property(value "${target}" "${property}")
- foreach(config ${configs})
- string(TOUPPER "${config}" upper_config)
- set_property(TARGET "${target}" PROPERTY "${property}_${upper_config}" "${value}")
- endforeach()
-endfunction()
-
-function(qt_handle_multi_config_output_dirs target)
- qt_get_cmake_configurations(possible_configs)
- qt_clone_property_for_configs(${target} LIBRARY_OUTPUT_DIRECTORY "${possible_configs}")
- qt_clone_property_for_configs(${target} RUNTIME_OUTPUT_DIRECTORY "${possible_configs}")
- qt_clone_property_for_configs(${target} ARCHIVE_OUTPUT_DIRECTORY "${possible_configs}")
-endfunction()
-
-# Add a finalizer function for the current CMake list file.
-#
-# You may add up to nine arguments that are passed to the finalizer.
-# A finalizer that is registered with qt_add_list_file_finalizer(foo bar baz)
-# will be called with nine arguments: foo(bar baz IGNORE IGNORE IGNORE...),
-# because CMake's handling of empty list elements is a cruel joke.
-#
-# For CMake < 3.18 the function qt_watch_current_list_dir must know about the finalizer.
-function(qt_add_list_file_finalizer func)
- set_property(GLOBAL APPEND
- PROPERTY QT_LIST_FILE_FINALIZER_FILES "${CMAKE_CURRENT_LIST_FILE}")
- set_property(GLOBAL APPEND
- PROPERTY QT_LIST_FILE_FINALIZER_FUNCS ${func})
- foreach(i RANGE 1 9)
- set(arg "${ARGV${i}}")
- if(i GREATER_EQUAL ARGC OR "${arg}" STREQUAL "")
- set(arg "IGNORE")
- endif()
- set_property(GLOBAL APPEND
- PROPERTY QT_LIST_FILE_FINALIZER_ARGV${i} "${arg}")
- endforeach()
-endfunction()
-
-# Watcher function for the variable CMAKE_CURRENT_LIST_DIR.
-# This is the driver of the finalizer facility.
-function(qt_watch_current_list_dir variable access value current_list_file stack)
- if(NOT access STREQUAL "MODIFIED_ACCESS")
- # We are only interested in modifications of CMAKE_CURRENT_LIST_DIR.
- return()
- endif()
- list(GET stack -1 stack_top)
- if(stack_top STREQUAL current_list_file)
- # If the top of the stack equals the current list file then
- # we're entering a file. We're not interested in this case.
- return()
- endif()
- get_property(files GLOBAL PROPERTY QT_LIST_FILE_FINALIZER_FILES)
- if(NOT files)
- return()
- endif()
- get_property(funcs GLOBAL PROPERTY QT_LIST_FILE_FINALIZER_FUNCS)
- foreach(i RANGE 1 9)
- get_property(args${i} GLOBAL PROPERTY QT_LIST_FILE_FINALIZER_ARGV${i})
- endforeach()
- list(LENGTH files n)
- set(i 0)
- while(i LESS n)
- list(GET files ${i} file)
- if(file STREQUAL stack_top)
- list(GET funcs ${i} func)
- foreach(k RANGE 1 9)
- list(GET args${k} ${i} a${k})
- endforeach()
- # We've found a file we're looking for. Call the finalizer.
- if(${CMAKE_VERSION} VERSION_LESS "3.18.0")
- # Make finalizer known functions here:
- if(func STREQUAL "qt_finalize_module")
- qt_finalize_module(${a1} ${a2} ${a3} ${a4} ${a5} ${a6} ${a7} ${a8} ${a9})
- elseif(func STREQUAL "qt_finalize_plugin")
- qt_finalize_plugin(${a1} ${a2} ${a3} ${a4} ${a5} ${a6} ${a7} ${a8} ${a9})
- elseif(func STREQUAL "qt_internal_finalize_app")
- qt_internal_finalize_app(${a1} ${a2} ${a3} ${a4} ${a5} ${a6} ${a7} ${a8} ${a9})
- else()
- message(FATAL_ERROR "qt_watch_current_list_dir doesn't know about ${func}. Consider adding it.")
- endif()
- else()
- cmake_language(CALL ${func} ${a1} ${a2} ${a3} ${a4} ${a5} ${a6} ${a7} ${a8} ${a9})
- endif()
- list(REMOVE_AT files ${i})
- list(REMOVE_AT funcs ${i})
- foreach(k RANGE 1 9)
- list(REMOVE_AT args${k} ${i})
- endforeach()
- math(EXPR n "${n} - 1")
- else()
- math(EXPR i "${i} + 1")
- endif()
- endwhile()
- set_property(GLOBAL PROPERTY QT_LIST_FILE_FINALIZER_FILES ${files})
- set_property(GLOBAL PROPERTY QT_LIST_FILE_FINALIZER_FUNCS ${funcs})
- foreach(i RANGE 1 9)
- set_property(GLOBAL PROPERTY QT_LIST_FILE_FINALIZER_ARGV${i} "${args${i}}")
- endforeach()
-endfunction()
-
-variable_watch(CMAKE_CURRENT_LIST_DIR qt_watch_current_list_dir)
-
-# Set target properties that are the same for all modules, plugins, executables
-# and 3rdparty libraries.
-function(qt_set_common_target_properties target)
- if(FEATURE_static_runtime)
- if(MSVC)
- set_property(TARGET ${target} PROPERTY
- MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")
- elseif(MINGW)
- target_link_options(${target} INTERFACE "LINKER:-static")
- endif()
- endif()
-endfunction()
-
-# Set common, informational target properties.
-#
-# On Windows, these properties are used to generate the version information resource.
-function(qt_set_target_info_properties target)
- cmake_parse_arguments(arg "" "${__default_target_info_args}" "" ${ARGN})
- if("${arg_TARGET_VERSION}" STREQUAL "")
- set(arg_TARGET_VERSION "${PROJECT_VERSION}.0")
- endif()
- if("${arg_TARGET_PRODUCT}" STREQUAL "")
- set(arg_TARGET_PRODUCT "Qt6")
- endif()
- if("${arg_TARGET_DESCRIPTION}" STREQUAL "")
- set(arg_TARGET_DESCRIPTION "C++ Application Development Framework")
- endif()
- if("${arg_TARGET_COMPANY}" STREQUAL "")
- set(arg_TARGET_COMPANY "The Qt Company Ltd.")
- endif()
- if("${arg_TARGET_COPYRIGHT}" STREQUAL "")
- set(arg_TARGET_COPYRIGHT "Copyright (C) 2020 The Qt Company Ltd.")
- endif()
- set_target_properties(${target} PROPERTIES
- QT_TARGET_VERSION "${arg_TARGET_VERSION}"
- QT_TARGET_COMPANY_NAME "${arg_TARGET_COMPANY}"
- QT_TARGET_DESCRIPTION "${arg_TARGET_DESCRIPTION}"
- QT_TARGET_COPYRIGHT "${arg_TARGET_COPYRIGHT}"
- QT_TARGET_PRODUCT_NAME "${arg_TARGET_PRODUCT}")
-endfunction()
-
-# Uses the QT_DELAYED_TARGET_* property values to set the final QT_TARGET_* properties.
-# Needed when doing executable finalization at the end of a subdirectory scope
-# (aka scope finalization).
-function(qt_internal_set_target_info_properties_from_delayed_properties target)
- set(args "")
- foreach(prop ${__default_target_info_args})
- get_target_property(prop_value "${target}" "QT_DELAYED_${prop}")
- list(APPEND args "${prop}" "${prop_value}")
- endforeach()
- qt_set_target_info_properties(${target} ${args})
-endfunction()
-
-# Updates the QT_DELAYED_ properties with values from the QT_ variants, in case if they were
-# set in-between a qt_add_* call and before scope finalization.
-function(qt_internal_update_delayed_target_info_properties target)
- foreach(prop ${__default_target_info_args})
- get_target_property(prop_value "${target}" "QT_${prop}")
- get_target_property(delayed_prop_value ${target} "QT_DELAYED_${prop}")
- set(final_value "${delayed_prop_value}")
- if(prop_value)
- set(final_value "${prop_value}")
- endif()
- set_target_properties(${target} PROPERTIES "QT_DELAYED_${prop}" "${final_value}")
- endforeach()
-endfunction()
-
-# This is the main entry function for creating a Qt module, that typically
-# consists of a library, public header files, private header files and configurable
-# features.
-#
-# A CMake target with the specified target parameter is created. If the current source
-# directory has a configure.cmake file, then that is also processed for feature definition
-# and testing. Any features defined as well as any features coming from dependencies to
-# this module are imported into the scope of the calling feature.
-#
-# Target is without leading "Qt". So e.g. the "QtCore" module has the target "Core".
-function(qt_add_module target)
- qt_internal_module_info(module "${target}")
-
- # Process arguments:
- qt_parse_all_arguments(arg "qt_add_module"
- "NO_MODULE_HEADERS;STATIC;DISABLE_TOOLS_EXPORT;EXCEPTIONS;INTERNAL_MODULE;NO_SYNC_QT;NO_PRIVATE_MODULE;HEADER_MODULE;GENERATE_METATYPES;NO_CONFIG_HEADER_FILE;SKIP_DEPENDS_INCLUDE"
- "MODULE_INCLUDE_NAME;CONFIG_MODULE_NAME;PRECOMPILED_HEADER;CONFIGURE_FILE_PATH;${__default_target_info_args}"
- "${__default_private_args};${__default_public_args};${__default_private_module_args};QMAKE_MODULE_CONFIG;EXTRA_CMAKE_FILES;EXTRA_CMAKE_INCLUDES;NO_PCH_SOURCES" ${ARGN})
-
- qt_internal_add_qt_repo_known_module("${target}")
-
- if(NOT DEFINED arg_CONFIG_MODULE_NAME)
- set(arg_CONFIG_MODULE_NAME "${module_lower}")
- endif()
-
- ### Define Targets:
- set(is_interface_lib 0)
- set(is_shared_lib 0)
- if(${arg_HEADER_MODULE})
- add_library("${target}" INTERFACE)
- set(is_interface_lib 1)
- elseif(${arg_STATIC})
- add_library("${target}" STATIC)
- elseif(${QT_BUILD_SHARED_LIBS})
- add_library("${target}" SHARED)
- set(is_shared_lib 1)
- else()
- add_library("${target}" STATIC)
- endif()
-
- set(property_prefix "INTERFACE_")
- if(NOT arg_HEADER_MODULE)
- qt_set_common_target_properties(${target})
- set(property_prefix "")
- endif()
-
- set_target_properties(${target} PROPERTIES
- _qt_config_module_name "${arg_CONFIG_MODULE_NAME}"
- ${property_prefix}QT_QMAKE_MODULE_CONFIG "${arg_QMAKE_MODULE_CONFIG}")
- set_property(TARGET "${target}" APPEND PROPERTY EXPORT_PROPERTIES _qt_config_module_name)
-
- set(is_framework 0)
- if(QT_FEATURE_framework AND NOT ${arg_HEADER_MODULE} AND NOT ${arg_STATIC})
- set(is_framework 1)
- set_target_properties(${target} PROPERTIES
- FRAMEWORK TRUE
- FRAMEWORK_VERSION ${PROJECT_VERSION_MAJOR}
- MACOSX_FRAMEWORK_IDENTIFIER org.qt-project.Qt${target}
- MACOSX_FRAMEWORK_BUNDLE_VERSION ${PROJECT_VERSION}
- MACOSX_FRAMEWORK_SHORT_VERSION_STRING ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}
- )
- endif()
-
- if(QT_FEATURE_reduce_relocations AND UNIX AND NOT is_interface_lib)
- # On x86 and x86-64 systems with ELF binaries (especially Linux), due to
- # a new optimization in GCC 5.x in combination with a recent version of
- # GNU binutils, compiling Qt applications with -fPIE is no longer
- # enough.
- # Applications now need to be compiled with the -fPIC option if the Qt option
- # \"reduce relocations\" is active.
- target_compile_options(${target} INTERFACE -fPIC)
- if(GCC AND is_shared_lib)
- target_link_options(${target} PRIVATE LINKER:-Bsymbolic-functions)
- endif()
- endif()
-
- if(QT_FEATURE_separate_debug_info AND is_shared_lib AND (UNIX OR MINGW))
- qt_enable_separate_debug_info(${target} ${INSTALL_LIBDIR})
- endif()
-
- if (ANDROID)
- qt_android_apply_arch_suffix("${target}")
- endif()
- qt_internal_add_target_aliases("${target}")
- qt_skip_warnings_are_errors_when_repo_unclean("${target}")
-
- # Add _private target to link against the private headers:
- if(NOT ${arg_NO_PRIVATE_MODULE})
- set(target_private "${target}Private")
- add_library("${target_private}" INTERFACE)
- qt_internal_add_target_aliases("${target_private}")
- set_target_properties(${target_private} PROPERTIES
- _qt_config_module_name ${arg_CONFIG_MODULE_NAME}_private)
- set_property(TARGET "${target_private}" APPEND PROPERTY
- EXPORT_PROPERTIES _qt_config_module_name)
- endif()
-
- if(NOT arg_HEADER_MODULE)
- set_target_properties(${target} PROPERTIES
- LIBRARY_OUTPUT_DIRECTORY "${QT_BUILD_DIR}/${INSTALL_LIBDIR}"
- RUNTIME_OUTPUT_DIRECTORY "${QT_BUILD_DIR}/${INSTALL_BINDIR}"
- ARCHIVE_OUTPUT_DIRECTORY "${QT_BUILD_DIR}/${INSTALL_LIBDIR}"
- VERSION ${PROJECT_VERSION}
- SOVERSION ${PROJECT_VERSION_MAJOR}
- )
- qt_set_target_info_properties(${target} ${ARGN})
- qt_handle_multi_config_output_dirs("${target}")
-
- if(NOT BUILD_SHARED_LIBS AND LINUX)
- # Horrible workaround for static build failures due to incorrect static library link
- # order. By increasing the multiplicity to 3, each library cycle will be repeated
- # 3 times on the link line, reducing the probability of undefined symbols at
- # link time.
- # These failures are only observed on Linux with the ld linker (not sure about
- # ld.gold).
- # Allow opting out and modifying the value via cache value, in case if we urgently
- # need to increase it without waiting for the qtbase change to propagate to
- # other dependent repos.
- # The proper fix will be to get rid of the cycles in the future.
- # See QTBUG-83498 for details.
- set(default_link_cycle_multiplicity "3")
- if(DEFINED QT_LINK_CYCLE_MULTIPLICITY)
- set(default_link_cycle_multiplicity "${QT_LINK_CYCLE_MULTIPLICITY}")
- endif()
- if(default_link_cycle_multiplicity)
- set_property(TARGET "${target}"
- PROPERTY
- LINK_INTERFACE_MULTIPLICITY "${default_link_cycle_multiplicity}")
- endif()
- endif()
-
- if (arg_SKIP_DEPENDS_INCLUDE)
- set_target_properties(${target} PROPERTIES QT_MODULE_SKIP_DEPENDS_INCLUDE TRUE)
- endif()
- if(is_framework)
- set_target_properties(${target} PROPERTIES
- OUTPUT_NAME Qt${target}
- )
- else()
- set_target_properties(${target} PROPERTIES
- OUTPUT_NAME "${INSTALL_CMAKE_NAMESPACE}${target}"
- )
- endif()
-
- qt_internal_apply_win_prefix_and_suffix("${target}")
-
- if (WIN32 AND BUILD_SHARED_LIBS)
- qt6_generate_win32_rc_file(${target})
- endif()
- endif()
-
- # Module headers:
- if(${arg_NO_MODULE_HEADERS} OR ${arg_NO_SYNC_QT})
- set_target_properties("${target}" PROPERTIES INTERFACE_MODULE_HAS_HEADERS OFF)
- else()
- if(arg_MODULE_INCLUDE_NAME)
- set(module_include_name ${arg_MODULE_INCLUDE_NAME})
- else()
- set(module_include_name ${module})
- endif()
- set_target_properties("${target}" PROPERTIES INTERFACE_MODULE_INCLUDE_NAME "${module_include_name}")
-
- # Use QT_BUILD_DIR for the syncqt call.
- # So we either write the generated files into the qtbase non-prefix build root, or the
- # module specific build root.
- qt_ensure_sync_qt()
- set(syncqt_full_command "${HOST_PERL}" -w "${QT_SYNCQT}"
- -quiet
- -check-includes
- -module "${module_include_name}"
- -version "${PROJECT_VERSION}"
- -outdir "${QT_BUILD_DIR}"
- -builddir "${PROJECT_BINARY_DIR}"
- "${PROJECT_SOURCE_DIR}")
- message(STATUS "Running syncqt for module: '${module_include_name}' ")
- execute_process(COMMAND ${syncqt_full_command})
-
- set_target_properties("${target}" PROPERTIES INTERFACE_MODULE_HAS_HEADERS ON)
-
- ### FIXME: Can we replace headers.pri?
- set(module_include_dir "${QT_BUILD_DIR}/${INSTALL_INCLUDEDIR}/${module_include_name}")
- qt_read_headers_pri("${module_include_dir}" "module_headers")
- set(module_depends_header "${module_include_dir}/${module}Depends")
- if(is_framework)
- if(NOT is_interface_lib)
- set(public_headers_to_copy "${module_headers_public}" "${module_depends_header}")
- qt_copy_framework_headers(${target} PUBLIC "${public_headers_to_copy}")
- qt_copy_framework_headers(${target} PRIVATE "${module_headers_private}")
- endif()
- else()
- set_property(TARGET ${target} APPEND PROPERTY PUBLIC_HEADER "${module_headers_public}")
- set_property(TARGET ${target} APPEND PROPERTY PUBLIC_HEADER ${module_depends_header})
- set_property(TARGET ${target} APPEND PROPERTY PRIVATE_HEADER "${module_headers_private}")
- endif()
- if (NOT ${arg_HEADER_MODULE})
- set_property(TARGET "${target}" PROPERTY MODULE_HEADER "${module_include_dir}/${module_include_name}")
- endif()
-
- if(module_headers_qpa)
- if(is_framework)
- qt_copy_framework_headers(${target} QPA "${module_headers_qpa}")
- else()
- qt_install(
- FILES ${module_headers_qpa}
- DESTINATION ${INSTALL_INCLUDEDIR}/${module}/${PROJECT_VERSION}/${module_include_name}/qpa)
- endif()
- endif()
- endif()
-
- if(NOT arg_HEADER_MODULE)
- # This property is used for super builds with static libraries. We use
- # it in QtPlugins.cmake.in to avoid "polluting" the dependency chain
- # for the target in it's project directory.
- # E.g: When we process find_package(Qt6 ... Gui) in QtDeclarative, the
- # rules in QtPugins.cmake add all the known Gui plugins as interface
- # dependencies. This in turn causes circular dependencies on every
- # plugin which links against Gui. Plugin A -> GUI -> Plugin A ....
-
- set_target_properties(${target} PROPERTIES QT_BUILD_PROJECT_NAME ${PROJECT_NAME})
- # Plugin types associated to a module
- if(NOT "x${arg_PLUGIN_TYPES}" STREQUAL "x")
- # Reset the variable containing the list of plugins for the given plugin type
- foreach(plugin_type ${arg_PLUGIN_TYPES})
- qt_get_sanitized_plugin_type("${plugin_type}" plugin_type)
- set_property(TARGET "${target}" APPEND PROPERTY MODULE_PLUGIN_TYPES "${plugin_type}")
- qt_internal_add_qt_repo_known_plugin_types("${plugin_type}")
- endforeach()
-
- # Save the non-sanitized plugin type values for qmake consumption via .pri files.
- set_property(TARGET "${target}"
- PROPERTY QMAKE_MODULE_PLUGIN_TYPES "${arg_PLUGIN_TYPES}")
- endif()
- endif()
-
- qt_internal_library_deprecation_level(deprecation_define)
-
- if(NOT arg_HEADER_MODULE)
- qt_autogen_tools_initial_setup(${target})
- endif()
-
- set(private_includes
- "$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>"
- "$<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}>"
- ${arg_INCLUDE_DIRECTORIES}
- )
-
- set(public_includes "")
- set(public_headers_list "public_includes")
- if(is_framework)
- set(public_headers_list "private_includes")
- endif()
-
- # Make sure the BUILD_INTERFACE include paths come before the framework headers, so that the
- # the compiler prefers the build dir includes.
- #
- # Make sure to add non-framework "build_dir/include" as an include path for moc to find the
- # currently built module headers. qmake does this too.
- # Framework-style include paths are found by moc when cmQtAutoMocUic.cxx detects frameworks by
- # looking at an include path and detecting a "QtFoo.framework/Headers" path.
- # Make sure to create such paths for both the the BUILD_INTERFACE and the INSTALL_INTERFACE.
- #
- # Only add syncqt headers if they exist.
- # This handles cases like QmlDevTools which do not have their own headers, but borrow them
- # from another module.
- if(NOT arg_NO_SYNC_QT AND NOT arg_NO_MODULE_HEADERS)
- # Don't include private headers unless they exist, aka syncqt created them.
- if(module_headers_private)
- list(APPEND private_includes
- "$<BUILD_INTERFACE:${module_include_dir}/${PROJECT_VERSION}>"
- "$<BUILD_INTERFACE:${module_include_dir}/${PROJECT_VERSION}/${module}>")
- endif()
-
- list(APPEND public_includes
- # For the syncqt headers
- "$<BUILD_INTERFACE:${module_repo_include_dir}>"
- "$<BUILD_INTERFACE:${module_include_dir}>")
- endif()
-
- if(is_framework)
- set(fw_bundle_subdir "${INSTALL_LIBDIR}/Qt${target}.framework")
- list(APPEND public_includes
- # Add the lib/Foo.framework dir as include path to let CMake generate
- # the -F compiler flag for framework-style includes to work.
- "$<INSTALL_INTERFACE:${fw_bundle_subdir}>"
-
- # Add the framework Headers subdir, so that non-framework-style includes work. The
- # BUILD_INTERFACE Headers symlink was previously claimed not to exist at the relevant
- # time, and a fully specified Header path was used instead. This doesn't seem to be a
- # problem anymore.
- "$<BUILD_INTERFACE:${QT_BUILD_DIR}/${fw_bundle_subdir}/Headers>"
- "$<INSTALL_INTERFACE:${fw_bundle_subdir}/Headers>"
- )
- endif()
-
- if(NOT arg_NO_MODULE_HEADERS AND NOT arg_NO_SYNC_QT)
- # For the syncqt headers
- list(APPEND ${public_headers_list} "$<INSTALL_INTERFACE:${INSTALL_INCLUDEDIR}/${module}>")
- endif()
- list(APPEND ${public_headers_list} ${arg_PUBLIC_INCLUDE_DIRECTORIES})
-
- set(header_module)
- if(arg_HEADER_MODULE)
- set(header_module "HEADER_MODULE")
-
- # Provide a *_timestamp target that can be used to trigger the build of custom_commands.
- set(timestamp_file "${CMAKE_CURRENT_BINARY_DIR}/timestamp")
- add_custom_command(OUTPUT "${timestamp_file}"
- COMMAND ${CMAKE_COMMAND} -E touch "${timestamp_file}"
- DEPENDS ${module_headers_public}
- VERBATIM)
- add_custom_target(${target}_timestamp ALL DEPENDS "${timestamp_file}")
- endif()
-
- set(defines_for_extend_target "")
-
- if(NOT arg_HEADER_MODULE)
- list(APPEND defines_for_extend_target
- QT_NO_CAST_TO_ASCII QT_ASCII_CAST_WARNINGS
- QT_MOC_COMPAT #we don't need warnings from calling moc code in our generated code
- QT_USE_QSTRINGBUILDER
- QT_DEPRECATED_WARNINGS
- QT_BUILDING_QT
- QT_BUILD_${module_define}_LIB ### FIXME: use QT_BUILD_ADDON for Add-ons or remove if we don't have add-ons anymore
- "${deprecation_define}"
- )
- endif()
-
- qt_extend_target("${target}"
- ${header_module}
- SOURCES ${arg_SOURCES}
- INCLUDE_DIRECTORIES
- ${private_includes}
- PUBLIC_INCLUDE_DIRECTORIES
- ${public_includes}
- PUBLIC_DEFINES
- ${arg_PUBLIC_DEFINES}
- QT_${module_define}_LIB
- DEFINES
- ${arg_DEFINES}
- ${defines_for_extend_target}
- PUBLIC_LIBRARIES ${arg_PUBLIC_LIBRARIES}
- LIBRARIES ${arg_LIBRARIES} Qt::PlatformModuleInternal
- PRIVATE_MODULE_INTERFACE ${arg_PRIVATE_MODULE_INTERFACE}
- FEATURE_DEPENDENCIES ${arg_FEATURE_DEPENDENCIES}
- DBUS_ADAPTOR_SOURCES ${arg_DBUS_ADAPTOR_SOURCES}
- DBUS_ADAPTOR_FLAGS ${arg_DBUS_ADAPTOR_FLAGS}
- DBUS_INTERFACE_SOURCES ${arg_DBUS_INTERFACE_SOURCES}
- DBUS_INTERFACE_FLAGS ${arg_DBUS_INTERFACE_FLAGS}
- COMPILE_OPTIONS ${arg_COMPILE_OPTIONS}
- PUBLIC_COMPILE_OPTIONS ${arg_PUBLIC_COMPILE_OPTIONS}
- LINK_OPTIONS ${arg_LINK_OPTIONS}
- PUBLIC_LINK_OPTIONS ${arg_PUBLIC_LINK_OPTIONS}
- MOC_OPTIONS ${arg_MOC_OPTIONS}
- ENABLE_AUTOGEN_TOOLS ${arg_ENABLE_AUTOGEN_TOOLS}
- DISABLE_AUTOGEN_TOOLS ${arg_DISABLE_AUTOGEN_TOOLS}
- PRECOMPILED_HEADER ${arg_PRECOMPILED_HEADER}
- NO_PCH_SOURCES ${arg_NO_PCH_SOURCES}
- )
-
- if(NOT ${arg_EXCEPTIONS} AND NOT ${arg_HEADER_MODULE})
- qt_internal_set_no_exceptions_flags("${target}")
- endif()
-
- set(configureFile "${CMAKE_CURRENT_SOURCE_DIR}/configure.cmake")
- if(arg_CONFIGURE_FILE_PATH)
- set(configureFile "${arg_CONFIGURE_FILE_PATH}")
- endif()
- if(EXISTS "${configureFile}" AND NOT arg_NO_CONFIG_HEADER_FILE)
- qt_feature_module_begin(
- LIBRARY "${target}"
- PUBLIC_FILE "qt${arg_CONFIG_MODULE_NAME}-config.h"
- PRIVATE_FILE "qt${arg_CONFIG_MODULE_NAME}-config_p.h"
- PUBLIC_DEPENDENCIES ${arg_FEATURE_DEPENDENCIES}
- PRIVATE_DEPENDENCIES ${arg_FEATURE_DEPENDENCIES}
- )
- include(${configureFile})
- qt_feature_module_end("${target}")
-
- set_property(TARGET "${target}" APPEND PROPERTY PUBLIC_HEADER "${CMAKE_CURRENT_BINARY_DIR}/qt${arg_CONFIG_MODULE_NAME}-config.h")
- set_property(TARGET "${target}" APPEND PROPERTY PRIVATE_HEADER "${CMAKE_CURRENT_BINARY_DIR}/qt${arg_CONFIG_MODULE_NAME}-config_p.h")
- endif()
-
- if(NOT arg_HEADER_MODULE)
- if(DEFINED module_headers_private)
- qt_internal_add_linker_version_script("${target}" PRIVATE_HEADERS ${module_headers_private} ${module_headers_qpa})
- else()
- qt_internal_add_linker_version_script("${target}")
- endif()
- endif()
-
- # Handle injections. Aka create forwarding headers for certain headers that have been
- # automatically generated in the build dir (for example qconfig.h, qtcore-config.h,
- # qvulkanfunctions.h, etc)
- # module_headers_injections come from the qt_read_headers_pri() call.
- # extra_library_injections come from the qt_feature_module_end() call.
- set(final_injections "")
- if(module_headers_injections)
- string(APPEND final_injections "${module_headers_injections} ")
- endif()
- if(extra_library_injections)
- string(APPEND final_injections "${extra_library_injections} ")
- endif()
-
- if(final_injections)
- qt_install_injections(${target} "${QT_BUILD_DIR}" "${QT_INSTALL_DIR}" ${final_injections})
- endif()
-
- # Handle creation of cmake files for consumers of find_package().
- set(path_suffix "${INSTALL_CMAKE_NAMESPACE}${target}")
- qt_path_join(config_build_dir ${QT_CONFIG_BUILD_DIR} ${path_suffix})
- qt_path_join(config_install_dir ${QT_CONFIG_INSTALL_DIR} ${path_suffix})
-
- set(extra_cmake_files)
- set(extra_cmake_includes)
- if (EXISTS "${CMAKE_CURRENT_LIST_DIR}/${INSTALL_CMAKE_NAMESPACE}${target}Macros.cmake")
- list(APPEND extra_cmake_files "${CMAKE_CURRENT_LIST_DIR}/${INSTALL_CMAKE_NAMESPACE}${target}Macros.cmake")
- list(APPEND extra_cmake_includes "${INSTALL_CMAKE_NAMESPACE}${target}Macros.cmake")
- endif()
- if (EXISTS "${CMAKE_CURRENT_LIST_DIR}/${INSTALL_CMAKE_NAMESPACE}${target}ConfigExtras.cmake.in")
- configure_file("${CMAKE_CURRENT_LIST_DIR}/${INSTALL_CMAKE_NAMESPACE}${target}ConfigExtras.cmake.in"
- "${config_build_dir}/${INSTALL_CMAKE_NAMESPACE}${target}ConfigExtras.cmake"
- @ONLY)
- list(APPEND extra_cmake_files "${config_build_dir}/${INSTALL_CMAKE_NAMESPACE}${target}ConfigExtras.cmake")
- list(APPEND extra_cmake_includes "${INSTALL_CMAKE_NAMESPACE}${target}ConfigExtras.cmake")
- endif()
-
- foreach(cmake_file IN LISTS arg_EXTRA_CMAKE_FILES)
- get_filename_component(basename ${cmake_file} NAME)
- file(COPY ${cmake_file} DESTINATION ${config_build_dir})
- list(APPEND extra_cmake_files "${config_build_dir}/${basename}")
- endforeach()
- list(APPEND extra_cmake_includes ${arg_EXTRA_CMAKE_INCLUDES})
-
- set(extra_cmake_code "")
-
- if(target STREQUAL Core)
- # Propagate non-build related variables that are needed for consuming Qt packages.
- # Do this in CoreConfig instead of Qt6Config, so that consumers can also use
- # find_package(Qt6Core) instead of find_package(Qt6 COMPONENTS Core)
- string(APPEND extra_cmake_code "
-set(QT_CMAKE_EXPORT_NAMESPACE ${QT_CMAKE_EXPORT_NAMESPACE})")
- endif()
-
- # Generate metatypes
- set(QT_MODULE_HAS_META_TYPES_FILE FALSE)
- if (${arg_GENERATE_METATYPES})
- set(QT_MODULE_HAS_META_TYPES_FILE TRUE)
- set(metatypes_install_dir ${INSTALL_LIBDIR}/metatypes)
- set(args)
- if (NOT QT_WILL_INSTALL)
- set(args COPY_OVER_INSTALL INSTALL_DIR "${QT_BUILD_DIR}/${metatypes_install_dir}")
- else()
- set(args INSTALL_DIR "${metatypes_install_dir}")
- endif()
- qt6_generate_meta_types_json_file(${target} ${args})
- endif()
- configure_package_config_file(
- "${QT_CMAKE_DIR}/QtModuleConfig.cmake.in"
- "${config_build_dir}/${INSTALL_CMAKE_NAMESPACE}${target}Config.cmake"
- INSTALL_DESTINATION "${config_install_dir}"
- )
-
- if (EXISTS "${CMAKE_CURRENT_LIST_DIR}/${INSTALL_CMAKE_NAMESPACE}${target}BuildInternals.cmake")
- configure_file("${CMAKE_CURRENT_LIST_DIR}/${INSTALL_CMAKE_NAMESPACE}${target}BuildInternals.cmake"
- "${config_build_dir}/${INSTALL_CMAKE_NAMESPACE}${target}BuildInternals.cmake"
- @ONLY)
- list(APPEND extra_cmake_files "${config_build_dir}/${INSTALL_CMAKE_NAMESPACE}${target}BuildInternals.cmake")
- endif()
-
- write_basic_package_version_file(
- "${config_build_dir}/${INSTALL_CMAKE_NAMESPACE}${target}ConfigVersion.cmake"
- VERSION ${PROJECT_VERSION}
- COMPATIBILITY AnyNewerVersion
- )
- qt_install(FILES
- "${config_build_dir}/${INSTALL_CMAKE_NAMESPACE}${target}Config.cmake"
- "${config_build_dir}/${INSTALL_CMAKE_NAMESPACE}${target}ConfigVersion.cmake"
- ${extra_cmake_files}
- DESTINATION "${config_install_dir}"
- COMPONENT Devel
- )
-
- file(COPY ${extra_cmake_files} DESTINATION "${config_build_dir}")
- set(exported_targets ${target})
- if(NOT ${arg_NO_PRIVATE_MODULE})
- list(APPEND exported_targets ${target_private})
- endif()
- set(export_name "${INSTALL_CMAKE_NAMESPACE}${target}Targets")
- qt_install(TARGETS ${exported_targets}
- EXPORT ${export_name}
- RUNTIME DESTINATION ${INSTALL_BINDIR}
- LIBRARY DESTINATION ${INSTALL_LIBDIR}
- ARCHIVE DESTINATION ${INSTALL_LIBDIR}
- FRAMEWORK DESTINATION ${INSTALL_LIBDIR}
- PUBLIC_HEADER DESTINATION ${INSTALL_INCLUDEDIR}/${module}
- PRIVATE_HEADER DESTINATION ${INSTALL_INCLUDEDIR}/${module}/${PROJECT_VERSION}/${module}/private
- )
-
- qt_apply_rpaths(TARGET "${target}" INSTALL_PATH "${INSTALL_LIBDIR}" RELATIVE_RPATH)
-
- if (ANDROID AND NOT arg_HEADER_MODULE)
- # Record install library location so it can be accessed by
- # qt_android_dependencies without having to specify it again.
- set_target_properties(${target} PROPERTIES
- QT_ANDROID_MODULE_INSTALL_DIR ${INSTALL_LIBDIR})
- endif()
-
- qt_install(EXPORT ${export_name}
- NAMESPACE ${QT_CMAKE_EXPORT_NAMESPACE}::
- DESTINATION ${config_install_dir})
-
- qt_internal_export_modern_cmake_config_targets_file(
- TARGETS ${exported_targets}
- EXPORT_NAME_PREFIX ${INSTALL_CMAKE_NAMESPACE}${target}
- CONFIG_INSTALL_DIR "${config_install_dir}")
-
- if (${arg_INTERNAL_MODULE})
- set(arg_INTERNAL_MODULE "INTERNAL_MODULE")
- else()
- unset(arg_INTERNAL_MODULE)
- endif()
-
- ### fixme: cmake is missing a built-in variable for this. We want to apply it only to modules and plugins
- # that belong to Qt.
- if(NOT arg_HEADER_MODULE)
- qt_internal_add_link_flags_no_undefined("${target}")
- endif()
-
- set(interface_includes "")
-
- # Handle cases like QmlDevTools which do not have their own headers, but rather borrow them
- # from another module.
- if(NOT arg_NO_SYNC_QT)
- list(APPEND interface_includes "$<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}>")
-
- # syncqt.pl does not create a private header directory like 'include/6.0/QtFoo' unless
- # the module has foo_p.h header files. For QtZlib, there are no such private headers, so we
- # need to make sure not to add such include paths unless the directory exists, otherwise
- # consumers of the module will fail at CMake generation time stating that
- # INTERFACE_INCLUDE_DIRECTORIES contains a non-existent path.
- if(NOT arg_NO_MODULE_HEADERS
- AND EXISTS "${module_include_dir}/${PROJECT_VERSION}/${module}")
- list(APPEND interface_includes
- "$<BUILD_INTERFACE:${module_include_dir}/${PROJECT_VERSION}>"
- "$<BUILD_INTERFACE:${module_include_dir}/${PROJECT_VERSION}/${module}>")
-
- if(is_framework)
- set(fw_headers_dir
- "${INSTALL_LIBDIR}/${module}.framework/Headers/")
- list(APPEND interface_includes
- "$<INSTALL_INTERFACE:${fw_headers_dir}${PROJECT_VERSION}>"
- "$<INSTALL_INTERFACE:${fw_headers_dir}${PROJECT_VERSION}/${module}>")
- else()
- list(APPEND interface_includes
- "$<INSTALL_INTERFACE:${INSTALL_INCLUDEDIR}/${module}/${PROJECT_VERSION}>"
- "$<INSTALL_INTERFACE:${INSTALL_INCLUDEDIR}/${module}/${PROJECT_VERSION}/${module}>")
- endif()
- endif()
- endif()
-
- if(NOT ${arg_NO_PRIVATE_MODULE})
- target_include_directories("${target_private}" INTERFACE ${interface_includes})
- target_link_libraries("${target_private}" INTERFACE "${target}")
- endif()
-
- if(is_framework AND NOT is_interface_lib)
- qt_finalize_framework_headers_copy(${target})
- endif()
-
- qt_describe_module(${target})
- qt_add_list_file_finalizer(qt_finalize_module ${target} ${arg_INTERNAL_MODULE} ${header_module})
-endfunction()
-
-function(qt_finalize_module target)
- qt_generate_prl_file(${target} "${INSTALL_LIBDIR}")
- qt_generate_module_pri_file("${target}" ${ARGN})
-endfunction()
-
-# Add libraries to variable ${out_libs_var} in a way that duplicates
-# are added at the end. This ensures the library order needed for the
-# linker.
-function(qt_merge_libs out_libs_var)
- foreach(dep ${ARGN})
- list(REMOVE_ITEM ${out_libs_var} ${dep})
- list(APPEND ${out_libs_var} ${dep})
- endforeach()
- set(${out_libs_var} ${${out_libs_var}} PARENT_SCOPE)
-endfunction()
-
-# Collects the library dependencies of a target.
-# This takes into account transitive usage requirements.
-function(qt_collect_libs target out_var)
- qt_internal_walk_libs("${target}" "${out_var}" "qt_collect_libs_dict" "collect_libs")
- set("${out_var}" "${${out_var}}" PARENT_SCOPE)
-endfunction()
-
-# Walks a target's link libraries recursively, and performs some actions (poor man's polypmorphism)
-#
-# out_var is the name of the variable where the result will be assigned. The result is a list of
-# libraries, mostly in generator expression form.
-# dict_name is used for caching the result, and preventing the same target from being processed
-# twice
-# operation is a string to tell the function what to do
-function(qt_internal_walk_libs target out_var dict_name operation)
- set(collected ${ARGN})
- if(target IN_LIST collected)
- return()
- endif()
- list(APPEND collected ${target})
- if(NOT TARGET ${dict_name})
- add_library(${dict_name} INTERFACE IMPORTED GLOBAL)
- endif()
- get_target_property(libs ${dict_name} INTERFACE_${target})
- if(NOT libs)
- unset(libs)
- get_target_property(target_libs ${target} INTERFACE_LINK_LIBRARIES)
- if(NOT target_libs)
- unset(target_libs)
- endif()
- get_target_property(target_type ${target} TYPE)
- if(target_type STREQUAL "STATIC_LIBRARY")
- get_target_property(link_libs ${target} LINK_LIBRARIES)
- if(link_libs)
- list(APPEND target_libs ${link_libs})
- endif()
- endif()
- foreach(lib ${target_libs})
- # Cannot use $<TARGET_POLICY:...> in add_custom_command.
- # Check the policy now, and replace the generator expression with the value.
- while(lib MATCHES "\\$<TARGET_POLICY:([^>]+)>")
- cmake_policy(GET ${CMAKE_MATCH_1} value)
- if(value STREQUAL "NEW")
- set(value "TRUE")
- else()
- set(value "FALSE")
- endif()
- string(REPLACE "${CMAKE_MATCH_0}" "${value}" lib "${lib}")
- endwhile()
-
- # Fix up $<TARGET_PROPERTY:FOO> expressions that refer to the "current" target.
- # Those cannot be used with add_custom_command.
- while(lib MATCHES "\\$<TARGET_PROPERTY:([^,>]+)>")
- string(REPLACE "${CMAKE_MATCH_0}" "$<TARGET_PROPERTY:${target},${CMAKE_MATCH_1}>"
- lib "${lib}")
- endwhile()
-
- if(lib MATCHES "^\\$<TARGET_OBJECTS:")
- # Skip object files.
- continue()
- elseif(lib MATCHES "^\\$<LINK_ONLY:(.*)>$")
- set(lib_target ${CMAKE_MATCH_1})
- else()
- set(lib_target ${lib})
- endif()
-
- if(TARGET ${lib_target})
- if ("${lib_target}" MATCHES "^Qt::(.*)")
- # If both, Qt::Foo and Foo targets exist, prefer the target name without
- # namespace. Which one is preferred doesn't really matter. This code exists to
- # avoid ending up with both, Qt::Foo and Foo in our dependencies.
- set(namespaceless_lib_target "${CMAKE_MATCH_1}")
- if(TARGET namespaceless_lib_target)
- set(lib_target ${namespaceless_lib_target})
- endif()
- endif()
- get_target_property(lib_target_type ${lib_target} TYPE)
- if(lib_target_type STREQUAL "INTERFACE_LIBRARY")
- qt_internal_walk_libs(
- ${lib_target} lib_libs "${dict_name}" "${operation}" ${collected})
- if(lib_libs)
- qt_merge_libs(libs ${lib_libs})
- set(is_module 0)
- endif()
- else()
- qt_merge_libs(libs "$<TARGET_FILE:${lib_target}>")
- qt_internal_walk_libs(
- ${lib_target} lib_libs "${dict_name}" "${operation}" ${collected})
- if(lib_libs)
- qt_merge_libs(libs ${lib_libs})
- endif()
- endif()
- if(operation STREQUAL "promote_global")
- set(lib_target_unaliased "${lib_target}")
- get_target_property(aliased_target ${lib_target} ALIASED_TARGET)
- if(aliased_target)
- set(lib_target_unaliased ${aliased_target})
- endif()
-
- get_property(is_imported TARGET ${lib_target_unaliased} PROPERTY IMPORTED)
- get_property(is_global TARGET ${lib_target_unaliased} PROPERTY IMPORTED_GLOBAL)
- if(NOT is_global AND is_imported)
- set_property(TARGET ${lib_target_unaliased} PROPERTY IMPORTED_GLOBAL TRUE)
- endif()
- endif()
- else()
- set(final_lib_name_to_merge "${lib_target}")
- if(lib_target MATCHES "/([^/]+).framework$")
- set(final_lib_name_to_merge "-framework ${CMAKE_MATCH_1}")
- endif()
- qt_merge_libs(libs "${final_lib_name_to_merge}")
- endif()
- endforeach()
- set_target_properties(${dict_name} PROPERTIES INTERFACE_${target} "${libs}")
- endif()
- set(${out_var} ${libs} PARENT_SCOPE)
-endfunction()
-
-# Generate a qmake .prl file for the given target.
-# The install_dir argument is a relative path, for example "lib".
-function(qt_generate_prl_file target install_dir)
- get_target_property(target_type ${target} TYPE)
- if(target_type STREQUAL "INTERFACE_LIBRARY")
- return()
- endif()
-
- get_target_property(rcc_objects ${target} QT_RCC_OBJECTS)
- if(rcc_objects)
- if(QT_WILL_INSTALL)
- list(TRANSFORM rcc_objects PREPEND "$$[QT_INSTALL_LIBS]/")
- endif()
- else()
- unset(rcc_objects)
- endif()
-
- unset(prl_config)
- set(is_static FALSE)
- if(target_type STREQUAL "STATIC_LIBRARY")
- list(APPEND prl_config static)
- set(is_static TRUE)
- elseif(target_type STREQUAL "SHARED_LIBRARY")
- list(APPEND prl_config shared)
- endif()
- if (NOT target_type STREQUAL "INTERFACE_LIBRARY")
- get_target_property(is_fw ${target} FRAMEWORK)
- if(is_fw)
- list(APPEND prl_config lib_bundle)
- endif()
- endif()
- list(JOIN prl_config " " prl_config)
-
- # Generate a preliminary .prl file that contains absolute paths to all libraries
- if(MINGW)
- # For MinGW, qmake doesn't have a lib prefix in prl files.
- set(prefix_for_final_prl_name "")
- else()
- set(prefix_for_final_prl_name "$<TARGET_FILE_PREFIX:${target}>")
- endif()
-
- # For frameworks, the prl file should be placed under the Resources subdir.
- get_target_property(is_framework ${target} FRAMEWORK)
- if(is_framework)
- get_target_property(fw_version ${target} FRAMEWORK_VERSION)
- string(APPEND prefix_for_final_prl_name "Versions/${fw_version}/Resources/")
- endif()
-
- # What follows is a complicated setup for generating configuration-specific
- # prl files. It has to be this way, because add_custom_command doesn't support
- # generator expressions in OUTPUT or DEPENDS.
- # To circumvent that, we create well known file names with file(GENERATE)
- # with configuration specific content, which are then fed to add_custom_command
- # that uses these genex-less file names. The actual command will extract the info
- # from the configuration-specific files, and create a properly named final prl file.
-
- # The file is named according to a pattern, that is then used in the
- # add_custom_command.
- set(prl_step1_name_prefix "preliminary_prl_for_${target}_step1_")
- set(prl_step1_name_suffix ".prl" )
- qt_path_join(prl_step1_path
- "${CMAKE_CURRENT_BINARY_DIR}"
- "${prl_step1_name_prefix}$<CONFIG>${prl_step1_name_suffix}")
-
- # Same, except instead of containing the prl contents, it will contain the final prl file
- # name computed via a generator expression.
- set(prl_meta_info_name_prefix "preliminary_prl_meta_info_for_${target}_")
- set(prl_meta_info_name_suffix ".txt")
- qt_path_join(prl_meta_info_path
- "${CMAKE_CURRENT_BINARY_DIR}"
- "${prl_meta_info_name_prefix}$<CONFIG>${prl_meta_info_name_suffix}")
-
- # The final prl file name that will be embedded in the file above.
- set(final_prl_file_name "${prefix_for_final_prl_name}$<TARGET_FILE_BASE_NAME:${target}>.prl")
- qt_path_join(final_prl_file_path "${QT_BUILD_DIR}/${install_dir}" "${final_prl_file_name}")
-
- # Generate the prl content and its final file name into configuration specific files
- # whose names we know, and can be used in add_custom_command.
- set(prl_step1_content
- "RCC_OBJECTS = ${rcc_objects}
-QMAKE_PRL_BUILD_DIR = ${CMAKE_CURRENT_BINARY_DIR}
-QMAKE_PRL_TARGET = $<TARGET_FILE_NAME:${target}>
-QMAKE_PRL_CONFIG = ${prl_config}
-QMAKE_PRL_VERSION = ${PROJECT_VERSION}
-")
- if(NOT is_static AND WIN32)
- # Do nothing. Prl files for shared libraries on Windows shouldn't have the libs listed,
- # as per qt_build_config.prf and the conditional CONFIG+=explicitlib assignment.
- else()
- set(prl_libs "")
- qt_collect_libs(${target} prl_libs)
- string(APPEND prl_step1_content "QMAKE_PRL_LIBS_FOR_CMAKE = ${prl_libs}\n")
- endif()
-
- file(GENERATE
- OUTPUT "${prl_step1_path}"
- CONTENT "${prl_step1_content}")
- file(GENERATE
- OUTPUT "${prl_meta_info_path}"
- CONTENT
- "FINAL_PRL_FILE_PATH = ${final_prl_file_path}")
-
- set(library_prefixes ${CMAKE_SHARED_LIBRARY_PREFIX} ${CMAKE_STATIC_LIBRARY_PREFIX})
- set(library_suffixes
- ${CMAKE_SHARED_LIBRARY_SUFFIX}
- ${CMAKE_EXTRA_SHARED_LIBRARY_SUFFIXES}
- ${CMAKE_STATIC_LIBRARY_SUFFIX})
-
- if(QT_GENERATOR_IS_MULTI_CONFIG)
- set(configs ${CMAKE_CONFIGURATION_TYPES})
- else()
- set(configs ${CMAKE_BUILD_TYPE})
- endif()
-
- foreach(config ${configs})
- # Output file for dependency tracking, and which will contain the final content.
- qt_path_join(prl_step2_path
- "${CMAKE_CURRENT_BINARY_DIR}" "preliminary_prl_for_${target}_step2_${config}.prl")
-
- # Input dependency names that are constructed for each config manually
- # (no genexes allowed).
- qt_path_join(prl_step1_path
- "${CMAKE_CURRENT_BINARY_DIR}"
- "${prl_step1_name_prefix}${config}${prl_step1_name_suffix}")
- qt_path_join(prl_meta_info_path
- "${CMAKE_CURRENT_BINARY_DIR}"
- "${prl_meta_info_name_prefix}${config}${prl_meta_info_name_suffix}")
- add_custom_command(
- OUTPUT "${prl_step2_path}"
- DEPENDS "${prl_step1_path}"
- "${prl_meta_info_path}"
- "${QT_CMAKE_DIR}/QtFinishPrlFile.cmake"
- "${QT_CMAKE_DIR}/QtGenerateLibHelpers.cmake"
- COMMAND ${CMAKE_COMMAND}
- "-DIN_FILE=${prl_step1_path}"
- "-DIN_META_FILE=${prl_meta_info_path}"
- "-DOUT_FILE=${prl_step2_path}"
- "-DLIBRARY_PREFIXES=${library_prefixes}"
- "-DLIBRARY_SUFFIXES=${library_suffixes}"
- "-DLINK_LIBRARY_FLAG=${CMAKE_LINK_LIBRARY_FLAG}"
- "-DQT_BUILD_LIBDIR=${QT_BUILD_DIR}/${INSTALL_LIBDIR}"
- -P "${QT_CMAKE_DIR}/QtFinishPrlFile.cmake"
- VERBATIM
- COMMENT "Generating prl file for target ${target}"
- )
-
- # Tell the target to depend on the preliminary prl file, to ensure the custom command
- # is executed. As a side-effect, this will also create the final prl file that
- # is named appropriately. It should not be specified as a BYPRODUCT.
- # This allows proper per-file dependency tracking, without having to resort on a POST_BUILD
- # step, which means that relinking would happen as well as transitive rebuilding of any
- # dependees.
- # This is inspired by https://gitlab.kitware.com/cmake/cmake/-/issues/20842
- target_sources(${target} PRIVATE "${prl_step2_path}")
- endforeach()
-
- # Installation of the .prl file happens globally elsewhere,
- # because we have no clue here what the actual file name is.
- # What we know however, is the directory where the prl file is created.
- # Save that for later, to install all prl files from that directory.
- get_property(prl_install_dirs GLOBAL PROPERTY QT_PRL_INSTALL_DIRS)
- if(NOT install_dir IN_LIST prl_install_dirs)
- set_property(GLOBAL APPEND PROPERTY QT_PRL_INSTALL_DIRS "${install_dir}")
- endif()
-endfunction()
-
-function(qt_export_tools module_name)
- # Bail out when cross-compiling, unless QT_BUILD_TOOLS_WHEN_CROSSCOMPILING is on.
- if(CMAKE_CROSSCOMPILING AND NOT QT_BUILD_TOOLS_WHEN_CROSSCOMPILING)
- return()
- endif()
-
- # If no tools were defined belonging to this module, don't create a config and targets file.
- if(NOT "${module_name}" IN_LIST QT_KNOWN_MODULES_WITH_TOOLS)
- return()
- endif()
-
- # The tools target name. For example: CoreTools
- set(target "${module_name}Tools")
-
- set(path_suffix "${INSTALL_CMAKE_NAMESPACE}${target}")
- qt_path_join(config_build_dir ${QT_CONFIG_BUILD_DIR} ${path_suffix})
- qt_path_join(config_install_dir ${QT_CONFIG_INSTALL_DIR} ${path_suffix})
-
- # Add the extra cmake statements to make the tool targets global, so it doesn't matter where
- # find_package is called.
- # Also assemble a list of tool targets to expose in the config file for informational purposes.
- set(extra_cmake_statements "")
- set(tool_targets "")
- set(tool_targets_non_prefixed "")
-
- # List of package dependencies that need be find_package'd when using the Tools package.
- set(package_deps "")
-
- foreach(tool_name ${QT_KNOWN_MODULE_${module_name}_TOOLS})
- # Specific tools can have package dependencies.
- # e.g. qtwaylandscanner depends on WaylandScanner (non-qt package).
- get_target_property(extra_packages "${tool_name}" QT_EXTRA_PACKAGE_DEPENDENCIES)
- if(extra_packages)
- list(APPEND package_deps "${extra_packages}")
- endif()
-
- if (CMAKE_CROSSCOMPILING AND QT_BUILD_TOOLS_WHEN_CROSSCOMPILING)
- string(REGEX REPLACE "_native$" "" tool_name ${tool_name})
- endif()
- set(extra_cmake_statements "${extra_cmake_statements}
-if (NOT QT_NO_CREATE_TARGETS)
- get_property(is_global TARGET ${INSTALL_CMAKE_NAMESPACE}::${tool_name} PROPERTY IMPORTED_GLOBAL)
- if(NOT is_global)
- set_property(TARGET ${INSTALL_CMAKE_NAMESPACE}::${tool_name} PROPERTY IMPORTED_GLOBAL TRUE)
- endif()
-endif()
-")
- list(APPEND tool_targets "${QT_CMAKE_EXPORT_NAMESPACE}::${tool_name}")
- list(APPEND tool_targets_non_prefixed "${tool_name}")
- endforeach()
-
- string(APPEND extra_cmake_statements
-"set(${QT_CMAKE_EXPORT_NAMESPACE}${module_name}Tools_TARGETS \"${tool_targets}\")")
-
- # Extract package dependencies that were determined in QtPostProcess, but only if ${module_name}
- # is an actual target.
- # module_name can be a non-existent target, if the tool doesn't have an existing associated
- # module, e.g. qtwaylandscanner.
- if(TARGET "${module_name}")
- get_target_property(module_package_deps "${module_name}" _qt_tools_package_deps)
- if(module_package_deps)
- list(APPEND package_deps "${module_package_deps}")
- endif()
- endif()
-
- # Configure and install dependencies file for the ${module_name}Tools package.
- configure_file(
- "${QT_CMAKE_DIR}/QtModuleToolsDependencies.cmake.in"
- "${config_build_dir}/${INSTALL_CMAKE_NAMESPACE}${target}Dependencies.cmake"
- @ONLY
- )
-
- qt_install(FILES
- "${config_build_dir}/${INSTALL_CMAKE_NAMESPACE}${target}Dependencies.cmake"
- DESTINATION "${config_install_dir}"
- COMPONENT Devel
- )
-
- # Configure and install the ${module_name}Tools package Config file.
- configure_package_config_file(
- "${QT_CMAKE_DIR}/QtModuleToolsConfig.cmake.in"
- "${config_build_dir}/${INSTALL_CMAKE_NAMESPACE}${target}Config.cmake"
- INSTALL_DESTINATION "${config_install_dir}"
- )
- write_basic_package_version_file(
- "${config_build_dir}/${INSTALL_CMAKE_NAMESPACE}${target}ConfigVersion.cmake"
- VERSION ${PROJECT_VERSION}
- COMPATIBILITY AnyNewerVersion
- )
-
- qt_install(FILES
- "${config_build_dir}/${INSTALL_CMAKE_NAMESPACE}${target}Config.cmake"
- "${config_build_dir}/${INSTALL_CMAKE_NAMESPACE}${target}ConfigVersion.cmake"
- DESTINATION "${config_install_dir}"
- COMPONENT Devel
- )
-
- set(export_name "${INSTALL_CMAKE_NAMESPACE}${target}Targets")
- qt_install(EXPORT "${export_name}"
- NAMESPACE "${QT_CMAKE_EXPORT_NAMESPACE}::"
- DESTINATION "${config_install_dir}")
-
-
- # Create versionless targets file.
- configure_file(
- "${QT_CMAKE_DIR}/QtModuleToolsVersionlessTargets.cmake.in"
- "${config_build_dir}/${INSTALL_CMAKE_NAMESPACE}${target}VersionlessTargets.cmake"
- @ONLY
- )
-
- qt_install(FILES
- "${config_build_dir}/${INSTALL_CMAKE_NAMESPACE}${target}VersionlessTargets.cmake"
- DESTINATION "${config_install_dir}"
- COMPONENT Devel
- )
-endfunction()
-
-# This function records a dependency between ${target_name} and ${dep_package_name}.
-# at the CMake package level.
-# E.g. The Tools package that provides the qtwaylandscanner target
-# needs to call find_package(WaylandScanner) (non-qt-package).
-# main_target_name = qtwaylandscanner
-# dep_package_name = WaylandScanner
-function(qt_record_extra_package_dependency main_target_name dep_package_name dep_package_version)
- if (TARGET "${main_target_name}")
- get_target_property(extra_packages "${main_target_name}" QT_EXTRA_PACKAGE_DEPENDENCIES)
- if(NOT extra_packages)
- set(extra_packages "")
- endif()
-
- list(APPEND extra_packages "${dep_package_name}\;${dep_package_version}")
- set_target_properties("${main_target_name}" PROPERTIES QT_EXTRA_PACKAGE_DEPENDENCIES
- "${extra_packages}")
- endif()
-endfunction()
-
-# This function records a dependency between ${main_target_name} and ${dep_target_name}
-# at the CMake package level.
-# E.g. Qt6CoreConfig.cmake needs to find_package(Qt6WinMain).
-# main_target_name = Core
-# dep_target_name = WinMain
-# This is just a convenience function that deals with Qt targets and their associated packages
-# instead of raw package names.
-function(qt_record_extra_qt_package_dependency main_target_name dep_target_name
- dep_package_version)
- # WinMain -> Qt6WinMain.
- qt_internal_module_info(qtfied_target_name "${dep_target_name}")
- qt_record_extra_package_dependency("${main_target_name}" "${qtfied_target_name_versioned}"
- "${dep_package_version}")
-endfunction()
-
-function(qt_internal_check_directory_or_type name dir type default result_var)
- if ("x${dir}" STREQUAL x)
- if("x${type}" STREQUAL x)
- message(FATAL_ERROR "qt_internal_add_plugin called without setting either TYPE or ${name}.")
- endif()
- set(${result_var} "${default}" PARENT_SCOPE)
- else()
- set(${result_var} "${dir}" PARENT_SCOPE)
- endif()
-endfunction()
-
-# Utility function to find the module to which a plug-in belongs.
-# This will set the QT_MODULE target property on the plug-in - e.g. "Gui", "Sql"...
-function(qt_get_module_for_plugin target target_type)
- qt_internal_get_qt_all_known_modules(known_modules)
-
- qt_get_sanitized_plugin_type("${target_type}" target_type)
- foreach(qt_module ${known_modules})
- get_target_property(module_type "${QT_CMAKE_EXPORT_NAMESPACE}::${qt_module}" TYPE)
- # Assuming interface libraries can't have plugins. Otherwise we'll need to fix the property
- # name, because the current one would be invalid for interface libraries.
- if(module_type STREQUAL "INTERFACE_LIBRARY")
- continue()
- endif()
-
- get_target_property(plugin_types
- "${QT_CMAKE_EXPORT_NAMESPACE}::${qt_module}"
- MODULE_PLUGIN_TYPES)
- if(plugin_types)
- foreach(plugin_type ${plugin_types})
- if("${target_type}" STREQUAL "${plugin_type}")
- set_target_properties("${target}" PROPERTIES QT_MODULE "${qt_module}")
- return()
- endif()
- endforeach()
- endif()
- endforeach()
- message(AUTHOR_WARNING "The plug-in '${target}' does not belong to any Qt module.")
-endfunction()
-
-
-# Collection of qt_add_plugin arguments so they can be shared across different
-# plugin type wrappers
-set(__qt_add_plugin_optional_args
- "STATIC;EXCEPTIONS;ALLOW_UNDEFINED_SYMBOLS"
-)
-set(__qt_add_plugin_single_args
- "TYPE;CLASS_NAME;OUTPUT_DIRECTORY;INSTALL_DIRECTORY;ARCHIVE_INSTALL_DIRECTORY;QML_TARGET_PATH;OUTPUT_NAME"
- ${__default_target_info_args}
-)
-set(__qt_add_plugin_multi_args
- "${__default_private_args};${__default_public_args};DEFAULT_IF"
-)
-# This is the main entry point for defining Qt plugins.
-# A CMake target is created with the given target. The TYPE parameter is needed to place the
-# plugin into the correct plugins/ sub-directory.
-function(qt_internal_add_plugin target)
- qt_internal_module_info(module "${target}")
-
- qt_internal_set_qt_known_plugins("${QT_KNOWN_PLUGINS}" "${target}")
-
- qt_parse_all_arguments(arg "qt_internal_add_plugin"
- "${__qt_add_plugin_optional_args};SKIP_INSTALL"
- "${__qt_add_plugin_single_args}"
- "${__qt_add_plugin_multi_args}"
- "${ARGN}"
- )
-
- qt_get_sanitized_plugin_type("${arg_TYPE}" plugin_type_escaped)
-
- set(output_directory_default "${QT_BUILD_DIR}/${INSTALL_PLUGINSDIR}/${arg_TYPE}")
- set(install_directory_default "${INSTALL_PLUGINSDIR}/${arg_TYPE}")
-
- if (arg_QML_TARGET_PATH)
- set(target_path "${arg_QML_TARGET_PATH}")
- set(output_directory_default "${QT_BUILD_DIR}/${INSTALL_QMLDIR}/${target_path}")
- set(install_directory_default "${INSTALL_QMLDIR}/${target_path}")
- endif()
-
- # Derive the class name from the target name if it's not explicitly specified.
- # Don't set it for qml plugins though.
- set(plugin_class_name "")
- if (NOT "${plugin_type_escaped}" STREQUAL "qml_plugin")
- if (NOT arg_CLASS_NAME)
- set(plugin_class_name "${target}")
- else()
- set(plugin_class_name "${arg_CLASS_NAME}")
- endif()
- endif()
-
- qt_internal_check_directory_or_type(OUTPUT_DIRECTORY "${arg_OUTPUT_DIRECTORY}" "${arg_TYPE}"
- "${output_directory_default}" output_directory)
- if (NOT arg_SKIP_INSTALL)
- qt_internal_check_directory_or_type(INSTALL_DIRECTORY "${arg_INSTALL_DIRECTORY}" "${arg_TYPE}"
- "${install_directory_default}" install_directory)
- set(archive_install_directory ${arg_ARCHIVE_INSTALL_DIRECTORY})
- if (NOT archive_install_directory AND install_directory)
- set(archive_install_directory "${install_directory}")
- endif()
- endif()
-
- if(arg_STATIC OR NOT BUILD_SHARED_LIBS)
- add_library("${target}" STATIC)
- else()
- add_library("${target}" MODULE)
- if(APPLE)
- # CMake defaults to using .so extensions for loadable modules, aka plugins,
- # but Qt plugins are actually suffixed with .dylib.
- set_property(TARGET "${target}" PROPERTY SUFFIX ".dylib")
- endif()
- qt_internal_apply_win_prefix_and_suffix("${target}")
- endif()
-
- qt_set_common_target_properties(${target})
- qt_set_target_info_properties(${target} ${ARGN} TARGET_VERSION "${arg_VERSION}")
-
- # Make sure the Qt6 plugin library names are like they were in Qt5 qmake land.
- # Whereas the Qt6 CMake target names are like the Qt5 CMake target names.
- set(output_name "${target}")
- if(arg_OUTPUT_NAME)
- set(output_name "${arg_OUTPUT_NAME}")
- endif()
- set_property(TARGET "${target}" PROPERTY OUTPUT_NAME "${output_name}")
-
- # Add a custom target with the Qt5 qmake name for a more user friendly ninja experience.
- if(arg_OUTPUT_NAME AND NOT TARGET "${output_name}")
- add_custom_target("${output_name}")
- add_dependencies("${output_name}" "${target}")
- endif()
-
- if (ANDROID)
- qt_android_apply_arch_suffix("${target}")
- set_target_properties(${target}
- PROPERTIES
- LIBRARY_OUTPUT_NAME "plugins_${arg_TYPE}_${output_name}"
- )
- endif()
- qt_internal_add_target_aliases("${target}")
- qt_skip_warnings_are_errors_when_repo_unclean("${target}")
-
- # Disable linking of plugins against other plugins during static regular and
- # super builds. The latter causes cyclic dependencies otherwise.
- set_target_properties(${target} PROPERTIES QT_DEFAULT_PLUGINS 0)
-
- set_target_properties("${target}" PROPERTIES
- LIBRARY_OUTPUT_DIRECTORY "${output_directory}"
- RUNTIME_OUTPUT_DIRECTORY "${output_directory}"
- ARCHIVE_OUTPUT_DIRECTORY "${output_directory}"
- QT_PLUGIN_TYPE "${plugin_type_escaped}"
- # Save the non-sanitized plugin type values for qmake consumption via .pri files.
- QT_QMAKE_PLUGIN_TYPE "${arg_TYPE}"
- QT_PLUGIN_CLASS_NAME "${plugin_class_name}")
- qt_handle_multi_config_output_dirs("${target}")
-
- qt_internal_library_deprecation_level(deprecation_define)
-
- qt_autogen_tools_initial_setup(${target})
-
- set(static_plugin_define "")
- if (arg_STATIC OR NOT QT_BUILD_SHARED_LIBS)
- set(static_plugin_define "QT_STATICPLUGIN")
- endif()
-
- # Save the Qt module in the plug-in's properties
- if(NOT plugin_type_escaped STREQUAL "qml_plugin")
- qt_get_module_for_plugin("${target}" "${plugin_type_escaped}")
- get_target_property(qt_module "${target}" QT_MODULE)
- endif()
-
- # Add the plug-in to the list of plug-ins of this module
- if(TARGET "${qt_module}")
- set_property(TARGET "${qt_module}" APPEND PROPERTY QT_PLUGINS "${target}")
- endif()
-
- set(_default_plugin 1)
- if (DEFINED arg_DEFAULT_IF)
- if (NOT ${arg_DEFAULT_IF})
- set(_default_plugin 0)
- endif()
- endif()
-
- set_property(TARGET "${target}" PROPERTY QT_DEFAULT_PLUGIN "${_default_plugin}")
- set_property(TARGET "${target}" APPEND PROPERTY EXPORT_PROPERTIES "QT_PLUGIN_CLASS_NAME;QT_PLUGIN_TYPE;QT_MODULE;QT_DEFAULT_PLUGIN")
-
- set(private_includes
- "${CMAKE_CURRENT_SOURCE_DIR}"
- "${CMAKE_CURRENT_BINARY_DIR}"
- # For the syncqt headers
- "$<BUILD_INTERFACE:${module_repo_include_dir}>"
- ${arg_INCLUDE_DIRECTORIES}
- )
-
- set(public_includes
- ${arg_PUBLIC_INCLUDE_DIRECTORIES}
- )
-
- qt_extend_target("${target}"
- SOURCES ${arg_SOURCES}
- INCLUDE_DIRECTORIES
- ${private_includes}
- PUBLIC_INCLUDE_DIRECTORIES
- ${public_includes}
- LIBRARIES ${arg_LIBRARIES} Qt::PlatformPluginInternal
- PUBLIC_LIBRARIES ${arg_PUBLIC_LIBRARIES}
- DEFINES
- ${arg_DEFINES}
- QT_DEPRECATED_WARNINGS
- "${deprecation_define}"
- "${static_plugin_define}"
- QT_PLUGIN
- PUBLIC_DEFINES
- QT_${module_define}_LIB
- ${arg_PUBLIC_DEFINES}
- FEATURE_DEPENDENCIES ${arg_FEATURE_DEPENDENCIES}
- DBUS_ADAPTOR_SOURCES "${arg_DBUS_ADAPTOR_SOURCES}"
- DBUS_ADAPTOR_FLAGS "${arg_DBUS_ADAPTOR_FLAGS}"
- DBUS_INTERFACE_SOURCES "${arg_DBUS_INTERFACE_SOURCES}"
- DBUS_INTERFACE_FLAGS "${arg_DBUS_INTERFACE_FLAGS}"
- COMPILE_OPTIONS ${arg_COMPILE_OPTIONS}
- PUBLIC_COMPILE_OPTIONS ${arg_PUBLIC_COMPILE_OPTIONS}
- LINK_OPTIONS ${arg_LINK_OPTIONS}
- PUBLIC_LINK_OPTIONS ${arg_PUBLIC_LINK_OPTIONS}
- MOC_OPTIONS ${arg_MOC_OPTIONS}
- ENABLE_AUTOGEN_TOOLS ${arg_ENABLE_AUTOGEN_TOOLS}
- DISABLE_AUTOGEN_TOOLS ${arg_DISABLE_AUTOGEN_TOOLS}
- )
- if(NOT ${arg_EXCEPTIONS})
- qt_internal_set_no_exceptions_flags("${target}")
- endif()
-
-
- set(qt_libs_private "")
- qt_internal_get_qt_all_known_modules(known_modules)
- foreach(it ${known_modules})
- list(FIND arg_LIBRARIES "Qt::${it}Private" pos)
- if(pos GREATER -1)
- list(APPEND qt_libs_private "Qt::${it}Private")
- endif()
- endforeach()
-
- qt_register_target_dependencies("${target}" "${arg_PUBLIC_LIBRARIES}" "${qt_libs_private}")
- qt_generate_plugin_pri_file("${target}" pri_file)
-
- if (NOT arg_SKIP_INSTALL)
- # Handle creation of cmake files for consumers of find_package().
- # If we are part of a Qt module, the plugin cmake files are installed as part of that module.
- if(qt_module)
- set(path_suffix "${INSTALL_CMAKE_NAMESPACE}${qt_module}")
- else()
- set(path_suffix "${INSTALL_CMAKE_NAMESPACE}${target}")
- endif()
-
- qt_path_join(config_build_dir ${QT_CONFIG_BUILD_DIR} ${path_suffix})
- qt_path_join(config_install_dir ${QT_CONFIG_INSTALL_DIR} ${path_suffix})
-
- configure_package_config_file(
- "${QT_CMAKE_DIR}/QtPluginConfig.cmake.in"
- "${config_build_dir}/${target}Config.cmake"
- INSTALL_DESTINATION "${config_install_dir}"
- )
- write_basic_package_version_file(
- "${config_build_dir}/${target}ConfigVersion.cmake"
- VERSION ${PROJECT_VERSION}
- COMPATIBILITY AnyNewerVersion
- )
-
- qt_install(FILES
- "${config_build_dir}/${target}Config.cmake"
- "${config_build_dir}/${target}ConfigVersion.cmake"
- DESTINATION "${config_install_dir}"
- COMPONENT Devel
- )
- qt_install(FILES
- "${pri_file}"
- DESTINATION "${INSTALL_MKSPECSDIR}/modules"
- )
-
- # Make the export name of plugins be consistent with modules, so that
- # qt_add_resource adds its additional targets to the same export set in a static Qt build.
- set(export_name "${INSTALL_CMAKE_NAMESPACE}${target}Targets")
- qt_install(TARGETS "${target}"
- EXPORT ${export_name}
- RUNTIME DESTINATION "${install_directory}"
- LIBRARY DESTINATION "${install_directory}"
- ARCHIVE DESTINATION "${archive_install_directory}"
- )
- qt_install(EXPORT ${export_name}
- NAMESPACE ${QT_CMAKE_EXPORT_NAMESPACE}::
- DESTINATION "${config_install_dir}"
- )
- qt_apply_rpaths(TARGET "${target}" INSTALL_PATH "${install_directory}" RELATIVE_RPATH)
- endif()
-
- if (NOT arg_ALLOW_UNDEFINED_SYMBOLS)
- ### fixme: cmake is missing a built-in variable for this. We want to apply it only to
- # modules and plugins that belong to Qt.
- qt_internal_add_link_flags_no_undefined("${target}")
- endif()
-
- qt_internal_add_linker_version_script(${target})
- qt_add_list_file_finalizer(qt_finalize_plugin ${target} "${install_directory}")
-endfunction()
-
-function(qt_finalize_plugin target install_directory)
- # Generate .prl files for plugins of static Qt builds.
- if(NOT BUILD_SHARED_LIBS)
- qt_generate_prl_file(${target} "${install_directory}")
- endif()
-endfunction()
-
-function(qt_install_qml_files target)
-
- qt_parse_all_arguments(arg "qt_install_qml_files"
- "" "" "FILES" ${ARGN}
- )
-
- if (NOT arg_FILES)
- message(FATAL_ERROR "No files specified for qt_install_qml_files. Please specify them using the FILES parameter.")
- endif()
-
- get_target_property(target_path ${target} QT_QML_MODULE_TARGET_PATH)
- if (NOT target_path)
- message(FATAL_ERROR "Target ${target} is not a qml module.")
- endif()
-
- qt_path_join(qml_module_install_dir ${QT_INSTALL_DIR} "${INSTALL_QMLDIR}/${target_path}")
- qt_copy_or_install(FILES ${arg_FILES}
- DESTINATION ${qml_module_install_dir}
- )
-
-endfunction()
-
-
-function(qt_add_resource target resourceName)
- # Don't try to add resources when cross compiling, and the target is actually a host target
- # (like a tool).
- qt_is_imported_target("${target}" is_imported)
- if(is_imported)
- return()
- endif()
-
- qt_parse_all_arguments(arg "qt_add_resource" "" "PREFIX;LANG;BASE" "FILES" ${ARGN})
-
- QT6_PROCESS_RESOURCE(${target} ${resourceName}
- PREFIX "${arg_PREFIX}"
- LANG "${arg_LANG}"
- BASE "${arg_BASE}"
- FILES ${arg_FILES}
- OUTPUT_TARGETS out_targets
- )
-
- if (out_targets)
- qt_install(TARGETS ${out_targets}
- EXPORT "${INSTALL_CMAKE_NAMESPACE}${target}Targets"
- DESTINATION ${INSTALL_LIBDIR}
- )
- foreach(out_target ${out_targets})
- get_target_property(resource_name ${out_target} QT_RESOURCE_NAME)
- if(NOT resource_name)
- continue()
- endif()
- if(QT_WILL_INSTALL)
- # Compute the install location of the rcc object file.
- # This is the relative path below the install destination (install_prefix/lib).
- # See CMake's computeInstallObjectDir function.
- set(object_file_name "qrc_${resource_name}.cpp${CMAKE_CXX_OUTPUT_EXTENSION}")
- qt_path_join(rcc_object_file_path
- "objects-$<CONFIG>" ${out_target} .rcc "${object_file_name}")
- else()
- # In a non-prefix build we use the object file paths right away.
- set(rcc_object_file_path $<TARGET_OBJECTS:$<TARGET_NAME:${out_target}>>)
- endif()
- set_property(TARGET ${target} APPEND PROPERTY QT_RCC_OBJECTS "${rcc_object_file_path}")
-
- # Make sure that the target cpp files are compiled with the regular Qt internal compile
- # flags, needed for building iOS apps with qmake where bitcode is involved.
- target_link_libraries("${out_target}" PRIVATE Qt::PlatformModuleInternal)
- endforeach()
- endif()
-
-endfunction()
-
-# Collection of qt_add_executable arguments so they can be shared across qt_add_executable
-# and qt_add_test_helper.
-set(__qt_add_executable_optional_args
- "GUI;BOOTSTRAP;NO_QT;NO_INSTALL;EXCEPTIONS;DELAY_RC;DELAY_TARGET_INFO"
-)
-set(__qt_add_executable_single_args
- "OUTPUT_DIRECTORY;INSTALL_DIRECTORY;VERSION"
- ${__default_target_info_args}
-)
-set(__qt_add_executable_multi_args
- "EXE_FLAGS;${__default_private_args};${__default_public_args}"
-)
-
-# This function creates a CMake target for a generic console or GUI binary.
-# Please consider to use a more specific version target like the one created
-# by qt_add_test or qt_add_tool below.
-function(qt_add_executable name)
- qt_parse_all_arguments(arg "qt_add_executable"
- "${__qt_add_executable_optional_args}"
- "${__qt_add_executable_single_args}"
- "${__qt_add_executable_multi_args}"
- ${ARGN})
-
- if ("x${arg_OUTPUT_DIRECTORY}" STREQUAL "x")
- set(arg_OUTPUT_DIRECTORY "${QT_BUILD_DIR}/${INSTALL_BINDIR}")
- endif()
-
- get_filename_component(arg_OUTPUT_DIRECTORY "${arg_OUTPUT_DIRECTORY}"
- ABSOLUTE BASE_DIR "${QT_BUILD_DIR}")
-
- if ("x${arg_INSTALL_DIRECTORY}" STREQUAL "x")
- set(arg_INSTALL_DIRECTORY "${INSTALL_BINDIR}")
- endif()
-
- if (ANDROID)
- add_library("${name}" MODULE)
- qt_android_apply_arch_suffix("${name}")
- qt_android_generate_deployment_settings("${name}")
- qt_android_add_apk_target("${name}")
- # On our qmake builds we don't compile the executables with
- # visibility=hidden. Not having this flag set will cause the
- # executable to have main() hidden and can then no longer be loaded
- # through dlopen()
- set_property(TARGET ${name} PROPERTY C_VISIBILITY_PRESET default)
- set_property(TARGET ${name} PROPERTY CXX_VISIBILITY_PRESET default)
- else()
- add_executable("${name}" ${arg_EXE_FLAGS})
- endif()
-
- if (arg_VERSION)
-
- if(arg_VERSION MATCHES "[0-9]+\\.[0-9]+\\.[0-9]+\\.[0-9]+")
- # nothing to do
- elseif(arg_VERSION MATCHES "[0-9]+\\.[0-9]+\\.[0-9]+")
- set(arg_VERSION "${arg_VERSION}.0")
- elseif(arg_VERSION MATCHES "[0-9]+\\.[0-9]+")
- set(arg_VERSION "${arg_VERSION}.0.0")
- elseif (arg_VERSION MATCHES "[0-9]+")
- set(arg_VERSION "${arg_VERSION}.0.0.0")
- else()
- message(FATAL_ERROR "Invalid version format")
- endif()
- endif()
-
- if(arg_DELAY_TARGET_INFO)
- # Delay the setting of target info properties if requested. Needed for scope finalization
- # of Qt apps.
- set_target_properties("${name}" PROPERTIES
- QT_DELAYED_TARGET_VERSION "${arg_VERSION}"
- QT_DELAYED_TARGET_PRODUCT "${arg_TARGET_PRODUCT}"
- QT_DELAYED_TARGET_DESCRIPTION "${arg_TARGET_DESCRIPTION}"
- QT_DELAYED_TARGET_COMPANY "${arg_TARGET_COMPANY}"
- QT_DELAYED_TARGET_COPYRIGHT "${arg_TARGET_COPYRIGHT}"
- )
- else()
- if("${arg_TARGET_DESCRIPTION}" STREQUAL "")
- set(arg_TARGET_DESCRIPTION "Qt ${name}")
- endif()
- qt_set_target_info_properties(${name} ${ARGN}
- TARGET_DESCRIPTION "${arg_TARGET_DESCRIPTION}"
- TARGET_VERSION "${arg_VERSION}")
- endif()
-
-
- if (WIN32 AND NOT arg_DELAY_RC)
- qt6_generate_win32_rc_file(${name})
- endif()
-
- qt_set_common_target_properties(${name})
- qt_autogen_tools_initial_setup(${name})
- qt_skip_warnings_are_errors_when_repo_unclean("${name}")
-
- set(extra_libraries "")
- if(NOT arg_BOOTSTRAP AND NOT arg_NO_QT)
- set(extra_libraries "Qt::Core")
- endif()
-
- set(private_includes
- "${CMAKE_CURRENT_SOURCE_DIR}"
- "${CMAKE_CURRENT_BINARY_DIR}"
- ${arg_INCLUDE_DIRECTORIES}
- )
-
- qt_extend_target("${name}"
- SOURCES ${arg_SOURCES}
- INCLUDE_DIRECTORIES ${private_includes}
- DEFINES ${arg_DEFINES}
- LIBRARIES ${arg_LIBRARIES} Qt::PlatformCommonInternal
- PUBLIC_LIBRARIES ${extra_libraries} ${arg_PUBLIC_LIBRARIES}
- DBUS_ADAPTOR_SOURCES "${arg_DBUS_ADAPTOR_SOURCES}"
- DBUS_ADAPTOR_FLAGS "${arg_DBUS_ADAPTOR_FLAGS}"
- DBUS_INTERFACE_SOURCES "${arg_DBUS_INTERFACE_SOURCES}"
- DBUS_INTERFACE_FLAGS "${arg_DBUS_INTERFACE_FLAGS}"
- COMPILE_OPTIONS ${arg_COMPILE_OPTIONS}
- LINK_OPTIONS ${arg_LINK_OPTIONS}
- MOC_OPTIONS ${arg_MOC_OPTIONS}
- ENABLE_AUTOGEN_TOOLS ${arg_ENABLE_AUTOGEN_TOOLS}
- DISABLE_AUTOGEN_TOOLS ${arg_DISABLE_AUTOGEN_TOOLS}
- )
- set_target_properties("${name}" PROPERTIES
- RUNTIME_OUTPUT_DIRECTORY "${arg_OUTPUT_DIRECTORY}"
- LIBRARY_OUTPUT_DIRECTORY "${arg_OUTPUT_DIRECTORY}"
- WIN32_EXECUTABLE "${arg_GUI}"
- MACOSX_BUNDLE "${arg_GUI}"
- )
- if(NOT ${arg_EXCEPTIONS})
- qt_internal_set_no_exceptions_flags("${name}")
- endif()
-
- # Check if target needs to be excluded from all target. Also affects qt_install.
- # Set by qt_exclude_tool_directories_from_default_target.
- set(exclude_from_all FALSE)
- if(__qt_exclude_tool_directories)
- foreach(absolute_dir ${__qt_exclude_tool_directories})
- string(FIND "${CMAKE_CURRENT_SOURCE_DIR}" "${absolute_dir}" dir_starting_pos)
- if(dir_starting_pos EQUAL 0)
- set(exclude_from_all TRUE)
- set_target_properties("${name}" PROPERTIES EXCLUDE_FROM_ALL TRUE)
- break()
- endif()
- endforeach()
- endif()
-
- if(NOT arg_NO_INSTALL)
- set(additional_install_args "")
- if(exclude_from_all)
- list(APPEND additional_install_args EXCLUDE_FROM_ALL COMPONENT "ExcludedExecutables")
- endif()
-
- qt_get_cmake_configurations(cmake_configs)
- foreach(cmake_config ${cmake_configs})
- qt_get_install_target_default_args(
- OUT_VAR install_targets_default_args
- CMAKE_CONFIG "${cmake_config}"
- ALL_CMAKE_CONFIGS "${cmake_configs}"
- RUNTIME "${arg_INSTALL_DIRECTORY}"
- LIBRARY "${arg_INSTALL_DIRECTORY}"
- BUNDLE "${arg_INSTALL_DIRECTORY}")
- qt_install(TARGETS "${name}"
- ${additional_install_args} # Needs to be before the DESTINATIONS.
- CONFIGURATIONS ${cmake_config}
- ${install_targets_default_args})
- endforeach()
- endif()
-endfunction()
-
-# Simple wrapper around qt_add_executable for benchmarks which insure that
-# the binary is built under ${CMAKE_CURRENT_BINARY_DIR} and never installed.
-# See qt_add_executable() for more details.
-function(qt_add_benchmark target)
-
- qt_parse_all_arguments(arg "qt_add_benchmark"
- "${__qt_add_executable_optional_args}"
- "${__qt_add_executable_single_args}"
- "${__qt_add_executable_multi_args}"
- ${ARGN}
- )
-
- qt_remove_args(exec_args
- ARGS_TO_REMOVE
- ${target}
- OUTPUT_DIRECTORY
- INSTALL_DIRECTORY
- ALL_ARGS
- "${__qt_add_executable_optional_args}"
- "${__qt_add_executable_single_args}"
- "${__qt_add_executable_multi_args}"
- ARGS
- ${ARGV}
- )
-
- if(NOT arg_OUTPUT_DIRECTORY)
- set(arg_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}")
- endif()
-
- qt_add_executable(${target}
- NO_INSTALL # we don't install benchmarks
- OUTPUT_DIRECTORY "${arg_OUTPUT_DIRECTORY}" # avoid polluting bin directory
- ${exec_args}
- )
-
-endfunction()
-
-# Simple wrapper around qt_add_executable for manual tests which insure that
-# the binary is built under ${CMAKE_CURRENT_BINARY_DIR} and never installed.
-# See qt_add_executable() for more details.
-function(qt_add_manual_test target)
-
- qt_parse_all_arguments(arg "qt_add_manual_test"
- "${__qt_add_executable_optional_args}"
- "${__qt_add_executable_single_args}"
- "${__qt_add_executable_multi_args}"
- ${ARGN}
- )
-
- qt_remove_args(exec_args
- ARGS_TO_REMOVE
- ${target}
- OUTPUT_DIRECTORY
- INSTALL_DIRECTORY
- ALL_ARGS
- "${__qt_add_executable_optional_args}"
- "${__qt_add_executable_single_args}"
- "${__qt_add_executable_multi_args}"
- ARGS
- ${ARGV}
- )
-
- if(NOT arg_OUTPUT_DIRECTORY)
- set(arg_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}")
- endif()
-
- qt_add_executable(${target}
- NO_INSTALL # we don't install benchmarks
- OUTPUT_DIRECTORY "${arg_OUTPUT_DIRECTORY}" # avoid polluting bin directory
- ${exec_args}
- )
-
-endfunction()
-
-
-# This function creates a CMake test target with the specified name for use with CTest.
-function(qt_add_test name)
- qt_parse_all_arguments(arg "qt_add_test"
- "RUN_SERIAL;EXCEPTIONS;GUI;QMLTEST;CATCH;LOWDPI"
- "OUTPUT_DIRECTORY;WORKING_DIRECTORY;TIMEOUT;VERSION"
- "QML_IMPORTPATH;TESTDATA;${__default_private_args};${__default_public_args}" ${ARGN}
- )
-
- if (NOT arg_OUTPUT_DIRECTORY)
- set(arg_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}")
- endif()
-
- if (${arg_EXCEPTIONS})
- set(exceptions_text "EXCEPTIONS")
- endif()
-
- if (${arg_GUI})
- set(gui_text "GUI")
- endif()
-
- if (arg_VERSION)
- set(version_arg VERSION "${arg_VERSION}")
- endif()
-
- # Handle cases where we have a qml test without source files
- if (arg_SOURCES)
- set(private_includes
- "${CMAKE_CURRENT_SOURCE_DIR}"
- "${CMAKE_CURRENT_BINARY_DIR}"
- "$<BUILD_INTERFACE:${QT_BUILD_DIR}/${INSTALL_INCLUDEDIR}>"
- ${arg_INCLUDE_DIRECTORIES}
- )
-
- qt_add_executable("${name}"
- ${exceptions_text}
- ${gui_text}
- ${version_arg}
- NO_INSTALL
- OUTPUT_DIRECTORY "${arg_OUTPUT_DIRECTORY}"
- SOURCES "${arg_SOURCES}"
- INCLUDE_DIRECTORIES
- ${private_includes}
- DEFINES
- QT_TESTCASE_BUILDDIR="${CMAKE_CURRENT_BINARY_DIR}"
- QT_TESTCASE_SOURCEDIR="${CMAKE_CURRENT_SOURCE_DIR}"
- ${arg_DEFINES}
- PUBLIC_LIBRARIES ${QT_CMAKE_EXPORT_NAMESPACE}::Core ${QT_CMAKE_EXPORT_NAMESPACE}::Test ${arg_PUBLIC_LIBRARIES}
- LIBRARIES ${arg_LIBRARIES}
- COMPILE_OPTIONS ${arg_COMPILE_OPTIONS}
- LINK_OPTIONS ${arg_LINK_OPTIONS}
- MOC_OPTIONS ${arg_MOC_OPTIONS}
- ENABLE_AUTOGEN_TOOLS ${arg_ENABLE_AUTOGEN_TOOLS}
- DISABLE_AUTOGEN_TOOLS ${arg_DISABLE_AUTOGEN_TOOLS}
- )
-
- # Tests should not be bundles on macOS even if arg_GUI is true, because some tests make
- # assumptions about the location of helper processes, and those paths would be different
- # if a test is built as a bundle.
- set_property(TARGET "${name}" PROPERTY MACOSX_BUNDLE FALSE)
- # The same goes for WIN32_EXECUTABLE, but because it will detach from the console window
- # and not print anything.
- set_property(TARGET "${name}" PROPERTY WIN32_EXECUTABLE FALSE)
-
- # QMLTest specifics
-
- qt_extend_target("${name}" CONDITION arg_QMLTEST
- PUBLIC_LIBRARIES ${QT_CMAKE_EXPORT_NAMESPACE}::QuickTest
- )
-
- qt_extend_target("${name}" CONDITION arg_QMLTEST AND NOT ANDROID
- DEFINES
- QUICK_TEST_SOURCE_DIR="${CMAKE_CURRENT_SOURCE_DIR}"
- )
-
- qt_extend_target("${name}" CONDITION arg_QMLTEST AND ANDROID
- DEFINES
- QUICK_TEST_SOURCE_DIR=":/"
- )
- endif()
-
- foreach(path IN LISTS arg_QML_IMPORTPATH)
- list(APPEND extra_test_args "-import" "${path}")
- endforeach()
-
- # Generate a label in the form tests/auto/foo/bar/tst_baz
- # and use it also for XML output
- file(RELATIVE_PATH label "${PROJECT_SOURCE_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}/${name}")
-
- if (arg_LOWDPI)
- target_compile_definitions("${name}" PUBLIC TESTCASE_LOWDPI)
- if (MACOS)
- set_property(TARGET "${name}" PROPERTY MACOSX_BUNDLE_INFO_PLIST "${QT_MKSPECS_DIR}/macx-clang/Info.plist.disable_highdpi")
- set_property(TARGET "${name}" PROPERTY PROPERTY MACOSX_BUNDLE TRUE)
- endif()
- endif()
-
- if (ANDROID)
- qt_android_add_test("${name}")
- else()
- if(arg_QMLTEST AND NOT arg_SOURCES)
- set(test_working_dir "${CMAKE_CURRENT_SOURCE_DIR}")
- set(test_executable ${QT_CMAKE_EXPORT_NAMESPACE}::qmltestrunner)
- else()
- if (arg_WORKING_DIRECTORY)
- set(test_working_dir "${arg_WORKING_DIRECTORY}")
- elseif(arg_OUTPUT_DIRECTORY)
- set(test_working_dir "${arg_OUTPUT_DIRECTORY}")
- else()
- set(test_working_dir "${CMAKE_CURRENT_BINARY_DIR}")
- endif()
- set(test_executable "${name}")
- endif()
-
- if (NOT arg_CATCH)
- list(APPEND test_outputs "-o" "${name}.xml,xml" "-o" "-,txt")
- endif()
-
- add_test(NAME "${name}" COMMAND ${test_executable} ${extra_test_args} ${test_outputs} WORKING_DIRECTORY "${test_working_dir}")
- endif()
- set_tests_properties("${name}" PROPERTIES RUN_SERIAL "${arg_RUN_SERIAL}" LABELS "${label}")
- if (arg_TIMEOUT)
- set_tests_properties(${name} PROPERTIES TIMEOUT ${arg_TIMEOUT})
- endif()
-
- # Add a ${target}/check makefile target, to more easily test one test.
- if(TEST "${name}")
- add_custom_target("${name}_check"
- VERBATIM
- COMMENT "Running ${CMAKE_CTEST_COMMAND} -V -R \"^${name}$\""
- COMMAND "${CMAKE_CTEST_COMMAND}" -V -R "^${name}$"
- )
- if(TARGET "${name}")
- add_dependencies("${name}_check" "${name}")
- endif()
- endif()
-
- # Get path to <qt_relocatable_install_prefix>/bin, as well as CMAKE_INSTALL_PREFIX/bin, then
- # prepend them to the PATH environment variable.
- # It's needed on Windows to find the shared libraries and plugins.
- # qt_relocatable_install_prefix is dynamically computed from the location of where the Qt CMake
- # package is found.
- # The regular CMAKE_INSTALL_PREFIX can be different for example when building standalone tests.
- # Any given CMAKE_INSTALL_PREFIX takes priority over qt_relocatable_install_prefix for the
- # PATH environment variable.
- set(install_prefixes "${CMAKE_INSTALL_PREFIX}")
- if(QT_BUILD_INTERNALS_RELOCATABLE_INSTALL_PREFIX)
- list(APPEND install_prefixes "${QT_BUILD_INTERNALS_RELOCATABLE_INSTALL_PREFIX}")
- endif()
-
- set(test_env_path "PATH=${CMAKE_CURRENT_BINARY_DIR}")
- foreach(install_prefix ${install_prefixes})
- set(test_env_path "${test_env_path}${QT_PATH_SEPARATOR}${install_prefix}/${INSTALL_BINDIR}")
- endforeach()
- set(test_env_path "${test_env_path}${QT_PATH_SEPARATOR}$ENV{PATH}")
- string(REPLACE ";" "\;" test_env_path "${test_env_path}")
- set_property(TEST "${name}" APPEND PROPERTY ENVIRONMENT "${test_env_path}")
- set_property(TEST "${name}" APPEND PROPERTY ENVIRONMENT "QT_TEST_RUNNING_IN_CTEST=1")
-
- # Add the install prefix to list of plugin paths when doing a prefix build
- if(NOT QT_INSTALL_DIR)
- foreach(install_prefix ${install_prefixes})
- list(APPEND plugin_paths "${install_prefix}/${INSTALL_PLUGINSDIR}")
- endforeach()
- endif()
-
- #TODO: Collect all paths from known repositories when performing a super
- # build.
- list(APPEND plugin_paths "${PROJECT_BINARY_DIR}/${INSTALL_PLUGINSDIR}")
- list(JOIN plugin_paths "${QT_PATH_SEPARATOR}" plugin_paths_joined)
- set_property(TEST "${name}" APPEND PROPERTY ENVIRONMENT "QT_PLUGIN_PATH=${plugin_paths_joined}")
-
- if(ANDROID OR IOS OR WINRT)
- set(builtin_testdata TRUE)
- endif()
-
- if(builtin_testdata)
- # Safe guard against qml only tests, no source files == no target
- if (TARGET "${name}")
- target_compile_definitions("${name}" PRIVATE BUILTIN_TESTDATA)
-
- foreach(testdata IN LISTS arg_TESTDATA)
- list(APPEND builtin_files ${testdata})
- endforeach()
-
- set(blacklist_path "BLACKLIST")
- if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/${blacklist_path}")
- list(APPEND builtin_files ${blacklist_path})
- endif()
-
- list(REMOVE_DUPLICATES builtin_files)
-
- # Skip Qt quick compiler when embedding test resources
- foreach(file IN LISTS builtin_files)
- set_source_files_properties(${file}
- PROPERTIES QT_SKIP_QUICKCOMPILER TRUE
- )
- endforeach()
-
- if (builtin_files)
- qt_add_resource(${name} "${name}_testdata_builtin"
- PREFIX "/"
- FILES ${builtin_files}
- BASE ${CMAKE_CURRENT_SOURCE_DIR})
- endif()
- endif()
- else()
- # Install test data
- file(RELATIVE_PATH relative_path_to_test_project
- "${QT_TOP_LEVEL_SOURCE_DIR}"
- "${CMAKE_CURRENT_SOURCE_DIR}")
- qt_path_join(testdata_install_dir ${QT_INSTALL_DIR}
- "${relative_path_to_test_project}")
- foreach(testdata IN LISTS arg_TESTDATA)
- set(testdata "${CMAKE_CURRENT_SOURCE_DIR}/${testdata}")
- if (IS_DIRECTORY "${testdata}")
- qt_install(
- DIRECTORY "${testdata}"
- DESTINATION "${testdata_install_dir}")
- else()
- qt_install(
- FILES "${testdata}"
- DESTINATION "${testdata_install_dir}")
- endif()
- endforeach()
- endif()
-
-endfunction()
-
-
-# This function creates an executable for use as a helper program with tests. Some
-# tests launch separate programs to test certain input/output behavior.
-# Specify OVERRIDE_OUTPUT_DIRECTORY if you dont' want to place the helper in the parent directory,
-# in which case you should specify OUTPUT_DIRECTORY "/foo/bar" manually.
-function(qt_add_test_helper name)
-
- set(qt_add_test_helper_optional_args
- "OVERRIDE_OUTPUT_DIRECTORY"
- )
-
- qt_parse_all_arguments(arg "qt_add_test_helper"
- "${qt_add_test_helper_optional_args};${__qt_add_executable_optional_args}"
- "${__qt_add_executable_single_args}"
- "${__qt_add_executable_multi_args}"
- ${ARGN})
-
- qt_remove_args(forward_args
- ARGS_TO_REMOVE
- "${name}"
- ${qt_add_test_helper_optional_args}
- ALL_ARGS
- ${qt_add_test_helper_optional_args}
- ${__qt_add_executable_optional_args}
- ${__qt_add_executable_single_args}
- ${__qt_add_executable_multi_args}
- ARGS
- ${ARGV}
- )
-
- set(extra_args_to_pass)
- if(NOT arg_OVERRIDE_OUTPUT_DIRECTORY)
- set(extra_args_to_pass OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/..")
- endif()
-
- qt_add_executable("${name}" NO_INSTALL ${extra_args_to_pass} ${forward_args})
-endfunction()
-
-# Sets QT_WILL_BUILD_TOOLS if tools will be built.
-function(qt_check_if_tools_will_be_built)
- if(QT_FORCE_FIND_TOOLS OR (CMAKE_CROSSCOMPILING AND NOT QT_BUILD_TOOLS_WHEN_CROSSCOMPILING))
- set(will_build_tools FALSE)
- else()
- set(will_build_tools TRUE)
- endif()
- set(QT_WILL_BUILD_TOOLS ${will_build_tools} CACHE INTERNAL "Are tools going to be built" FORCE)
-endfunction()
-
-# Wrapper function to create a regular cmake target and forward all the
-# arguments collected by the conversion script. This is only meant for tests!
-function(qt_add_cmake_library target)
- # Process arguments:
- qt_parse_all_arguments(arg "qt_add_cmake_library"
- "SHARED;MODULE;STATIC;INTERFACE"
- "OUTPUT_DIRECTORY;ARCHIVE_INSTALL_DIRECTORY;INSTALL_DIRECTORY"
- "${__default_private_args};${__default_public_args}"
- ${ARGN}
- )
-
- ### Define Targets:
- if(${arg_INTERFACE})
- add_library("${target}" INTERFACE)
- elseif(${arg_STATIC} OR (${arg_MODULE} AND NOT BUILD_SHARED_LIBS))
- add_library("${target}" STATIC)
- elseif(${arg_SHARED})
- add_library("${target}" SHARED)
- qt_internal_apply_win_prefix_and_suffix("${target}")
- elseif(${arg_MODULE})
- add_library("${target}" MODULE)
- set_property(TARGET ${name} PROPERTY C_VISIBILITY_PRESET default)
- set_property(TARGET ${name} PROPERTY CXX_VISIBILITY_PRESET default)
- set_property(TARGET ${name} PROPERTY OBJC_VISIBILITY_PRESET default)
- set_property(TARGET ${name} PROPERTY OBJCXX_VISIBILITY_PRESET default)
-
- if(APPLE)
- # CMake defaults to using .so extensions for loadable modules, aka plugins,
- # but Qt plugins are actually suffixed with .dylib.
- set_property(TARGET "${target}" PROPERTY SUFFIX ".dylib")
- endif()
- qt_internal_apply_win_prefix_and_suffix("${target}")
- else()
- add_library("${target}")
- endif()
-
- if (NOT arg_ARCHIVE_INSTALL_DIRECTORY AND arg_INSTALL_DIRECTORY)
- set(arg_ARCHIVE_INSTALL_DIRECTORY "${arg_INSTALL_DIRECTORY}")
- endif()
-
- if (ANDROID)
- qt_android_apply_arch_suffix("${target}")
- endif()
- qt_skip_warnings_are_errors_when_repo_unclean("${target}")
-
- if (arg_INSTALL_DIRECTORY)
- set(install_arguments
- ARCHIVE_INSTALL_DIRECTORY ${arg_ARCHIVE_INSTALL_DIRECTORY}
- INSTALL_DIRECTORY ${arg_INSTALL_DIRECTORY}
- )
- endif()
-
- if (arg_OUTPUT_DIRECTORY)
- set_target_properties(${target} PROPERTIES
- ARCHIVE_OUTPUT_DIRECTORY ${arg_OUTPUT_DIRECTORY}
- RUNTIME_OUTPUT_DIRECTORY ${arg_OUTPUT_DIRECTORY}
- LIBRARY_OUTPUT_DIRECTORY ${arg_OUTPUT_DIRECTORY}
- )
- endif()
-
- qt_extend_target("${target}"
- SOURCES ${arg_SOURCES}
- INCLUDE_DIRECTORIES
- ${arg_INCLUDE_DIRECTORIES}
- PUBLIC_INCLUDE_DIRECTORIES
- ${arg_PUBLIC_INCLUDE_DIRECTORIES}
- PUBLIC_DEFINES
- ${arg_PUBLIC_DEFINES}
- DEFINES
- ${arg_DEFINES}
- PUBLIC_LIBRARIES ${arg_PUBLIC_LIBRARIES}
- LIBRARIES ${arg_LIBRARIES} Qt::PlatformCommonInternal
- COMPILE_OPTIONS ${arg_COMPILE_OPTIONS}
- PUBLIC_COMPILE_OPTIONS ${arg_PUBLIC_COMPILE_OPTIONS}
- LINK_OPTIONS ${arg_LINK_OPTIONS}
- PUBLIC_LINK_OPTIONS ${arg_PUBLIC_LINK_OPTIONS}
- MOC_OPTIONS ${arg_MOC_OPTIONS}
- ENABLE_AUTOGEN_TOOLS ${arg_ENABLE_AUTOGEN_TOOLS}
- DISABLE_AUTOGEN_TOOLS ${arg_DISABLE_AUTOGEN_TOOLS}
- ${install_arguments}
- )
-
-endfunction()
-
-#
-# This function replaces qmake's qt_helper_lib feature. It is intended to
-# compile 3rdparty libraries as part of the build.
-#
-function(qt_add_3rdparty_library target)
- # Process arguments:
- qt_parse_all_arguments(arg "qt_add_3rdparty_library"
- "SHARED;MODULE;STATIC;INTERFACE;EXCEPTIONS;INSTALL;SKIP_AUTOMOC"
- "OUTPUT_DIRECTORY;QMAKE_LIB_NAME"
- "${__default_private_args};${__default_public_args}"
- ${ARGN}
- )
-
- ### Define Targets:
- if(${arg_INTERFACE})
- add_library("${target}" INTERFACE)
- elseif(${arg_STATIC} OR (${arg_MODULE} AND NOT BUILD_SHARED_LIBS))
- add_library("${target}" STATIC)
- elseif(${arg_SHARED})
- add_library("${target}" SHARED)
- elseif(${arg_MODULE})
- add_library("${target}" MODULE)
- set_property(TARGET ${name} PROPERTY C_VISIBILITY_PRESET default)
- set_property(TARGET ${name} PROPERTY CXX_VISIBILITY_PRESET default)
- set_property(TARGET ${name} PROPERTY OBJC_VISIBILITY_PRESET default)
- set_property(TARGET ${name} PROPERTY OBJCXX_VISIBILITY_PRESET default)
-
- if(APPLE)
- # CMake defaults to using .so extensions for loadable modules, aka plugins,
- # but Qt plugins are actually suffixed with .dylib.
- set_property(TARGET "${target}" PROPERTY SUFFIX ".dylib")
- endif()
- else()
- add_library("${target}")
- endif()
-
- if(NOT arg_INTERFACE)
- qt_set_common_target_properties(${target})
- endif()
-
- if (NOT arg_ARCHIVE_INSTALL_DIRECTORY AND arg_INSTALL_DIRECTORY)
- set(arg_ARCHIVE_INSTALL_DIRECTORY "${arg_INSTALL_DIRECTORY}")
- endif()
-
- qt_internal_add_qt_repo_known_module(${target})
- qt_internal_add_target_aliases(${target})
-
- if (ANDROID)
- qt_android_apply_arch_suffix("${target}")
- endif()
-
- qt_skip_warnings_are_errors_when_repo_unclean("${target}")
-
- set_target_properties(${target} PROPERTIES
- LIBRARY_OUTPUT_DIRECTORY "${QT_BUILD_DIR}/${INSTALL_LIBDIR}"
- RUNTIME_OUTPUT_DIRECTORY "${QT_BUILD_DIR}/${INSTALL_BINDIR}"
- ARCHIVE_OUTPUT_DIRECTORY "${QT_BUILD_DIR}/${INSTALL_LIBDIR}"
- VERSION ${PROJECT_VERSION}
- SOVERSION ${PROJECT_VERSION_MAJOR}
- QT_MODULE_IS_3RDPARTY_LIBRARY TRUE
- QT_MODULE_SKIP_DEPENDS_INCLUDE TRUE
- )
- qt_handle_multi_config_output_dirs("${target}")
-
- set_target_properties(${target} PROPERTIES
- OUTPUT_NAME "${INSTALL_CMAKE_NAMESPACE}${target}"
- )
-
- if(NOT arg_SKIP_AUTOMOC)
- qt_autogen_tools_initial_setup(${target})
- endif()
-
- if(NOT arg_INTERFACE)
- # This property is used for super builds with static libraries. We use
- # it in QtPlugins.cmake.in to avoid "polluting" the dependency chain
- # for the target in it's project directory.
- # E.g: When we process find_package(Qt6 ... Gui) in QtDeclarative, the
- # rules in QtPugins.cmake add all the known Gui plugins as interface
- # dependencies. This in turn causes circular dependencies on every
- # plugin which links against Gui. Plugin A -> GUI -> Plugin A ....
- set_target_properties(${target} PROPERTIES QT_BUILD_PROJECT_NAME ${PROJECT_NAME})
- endif()
-
- if(NOT arg_EXCEPTIONS AND NOT arg_INTERFACE)
- qt_internal_set_no_exceptions_flags("${target}")
- endif()
-
- qt_generate_3rdparty_lib_pri_file("${target}" "${arg_QMAKE_LIB_NAME}" pri_file)
- if(pri_file)
- qt_install(FILES "${pri_file}" DESTINATION "${INSTALL_MKSPECSDIR}/modules")
- endif()
-
- qt_extend_target("${target}"
- SOURCES ${arg_SOURCES}
- INCLUDE_DIRECTORIES
- ${arg_INCLUDE_DIRECTORIES}
- PUBLIC_INCLUDE_DIRECTORIES
- ${arg_PUBLIC_INCLUDE_DIRECTORIES}
- PUBLIC_DEFINES
- ${arg_PUBLIC_DEFINES}
- DEFINES
- ${arg_DEFINES}
- PUBLIC_LIBRARIES ${arg_PUBLIC_LIBRARIES}
- LIBRARIES ${arg_LIBRARIES} Qt::PlatformModuleInternal
- COMPILE_OPTIONS ${arg_COMPILE_OPTIONS}
- PUBLIC_COMPILE_OPTIONS ${arg_PUBLIC_COMPILE_OPTIONS}
- LINK_OPTIONS ${arg_LINK_OPTIONS}
- PUBLIC_LINK_OPTIONS ${arg_PUBLIC_LINK_OPTIONS}
- MOC_OPTIONS ${arg_MOC_OPTIONS}
- ENABLE_AUTOGEN_TOOLS ${arg_ENABLE_AUTOGEN_TOOLS}
- DISABLE_AUTOGEN_TOOLS ${arg_DISABLE_AUTOGEN_TOOLS}
- ${install_arguments}
- )
-
- if(NOT BUILD_SHARED_LIBS OR arg_INSTALL)
- set(path_suffix "${INSTALL_CMAKE_NAMESPACE}${target}")
- qt_path_join(config_build_dir ${QT_CONFIG_BUILD_DIR} ${path_suffix})
- qt_path_join(config_install_dir ${QT_CONFIG_INSTALL_DIR} ${path_suffix})
- set(export_name "${INSTALL_CMAKE_NAMESPACE}${target}Targets")
-
- configure_package_config_file(
- "${QT_CMAKE_DIR}/Qt3rdPartyLibraryConfig.cmake.in"
- "${config_build_dir}/${INSTALL_CMAKE_NAMESPACE}${target}Config.cmake"
- INSTALL_DESTINATION "${config_install_dir}"
- )
-
- write_basic_package_version_file(
- "${config_build_dir}/${INSTALL_CMAKE_NAMESPACE}${target}ConfigVersion.cmake"
- VERSION ${PROJECT_VERSION}
- COMPATIBILITY AnyNewerVersion
- )
-
- qt_install(FILES
- "${config_build_dir}/${INSTALL_CMAKE_NAMESPACE}${target}Config.cmake"
- "${config_build_dir}/${INSTALL_CMAKE_NAMESPACE}${target}ConfigVersion.cmake"
- DESTINATION "${config_install_dir}"
- COMPONENT Devel
- )
-
- qt_install(TARGETS ${target}
- EXPORT "${export_name}"
- RUNTIME DESTINATION ${INSTALL_BINDIR}
- LIBRARY DESTINATION ${INSTALL_LIBDIR}
- ARCHIVE DESTINATION ${INSTALL_LIBDIR}
- )
-
- qt_install(EXPORT ${export_name}
- NAMESPACE "${QT_CMAKE_EXPORT_NAMESPACE}::"
- DESTINATION "${config_install_dir}"
- )
-
- qt_internal_export_modern_cmake_config_targets_file(
- TARGETS ${target}
- EXPORT_NAME_PREFIX ${INSTALL_CMAKE_NAMESPACE}${target}
- CONFIG_INSTALL_DIR "${config_install_dir}"
- )
- endif()
-endfunction()
-
-function(qt_install_3rdparty_library_wrap_config_extra_file target)
- if(TARGET "${target}")
- set(use_bundled "ON")
- else()
- set(use_bundled "OFF")
- endif()
-
- set(QT_USE_BUNDLED_${target} "${use_bundled}" CACHE BOOL "" FORCE)
- set(extra_cmake_code "set(QT_USE_BUNDLED_${target} ${use_bundled} CACHE BOOL \"\" FORCE)")
- configure_file(
- "${QT_CMAKE_DIR}/QtFindWrapConfigExtra.cmake.in"
- "${QT_CONFIG_BUILD_DIR}/${INSTALL_CMAKE_NAMESPACE}/FindWrap${target}ConfigExtra.cmake"
- @ONLY
- )
-
- qt_install(FILES
- "${QT_CONFIG_BUILD_DIR}/${INSTALL_CMAKE_NAMESPACE}/FindWrap${target}ConfigExtra.cmake"
- DESTINATION "${QT_CONFIG_INSTALL_DIR}/${INSTALL_CMAKE_NAMESPACE}"
- COMPONENT Devel
- )
-endfunction()
-
-function(qt_get_tool_cmake_configuration out_var)
- qt_get_main_cmake_configuration("${out_var}")
- string(TOUPPER "${${out_var}}" upper_config)
- set("${out_var}" "${upper_config}" PARENT_SCOPE)
-endfunction()
-
-function(qt_get_main_cmake_configuration out_var)
- if(CMAKE_BUILD_TYPE)
- set(config "${CMAKE_BUILD_TYPE}")
- elseif(QT_MULTI_CONFIG_FIRST_CONFIG)
- set(config "${QT_MULTI_CONFIG_FIRST_CONFIG}")
- endif()
- set("${out_var}" "${config}" PARENT_SCOPE)
-endfunction()
-
-# Returns the target name for the tool with the given name.
-#
-# In most cases, the target name is the same as the tool name.
-# If the user specifies to build tools when cross-compiling, then the
-# suffix "_native" is appended.
-function(qt_get_tool_target_name out_var name)
- if (CMAKE_CROSSCOMPILING AND QT_BUILD_TOOLS_WHEN_CROSSCOMPILING)
- set(${out_var} ${name}_native PARENT_SCOPE)
- else()
- set(${out_var} ${name} PARENT_SCOPE)
- endif()
-endfunction()
-
-# Returns the tool name for a given tool target.
-# This is the inverse of qt_get_tool_target_name.
-function(qt_tool_target_to_name out_var target)
- set(name ${target})
- if (CMAKE_CROSSCOMPILING AND QT_BUILD_TOOLS_WHEN_CROSSCOMPILING)
- string(REGEX REPLACE "_native$" "" name ${target})
- endif()
- set(${out_var} ${name} PARENT_SCOPE)
-endfunction()
-
-# This function is used to define a "Qt tool", such as moc, uic or rcc.
-# The BOOTSTRAP option allows building it as standalone program, otherwise
-# it will be linked against QtCore.
-#
-# We must pass this function a target name obtained from
-# qt_get_tool_target_name like this:
-# qt_get_tool_target_name(target_name my_tool)
-# qt_add_tool(${target_name})
-#
-function(qt_add_tool target_name)
- qt_tool_target_to_name(name ${target_name})
- qt_parse_all_arguments(arg "qt_add_tool" "BOOTSTRAP;NO_QT;NO_INSTALL"
- "TOOLS_TARGET;${__default_target_info_args}"
- "${__default_private_args}" ${ARGN})
-
- # Handle case when a tool does not belong to a module and it can't be built either (like
- # during a cross-compile).
- if(NOT arg_TOOLS_TARGET AND NOT QT_WILL_BUILD_TOOLS)
- message(FATAL_ERROR "The tool \"${name}\" has not been assigned to a module via"
- " TOOLS_TARGET (so it can't be found) and it can't be built"
- " (QT_WILL_BUILD_TOOLS is ${QT_WILL_BUILD_TOOLS}).")
- endif()
-
- if(CMAKE_CROSSCOMPILING AND QT_BUILD_TOOLS_WHEN_CROSSCOMPILING AND (name STREQUAL target_name))
- message(FATAL_ERROR
- "qt_add_tool must be passed a target obtained from qt_get_tool_target_name.")
- endif()
-
- set(full_name "${QT_CMAKE_EXPORT_NAMESPACE}::${name}")
- set(imported_tool_target_found FALSE)
- if(TARGET ${full_name})
- get_property(path TARGET ${full_name} PROPERTY LOCATION)
- message(STATUS "Tool '${full_name}' was found at ${path}.")
- set(imported_tool_target_found TRUE)
- if(CMAKE_CROSSCOMPILING AND NOT QT_BUILD_TOOLS_WHEN_CROSSCOMPILING)
- return()
- endif()
- endif()
-
- if(arg_TOOLS_TARGET AND (NOT QT_WILL_BUILD_TOOLS OR QT_BUILD_TOOLS_WHEN_CROSSCOMPILING)
- AND NOT imported_tool_target_found)
- set(tools_package_name "Qt6${arg_TOOLS_TARGET}Tools")
- message(STATUS "Searching for tool '${full_name}' in package ${tools_package_name}.")
-
- # Only search in path provided by QT_HOST_PATH. We need to do it with CMAKE_PREFIX_PATH
- # instead of PATHS option, because any find_dependency call inside a Tools package would
- # not get the proper prefix when using PATHS.
- set(BACKUP_CMAKE_PREFIX_PATH ${CMAKE_PREFIX_PATH})
- set(CMAKE_PREFIX_PATH "${QT_HOST_PATH}")
-
- # Search both with sysroots prepended as well as in the host system. When cross compiling
- # the mode_package might be set to ONLY only, and the Qt6 tools packages are actually
- # in the host system.
- set(BACKUP_CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ${CMAKE_FIND_ROOT_PATH_MODE_PACKAGE})
- set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE "BOTH")
- set(BACKUP_CMAKE_SIZEOF_VOID_P "${CMAKE_SIZEOF_VOID_P}")
- set(CMAKE_SIZEOF_VOID_P "")
- find_package(
- ${tools_package_name}
- ${PROJECT_VERSION}
- NO_PACKAGE_ROOT_PATH
- NO_CMAKE_ENVIRONMENT_PATH
- NO_SYSTEM_ENVIRONMENT_PATH
- NO_CMAKE_PACKAGE_REGISTRY
- NO_CMAKE_SYSTEM_PATH
- NO_CMAKE_SYSTEM_PACKAGE_REGISTRY)
- set(CMAKE_SIZEOF_VOID_P "${BACKUP_CMAKE_SIZEOF_VOID_P}")
- set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE "${BACKUP_CMAKE_FIND_ROOT_PATH_MODE_PACKAGE}")
- set(CMAKE_PREFIX_PATH "${BACKUP_CMAKE_PREFIX_PATH}")
-
- if(${${tools_package_name}_FOUND} AND TARGET ${full_name})
- # Even if the tool is already visible, make sure that our modules remain associated
- # with the tools.
- qt_internal_append_known_modules_with_tools("${arg_TOOLS_TARGET}")
- get_property(path TARGET ${full_name} PROPERTY LOCATION)
- message(STATUS "${full_name} was found at ${path} using package ${tools_package_name}.")
- if (NOT QT_BUILD_TOOLS_WHEN_CROSSCOMPILING)
- return()
- endif()
- endif()
- endif()
-
- if(NOT QT_WILL_BUILD_TOOLS)
- message(FATAL_ERROR "The tool \"${full_name}\" was not found in the "
- "${tools_package_name} package. "
- "Package found: ${${tools_package_name}_FOUND}")
- else()
- if(QT_BUILD_TOOLS_WHEN_CROSSCOMPILING)
- message(STATUS "Tool '${target_name}' will be cross-built from source.")
- else()
- message(STATUS "Tool '${full_name}' will be built from source.")
- endif()
- endif()
-
- set(disable_autogen_tools "${arg_DISABLE_AUTOGEN_TOOLS}")
- if (arg_NO_QT)
- # FIXME: Remove NO_QT again once qmake can use a "normal" Qt!
- if (arg_BOOTSTRAP)
- message(FATAL_ERROR "Tool can not be NO_QT and BOOTSTRAP at the same time!")
- endif()
- set(corelib "")
- else()
- if (arg_BOOTSTRAP)
- set(corelib ${QT_CMAKE_EXPORT_NAMESPACE}::Bootstrap)
- list(APPEND disable_autogen_tools "uic" "moc" "rcc")
- else()
- set(corelib ${QT_CMAKE_EXPORT_NAMESPACE}::Core)
- endif()
- endif()
-
- set(bootstrap "")
- if(arg_BOOTSTRAP)
- set(bootstrap BOOTSTRAP)
- endif()
-
- set(no_qt "")
- if(arg_NO_QT)
- set(no_qt NO_QT)
- endif()
-
- qt_add_executable("${target_name}" OUTPUT_DIRECTORY "${QT_BUILD_DIR}/${INSTALL_BINDIR}"
- ${bootstrap}
- ${no_qt}
- NO_INSTALL
- SOURCES ${arg_SOURCES}
- INCLUDE_DIRECTORIES
- ${arg_INCLUDE_DIRECTORIES}
- DEFINES
- QT_USE_QSTRINGBUILDER
- ${arg_DEFINES}
- PUBLIC_LIBRARIES ${corelib}
- LIBRARIES ${arg_LIBRARIES} Qt::PlatformToolInternal
- COMPILE_OPTIONS ${arg_COMPILE_OPTIONS}
- LINK_OPTIONS ${arg_LINK_OPTIONS}
- MOC_OPTIONS ${arg_MOC_OPTIONS}
- DISABLE_AUTOGEN_TOOLS ${disable_autogen_tools}
- TARGET_VERSION "${arg_TARGET_VERSION}"
- TARGET_PRODUCT "${arg_TARGET_PRODUCT}"
- TARGET_DESCRIPTION "${arg_TARGET_DESCRIPTION}"
- TARGET_COMPANY "${arg_TARGET_COMPANY}"
- TARGET_COPYRIGHT "${arg_TARGET_COPYRIGHT}"
- )
- qt_internal_add_target_aliases("${target_name}")
-
- if (NOT target_name STREQUAL name)
- set_target_properties(${target_name} PROPERTIES
- OUTPUT_NAME ${name}
- EXPORT_NAME ${name}
- )
- endif()
-
- if(TARGET host_tools)
- add_dependencies(host_tools "${target_name}")
- if(bootstrap OR no_qt)
- add_dependencies(bootstrap_tools "${target_name}")
- endif()
- endif()
-
- # If building with a multi-config configuration, the main configuration tool will be placed in
- # ./bin, while the rest will be in <CONFIG> specific subdirectories.
- qt_get_tool_cmake_configuration(tool_cmake_configuration)
- set_target_properties("${target_name}" PROPERTIES
- RUNTIME_OUTPUT_DIRECTORY_${tool_cmake_configuration} "${QT_BUILD_DIR}/${INSTALL_BINDIR}"
- )
-
- if(NOT arg_NO_INSTALL AND arg_TOOLS_TARGET)
- # Assign a tool to an export set, and mark the module to which the tool belongs.
- qt_internal_append_known_modules_with_tools("${arg_TOOLS_TARGET}")
-
- # Also append the tool to the module list.
- qt_internal_append_known_module_tool("${arg_TOOLS_TARGET}" "${target_name}")
-
- qt_get_cmake_configurations(cmake_configs)
-
- set(install_initial_call_args
- EXPORT "${INSTALL_CMAKE_NAMESPACE}${arg_TOOLS_TARGET}ToolsTargets")
-
- foreach(cmake_config ${cmake_configs})
- qt_get_install_target_default_args(
- OUT_VAR install_targets_default_args
- CMAKE_CONFIG "${cmake_config}"
- ALL_CMAKE_CONFIGS "${cmake_configs}")
- qt_install(TARGETS "${target_name}"
- ${install_initial_call_args}
- CONFIGURATIONS ${cmake_config}
- ${install_targets_default_args})
- unset(install_initial_call_args)
- endforeach()
-
- qt_apply_rpaths(TARGET "${target_name}" INSTALL_PATH "${INSTALL_BINDIR}" RELATIVE_RPATH)
-
- endif()
-
- if(QT_FEATURE_separate_debug_info AND (UNIX OR MINGW))
- qt_enable_separate_debug_info(${target_name} ${INSTALL_BINDIR})
- endif()
-endfunction()
-
-function(qt_create_tracepoints name tracePointsFile)
- #### TODO
- string(TOLOWER "${name}" name)
-
- file(GENERATE OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/qt${name}_tracepoints_p.h" CONTENT
- "#include <private/qtrace_p.h>")
-endfunction()
-
-# Handle files that need special SIMD-related flags.
-# This creates an object library and makes target link
-# to it (privately).
-function(qt_add_simd_part target)
- qt_parse_all_arguments(arg "qt_add_simd_part" "" ""
- "NAME;SIMD;${__default_private_args};COMPILE_FLAGS" ${ARGN})
- if ("x${arg_SIMD}" STREQUAL x)
- message(FATAL_ERROR "qt_add_simd_part needs a SIMD type to be set.")
- endif()
-
- set(condition "QT_FEATURE_${arg_SIMD}")
- string(TOUPPER "QT_CFLAGS_${arg_SIMD}" simd_flags_var_name)
- set(simd_flags_expanded "")
-
- # As per mkspecs/features/simd.prf, the arch_haswell SIMD compiler is enabled when
- # qmake's CONFIG contains "avx2", which maps to CMake's QT_FEATURE_avx2.
- # The list of dependencies 'avx2 bmi bmi2 f16c fma lzcnt popcnt' only influences whether
- # the 'arch_haswell' SIMD flags need to be added explicitly to the compiler invocation.
- # If the compiler adds them implicitly, they must be present in qmake's QT_CPU_FEATURES as
- # detected by the architecture test, and thus they are present in TEST_subarch_result.
- if("${arg_SIMD}" STREQUAL arch_haswell)
- set(condition "QT_FEATURE_avx2")
-
- # Use avx2 flags as per simd.prf, if there are no specific arch_haswell flags specified in
- # QtCompilerOptimization.cmake.
- if("${simd_flags_var_name}" STREQUAL "")
- set(simd_flags_var_name "QT_CFLAGS_AVX2")
- endif()
-
- # The avx512 profiles dependencies DO influence if the SIMD compiler will be executed,
- # so each of the profile dependencies have to be in qmake's CONFIG for the compiler to be
- # enabled, which means the CMake features have to evaluate to true.
- # Also the profile flags to be used are a combination of arch_haswell, avx512f and each of the
- # dependencies.
- elseif("${arg_SIMD}" STREQUAL avx512common)
- set(condition "QT_FEATURE_avx512cd")
- list(APPEND simd_flags_expanded "${QT_CFLAGS_ARCH_HASWELL}")
- list(APPEND simd_flags_expanded "${QT_CFLAGS_AVX512F}")
- list(APPEND simd_flags_expanded "${QT_CFLAGS_AVX512CD}")
- list(REMOVE_DUPLICATES simd_flags_expanded)
- elseif("${arg_SIMD}" STREQUAL avx512core)
- set(condition "QT_FEATURE_avx512cd AND QT_FEATURE_avx512bw AND QT_FEATURE_avx512dq AND QT_FEATURE_avx512vl")
- list(APPEND simd_flags_expanded "${QT_CFLAGS_ARCH_HASWELL}")
- list(APPEND simd_flags_expanded "${QT_CFLAGS_AVX512F}")
- list(APPEND simd_flags_expanded "${QT_CFLAGS_AVX512CD}")
- list(APPEND simd_flags_expanded "${QT_CFLAGS_AVX512BW}")
- list(APPEND simd_flags_expanded "${QT_CFLAGS_AVX512DQ}")
- list(APPEND simd_flags_expanded "${QT_CFLAGS_AVX512VL}")
- list(REMOVE_DUPLICATES simd_flags_expanded)
- endif()
-
- set(name "${arg_NAME}")
- if("x${name}" STREQUAL x)
- set(name "${target}_simd_${arg_SIMD}")
- endif()
-
- qt_evaluate_config_expression(result ${condition})
- if(${result})
- if(QT_CMAKE_DEBUG_EXTEND_TARGET)
- message("qt_add_simd_part(${target} SIMD ${arg_SIMD} ...): Evaluated")
- endif()
-
- if(NOT simd_flags_expanded)
- set(simd_flags_expanded "${${simd_flags_var_name}}")
- endif()
-
- foreach(source IN LISTS arg_SOURCES)
- set_property(SOURCE "${source}" APPEND
- PROPERTY COMPILE_OPTIONS
- ${simd_flags_expanded}
- ${arg_COMPILE_FLAGS}
- )
- endforeach()
- set_source_files_properties(${arg_SOURCES} PROPERTIES SKIP_PRECOMPILE_HEADERS TRUE)
- target_sources(${target} PRIVATE ${arg_SOURCES})
- else()
- if(QT_CMAKE_DEBUG_EXTEND_TARGET)
- message("qt_add_simd_part(${target} SIMD ${arg_SIMD} ...): Skipped")
- endif()
- endif()
-endfunction()
-
-# From Qt6CoreMacros
-# Function used to create the names of output files preserving relative dirs
-function(qt_make_output_file infile prefix suffix source_dir binary_dir result)
- get_filename_component(outfilename "${infile}" NAME_WE)
-
- set(base_dir "${source_dir}")
- string(FIND "${infile}" "${binary_dir}/" in_binary)
- if (in_binary EQUAL 0)
- set(base_dir "${binary_dir}")
- endif()
-
- get_filename_component(abs_infile "${infile}" ABSOLUTE BASE_DIR "${base_dir}")
- file(RELATIVE_PATH rel_infile "${base_dir}" "${abs_infile}")
- string(REPLACE "../" "__/" mapped_infile "${rel_infile}")
-
- get_filename_component(abs_mapped_infile "${mapped_infile}" ABSOLUTE BASE_DIR "${binary_dir}")
- get_filename_component(outpath "${abs_mapped_infile}" PATH)
-
- file(MAKE_DIRECTORY "${outpath}")
- set("${result}" "${outpath}/${prefix}${outfilename}${suffix}" PARENT_SCOPE)
-endfunction()
-
-
-# Complete manual moc invocation with full control.
-# Use AUTOMOC whenever possible.
-function(qt_manual_moc result)
- cmake_parse_arguments(arg "" "OUTPUT_MOC_JSON_FILES" "FLAGS" ${ARGN})
- set(moc_files)
- set(metatypes_json_list)
- foreach(infile ${arg_UNPARSED_ARGUMENTS})
- qt_make_output_file("${infile}" "moc_" ".cpp"
- "${CMAKE_CURRENT_SOURCE_DIR}" "${CMAKE_CURRENT_BINARY_DIR}" outfile)
- list(APPEND moc_files "${outfile}")
-
- set(moc_parameters_file "${outfile}_parameters$<$<BOOL:$<CONFIGURATION>>:_$<CONFIGURATION>>")
- set(moc_parameters ${arg_FLAGS} -o "${outfile}" "${infile}")
-
- set(metatypes_byproducts)
- if (arg_OUTPUT_MOC_JSON_FILES)
- set(moc_json_file "${outfile}.json")
- list(APPEND moc_parameters --output-json)
- list(APPEND metatypes_json_list "${outfile}.json")
- set(metatypes_byproducts "${outfile}.json")
- endif()
-
- string (REPLACE ";" "\n" moc_parameters "${moc_parameters}")
-
- file(GENERATE OUTPUT "${moc_parameters_file}" CONTENT "${moc_parameters}\n")
-
- add_custom_command(OUTPUT "${outfile}" ${metatypes_byproducts}
- COMMAND ${QT_CMAKE_EXPORT_NAMESPACE}::moc "@${moc_parameters_file}"
- DEPENDS "${infile}" ${moc_depends} ${QT_CMAKE_EXPORT_NAMESPACE}::moc
- WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" VERBATIM)
- endforeach()
- set("${result}" ${moc_files} PARENT_SCOPE)
-
- # Register generated json files
- if (arg_OUTPUT_MOC_JSON_FILES)
- set(${arg_OUTPUT_MOC_JSON_FILES} "${metatypes_json_list}" PARENT_SCOPE)
- endif()
-endfunction()
-
-
-# helper to set up a qdbusxml2cpp rule
-function(qt_create_qdbusxml2cpp_command target infile)
- qt_parse_all_arguments(arg "qt_create_qdbusxml2cpp_command" "ADAPTOR;INTERFACE" "BASENAME" "FLAGS" ${ARGN})
- if((arg_ADAPTOR AND arg_INTERFACE) OR (NOT arg_ADAPTOR AND NOT arg_INTERFACE))
- message(FATAL_ERROR "qt_create_dbusxml2cpp_command needs either ADAPTOR or INTERFACE.")
- endif()
-
- set(option "-a")
- set(type "adaptor")
- if (arg_INTERFACE)
- set(option "-p")
- set(type "interface")
- endif()
-
- if ("${arg_BASENAME}" STREQUAL "")
- get_filename_component(file_dir "${infile}" DIRECTORY)
- get_filename_component(file_name "${infile}" NAME_WLE)
- get_filename_component(file_ext "${infile}" LAST_EXT)
-
- if("${file_ext}" STREQUAL ".xml")
- else()
- message(FATAL_ERROR "DBUS ${type} input file is not xml.")
- endif()
-
- # use last part of io.qt.something.xml!
- get_filename_component(file_ext "${file_name}" LAST_EXT)
- if("x${file_ext}" STREQUAL "x")
- else()
- string(SUBSTRING "${file_ext}" 1 -1 file_name) # cut of leading '.'
- endif()
-
- string(TOLOWER "${file_name}" file_name)
- set(file_name "${file_name}_${type}")
- else()
- set(file_name ${arg_BASENAME})
- endif()
-
- # Use absolute file path for the source file and set the current working directory to the
- # current binary directory, because setting an absolute path for the header:source combo option
- # does not work. Splitting on ":" breaks inside the dbus tool when running on Windows
- # due to ":" being contained in the drive path (e.g C:\foo.h:C:\foo.cpp).
- get_filename_component(absolute_in_file_path "${infile}" ABSOLUTE)
-
- set(header_file "${file_name}.h")
- set(source_file "${file_name}.cpp")
-
- add_custom_command(OUTPUT "${header_file}" "${source_file}"
- COMMAND ${QT_CMAKE_EXPORT_NAMESPACE}::qdbusxml2cpp ${arg_FLAGS} "${option}"
- "${header_file}:${source_file}" "${absolute_in_file_path}"
- DEPENDS "${absolute_in_file_path}" ${QT_CMAKE_EXPORT_NAMESPACE}::qdbusxml2cpp
- WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}"
- VERBATIM)
-
- target_sources("${target}" PRIVATE "${header_file}" "${source_file}")
-endfunction()
-
-function(qt_compute_injection_forwarding_header target)
- qt_parse_all_arguments(arg "qt_compute_injection_forwarding_header"
- "PRIVATE" "SOURCE;OUT_VAR" "" ${ARGN})
- qt_internal_module_info(module "${target}")
- get_filename_component(file_name "${arg_SOURCE}" NAME)
-
- set(source_absolute_path "${CMAKE_CURRENT_BINARY_DIR}/${arg_SOURCE}")
- file(RELATIVE_PATH relpath "${PROJECT_BINARY_DIR}" "${source_absolute_path}")
-
- if (arg_PRIVATE)
- set(fwd "${PROJECT_VERSION}/${module}/private/${file_name}")
- else()
- set(fwd "${file_name}")
- endif()
-
- string(APPEND ${arg_OUT_VAR} " ${relpath}:${fwd}")
- set(${arg_OUT_VAR} ${${arg_OUT_VAR}} PARENT_SCOPE)
-endfunction()
-
-
-function(qt_add_docs)
- if(${ARGC} EQUAL 1)
- # Function called from old generated CMakeLists.txt that was missing the target parameter
- return()
- endif()
- if(NOT ${ARGC} EQUAL 2)
- message(FATAL_ERROR "qt_add_docs called with the wrong number of arguments. Should be qt_add_docs(target path_to_project.qdocconf).")
- return()
- endif()
- set(target ${ARGV0})
- set(doc_project ${ARGV1})
-
- # If a target is not built (which can happen for tools when crosscompiling, we shouldn't try
- # to generate docs.
- if(NOT TARGET "${target}")
- return()
- endif()
-
- if (NOT QT_SUPERBUILD OR QT_WILL_INSTALL)
- set(qdoc_bin "${QT_BUILD_INTERNALS_RELOCATABLE_INSTALL_PREFIX}/${INSTALL_BINDIR}/qdoc")
- set(qtattributionsscanner_bin "${QT_BUILD_INTERNALS_RELOCATABLE_INSTALL_PREFIX}/${INSTALL_BINDIR}/qtattributionsscanner")
- set(qhelpgenerator_bin "${QT_BUILD_INTERNALS_RELOCATABLE_INSTALL_PREFIX}/${INSTALL_BINDIR}/qhelpgenerator")
- else()
- set(qdoc_bin "${QT_BUILD_INTERNALS_RELOCATABLE_INSTALL_PREFIX}/qtbase/${INSTALL_BINDIR}/qdoc")
- set(qtattributionsscanner_bin "${QT_BUILD_INTERNALS_RELOCATABLE_INSTALL_PREFIX}/qtbase/${INSTALL_BINDIR}/qtattributionsscanner")
- set(qhelpgenerator_bin "${QT_BUILD_INTERNALS_RELOCATABLE_INSTALL_PREFIX}/qtbase/${INSTALL_BINDIR}/qhelpgenerator")
- endif()
-
- get_target_property(target_type ${target} TYPE)
- if (NOT target_type STREQUAL "INTERFACE_LIBRARY")
- get_target_property(target_bin_dir ${target} BINARY_DIR)
- get_target_property(target_source_dir ${target} SOURCE_DIR)
- else()
- set(target_bin_dir ${CMAKE_CURRENT_BINARY_DIR})
- set(target_source_dir ${CMAKE_CURRENT_SOURCE_DIR})
- endif()
- set(doc_ouput_dir "${target_bin_dir}/.doc")
-
-
- # Generate include dir list
- set(target_include_dirs_file "${doc_ouput_dir}/$<CONFIG>/includes.txt")
-
- set(include_paths_property "$<TARGET_PROPERTY:${target},INCLUDE_DIRECTORIES>")
- if (NOT target_type STREQUAL "INTERFACE_LIBRARY")
- file(GENERATE
- OUTPUT ${target_include_dirs_file}
- CONTENT "-I$<JOIN:${include_paths_property},\n-I>"
- )
- set(include_path_args "@${target_include_dirs_file}")
- else()
- set(include_path_args "")
- endif()
-
- get_filename_component(doc_target "${doc_project}" NAME_WLE)
- if (QT_WILL_INSTALL)
- set(qdoc_output_dir "${CMAKE_BINARY_DIR}/${INSTALL_DOCDIR}/${doc_target}")
- set(index_dir "${CMAKE_BINARY_DIR}/${INSTALL_DOCDIR}")
- elseif (QT_SUPERBUILD)
- set(qdoc_output_dir "${QT_BUILD_INTERNALS_RELOCATABLE_INSTALL_PREFIX}/qtbase/${INSTALL_DOCDIR}/${doc_target}")
- set(index_dir "${QT_BUILD_INTERNALS_RELOCATABLE_INSTALL_PREFIX}/qtbase/${INSTALL_DOCDIR}")
- else()
- set(qdoc_output_dir "${QT_BUILD_INTERNALS_RELOCATABLE_INSTALL_PREFIX}/${INSTALL_DOCDIR}/${doc_target}")
- set(index_dir "${QT_BUILD_INTERNALS_RELOCATABLE_INSTALL_PREFIX}/${INSTALL_DOCDIR}")
- endif()
-
- # qtattributionsscanner
- add_custom_target(qattributionsscanner_${target}
- DEPENDS ${qattributionsscanner_bin}
- COMMAND ${qtattributionsscanner_bin}
- ${PROJECT_SOURCE_DIR}
- --filter "QDocModule=${qdoc_target}"
- -o "${target_bin_dir}/codeattributions.qdoc"
- )
-
- # prepare docs target
- set(prepare_qdoc_args
- -outputdir "${qdoc_output_dir}"
- -installdir "${QT_INSTALL_DIR}/${INSTALL_DOCDIR}"
- "${target_source_dir}/${doc_project}"
- -prepare
- -indexdir "${index_dir}"
- -no-link-errors
- "${include_path_args}"
- )
-
- if (QT_WILL_INSTALL)
- set(qt_install_docs_env "${CMAKE_INSTALL_PREFIX}/${INSTALL_DOCDIR}")
- elseif (QT_SUPERBUILD)
- set(qt_install_docs_env "${QT_BUILD_INTERNALS_RELOCATABLE_INSTALL_PREFIX}/qtbase/${INSTALL_DOCDIR}")
- else()
- set(qt_install_docs_env "${QT_BUILD_INTERNALS_RELOCATABLE_INSTALL_PREFIX}/${INSTALL_DOCDIR}")
- endif()
-
- set(qdoc_env_args
- "QT_INSTALL_DOCS=\"${qt_install_docs_env}\""
- "QT_VERSION=${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}"
- "QT_VER=${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}"
- "QT_VERSION_TAG=${PROJECT_VERSION_MAJOR}${PROJECT_VERSION_MINOR}${PROJECT_VERSION_PATCH}"
- "BUILDDIR=${target_bin_dir}"
- )
-
- add_custom_target(prepare_docs_${target}
- DEPENDS ${qdoc_bin}
- COMMAND ${CMAKE_COMMAND} -E env ${qdoc_env_args}
- ${qdoc_bin}
- ${prepare_qdoc_args}
- )
-
- add_dependencies(prepare_docs_${target} qattributionsscanner_${target})
-
- # generate docs target
- set(generate_qdocs_args
- -outputdir "${qdoc_output_dir}"
- -installdir "${INSTALL_DOCDIR}"
- "${target_source_dir}/${doc_project}"
- -generate
- -indexdir "${index_dir}"
- "${include_path_args}"
- )
-
- add_custom_target(generate_docs_${target}
- DEPENDS ${qdoc_bin}
- COMMAND ${CMAKE_COMMAND} -E env ${qdoc_env_args}
- ${qdoc_bin}
- ${generate_qdocs_args}
- )
-
- add_dependencies(generate_docs_${target} prepare_docs_${target})
-
- # generate html
- set(html_qdocs_args
- -outputdir "${qdoc_output_dir}"
- -installdir "${INSTALL_DOCDIR}"
- "${target_source_dir}/${doc_project}"
- -indexdir "${index_dir}"
- "${include_path_args}"
- )
-
- add_custom_target(html_docs_${target}
- DEPENDS ${qdoc_bin}
- COMMAND ${CMAKE_COMMAND} -E env ${qdoc_env_args}
- ${qdoc_bin}
- ${html_qdocs_args}
- )
-
- add_dependencies(html_docs_${target} generate_docs_${target})
-
- # generate .qch
- set(qch_file_name ${doc_target}.qch)
- set(qch_file_path ${qdoc_output_dir}/${qch_file_name})
-
- add_custom_target(qch_docs_${target}
- DEPENDS ${qhelpgenerator_bin}
- COMMAND ${qhelpgenerator_bin}
- "${qdoc_output_dir}/${doc_target}.qhp"
- -o "${qch_file_path}"
- )
- add_dependencies(qch_docs_${target} generate_docs_${target})
-
- if (QT_WILL_INSTALL)
- add_custom_target(install_html_docs_${target}
- COMMAND ${CMAKE_COMMAND} -E copy_directory
- "${qdoc_output_dir}"
- "${CMAKE_INSTALL_PREFIX}/${INSTALL_DOCDIR}/${doc_target}"
- COMMENT "Installing html docs for target ${target}"
- )
-
- add_custom_target(install_qch_docs_${target}
- COMMAND ${CMAKE_COMMAND} -E copy_if_different
- "${qch_file_path}"
- "${CMAKE_INSTALL_PREFIX}/${INSTALL_DOCDIR}/${qch_file_name}"
- COMMENT "Installing qch docs for target ${target}"
- )
- else()
- # Don't need to do anything when not installing
- add_custom_target(install_html_docs_${target})
- add_custom_target(install_qch_docs_${target})
- endif()
-
- add_dependencies(install_html_docs_${target} html_docs_${target})
- add_dependencies(install_qch_docs_${target} qch_docs_${target})
-
- add_custom_target(install_docs_${target})
- add_dependencies(install_docs_${target} install_html_docs_${target} install_qch_docs_${target})
-
- add_custom_target(docs_${target})
- add_dependencies(docs_${target} html_docs_${target})
- add_dependencies(docs_${target} qch_docs_${target})
-
- add_dependencies(${qt_docs_prepare_target_name} prepare_docs_${target})
- add_dependencies(${qt_docs_generate_target_name} generate_docs_${target})
- add_dependencies(${qt_docs_html_target_name} html_docs_${target})
- add_dependencies(${qt_docs_qch_target_name} qch_docs_${target})
- add_dependencies(${qt_docs_target_name} docs_${target})
- add_dependencies(${qt_docs_install_html_target_name} install_html_docs_${target})
- add_dependencies(${qt_docs_install_qch_target_name} install_qch_docs_${target})
- add_dependencies(${qt_docs_install_target_name} install_docs_${target})
-
-endfunction()
-
-# This function recursively walks transitive link libraries of the given target
-# and promotes those targets to be IMPORTED_GLOBAL if they are not.
-#
-# This is required for .prl file generation in top-level builds, to make sure that imported 3rd
-# party library targets in any repo are made global, so there are no scoping issues.
-#
-# Only works if called from qt_find_package(), because the promotion needs to happen in the same
-# directory scope where the imported target is first created.
-#
-# Uses qt_internal_walk_libs.
-function(qt_find_package_promote_targets_to_global_scope target)
- qt_internal_walk_libs("${target}" _discared_out_var
- "qt_find_package_targets_dict" "promote_global")
-endfunction()
-
-macro(qt_find_package)
- # Get the target names we expect to be provided by the package.
- set(options CONFIG NO_MODULE MODULE REQUIRED)
- set(oneValueArgs MODULE_NAME QMAKE_LIB)
- set(multiValueArgs PROVIDED_TARGETS COMPONENTS)
- cmake_parse_arguments(arg "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
-
- # If some Qt internal project calls qt_find_package(WrapFreeType), but WrapFreeType was already
- # found as part of a find_dependency() call from a ModuleDependencies.cmake file (or similar),
- # and the provided target is also found, that means this might have been an unnecessary
- # qt_find_package() call, because the dependency was already found via some other transitive
- # dependency. Return early, so that CMake doesn't fail wiht an error with trying to promote the
- # targets to be global. This behavior is not enabled by default, because there are cases
- # when a regular find_package() (non qt_) can find a package (Freetype -> PNG), and a subsequent
- # qt_find_package(PNG PROVIDED_TARGET PNG::PNG) still needs to succeed and register the provided
- # targets. To enable the debugging behavior, set QT_DEBUG_QT_FIND_PACKAGE to 1.
- set(_qt_find_package_skip_find_package FALSE)
- if(QT_DEBUG_QT_FIND_PACKAGE AND ${ARGV0}_FOUND AND arg_PROVIDED_TARGETS)
- set(_qt_find_package_skip_find_package TRUE)
- foreach(qt_find_package_target_name ${arg_PROVIDED_TARGETS})
- if(NOT TARGET ${qt_find_package_target_name})
- set(_qt_find_package_skip_find_package FALSE)
- endif()
- endforeach()
-
- if(_qt_find_package_skip_find_package)
- message(AUTHOR_WARNING "qt_find_package(${ARGV0}) called even though the package "
- "was already found. Consider removing the call.")
- endif()
- endif()
-
- # Get the version if specified.
- set(package_version "")
- if(${ARGC} GREATER_EQUAL 2)
- if(${ARGV1} MATCHES "^[0-9\.]+$")
- set(package_version "${ARGV1}")
- endif()
- endif()
-
- if(arg_COMPONENTS)
- # Re-append components to forward them.
- list(APPEND arg_UNPARSED_ARGUMENTS "COMPONENTS;${arg_COMPONENTS}")
- endif()
-
- # Don't look for packages in PATH if requested to.
- if(QT_NO_USE_FIND_PACKAGE_SYSTEM_ENVIRONMENT_PATH)
- set(_qt_find_package_use_system_env_backup "${CMAKE_FIND_USE_SYSTEM_ENVIRONMENT_PATH}")
- set(CMAKE_FIND_USE_SYSTEM_ENVIRONMENT_PATH "OFF")
- endif()
-
- if(NOT (arg_CONFIG OR arg_NO_MODULE OR arg_MODULE) AND NOT _qt_find_package_skip_find_package)
- # Try to find a config package first in quiet mode
- set(config_package_arg ${arg_UNPARSED_ARGUMENTS})
- list(APPEND config_package_arg "CONFIG;QUIET")
- find_package(${config_package_arg})
-
- # Double check that in config mode the targets become visible. Sometimes
- # only the module mode creates the targets. For example with vcpkg, the sqlite
- # package provides sqlite3-config.cmake, which offers multi-config targets but
- # in their own way. CMake has FindSQLite3.cmake and with the original
- # qt_find_package(SQLite3) call it is our intention to use the cmake package
- # in module mode.
- if (${ARGV0}_FOUND AND arg_PROVIDED_TARGETS)
- unset(any_target_found)
- foreach(expected_target ${arg_PROVIDED_TARGETS})
- if (TARGET ${expected_target})
- set(any_target_found TRUE)
- break()
- endif()
- endforeach()
- if(NOT any_target_found)
- unset(${ARGV0}_FOUND)
- endif()
- endif()
- endif()
-
- # Ensure the options are back in the original unparsed arguments
- foreach(opt IN LISTS options)
- if(arg_${opt})
- list(APPEND arg_UNPARSED_ARGUMENTS ${opt})
- endif()
- endforeach()
-
- if (NOT ${ARGV0}_FOUND AND NOT _qt_find_package_skip_find_package)
- # Unset the NOTFOUND ${package}_DIR var that might have been set by the previous
- # find_package call, to get rid of "not found" messagees in the feature summary
- # if the package is found by the next find_package call.
- if(DEFINED CACHE{${ARGV0}_DIR} AND NOT ${ARGV0}_DIR)
- unset(${ARGV0}_DIR CACHE)
- endif()
-
- # Call original function without our custom arguments.
- find_package(${arg_UNPARSED_ARGUMENTS})
- endif()
-
- if(QT_NO_USE_FIND_PACKAGE_SYSTEM_ENVIRONMENT_PATH)
- if("${_qt_find_package_use_system_env_backup}" STREQUAL "")
- unset(CMAKE_FIND_USE_SYSTEM_ENVIRONMENT_PATH)
- else()
- set(CMAKE_FIND_USE_SYSTEM_ENVIRONMENT_PATH "${_qt_find_package_use_system_env_backup}")
- endif()
- endif()
-
- if(${ARGV0}_FOUND AND arg_PROVIDED_TARGETS AND NOT _qt_find_package_skip_find_package)
- # If package was found, associate each target with its package name. This will be used
- # later when creating Config files for Qt libraries, to generate correct find_dependency()
- # calls. Also make the provided targets global, so that the properties can be read in
- # all scopes.
- foreach(qt_find_package_target_name ${arg_PROVIDED_TARGETS})
- if(TARGET ${qt_find_package_target_name})
- # Allow usage of aliased targets by setting properties on the actual target
- get_target_property(aliased_target ${qt_find_package_target_name} ALIASED_TARGET)
- if(aliased_target)
- set(qt_find_package_target_name ${aliased_target})
- endif()
-
- set_target_properties(${qt_find_package_target_name}
- PROPERTIES INTERFACE_QT_PACKAGE_NAME ${ARGV0})
- if(package_version)
- set_target_properties(${qt_find_package_target_name}
- PROPERTIES INTERFACE_QT_PACKAGE_VERSION ${ARGV1})
- endif()
-
- if(arg_COMPONENTS)
- string(REPLACE ";" " " components_as_string "${arg_COMPONENTS}")
- set_property(TARGET ${qt_find_package_target_name}
- PROPERTY INTERFACE_QT_PACKAGE_COMPONENTS ${components_as_string})
- endif()
-
- get_property(is_global TARGET ${qt_find_package_target_name} PROPERTY
- IMPORTED_GLOBAL)
- if(NOT is_global)
- set_property(TARGET ${qt_find_package_target_name} PROPERTY
- IMPORTED_GLOBAL TRUE)
- qt_find_package_promote_targets_to_global_scope(
- "${qt_find_package_target_name}")
- endif()
- endif()
-
- endforeach()
-
- if(arg_MODULE_NAME AND arg_QMAKE_LIB
- AND (NOT arg_QMAKE_LIB IN_LIST QT_QMAKE_LIBS_FOR_${arg_MODULE_NAME}))
- set(QT_QMAKE_LIBS_FOR_${arg_MODULE_NAME}
- ${QT_QMAKE_LIBS_FOR_${arg_MODULE_NAME}};${arg_QMAKE_LIB} CACHE INTERNAL "")
- set(QT_QMAKE_LIB_TARGETS_${arg_QMAKE_LIB} ${arg_PROVIDED_TARGETS} CACHE INTERNAL "")
- endif()
- endif()
-endmacro()
-
-macro(qt_add_qmake_lib_dependency lib dep)
- string(REPLACE "-" "_" dep ${dep})
- string(TOUPPER "${dep}" ucdep)
- list(APPEND QT_QMAKE_LIB_DEPS_${lib} ${ucdep})
-endmacro()
-
-macro(qt_find_apple_system_frameworks)
- if(APPLE)
- find_library(FWAppKit AppKit)
- find_library(FWAssetsLibrary AssetsLibrary)
- find_library(FWAudioToolbox AudioToolbox)
- find_library(FWApplicationServices ApplicationServices)
- find_library(FWCarbon Carbon)
- find_library(FWCoreFoundation CoreFoundation)
- find_library(FWCoreServices CoreServices)
- find_library(FWCoreGraphics CoreGraphics)
- find_library(FWCoreText CoreText)
- find_library(FWCoreVideo CoreVideo)
- find_library(FWcups cups)
- find_library(FWDiskArbitration DiskArbitration)
- find_library(FWFoundation Foundation)
- find_library(FWIOBluetooth IOBluetooth)
- find_library(FWIOKit IOKit)
- find_library(FWIOSurface IOSurface)
- find_library(FWImageIO ImageIO)
- find_library(FWMetal Metal)
- find_library(FWMobileCoreServices MobileCoreServices)
- find_library(FWQuartzCore QuartzCore)
- find_library(FWSecurity Security)
- find_library(FWSystemConfiguration SystemConfiguration)
- find_library(FWUIKit UIKit)
- find_library(FWWatchKit WatchKit)
- find_library(FWGameController GameController)
- endif()
-endmacro()
-
-# Match the pattern 'regex' in 'input_line', replace the match with 'replacement'
-# and set that result in 'out_var' in the parent scope.
-function(qt_regex_match_and_get input_line regex replacement out_var)
- string(REGEX MATCH "${regex}" match "${input_line}")
- if(match)
- string(REGEX REPLACE "${regex}" "${replacement}" match "${input_line}")
- string(STRIP ${match} match)
- set(${out_var} "${match}" PARENT_SCOPE)
- endif()
-endfunction()
-
-# Match 'regex' in a list of lines. When found, set the value to 'out_var' and break early.
-function(qt_qlalr_find_option_in_list input_list regex out_var)
- foreach(line ${input_list})
- qt_regex_match_and_get("${line}" "${regex}" "\\1" option)
- if(option)
- string(TOLOWER ${option} option)
- set(${out_var} "${option}" PARENT_SCOPE)
- return()
- endif()
- endforeach()
- message(FATAL_ERROR "qt_qlalr_find_option_in_list: Could not extract ${out_var}")
-endfunction()
-
-# Generate a few output files using qlalr, and assign those to 'consuming_target'.
-# 'input_file_list' is a list of 'foo.g' file paths.
-# 'flags' are extra flags to be passed to qlalr.
-function(qt_process_qlalr consuming_target input_file_list flags)
- # Don't try to extend_target when cross compiling an imported host target (like a tool).
- qt_is_imported_target("${consuming_target}" is_imported)
- if(is_imported)
- return()
- endif()
-
- foreach(input_file ${input_file_list})
- file(STRINGS ${input_file} input_file_lines)
- qt_qlalr_find_option_in_list("${input_file_lines}" "^%parser(.+)" "parser")
- qt_qlalr_find_option_in_list("${input_file_lines}" "^%decl(.+)" "decl")
- qt_qlalr_find_option_in_list("${input_file_lines}" "^%impl(.+)" "impl")
- get_filename_component(base_file_name ${input_file} NAME_WE)
-
- set(cpp_file "${parser}.cpp")
- set(private_file "${parser}_p.h")
- set(decl_file "${decl}")
- set(impl_file "${impl}")
- add_custom_command(
- OUTPUT ${cpp_file} ${private_file} ${decl_file} ${impl_file}
- COMMAND ${QT_CMAKE_EXPORT_NAMESPACE}::qlalr ${flags} ${input_file}
- DEPENDS ${QT_CMAKE_EXPORT_NAMESPACE}::qlalr
- MAIN_DEPENDENCY ${input_file}
- )
- target_sources(${consuming_target} PRIVATE ${cpp_file} ${impl_file})
- endforeach()
-endfunction()
-
-
-# qt_configure_file(OUTPUT output-file <INPUT input-file | CONTENT content>)
-# input-file is relative to ${CMAKE_CURRENT_SOURCE_DIR}
-# output-file is relative to ${CMAKE_CURRENT_BINARY_DIR}
-#
-# This function is similar to file(GENERATE OUTPUT) except it writes the content
-# to the file at configure time, rather than at generate time. Once CMake 3.18 is released, it can use file(CONFIGURE) in its implmenetation. Until then, it
-# uses configure_file() with a generic input file as source, when used with the CONTENT signature.
-function(qt_configure_file)
- qt_parse_all_arguments(arg "qt_configure_file" "" "OUTPUT;INPUT;CONTENT" "" ${ARGN})
-
- if(NOT arg_OUTPUT)
- message(FATAL_ERROR "No output file provided to qt_configure_file.")
- endif()
-
- if(arg_CONTENT)
- set(template_name "QtFileConfigure.txt.in")
- # When building qtbase, use the source template file.
- # Otherwise use the installed file.
- # This should work for non-prefix and superbuilds as well.
- if(QtBase_SOURCE_DIR)
- set(input_file "${QtBase_SOURCE_DIR}/cmake/${template_name}")
- else()
- set(input_file "${Qt6_DIR}/${template_name}")
- endif()
- set(__qt_file_configure_content "${arg_CONTENT}")
- elseif(arg_INPUT)
- set(input_file "${arg_INPUT}")
- else()
- message(FATAL_ERROR "No input value provided to qt_configure_file.")
- endif()
-
- configure_file("${input_file}" "${arg_OUTPUT}" @ONLY)
-endfunction()
-
-macro(qt_add_string_to_qconfig_cpp str)
- string(LENGTH "${str}" length)
- string(APPEND QT_CONFIG_STRS " \"${str}\\0\"\n")
- string(APPEND QT_CONFIG_STR_OFFSETS " ${QT_CONFIG_STR_OFFSET},\n")
- math(EXPR QT_CONFIG_STR_OFFSET "${QT_CONFIG_STR_OFFSET}+${length}+1")
-endmacro()
-
-function(qt_generate_qconfig_cpp)
- set(QT_CONFIG_STR_OFFSET "0")
- set(QT_CONFIG_STR_OFFSETS "")
- set(QT_CONFIG_STRS "")
-
- # Start first part.
- qt_add_string_to_qconfig_cpp("${INSTALL_DOCDIR}")
- qt_add_string_to_qconfig_cpp("${INSTALL_INCLUDEDIR}")
- qt_add_string_to_qconfig_cpp("${INSTALL_LIBDIR}")
- qt_add_string_to_qconfig_cpp("${INSTALL_LIBEXECDIR}")
- qt_add_string_to_qconfig_cpp("${INSTALL_BINDIR}")
- qt_add_string_to_qconfig_cpp("${INSTALL_PLUGINSDIR}")
- qt_add_string_to_qconfig_cpp("${INSTALL_QMLDIR}")
- qt_add_string_to_qconfig_cpp("${INSTALL_ARCHDATADIR}")
- qt_add_string_to_qconfig_cpp("${INSTALL_DATADIR}")
- qt_add_string_to_qconfig_cpp("${INSTALL_TRANSLATIONSDIR}")
- qt_add_string_to_qconfig_cpp("${INSTALL_EXAMPLESDIR}")
- qt_add_string_to_qconfig_cpp("${INSTALL_TESTSDIR}")
-
- # Save first part.
- set(QT_CONFIG_STR_OFFSETS_FIRST "${QT_CONFIG_STR_OFFSETS}")
- set(QT_CONFIG_STRS_FIRST "${QT_CONFIG_STRS}")
-
- # Start second part.
- set(QT_CONFIG_STR_OFFSETS "")
- set(QT_CONFIG_STRS "")
-
- qt_add_string_to_qconfig_cpp("") # config.input.sysroot
- qt_add_string_to_qconfig_cpp("false") # qmake_sysrootify
- qt_add_string_to_qconfig_cpp("${INSTALL_BINDIR}") # TODO: Host-specific
- qt_add_string_to_qconfig_cpp("${INSTALL_LIBDIR}") # TODO: Host-specific
- qt_add_string_to_qconfig_cpp("${INSTALL_DATADIR}") # TODO: Host-specific
- qt_add_string_to_qconfig_cpp("${QT_QMAKE_TARGET_MKSPEC}")
- qt_add_string_to_qconfig_cpp("${QT_QMAKE_HOST_MKSPEC}")
-
- # Save second part.
- set(QT_CONFIG_STR_OFFSETS_SECOND "${QT_CONFIG_STR_OFFSETS}")
- set(QT_CONFIG_STRS_SECOND "${QT_CONFIG_STRS}")
-
- # Settings path / sysconf dir.
- if(APPLE)
- set(QT_DEFAULT_SYS_CONF_DIR "/Library/Preferences/Qt")
- else()
- set(QT_DEFAULT_SYS_CONF_DIR "etc/xdg")
- endif()
-
- # Compute and set relocation prefixes.
- # TODO: Clean this up, there's a bunch of unrealistic assumptions here.
- # See qtConfOutput_preparePaths in qtbase/configure.pri.
- if(WIN32)
- set(lib_location_absolute_path
- "${QT_BUILD_INTERNALS_RELOCATABLE_INSTALL_PREFIX}/${INSTALL_BINDIR}")
- else()
- set(lib_location_absolute_path
- "${QT_BUILD_INTERNALS_RELOCATABLE_INSTALL_PREFIX}/${INSTALL_LIBDIR}")
- endif()
- file(RELATIVE_PATH from_lib_location_to_prefix
- "${lib_location_absolute_path}" "${QT_BUILD_INTERNALS_RELOCATABLE_INSTALL_PREFIX}")
- set(QT_CONFIGURE_LIBLOCATION_TO_PREFIX_PATH "${from_lib_location_to_prefix}")
-
- # The QT_CONFIGURE_HOSTBINDIR_TO_*PREFIX_PATH defines are exclusively used by qmake to determine
- # the prefix from the location of the qmake executable. In our build of qmake host_prefix is
- # always the same as ext_prefix, and we can just use CMAKE_INSTALL_PREFIX for the calculation of
- # the relative path between <ext_prefix>/bin and <ext_prefix>.
- set(bin_dir_absolute_path "${CMAKE_INSTALL_PREFIX}/${INSTALL_BINDIR}")
- file(RELATIVE_PATH from_bin_dir_to_prefix "${bin_dir_absolute_path}" "${CMAKE_INSTALL_PREFIX}")
- set(QT_CONFIGURE_HOSTBINDIR_TO_HOSTPREFIX_PATH "${from_bin_dir_to_prefix}")
- set(QT_CONFIGURE_HOSTBINDIR_TO_EXTPREFIX_PATH "${from_bin_dir_to_prefix}")
-
- configure_file(global/qconfig.cpp.in global/qconfig.cpp @ONLY)
-endfunction()
-
-function(qt_set_language_standards)
- ## Use the latest standard the compiler supports (same as qt_common.prf)
- if (QT_FEATURE_cxx2a)
- set(CMAKE_CXX_STANDARD 20 PARENT_SCOPE)
- else()
- set(CMAKE_CXX_STANDARD 17 PARENT_SCOPE)
- endif()
-
- if (c_std_11 IN_LIST CMAKE_C_COMPILE_FEATURES)
- set(CMAKE_C_STANDARD 11 PARENT_SCOPE)
- elseif (c_std_99 IN_LIST CMAKE_C_COMPILE_FEATURES)
- set(CMAKE_C_STANDARD 99 PARENT_SCOPE)
- endif()
-endfunction()
-
-function(qt_set_language_standards_interface_compile_features target)
- # Regardless of which C++ standard is used to build Qt itself, require C++17 when building
- # Qt applications using CMake (because the Qt header files use C++17 features).
- set(cpp_feature "cxx_std_17")
- target_compile_features("${target}" INTERFACE ${cpp_feature})
-endfunction()
-
-function(qt_enable_msvc_cplusplus_define target visibility)
- # For MSVC we need to explicitly pass -Zc:__cplusplus to get correct __cplusplus.
- # Check qt_config_compile_test for more info.
- if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC" AND MSVC_VERSION GREATER_EQUAL 1913)
- target_compile_options("${target}" ${visibility} "-Zc:__cplusplus")
- endif()
-endfunction()
-
-function(qt_enable_utf8_sources target)
- set(utf8_flags "")
- if(MSVC)
- list(APPEND utf8_flags "-utf-8")
- elseif(WIN32 AND ICC)
- list(APPEND utf8_flags "-Qoption,cpp,--unicode_source_kind,UTF-8")
- endif()
-
- if(utf8_flags)
- # Allow opting out by specifying the QT_NO_UTF8_SOURCE target property.
- set(genex_condition "$<NOT:$<BOOL:$<TARGET_PROPERTY:QT_NO_UTF8_SOURCE>>>")
- set(utf8_flags "$<${genex_condition}:${utf8_flags}>")
- target_compile_options("${target}" INTERFACE "${utf8_flags}")
- endif()
-endfunction()
-
-# Equivalent of qmake's qtNomakeTools(directory1 directory2).
-# If QT_NO_MAKE_TOOLS is true, then targets within the given directories will be excluded from the
-# default 'all' target, as well as from install phase.
-# The private variable is checked by qt_add_executable.
-function(qt_exclude_tool_directories_from_default_target)
- if(QT_NO_MAKE_TOOLS)
- set(absolute_path_directories "")
- foreach(directory ${ARGV})
- list(APPEND absolute_path_directories "${CMAKE_CURRENT_SOURCE_DIR}/${directory}")
- endforeach()
- set(__qt_exclude_tool_directories "${absolute_path_directories}" PARENT_SCOPE)
- endif()
-endfunction()
-
-function(qt_compute_relative_rpath_base rpath install_location out_var)
- set(install_lib_dir_absolute "${CMAKE_INSTALL_PREFIX}/${INSTALL_LIBDIR}")
- get_filename_component(rpath_absolute "${rpath}"
- ABSOLUTE BASE_DIR "${install_lib_dir_absolute}")
-
- if(NOT IS_ABSOLUTE)
- set(install_location_absolute "${CMAKE_INSTALL_PREFIX}/${install_location}")
- endif()
- # Compute relative rpath from where the target will be installed, to the place where libraries
- # will be placed (INSTALL_LIBDIR).
- file(RELATIVE_PATH rpath_relative "${install_location_absolute}" "${rpath_absolute}")
-
- if("${rpath_relative}" STREQUAL "")
- # file(RELATIVE_PATH) returns an empty string if the given absolute paths are equal
- set(rpath_relative ".")
- endif()
-
- # Prepend $ORIGIN / @loader_path style tokens (qmake's QMAKE_REL_RPATH_BASE), to make the
- # relative rpaths work. qmake does this automatically when generating a project, so it wasn't
- # needed in the .prf files, but for CMake we need to prepend them ourselves.
- if(APPLE)
- set(rpath_rel_base "@loader_path")
- elseif(LINUX)
- set(rpath_rel_base "$ORIGIN")
- else()
- message(WARNING "No known RPATH_REL_BASE for target platform.")
- set(rpath_rel_base "NO_KNOWN_RPATH_REL_BASE")
- endif()
-
- if(rpath_relative STREQUAL ".")
- set(rpath_relative "${rpath_rel_base}")
- else()
- set(rpath_relative "${rpath_rel_base}/${rpath_relative}")
- endif()
-
- set("${out_var}" "${rpath_relative}" PARENT_SCOPE)
-endfunction()
-
-# Applies necessary rpaths to a target upon target installation.
-# No-op when targeting Windows, Android, or non-prefix builds.
-#
-# If no RELATIVE_RPATH option is given, embeds an absolute path rpath to ${INSTALL_LIBDIR}.
-# If RELATIVE_RPATH is given, the INSTALL_PATH value is to compute the relative path from
-# ${INSTALL_LIBDIR} to wherever the target will be installed (the value of INSTALL_PATH).
-# It's the equivalent of qmake's relative_qt_rpath.
-# INSTALL_PATH is used to implement the equivalent of qmake's $$qtRelativeRPathBase().
-#
-# A cache variable QT_DISABLE_RPATH can be set to disable embedding any rpaths when installing.
-function(qt_apply_rpaths)
- # No rpath support for win32 and android. Also no need to apply rpaths when doing a non-prefix
- # build.
- if(NOT QT_WILL_INSTALL OR WIN32 OR ANDROID)
- return()
- endif()
-
- # Rpaths xplicitly disabled (like for uikit), equivalent to qmake's no_qt_rpath.
- if(QT_DISABLE_RPATH)
- return()
- endif()
-
- qt_parse_all_arguments(arg "qt_apply_rpaths" "RELATIVE_RPATH" "TARGET;INSTALL_PATH" "" ${ARGN})
- if(NOT arg_TARGET)
- message(FATAL_ERRO "No target given to qt_apply_rpaths.")
- else()
- set(target "${arg_TARGET}")
- endif()
-
- # If a target is not built (which can happen for tools when crosscompiling, we shouldn't try
- # to apply properties.
- if(NOT TARGET "${target}")
- return()
- endif()
-
- # Protect against interface libraries.
- get_target_property(target_type "${target}" TYPE)
- if (target_type STREQUAL "INTERFACE_LIBRARY")
- return()
- endif()
-
- if(NOT arg_INSTALL_PATH)
- message(FATAL_ERROR "No INSTALL_PATH given to qt_apply_rpaths.")
- endif()
-
- set(rpaths "")
-
- # Modify the install path to contain the nested structure of a framework.
- get_target_property(is_framework "${target}" FRAMEWORK)
- if(is_framework)
- if(UIKIT)
- # Shallow framework
- string(APPEND arg_INSTALL_PATH "/Qt${target}.framework")
- else()
- # Full framework
- string(APPEND arg_INSTALL_PATH "/Qt${target}.framework/Versions/Current")
- endif()
- endif()
-
- # Same but for an app bundle.
- get_target_property(is_bundle "${target}" MACOSX_BUNDLE)
- if(is_bundle AND NOT is_framework)
- if(UIKIT)
- # Shallow bundle
- string(APPEND arg_INSTALL_PATH "/${target}.app")
- else()
- # Full bundle
- string(APPEND arg_INSTALL_PATH "/${target}.app/Contents/MacOS")
- endif()
- endif()
-
- # Somewhat similar to mkspecs/features/qt.prf
- if(arg_RELATIVE_RPATH)
- qt_compute_relative_rpath_base(
- "${_default_install_rpath}" "${arg_INSTALL_PATH}" relative_rpath)
- list(APPEND rpaths "${relative_rpath}")
- else()
- list(APPEND rpaths "${_default_install_rpath}")
- endif()
-
- # Somewhat similar to mkspecs/features/qt_build_extra.prf.
- foreach(rpath ${QT_EXTRA_RPATHS})
- if(IS_ABSOLUTE)
- list(APPEND rpaths "${rpath}")
- else()
- qt_compute_relative_rpath_base("${rpath}" "${arg_INSTALL_PATH}" relative_rpath)
- list(APPEND rpaths "${relative_rpath}")
- endif()
- endforeach()
-
- if(rpaths)
- list(REMOVE_DUPLICATES rpaths)
- set_property(TARGET "${target}" APPEND PROPERTY INSTALL_RPATH ${rpaths})
- endif()
-endfunction()
-
-function(qt_internal_set_up_sanitizer_features)
- set(ECM_ENABLE_SANITIZERS "" CACHE STRING "Enable sanitizers")
- set_property(CACHE ECM_ENABLE_SANITIZERS PROPERTY STRINGS "address;memory;thread;undefined")
-
- # If FEATURE_sanitize_foo is set on the command line, make sure to set the appropriate
- # ECM_ENABLE_SANITIZERS value. Also the other way around. This basically allows setting either
- # the feature or ECM_ENABLE_SANITIZERS directly.
- #
- # TODO: Decide which one of these should be the source of truth, because reconfiguration with
- # different options might not work as expected when ECM_ENABLE_SANITIZERS is provided instead of
- # the features.
- set(enabled_sanitizer_features "")
- foreach(sanitizer_type address memory thread undefined)
- if(FEATURE_sanitize_${sanitizer_type})
- list(APPEND enabled_sanitizer_features "${sanitizer_type}")
- endif()
- endforeach()
- if(enabled_sanitizer_features)
- set(ECM_ENABLE_SANITIZERS
- "${enabled_sanitizer_features}" CACHE STRING "Enable sanitizers" FORCE)
- endif()
-
- if(ECM_ENABLE_SANITIZERS)
- foreach(sanitizer_type ${ECM_ENABLE_SANITIZERS})
- message(STATUS "Enabling sanitizer: ${sanitizer_type}")
- set(feature_name "FEATURE_sanitize_${sanitizer_type}")
- set(${feature_name} "ON" CACHE BOOL "Enable ${sanitizer_type} sanitizer" FORCE)
- set(QT_${feature_name} "ON" CACHE BOOL "Enable ${sanitizer_type} sanitizer" FORCE)
- endforeach()
- endif()
-endfunction()
-
-function(qt_internal_apply_win_prefix_and_suffix target)
- if(WIN32)
- # Table of prefix / suffixes for MSVC libraries as qmake expects them to be created.
- # static - Qt6EdidSupport.lib (platform support libraries / or static QtCore, etc)
- # shared - Qt6Core.dll
- # shared import library - Qt6Core.lib
- # module aka Qt plugin - qwindows.dll
- # module import library - qwindows.lib
- #
- # The CMake defaults are fine for us.
-
- # Table of prefix / suffixes for MinGW libraries as qmake expects them to be created.
- # static - libQt6EdidSupport.a (platform support libraries / or static QtCore, etc)
- # shared - Qt6Core.dll
- # shared import library - libQt6Core.a
- # module aka Qt plugin - qwindows.dll
- # module import library - libqwindows.a
- #
- # CMake for Windows-GNU platforms defaults the prefix to "lib".
- # CMake for Windows-GNU platforms defaults the import suffix to ".dll.a".
- # These CMake defaults are not ok for us.
-
- # This should cover both MINGW with GCC and CLANG.
- if(NOT MSVC)
- set_property(TARGET "${target}" PROPERTY IMPORT_SUFFIX ".a")
-
- get_target_property(target_type ${target} TYPE)
- if(target_type STREQUAL "STATIC_LIBRARY")
- set_property(TARGET "${target}" PROPERTY PREFIX "lib")
- else()
- set_property(TARGET "${target}" PROPERTY PREFIX "")
- set_property(TARGET "${target}" PROPERTY IMPORT_PREFIX "lib")
- endif()
- endif()
- endif()
-endfunction()
-
-include(QtApp)
-
-# Compatibility macros that should be removed once all their usages are removed.
-function(extend_target)
- qt_extend_target(${ARGV})
-endfunction()
-
-function(add_qt_module)
- qt_add_module(${ARGV})
-endfunction()
-
-function(add_qt_plugin)
- qt_add_plugin(${ARGV})
-endfunction()
-
-function(add_qt_tool)
- qt_add_tool(${ARGV})
-endfunction()
-
-function(add_qt_test)
- qt_add_test(${ARGV})
-endfunction()
-
-function(add_qt_test_helper)
- qt_add_test_helper(${ARGV})
-endfunction()
-
-function(add_qt_manual_test)
- qt_add_manual_test(${ARGV})
-endfunction()
-
-function(add_qt_benchmark)
- qt_add_benchmark(${ARGV})
-endfunction()
-
-function(add_qt_executable)
- qt_add_executable(${ARGV})
-endfunction()
-
-function(add_qt_simd_part)
- qt_add_simd_part(${ARGV})
-endfunction()
-
-function(add_qt_docs)
- qt_add_docs(${ARGV})
-endfunction()
-
-function(add_qt_resource)
- qt_add_resource(${ARGV})
-endfunction()
-
-function(add_cmake_library)
- qt_add_cmake_library(${ARGV})
-endfunction()
+qt_internal_setup_build_and_global_variables()
diff --git a/cmake/QtBuildHelpers.cmake b/cmake/QtBuildHelpers.cmake
new file mode 100644
index 0000000000..cce57cd5f6
--- /dev/null
+++ b/cmake/QtBuildHelpers.cmake
@@ -0,0 +1,458 @@
+# Copyright (C) 2023 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+function(qt_internal_validate_cmake_generator)
+ get_property(warning_shown GLOBAL PROPERTY _qt_validate_cmake_generator_warning_shown)
+
+ if(NOT warning_shown
+ AND NOT CMAKE_GENERATOR MATCHES "Ninja"
+ AND NOT QT_SILENCE_CMAKE_GENERATOR_WARNING
+ AND NOT DEFINED ENV{QT_SILENCE_CMAKE_GENERATOR_WARNING})
+ set_property(GLOBAL PROPERTY _qt_validate_cmake_generator_warning_shown TRUE)
+ message(WARNING
+ "The officially supported CMake generator for building Qt is "
+ "Ninja / Ninja Multi-Config. "
+ "You are using: '${CMAKE_GENERATOR}' instead. "
+ "Thus, you might encounter issues. Use at your own risk.")
+ endif()
+endfunction()
+
+macro(qt_internal_set_qt_building_qt)
+ # Set the QT_BUILDING_QT variable so we can verify whether we are building
+ # Qt from source.
+ # Make sure not to set it when building a standalone test, otherwise
+ # upon reconfiguration we get an error about qt_internal_add_test
+ # not being found due the if(NOT QT_BUILDING_QT) check we have
+ # in each standalone test.
+ if(NOT QT_INTERNAL_IS_STANDALONE_TEST)
+ set(QT_BUILDING_QT TRUE CACHE BOOL
+ "When this is present and set to true, it signals that we are building Qt from source.")
+ endif()
+endmacro()
+
+macro(qt_internal_unset_extra_build_internals_vars)
+ # Reset content of extra build internal vars for each inclusion of QtSetup.
+ unset(QT_EXTRA_BUILD_INTERNALS_VARS)
+endmacro()
+
+macro(qt_internal_get_generator_is_multi_config)
+ # Save the global property in a variable to make it available to feature conditions.
+ get_property(QT_GENERATOR_IS_MULTI_CONFIG GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
+endmacro()
+
+macro(qt_internal_setup_position_independent_code)
+ ## Position independent code:
+ set(CMAKE_POSITION_INDEPENDENT_CODE ON)
+
+ # Does the linker support position independent code?
+ include(CheckPIESupported)
+ check_pie_supported()
+endmacro()
+
+macro(qt_internal_set_link_depends_no_shared)
+ # Do not relink dependent libraries when no header has changed:
+ set(CMAKE_LINK_DEPENDS_NO_SHARED ON)
+endmacro()
+
+macro(qt_internal_set_qt_source_tree_var)
+ # Specify the QT_SOURCE_TREE only when building qtbase. Needed by some tests when the tests are
+ # built as part of the project, and not standalone. For standalone tests, the value is set in
+ # QtBuildInternalsExtra.cmake.
+ if(PROJECT_NAME STREQUAL "QtBase")
+ set(QT_SOURCE_TREE "${QtBase_SOURCE_DIR}" CACHE PATH
+ "A path to the source tree of the previously configured QtBase project." FORCE)
+ endif()
+endmacro()
+
+macro(qt_internal_include_qt_platform_android)
+ ## Android platform settings
+ if(ANDROID)
+ include(QtPlatformAndroid)
+ endif()
+endmacro()
+
+macro(qt_internal_set_compiler_optimization_flags)
+ include(QtCompilerOptimization)
+endmacro()
+
+macro(qt_internal_set_compiler_warning_flags)
+ include(QtCompilerFlags)
+endmacro()
+
+macro(qt_internal_set_skip_setup_deployment)
+ if(NOT QT_BUILD_EXAMPLES)
+ # Disable deployment setup to avoid warnings about missing patchelf with CMake < 3.21.
+ set(QT_SKIP_SETUP_DEPLOYMENT ON)
+ endif()
+endmacro()
+
+macro(qt_internal_reset_global_state)
+ qt_internal_clear_qt_repo_known_modules()
+ qt_internal_clear_qt_repo_known_plugin_types()
+ qt_internal_set_qt_known_plugins("")
+
+ set(QT_KNOWN_MODULES_WITH_TOOLS "" CACHE INTERNAL "Known Qt modules with tools" FORCE)
+endmacro()
+
+macro(qt_internal_set_qt_path_separator)
+ # For adjusting variables when running tests, we need to know what
+ # the correct variable is for separating entries in PATH-alike
+ # variables.
+ if(CMAKE_HOST_SYSTEM_NAME STREQUAL "Windows")
+ set(QT_PATH_SEPARATOR "\\;")
+ else()
+ set(QT_PATH_SEPARATOR ":")
+ endif()
+endmacro()
+
+macro(qt_internal_set_internals_extra_cmake_code)
+ # This is used to hold extra cmake code that should be put into QtBuildInternalsExtra.cmake file
+ # at the QtPostProcess stage.
+ set(QT_BUILD_INTERNALS_EXTRA_CMAKE_CODE "")
+endmacro()
+
+macro(qt_internal_set_top_level_source_dir)
+ # Save the value of the current first project source dir.
+ # This will be /path/to/qtbase for qtbase both in a super-build and a non super-build.
+ # This will be /path/to/qtbase/tests when building standalone tests.
+ set(QT_TOP_LEVEL_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}")
+endmacro()
+
+macro(qt_internal_set_apple_archiver_flags)
+ # Prevent warnings about object files without any symbols. This is a common
+ # thing in Qt as we tend to build files unconditionally, and then use ifdefs
+ # to compile out parts that are not relevant.
+ if(CMAKE_CXX_COMPILER_ID MATCHES "AppleClang")
+ foreach(lang ASM C CXX)
+ # We have to tell 'ar' to not run ranlib by itself, by passing the 'S' option
+ set(CMAKE_${lang}_ARCHIVE_CREATE "<CMAKE_AR> qcS <TARGET> <LINK_FLAGS> <OBJECTS>")
+ set(CMAKE_${lang}_ARCHIVE_APPEND "<CMAKE_AR> qS <TARGET> <LINK_FLAGS> <OBJECTS>")
+ set(CMAKE_${lang}_ARCHIVE_FINISH "<CMAKE_RANLIB> -no_warning_for_no_symbols <TARGET>")
+ endforeach()
+ endif()
+endmacro()
+
+macro(qt_internal_set_apple_privacy_manifest target manifest_file)
+ set_target_properties(${target} PROPERTIES _qt_privacy_manifest "${manifest_file}")
+endmacro()
+
+macro(qt_internal_set_debug_extend_target)
+ option(QT_CMAKE_DEBUG_EXTEND_TARGET "Debug extend_target calls in Qt's build system" OFF)
+endmacro()
+
+# These upstream CMake modules will be automatically include()'d when doing
+# find_package(Qt6 COMPONENTS BuildInternals).
+function(qt_internal_get_qt_build_upstream_cmake_modules out_var)
+ set(${out_var}
+ CMakeFindBinUtils
+ CMakePackageConfigHelpers
+ CheckCXXSourceCompiles
+ FeatureSummary
+ PARENT_SCOPE
+ )
+endfunction()
+
+# These helpers will be installed when building qtbase, and they will be automatically include()'d
+# when doing find_package(Qt6 COMPONENTS BuildInternals).
+# The helpers are expected to exist under the qtbase/cmake sub-directory and their file name
+# extension should be '.cmake'.
+function(qt_internal_get_qt_build_private_helpers out_var)
+ set(${out_var}
+ Qt3rdPartyLibraryHelpers
+ QtAndroidHelpers
+ QtAppHelpers
+ QtAutoDetectHelpers
+ QtAutogenHelpers
+ QtBuildInformation
+ QtBuildOptionsHelpers
+ QtBuildPathsHelpers
+ QtBuildRepoExamplesHelpers
+ QtBuildRepoHelpers
+ QtCMakeHelpers
+ QtCMakeVersionHelpers
+ QtDbusHelpers
+ QtDeferredDependenciesHelpers
+ QtDocsHelpers
+ QtExecutableHelpers
+ QtFindPackageHelpers
+ QtFlagHandlingHelpers
+ QtFrameworkHelpers
+ QtGlobalStateHelpers
+ QtHeadersClean
+ QtInstallHelpers
+ QtJavaHelpers
+ QtLalrHelpers
+ QtMkspecHelpers
+ QtModuleHelpers
+ QtNoLinkTargetHelpers
+ QtPkgConfigHelpers
+ QtPlatformTargetHelpers
+ QtPluginHelpers
+ QtPostProcessHelpers
+ QtPrecompiledHeadersHelpers
+ QtPriHelpers
+ QtPrlHelpers
+ QtQmakeHelpers
+ QtResourceHelpers
+ QtRpathHelpers
+ QtSanitizerHelpers
+ QtScopeFinalizerHelpers
+ QtSeparateDebugInfo
+ QtSimdHelpers
+ QtSingleRepoTargetSetBuildHelpers
+ QtSyncQtHelpers
+ QtTargetHelpers
+ QtTestHelpers
+ QtToolHelpers
+ QtToolchainHelpers
+ QtUnityBuildHelpers
+ QtWasmHelpers
+ QtWrapperScriptHelpers
+ PARENT_SCOPE
+ )
+endfunction()
+
+# These files will be installed when building qtbase, but will NOT be automatically include()d
+# when doing find_package(Qt6 COMPONENTS BuildInternals).
+# The files are expected to exist under the qtbase/cmake sub-directory.
+function(qt_internal_get_qt_build_private_files_to_install out_var)
+ set(${out_var}
+ ModuleDescription.json.in
+ PkgConfigLibrary.pc.in
+ Qt3rdPartyLibraryConfig.cmake.in
+ QtBaseTopLevelHelpers.cmake
+ QtBuild.cmake
+ QtBuildHelpers.cmake
+ QtCMakePackageVersionFile.cmake.in
+ QtCompilerFlags.cmake
+ QtCompilerOptimization.cmake
+ QtConfigDependencies.cmake.in
+ QtConfigureTimeExecutableCMakeLists.txt.in
+ QtFileConfigure.txt.in
+ QtFindWrapConfigExtra.cmake.in
+ QtFindWrapHelper.cmake
+ QtFinishPkgConfigFile.cmake
+ QtFinishPrlFile.cmake
+ QtGenerateExtPri.cmake
+ QtGenerateLibHelpers.cmake
+ QtGenerateLibPri.cmake
+ QtGenerateVersionScript.cmake
+ QtModuleConfig.cmake.in
+ QtModuleDependencies.cmake.in
+ QtModuleHeadersCheck.cmake
+ QtModuleToolsConfig.cmake.in
+ QtModuleToolsDependencies.cmake.in
+ QtModuleToolsVersionlessTargets.cmake.in
+ QtPlatformAndroid.cmake
+ QtPlatformSupport.cmake
+ QtPluginConfig.cmake.in
+ QtPluginDependencies.cmake.in
+ QtPlugins.cmake.in
+ QtPostProcess.cmake
+ QtProcessConfigureArgs.cmake
+ QtSeparateDebugInfo.Info.plist.in
+ QtSetup.cmake
+ QtStandaloneTestsConfig.cmake.in
+ QtVersionlessAliasTargets.cmake.in
+ QtVersionlessTargets.cmake.in
+ QtWriteArgsFile.cmake
+ modulecppexports.h.in
+ qbatchedtestrunner.in.cpp
+ PARENT_SCOPE
+ )
+endfunction()
+
+# These helpers will be installed when building qtbase, and they will be automatically include()'d
+# when doing find_package(Qt6 COMPONENTS BuildInternals).
+# The helpers are expected to exist under the qtbase/cmake sub-directory and their file name
+# extension should be '.cmake'.
+# In addition, they are meant to be included when doing find_package(Qt6) as well.
+function(qt_internal_get_qt_build_public_helpers out_var)
+ set(${out_var}
+ QtFeature
+ QtFeatureCommon
+ QtPublicAppleHelpers
+ QtPublicCMakeHelpers
+ QtPublicCMakeVersionHelpers
+ QtPublicDependencyHelpers
+ QtPublicExternalProjectHelpers
+ QtPublicFinalizerHelpers
+ QtPublicFindPackageHelpers
+ QtPublicPluginHelpers
+ QtPublicTargetHelpers
+ QtPublicTestHelpers
+ QtPublicToolHelpers
+ QtPublicWalkLibsHelpers
+ PARENT_SCOPE
+ )
+endfunction()
+
+# These files will be installed when building qtbase, but will NOT be automatically include()d
+# when doing find_package(Qt6) nor find_package(Qt6 COMPONENTS BuildInternals).
+# The files are expected to exist under the qtbase/cmake sub-directory.
+function(qt_internal_get_qt_build_public_files_to_install out_var)
+ set(${out_var}
+ QtCopyFileIfDifferent.cmake
+ QtInitProject.cmake
+
+ # Public CMake files that are installed next Qt6Config.cmake, but are NOT included by it.
+ # Instead they are included by the generated CMake toolchain file.
+ QtPublicWasmToolchainHelpers.cmake
+
+ PARENT_SCOPE
+ )
+endfunction()
+
+# Includes all Qt CMake helper files that define functions and macros.
+macro(qt_internal_include_all_helpers)
+ # Upstream cmake modules.
+ qt_internal_get_qt_build_upstream_cmake_modules(__qt_upstream_helpers)
+ foreach(__qt_file_name IN LISTS __qt_upstream_helpers)
+ include("${__qt_file_name}")
+ endforeach()
+
+ # Internal helpers available only while building Qt itself.
+ qt_internal_get_qt_build_private_helpers(__qt_private_helpers)
+ foreach(__qt_file_name IN LISTS __qt_private_helpers)
+ include("${__qt_file_name}")
+ endforeach()
+
+ # Helpers that are available in public projects and while building Qt itself.
+ qt_internal_get_qt_build_public_helpers(__qt_public_helpers)
+ foreach(__qt_file_name IN LISTS __qt_public_helpers)
+ include("${__qt_file_name}")
+ endforeach()
+endmacro()
+
+function(qt_internal_check_host_path_set_for_cross_compiling)
+ if(CMAKE_CROSSCOMPILING)
+ if(NOT IS_DIRECTORY "${QT_HOST_PATH}")
+ message(FATAL_ERROR "You need to set QT_HOST_PATH to cross compile Qt.")
+ endif()
+ endif()
+endfunction()
+
+macro(qt_internal_setup_find_host_info_package)
+ _qt_internal_determine_if_host_info_package_needed(__qt_build_requires_host_info_package)
+ _qt_internal_find_host_info_package("${__qt_build_requires_host_info_package}")
+endmacro()
+
+macro(qt_internal_setup_poor_mans_scope_finalizer)
+ # This sets up the poor man's scope finalizer mechanism.
+ # For newer CMake versions, we use cmake_language(DEFER CALL) instead.
+ if(CMAKE_VERSION VERSION_LESS "3.19.0")
+ variable_watch(CMAKE_CURRENT_LIST_DIR qt_watch_current_list_dir)
+ endif()
+endmacro()
+
+macro(qt_internal_set_qt_namespace)
+ set(QT_NAMESPACE "" CACHE STRING "Qt Namespace")
+endmacro()
+
+macro(qt_internal_set_qt_coord_type)
+ if(PROJECT_NAME STREQUAL "QtBase")
+ set(QT_COORD_TYPE double CACHE STRING "Type of qreal")
+ endif()
+endmacro()
+
+function(qt_internal_check_macos_host_version)
+ # macOS versions 10.14 and less don't have the implementation of std::filesystem API.
+ if(CMAKE_HOST_APPLE AND CMAKE_HOST_SYSTEM_VERSION VERSION_LESS "19.0.0")
+ message(FATAL_ERROR "macOS versions less than 10.15 are not supported for building Qt.")
+ endif()
+endfunction()
+
+function(qt_internal_setup_tool_path_command)
+ if(NOT CMAKE_HOST_WIN32)
+ return()
+ endif()
+ set(bindir "${QT_BUILD_INTERNALS_RELOCATABLE_INSTALL_PREFIX}/${INSTALL_BINDIR}")
+ file(TO_NATIVE_PATH "${bindir}" bindir)
+ list(APPEND command COMMAND)
+ list(APPEND command set PATH=${bindir}$<SEMICOLON>%PATH%)
+ set(QT_TOOL_PATH_SETUP_COMMAND "${command}" CACHE INTERNAL
+ "internal command prefix for tool invocations" FORCE)
+ # QT_TOOL_PATH_SETUP_COMMAND is deprecated. Please use _qt_internal_get_wrap_tool_script_path
+ # instead.
+endfunction()
+
+macro(qt_internal_setup_android_platform_specifics)
+ if(ANDROID)
+ qt_internal_setup_android_target_properties()
+ endif()
+endmacro()
+
+macro(qt_internal_setup_build_and_global_variables)
+ qt_internal_validate_cmake_generator()
+ qt_internal_set_qt_building_qt()
+ qt_internal_set_cmake_build_type()
+ qt_internal_set_message_log_level(CMAKE_MESSAGE_LOG_LEVEL)
+ qt_internal_unset_extra_build_internals_vars()
+ qt_internal_get_generator_is_multi_config()
+
+ # Depends on qt_internal_set_cmake_build_type
+ qt_internal_setup_cmake_config_postfix()
+
+ qt_internal_setup_position_independent_code()
+ qt_internal_set_link_depends_no_shared()
+ qt_internal_setup_default_install_prefix()
+ qt_internal_set_qt_source_tree_var()
+ qt_internal_set_export_compile_commands()
+ qt_internal_set_configure_from_ide()
+
+ # Depends on qt_internal_set_configure_from_ide
+ qt_internal_set_sync_headers_at_configure_time()
+
+ qt_internal_setup_build_benchmarks()
+
+ # Depends on qt_internal_setup_build_benchmarks
+ qt_internal_setup_build_tests()
+
+ qt_internal_setup_build_tools()
+
+ # Depends on qt_internal_setup_default_install_prefix
+ qt_internal_setup_build_examples()
+
+ qt_internal_set_qt_host_path()
+
+ qt_internal_include_qt_platform_android()
+
+ # Depends on qt_internal_setup_default_install_prefix
+ qt_internal_setup_paths_and_prefixes()
+
+ qt_internal_reset_global_state()
+
+ # Depends on qt_internal_setup_paths_and_prefixes
+ qt_internal_set_mkspecs_dir()
+ qt_internal_setup_platform_definitions_and_mkspec()
+
+ qt_internal_check_macos_host_version()
+ _qt_internal_check_apple_sdk_and_xcode_versions()
+ qt_internal_check_host_path_set_for_cross_compiling()
+ qt_internal_setup_android_platform_specifics()
+ qt_internal_setup_find_host_info_package()
+ qt_internal_setup_tool_path_command()
+ qt_internal_setup_default_target_function_options()
+ qt_internal_set_default_rpath_settings()
+ qt_internal_set_qt_namespace()
+ qt_internal_set_qt_coord_type()
+ qt_internal_set_qt_path_separator()
+ qt_internal_set_internals_extra_cmake_code()
+ qt_internal_set_top_level_source_dir()
+ qt_internal_set_apple_archiver_flags()
+ qt_internal_set_debug_extend_target()
+ qt_internal_setup_poor_mans_scope_finalizer()
+
+ qt_internal_set_compiler_optimization_flags()
+ qt_internal_set_compiler_warning_flags()
+
+ qt_set_language_standards()
+ qt_internal_set_use_ccache()
+ qt_internal_set_unity_build()
+ qt_internal_set_allow_symlink_in_paths()
+ qt_internal_set_skip_setup_deployment()
+ qt_internal_set_qt_allow_download()
+
+ qt_internal_detect_dirty_features()
+endmacro()
+
diff --git a/cmake/QtBuildInformation.cmake b/cmake/QtBuildInformation.cmake
index 119bc3f2c0..11fa9996b1 100644
--- a/cmake/QtBuildInformation.cmake
+++ b/cmake/QtBuildInformation.cmake
@@ -1,68 +1,239 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+function(qt_internal_set_message_log_level out_var)
+ # Decide whether output should be verbose or not.
+ # Default to verbose (--log-level=STATUS) in a developer-build and
+ # non-verbose (--log-level=NOTICE) otherwise.
+ # If a custom CMAKE_MESSAGE_LOG_LEVEL was specified, it takes priority.
+ # Passing an explicit --log-level=Foo has the highest priority.
+ if(NOT CMAKE_MESSAGE_LOG_LEVEL)
+ if(FEATURE_developer_build OR QT_FEATURE_developer_build)
+ set(CMAKE_MESSAGE_LOG_LEVEL "STATUS")
+ else()
+ set(CMAKE_MESSAGE_LOG_LEVEL "NOTICE")
+ endif()
+ set(${out_var} "${CMAKE_MESSAGE_LOG_LEVEL}" PARENT_SCOPE)
+ endif()
+endfunction()
+
function(qt_print_feature_summary)
- include(FeatureSummary)
+ if(QT_SUPERBUILD)
+ qt_internal_set_message_log_level(message_log_level)
+ if(message_log_level)
+ # In a top-level build, ensure that the feature_summary is affected by the
+ # selected log-level.
+ set(CMAKE_MESSAGE_LOG_LEVEL "${message_log_level}")
+ endif()
+ endif()
+
# Show which packages were found.
- feature_summary(WHAT PACKAGES_FOUND
+ feature_summary(INCLUDE_QUIET_PACKAGES
+ WHAT PACKAGES_FOUND
REQUIRED_PACKAGES_NOT_FOUND
RECOMMENDED_PACKAGES_NOT_FOUND
OPTIONAL_PACKAGES_NOT_FOUND
RUNTIME_PACKAGES_NOT_FOUND
FATAL_ON_MISSING_REQUIRED_PACKAGES)
+ qt_internal_run_additional_summary_checks()
qt_configure_print_summary()
endfunction()
+function(qt_internal_run_additional_summary_checks)
+ get_property(
+ rpath_workaround_enabled
+ GLOBAL PROPERTY _qt_internal_staging_prefix_build_rpath_workaround)
+ if(rpath_workaround_enabled)
+ set(message
+ "Due to CMAKE_STAGING_PREFIX usage and an unfixed CMake bug,
+ to ensure correct build time rpaths, directory-level install
+ rules like ninja src/gui/install will not work.
+ Check QTBUG-102592 for further details.")
+ qt_configure_add_report_entry(
+ TYPE NOTE
+ MESSAGE "${message}"
+ )
+ endif()
+endfunction()
+
function(qt_print_build_instructions)
if((NOT PROJECT_NAME STREQUAL "QtBase" AND
- NOT PROJECT_NAME STREQUAL "Qt") OR
- QT_BUILD_STANDALONE_TESTS)
+ NOT PROJECT_NAME STREQUAL "Qt") OR QT_INTERNAL_BUILD_STANDALONE_PARTS)
return()
endif()
+ if(QT_SUPERBUILD)
+ qt_internal_set_message_log_level(message_log_level)
+ if(message_log_level)
+ # In a top-level build, ensure that qt_print_build_instructions is affected by the
+ # selected log-level.
+ set(CMAKE_MESSAGE_LOG_LEVEL "${message_log_level}")
+ endif()
+ endif()
+
set(build_command "cmake --build . --parallel")
set(install_command "cmake --install .")
- message("Qt is now configured for building. Just run '${build_command}'\n")
+ # Suggest "ninja install" for Multi-Config builds
+ # until https://gitlab.kitware.com/cmake/cmake/-/issues/21475 is fixed.
+ if(CMAKE_GENERATOR STREQUAL "Ninja Multi-Config")
+ set(install_command "ninja install")
+ endif()
+
+ set(configure_module_command "qt-configure-module")
+ if(CMAKE_HOST_WIN32)
+ string(APPEND configure_module_command ".bat")
+ endif()
+ if("${CMAKE_STAGING_PREFIX}" STREQUAL "")
+ set(local_install_prefix "${CMAKE_INSTALL_PREFIX}")
+ else()
+ set(local_install_prefix "${CMAKE_STAGING_PREFIX}")
+ endif()
+
+ set(msg "\n")
+
+ list(APPEND msg "Qt is now configured for building. Just run '${build_command}'\n")
if(QT_WILL_INSTALL)
- message("Once everything is built, you must run '${install_command}'")
- message("Qt will be installed into '${CMAKE_INSTALL_PREFIX}'")
+ list(APPEND msg "Once everything is built, you must run '${install_command}'")
+ list(APPEND msg "Qt will be installed into '${CMAKE_INSTALL_PREFIX}'")
+ else()
+ list(APPEND msg
+ "Once everything is built, Qt is installed. You should NOT run '${install_command}'")
+ list(APPEND msg
+ "Note that this build cannot be deployed to other machines or devices.")
+ endif()
+ list(APPEND msg
+ "\nTo configure and build other Qt modules, you can use the following convenience script:
+ ${local_install_prefix}/${INSTALL_BINDIR}/${configure_module_command}")
+ list(APPEND msg "\nIf reconfiguration fails for some reason, try removing 'CMakeCache.txt' \
+from the build directory")
+ if(CMAKE_VERSION VERSION_GREATER_EQUAL "3.24")
+ list(APPEND msg "Alternatively, you can add the --fresh flag to your CMake flags.\n")
else()
- message("Once everything is built, Qt is installed. You should NOT run '${install_command}'")
- message("Note that this build cannot be deployed to other machines or devices.")
+ list(APPEND msg "\n")
+ endif()
+
+ list(JOIN msg "\n" msg)
+
+ if(NOT QT_INTERNAL_BUILD_INSTRUCTIONS_SHOWN)
+ qt_configure_print_build_instructions_helper("${msg}")
+ endif()
+
+ set(QT_INTERNAL_BUILD_INSTRUCTIONS_SHOWN "TRUE" CACHE STRING "" FORCE)
+
+ if(QT_SUPERBUILD)
+ qt_internal_save_previously_visited_packages()
endif()
- message("\nTo configure and build other modules, you can use the following convenience script:
- ${QT_STAGING_PREFIX}/${INSTALL_BINDIR}/qt-cmake")
- message("\nIf reconfiguration fails for some reason, try to remove 'CMakeCache.txt' \
-from the build directory \n")
+endfunction()
+
+function(qt_configure_print_summary_helper summary_reports force_show)
+ # We force show the summary by temporarily (within the scope of the function) resetting the
+ # current log level.
+ if(force_show)
+ set(CMAKE_MESSAGE_LOG_LEVEL "STATUS")
+
+ # Need 2 flushes to ensure no interleaved input is printed due to a mix of message(STATUS)
+ # and message(NOTICE) calls.
+ execute_process(COMMAND ${CMAKE_COMMAND} -E echo " ")
+
+ message(STATUS "Configure summary:\n${summary_reports}")
+
+ execute_process(COMMAND ${CMAKE_COMMAND} -E echo " ")
+ endif()
+endfunction()
+
+function(qt_configure_print_build_instructions_helper msg)
+ # We want to ensure build instructions are always shown the first time, regardless of the
+ # current log level.
+ set(CMAKE_MESSAGE_LOG_LEVEL "STATUS")
+ message(STATUS "${msg}")
endfunction()
function(qt_configure_print_summary)
# Evaluate all recorded commands.
qt_configure_eval_commands()
- # Show Qt-specific configure summary and any notes, wranings, etc.
+ set(summary_file "${CMAKE_BINARY_DIR}/config.summary")
+ file(WRITE "${summary_file}" "")
+
+ get_property(features_possibly_changed GLOBAL PROPERTY _qt_dirty_build)
+
+ # Show Qt-specific configuration summary.
if(__qt_configure_reports)
- message("Configure summary:\n${__qt_configure_reports}")
+ # The summary will only be printed for log level STATUS or above.
+ # Check whether the log level is sufficient for printing the summary.
+ set(log_level_sufficient_for_printed_summary TRUE)
+ if(CMAKE_VERSION GREATER_EQUAL "3.25")
+ cmake_language(GET_MESSAGE_LOG_LEVEL log_level)
+ set(sufficient_log_levels STATUS VERBOSE DEBUG TRACE)
+ if(NOT log_level IN_LIST sufficient_log_levels)
+ set(log_level_sufficient_for_printed_summary FALSE)
+ endif()
+ endif()
+
+ # We want to show the configuration summary file and log level message only on
+ # first configuration or when we detect a feature change, to keep most
+ # reconfiguration output as quiet as possible.
+ # Currently feature change detection is not entirely reliable.
+ if(log_level_sufficient_for_printed_summary
+ AND (NOT QT_INTERNAL_SUMMARY_INSTRUCTIONS_SHOWN OR features_possibly_changed))
+ set(force_show_summary TRUE)
+ message(
+ "\n"
+ "-- Configuration summary shown below. It has also been written to"
+ " ${CMAKE_BINARY_DIR}/config.summary")
+ message(
+ "-- Configure with --log-level=STATUS or higher to increase "
+ "CMake's message verbosity. "
+ "The log level does not persist across reconfigurations.")
+ else()
+ set(force_show_summary FALSE)
+ message(
+ "\n"
+ "-- Configuration summary has been written to"
+ " ${CMAKE_BINARY_DIR}/config.summary")
+ endif()
+
+ qt_configure_print_summary_helper(
+ "${__qt_configure_reports}"
+ ${force_show_summary})
+
+ file(APPEND "${summary_file}" "${__qt_configure_reports}")
endif()
+
+ # Show Qt specific notes, warnings, errors.
if(__qt_configure_notes)
message("${__qt_configure_notes}")
+ file(APPEND "${summary_file}" "${__qt_configure_notes}")
endif()
if(__qt_configure_warnings)
message("${__qt_configure_warnings}")
+ file(APPEND "${summary_file}" "${__qt_configure_warnings}")
endif()
if(__qt_configure_errors)
message("${__qt_configure_errors}")
+ file(APPEND "${summary_file}" "${__qt_configure_errors}")
endif()
message("")
if(__qt_configure_an_error_occurred)
message(FATAL_ERROR "Check the configuration messages for an error that has occurred.")
endif()
+ file(APPEND "${summary_file}" "\n")
+ set(QT_INTERNAL_SUMMARY_INSTRUCTIONS_SHOWN "TRUE" CACHE STRING "" FORCE)
endfunction()
# Takes a list of arguments, and saves them to be evaluated at the end of the configuration
# phase when the configuration summary is shown.
+#
+# RECORD_ON_FEATURE_EVALUATION option allows to record the command even while the feature
+# evaluation-only stage.
function(qt_configure_record_command)
+ cmake_parse_arguments(arg "RECORD_ON_FEATURE_EVALUATION"
+ ""
+ "" ${ARGV})
# Don't record commands when only evaluating features of a configure.cmake file.
- if(__QtFeature_only_evaluate_features)
+ if(__QtFeature_only_evaluate_features AND NOT arg_RECORD_ON_FEATURE_EVALUATION)
return()
endif()
@@ -70,11 +241,11 @@ function(qt_configure_record_command)
if(NOT DEFINED command_count)
set(command_count 0)
- else()
- math(EXPR command_count "${command_count}+1")
endif()
- set_property(GLOBAL PROPERTY qt_configure_command_${command_count} "${ARGV}")
+ set_property(GLOBAL PROPERTY qt_configure_command_${command_count} "${arg_UNPARSED_ARGUMENTS}")
+
+ math(EXPR command_count "${command_count}+1")
set_property(GLOBAL PROPERTY qt_configure_command_count "${command_count}")
endfunction()
@@ -131,13 +302,32 @@ macro(qt_configure_add_report_padded label message)
set(__qt_configure_reports "${__qt_configure_reports}" PARENT_SCOPE)
endmacro()
+# Pad 'label' and 'value' with dots like this:
+# "label ............... value"
+#
+# PADDING_LENGTH specifies the number of characters from the start to the last dot.
+# Default is 30.
+# MIN_PADDING specifies the minimum number of dots that are used for the padding.
+# Default is 0.
function(qt_configure_get_padded_string label value out_var)
- set(pad_string "........................................")
+ cmake_parse_arguments(arg "" "PADDING_LENGTH;MIN_PADDING" "" ${ARGN})
+ if("${arg_MIN_PADDING}" STREQUAL "")
+ set(arg_MIN_PADDING 0)
+ endif()
+ if(arg_PADDING_LENGTH)
+ set(pad_string "")
+ math(EXPR n "${arg_PADDING_LENGTH} - 1")
+ foreach(i RANGE ${n})
+ string(APPEND pad_string ".")
+ endforeach()
+ else()
+ set(pad_string ".........................................")
+ endif()
string(LENGTH "${label}" label_len)
string(LENGTH "${pad_string}" pad_len)
math(EXPR pad_len "${pad_len}-${label_len}")
if(pad_len LESS "0")
- set(pad_len "0")
+ set(pad_len ${arg_MIN_PADDING})
endif()
string(SUBSTRING "${pad_string}" 0 "${pad_len}" pad_string)
set(output "${label} ${pad_string} ${value}")
@@ -149,9 +339,11 @@ function(qt_configure_add_summary_entry)
endfunction()
function(qt_configure_process_add_summary_entry)
- qt_parse_all_arguments(arg "qt_configure_add_summary_entry"
+ cmake_parse_arguments(PARSE_ARGV 0 arg
""
- "ARGS;TYPE;MESSAGE" "CONDITION" ${ARGN})
+ "ARGS;TYPE;MESSAGE"
+ "CONDITION")
+ _qt_internal_validate_all_args_are_parsed(arg)
if(NOT arg_TYPE)
set(arg_TYPE "feature")
@@ -220,6 +412,8 @@ function(qt_configure_process_add_summary_entry)
endif()
qt_configure_add_report_padded("${label}" "${value}")
+ elseif(arg_TYPE STREQUAL "message")
+ qt_configure_add_report_padded("${arg_ARGS}" "${arg_MESSAGE}")
endif()
endfunction()
@@ -229,17 +423,22 @@ endfunction()
function(qt_configure_process_add_summary_build_type_and_config)
get_property(subarch_summary GLOBAL PROPERTY qt_configure_subarch_summary)
- set(message
- "Building for: ${QT_QMAKE_TARGET_MKSPEC} (${TEST_architecture_arch}, CPU features: ${subarch_summary})")
+ if(APPLE AND (CMAKE_OSX_ARCHITECTURES MATCHES ";"))
+ set(message
+ "Building for: ${QT_QMAKE_TARGET_MKSPEC} (${CMAKE_OSX_ARCHITECTURES}), ${TEST_architecture_arch} features: ${subarch_summary})")
+ else()
+ set(message
+ "Building for: ${QT_QMAKE_TARGET_MKSPEC} (${TEST_architecture_arch}, CPU features: ${subarch_summary})")
+ endif()
qt_configure_add_report("${message}")
set(message "Compiler: ")
if(CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang")
string(APPEND message "clang (Apple)")
+ elseif(CMAKE_CXX_COMPILER_ID STREQUAL "IntelLLVM")
+ string(APPEND message "clang (Intel LLVM)")
elseif(CLANG)
string(APPEND message "clang")
- elseif(ICC)
- string(APPEND message "intel_icc")
elseif(QCC)
string(APPEND message "rim_qcc")
elseif(GCC)
@@ -301,8 +500,11 @@ function(qt_configure_add_summary_section)
endfunction()
function(qt_configure_process_add_summary_section)
- qt_parse_all_arguments(arg "qt_configure_add_summary_section"
- "" "NAME" "" ${ARGN})
+ cmake_parse_arguments(PARSE_ARGV 0 arg
+ ""
+ "NAME"
+ "")
+ _qt_internal_validate_all_args_are_parsed(arg)
qt_configure_add_report("${__qt_configure_indent}${arg_NAME}:")
if(NOT DEFINED __qt_configure_indent)
@@ -328,10 +530,17 @@ function(qt_configure_add_report_entry)
qt_configure_record_command(ADD_REPORT_ENTRY ${ARGV})
endfunction()
+function(qt_configure_add_report_error error)
+ message(SEND_ERROR "${error}")
+ qt_configure_add_report_entry(TYPE ERROR MESSAGE "${error}" CONDITION TRUE ${ARGN})
+endfunction()
+
function(qt_configure_process_add_report_entry)
- qt_parse_all_arguments(arg "qt_configure_add_report_entry"
+ cmake_parse_arguments(PARSE_ARGV 0 arg
""
- "TYPE;MESSAGE" "CONDITION" ${ARGN})
+ "TYPE;MESSAGE"
+ "CONDITION")
+ _qt_internal_validate_all_args_are_parsed(arg)
set(possible_types NOTE WARNING ERROR FATAL_ERROR)
if(NOT "${arg_TYPE}" IN_LIST possible_types)
diff --git a/cmake/QtBuildInternals/QtBuildInternalsAndroid.cmake b/cmake/QtBuildInternals/QtBuildInternalsAndroid.cmake
deleted file mode 100644
index 1d3997b0c9..0000000000
--- a/cmake/QtBuildInternals/QtBuildInternalsAndroid.cmake
+++ /dev/null
@@ -1,216 +0,0 @@
-#
-# Android specific functions/macros/properties required for building Qt Modules
-#
-
-define_property(TARGET
- PROPERTY
- QT_ANDROID_MODULE_INSTALL_DIR
- BRIEF_DOCS
- "Recorded install location for a Qt Module."
- FULL_DOCS
- "Recorded install location for a Qt Module. Used by qt_android_dependencies()."
-)
-
-
-define_property(TARGET
- PROPERTY
- QT_ANDROID_JAR_DEPENDENCIES
- BRIEF_DOCS
- "Qt Module Jar dependencies list."
- FULL_DOCS
- "Qt Module Jar dependencies list."
-)
-
-define_property(TARGET
- PROPERTY
- QT_ANDROID_BUNDLED_JAR_DEPENDENCIES
- BRIEF_DOCS
- "Qt Module Jars that should be bundled with it during packing."
- FULL_DOCS
- "Qt Module Jars that should be bundled with it during packing."
-)
-
-define_property(TARGET
- PROPERTY
- QT_ANDROID_LIB_DEPENDENCIES
- BRIEF_DOCS
- "Qt Module C++ libraries that should be bundled with it during packing."
- FULL_DOCS
- "Qt Module C++ libraries that should be bundled with it during packing."
-)
-
-define_property(TARGET
- PROPERTY
- QT_ANDROID_LIB_DEPENDENCY_REPLACEMENTS
- BRIEF_DOCS
- "Qt Module C++ libraries that can replace libraries declared with the QT_ANDROID_LIB_DEPENDENCIES property."
- FULL_DOCS
- "Qt Module C++ libraries that can replace libraries declared with the QT_ANDROID_LIB_DEPENDENCIES property."
-)
-
-define_property(TARGET
- PROPERTY
- QT_ANDROID_BUNDLED_FILES
- BRIEF_DOCS
- "Qt Module files that need to be bundled during packing."
- FULL_DOCS
- "Qt Module files that need to be bundled during packing."
-)
-
-define_property(TARGET
- PROPERTY
- QT_ANDROID_PERMISSIONS
- BRIEF_DOCS
- "Qt Module android permission list."
- FULL_DOCS
- "Qt Module android permission list."
-)
-# Generate Qt Module -android-dependencies.xml required by the
-# androiddeploytoolqt to successfully copy all the plugins and other dependent
-# items into tha APK
-function(qt_android_dependencies target)
- get_target_property(target_type "${target}" TYPE)
- if(target_type STREQUAL "INTERFACE_LIBRARY")
- return()
- endif()
-
- get_target_property(arg_JAR_DEPENDENCIES ${target} QT_ANDROID_JAR_DEPENDENCIES)
- get_target_property(arg_BUNDLED_JAR_DEPENDENCIES ${target} QT_ANDROID_BUNDLED_JAR_DEPENDENCIES)
- get_target_property(arg_LIB_DEPENDENCIES ${target} QT_ANDROID_LIB_DEPENDENCIES)
- get_target_property(arg_LIB_DEPENDENCY_REPLACEMENTS ${target} QT_ANDROID_LIB_DEPENDENCY_REPLACEMENTS)
- get_target_property(arg_BUNDLED_FILES ${target} QT_ANDROID_BUNDLED_FILES)
- get_target_property(arg_PERMISSIONS ${target} QT_ANDROID_PERMISSIONS)
- get_target_property(module_plugins ${target} MODULE_PLUGIN_TYPES)
-
- if ((NOT module_plugins)
- AND (NOT arg_JAR_DEPENDENCIES)
- AND (NOT arg_LIB_DEPENDENCY_REPLACEMENTS)
- AND (NOT arg_LIB_DEPENDENCIES)
- AND (NOT arg_BUNDLED_JAR_DEPENDENCIES)
- AND (NOT arg_PERMISSIONS)
- AND (NOT arg_BUNDLED_FILES))
- # None of the values were set, so there's nothing to do
- return()
- endif()
-
-
- get_target_property(target_output_name ${target} OUTPUT_NAME)
- if (NOT target_output_name)
- set(target_name ${target})
- else()
- set(target_name ${target_output_name})
- endif()
-
- # mimic qmake's section and string splitting from
- # mkspecs/feature/qt_android_deps.prf
- macro(section string delimiter first second)
- string(FIND ${string} ${delimiter} delimiter_location)
- if (NOT ${delimiter_location} EQUAL -1)
- string(SUBSTRING ${string} 0 ${delimiter_location} ${first})
- math(EXPR delimiter_location "${delimiter_location} + 1")
- string(SUBSTRING ${string} ${delimiter_location} -1 ${second})
- else()
- set(${first} ${string})
- set(${second} "")
- endif()
- endmacro()
-
- set(dependency_file "${QT_BUILD_DIR}/${INSTALL_LIBDIR}/${target_name}_${CMAKE_ANDROID_ARCH_ABI}-android-dependencies.xml")
-
- set(file_contents "<rules><dependencies>\n")
- string(APPEND file_contents "<lib name=\"${target_name}_${CMAKE_ANDROID_ARCH_ABI}\"><depends>\n")
-
- # Jar Dependencies
- if(arg_JAR_DEPENDENCIES)
- foreach(jar_dependency IN LISTS arg_JAR_DEPENDENCIES)
- section(${jar_dependency} ":" jar_file init_class)
- if (init_class)
- set(init_class "initClass=\"${init_class}\"")
- endif()
- file(TO_NATIVE_PATH ${jar_file} jar_file_native)
- string(APPEND file_contents "<jar file=\"${jar_file_native}\" ${init_class} />\n")
- endforeach()
- endif()
-
- # Bundled Jar Dependencies
- if(arg_BUNDLED_JAR_DEPENDENCIES)
- foreach(jar_bundle IN LISTS arg_BUNDLED_JAR_DEPENDENCIES)
- section(${jar_bundle} ":" bundle_file init_calss)
- if (init_class)
- set(init_class "initClass=\"${init_class}\"")
- endif()
- file(TO_NATIVE_PATH ${jar_bundle} jar_bundle_native)
- string(APPEND file_contents "<jar bundling=\"1\" file=\"${jar_bundle_native}\" ${init_class} />\n")
- endforeach()
- endif()
-
- # Lib Dependencies
- if(arg_LIB_DEPENDENCIES)
- foreach(lib IN LISTS arg_LIB_DEPENDENCIES)
- string(REPLACE ".so" "_${CMAKE_ANDROID_ARCH_ABI}.so" lib ${lib})
- section(${lib} ":" lib_file lib_extends)
- if (lib_extends)
- set(lib_extends "extends=\"${lib_extends}\"")
- endif()
- file(TO_NATIVE_PATH ${lib_file} lib_file_native)
- string(APPEND file_contents "<lib file=\"${lib_file_native}\" ${lib_extends} />\n")
- endforeach()
- endif()
-
- # Lib Dependencies Replacements
- if(arg_LIB_DEPENDENCY_REPLACEMENTS)
- foreach(lib IN LISTS arg_LIB_DEPENDENCY_REPLACEMENTS)
- string(REPLACE ".so" "_${CMAKE_ANDROID_ARCH_ABI}.so" lib ${lib})
- section(${lib} ":" lib_file lib_replacement)
- if (lib_replacement)
- file(TO_NATIVE_PATH ${lib_replacement} lib_replacement_native)
- set(lib_replacement "replaces=\"${lib_replacement_native}\"")
- endif()
- file(TO_NATIVE_PATH ${lib_file} lib_file_native)
- string(APPEND file_contents "<lib file=\"${lib_file_native}\" ${lib_replacement} />\n")
- endforeach()
- endif()
-
-
- # Bundled files
- if(arg_BUNDLED_FILES)
- foreach(bundled_file IN LISTS arg_BUNDLED_FILES)
- file(TO_NATIVE_PATH ${bundled_file} file_native)
- string(APPEND file_contents "<bundled file=\"${file_native}\" />\n")
- endforeach()
- endif()
-
- # Module plugins
- if(module_plugins)
- foreach(plugin IN LISTS module_plugins)
- string(APPEND file_contents "<bundled file=\"plugins/${plugin}\" />\n")
- endforeach()
- endif()
-
- # Android Permissions
- if(arg_PERMISSIONS)
- foreach(permission IN LISTS arg_PERMISSIONS)
- string(APPEND file_contents "<permission name=\"${permission}\" />\n")
- endforeach()
- endif()
-
- string(APPEND file_contents "</depends></lib>")
- string(APPEND file_contents "</dependencies></rules>\n")
- file(WRITE ${dependency_file} ${file_contents})
-
- get_target_property(target_install_dir ${target} QT_ANDROID_MODULE_INSTALL_DIR)
- if (NOT target_install_dir)
- message(SEND_ERROR "qt_android_dependencies: Target ${target} is either not a Qt Module or has no recorded install location")
- return()
- endif()
-
- # Copy file into install directory, required by the androiddeployqt tool.
- qt_install(FILES
- ${dependency_file}
- DESTINATION
- ${target_install_dir}
- COMPONENT
- Devel)
-endfunction()
-
-
diff --git a/cmake/QtBuildInternals/QtBuildInternalsConfig.cmake b/cmake/QtBuildInternals/QtBuildInternalsConfig.cmake
index 95564e0599..129f1ebb77 100644
--- a/cmake/QtBuildInternals/QtBuildInternalsConfig.cmake
+++ b/cmake/QtBuildInternals/QtBuildInternalsConfig.cmake
@@ -1,19 +1,29 @@
-if (CMAKE_VERSION VERSION_LESS 3.1.0)
- message(FATAL_ERROR "Qt requires at least CMake version 3.1.0")
-endif()
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
-######################################
-#
-# Macros for building Qt modules
-#
-######################################
+# These values should be kept in sync with those in qtbase/.cmake.conf
+cmake_minimum_required(VERSION 3.16...3.21)
set(QT_BACKUP_CMAKE_INSTALL_PREFIX_BEFORE_EXTRA_INCLUDE "${CMAKE_INSTALL_PREFIX}")
+# This depends on qt_internal_read_repo_dependencies existing.
if(EXISTS "${CMAKE_CURRENT_LIST_DIR}/QtBuildInternalsExtra.cmake")
include(${CMAKE_CURRENT_LIST_DIR}/QtBuildInternalsExtra.cmake)
endif()
+macro(qt_internal_setup_cmake_and_export_namespace)
+ # The variables might have already been set in QtBuildInternalsExtra.cmake if the file is
+ # included while building a new module and not QtBase. In that case, stop overriding the value.
+ if(NOT INSTALL_CMAKE_NAMESPACE)
+ set(INSTALL_CMAKE_NAMESPACE "Qt${PROJECT_VERSION_MAJOR}"
+ CACHE STRING "CMake namespace [Qt${PROJECT_VERSION_MAJOR}]")
+ endif()
+ if(NOT QT_CMAKE_EXPORT_NAMESPACE)
+ set(QT_CMAKE_EXPORT_NAMESPACE "Qt${PROJECT_VERSION_MAJOR}"
+ CACHE STRING "CMake namespace used when exporting targets [Qt${PROJECT_VERSION_MAJOR}]")
+ endif()
+endmacro()
+
macro(qt_set_up_build_internals_paths)
# Set up the paths for the cmake modules located in the prefix dir. Prepend, so the paths are
# least important compared to the source dir ones, but more important than command line
@@ -26,6 +36,9 @@ macro(qt_set_up_build_internals_paths)
# building qtdeclarative, rather than having to build qtbase first (which will copy
# QtBuild.cmake to the build dir). This is similar to qmake non-prefix builds, where the
# source qtbase/mkspecs directory is used.
+ # TODO: Clean this up, together with qt_internal_try_compile_binary_for_strip to only use the
+ # the qtbase sources when building qtbase. And perhaps also when doing a non-prefix
+ # developer-build.
if(EXISTS "${QT_SOURCE_TREE}/cmake")
list(PREPEND CMAKE_MODULE_PATH "${QT_SOURCE_TREE}/cmake")
endif()
@@ -41,432 +54,15 @@ macro(qt_set_up_build_internals_paths)
endif()
endmacro()
+qt_internal_setup_cmake_and_export_namespace()
+
# Set up the build internal paths unless explicitly requested not to.
if(NOT QT_BUILD_INTERNALS_SKIP_CMAKE_MODULE_PATH_ADDITION)
+ # Depends on qt_internal_setup_cmake_and_export_namespace
qt_set_up_build_internals_paths()
endif()
-# Define some constants to check for certain platforms, etc.
-# Needs to be loaded before qt_repo_build() to handle require() clauses before even starting a repo
-# build.
-include(QtPlatformSupport)
-
-function(qt_build_internals_disable_pkg_config_if_needed)
- # pkg-config should not be used by default on Darwin and Windows platforms, as defined in
- # the qtbase/configure.json. Unfortunately by the time the feature is evaluated there are
- # already a few find_package() calls.
- # So we have to duplicate the condition logic here and disable pkg-config for those platforms by
- # default.
- #
- # Note that on macOS, if the pkg-config feature is enabled by the user explicitly, we will also
- # tell CMake to consider paths like /usr/local (Homebrew) as system paths when looking for
- # packages.
- # We have to do that because disabling these paths but keeping pkg-config
- # enabled won't enable finding all system libraries via pkg-config alone, many libraries can
- # only be found via FooConfig.cmake files which means /usr/local should be in the system prefix
- # path.
- set(pkg_config_enabled ON)
- if(APPLE OR WIN32)
- set(pkg_config_enabled OFF)
- endif()
- if(DEFINED FEATURE_pkg_config)
- if(FEATURE_pkg_config)
- set(pkg_config_enabled ON)
- else()
- set(pkg_config_enabled OFF)
- endif()
- endif()
- set(FEATURE_pkg_config "${pkg_config_enabled}" CACHE STRING "Using pkg-config")
- if(NOT pkg_config_enabled)
- qt_build_internals_disable_pkg_config()
- else()
- unset(PKG_CONFIG_EXECUTABLE CACHE)
- endif()
-endfunction()
-
-function(qt_build_internals_disable_pkg_config)
- # Disable pkg-config by setting an empty executable path. There's no documented way to
- # mark the package as found, but force all pkg_check_modules calls to do nothing.
- set(PKG_CONFIG_EXECUTABLE "" CACHE STRING "Disabled pkg-config usage." FORCE)
-endfunction()
-
-if(NOT QT_BUILD_INTERNALS_SKIP_PKG_CONFIG_ADJUSTMENT)
- qt_build_internals_disable_pkg_config_if_needed()
-endif()
-
-macro(qt_build_internals_find_pkg_config)
- # Find package config once before any system prefix modifications.
- find_package(PkgConfig QUIET)
-endmacro()
-
-if(NOT QT_BUILD_INTERNALS_SKIP_FIND_PKG_CONFIG)
- qt_build_internals_find_pkg_config()
-endif()
-
-function(qt_build_internals_set_up_system_prefixes)
- if(APPLE AND NOT FEATURE_pkg_config)
- # Remove /usr/local and other paths like that which CMake considers as system prefixes on
- # darwin platforms. CMake considers them as system prefixes, but in qmake / Qt land we only
- # consider the SDK path as a system prefix.
- # 3rd party libraries in these locations should not be picked up when building Qt,
- # unless opted-in via the pkg-config feature, which in turn will disable this behavior.
- #
- # Note that we can't remove /usr as a system prefix path, because many programs won't be
- # found then (e.g. perl).
- set(QT_CMAKE_SYSTEM_PREFIX_PATH_BACKUP "${CMAKE_SYSTEM_PREFIX_PATH}" PARENT_SCOPE)
- set(QT_CMAKE_SYSTEM_FRAMEWORK_PATH_BACKUP "${CMAKE_SYSTEM_FRAMEWORK_PATH}" PARENT_SCOPE)
-
- list(REMOVE_ITEM CMAKE_SYSTEM_PREFIX_PATH
- "/usr/local" # Homebrew
- "/usr/X11R6"
- "/usr/pkg"
- "/opt"
- "/sw" # Fink
- "/opt/local" # MacPorts
- )
- if(_CMAKE_INSTALL_DIR)
- list(REMOVE_ITEM CMAKE_SYSTEM_PREFIX_PATH "${_CMAKE_INSTALL_DIR}")
- endif()
- list(REMOVE_ITEM CMAKE_SYSTEM_FRAMEWORK_PATH "~/Library/Frameworks")
- set(CMAKE_SYSTEM_PREFIX_PATH "${CMAKE_SYSTEM_PREFIX_PATH}" PARENT_SCOPE)
- set(CMAKE_SYSTEM_FRAMEWORK_PATH "${CMAKE_SYSTEM_FRAMEWORK_PATH}" PARENT_SCOPE)
-
- # Also tell qt_find_package() not to use PATH when looking for packages.
- # We can't simply set CMAKE_FIND_USE_SYSTEM_ENVIRONMENT_PATH to OFF because that will break
- # find_program(), and for instance ccache won't be found.
- # That's why we set a different variable which is used by qt_find_package.
- set(QT_NO_USE_FIND_PACKAGE_SYSTEM_ENVIRONMENT_PATH "ON" PARENT_SCOPE)
- endif()
-endfunction()
-
-if(NOT QT_BUILD_INTERNALS_SKIP_SYSTEM_PREFIX_ADJUSTMENT)
- qt_build_internals_set_up_system_prefixes()
-endif()
-
-macro(qt_build_internals_set_up_private_api)
- # Qt specific setup common for all modules:
- include(QtSetup)
- include(FeatureSummary)
-
- # Optionally include a repo specific Setup module.
- include(${PROJECT_NAME}Setup OPTIONAL)
- include(QtRepoSetup OPTIONAL)
-
- # Find Apple frameworks if needed.
- qt_find_apple_system_frameworks()
+include(QtBuildHelpers)
- # Decide whether tools will be built.
- qt_check_if_tools_will_be_built()
-endmacro()
-
-macro(qt_enable_cmake_languages)
- include(CheckLanguage)
- set(__qt_required_language_list C CXX)
- set(__qt_optional_language_list )
-
- # https://gitlab.kitware.com/cmake/cmake/-/issues/20545
- if(APPLE)
- list(APPEND __qt_optional_language_list OBJC OBJCXX)
- endif()
-
- foreach(__qt_lang ${__qt_required_language_list})
- enable_language(${__qt_lang})
- endforeach()
-
- foreach(__qt_lang ${__qt_optional_language_list})
- check_language(${__qt_lang})
- if(CMAKE_${__qt_lang}_COMPILER)
- enable_language(${__qt_lang})
- endif()
- endforeach()
-endmacro()
-
-# Minimum setup required to have any CMakeList.txt build as as a standalone
-# project after importing BuildInternals
-macro(qt_prepare_standalone_project)
- qt_set_up_build_internals_paths()
- qt_build_internals_set_up_private_api()
- qt_enable_cmake_languages()
-endmacro()
-
-macro(qt_build_repo_begin)
- qt_build_internals_set_up_private_api()
- qt_enable_cmake_languages()
-
- # Add global docs targets that will work both for per-repo builds, and super builds.
- if(NOT TARGET docs)
- add_custom_target(docs)
- add_custom_target(prepare_docs)
- add_custom_target(generate_docs)
- add_custom_target(html_docs)
- add_custom_target(qch_docs)
- add_custom_target(install_html_docs_docs)
- add_custom_target(install_qch_docs_docs)
- add_custom_target(install_docs_docs)
- endif()
-
- string(TOLOWER ${PROJECT_NAME} project_name_lower)
-
- set(qt_docs_target_name docs_${project_name_lower})
- set(qt_docs_prepare_target_name prepare_docs_${project_name_lower})
- set(qt_docs_generate_target_name generate_docs_${project_name_lower})
- set(qt_docs_html_target_name html_docs_${project_name_lower})
- set(qt_docs_qch_target_name qch_docs_${project_name_lower})
- set(qt_docs_install_html_target_name install_html_docs_${project_name_lower})
- set(qt_docs_install_qch_target_name install_qch_docs_${project_name_lower})
- set(qt_docs_install_target_name install_docs_${project_name_lower})
-
- add_custom_target(${qt_docs_target_name})
- add_custom_target(${qt_docs_prepare_target_name})
- add_custom_target(${qt_docs_generate_target_name})
- add_custom_target(${qt_docs_qch_target_name})
- add_custom_target(${qt_docs_html_target_name})
- add_custom_target(${qt_docs_install_html_target_name})
- add_custom_target(${qt_docs_install_qch_target_name})
- add_custom_target(${qt_docs_install_target_name})
-
- add_dependencies(${qt_docs_generate_target_name} ${qt_docs_prepare_target_name})
- add_dependencies(${qt_docs_html_target_name} ${qt_docs_generate_target_name})
- add_dependencies(${qt_docs_install_html_target_name} ${qt_docs_html_target_name})
- add_dependencies(${qt_docs_install_qch_target_name} ${qt_docs_qch_target_name})
- add_dependencies(${qt_docs_install_target_name} ${qt_docs_install_html_target_name} ${qt_docs_install_qch_target_name})
-
- # Make global doc targets depend on the module ones.
- add_dependencies(docs ${qt_docs_target_name})
- add_dependencies(prepare_docs ${qt_docs_prepare_target_name})
- add_dependencies(generate_docs ${qt_docs_generate_target_name})
- add_dependencies(html_docs ${qt_docs_html_target_name})
- add_dependencies(qch_docs ${qt_docs_qch_target_name})
- add_dependencies(install_html_docs_docs ${qt_docs_install_html_target_name})
- add_dependencies(install_qch_docs_docs ${qt_docs_install_qch_target_name})
- add_dependencies(install_docs_docs ${qt_docs_install_target_name})
-
- # Add host_tools meta target, so that developrs can easily build only tools and their
- # dependencies when working in qtbase.
- if(NOT TARGET host_tools)
- add_custom_target(host_tools)
- add_custom_target(bootstrap_tools)
- endif()
-endmacro()
-
-macro(qt_build_repo_end)
- if(NOT QT_BUILD_STANDALONE_TESTS)
- # Delayed actions on some of the Qt targets:
- include(QtPostProcess)
-
- # Install the repo-specific cmake find modules.
- qt_path_join(__qt_repo_install_dir ${QT_CONFIG_INSTALL_DIR} ${INSTALL_CMAKE_NAMESPACE})
-
- if(NOT PROJECT_NAME STREQUAL "QtBase")
- if (EXISTS cmake)
- qt_copy_or_install(DIRECTORY cmake/
- DESTINATION "${__qt_repo_install_dir}"
- FILES_MATCHING PATTERN "Find*.cmake"
- )
- endif()
- endif()
-
- if(NOT QT_SUPERBUILD)
- qt_print_feature_summary()
- endif()
- endif()
-
- if(NOT QT_SUPERBUILD)
- qt_print_build_instructions()
- endif()
-endmacro()
-
-macro(qt_build_repo)
- qt_build_repo_begin(${ARGN})
-
- # If testing is enabled, try to find the qtbase Test package.
- # Do this before adding src, because there might be test related conditions
- # in source.
- if (BUILD_TESTING AND NOT QT_BUILD_STANDALONE_TESTS)
- find_package(Qt6 ${PROJECT_VERSION} CONFIG REQUIRED COMPONENTS Test)
- endif()
-
- if(NOT QT_BUILD_STANDALONE_TESTS)
- if (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/src/CMakeLists.txt")
- add_subdirectory(src)
- endif()
-
- if (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/tools/CMakeLists.txt")
- add_subdirectory(tools)
- endif()
- endif()
-
- if (BUILD_TESTING AND EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/tests/CMakeLists.txt")
- add_subdirectory(tests)
- if(QT_NO_MAKE_TESTS)
- set_property(DIRECTORY tests PROPERTY EXCLUDE_FROM_ALL TRUE)
- endif()
- endif()
-
- qt_build_repo_end()
-
- if (BUILD_EXAMPLES AND BUILD_SHARED_LIBS
- AND EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/examples/CMakeLists.txt"
- AND NOT QT_BUILD_STANDALONE_TESTS)
- add_subdirectory(examples)
- if(QT_NO_MAKE_EXAMPLES)
- set_property(DIRECTORY examples PROPERTY EXCLUDE_FROM_ALL TRUE)
- endif()
- endif()
-endmacro()
-
-macro(qt_set_up_standalone_tests_build)
- # Remove this macro once all usages of it have been removed.
- # Standalone tests are not handled via the main repo project and qt_build_tests.
-endmacro()
-
-function(qt_get_standalone_tests_confg_files_path out_var)
- set(path "${QT_CONFIG_INSTALL_DIR}/${INSTALL_CMAKE_NAMESPACE}BuildInternals/StandaloneTests")
-
- # QT_CONFIG_INSTALL_DIR is relative in prefix builds.
- if(QT_WILL_INSTALL)
- qt_path_join(path "${CMAKE_INSTALL_PREFIX}" "${path}")
- endif()
-
- set("${out_var}" "${path}" PARENT_SCOPE)
-endfunction()
-
-macro(qt_build_tests)
- if(QT_BUILD_STANDALONE_TESTS)
- # Find location of TestsConfig.cmake. These contain the modules that need to be
- # find_package'd when testing.
- qt_get_standalone_tests_confg_files_path(_qt_build_tests_install_prefix)
- include("${_qt_build_tests_install_prefix}/${PROJECT_NAME}TestsConfig.cmake" OPTIONAL)
-
- # Of course we always need the test module as well.
- find_package(Qt6 ${PROJECT_VERSION} CONFIG REQUIRED COMPONENTS Test)
-
- # Set language standards after finding Core, because that's when the relevant
- # feature variables are available, and the call in QtSetup is too early when building
- # standalone tests, because Core was not find_package()'d yet.
- qt_set_language_standards()
-
- if(NOT QT_SUPERBUILD)
- # Set up fake standalone tests install prefix, so we don't pollute the Qt install
- # prefix. For super builds it needs to be done in qt5/CMakeLists.txt.
- qt_set_up_fake_standalone_tests_install_prefix()
- endif()
- endif()
-
- if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/auto/CMakeLists.txt")
- add_subdirectory(auto)
- endif()
- if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/benchmarks/CMakeLists.txt" AND QT_BUILD_BENCHMARKS)
- add_subdirectory(benchmarks)
- endif()
- if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/manual/CMakeLists.txt")
- # add_subdirectory(manual) don't build manual tests for now, because qmake doesn't.
- endif()
-endmacro()
-
-function(qt_compute_relative_path_from_cmake_config_dir_to_prefix)
- # Compute the reverse relative path from the CMake config dir to the install prefix.
- # This is used in QtBuildInternalsExtras to create a relocatable relative install prefix path.
- # This path is used for finding syncqt and other things, regardless of initial install prefix
- # (e.g installed Qt was archived and unpacked to a different path on a different machine).
- #
- # This is meant to be called only once when configuring qtbase.
- #
- # Similar code exists in Qt6CoreConfigExtras.cmake.in and src/corelib/CMakeLists.txt which
- # might not be needed anymore.
- if(QT_WILL_INSTALL)
- get_filename_component(clean_config_prefix
- "${CMAKE_INSTALL_PREFIX}/${QT_CONFIG_INSTALL_DIR}" ABSOLUTE)
- else()
- get_filename_component(clean_config_prefix "${QT_CONFIG_BUILD_DIR}" ABSOLUTE)
- endif()
- file(RELATIVE_PATH
- qt_path_from_cmake_config_dir_to_prefix
- "${clean_config_prefix}" "${CMAKE_INSTALL_PREFIX}")
- set(qt_path_from_cmake_config_dir_to_prefix "${qt_path_from_cmake_config_dir_to_prefix}"
- PARENT_SCOPE)
-endfunction()
-
-function(qt_get_relocatable_install_prefix out_var)
- # We need to compute it only once while building qtbase. Afterwards it's loaded from
- # QtBuildInternalsExtras.cmake.
- if(QT_BUILD_INTERNALS_RELOCATABLE_INSTALL_PREFIX)
- return()
- endif()
- # The QtBuildInternalsExtras value is dynamically computed, whereas the initial qtbase
- # configuration uses an absolute path.
- set(${out_var} "${CMAKE_INSTALL_PREFIX}" PARENT_SCOPE)
-endfunction()
-
-function(qt_set_up_fake_standalone_tests_install_prefix)
- # Set a fake local (non-cache) CMAKE_INSTALL_PREFIX.
- # Needed for standalone tests, we don't want to accidentally install a test into the Qt prefix.
- # Allow opt-out, if a user knows what they're doing.
- if(QT_NO_FAKE_STANDALONE_TESTS_INSTALL_PREFIX)
- return()
- endif()
- set(new_install_prefix "${CMAKE_BINARY_DIR}/fake_prefix")
-
- # It's IMPORTANT that this is not a cache variable. Otherwise
- # qt_get_standalone_tests_confg_files_path() will not work on re-configuration.
- message(STATUS
- "Setting local standalone test install prefix (non-cached) to '${new_install_prefix}'.")
- set(CMAKE_INSTALL_PREFIX "${new_install_prefix}" PARENT_SCOPE)
-endfunction()
-
-# Mean to be called when configuring examples as part of the main build tree, as well as for CMake
-# tests (tests that call CMake to try and build CMake applications).
-macro(qt_internal_set_up_build_dir_package_paths)
- list(APPEND CMAKE_PREFIX_PATH "${QT_BUILD_DIR}")
- # Make sure the CMake config files do not recreate the already-existing targets
- set(QT_NO_CREATE_TARGETS TRUE)
- set(BACKUP_CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ${CMAKE_FIND_ROOT_PATH_MODE_PACKAGE})
- set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE "BOTH")
-endmacro()
-
-macro(qt_examples_build_begin)
- # Examples that are built as part of the Qt build need to use the CMake config files from the
- # build dir, because they are not installed yet in a prefix build.
- # Appending to CMAKE_PREFIX_PATH helps find the initial Qt6Config.cmake.
- # Appending to QT_EXAMPLES_CMAKE_PREFIX_PATH helps find components of Qt6, because those
- # find_package calls use NO_DEFAULT_PATH, and thus CMAKE_PREFIX_PATH is ignored.
- qt_internal_set_up_build_dir_package_paths()
- list(APPEND QT_EXAMPLES_CMAKE_PREFIX_PATH "${QT_BUILD_DIR}")
-
- # Because CMAKE_INSTALL_RPATH is empty by default in the repo project, examples need to have
- # it set here, so they can run when installed.
- # This means that installed examples are not relocatable at the moment. We would need to
- # annotate where each example is installed to, to be able to derive a relative rpath, and it
- # seems there's no way to query such information from CMake itself.
- set(CMAKE_INSTALL_RPATH "${_default_install_rpath}")
- set(QT_DISABLE_QT_ADD_PLUGIN_COMPATIBILITY TRUE)
-endmacro()
-
-macro(qt_examples_build_end)
- # We use AUTOMOC/UIC/RCC in the examples. Make sure to not fail on a fresh Qt build, that e.g. the moc binary does not exist yet.
-
- # This function gets all targets below this directory
- function(get_all_targets _result _dir)
- get_property(_subdirs DIRECTORY "${_dir}" PROPERTY SUBDIRECTORIES)
- foreach(_subdir IN LISTS _subdirs)
- get_all_targets(${_result} "${_subdir}")
- endforeach()
- get_property(_sub_targets DIRECTORY "${_dir}" PROPERTY BUILDSYSTEM_TARGETS)
- set(${_result} ${${_result}} ${_sub_targets} PARENT_SCOPE)
- endfunction()
-
- get_all_targets(targets "${CMAKE_CURRENT_SOURCE_DIR}")
-
- foreach(target ${targets})
- qt_autogen_tools(${target} ENABLE_AUTOGEN_TOOLS "moc" "rcc")
- if(TARGET Qt::Widgets)
- qt_autogen_tools(${target} ENABLE_AUTOGEN_TOOLS "uic")
- endif()
- endforeach()
-
- set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ${BACKUP_CMAKE_FIND_ROOT_PATH_MODE_PACKAGE})
-endmacro()
-
-if (ANDROID)
- include(${CMAKE_CURRENT_LIST_DIR}/QtBuildInternalsAndroid.cmake)
-endif()
+qt_internal_include_all_helpers()
+qt_internal_setup_build_internals()
diff --git a/cmake/QtBuildInternals/QtStandaloneTestTemplateProject/CMakeLists.txt b/cmake/QtBuildInternals/QtStandaloneTestTemplateProject/CMakeLists.txt
index a84c567b5a..766e372666 100644
--- a/cmake/QtBuildInternals/QtStandaloneTestTemplateProject/CMakeLists.txt
+++ b/cmake/QtBuildInternals/QtStandaloneTestTemplateProject/CMakeLists.txt
@@ -1,21 +1,7 @@
-cmake_minimum_required(VERSION 3.16)
-project(qt_single_test VERSION 6.0.0 LANGUAGES C CXX ASM)
-
-find_package(Qt6 REQUIRED COMPONENTS BuildInternals)
-
-# Includes QtSetup and friends for private CMake API.
-qt_build_internals_set_up_private_api()
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
-# Find all StandaloneTestsConfig.cmake files, and include them
-# This will find all Qt packages that are required for standalone tests.
-# It will find more packages that needed for a certain test, but will ensure any test can
-# be built.
-qt_get_standalone_tests_confg_files_path(standalone_tests_config_path)
-
-file(GLOB config_files "${standalone_tests_config_path}/*")
-foreach(file ${config_files})
- include("${file}")
-endforeach()
+cmake_minimum_required(VERSION 3.16)
# Get the absolute path of the passed-in project dir, relative to the current working directory
# of the calling script, rather than relative to this source directory.
@@ -27,10 +13,26 @@ else()
set(absolute_project_path "${QT_STANDALONE_TEST_PATH}")
endif()
-# Just before adding the test, change the local (non-cache) install prefix to something other than
-# the Qt install prefix, so that tests don't try to install and pollute the Qt install prefix.
-# Needs to be called after qt_get_standalone_tests_confg_files_path().
-qt_set_up_fake_standalone_tests_install_prefix()
+# If path does not include the drive letter, we try to add it.
+get_filename_component(absolute_project_path "." REALPATH BASE_DIR "${absolute_project_path}")
+
+if(NOT IS_DIRECTORY "${absolute_project_path}")
+ get_filename_component(filename "${absolute_project_path}" NAME)
+ get_filename_component(directory "${absolute_project_path}" DIRECTORY)
+
+ if(filename STREQUAL "CMakeLists.txt")
+ set(absolute_project_path "${directory}")
+ endif()
+endif()
+
+# Get the project name base on test directory name
+get_filename_component(project_name "${absolute_project_path}" NAME)
+
+project(${project_name} VERSION 6.0.0 LANGUAGES C CXX ASM)
+
+find_package(Qt6 REQUIRED COMPONENTS BuildInternals Core)
+
+include(${CMAKE_CURRENT_LIST_DIR}/Main.cmake NO_POLICY_SCOPE)
# Add the test project path as a subdirectory project.
add_subdirectory("${absolute_project_path}" "build_dir")
diff --git a/cmake/QtBuildInternals/QtStandaloneTestTemplateProject/Main.cmake b/cmake/QtBuildInternals/QtStandaloneTestTemplateProject/Main.cmake
new file mode 100644
index 0000000000..bd0984f314
--- /dev/null
+++ b/cmake/QtBuildInternals/QtStandaloneTestTemplateProject/Main.cmake
@@ -0,0 +1,27 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+# Includes QtSetup and friends for private CMake API.
+set(QT_INTERNAL_IS_STANDALONE_TEST TRUE)
+qt_internal_project_setup()
+qt_build_internals_set_up_private_api()
+
+# Find all StandaloneTestsConfig.cmake files, and include them
+# This will find all Qt packages that are required for standalone tests.
+# It will find more packages that needed for a certain test, but will ensure any test can
+# be built.
+qt_get_standalone_parts_config_files_path(standalone_parts_config_path)
+
+file(GLOB config_files "${standalone_parts_config_path}/*")
+foreach(file ${config_files})
+ include("${file}")
+endforeach()
+
+# Set language standards after finding Core, because that's when the relevant
+# feature variables are available.
+qt_set_language_standards()
+
+# Just before adding the test, change the local (non-cache) install prefix to something other than
+# the Qt install prefix, so that tests don't try to install and pollute the Qt install prefix.
+# Needs to be called after qt_get_standalone_parts_config_files_path().
+qt_internal_set_up_fake_standalone_parts_install_prefix()
diff --git a/cmake/QtBuildInternalsExtra.cmake.in b/cmake/QtBuildInternalsExtra.cmake.in
index 5f58d4e79f..8985f8178a 100644
--- a/cmake/QtBuildInternalsExtra.cmake.in
+++ b/cmake/QtBuildInternalsExtra.cmake.in
@@ -1,3 +1,6 @@
+# Copyright (C) 2024 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Propagate common variables via BuildInternals package.
set(QT_BUILD_SHARED_LIBS @BUILD_SHARED_LIBS@)
option(BUILD_SHARED_LIBS "Build Qt statically or dynamically" @BUILD_SHARED_LIBS@)
@@ -13,6 +16,24 @@ get_filename_component(QT_BUILD_INTERNALS_RELOCATABLE_INSTALL_PREFIX
${CMAKE_CURRENT_LIST_DIR}/../@qt_path_from_cmake_config_dir_to_prefix@
ABSOLUTE)
+# Stores in out_var the new install/staging prefix for this build.
+#
+# new_prefix: the new prefix for this repository
+# orig_prefix: the prefix that was used when qtbase was configured
+#
+# On Windows hosts: if the original prefix does not start with a drive letter, this function removes
+# the drive letter from the new prefix. This is needed for installation with DESTDIR set.
+function(qt_internal_new_prefix out_var new_prefix orig_prefix)
+ if(CMAKE_HOST_WIN32)
+ set(drive_letter_regexp "^[a-zA-Z]:")
+ if(new_prefix MATCHES "${drive_letter_regexp}"
+ AND NOT orig_prefix MATCHES "${drive_letter_regexp}")
+ string(SUBSTRING "${new_prefix}" 2 -1 new_prefix)
+ endif()
+ endif()
+ set(${out_var} "${new_prefix}" PARENT_SCOPE)
+endfunction()
+
# If no explicit CMAKE_INSTALL_PREFIX is provided, force set the original Qt installation prefix,
# so that further modules / repositories are installed into same original location.
# This means by default when configuring qtsvg / qtdeclarative, they will be installed the regular
@@ -20,10 +41,31 @@ get_filename_component(QT_BUILD_INTERNALS_RELOCATABLE_INSTALL_PREFIX
# If an explicit installation prefix is specified, honor it.
# This is an attempt to support Conan, aka handle installation of modules into a
# different installation prefix than the original one. Also allow to opt out via a special variable.
+# In a top-level build, QtSetup.cmake takes care of setting CMAKE_INSTALL_PREFIX.
if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT AND
- NOT QT_BUILD_INTERNALS_NO_FORCE_SET_INSTALL_PREFIX)
- set(CMAKE_INSTALL_PREFIX "@CMAKE_INSTALL_PREFIX@" CACHE PATH
+ NOT QT_BUILD_INTERNALS_NO_FORCE_SET_INSTALL_PREFIX
+ AND NOT QT_SUPERBUILD)
+ set(qtbi_orig_prefix "@CMAKE_INSTALL_PREFIX@")
+ set(qtbi_orig_staging_prefix "@CMAKE_STAGING_PREFIX@")
+ qt_internal_new_prefix(qtbi_new_prefix
+ "${QT_BUILD_INTERNALS_RELOCATABLE_INSTALL_PREFIX}"
+ "${qtbi_orig_prefix}")
+ if(NOT qtbi_orig_staging_prefix STREQUAL ""
+ AND "${CMAKE_STAGING_PREFIX}" STREQUAL ""
+ AND NOT QT_BUILD_INTERNALS_NO_FORCE_SET_STAGING_PREFIX)
+ qt_internal_new_prefix(qtbi_new_staging_prefix
+ "${qtbi_new_prefix}"
+ "${qtbi_orig_staging_prefix}")
+ set(CMAKE_STAGING_PREFIX "${qtbi_new_staging_prefix}" CACHE PATH
+ "Staging path prefix, prepended onto install directories on the host machine." FORCE)
+ set(qtbi_new_prefix "${qtbi_orig_prefix}")
+ endif()
+ set(CMAKE_INSTALL_PREFIX "${qtbi_new_prefix}" CACHE PATH
"Install path prefix, prepended onto install directories." FORCE)
+ unset(qtbi_orig_prefix)
+ unset(qtbi_new_prefix)
+ unset(qtbi_orig_staging_prefix)
+ unset(qtbi_new_staging_prefix)
endif()
# Propagate developer builds to other modules via BuildInternals package.
@@ -39,15 +81,59 @@ set(QT_SOURCE_TREE "@QT_SOURCE_TREE@" CACHE PATH
"A path to the source tree of the previously configured QtBase project." FORCE)
# Propagate decision of building tests and examples to other repositories.
-set(BUILD_TESTING @BUILD_TESTING@ CACHE BOOL "Build the testing tree.")
-set(BUILD_EXAMPLES @BUILD_EXAMPLES@ CACHE BOOL "Build Qt examples")
-set(QT_NO_MAKE_TESTS @QT_NO_MAKE_TESTS@ CACHE BOOL
+set(QT_BUILD_TESTS @QT_BUILD_TESTS@ CACHE BOOL "Build the testing tree.")
+set(QT_BUILD_EXAMPLES @QT_BUILD_EXAMPLES@ CACHE BOOL "Build Qt examples")
+set(QT_BUILD_BENCHMARKS @QT_BUILD_BENCHMARKS@ CACHE BOOL "Build Qt Benchmarks")
+set(QT_BUILD_MANUAL_TESTS @QT_BUILD_MANUAL_TESTS@ CACHE BOOL "Build Qt manual tests")
+set(QT_BUILD_MINIMAL_STATIC_TESTS @QT_BUILD_MINIMAL_STATIC_TESTS@ CACHE BOOL
+ "Build minimal subset of tests for static Qt builds")
+set(QT_BUILD_MINIMAL_ANDROID_MULTI_ABI_TESTS @QT_BUILD_MINIMAL_ANDROID_MULTI_ABI_TESTS@ CACHE BOOL
+ "Build minimal subset of tests for Android multi-ABI Qt builds")
+
+set(QT_BUILD_TESTS_BATCHED @QT_BUILD_TESTS_BATCHED@ CACHE BOOL
+ "Should all tests be batched into a single binary.")
+
+set(QT_BUILD_TESTS_BY_DEFAULT @QT_BUILD_TESTS_BY_DEFAULT@ CACHE BOOL
"Should tests be built as part of the default 'all' target.")
-set(QT_NO_MAKE_EXAMPLES @QT_NO_MAKE_EXAMPLES@ CACHE BOOL
+set(QT_BUILD_EXAMPLES_BY_DEFAULT @QT_BUILD_EXAMPLES_BY_DEFAULT@ CACHE BOOL
"Should examples be built as part of the default 'all' target.")
+set(QT_BUILD_TOOLS_BY_DEFAULT @QT_BUILD_TOOLS_BY_DEFAULT@ CACHE BOOL
+ "Should tools be built as part of the default 'all' target.")
+
+set(QT_BUILD_EXAMPLES_AS_EXTERNAL "@QT_BUILD_EXAMPLES_AS_EXTERNAL@" CACHE BOOL
+ "Should examples be built as ExternalProjects.")
# Propagate usage of ccache.
set(QT_USE_CCACHE @QT_USE_CCACHE@ CACHE BOOL "Enable the use of ccache")
+# Propagate usage of vcpkg, ON by default.
+set(QT_USE_VCPKG @QT_USE_VCPKG@ CACHE BOOL "Enable the use of vcpkg")
+
+# Propagate usage of unity build.
+set(QT_UNITY_BUILD @QT_UNITY_BUILD@ CACHE BOOL "Enable unity (jumbo) build")
+set(QT_UNITY_BUILD_BATCH_SIZE "@QT_UNITY_BUILD_BATCH_SIZE@" CACHE STRING "Unity build batch size")
+
+# Propragate the value of WARNINGS_ARE_ERRORS.
+set(WARNINGS_ARE_ERRORS "@WARNINGS_ARE_ERRORS@" CACHE BOOL "Build Qt with warnings as errors")
+
+# Propagate usage of versioned hard link.
+set(QT_CREATE_VERSIONED_HARD_LINK "@QT_CREATE_VERSIONED_HARD_LINK@" CACHE BOOL
+ "Enable the use of versioned hard link")
+
+# The minimum version required to build Qt.
+set(QT_SUPPORTED_MIN_CMAKE_VERSION_FOR_BUILDING_QT "@supported_min_version_for_building_qt@")
+set(QT_COMPUTED_MIN_CMAKE_VERSION_FOR_BUILDING_QT "@computed_min_version_for_building_qt@")
+
+# The lower and upper CMake version policy range as computed by qtbase.
+# These values are inherited when building other Qt repositories, unless overridden
+# in the respective repository .cmake.conf file.
+# These are not cache variables, so that they can be overridden in each repo directory scope.
+if(NOT DEFINED QT_MIN_NEW_POLICY_CMAKE_VERSION)
+ set(QT_MIN_NEW_POLICY_CMAKE_VERSION "@min_new_policy_version@")
+endif()
+if(NOT DEFINED QT_MAX_NEW_POLICY_CMAKE_VERSION)
+ set(QT_MAX_NEW_POLICY_CMAKE_VERSION "@max_new_policy_version@")
+endif()
+
# Extra set of exported variables
@QT_EXTRA_BUILD_INTERNALS_VARS@
diff --git a/cmake/QtBuildOptionsHelpers.cmake b/cmake/QtBuildOptionsHelpers.cmake
new file mode 100644
index 0000000000..3879920f65
--- /dev/null
+++ b/cmake/QtBuildOptionsHelpers.cmake
@@ -0,0 +1,383 @@
+# Copyright (C) 2023 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+# Try to detect if CMAKE_BUILD_TYPE is default initialized by CMake, or it was set by the user.
+#
+# CMake initializes CMAKE_BUILD_TYPE to the value of CMAKE_BUILD_TYPE_INIT during the first
+# project() call if CMAKE_BUILD_TYPE is empty.
+#
+# Unfortunately on most Windows platforms, it defaults to 'Debug', so we can't differentiate
+# between a 'Debug' value set on the command line by the user, a value set by the project, or if it
+# was default initialized.
+# We need to rely on heuristics to determine that.
+#
+# We try to check the value of CMAKE_BUILD_TYPE before the first project() call by inspecting
+# various variables:
+# 1) When using a qt.toolchain.cmake file, we rely on the toolchain file to tell us
+# if a value was set by the user at initial configure time via the
+# __qt_toolchain_cmake_build_type_before_project_call variable. On a 2nd run there will
+# always be a value in the cache, but at that point we've already set it to whatever it needs
+# to be.
+# 2) Whe configuring qtbase, a top-level qt, or a standalone project we rely on one of the following
+# variables being set:
+# - __qt_auto_detect_cmake_build_type_before_project_call (e.g for qtbase)
+# - __qt_internal_standalone_project_cmake_build_type_before_project_call (e.g for sqldrivers)
+# 3) When using a multi-config generator, we assume that the CMAKE_BUILD_TYPE is not default
+# initialized.
+# 4) The user can also force the build type to be considered non-default-initialized by setting
+# QT_NO_FORCE_SET_CMAKE_BUILD_TYPE to TRUE. It has weird naming that doesn't quite correspond
+# to the meaning, but it's been called like that for a while now and I'm hesitant to change
+# the name in case it's used by various projects.
+#
+# The code doesn't handle an empty "" config set by the user, but we claim that's an
+# unsupported config when building Qt.
+function(qt_internal_is_cmake_build_type_default_initialized_heuristic out_var)
+ get_property(is_multi_config GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
+ get_cmake_property(aready_force_set _qt_build_internals_cmake_build_type_set)
+
+ if(
+ # Set by CMake's Platform/Windows-MSVC.cmake when CMAKE_BUILD_TYPE is empty
+ # The STREQUAL check needs to have expanded variables because an undefined var is not equal
+ # to an empty defined var.
+ "${CMAKE_BUILD_TYPE}" STREQUAL "${CMAKE_BUILD_TYPE_INIT}"
+
+ # Set by qt_internal_force_set_cmake_build_type()
+ AND aready_force_set MATCHES "NOTFOUND"
+
+ # Set by qt_auto_detect_cmake_build_type()
+ AND NOT __qt_auto_detect_cmake_build_type_before_project_call
+
+ # Set by sqldrivers project
+ AND NOT __qt_internal_standalone_project_cmake_build_type_before_project_call
+
+ # Set by qt.toolchain.cmake
+ AND NOT __qt_toolchain_cmake_build_type_before_project_call
+
+ # Set by user explicitily
+ AND NOT QT_NO_FORCE_SET_CMAKE_BUILD_TYPE
+
+ # Set in multi-config builds
+ AND NOT is_multi_config)
+
+ set(${out_var} TRUE PARENT_SCOPE)
+ else()
+ set(${out_var} FALSE PARENT_SCOPE)
+ endif()
+endfunction()
+
+function(qt_internal_force_set_cmake_build_type value)
+ cmake_parse_arguments(PARSE_ARGV 1 arg
+ "SHOW_MESSAGE"
+ ""
+ ""
+ )
+ _qt_internal_validate_all_args_are_parsed(arg)
+
+ set(CMAKE_BUILD_TYPE "${value}" CACHE STRING "Choose the type of build." FORCE)
+ set_property(CACHE CMAKE_BUILD_TYPE
+ PROPERTY STRINGS
+ "Debug" "Release" "MinSizeRel" "RelWithDebInfo") # Set the possible values for cmake-gui.
+ if(arg_SHOW_MESSAGE)
+ message(STATUS "Force setting build type to '${value}'.")
+ endif()
+ set_property(GLOBAL PROPERTY _qt_build_internals_cmake_build_type_set "${value}")
+endfunction()
+
+# Only override the build type if it was default initialized by CMake.
+function(qt_internal_force_set_cmake_build_type_if_cmake_default_initialized value)
+ qt_internal_is_cmake_build_type_default_initialized_heuristic(is_default_cmake_build_type)
+ if(is_default_cmake_build_type)
+ qt_internal_force_set_cmake_build_type("${value}" SHOW_MESSAGE)
+ endif()
+endfunction()
+
+function(qt_internal_set_cmake_build_type)
+ # When building standalone tests against a multi-config Qt, we want to configure the
+ # tests / examples with
+ # the first multi-config configuration, rather than use CMake's default configuration.
+ # In the case of Windows, we definitely don't want it to default to Debug, because that causes
+ # issues in the CI.
+ if(QT_INTERNAL_BUILD_STANDALONE_PARTS AND QT_MULTI_CONFIG_FIRST_CONFIG)
+ qt_internal_force_set_cmake_build_type_if_cmake_default_initialized(
+ "${QT_MULTI_CONFIG_FIRST_CONFIG}")
+
+ # We want the same build type to be used when configuring all Qt repos or standalone
+ # tests or single tests, so we reuse the initial build type set by qtbase.
+ # __qt_internal_initial_qt_cmake_build_type is saved in QtBuildInternalsExtra.cmake.in.
+ elseif(__qt_internal_initial_qt_cmake_build_type)
+ qt_internal_force_set_cmake_build_type_if_cmake_default_initialized(
+ "${__qt_internal_initial_qt_cmake_build_type}")
+
+ # Default to something sensible when configuring qtbase / top-level.
+ else()
+ qt_internal_set_qt_appropriate_default_cmake_build_type()
+ endif()
+endfunction()
+
+# Sets a default cmake build type for qtbase / top-level.
+macro(qt_internal_set_qt_appropriate_default_cmake_build_type)
+ set(_default_build_type "Release")
+ if(FEATURE_developer_build)
+ set(_default_build_type "Debug")
+ endif()
+
+ qt_internal_is_cmake_build_type_default_initialized_heuristic(is_default_cmake_build_type)
+ if(is_default_cmake_build_type)
+ qt_internal_force_set_cmake_build_type("${_default_build_type}")
+ message(STATUS "Setting build type to '${_default_build_type}' as none was specified.")
+ elseif(CMAKE_CONFIGURATION_TYPES)
+ message(STATUS "Building for multiple configurations: ${CMAKE_CONFIGURATION_TYPES}.")
+ message(STATUS "Main configuration is: ${QT_MULTI_CONFIG_FIRST_CONFIG}.")
+ if(CMAKE_NINJA_MULTI_DEFAULT_BUILD_TYPE)
+ message(STATUS
+ "Default build configuration set to '${CMAKE_NINJA_MULTI_DEFAULT_BUILD_TYPE}'.")
+ endif()
+ if(CMAKE_GENERATOR STREQUAL "Ninja")
+ message(FATAL_ERROR
+ "It's not possible to build multiple configurations with the single config Ninja "
+ "generator. Consider configuring with -G\"Ninja Multi-Config\" instead of -GNinja."
+ )
+ endif()
+ else()
+ message(STATUS "CMAKE_BUILD_TYPE was already explicitly set to: '${CMAKE_BUILD_TYPE}'")
+ endif()
+endmacro()
+
+macro(qt_internal_set_configure_from_ide)
+ # QT_INTERNAL_CONFIGURE_FROM_IDE is set to TRUE for the following known IDE applications:
+ # - Qt Creator, detected by QTC_RUN environment variable
+ # - CLion, detected by CLION_IDE environment variable
+ # - Visual Studio Code, detected by VSCODE_CLI environment variable
+ if("$ENV{QTC_RUN}" OR "$ENV{CLION_IDE}" OR "$ENV{VSCODE_CLI}")
+ set(QT_INTERNAL_CONFIGURE_FROM_IDE TRUE CACHE INTERNAL "Configuring Qt Project from IDE")
+ else()
+ set(QT_INTERNAL_CONFIGURE_FROM_IDE FALSE CACHE INTERNAL "Configuring Qt Project from IDE")
+ endif()
+endmacro()
+
+macro(qt_internal_set_sync_headers_at_configure_time)
+ set(_qt_sync_headers_at_configure_time_default ${QT_INTERNAL_CONFIGURE_FROM_IDE})
+
+ if(FEATURE_developer_build)
+ # Sync headers during the initial configuration of a -developer-build to facilitate code
+ # navigation for code editors that use an LSP-based code model.
+ set(_qt_sync_headers_at_configure_time_default TRUE)
+ endif()
+
+ # Sync Qt header files at configure time
+ option(QT_SYNC_HEADERS_AT_CONFIGURE_TIME "Run syncqt at configure time already"
+ ${_qt_sync_headers_at_configure_time_default})
+ unset(_qt_sync_headers_at_configure_time_default)
+
+ # In static Ninja Multi-Config builds the sync_headers dependencies(and other autogen
+ # dependencies are not added to '_autogen/timestamp' targets. See QTBUG-113974.
+ if(CMAKE_GENERATOR STREQUAL "Ninja Multi-Config" AND NOT QT_BUILD_SHARED_LIBS)
+ set(QT_SYNC_HEADERS_AT_CONFIGURE_TIME TRUE CACHE BOOL "" FORCE)
+ endif()
+endmacro()
+
+macro(qt_internal_set_export_compile_commands)
+ if(FEATURE_developer_build)
+ if(DEFINED QT_CMAKE_EXPORT_COMPILE_COMMANDS)
+ set(CMAKE_EXPORT_COMPILE_COMMANDS ${QT_CMAKE_EXPORT_COMPILE_COMMANDS})
+ else()
+ set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
+ endif()
+ endif()
+endmacro()
+
+macro(qt_internal_setup_build_benchmarks)
+ if(FEATURE_developer_build)
+ set(__build_benchmarks ON)
+
+ # Disable benchmarks for single configuration generators which do not build
+ # with release configuration.
+ if(CMAKE_BUILD_TYPE AND CMAKE_BUILD_TYPE STREQUAL Debug)
+ set(__build_benchmarks OFF)
+ endif()
+ else()
+ set(__build_benchmarks OFF)
+ endif()
+
+ # Build Benchmarks
+ option(QT_BUILD_BENCHMARKS "Build Qt Benchmarks" ${__build_benchmarks})
+endmacro()
+
+macro(qt_internal_setup_build_tests)
+ if(FEATURE_developer_build)
+ set(_qt_build_tests_default ON)
+
+ # Tests are not built by default with qmake for iOS and friends, and thus the overall build
+ # tends to fail. Disable them by default when targeting uikit.
+ if(UIKIT OR ANDROID)
+ set(_qt_build_tests_default OFF)
+ endif()
+ else()
+ set(_qt_build_tests_default OFF)
+ endif()
+
+ # If benchmarks are explicitly enabled, force tests to also be built, even if they might
+ # not work on the platform.
+ if(QT_BUILD_BENCHMARKS)
+ set(_qt_build_tests_default ON)
+ endif()
+
+ ## Set up testing
+ option(QT_BUILD_TESTS "Build the testing tree." ${_qt_build_tests_default})
+ unset(_qt_build_tests_default)
+ option(QT_BUILD_TESTS_BY_DEFAULT
+ "Should tests be built as part of the default 'all' target." ON)
+ if(QT_BUILD_STANDALONE_TESTS)
+ # BuildInternals might have set it to OFF on initial configuration. So force it to ON when
+ # building standalone tests.
+ set(QT_BUILD_TESTS ON CACHE BOOL "Build the testing tree." FORCE)
+
+ # Also force the tests to be built as part of the default build target.
+ set(QT_BUILD_TESTS_BY_DEFAULT ON CACHE BOOL
+ "Should tests be built as part of the default 'all' target." FORCE)
+ endif()
+ set(BUILD_TESTING ${QT_BUILD_TESTS} CACHE INTERNAL "")
+
+ if(WASM)
+ set(_qt_batch_tests ON)
+ else()
+ set(_qt_batch_tests OFF)
+ endif()
+
+ if(DEFINED INPUT_batch_tests)
+ if (${INPUT_batch_tests})
+ set(_qt_batch_tests ON)
+ else()
+ set(_qt_batch_tests OFF)
+ endif()
+ endif()
+
+ option(QT_BUILD_TESTS_BATCHED "Link all tests into a single binary." ${_qt_batch_tests})
+
+ if(QT_BUILD_TESTS AND QT_BUILD_TESTS_BATCHED AND CMAKE_VERSION VERSION_LESS "3.19")
+ message(FATAL_ERROR
+ "Test batching requires at least CMake 3.19, due to requiring per-source "
+ "TARGET_DIRECTORY assignments and DEFER calls.")
+ endif()
+
+ option(QT_BUILD_MANUAL_TESTS "Build Qt manual tests" OFF)
+
+ if(WASM AND _qt_batch_tests)
+ set(_qt_wasm_and_batch_tests ON)
+ else()
+ set(_qt_wasm_and_batch_tests OFF)
+ endif()
+
+ option(QT_BUILD_MINIMAL_STATIC_TESTS "Build minimal subset of tests for static Qt builds" ${_qt_wasm_and_batch_tests})
+
+ option(QT_BUILD_WASM_BATCHED_TESTS "Build subset of tests for wasm batched tests" ${_qt_wasm_and_batch_tests})
+
+ option(QT_BUILD_MINIMAL_ANDROID_MULTI_ABI_TESTS
+ "Build minimal subset of tests for Android multi-ABI Qt builds" OFF)
+
+ include(CTest)
+ enable_testing()
+endmacro()
+
+macro(qt_internal_setup_build_tools)
+ # QT_BUILD_TOOLS_WHEN_CROSSCOMPILING -> QT_FORCE_BUILD_TOOLS
+ # pre-6.4 compatibility flag (remove sometime in the future)
+ if(CMAKE_CROSSCOMPILING AND QT_BUILD_TOOLS_WHEN_CROSSCOMPILING)
+ message(WARNING "QT_BUILD_TOOLS_WHEN_CROSSCOMPILING is deprecated. "
+ "Please use QT_FORCE_BUILD_TOOLS instead.")
+ set(QT_FORCE_BUILD_TOOLS TRUE CACHE INTERNAL "" FORCE)
+ endif()
+
+ # When cross-building, we don't build tools by default. Sometimes this also covers Qt apps as
+ # well. Like in qttools/assistant/assistant.pro, load(qt_app), which is guarded by a
+ # qtNomakeTools() call.
+ set(_qt_build_tools_by_default_default ON)
+ if(CMAKE_CROSSCOMPILING AND NOT QT_FORCE_BUILD_TOOLS)
+ set(_qt_build_tools_by_default_default OFF)
+ endif()
+ option(QT_BUILD_TOOLS_BY_DEFAULT "Should tools be built as part of the default 'all' target."
+ "${_qt_build_tools_by_default_default}")
+ unset(_qt_build_tools_by_default_default)
+endmacro()
+
+macro(qt_internal_setup_build_examples)
+ option(QT_BUILD_EXAMPLES "Build Qt examples" OFF)
+ option(QT_BUILD_EXAMPLES_BY_DEFAULT
+ "Should examples be built as part of the default 'all' target." ON)
+ option(QT_INSTALL_EXAMPLES_SOURCES "Install example sources" OFF)
+ option(QT_INSTALL_EXAMPLES_SOURCES_BY_DEFAULT
+ "Install example sources as part of the default 'install' target" ON)
+
+ # We need a way to force disable building in-tree examples in the CI, so that we instead build
+ # standalone examples. Because the Coin yaml instructions don't allow us to remove
+ # -make examples from from the configure args, we instead read a variable that only Coin sets.
+ if(QT_INTERNAL_CI_NO_BUILD_IN_TREE_EXAMPLES)
+ set(QT_BUILD_EXAMPLES OFF CACHE BOOL "Build Qt examples" FORCE)
+ endif()
+
+ if(QT_BUILD_STANDALONE_EXAMPLES)
+ # BuildInternals might have set it to OFF on initial configuration. So force it to ON when
+ # building standalone examples.
+ set(QT_BUILD_EXAMPLES ON CACHE BOOL "Build Qt examples" FORCE)
+
+ # Also force the examples to be built as part of the default build target.
+ set(QT_BUILD_EXAMPLES_BY_DEFAULT ON CACHE BOOL
+ "Should examples be built as part of the default 'all' target." FORCE)
+ endif()
+
+ option(QT_DEPLOY_MINIMAL_EXAMPLES
+ "Deploy minimal subset of examples to save time and space" OFF)
+
+ # FIXME: Support prefix builds as well QTBUG-96232
+ # We don't want to enable EP examples with -debug-and-release because starting with CMake 3.24
+ # ExternalProject_Add ends up creating build rules twice, once for each configuration, in the
+ # same build dir, which ends up causing various issues due to concurrent builds as well as
+ # clobbered CMakeCache.txt and ninja files.
+ if(QT_WILL_INSTALL OR QT_FEATURE_debug_and_release)
+ set(_qt_build_examples_as_external OFF)
+ else()
+ set(_qt_build_examples_as_external ON)
+ endif()
+ option(QT_BUILD_EXAMPLES_AS_EXTERNAL "Should examples be built as ExternalProjects."
+ ${_qt_build_examples_as_external})
+ unset(_qt_build_examples_as_external)
+endmacro()
+
+macro(qt_internal_set_qt_host_path)
+ ## Path used to find host tools, either when cross-compiling or just when using the tools from
+ ## a different host build.
+ set(QT_HOST_PATH "$ENV{QT_HOST_PATH}" CACHE PATH
+ "Installed Qt host directory path, used for cross compiling.")
+endmacro()
+
+macro(qt_internal_set_use_ccache)
+ option(QT_USE_CCACHE "Enable the use of ccache")
+ if(QT_USE_CCACHE)
+ find_program(CCACHE_PROGRAM ccache)
+ if(CCACHE_PROGRAM)
+ set(CMAKE_C_COMPILER_LAUNCHER "${CCACHE_PROGRAM}")
+ set(CMAKE_CXX_COMPILER_LAUNCHER "${CCACHE_PROGRAM}")
+ set(CMAKE_OBJC_COMPILER_LAUNCHER "${CCACHE_PROGRAM}")
+ set(CMAKE_OBJCXX_COMPILER_LAUNCHER "${CCACHE_PROGRAM}")
+ else()
+ message(FATAL_ERROR "Ccache use was requested, but the program was not found.")
+ endif()
+ endif()
+endmacro()
+
+macro(qt_internal_set_unity_build)
+ option(QT_UNITY_BUILD "Enable unity (jumbo) build")
+ set(QT_UNITY_BUILD_BATCH_SIZE "32" CACHE STRING "Unity build batch size")
+ if(QT_UNITY_BUILD)
+ set(CMAKE_UNITY_BUILD ON)
+ set(CMAKE_UNITY_BUILD_BATCH_SIZE "${QT_UNITY_BUILD_BATCH_SIZE}")
+ endif()
+endmacro()
+
+macro(qt_internal_set_allow_symlink_in_paths)
+ option(QT_ALLOW_SYMLINK_IN_PATHS "Allows symlinks in paths." OFF)
+endmacro()
+
+macro(qt_internal_set_qt_allow_download)
+ option(QT_ALLOW_DOWNLOAD "Allows files to be downloaded when building Qt." OFF)
+endmacro()
diff --git a/cmake/QtBuildPathsHelpers.cmake b/cmake/QtBuildPathsHelpers.cmake
new file mode 100644
index 0000000000..6431fa1937
--- /dev/null
+++ b/cmake/QtBuildPathsHelpers.cmake
@@ -0,0 +1,247 @@
+# Copyright (C) 2023 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+macro(qt_internal_setup_default_install_prefix)
+ # Detect non-prefix builds: either when the qtbase install prefix is set to the binary dir
+ # or when a developer build is explicitly enabled and no install prefix (or staging prefix)
+ # is specified.
+ # This detection only happens when building qtbase, and later is propagated via the generated
+ # QtBuildInternalsExtra.cmake file.
+ if(PROJECT_NAME STREQUAL "QtBase" AND NOT QT_INTERNAL_BUILD_STANDALONE_PARTS)
+ if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
+ # Handle both FEATURE_ and QT_FEATURE_ cases when they are specified on the command line
+ # explicitly. It's possible for one to be set, but not the other, because
+ # qtbase/configure.cmake is not processed by this point.
+ if((FEATURE_developer_build
+ OR QT_FEATURE_developer_build
+ OR FEATURE_no_prefix
+ OR QT_FEATURE_no_prefix
+ )
+ AND NOT CMAKE_STAGING_PREFIX)
+ # Handle non-prefix builds by setting the CMake install prefix to point to qtbase's
+ # build dir. While building another repo (like qtsvg) the CMAKE_PREFIX_PATH should
+ # be set on the command line to point to the qtbase build dir.
+ set(__qt_default_prefix "${QtBase_BINARY_DIR}")
+ else()
+ if(CMAKE_HOST_WIN32)
+ set(__qt_default_prefix "C:/Qt/")
+ else()
+ set(__qt_default_prefix "/usr/local/")
+ endif()
+ string(APPEND __qt_default_prefix
+ "Qt-${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}")
+ endif()
+ set(CMAKE_INSTALL_PREFIX ${__qt_default_prefix} CACHE PATH
+ "Install path prefix, prepended onto install directories." FORCE)
+ unset(__qt_default_prefix)
+ endif()
+ if(CMAKE_STAGING_PREFIX)
+ set(__qt_prefix "${CMAKE_STAGING_PREFIX}")
+ else()
+ set(__qt_prefix "${CMAKE_INSTALL_PREFIX}")
+ endif()
+ if(__qt_prefix STREQUAL QtBase_BINARY_DIR)
+ set(__qt_will_install_value OFF)
+ else()
+ set(__qt_will_install_value ON)
+ endif()
+ set(QT_WILL_INSTALL ${__qt_will_install_value} CACHE BOOL
+ "Boolean indicating if doing a Qt prefix build (vs non-prefix build)." FORCE)
+ unset(__qt_prefix)
+ unset(__qt_will_install_value)
+ endif()
+endmacro()
+
+function(qt_internal_setup_build_and_install_paths)
+ # Compute the values of QT_BUILD_DIR, QT_INSTALL_DIR, QT_CONFIG_BUILD_DIR, QT_CONFIG_INSTALL_DIR
+ # taking into account whether the current build is a prefix build or a non-prefix build,
+ # and whether it is a superbuild or non-superbuild.
+ # A third case is when another module or standalone tests/examples are built against a
+ # super-built Qt.
+ # The layout for the third case is the same as for non-superbuilds.
+ #
+ # These values should be prepended to file paths in commands or properties,
+ # in order to correctly place generated Config files, generated Targets files,
+ # executables / libraries, when copying / installing files, etc.
+ #
+ # The build dir variables will always be absolute paths.
+ # The QT_INSTALL_DIR variable will have a relative path in a prefix build,
+ # which means that it can be empty, so use qt_join_path to prevent accidental absolute paths.
+ if(QT_SUPERBUILD)
+ # In this case, we always copy all the build products in qtbase/{bin,lib,...}
+ if(QT_WILL_INSTALL)
+ set(QT_BUILD_DIR "${QtBase_BINARY_DIR}")
+ set(QT_INSTALL_DIR "")
+ else()
+ if("${CMAKE_STAGING_PREFIX}" STREQUAL "")
+ set(QT_BUILD_DIR "${QtBase_BINARY_DIR}")
+ set(QT_INSTALL_DIR "${QtBase_BINARY_DIR}")
+ else()
+ set(QT_BUILD_DIR "${CMAKE_STAGING_PREFIX}")
+ set(QT_INSTALL_DIR "${CMAKE_STAGING_PREFIX}")
+ endif()
+ endif()
+ else()
+ if(QT_WILL_INSTALL)
+ # In the usual prefix build case, the build dir is the current module build dir,
+ # and the install dir is the prefix, so we don't set it.
+ set(QT_BUILD_DIR "${CMAKE_BINARY_DIR}")
+ set(QT_INSTALL_DIR "")
+ else()
+ # When doing a non-prefix build, both the build dir and install dir are the same,
+ # pointing to the qtbase build dir.
+ set(QT_BUILD_DIR "${QT_STAGING_PREFIX}")
+ set(QT_INSTALL_DIR "${QT_BUILD_DIR}")
+ endif()
+ endif()
+
+ set(__config_path_part "${INSTALL_LIBDIR}/cmake")
+ set(QT_CONFIG_BUILD_DIR "${QT_BUILD_DIR}/${__config_path_part}")
+ set(QT_CONFIG_INSTALL_DIR "${QT_INSTALL_DIR}")
+ if(QT_CONFIG_INSTALL_DIR)
+ string(APPEND QT_CONFIG_INSTALL_DIR "/")
+ endif()
+ string(APPEND QT_CONFIG_INSTALL_DIR ${__config_path_part})
+
+ set(QT_BUILD_DIR "${QT_BUILD_DIR}" PARENT_SCOPE)
+ set(QT_INSTALL_DIR "${QT_INSTALL_DIR}" PARENT_SCOPE)
+ set(QT_CONFIG_BUILD_DIR "${QT_CONFIG_BUILD_DIR}" PARENT_SCOPE)
+ set(QT_CONFIG_INSTALL_DIR "${QT_CONFIG_INSTALL_DIR}" PARENT_SCOPE)
+endfunction()
+
+function(qt_configure_process_path name default docstring)
+ # Values are computed once for qtbase, and then exported and reused for other projects.
+ if(NOT PROJECT_NAME STREQUAL "QtBase")
+ return()
+ endif()
+
+ # No value provided, set the default.
+ if(NOT DEFINED "${name}")
+ set("${name}" "${default}" CACHE STRING "${docstring}")
+ else()
+ get_filename_component(given_path_as_abs "${${name}}" ABSOLUTE BASE_DIR
+ "${CMAKE_INSTALL_PREFIX}")
+ file(RELATIVE_PATH rel_path "${CMAKE_INSTALL_PREFIX}"
+ "${given_path_as_abs}")
+
+ # If absolute path given, check that it's inside the prefix (error out if not).
+ # TODO: Figure out if we need to support paths that are outside the prefix.
+ #
+ # If relative path given, it's relative to the install prefix (rather than the binary dir,
+ # which is what qmake does for some reason).
+ # In both cases, store the value as a relative path.
+ if("${rel_path}" STREQUAL "")
+ # file(RELATIVE_PATH) returns an empty string if the given absolute paths are equal
+ set(rel_path ".")
+ elseif(rel_path MATCHES "^\.\./")
+ # INSTALL_SYSCONFDIR is allowed to be outside the prefix.
+ if(NOT name STREQUAL "INSTALL_SYSCONFDIR")
+ message(FATAL_ERROR
+ "Path component '${name}' is outside computed install prefix: ${rel_path} ")
+ return()
+ endif()
+ set("${name}" "${${name}}" CACHE STRING "${docstring}" FORCE)
+ else()
+ set("${name}" "${rel_path}" CACHE STRING "${docstring}" FORCE)
+ endif()
+ endif()
+endfunction()
+
+macro(qt_internal_setup_configure_install_paths)
+ # Install locations:
+ qt_configure_process_path(INSTALL_BINDIR "bin" "Executables [PREFIX/bin]")
+ qt_configure_process_path(INSTALL_INCLUDEDIR "include" "Header files [PREFIX/include]")
+ qt_configure_process_path(INSTALL_LIBDIR "lib" "Libraries [PREFIX/lib]")
+ qt_configure_process_path(INSTALL_MKSPECSDIR "mkspecs" "Mkspecs files [PREFIX/mkspecs]")
+ qt_configure_process_path(INSTALL_ARCHDATADIR "." "Arch-dependent data [PREFIX]")
+ qt_configure_process_path(INSTALL_PLUGINSDIR
+ "${INSTALL_ARCHDATADIR}/plugins"
+ "Plugins [ARCHDATADIR/plugins]")
+
+ if(NOT INSTALL_MKSPECSDIR MATCHES "(^|/)mkspecs")
+ message(FATAL_ERROR "INSTALL_MKSPECSDIR must end with '/mkspecs'")
+ endif()
+
+ if (WIN32)
+ set(_default_libexec "${INSTALL_ARCHDATADIR}/bin")
+ else()
+ set(_default_libexec "${INSTALL_ARCHDATADIR}/libexec")
+ endif()
+
+ qt_configure_process_path(
+ INSTALL_LIBEXECDIR
+ "${_default_libexec}"
+ "Helper programs [ARCHDATADIR/bin on Windows, ARCHDATADIR/libexec otherwise]")
+ qt_configure_process_path(INSTALL_QMLDIR
+ "${INSTALL_ARCHDATADIR}/qml"
+ "QML imports [ARCHDATADIR/qml]")
+ qt_configure_process_path(INSTALL_DATADIR "." "Arch-independent data [PREFIX]")
+ qt_configure_process_path(INSTALL_DOCDIR "${INSTALL_DATADIR}/doc" "Documentation [DATADIR/doc]")
+ qt_configure_process_path(INSTALL_TRANSLATIONSDIR "${INSTALL_DATADIR}/translations"
+ "Translations [DATADIR/translations]")
+ if(APPLE)
+ set(QT_DEFAULT_SYS_CONF_DIR "/Library/Preferences/Qt")
+ else()
+ set(QT_DEFAULT_SYS_CONF_DIR "etc/xdg")
+ endif()
+ qt_configure_process_path(
+ INSTALL_SYSCONFDIR
+ "${QT_DEFAULT_SYS_CONF_DIR}"
+ "Settings used by Qt programs [PREFIX/etc/xdg]/[/Library/Preferences/Qt]")
+ qt_configure_process_path(INSTALL_EXAMPLESDIR "examples" "Examples [PREFIX/examples]")
+ qt_configure_process_path(INSTALL_TESTSDIR "tests" "Tests [PREFIX/tests]")
+ qt_configure_process_path(INSTALL_DESCRIPTIONSDIR
+ "${INSTALL_ARCHDATADIR}/modules"
+ "Module description files directory")
+endmacro()
+
+macro(qt_internal_set_cmake_install_libdir)
+ # Ensure that GNUInstallDirs's CMAKE_INSTALL_LIBDIR points to the same lib dir that Qt was
+ # configured with. Currently this is important for QML plugins, which embed an rpath based
+ # on that value.
+ set(CMAKE_INSTALL_LIBDIR "${INSTALL_LIBDIR}")
+endmacro()
+
+macro(qt_internal_set_qt_cmake_dir)
+ set(QT_CMAKE_DIR "${CMAKE_CURRENT_LIST_DIR}")
+endmacro()
+
+macro(qt_internal_set_qt_apple_support_files_path)
+ # This is analogous to what we have in QtConfig.cmake.in. It's copied here so that iOS
+ # tests can be built in tree.
+ if(APPLE)
+ if(NOT CMAKE_SYSTEM_NAME OR CMAKE_SYSTEM_NAME STREQUAL "Darwin")
+ set(__qt_internal_cmake_apple_support_files_path "${QT_CMAKE_DIR}/macos")
+ elseif(CMAKE_SYSTEM_NAME STREQUAL "iOS")
+ set(__qt_internal_cmake_apple_support_files_path "${QT_CMAKE_DIR}/ios")
+ elseif(CMAKE_SYSTEM_NAME STREQUAL "visionOS")
+ set(__qt_internal_cmake_apple_support_files_path "${QT_CMAKE_DIR}/visionos")
+ endif()
+ endif()
+endmacro()
+
+macro(qt_internal_set_qt_staging_prefix)
+ if(NOT "${CMAKE_STAGING_PREFIX}" STREQUAL "")
+ set(QT_STAGING_PREFIX "${CMAKE_STAGING_PREFIX}")
+ else()
+ set(QT_STAGING_PREFIX "${CMAKE_INSTALL_PREFIX}")
+ endif()
+endmacro()
+
+macro(qt_internal_setup_paths_and_prefixes)
+ qt_internal_setup_configure_install_paths()
+
+ qt_internal_set_qt_staging_prefix()
+
+ # Depends on QT_STAGING_PREFIX being set.
+ qt_internal_setup_build_and_install_paths()
+
+ qt_get_relocatable_install_prefix(QT_BUILD_INTERNALS_RELOCATABLE_INSTALL_PREFIX)
+
+ # Depends on INSTALL_LIBDIR being set.
+ qt_internal_set_cmake_install_libdir()
+
+ qt_internal_set_qt_cmake_dir()
+
+ qt_internal_set_qt_apple_support_files_path()
+endmacro()
diff --git a/cmake/QtBuildRepoExamplesHelpers.cmake b/cmake/QtBuildRepoExamplesHelpers.cmake
new file mode 100644
index 0000000000..6802d81323
--- /dev/null
+++ b/cmake/QtBuildRepoExamplesHelpers.cmake
@@ -0,0 +1,652 @@
+# Copyright (C) 2023 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+macro(qt_examples_build_begin)
+ set(options EXTERNAL_BUILD)
+ set(singleOpts "")
+ set(multiOpts DEPENDS)
+
+ cmake_parse_arguments(arg "${options}" "${singleOpts}" "${multiOpts}" ${ARGN})
+
+ # Examples are not unity-ready.
+ set(CMAKE_UNITY_BUILD OFF)
+
+ # Skip running deployment steps when the developer asked to deploy a minimal subset of examples.
+ # Each example can then decide whether it wants to be deployed as part of the minimal subset
+ # by unsetting the QT_INTERNAL_SKIP_DEPLOYMENT variable before its qt_internal_add_example call.
+ # This will be used by our CI.
+ if(NOT DEFINED QT_INTERNAL_SKIP_DEPLOYMENT AND QT_DEPLOY_MINIMAL_EXAMPLES)
+ set(QT_INTERNAL_SKIP_DEPLOYMENT TRUE)
+ endif()
+
+ # Use by qt_internal_add_example.
+ set(QT_EXAMPLE_BASE_DIR "${CMAKE_CURRENT_SOURCE_DIR}")
+
+ if(QT_BUILD_STANDALONE_EXAMPLES)
+ # Find all qt packages, so that the various if(QT_FEATURE_foo) add_subdirectory()
+ # conditions have correct values, regardless whether we will use ExternalProjects or not.
+ qt_internal_find_standalone_parts_config_files()
+ endif()
+
+ if(arg_EXTERNAL_BUILD AND QT_BUILD_EXAMPLES_AS_EXTERNAL)
+ # Examples will be built using ExternalProject.
+ # We depend on all plugins built as part of the current repo as well as current repo's
+ # dependencies plugins, to prevent opportunities for
+ # weird errors associated with loading out-of-date plugins from
+ # unrelated Qt modules.
+ # We also depend on all targets from this repo's src and tools subdirectories
+ # to ensure that we've built anything that a find_package() call within
+ # an example might use. Projects can add further dependencies if needed,
+ # but that should rarely be necessary.
+ set(QT_EXAMPLE_DEPENDENCIES ${qt_repo_plugins_recursive} ${arg_DEPENDS})
+
+ if(TARGET ${qt_repo_targets_name}_src)
+ list(APPEND QT_EXAMPLE_DEPENDENCIES ${qt_repo_targets_name}_src_for_examples)
+ endif()
+
+ if(TARGET ${qt_repo_targets_name}_tools)
+ list(APPEND QT_EXAMPLE_DEPENDENCIES ${qt_repo_targets_name}_tools)
+ endif()
+
+ set(QT_IS_EXTERNAL_EXAMPLES_BUILD TRUE)
+
+ string(TOLOWER ${PROJECT_NAME} project_name_lower)
+ if(NOT TARGET examples)
+ if(QT_BUILD_EXAMPLES_BY_DEFAULT)
+ add_custom_target(examples ALL)
+ else()
+ add_custom_target(examples)
+ endif()
+ endif()
+ if(NOT TARGET examples_${project_name_lower})
+ add_custom_target(examples_${project_name_lower})
+ add_dependencies(examples examples_${project_name_lower})
+ endif()
+
+ include(ExternalProject)
+ else()
+ # This repo has not yet been updated to build examples in a separate
+ # build from this main build, or we can't use that arrangement yet.
+ # Build them directly as part of the main build instead for backward
+ # compatibility.
+ if(NOT BUILD_SHARED_LIBS)
+ # Ordinarily, it would be an error to call return() from within a
+ # macro(), but in this case we specifically want to return from the
+ # caller's scope if we are doing a static build and the project
+ # isn't building examples in a separate build from the main build.
+ # Configuring static builds requires tools that are not available
+ # until build time.
+ return()
+ endif()
+
+ if(NOT QT_BUILD_EXAMPLES_BY_DEFAULT)
+ set_directory_properties(PROPERTIES EXCLUDE_FROM_ALL TRUE)
+ endif()
+ endif()
+
+ # TODO: Change this to TRUE when all examples in all repos are ported to use
+ # qt_internal_add_example.
+ # We shouldn't need to call qt_internal_set_up_build_dir_package_paths when
+ # QT_IS_EXTERNAL_EXAMPLES_BUILD is TRUE.
+ # Due to not all examples being ported, if we don't
+ # call qt_internal_set_up_build_dir_package_paths -> set(QT_NO_CREATE_TARGETS TRUE) we'll get
+ # CMake configuration errors saying we redefine Qt targets because we both build them and find
+ # them as part of find_package.
+ set(__qt_all_examples_ported_to_external_projects FALSE)
+
+ # Examples that are built as part of the Qt build need to use the CMake config files from the
+ # build dir, because they are not installed yet in a prefix build.
+ # Prepending to CMAKE_PREFIX_PATH helps find the initial Qt6Config.cmake.
+ # Prepending to QT_BUILD_CMAKE_PREFIX_PATH helps find components of Qt6, because those
+ # find_package calls use NO_DEFAULT_PATH, and thus CMAKE_PREFIX_PATH is ignored.
+ # Prepending to CMAKE_FIND_ROOT_PATH ensures the components are found while cross-compiling
+ # without setting CMAKE_FIND_ROOT_PATH_MODE_PACKAGE to BOTH.
+ if(NOT QT_IS_EXTERNAL_EXAMPLES_BUILD OR NOT __qt_all_examples_ported_to_external_projects)
+ qt_internal_set_up_build_dir_package_paths()
+ list(PREPEND CMAKE_FIND_ROOT_PATH "${QT_BUILD_DIR}")
+ list(PREPEND QT_BUILD_CMAKE_PREFIX_PATH "${QT_BUILD_DIR}/${INSTALL_LIBDIR}/cmake")
+ endif()
+
+ # Because CMAKE_INSTALL_RPATH is empty by default in the repo project, examples need to have
+ # it set here, so they can run when installed.
+ # This means that installed examples are not relocatable at the moment. We would need to
+ # annotate where each example is installed to, to be able to derive a relative rpath, and it
+ # seems there's no way to query such information from CMake itself.
+ set(CMAKE_INSTALL_RPATH "${_default_install_rpath}")
+
+ install(CODE "
+# Backup CMAKE_INSTALL_PREFIX because we're going to change it in each example subdirectory
+# and restore it after all examples are processed so that QtFooToolsAdditionalTargetInfo.cmake
+# files are installed into the original install prefix.
+set(_qt_internal_examples_cmake_install_prefix_backup \"\${CMAKE_INSTALL_PREFIX}\")
+")
+endmacro()
+
+macro(qt_examples_build_end)
+ # We use AUTOMOC/UIC/RCC in the examples. When the examples are part of the
+ # main build rather than being built in their own separate project, make
+ # sure we do not fail on a fresh Qt build (e.g. the moc binary won't exist
+ # yet because it is created at build time).
+
+ _qt_internal_collect_buildsystem_targets(targets
+ "${CMAKE_CURRENT_SOURCE_DIR}" EXCLUDE UTILITY ALIAS)
+
+ foreach(target ${targets})
+ qt_autogen_tools(${target} ENABLE_AUTOGEN_TOOLS "moc" "rcc")
+ if(TARGET Qt::Widgets)
+ qt_autogen_tools(${target} ENABLE_AUTOGEN_TOOLS "uic")
+ endif()
+ set_target_properties(${target} PROPERTIES UNITY_BUILD OFF)
+ endforeach()
+
+ install(CODE "
+# Restore backed up CMAKE_INSTALL_PREFIX.
+set(CMAKE_INSTALL_PREFIX \"\${_qt_internal_examples_cmake_install_prefix_backup}\")
+")
+
+ set(CMAKE_UNITY_BUILD ${QT_UNITY_BUILD})
+endmacro()
+
+# Allows building an example either as an ExternalProject or in-tree with the Qt build.
+# Also allows installing the example sources.
+function(qt_internal_add_example subdir)
+ # Don't show warnings for examples that were added via qt_internal_add_example.
+ # Those that are added via add_subdirectory will see the warning, due to the parent scope
+ # having the variable set to TRUE.
+ if(QT_FEATURE_developer_build AND NOT QT_NO_WARN_ABOUT_EXAMPLE_ADD_SUBDIRECTORY_WARNING)
+ set(QT_WARN_ABOUT_EXAMPLE_ADD_SUBDIRECTORY FALSE)
+ endif()
+
+ # Pre-compute unique example name based on the subdir, in case of target name clashes.
+ qt_internal_get_example_unique_name(unique_example_name "${subdir}")
+
+ # QT_INTERNAL_NO_CONFIGURE_EXAMPLES is not meant to be used by Qt builders, it's here for faster
+ # testing of the source installation code path for build system engineers.
+ if(NOT QT_INTERNAL_NO_CONFIGURE_EXAMPLES)
+ if(NOT QT_IS_EXTERNAL_EXAMPLES_BUILD)
+ qt_internal_add_example_in_tree("${subdir}")
+ else()
+ qt_internal_add_example_external_project("${subdir}"
+ NAME "${unique_example_name}")
+ endif()
+ endif()
+
+ if(QT_INSTALL_EXAMPLES_SOURCES)
+ string(TOLOWER ${PROJECT_NAME} project_name_lower)
+
+ qt_internal_install_example_sources("${subdir}"
+ NAME "${unique_example_name}"
+ REPO_NAME "${project_name_lower}")
+ endif()
+endfunction()
+
+# Gets the install prefix where an example should be installed.
+# Used for computing the final installation path.
+function(qt_internal_get_example_install_prefix out_var)
+ # Allow customizing the installation path of the examples. Will be used in CI.
+ if(QT_INTERNAL_EXAMPLES_INSTALL_PREFIX)
+ set(qt_example_install_prefix "${QT_INTERNAL_EXAMPLES_INSTALL_PREFIX}")
+ elseif(QT_BUILD_STANDALONE_EXAMPLES)
+ # TODO: We might need to reset and pipe through an empty CMAKE_STAGING_PREFIX if we ever
+ # try to run standalone examples in the CI when cross-compiling, similar how it's done in
+ # qt_internal_set_up_fake_standalone_parts_install_prefix.
+ qt_internal_get_fake_standalone_install_prefix(qt_example_install_prefix)
+ else()
+ set(qt_example_install_prefix "${CMAKE_INSTALL_PREFIX}/${INSTALL_EXAMPLESDIR}")
+ endif()
+ file(TO_CMAKE_PATH "${qt_example_install_prefix}" qt_example_install_prefix)
+ set(${out_var} "${qt_example_install_prefix}" PARENT_SCOPE)
+endfunction()
+
+# Gets the install prefix where an example's sources should be installed.
+# Used for computing the final installation path.
+function(qt_internal_get_examples_sources_install_prefix out_var)
+ # Allow customizing the installation path of the examples source specifically.
+ if(QT_INTERNAL_EXAMPLES_SOURCES_INSTALL_PREFIX)
+ set(qt_example_install_prefix "${QT_INTERNAL_EXAMPLES_SOURCES_INSTALL_PREFIX}")
+ else()
+ qt_internal_get_example_install_prefix(qt_example_install_prefix)
+ endif()
+ file(TO_CMAKE_PATH "${qt_example_install_prefix}" qt_example_install_prefix)
+ set(${out_var} "${qt_example_install_prefix}" PARENT_SCOPE)
+endfunction()
+
+# Gets the relative path of an example, relative to the current repo's examples source dir.
+# QT_EXAMPLE_BASE_DIR is meant to be already set in a parent scope.
+function(qt_internal_get_example_rel_path out_var subdir)
+ file(RELATIVE_PATH example_rel_path
+ "${QT_EXAMPLE_BASE_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}/${subdir}")
+ set(${out_var} "${example_rel_path}" PARENT_SCOPE)
+endfunction()
+
+# Gets the install path where an example should be installed.
+function(qt_internal_get_example_install_path out_var subdir)
+ qt_internal_get_example_install_prefix(qt_example_install_prefix)
+ qt_internal_get_example_rel_path(example_rel_path "${subdir}")
+ set(example_install_path "${qt_example_install_prefix}/${example_rel_path}")
+
+ set(${out_var} "${example_install_path}" PARENT_SCOPE)
+endfunction()
+
+# Gets the install path where an example's sources should be installed.
+function(qt_internal_get_examples_sources_install_path out_var subdir)
+ qt_internal_get_examples_sources_install_prefix(qt_example_install_prefix)
+ qt_internal_get_example_rel_path(example_rel_path "${subdir}")
+ set(example_install_path "${qt_example_install_prefix}/${example_rel_path}")
+
+ set(${out_var} "${example_install_path}" PARENT_SCOPE)
+endfunction()
+
+# Get the unique name of an example project based on its subdir or explicitly given name.
+# Makes the name unique by appending a short sha1 hash of the relative path of the example
+# if a target of the same name already exist.
+function(qt_internal_get_example_unique_name out_var subdir)
+ qt_internal_get_example_rel_path(example_rel_path "${subdir}")
+
+ set(name "${subdir}")
+
+ # qtdeclarative has calls like qt_internal_add_example(imagine/automotive)
+ # so passing a nested subdirectory. Custom targets (and thus ExternalProjects) can't contain
+ # slashes, so extract the last part of the path to be used as a name.
+ if(name MATCHES "/")
+ string(REPLACE "/" ";" exploded_path "${name}")
+ list(POP_BACK exploded_path last_dir)
+ if(NOT last_dir)
+ message(FATAL_ERROR "Example subdirectory must have a name.")
+ else()
+ set(name "${last_dir}")
+ endif()
+ endif()
+
+ # Likely a clash with an example subdir ExternalProject custom target of the same name in a
+ # top-level build.
+ if(TARGET "${name}")
+ string(SHA1 rel_path_hash "${example_rel_path}")
+ string(SUBSTRING "${rel_path_hash}" 0 4 short_hash)
+ set(name "${name}-${short_hash}")
+ endif()
+
+ set(${out_var} "${name}" PARENT_SCOPE)
+endfunction()
+
+# Use old non-ExternalProject approach, aka build in-tree with the Qt build.
+function(qt_internal_add_example_in_tree subdir)
+ # Unset the default CMAKE_INSTALL_PREFIX that's generated in
+ # ${CMAKE_CURRENT_BINARY_DIR}/cmake_install.cmake
+ # so we can override it with a different value in
+ # ${CMAKE_CURRENT_BINARY_DIR}/${subdir}/cmake_install.cmake
+ #
+ install(CODE "
+# Unset the CMAKE_INSTALL_PREFIX in the current cmake_install.cmake file so that it can be
+# overridden in the included add_subdirectory-specific cmake_install.cmake files instead.
+# Also unset the deployment prefix, so it can be recomputed for each example subdirectory.
+unset(CMAKE_INSTALL_PREFIX)
+unset(QT_DEPLOY_PREFIX)
+")
+
+ # Override the install prefix in the subdir cmake_install.cmake, so that
+ # relative install(TARGETS DESTINATION) calls in example projects install where we tell them to.
+ qt_internal_get_example_install_path(example_install_path "${subdir}")
+ set(CMAKE_INSTALL_PREFIX "${example_install_path}")
+
+ # Make sure unclean example projects have their INSTALL_EXAMPLEDIR set to "."
+ # Won't have any effect on example projects that don't use INSTALL_EXAMPLEDIR.
+ # This plus the install prefix above takes care of installing examples where we want them to
+ # be installed, while allowing us to remove INSTALL_EXAMPLEDIR code in each example
+ # incrementally.
+ # TODO: Remove once all repositories use qt_internal_add_example instead of add_subdirectory.
+ set(QT_INTERNAL_SET_EXAMPLE_INSTALL_DIR_TO_DOT ON)
+
+ add_subdirectory(${subdir})
+endfunction()
+
+function(qt_internal_add_example_external_project subdir)
+ set(options "")
+ set(singleOpts NAME)
+ set(multiOpts "")
+
+ cmake_parse_arguments(PARSE_ARGV 1 arg "${options}" "${singleOpts}" "${multiOpts}")
+
+ _qt_internal_get_build_vars_for_external_projects(
+ CMAKE_DIR_VAR qt_cmake_dir
+ PREFIXES_VAR qt_prefixes
+ ADDITIONAL_PACKAGES_PREFIXES_VAR qt_additional_packages_prefixes
+ )
+
+ list(APPEND QT_ADDITIONAL_PACKAGES_PREFIX_PATH "${qt_additional_packages_prefixes}")
+
+ set(vars_to_pass_if_defined)
+ set(var_defs)
+ if(QT_HOST_PATH OR CMAKE_CROSSCOMPILING)
+ list(APPEND var_defs
+ -DCMAKE_TOOLCHAIN_FILE:FILEPATH=${qt_cmake_dir}/qt.toolchain.cmake
+ )
+ else()
+ list(PREPEND CMAKE_PREFIX_PATH ${qt_prefixes})
+
+ # Setting CMAKE_SYSTEM_NAME affects CMAKE_CROSSCOMPILING, even if it is
+ # set to the same as the host, so it should only be set if it is different.
+ # See https://gitlab.kitware.com/cmake/cmake/-/issues/21744
+ if(NOT DEFINED CMAKE_TOOLCHAIN_FILE AND
+ NOT CMAKE_SYSTEM_NAME STREQUAL CMAKE_HOST_SYSTEM_NAME)
+ list(APPEND vars_to_pass_if_defined CMAKE_SYSTEM_NAME:STRING)
+ endif()
+ endif()
+
+ # We we need to augment the CMAKE_MODULE_PATH with the current repo cmake build dir, to find
+ # files like FindWrapBundledFooConfigExtra.cmake.
+ set(module_paths "${qt_prefixes}")
+ list(TRANSFORM module_paths APPEND "/${INSTALL_LIBDIR}/cmake/${QT_CMAKE_EXPORT_NAMESPACE}")
+ list(APPEND CMAKE_MODULE_PATH ${module_paths})
+
+ # Pass additional paths where qml plugin config files should be included by Qt6QmlPlugins.cmake.
+ # This is needed in prefix builds, where the cmake files are not installed yet.
+ set(glob_prefixes "${qt_prefixes}")
+ list(TRANSFORM glob_prefixes APPEND "/${INSTALL_LIBDIR}/cmake/${QT_CMAKE_EXPORT_NAMESPACE}Qml")
+
+ set(qml_plugin_cmake_config_file_glob_prefixes "")
+ foreach(glob_prefix IN LISTS glob_prefix)
+ if(EXISTS "${glob_prefix}")
+ list(APPEND qml_plugin_cmake_config_file_glob_prefixes "${glob_prefix}")
+ endif()
+ endforeach()
+
+ if(qml_plugin_cmake_config_file_glob_prefixes)
+ set(QT_ADDITIONAL_QML_PLUGIN_GLOB_PREFIXES ${qml_plugin_cmake_config_file_glob_prefixes})
+ endif()
+
+ # In multi-config mode by default we exclude building tools for configs other than the main one.
+ # Trying to build an example in a non-default config using the non-installed
+ # QtFooConfig.cmake files would error out saying moc is not found.
+ # Make sure to build examples only with the main config.
+ # When users build an example against an installed Qt they won't have this problem because
+ # the generated non-main QtFooTargets-$<CONFIG>.cmake file is empty and doesn't advertise
+ # a tool that is not there.
+ if(QT_GENERATOR_IS_MULTI_CONFIG)
+ set(CMAKE_CONFIGURATION_TYPES "${QT_MULTI_CONFIG_FIRST_CONFIG}")
+ endif()
+
+ # We need to pass the modified CXX flags of the parent project so that using sccache works
+ # properly and doesn't error out due to concurrent access to the pdb files.
+ # See qt_internal_set_up_config_optimizations_like_in_qmake, "/Zi" "/Z7".
+ if(MSVC AND QT_FEATURE_msvc_obj_debug_info)
+ qt_internal_get_enabled_languages_for_flag_manipulation(enabled_languages)
+ set(configs RELWITHDEBINFO DEBUG)
+ foreach(lang ${enabled_languages})
+ foreach(config ${configs})
+ set(flag_var_name "CMAKE_${lang}_FLAGS_${config}")
+ list(APPEND vars_to_pass_if_defined "${flag_var_name}:STRING")
+ endforeach()
+ endforeach()
+ endif()
+
+ # When cross-compiling for a qemu target in our CI, we source an environment script
+ # that sets environment variables like CC and CXX. These are parsed by CMake on initial
+ # configuration to populate the cache vars CMAKE_${lang}_COMPILER.
+ # If the environment variable specified not only the compiler path, but also a list of flags
+ # to pass to the compiler, CMake parses those out into a separate CMAKE_${lang}_COMPILER_ARG1
+ # cache variable. In such a case, we want to ensure that the external project also sees those
+ # flags.
+ # Unfortunately we can't do that by simply forwarding CMAKE_${lang}_COMPILER_ARG1 to the EP
+ # because it breaks the compiler identification try_compile call, it simply doesn't consider
+ # the cache var. From what I could gather, it's a limitation of try_compile and the list
+ # of variables it considers for forwarding.
+ # To fix this case, we ensure not to pass either cache variable, and let the external project
+ # and its compiler identification try_compile project pick up the compiler and the flags
+ # from the environment variables instead.
+ foreach(lang_as_env_var CC CXX OBJC OBJCXX)
+ if(lang_as_env_var STREQUAL "CC")
+ set(lang_as_cache_var "C")
+ else()
+ set(lang_as_cache_var "${lang_as_env_var}")
+ endif()
+ set(lang_env_value "$ENV{${lang_as_env_var}}")
+ if(lang_env_value
+ AND CMAKE_${lang_as_cache_var}_COMPILER
+ AND CMAKE_${lang_as_cache_var}_COMPILER_ARG1)
+ # The compiler environment variable is set and specifies a list of extra flags, don't
+ # forward the compiler cache vars and rely on the environment variable to be picked up
+ # instead.
+ else()
+ list(APPEND vars_to_pass_if_defined "CMAKE_${lang_as_cache_var}_COMPILER:STRING")
+ endif()
+ endforeach()
+ unset(lang_as_env_var)
+ unset(lang_as_cache_var)
+ unset(lang_env_value)
+
+ list(APPEND vars_to_pass_if_defined
+ CMAKE_BUILD_TYPE:STRING
+ CMAKE_CONFIGURATION_TYPES:STRING
+ CMAKE_PREFIX_PATH:STRING
+ QT_BUILD_CMAKE_PREFIX_PATH:STRING
+ QT_ADDITIONAL_PACKAGES_PREFIX_PATH:STRING
+ QT_ADDITIONAL_QML_PLUGIN_GLOB_PREFIXES:STRING
+ QT_INTERNAL_SKIP_DEPLOYMENT:BOOL
+ CMAKE_FIND_ROOT_PATH:STRING
+ CMAKE_MODULE_PATH:STRING
+ BUILD_SHARED_LIBS:BOOL
+ CMAKE_OSX_ARCHITECTURES:STRING
+ CMAKE_OSX_DEPLOYMENT_TARGET:STRING
+ CMAKE_XCODE_ATTRIBUTE_CODE_SIGNING_ALLOWED:BOOL
+ CMAKE_XCODE_ATTRIBUTE_ONLY_ACTIVE_ARCH:BOOL
+ CMAKE_C_COMPILER_LAUNCHER:STRING
+ CMAKE_CXX_COMPILER_LAUNCHER:STRING
+ CMAKE_OBJC_COMPILER_LAUNCHER:STRING
+ CMAKE_OBJCXX_COMPILER_LAUNCHER:STRING
+ )
+
+ # QT_EXAMPLE_CMAKE_VARS_TO_PASS can be set by specific repos to pass any additional required
+ # CMake cache variables.
+ # One use case is passing locations of 3rd party package locations like Protobuf via _ROOT
+ # variables.
+ set(extra_vars_var_name "")
+ if(QT_EXAMPLE_CMAKE_VARS_TO_PASS)
+ set(extra_vars_var_name "QT_EXAMPLE_CMAKE_VARS_TO_PASS")
+ endif()
+ foreach(var_with_type IN LISTS vars_to_pass_if_defined ${extra_vars_var_name})
+ string(REPLACE ":" ";" key_as_list "${var_with_type}")
+ list(GET key_as_list 0 var)
+ if(NOT DEFINED ${var})
+ continue()
+ endif()
+
+ # Preserve lists
+ string(REPLACE ";" "$<SEMICOLON>" varForGenex "${${var}}")
+
+ list(APPEND var_defs -D${var_with_type}=${varForGenex})
+ endforeach()
+
+ if(QT_INTERNAL_VERBOSE_EXAMPLES)
+ list(APPEND var_defs -DCMAKE_MESSAGE_LOG_LEVEL:STRING=DEBUG)
+ list(APPEND var_defs -DCMAKE_AUTOGEN_VERBOSE:BOOL=TRUE)
+ endif()
+
+ set(deps "")
+ list(REMOVE_DUPLICATES QT_EXAMPLE_DEPENDENCIES)
+ foreach(dep IN LISTS QT_EXAMPLE_DEPENDENCIES)
+ if(TARGET ${dep})
+ list(APPEND deps ${dep})
+ endif()
+ endforeach()
+
+ set(independent_args)
+ cmake_policy(PUSH)
+ if(POLICY CMP0114)
+ set(independent_args INDEPENDENT TRUE)
+ cmake_policy(SET CMP0114 NEW)
+ endif()
+
+ # The USES_TERMINAL_BUILD setting forces the build step to the console pool
+ # when using Ninja. This has two benefits:
+ #
+ # - You see build output as it is generated instead of at the end of the
+ # build step.
+ # - Only one task can use the console pool at a time, so it effectively
+ # serializes all example build steps, thereby preventing CPU
+ # over-commitment.
+ #
+ # If the loss of interactivity is not so important, one can allow CPU
+ # over-commitment for Ninja builds. This may result in better throughput,
+ # but is not allowed by default because it can make a machine almost
+ # unusable while a compilation is running.
+ set(terminal_args USES_TERMINAL_BUILD TRUE)
+ if(CMAKE_GENERATOR MATCHES "Ninja")
+ option(QT_BUILD_EXAMPLES_WITH_CPU_OVERCOMMIT
+ "Allow CPU over-commitment when building examples (Ninja only)"
+ )
+ if(QT_BUILD_EXAMPLES_WITH_CPU_OVERCOMMIT)
+ set(terminal_args)
+ endif()
+ endif()
+
+ # QT_EXAMPLE_INSTALL_MARKER
+ # The goal is to install each example project into a directory that keeps the example source dir
+ # hierarchy, without polluting the example projects with dirty INSTALL_EXAMPLEDIR and
+ # INSTALL_EXAMPLESDIR usage.
+ # E.g. ensure qtbase/examples/widgets/widgets/wiggly is installed to
+ # $qt_example_install_prefix/examples/widgets/widgets/wiggly/wiggly.exe
+ # $qt_example_install_prefix defaults to ${CMAKE_INSTALL_PREFIX}/${INSTALL_EXAMPLEDIR}
+ # but can also be set to a custom location.
+ # This needs to work both:
+ # - when using ExternalProject to build examples
+ # - when examples are built in-tree as part of Qt (no ExternalProject).
+ # The reason we want to support the latter is for nicer IDE integration: a can developer can
+ # work with a Qt repo and its examples using the same build dir.
+ #
+ # In both case we have to ensure examples are not accidentally installed to $qt_prefix/bin or
+ # similar.
+ #
+ # Example projects installation matrix.
+ # 1) ExternalProject + unclean example install rules (INSTALL_EXAMPLEDIR is set) =>
+ # use _qt_internal_override_example_install_dir_to_dot + ExternalProject_Add's INSTALL_DIR
+ # using relative_dir from QT_EXAMPLE_BASE_DIR to example_source_dir
+ #
+ # 2) ExternalProject + clean example install rules =>
+ # use ExternalProject_Add's INSTALL_DIR using relative_dir from QT_EXAMPLE_BASE_DIR to
+ # example_source_dir, _qt_internal_override_example_install_dir_to_dot would be a no-op
+ #
+ # 3) in-tree + unclean example install rules (INSTALL_EXAMPLEDIR is set)
+ # +
+ # 4) in-tree + clean example install rules =>
+ # ensure CMAKE_INSTALL_PREFIX is unset in parent cmake_install.cmake file, set non-cache
+ # CMAKE_INSTALL_PREFIX using relative_dir from QT_EXAMPLE_BASE_DIR to
+ # example_source_dir, use _qt_internal_override_example_install_dir_to_dot to ensure
+ # INSTALL_EXAMPLEDIR does not interfere.
+
+ qt_internal_get_example_install_path(example_install_path "${subdir}")
+
+ set(ep_binary_dir "${CMAKE_CURRENT_BINARY_DIR}/${subdir}")
+
+ set(build_command "")
+ if(QT_INTERNAL_VERBOSE_EXAMPLES AND CMAKE_GENERATOR MATCHES "Ninja")
+ set(build_command BUILD_COMMAND "${CMAKE_COMMAND}" --build "." -- -v)
+ endif()
+
+ ExternalProject_Add(${arg_NAME}
+ EXCLUDE_FROM_ALL TRUE
+ SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/${subdir}"
+ PREFIX "${CMAKE_CURRENT_BINARY_DIR}/${subdir}-ep"
+ STAMP_DIR "${CMAKE_CURRENT_BINARY_DIR}/${subdir}-ep/stamp"
+ BINARY_DIR "${ep_binary_dir}"
+ INSTALL_DIR "${example_install_path}"
+ INSTALL_COMMAND ""
+ ${build_command}
+ TEST_COMMAND ""
+ DEPENDS ${deps}
+ CMAKE_CACHE_ARGS ${var_defs}
+ -DCMAKE_INSTALL_PREFIX:STRING=<INSTALL_DIR>
+ -DQT_INTERNAL_SET_EXAMPLE_INSTALL_DIR_TO_DOT:BOOL=TRUE
+ ${terminal_args}
+ )
+
+ # Install the examples when the the user runs 'make install', and not at build time (which is
+ # the default for ExternalProjects).
+ install(CODE "\
+# Install example from inside ExternalProject into the main build's install prefix.
+execute_process(
+ COMMAND
+ \"${CMAKE_COMMAND}\" --build \"${ep_binary_dir}\" --target install
+)
+")
+
+ # Force configure step to re-run after we configure the main project
+ set(reconfigure_check_file ${CMAKE_CURRENT_BINARY_DIR}/reconfigure_${arg_NAME}.txt)
+ file(TOUCH ${reconfigure_check_file})
+ ExternalProject_Add_Step(${arg_NAME} reconfigure-check
+ DEPENDERS configure
+ DEPENDS ${reconfigure_check_file}
+ ${independent_args}
+ )
+
+ # Create an apk external project step and custom target that invokes the apk target
+ # within the external project.
+ # Make the global apk target depend on that custom target.
+ if(ANDROID)
+ ExternalProject_Add_Step(${arg_NAME} apk
+ COMMAND ${CMAKE_COMMAND} --build <BINARY_DIR> --target apk
+ DEPENDEES configure
+ EXCLUDE_FROM_MAIN YES
+ ${terminal_args}
+ )
+ ExternalProject_Add_StepTargets(${arg_NAME} apk)
+
+ if(TARGET apk)
+ add_dependencies(apk ${arg_NAME}-apk)
+ endif()
+ endif()
+
+ cmake_policy(POP)
+
+ string(TOLOWER ${PROJECT_NAME} project_name_lower)
+ add_dependencies(examples_${project_name_lower} ${arg_NAME})
+
+endfunction()
+
+function(qt_internal_install_example_sources subdir)
+ set(options "")
+ set(single_args NAME REPO_NAME)
+ set(multi_args "")
+
+ cmake_parse_arguments(PARSE_ARGV 1 arg "${options}" "${single_args}" "${multi_args}")
+
+ qt_internal_get_examples_sources_install_path(example_install_path "${subdir}")
+
+ # The trailing slash is important to avoid duplicate nested directory names.
+ set(example_source_dir "${subdir}/")
+
+ # Allow controlling whether sources should be part of the default install target.
+ if(QT_INSTALL_EXAMPLES_SOURCES_BY_DEFAULT)
+ set(exclude_from_all "")
+ else()
+ set(exclude_from_all "EXCLUDE_FROM_ALL")
+ endif()
+
+ # Create an install component for all example sources. Can also be part of the default
+ # install target if EXCLUDE_FROM_ALL is not passed.
+ install(
+ DIRECTORY "${example_source_dir}"
+ DESTINATION "${example_install_path}"
+ COMPONENT "examples_sources"
+ USE_SOURCE_PERMISSIONS
+ ${exclude_from_all}
+ )
+
+ # Also create a specific install component just for this repo's examples.
+ install(
+ DIRECTORY "${example_source_dir}"
+ DESTINATION "${example_install_path}"
+ COMPONENT "examples_sources_${arg_REPO_NAME}"
+ USE_SOURCE_PERMISSIONS
+ EXCLUDE_FROM_ALL
+ )
+
+ # Also create a specific install component just for the current example's sources.
+ install(
+ DIRECTORY "${example_source_dir}"
+ DESTINATION "${example_install_path}"
+ COMPONENT "examples_sources_${arg_NAME}"
+ USE_SOURCE_PERMISSIONS
+ EXCLUDE_FROM_ALL
+ )
+endfunction()
diff --git a/cmake/QtBuildRepoHelpers.cmake b/cmake/QtBuildRepoHelpers.cmake
new file mode 100644
index 0000000000..8bd0615090
--- /dev/null
+++ b/cmake/QtBuildRepoHelpers.cmake
@@ -0,0 +1,1079 @@
+# Copyright (C) 2023 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+# Macros and functions for building Qt submodules
+
+# The macro sets all the necessary pre-conditions and setup consistent environment for building
+# the Qt repository. It has to be called right after the find_package(Qt6 COMPONENTS BuildInternals)
+# call. Otherwise we cannot make sure that all the required policies will be applied to the Qt
+# components that are involved in build procedure.
+macro(qt_internal_project_setup)
+ # Check for the minimum CMake version.
+ qt_internal_require_suitable_cmake_version()
+ qt_internal_upgrade_cmake_policies()
+ qt_internal_promote_platform_targets_to_global()
+endmacro()
+
+macro(qt_build_internals_set_up_private_api)
+ # TODO: this call needs to be removed once all repositories got the qtbase update
+ qt_internal_project_setup()
+
+ # Qt specific setup common for all modules:
+ include(QtSetup)
+
+ # Optionally include a repo specific Setup module.
+ include(${PROJECT_NAME}Setup OPTIONAL)
+ include(QtRepoSetup OPTIONAL)
+
+ # Find Apple frameworks if needed.
+ qt_find_apple_system_frameworks()
+
+ # Decide whether tools will be built.
+ qt_check_if_tools_will_be_built()
+endmacro()
+
+# add toplevel targets for each subdirectory, e.g. qtbase_src
+function(qt_build_internals_add_toplevel_targets qt_repo_targets_name)
+ set(qt_repo_target_all "")
+ get_directory_property(directories DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" SUBDIRECTORIES)
+ foreach(directory IN LISTS directories)
+ set(qt_repo_targets "")
+ get_filename_component(qt_repo_target_basename ${directory} NAME)
+ _qt_internal_collect_buildsystem_targets(qt_repo_targets "${directory}" EXCLUDE UTILITY)
+ if (qt_repo_targets)
+ set(qt_repo_target_name "${qt_repo_targets_name}_${qt_repo_target_basename}")
+ message(DEBUG "${qt_repo_target_name} depends on ${qt_repo_targets}")
+ add_custom_target("${qt_repo_target_name}"
+ COMMENT "Building everything in ${qt_repo_targets_name}/${qt_repo_target_basename}")
+ add_dependencies("${qt_repo_target_name}" ${qt_repo_targets})
+ list(APPEND qt_repo_target_all "${qt_repo_target_name}")
+
+ # Create special dependency target for External Project examples excluding targets
+ # marked as skipped.
+ if(qt_repo_target_basename STREQUAL "src")
+ set(qt_repo_target_name
+ "${qt_repo_targets_name}_${qt_repo_target_basename}_for_examples")
+ add_custom_target("${qt_repo_target_name}")
+
+ set(unskipped_targets "")
+ foreach(target IN LISTS qt_repo_targets)
+ if(TARGET "${target}")
+ qt_internal_is_target_skipped_for_examples("${target}" is_skipped)
+ if(NOT is_skipped)
+ list(APPEND unskipped_targets "${target}")
+ endif()
+ endif()
+ endforeach()
+ if(unskipped_targets)
+ add_dependencies("${qt_repo_target_name}" ${unskipped_targets})
+ endif()
+ endif()
+ endif()
+
+ endforeach()
+ if (qt_repo_target_all)
+ # Note qt_repo_targets_name is different from qt_repo_target_name that is used above.
+ add_custom_target("${qt_repo_targets_name}"
+ COMMENT "Building everything in ${qt_repo_targets_name}")
+ add_dependencies("${qt_repo_targets_name}" ${qt_repo_target_all})
+ message(DEBUG "${qt_repo_targets_name} depends on ${qt_repo_target_all}")
+ endif()
+endfunction()
+
+macro(qt_enable_cmake_languages)
+ set(__qt_required_language_list C CXX)
+ set(__qt_platform_required_language_list )
+
+ if(APPLE)
+ list(APPEND __qt_platform_required_language_list OBJC OBJCXX)
+ endif()
+
+ foreach(__qt_lang ${__qt_required_language_list})
+ enable_language(${__qt_lang})
+ endforeach()
+
+ foreach(__qt_lang ${__qt_platform_required_language_list})
+ enable_language(${__qt_lang})
+ endforeach()
+
+ # The qtbase call is handled in qtbase/CMakeLists.txt.
+ # This call is used for projects other than qtbase, including for other project's standalone
+ # tests/examples.
+ # Because the function uses QT_FEATURE_foo values, it's important that find_package(Qt6Core) is
+ # called before this function. but that's usually the case for Qt repos.
+ if(NOT PROJECT_NAME STREQUAL "QtBase")
+ qt_internal_set_up_config_optimizations_like_in_qmake()
+ endif()
+endmacro()
+
+# Minimum setup required to have any CMakeList.txt build as as a standalone
+# project after importing BuildInternals
+macro(qt_prepare_standalone_project)
+ qt_set_up_build_internals_paths()
+ qt_build_internals_set_up_private_api()
+ qt_enable_cmake_languages()
+endmacro()
+
+# Define a repo target set, and store accompanying information.
+#
+# A repo target set is a subset of targets in a Qt module repository. To build a repo target set,
+# set QT_BUILD_SINGLE_REPO_TARGET_SET to the name of the repo target set.
+#
+# This function is to be called in the top-level project file of a repository,
+# before qt_internal_prepare_single_repo_target_set_build()
+#
+# This function stores information in variables of the parent scope.
+#
+# Positional Arguments:
+# name - The name of this repo target set.
+#
+# Named Arguments:
+# DEPENDS - List of Qt6 COMPONENTS that are build dependencies of this repo target set.
+function(qt_internal_define_repo_target_set name)
+ set(oneValueArgs DEPENDS)
+ set(prefix QT_REPO_TARGET_SET_)
+ cmake_parse_arguments(${prefix}${name} "" ${oneValueArgs} "" ${ARGN})
+ foreach(arg IN LISTS oneValueArgs)
+ set(${prefix}${name}_${arg} ${${prefix}${name}_${arg}} PARENT_SCOPE)
+ endforeach()
+ set(QT_REPO_KNOWN_TARGET_SETS "${QT_REPO_KNOWN_TARGET_SETS};${name}" PARENT_SCOPE)
+endfunction()
+
+# Setup a single repo target set build if QT_BUILD_SINGLE_REPO_TARGET_SET is defined.
+#
+# This macro must be called in the top-level project file of the repository after all repo target
+# sets have been defined.
+macro(qt_internal_prepare_single_repo_target_set_build)
+ if(DEFINED QT_BUILD_SINGLE_REPO_TARGET_SET)
+ if(NOT QT_BUILD_SINGLE_REPO_TARGET_SET IN_LIST QT_REPO_KNOWN_TARGET_SETS)
+ message(FATAL_ERROR
+ "Repo target set '${QT_BUILD_SINGLE_REPO_TARGET_SET}' is undefined.")
+ endif()
+ message(STATUS
+ "Preparing single repo target set build of ${QT_BUILD_SINGLE_REPO_TARGET_SET}")
+ if (NOT "${QT_REPO_TARGET_SET_${QT_BUILD_SINGLE_REPO_TARGET_SET}_DEPENDS}" STREQUAL "")
+ find_package(${INSTALL_CMAKE_NAMESPACE} ${PROJECT_VERSION} CONFIG REQUIRED
+ COMPONENTS ${QT_REPO_TARGET_SET_${QT_BUILD_SINGLE_REPO_TARGET_SET}_DEPENDS})
+ endif()
+ endif()
+endmacro()
+
+# There are three necessary copies of this macro in
+# qtbase/cmake/QtBaseHelpers.cmake
+# qtbase/cmake/QtBaseTopLevelHelpers.cmake
+# qtbase/cmake/QtBuildRepoHelpers.cmake
+macro(qt_internal_setup_standalone_parts)
+ # A generic marker for any kind of standalone builds, either tests or examples.
+ if(NOT DEFINED QT_INTERNAL_BUILD_STANDALONE_PARTS
+ AND (QT_BUILD_STANDALONE_TESTS OR QT_BUILD_STANDALONE_EXAMPLES))
+ set(QT_INTERNAL_BUILD_STANDALONE_PARTS TRUE CACHE INTERNAL
+ "Whether standalone tests or examples are being built")
+ endif()
+endmacro()
+
+macro(qt_build_repo_begin)
+ qt_internal_setup_standalone_parts()
+
+ set(QT_INTERNAL_REPO_POST_PROCESS_CALLED FALSE)
+ list(APPEND CMAKE_MESSAGE_CONTEXT "${PROJECT_NAME}")
+
+ qt_build_internals_set_up_private_api()
+
+ # Prevent installation in non-prefix builds.
+ # We need to associate targets with export names, and that is only possible to do with the
+ # install(TARGETS) command. But in a non-prefix build, we don't want to install anything.
+ # To make sure that developers don't accidentally run make install, add bail out code to
+ # cmake_install.cmake.
+ if(NOT QT_WILL_INSTALL)
+ # In a top-level build, print a message only in qtbase, which is the first repository.
+ if(NOT QT_SUPERBUILD OR (PROJECT_NAME STREQUAL "QtBase"))
+ install(CODE [[message(FATAL_ERROR
+ "Qt was configured as non-prefix build. "
+ "Installation is not supported for this arrangement.")]])
+ endif()
+
+ install(CODE [[return()]])
+ endif()
+
+ qt_enable_cmake_languages()
+
+ qt_internal_generate_binary_strip_wrapper()
+
+ # Add global docs targets that will work both for per-repo builds, and super builds.
+ if(NOT TARGET docs)
+ add_custom_target(docs)
+ add_custom_target(prepare_docs)
+ add_custom_target(generate_docs)
+ add_custom_target(html_docs)
+ add_custom_target(qch_docs)
+ add_custom_target(install_html_docs)
+ add_custom_target(install_qch_docs)
+ add_custom_target(install_docs)
+ add_dependencies(html_docs generate_docs)
+ add_dependencies(docs html_docs qch_docs)
+ add_dependencies(install_docs install_html_docs install_qch_docs)
+ endif()
+
+ if(NOT TARGET sync_headers)
+ add_custom_target(sync_headers)
+ endif()
+
+ # The special target that we use to sync 3rd-party headers before the gn run when building
+ # qtwebengine in top-level builds.
+ if(NOT TARGET thirdparty_sync_headers)
+ add_custom_target(thirdparty_sync_headers)
+ endif()
+
+ # Add global qt_plugins, qpa_plugins and qpa_default_plugins convenience custom targets.
+ # Internal executables will add a dependency on the qpa_default_plugins target,
+ # so that building and running a test ensures it won't fail at runtime due to a missing qpa
+ # plugin.
+ if(NOT TARGET qt_plugins)
+ add_custom_target(qt_plugins)
+ add_custom_target(qpa_plugins)
+ add_custom_target(qpa_default_plugins)
+ endif()
+
+ string(TOLOWER ${PROJECT_NAME} project_name_lower)
+
+ # Target to build all plugins that are part of the current repo.
+ set(qt_repo_plugins "qt_plugins_${project_name_lower}")
+ if(NOT TARGET ${qt_repo_plugins})
+ add_custom_target(${qt_repo_plugins})
+ endif()
+
+ # Target to build all plugins that are part of the current repo and the current repo's
+ # dependencies plugins. Used for external project example dependencies.
+ set(qt_repo_plugins_recursive "${qt_repo_plugins}_recursive")
+ if(NOT TARGET ${qt_repo_plugins_recursive})
+ add_custom_target(${qt_repo_plugins_recursive})
+ add_dependencies(${qt_repo_plugins_recursive} "${qt_repo_plugins}")
+ endif()
+
+ qt_internal_read_repo_dependencies(qt_repo_deps "${PROJECT_SOURCE_DIR}")
+ if(qt_repo_deps)
+ foreach(qt_repo_dep IN LISTS qt_repo_deps)
+ if(TARGET qt_plugins_${qt_repo_dep})
+ message(DEBUG
+ "${qt_repo_plugins_recursive} depends on qt_plugins_${qt_repo_dep}")
+ add_dependencies(${qt_repo_plugins_recursive} "qt_plugins_${qt_repo_dep}")
+ endif()
+ endforeach()
+ endif()
+
+ set(qt_repo_targets_name ${project_name_lower})
+ set(qt_docs_target_name docs_${project_name_lower})
+ set(qt_docs_prepare_target_name prepare_docs_${project_name_lower})
+ set(qt_docs_generate_target_name generate_docs_${project_name_lower})
+ set(qt_docs_html_target_name html_docs_${project_name_lower})
+ set(qt_docs_qch_target_name qch_docs_${project_name_lower})
+ set(qt_docs_install_html_target_name install_html_docs_${project_name_lower})
+ set(qt_docs_install_qch_target_name install_qch_docs_${project_name_lower})
+ set(qt_docs_install_target_name install_docs_${project_name_lower})
+
+ add_custom_target(${qt_docs_target_name})
+ add_custom_target(${qt_docs_prepare_target_name})
+ add_custom_target(${qt_docs_generate_target_name})
+ add_custom_target(${qt_docs_qch_target_name})
+ add_custom_target(${qt_docs_html_target_name})
+ add_custom_target(${qt_docs_install_html_target_name})
+ add_custom_target(${qt_docs_install_qch_target_name})
+ add_custom_target(${qt_docs_install_target_name})
+
+ add_dependencies(${qt_docs_generate_target_name} ${qt_docs_prepare_target_name})
+ add_dependencies(${qt_docs_html_target_name} ${qt_docs_generate_target_name})
+ add_dependencies(${qt_docs_target_name} ${qt_docs_html_target_name} ${qt_docs_qch_target_name})
+ add_dependencies(${qt_docs_install_target_name} ${qt_docs_install_html_target_name} ${qt_docs_install_qch_target_name})
+
+ # Make top-level prepare_docs target depend on the repository-level prepare_docs_<repo> target.
+ add_dependencies(prepare_docs ${qt_docs_prepare_target_name})
+
+ # Make top-level install_*_docs targets depend on the repository-level install_*_docs targets.
+ add_dependencies(install_html_docs ${qt_docs_install_html_target_name})
+ add_dependencies(install_qch_docs ${qt_docs_install_qch_target_name})
+
+ # Add host_tools meta target, so that developrs can easily build only tools and their
+ # dependencies when working in qtbase.
+ if(NOT TARGET host_tools)
+ add_custom_target(host_tools)
+ add_custom_target(bootstrap_tools)
+ endif()
+
+ # Add benchmark meta target. It's collection of all benchmarks added/registered by
+ # 'qt_internal_add_benchmark' helper.
+ if(NOT TARGET benchmark)
+ add_custom_target(benchmark)
+ endif()
+
+ if(QT_INTERNAL_SYNCED_MODULES)
+ set_property(GLOBAL PROPERTY _qt_synced_modules ${QT_INTERNAL_SYNCED_MODULES})
+ endif()
+endmacro()
+
+# Runs delayed actions on some of the Qt targets.
+# Can be called either explicitly or as part of qt_build_repo_end().
+macro(qt_build_repo_post_process)
+ if(NOT QT_INTERNAL_REPO_POST_PROCESS_CALLED)
+ set(QT_INTERNAL_REPO_POST_PROCESS_CALLED TRUE)
+ if(NOT QT_INTERNAL_BUILD_STANDALONE_PARTS)
+ include(QtPostProcess)
+ endif()
+ endif()
+endmacro()
+
+macro(qt_build_repo_end)
+ if(NOT QT_INTERNAL_BUILD_STANDALONE_PARTS)
+ qt_build_repo_post_process()
+
+ # Install the repo-specific cmake find modules.
+ qt_path_join(__qt_repo_install_dir ${QT_CONFIG_INSTALL_DIR} ${INSTALL_CMAKE_NAMESPACE})
+ qt_path_join(__qt_repo_build_dir ${QT_CONFIG_BUILD_DIR} ${INSTALL_CMAKE_NAMESPACE})
+
+ if(NOT PROJECT_NAME STREQUAL "QtBase")
+ if(IS_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
+ qt_copy_or_install(DIRECTORY cmake/
+ DESTINATION "${__qt_repo_install_dir}"
+ FILES_MATCHING PATTERN "Find*.cmake"
+ )
+ if(QT_SUPERBUILD AND QT_WILL_INSTALL)
+ file(COPY cmake/
+ DESTINATION "${__qt_repo_build_dir}"
+ FILES_MATCHING PATTERN "Find*.cmake"
+ )
+ endif()
+ endif()
+ endif()
+
+ if(NOT QT_SUPERBUILD)
+ qt_print_feature_summary()
+ endif()
+ endif()
+
+ qt_build_internals_add_toplevel_targets(${qt_repo_targets_name})
+
+ qt_internal_show_extra_ide_sources()
+
+ if(NOT QT_SUPERBUILD)
+ qt_print_build_instructions()
+ endif()
+
+ get_property(synced_modules GLOBAL PROPERTY _qt_synced_modules)
+ if(synced_modules)
+ set(QT_INTERNAL_SYNCED_MODULES ${synced_modules} CACHE INTERNAL
+ "List of the synced modules. Prevents running syncqt.cpp after the first configuring.")
+ endif()
+
+ if(NOT QT_SUPERBUILD)
+ qt_internal_save_previously_visited_packages()
+ endif()
+
+ if(QT_INTERNAL_FRESH_REQUESTED)
+ set(QT_INTERNAL_FRESH_REQUESTED "FALSE" CACHE INTERNAL "")
+ endif()
+
+ if(NOT QT_SUPERBUILD)
+ qt_internal_qt_configure_end()
+ endif()
+
+ list(POP_BACK CMAKE_MESSAGE_CONTEXT)
+endmacro()
+
+function(qt_internal_show_extra_ide_sources)
+ if(CMAKE_VERSION VERSION_LESS 3.20)
+ set(ide_sources_default OFF)
+ else()
+ set(ide_sources_default ON)
+ endif()
+
+ option(QT_SHOW_EXTRA_IDE_SOURCES "Generate CMake targets exposing non-source files to IDEs" ${ide_sources_default})
+ if(CMAKE_VERSION VERSION_LESS 3.20 AND QT_SHOW_EXTRA_IDE_SOURCES)
+ message(WARNING "QT_SHOW_EXTRA_IDE_SOURCES requires cmake-3.20")
+ return()
+ endif()
+
+ if(NOT QT_SHOW_EXTRA_IDE_SOURCES)
+ return()
+ endif()
+
+ # coin
+ set(coin_target_name ${qt_repo_targets_name}_coin_files)
+ file(GLOB_RECURSE coin_files LIST_DIRECTORIES false FOLLOW_SYMLINKS coin/*)
+ if(coin_files)
+ source_group(TREE "${CMAKE_CURRENT_SOURCE_DIR}/coin" FILES ${coin_files})
+ add_custom_target(${coin_target_name} SOURCES ${coin_files})
+ endif()
+
+ # config.test
+ set(config_tests_target_name ${qt_repo_targets_name}_config_tests)
+ file(GLOB_RECURSE config_tests_file LIST_DIRECTORIES false FOLLOW_SYMLINKS config.tests/*)
+ if(config_tests_file)
+ source_group(TREE "${CMAKE_CURRENT_SOURCE_DIR}/config.tests" FILES ${config_tests_file})
+ add_custom_target(${config_tests_target_name} SOURCES ${config_tests_file})
+ endif()
+
+ # cmake
+ set(cmake_target_name ${qt_repo_targets_name}_cmake_files)
+ file(GLOB_RECURSE cmake_files LIST_DIRECTORIES false FOLLOW_SYMLINKS
+ cmake/*
+ configure.cmake
+ qt_cmdline.cmake
+ .cmake.conf
+ *.cmake
+ *.cmake.in)
+ foreach(cmake_file IN LISTS cmake_files)
+ if(NOT ((cmake_file IN_LIST coin_files) OR (file IN_LIST config_tests_files)))
+ list(APPEND cmake_target_files ${cmake_file})
+ endif()
+ endforeach()
+
+ if(cmake_target_files)
+ source_group(TREE "${CMAKE_CURRENT_SOURCE_DIR}" FILES ${cmake_target_files})
+ add_custom_target(${cmake_target_name} SOURCES ${cmake_target_files})
+ endif()
+
+ # licenses
+ set(licenses_target_name ${qt_repo_targets_name}_licenses)
+ file(GLOB licenses_files LIST_DIRECTORIES false LICENSES/*)
+ if (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/licenseRule.json")
+ list(APPEND licenses_files "${CMAKE_CURRENT_SOURCE_DIR}/licenseRule.json")
+ endif()
+ if(licenses_files)
+ source_group(TREE "${CMAKE_CURRENT_SOURCE_DIR}" FILES ${licenses_files})
+ add_custom_target(${licenses_target_name} SOURCES ${licenses_files})
+ endif()
+
+ # changelogs
+ set(changelogs_target_name ${qt_repo_targets_name}_changelogs)
+ file(GLOB change_logs_files LIST_DIRECTORIES false dist/*)
+ if(change_logs_files)
+ source_group(TREE "${CMAKE_CURRENT_SOURCE_DIR}/dist" FILES ${change_logs_files})
+ add_custom_target(${changelogs_target_name} SOURCES ${change_logs_files})
+ endif()
+
+ # extra files
+ set(target_name ${qt_repo_targets_name}_extra_files)
+ add_custom_target(${target_name})
+
+ set(recursive_glob_patterns
+ ${QT_BUILD_EXTRA_IDE_FILE_RECURSIVE_PATTERNS}
+ )
+ set(simple_glob_patterns
+ .gitattributes
+ .gitignore
+ .tag
+ config_help.txt
+ ${QT_BUILD_EXTRA_IDE_FILE_PATTERNS}
+ )
+
+ if(recursive_glob_patterns)
+ file(GLOB_RECURSE files LIST_DIRECTORIES false FOLLOW_SYMLINKS ${recursive_glob_patterns})
+ if(files)
+ source_group(TREE "${CMAKE_CURRENT_SOURCE_DIR}" FILES ${files})
+ target_sources(${target_name} PRIVATE ${files})
+ endif()
+ endif()
+
+ file(GLOB files LIST_DIRECTORIES false ${simple_glob_patterns})
+ if(files)
+ source_group(TREE "${CMAKE_CURRENT_SOURCE_DIR}" FILES ${files})
+ target_sources(${target_name} PRIVATE ${files})
+ endif()
+endfunction()
+
+
+# Function called either at the end of per-repo configuration, or at the end of configuration of
+# a super build.
+# At the moment it is called before examples are configured in a per-repo build. We might want
+# to change that at some point if needed.
+function(qt_internal_qt_configure_end)
+ # If Qt is configued via the configure script, remove the marker variable, so that any future
+ # reconfigurations that are done by calling cmake directly don't trigger configure specific
+ # logic.
+ if(QT_INTERNAL_CALLED_FROM_CONFIGURE)
+ unset(QT_INTERNAL_CALLED_FROM_CONFIGURE CACHE)
+ endif()
+endfunction()
+
+macro(qt_build_repo)
+ qt_build_repo_begin(${ARGN})
+
+ qt_build_repo_impl_find_package_tests()
+ qt_build_repo_impl_src()
+ qt_build_repo_impl_tools()
+
+ qt_build_repo_post_process()
+ qt_build_repo_impl_tests()
+
+ qt_build_repo_end()
+
+ qt_build_repo_impl_examples()
+endmacro()
+
+macro(qt_build_repo_impl_find_package_tests)
+ # If testing is enabled, try to find the qtbase Test package.
+ # Do this before adding src, because there might be test related conditions
+ # in source.
+ if(QT_BUILD_TESTS AND NOT QT_INTERNAL_BUILD_STANDALONE_PARTS)
+ # When looking for the Test package, do it using the Qt6 package version, in case if
+ # PROJECT_VERSION is following a different versioning scheme.
+ if(Qt6_VERSION)
+ set(_qt_build_repo_impl_find_package_tests_version "${Qt6_VERSION}")
+ else()
+ set(_qt_build_repo_impl_find_package_tests_version "${PROJECT_VERSION}")
+ endif()
+
+ find_package(Qt6
+ "${_qt_build_repo_impl_find_package_tests_version}"
+ CONFIG REQUIRED COMPONENTS Test)
+ unset(_qt_build_repo_impl_find_package_tests_version)
+ endif()
+endmacro()
+
+macro(qt_build_repo_impl_src)
+ if(NOT QT_INTERNAL_BUILD_STANDALONE_PARTS)
+ if (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/src/CMakeLists.txt")
+ add_subdirectory(src)
+ endif()
+ endif()
+ if(QT_FEATURE_lttng AND NOT TARGET LTTng::UST)
+ qt_find_package(LTTngUST PROVIDED_TARGETS LTTng::UST
+ MODULE_NAME global QMAKE_LIB lttng-ust)
+ endif()
+endmacro()
+
+macro(qt_build_repo_impl_tools)
+ if(NOT QT_INTERNAL_BUILD_STANDALONE_PARTS)
+ if (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/tools/CMakeLists.txt")
+ add_subdirectory(tools)
+ endif()
+ endif()
+endmacro()
+
+macro(qt_build_repo_impl_tests)
+ if((QT_BUILD_TESTS OR QT_BUILD_STANDALONE_TESTS)
+ AND EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/tests/CMakeLists.txt")
+ if(QT_BUILD_STANDALONE_EXAMPLES)
+ message(FATAL_ERROR
+ "Can't build both standalone tests and standalone examples at once.")
+ endif()
+ option(QT_BUILD_TESTS_PROJECT_${PROJECT_NAME} "Configure tests for project ${PROJECT_NAME}" TRUE)
+
+ if (QT_BUILD_TESTS_PROJECT_${PROJECT_NAME})
+ add_subdirectory(tests)
+ if(NOT QT_BUILD_TESTS_BY_DEFAULT)
+ set_property(DIRECTORY tests PROPERTY EXCLUDE_FROM_ALL TRUE)
+ endif()
+ endif()
+ endif()
+endmacro()
+
+macro(qt_build_repo_impl_examples)
+ if((QT_BUILD_EXAMPLES OR QT_BUILD_STANDALONE_EXAMPLES)
+ AND EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/examples/CMakeLists.txt")
+ if(QT_BUILD_STANDALONE_TESTS)
+ message(FATAL_ERROR
+ "Can't build both standalone tests and standalone examples at once.")
+ endif()
+
+ message(STATUS "Configuring examples.")
+
+ option(QT_BUILD_EXAMPLES_PROJECT_${PROJECT_NAME} "Configure examples for project ${PROJECT_NAME}" TRUE)
+ if(QT_BUILD_EXAMPLES_PROJECT_${PROJECT_NAME})
+
+ # Set this before any examples subdirectories are added, to warn about examples that are
+ # added via add_subdirectory() calls instead of qt_internal_add_example().
+ if(QT_FEATURE_developer_build
+ AND NOT QT_NO_WARN_ABOUT_EXAMPLE_ADD_SUBDIRECTORY_WARNING)
+ set(QT_WARN_ABOUT_EXAMPLE_ADD_SUBDIRECTORY TRUE)
+ endif()
+
+ add_subdirectory(examples)
+ endif()
+ endif()
+endmacro()
+
+macro(qt_set_up_standalone_tests_build)
+ # Remove this macro once all usages of it have been removed.
+ # Standalone tests are not handled via the main repo project and qt_build_tests.
+endmacro()
+
+function(qt_get_standalone_parts_config_files_path out_var)
+ # TODO: Rename this to StandaloneParts in some future Qt version, if it confuses people too
+ # much. Currently not renamed, not to break distro installation scripts that might exclude
+ # the files.
+ set(dir_name "StandaloneTests")
+
+ set(path_suffix "${INSTALL_LIBDIR}/cmake/${INSTALL_CMAKE_NAMESPACE}BuildInternals/${dir_name}")
+
+ # Each repo's standalone parts might be configured with a unique CMAKE_STAGING_PREFIX,
+ # different from any previous one, and it might not coincide with where the BuildInternals
+ # config file is.
+ if(QT_WILL_INSTALL AND CMAKE_STAGING_PREFIX)
+ qt_path_join(path "${CMAKE_STAGING_PREFIX}" "${path_suffix}")
+ else()
+ qt_path_join(path "${QT_BUILD_INTERNALS_RELOCATABLE_INSTALL_PREFIX}" "${path_suffix}")
+ endif()
+
+ set("${out_var}" "${path}" PARENT_SCOPE)
+endfunction()
+
+function(qt_internal_get_standalone_parts_config_file_name out_var)
+ # When doing a "single repo target set" build (like in qtscxqml) ensure we use a unique tests
+ # config file for each repo target set. Using the PROJECT_NAME only is not enough because
+ # the same file will be overridden with different content on each repo set install.
+ set(tests_config_file_name "${PROJECT_NAME}")
+
+ if(QT_BUILD_SINGLE_REPO_TARGET_SET)
+ string(APPEND tests_config_file_name "RepoSet${QT_BUILD_SINGLE_REPO_TARGET_SET}")
+ endif()
+
+ # TODO: Rename this to StandalonePartsConfig.cmake in some future Qt version, if it confuses
+ # people too much. Currently not renamed, not to break distro installation scripts that might
+ # exclude # the files.
+ string(APPEND tests_config_file_name "TestsConfig.cmake")
+
+ set(${out_var} "${tests_config_file_name}" PARENT_SCOPE)
+endfunction()
+
+macro(qt_internal_find_standalone_test_config_file)
+ if(QT_INTERNAL_BUILD_STANDALONE_PARTS)
+ # Of course we always need the test module as well.
+ # When looking for the Test package, do it using the Qt6 package version, in case if
+ # PROJECT_VERSION is following a different versioning scheme.
+ if(Qt6_VERSION)
+ set(_qt_build_tests_package_version "${Qt6_VERSION}")
+ else()
+ set(_qt_build_tests_package_version "${PROJECT_VERSION}")
+ endif()
+ find_package(Qt6 "${_qt_build_tests_package_version}" CONFIG REQUIRED COMPONENTS Test)
+ unset(_qt_build_tests_package_version)
+ endif()
+endmacro()
+
+# Used by standalone tests and standalone non-ExternalProject examples to find all installed qt
+# packages.
+macro(qt_internal_find_standalone_parts_config_files)
+ if(QT_INTERNAL_BUILD_STANDALONE_PARTS)
+ # Find location of TestsConfig.cmake. These contain the modules that need to be
+ # find_package'd when building tests or examples.
+ qt_get_standalone_parts_config_files_path(_qt_build_parts_install_prefix)
+
+ qt_internal_get_standalone_parts_config_file_name(_qt_parts_config_file_name)
+ set(_qt_standalone_parts_config_file_path
+ "${_qt_build_parts_install_prefix}/${_qt_parts_config_file_name}")
+ include("${_qt_standalone_parts_config_file_path}"
+ OPTIONAL
+ RESULT_VARIABLE _qt_standalone_parts_included)
+ if(NOT _qt_standalone_parts_included)
+ message(DEBUG
+ "Standalone parts config file not included because it does not exist: "
+ "${_qt_standalone_parts_config_file_path}"
+ )
+ else()
+ message(DEBUG
+ "Standalone parts config file included successfully: "
+ "${_qt_standalone_parts_config_file_path}"
+ )
+ endif()
+
+ unset(_qt_standalone_parts_config_file_path)
+ unset(_qt_standalone_parts_included)
+ unset(_qt_parts_config_file_name)
+ endif()
+endmacro()
+
+macro(qt_build_tests)
+ # Tests are not unity-ready.
+ set(CMAKE_UNITY_BUILD OFF)
+
+ # Prepending to QT_BUILD_CMAKE_PREFIX_PATH helps find components of Qt6, because those
+ # find_package calls use NO_DEFAULT_PATH, and thus CMAKE_PREFIX_PATH is ignored.
+ list(PREPEND CMAKE_FIND_ROOT_PATH "${QT_BUILD_DIR}")
+ list(PREPEND QT_BUILD_CMAKE_PREFIX_PATH "${QT_BUILD_DIR}/${INSTALL_LIBDIR}/cmake")
+
+ qt_internal_find_standalone_parts_config_files()
+ qt_internal_find_standalone_test_config_file()
+
+ if(QT_BUILD_STANDALONE_TESTS)
+ # Set language standards after finding Core, because that's when the relevant
+ # feature variables are available, and the call in QtSetup is too early when building
+ # standalone tests, because Core was not find_package()'d yet.
+ qt_set_language_standards()
+
+ # Set up fake standalone parts install prefix, so we don't pollute the Qt install
+ # prefix with tests.
+ qt_internal_set_up_fake_standalone_parts_install_prefix()
+ else()
+ if(ANDROID)
+ # When building in-tree tests we need to specify the QT_ANDROID_ABIS list. Since we
+ # build Qt for the single ABI, build tests for this ABI only.
+ set(QT_ANDROID_ABIS "${CMAKE_ANDROID_ARCH_ABI}")
+ endif()
+ endif()
+
+ if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/auto/CMakeLists.txt")
+ add_subdirectory(auto)
+ endif()
+ if(NOT QT_BUILD_MINIMAL_STATIC_TESTS AND NOT QT_BUILD_MINIMAL_ANDROID_MULTI_ABI_TESTS)
+ if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/baseline/CMakeLists.txt")
+ add_subdirectory(baseline)
+ endif()
+ if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/benchmarks/CMakeLists.txt" AND QT_BUILD_BENCHMARKS)
+ add_subdirectory(benchmarks)
+ endif()
+ if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/manual/CMakeLists.txt" AND QT_BUILD_MANUAL_TESTS)
+ add_subdirectory(manual)
+ # Adding this logic to all tests impacts the configure time ~3sec in addition. We still
+ # might want this in the future for other test types since currently we have a moderate
+ # subset of tests that require manual initialization of autotools.
+ _qt_internal_collect_buildsystem_targets(targets
+ "${CMAKE_CURRENT_SOURCE_DIR}/manual" EXCLUDE UTILITY ALIAS)
+ foreach(target ${targets})
+ qt_autogen_tools(${target} ENABLE_AUTOGEN_TOOLS "moc" "rcc")
+ if(TARGET Qt::Widgets)
+ qt_autogen_tools(${target} ENABLE_AUTOGEN_TOOLS "uic")
+ endif()
+ endforeach()
+ endif()
+ endif()
+
+ set(CMAKE_UNITY_BUILD ${QT_UNITY_BUILD})
+endmacro()
+
+function(qt_compute_relative_path_from_cmake_config_dir_to_prefix)
+ # Compute the reverse relative path from the CMake config dir to the install prefix.
+ # This is used in QtBuildInternalsExtras to create a relocatable relative install prefix path.
+ # This path is used for finding syncqt and other things, regardless of initial install prefix
+ # (e.g installed Qt was archived and unpacked to a different path on a different machine).
+ #
+ # This is meant to be called only once when configuring qtbase.
+ #
+ # Similar code exists in Qt6CoreConfigExtras.cmake.in and src/corelib/CMakeLists.txt which
+ # might not be needed anymore.
+ if(CMAKE_STAGING_PREFIX)
+ set(__qt_prefix "${CMAKE_STAGING_PREFIX}")
+ else()
+ set(__qt_prefix "${CMAKE_INSTALL_PREFIX}")
+ endif()
+
+ if(QT_WILL_INSTALL)
+ get_filename_component(clean_config_prefix
+ "${__qt_prefix}/${QT_CONFIG_INSTALL_DIR}" ABSOLUTE)
+ else()
+ get_filename_component(clean_config_prefix "${QT_CONFIG_BUILD_DIR}" ABSOLUTE)
+ endif()
+ file(RELATIVE_PATH
+ qt_path_from_cmake_config_dir_to_prefix
+ "${clean_config_prefix}" "${__qt_prefix}")
+ set(qt_path_from_cmake_config_dir_to_prefix "${qt_path_from_cmake_config_dir_to_prefix}"
+ PARENT_SCOPE)
+endfunction()
+
+function(qt_get_relocatable_install_prefix out_var)
+ # We need to compute it only once while building qtbase. Afterwards it's loaded from
+ # QtBuildInternalsExtras.cmake.
+ if(QT_BUILD_INTERNALS_RELOCATABLE_INSTALL_PREFIX)
+ return()
+ endif()
+ # The QtBuildInternalsExtras value is dynamically computed, whereas the initial qtbase
+ # configuration uses an absolute path.
+ set(${out_var} "${CMAKE_INSTALL_PREFIX}" PARENT_SCOPE)
+endfunction()
+
+function(qt_internal_get_fake_standalone_install_prefix out_var)
+ set(new_install_prefix "${CMAKE_BINARY_DIR}/fake_prefix")
+ set(${out_var} "${new_install_prefix}" PARENT_SCOPE)
+endfunction()
+
+function(qt_internal_set_up_fake_standalone_parts_install_prefix)
+ # Set a fake local (non-cache) CMAKE_INSTALL_PREFIX.
+ # Needed for standalone tests, we don't want to accidentally install a test into the Qt prefix.
+ # Allow opt-out, if a user knows what they're doing.
+ if(QT_NO_FAKE_STANDALONE_TESTS_INSTALL_PREFIX)
+ return()
+ endif()
+ qt_internal_get_fake_standalone_install_prefix(new_install_prefix)
+
+ # It's IMPORTANT that this is not a cache variable. Otherwise
+ # qt_get_standalone_parts_config_files_path() will not work on re-configuration.
+ message(STATUS
+ "Setting local standalone test install prefix (non-cached) to '${new_install_prefix}'.")
+ set(CMAKE_INSTALL_PREFIX "${new_install_prefix}" PARENT_SCOPE)
+
+ # We also need to clear the staging prefix if it's set, otherwise CMake will modify any computed
+ # rpaths containing the staging prefix to point to the new fake prefix, which is not what we
+ # want. This replacement is done in cmComputeLinkInformation::GetRPath().
+ #
+ # By clearing the staging prefix for the standalone tests, any detected link time
+ # rpaths will be embedded as-is, which will point to the place where Qt was installed (aka
+ # the staging prefix).
+ if(DEFINED CMAKE_STAGING_PREFIX)
+ message(STATUS "Clearing local standalone test staging prefix (non-cached).")
+ set(CMAKE_STAGING_PREFIX "" PARENT_SCOPE)
+ endif()
+endfunction()
+
+# Meant to be called when configuring examples as part of the main build tree (unless standalone
+# examples are being built), as well as for CMake tests (tests that call CMake to try and build
+# CMake applications).
+macro(qt_internal_set_up_build_dir_package_paths)
+ list(PREPEND CMAKE_PREFIX_PATH "${QT_BUILD_DIR}/${INSTALL_LIBDIR}/cmake")
+
+ # Make sure the CMake config files do not recreate the already-existing targets.
+ if(NOT QT_BUILD_STANDALONE_EXAMPLES)
+ set(QT_NO_CREATE_TARGETS TRUE)
+ endif()
+endmacro()
+
+function(qt_internal_static_link_order_test)
+ # The CMake versions greater than 3.21 take care about the resource object files order in a
+ # linker line, it's expected that all object files are located at the beginning of the linker
+ # line.
+ # No need to run the test.
+ if(CMAKE_VERSION VERSION_LESS 3.21)
+ __qt_internal_check_link_order_matters(link_order_matters)
+ if(link_order_matters)
+ set(summary_message "no")
+ else()
+ set(summary_message "yes")
+ endif()
+ else()
+ set(summary_message "yes")
+ endif()
+ qt_configure_add_summary_entry(TYPE "message"
+ ARGS "Linker can resolve circular dependencies"
+ MESSAGE "${summary_message}"
+ )
+endfunction()
+
+function(qt_internal_check_cmp0099_available)
+ # Don't care about CMP0099 in CMake versions greater than or equal to 3.21
+ if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.21)
+ return()
+ endif()
+
+ __qt_internal_check_cmp0099_available(result)
+ if(result)
+ set(summary_message "yes")
+ else()
+ set(summary_message "no")
+ endif()
+ qt_configure_add_summary_entry(TYPE "message"
+ ARGS "CMake policy CMP0099 is supported"
+ MESSAGE "${summary_message}"
+ )
+endfunction()
+
+function(qt_internal_run_common_config_tests)
+ qt_configure_add_summary_section(NAME "Common build options")
+ qt_internal_static_link_order_test()
+ qt_internal_check_cmp0099_available()
+ qt_configure_end_summary_section()
+endfunction()
+
+# It is used in QtWebEngine to replace the REALPATH with ABSOLUTE path, which is
+# useful for building Qt in Homebrew.
+function(qt_internal_get_filename_path_mode out_var)
+ set(mode REALPATH)
+ if(APPLE AND QT_ALLOW_SYMLINK_IN_PATHS)
+ set(mode ABSOLUTE)
+ endif()
+ set(${out_var} ${mode} PARENT_SCOPE)
+endfunction()
+
+macro(qt_internal_setup_platform_support_variables)
+ # Define some constants to check for certain platforms, etc.
+ # Needs to be loaded before qt_repo_build() to handle require() clauses before even starting a
+ # repo build.
+ include(QtPlatformSupport)
+endmacro()
+
+function(qt_build_internals_set_up_system_prefixes)
+ if(APPLE AND NOT FEATURE_pkg_config)
+ # Remove /usr/local and other paths like that which CMake considers as system prefixes on
+ # darwin platforms. CMake considers them as system prefixes, but in qmake / Qt land we only
+ # consider the SDK path as a system prefix.
+ # 3rd party libraries in these locations should not be picked up when building Qt,
+ # unless opted-in via the pkg-config feature, which in turn will disable this behavior.
+ #
+ # Note that we can't remove /usr as a system prefix path, because many programs won't be
+ # found then (e.g. perl).
+ set(QT_CMAKE_SYSTEM_PREFIX_PATH_BACKUP "${CMAKE_SYSTEM_PREFIX_PATH}" PARENT_SCOPE)
+ set(QT_CMAKE_SYSTEM_FRAMEWORK_PATH_BACKUP "${CMAKE_SYSTEM_FRAMEWORK_PATH}" PARENT_SCOPE)
+
+ list(REMOVE_ITEM CMAKE_SYSTEM_PREFIX_PATH
+ "/usr/local" # Homebrew
+ "/opt/homebrew" # Apple Silicon Homebrew
+ "/usr/X11R6"
+ "/usr/pkg"
+ "/opt"
+ "/sw" # Fink
+ "/opt/local" # MacPorts
+ )
+ if(_CMAKE_INSTALL_DIR)
+ list(REMOVE_ITEM CMAKE_SYSTEM_PREFIX_PATH "${_CMAKE_INSTALL_DIR}")
+ endif()
+ list(REMOVE_ITEM CMAKE_SYSTEM_FRAMEWORK_PATH "~/Library/Frameworks")
+ set(CMAKE_SYSTEM_PREFIX_PATH "${CMAKE_SYSTEM_PREFIX_PATH}" PARENT_SCOPE)
+ set(CMAKE_SYSTEM_FRAMEWORK_PATH "${CMAKE_SYSTEM_FRAMEWORK_PATH}" PARENT_SCOPE)
+
+ # Also tell qt_find_package() not to use PATH when looking for packages.
+ # We can't simply set CMAKE_FIND_USE_SYSTEM_ENVIRONMENT_PATH to OFF because that will break
+ # find_program(), and for instance ccache won't be found.
+ # That's why we set a different variable which is used by qt_find_package.
+ set(QT_NO_USE_FIND_PACKAGE_SYSTEM_ENVIRONMENT_PATH "ON" PARENT_SCOPE)
+ endif()
+endfunction()
+
+function(qt_build_internals_disable_pkg_config_if_needed)
+ # pkg-config should not be used by default on Darwin and Windows platforms (and QNX), as defined
+ # in the qtbase/configure.json. Unfortunately by the time the feature is evaluated there are
+ # already a few find_package() calls that try to use the FindPkgConfig module.
+ # Thus, we have to duplicate the condition logic here and disable pkg-config for those platforms
+ # by default.
+ # We also need to check if the pkg-config executable exists, to mirror the condition test in
+ # configure.json. We do that by trying to find the executable ourselves, and not delegating to
+ # the FindPkgConfig module because that has more unwanted side-effects.
+ #
+ # Note that on macOS, if the pkg-config feature is enabled by the user explicitly, we will also
+ # tell CMake to consider paths like /usr/local (Homebrew) as system paths when looking for
+ # packages.
+ # We have to do that because disabling these paths but keeping pkg-config
+ # enabled won't enable finding all system libraries via pkg-config alone, many libraries can
+ # only be found via FooConfig.cmake files which means /usr/local should be in the system prefix
+ # path.
+
+ set(pkg_config_enabled ON)
+ qt_build_internals_find_pkg_config_executable()
+
+ if(APPLE OR WIN32 OR QNX OR ANDROID OR WASM OR (NOT PKG_CONFIG_EXECUTABLE))
+ set(pkg_config_enabled OFF)
+ endif()
+
+ # If user explicitly specified a value for the feature, honor it, even if it might break
+ # the build.
+ if(DEFINED FEATURE_pkg_config)
+ if(FEATURE_pkg_config)
+ set(pkg_config_enabled ON)
+ else()
+ set(pkg_config_enabled OFF)
+ endif()
+ endif()
+
+ set(FEATURE_pkg_config "${pkg_config_enabled}" CACHE STRING "Using pkg-config")
+ if(NOT pkg_config_enabled)
+ qt_build_internals_disable_pkg_config()
+ else()
+ unset(PKG_CONFIG_EXECUTABLE CACHE)
+ endif()
+endfunction()
+
+# This is a copy of the first few lines in FindPkgConfig.cmake.
+function(qt_build_internals_find_pkg_config_executable)
+ # find pkg-config, use PKG_CONFIG if set
+ if((NOT PKG_CONFIG_EXECUTABLE) AND (NOT "$ENV{PKG_CONFIG}" STREQUAL ""))
+ set(PKG_CONFIG_EXECUTABLE "$ENV{PKG_CONFIG}" CACHE FILEPATH "pkg-config executable")
+ endif()
+ find_program(PKG_CONFIG_EXECUTABLE NAMES pkg-config DOC "pkg-config executable")
+ mark_as_advanced(PKG_CONFIG_EXECUTABLE)
+endfunction()
+
+function(qt_build_internals_disable_pkg_config)
+ # Disable pkg-config by setting an empty executable path. There's no documented way to
+ # mark the package as not found, but we can force all pkg_check_modules calls to do nothing
+ # by setting the variable to an empty value.
+ set(PKG_CONFIG_EXECUTABLE "" CACHE STRING "Disabled pkg-config usage." FORCE)
+endfunction()
+
+macro(qt_build_internals_find_pkg_config)
+ # Find package config once before any system prefix modifications.
+ find_package(PkgConfig QUIET)
+endmacro()
+
+
+macro(qt_internal_setup_pkg_config_and_system_prefixes)
+ if(NOT QT_BUILD_INTERNALS_SKIP_PKG_CONFIG_ADJUSTMENT)
+ qt_build_internals_disable_pkg_config_if_needed()
+ endif()
+
+ if(NOT QT_BUILD_INTERNALS_SKIP_FIND_PKG_CONFIG)
+ qt_build_internals_find_pkg_config()
+ endif()
+
+ if(NOT QT_BUILD_INTERNALS_SKIP_SYSTEM_PREFIX_ADJUSTMENT)
+ qt_build_internals_set_up_system_prefixes()
+ endif()
+endmacro()
+
+macro(qt_internal_setup_standalone_test_when_called_as_a_find_package_component)
+ if ("STANDALONE_TEST" IN_LIST Qt6BuildInternals_FIND_COMPONENTS)
+ include(${CMAKE_CURRENT_LIST_DIR}/QtStandaloneTestTemplateProject/Main.cmake)
+ if (NOT PROJECT_VERSION_MAJOR)
+ get_property(_qt_major_version TARGET ${QT_CMAKE_EXPORT_NAMESPACE}::Core PROPERTY INTERFACE_QT_MAJOR_VERSION)
+ set(PROJECT_VERSION ${Qt${_qt_major_version}Core_VERSION})
+
+ string(REPLACE "." ";" _qt_core_version_list ${PROJECT_VERSION})
+ list(GET _qt_core_version_list 0 PROJECT_VERSION_MAJOR)
+ list(GET _qt_core_version_list 1 PROJECT_VERSION_MINOR)
+ list(GET _qt_core_version_list 2 PROJECT_VERSION_PATCH)
+ endif()
+ endif()
+endmacro()
+
+macro(qt_internal_setup_build_internals)
+ qt_internal_set_qt_repo_dependencies()
+ qt_internal_setup_platform_support_variables()
+ qt_internal_setup_pkg_config_and_system_prefixes()
+ qt_internal_setup_standalone_test_when_called_as_a_find_package_component()
+endmacro()
+
+# Recursively reads the dependencies section from dependencies.yaml in ${repo_dir} and returns the
+# list of dependencies, including transitive ones, in out_var.
+#
+# The returned dependencies are topologically sorted.
+#
+# Example output for qtdeclarative:
+# qtbase;qtimageformats;qtlanguageserver;qtshadertools;qtsvg
+#
+function(qt_internal_read_repo_dependencies out_var repo_dir)
+ set(seen ${ARGN})
+ set(dependencies "")
+ set(in_dependencies_section FALSE)
+ set(dependencies_file "${repo_dir}/dependencies.yaml")
+ if(EXISTS "${dependencies_file}")
+ file(STRINGS "${dependencies_file}" lines)
+ foreach(line IN LISTS lines)
+ if(line MATCHES "^([^ ]+):")
+ if(CMAKE_MATCH_1 STREQUAL "dependencies")
+ set(in_dependencies_section TRUE)
+ else()
+ set(in_dependencies_section FALSE)
+ endif()
+ elseif(in_dependencies_section AND line MATCHES "^ (.+):$")
+ set(dependency "${CMAKE_MATCH_1}")
+ set(dependency_repo_dir "${repo_dir}/${dependency}")
+ string(REGEX MATCH "[^/]+$" dependency "${dependency}")
+ if(NOT dependency IN_LIST seen)
+ qt_internal_read_repo_dependencies(subdeps "${dependency_repo_dir}"
+ ${seen} ${dependency})
+ if(dependency MATCHES "^tqtc-(.+)")
+ set(dependency "${CMAKE_MATCH_1}")
+ endif()
+ list(APPEND dependencies ${subdeps} ${dependency})
+ endif()
+ endif()
+ endforeach()
+ list(REMOVE_DUPLICATES dependencies)
+ endif()
+ set(${out_var} "${dependencies}" PARENT_SCOPE)
+endfunction()
+
+macro(qt_internal_set_qt_repo_dependencies)
+ # The top-level check needs to happen because it's possible
+ # to configure a top-level build with a few repos and then configure another repo
+ # using qt-configure-module in a separate build dir, where QT_SUPERBUILD will not
+ # be set anymore.
+ if(DEFINED QT_REPO_MODULE_VERSION AND NOT DEFINED QT_REPO_DEPENDENCIES AND NOT QT_SUPERBUILD)
+ qt_internal_read_repo_dependencies(QT_REPO_DEPENDENCIES "${PROJECT_SOURCE_DIR}")
+ endif()
+endmacro()
diff --git a/cmake/QtCMakeHelpers.cmake b/cmake/QtCMakeHelpers.cmake
new file mode 100644
index 0000000000..142a003cbc
--- /dev/null
+++ b/cmake/QtCMakeHelpers.cmake
@@ -0,0 +1,235 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+# The common implementation of qt_configure_file functionality.
+macro(qt_configure_file_impl)
+ if(NOT arg_OUTPUT)
+ message(FATAL_ERROR "No output file provided to qt_configure_file.")
+ endif()
+
+ # We use this check for the cases when the specified CONTENT is empty. The value of arg_CONTENT
+ # is undefined, but we still want to create a file with empty content.
+ if(NOT "CONTENT" IN_LIST arg_KEYWORDS_MISSING_VALUES)
+ if(arg_INPUT)
+ message(WARNING "Both CONTENT and INPUT are specified. CONTENT will be used to generate"
+ " output")
+ endif()
+ set(template_name "QtFileConfigure.txt.in")
+ # When building qtbase, use the source template file.
+ # Otherwise use the installed file (basically wherever Qt6 package is found).
+ # This should work for non-prefix and superbuilds as well.
+ if(QtBase_SOURCE_DIR)
+ set(input_file "${QtBase_SOURCE_DIR}/cmake/${template_name}")
+ else()
+ set(input_file "${_qt_6_config_cmake_dir}/${template_name}")
+ endif()
+ set(__qt_file_configure_content "${arg_CONTENT}")
+ elseif(arg_INPUT)
+ set(input_file "${arg_INPUT}")
+ else()
+ message(FATAL_ERROR "No input value provided to qt_configure_file.")
+ endif()
+
+ configure_file("${input_file}" "${arg_OUTPUT}" @ONLY)
+endmacro()
+
+# qt_configure_file(OUTPUT output-file <INPUT input-file | CONTENT content>)
+# input-file is relative to ${CMAKE_CURRENT_SOURCE_DIR}
+# output-file is relative to ${CMAKE_CURRENT_BINARY_DIR}
+#
+# This function is similar to file(GENERATE OUTPUT) except it writes the content
+# to the file at configure time, rather than at generate time.
+#
+# TODO: Once we require 3.18+, this can use file(CONFIGURE) in its implementation,
+# or maybe its usage can be replaced by file(CONFIGURE). Until then, it uses
+# configure_file() with a generic input file as source, when used with the CONTENT
+# signature.
+function(qt_configure_file)
+ cmake_parse_arguments(PARSE_ARGV 0 arg "" "OUTPUT;INPUT;CONTENT" "")
+ qt_configure_file_impl()
+endfunction()
+
+# A version of cmake_parse_arguments that makes sure all arguments are processed and errors out
+# with a message about ${type} having received unknown arguments.
+#
+# TODO: Remove when all usage of qt_parse_all_arguments were replaced by
+# cmake_parse_all_arguments(PARSEARGV) instances
+macro(qt_parse_all_arguments result type flags options multiopts)
+ cmake_parse_arguments(${result} "${flags}" "${options}" "${multiopts}" ${ARGN})
+ if(DEFINED ${result}_UNPARSED_ARGUMENTS)
+ message(FATAL_ERROR "Unknown arguments were passed to ${type} (${${result}_UNPARSED_ARGUMENTS}).")
+ endif()
+endmacro()
+
+# Checks whether any unparsed arguments have been passed to the function at the call site.
+# Use this right after `cmake_parse_arguments`.
+function(_qt_internal_validate_all_args_are_parsed prefix)
+ if(DEFINED ${prefix}_UNPARSED_ARGUMENTS)
+ message(FATAL_ERROR "Unknown arguments: (${${prefix}_UNPARSED_ARGUMENTS})")
+ endif()
+endfunction()
+
+# Print all variables defined in the current scope.
+macro(qt_debug_print_variables)
+ cmake_parse_arguments(__arg "DEDUP" "" "MATCH;IGNORE" ${ARGN})
+ message("Known Variables:")
+ get_cmake_property(__variableNames VARIABLES)
+ list (SORT __variableNames)
+ if (__arg_DEDUP)
+ list(REMOVE_DUPLICATES __variableNames)
+ endif()
+
+ foreach(__var ${__variableNames})
+ set(__ignore OFF)
+ foreach(__i ${__arg_IGNORE})
+ if(__var MATCHES "${__i}")
+ set(__ignore ON)
+ break()
+ endif()
+ endforeach()
+
+ if (__ignore)
+ continue()
+ endif()
+
+ set(__show OFF)
+ foreach(__i ${__arg_MATCH})
+ if(__var MATCHES "${__i}")
+ set(__show ON)
+ break()
+ endif()
+ endforeach()
+
+ if (__show)
+ message(" ${__var}=${${__var}}.")
+ endif()
+ endforeach()
+endmacro()
+
+macro(assert)
+ if (${ARGN})
+ else()
+ message(FATAL_ERROR "ASSERT: ${ARGN}.")
+ endif()
+endmacro()
+
+# Takes a list of path components and joins them into one path separated by forward slashes "/",
+# and saves the path in out_var.
+function(qt_path_join out_var)
+ string(JOIN "/" path ${ARGN})
+ set(${out_var} ${path} PARENT_SCOPE)
+endfunction()
+
+# qt_remove_args can remove arguments from an existing list of function
+# arguments in order to pass a filtered list of arguments to a different function.
+# Parameters:
+# out_var: result of remove all arguments specified by ARGS_TO_REMOVE from ALL_ARGS
+# ARGS_TO_REMOVE: Arguments to remove.
+# ALL_ARGS: All arguments supplied to cmake_parse_arguments
+# from which ARGS_TO_REMOVE should be removed from. We require all the
+# arguments or we can't properly identify the range of the arguments detailed
+# in ARGS_TO_REMOVE.
+# ARGS: Arguments passed into the function, usually ${ARGV}
+#
+# E.g.:
+# We want to forward all arguments from foo to bar, execpt ZZZ since it will
+# trigger an error in bar.
+#
+# foo(target BAR .... ZZZ .... WWW ...)
+# bar(target BAR.... WWW...)
+#
+# function(foo target)
+# cmake_parse_arguments(PARSE_ARGV 1 arg "" "" "BAR;ZZZ;WWW")
+# qt_remove_args(forward_args
+# ARGS_TO_REMOVE ${target} ZZZ
+# ALL_ARGS ${target} BAR ZZZ WWW
+# ARGS ${ARGV}
+# )
+# bar(${target} ${forward_args})
+# endfunction()
+#
+function(qt_remove_args out_var)
+ cmake_parse_arguments(arg "" "" "ARGS_TO_REMOVE;ALL_ARGS;ARGS" ${ARGN})
+ set(result ${arg_ARGS})
+ foreach(arg IN LISTS arg_ARGS_TO_REMOVE)
+ # find arg
+ list(FIND result ${arg} find_result)
+ if (NOT find_result EQUAL -1)
+ # remove arg
+ list(REMOVE_AT result ${find_result})
+ list(LENGTH result result_len)
+ if(find_result EQUAL result_len)
+ # We removed the last argument, could have been an option keyword
+ continue()
+ endif()
+ list(GET result ${find_result} arg_current)
+ # remove values until we hit another arg or the end of the list
+ while(NOT "${arg_current}" IN_LIST arg_ALL_ARGS AND find_result LESS result_len)
+ list(REMOVE_AT result ${find_result})
+ list(LENGTH result result_len)
+ if (NOT find_result EQUAL result_len)
+ list(GET result ${find_result} arg_current)
+ endif()
+ endwhile()
+ endif()
+ endforeach()
+ set(${out_var} "${result}" PARENT_SCOPE)
+endfunction()
+
+# Creates a regular expression that exactly matches the given string
+# Found in https://gitlab.kitware.com/cmake/cmake/issues/18580
+function(qt_re_escape out_var str)
+ string(REGEX REPLACE "([][+.*()^])" "\\\\\\1" regex "${str}")
+ set(${out_var} ${regex} PARENT_SCOPE)
+endfunction()
+
+# Input: string
+# Output: regex string to match the string case insensitively
+# Example: "Release" -> "^([Rr][Ee][Ll][Ee][Aa][Ss][Ee])$"
+#
+# Regular expressions like this are used in cmake_install.cmake files for case-insensitive string
+# comparison.
+function(qt_create_case_insensitive_regex out_var input)
+ set(result "^(")
+ string(LENGTH "${input}" n)
+ math(EXPR n "${n} - 1")
+ foreach(i RANGE 0 ${n})
+ string(SUBSTRING "${input}" ${i} 1 c)
+ string(TOUPPER "${c}" uc)
+ string(TOLOWER "${c}" lc)
+ string(APPEND result "[${uc}${lc}]")
+ endforeach()
+ string(APPEND result ")$")
+ set(${out_var} "${result}" PARENT_SCOPE)
+endfunction()
+
+# Gets a target property, and returns "" if the property was not found
+function(qt_internal_get_target_property out_var target property)
+ get_target_property(result "${target}" "${property}")
+ if("${result}" STREQUAL "result-NOTFOUND")
+ set(result "")
+ endif()
+ set(${out_var} "${result}" PARENT_SCOPE)
+endfunction()
+
+# Creates a wrapper ConfigVersion.cmake file to be loaded by find_package when checking for
+# compatible versions. It expects a ConfigVersionImpl.cmake file in the same directory which will
+# be included to do the regular version checks.
+# The version check result might be overridden by the wrapper.
+# package_name is used by the content of the wrapper file to include the basic package version file.
+# example: Qt6Gui
+# out_path should be the build path where the write the file.
+function(qt_internal_write_qt_package_version_file package_name out_path)
+ set(extra_code "")
+
+ # Need to check for FEATURE_developer_build as well, because QT_FEATURE_developer_build is not
+ # yet available when configuring the file for the BuildInternals package.
+ if(FEATURE_developer_build OR QT_FEATURE_developer_build)
+ string(APPEND extra_code "
+# Disabling version check because Qt was configured with -developer-build.
+set(__qt_disable_package_version_check TRUE)
+set(__qt_disable_package_version_check_due_to_developer_build TRUE)")
+ endif()
+
+ configure_file("${QT_CMAKE_DIR}/QtCMakePackageVersionFile.cmake.in" "${out_path}" @ONLY)
+endfunction()
diff --git a/cmake/QtCMakePackageVersionFile.cmake.in b/cmake/QtCMakePackageVersionFile.cmake.in
new file mode 100644
index 0000000000..d4c30b33ac
--- /dev/null
+++ b/cmake/QtCMakePackageVersionFile.cmake.in
@@ -0,0 +1,68 @@
+# Copyright (C) 2024 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+# Include the basic version config file to get results of regular version checking.
+include("${CMAKE_CURRENT_LIST_DIR}/@package_name@ConfigVersionImpl.cmake")
+
+set(__qt_disable_package_version_check FALSE)
+
+# Allow to opt out of the version check.
+if(QT_NO_PACKAGE_VERSION_CHECK)
+ set(__qt_disable_package_version_check TRUE)
+endif()
+
+# Extra CMake code begin
+@extra_code@
+# Extra CMake code end
+
+if((NOT PACKAGE_VERSION_COMPATIBLE) OR PACKAGE_VERSION_UNSUITABLE)
+ set(__qt_package_version_incompatible TRUE)
+else()
+ set(__qt_package_version_incompatible FALSE)
+endif()
+
+if(__qt_disable_package_version_check)
+ # Don't show the warning needlessly if we know that we're doing an exact search, and the
+ # version found is not the exactly same.
+ if(${CMAKE_FIND_PACKAGE_NAME}_FIND_VERSION_EXACT
+ AND NOT PACKAGE_FIND_VERSION STREQUAL PACKAGE_VERSION)
+ set(QT_NO_PACKAGE_VERSION_INCOMPATIBLE_WARNING TRUE)
+ endif()
+
+ # Warn if version check is disabled regardless if it's a Qt repo build or user project build.
+ # Allow to opt out of warning.
+ if(__qt_package_version_incompatible AND NOT QT_NO_PACKAGE_VERSION_INCOMPATIBLE_WARNING
+ AND NOT ${CMAKE_FIND_PACKAGE_NAME}_FIND_QUIETLY)
+ message(WARNING
+ "Package ${PACKAGE_FIND_NAME} with version ${PACKAGE_VERSION} was accepted as "
+ "compatible because QT_NO_PACKAGE_VERSION_CHECK was set to TRUE. There is no guarantee "
+ "the build will succeed. You can silence this warning by passing "
+ "-DQT_NO_PACKAGE_VERSION_INCOMPATIBLE_WARNING=TRUE")
+ endif()
+
+ # Mark version as compatible. This is how we disable the version check.
+ set(PACKAGE_VERSION_COMPATIBLE TRUE)
+ unset(PACKAGE_VERSION_UNSUITABLE)
+
+# If QT_REPO_MODULE_VERSION is set, that means we are building a Qt repo. Show message that one can
+# disable the check if they need to.
+elseif(QT_REPO_MODULE_VERSION AND __qt_package_version_incompatible)
+ if(PACKAGE_FIND_VERSION_RANGE)
+ set(__qt_package_version_message_prefix "Version range ${PACKAGE_FIND_VERSION_RANGE}")
+ else()
+ set(__qt_package_version_message_prefix "Version ${PACKAGE_FIND_VERSION}")
+ endif()
+
+ message(WARNING
+ "${__qt_package_version_message_prefix} of package ${PACKAGE_FIND_NAME} was requested but "
+ "an incompatible version was found: ${PACKAGE_VERSION}. You can pass "
+ "-DQT_NO_PACKAGE_VERSION_CHECK=TRUE to disable the version check and force the "
+ "incompatible version to be used. There is no guarantee the build will succeed. "
+ "Use at your own risk. "
+ "You can silence this warning by passing -DQT_NO_PACKAGE_VERSION_INCOMPATIBLE_WARNING=TRUE")
+endif()
+
+unset(__qt_disable_package_version_check)
+unset(__qt_disable_package_version_check_due_to_developer_build)
+unset(__qt_package_version_message_prefix)
+unset(__qt_package_version_incompatible)
diff --git a/cmake/QtCMakeVersionHelpers.cmake b/cmake/QtCMakeVersionHelpers.cmake
new file mode 100644
index 0000000000..322e58eed1
--- /dev/null
+++ b/cmake/QtCMakeVersionHelpers.cmake
@@ -0,0 +1,236 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+# Returns the minimum supported CMake version required to /build/ Qt as originally advertised by Qt.
+function(qt_internal_get_supported_min_cmake_version_for_building_qt out_var)
+ if(NOT DEFINED BUILD_SHARED_LIBS)
+ message(FATAL_ERROR "BUILD_SHARED_LIBS is needed to decide the minimum CMake version. "
+ "It should have been set by this point.")
+ endif()
+
+ # First check if a value is already set in QtBuildInternalsExtras.cmake, which means we're
+ # building a repo other than qtbase and the minimum version was already recorded.
+ if(QT_SUPPORTED_MIN_CMAKE_VERSION_FOR_BUILDING_QT)
+ set(supported_version "${QT_SUPPORTED_MIN_CMAKE_VERSION_FOR_BUILDING_QT}")
+
+ # We're building qtbase so the values come from .cmake.conf.
+ elseif(APPLE)
+ set(supported_version "${QT_SUPPORTED_MIN_CMAKE_VERSION_FOR_BUILDING_QT_APPLE}")
+ elseif(BUILD_SHARED_LIBS)
+ set(supported_version "${QT_SUPPORTED_MIN_CMAKE_VERSION_FOR_BUILDING_QT_SHARED}")
+ else()
+ set(supported_version "${QT_SUPPORTED_MIN_CMAKE_VERSION_FOR_BUILDING_QT_STATIC}")
+ endif()
+
+ set(${out_var} "${supported_version}" PARENT_SCOPE)
+endfunction()
+
+# Returns the minimum supported CMake version required to /use/ Qt as originally advertised by Qt.
+function(qt_internal_get_supported_min_cmake_version_for_using_qt out_var)
+ if(NOT DEFINED BUILD_SHARED_LIBS)
+ message(FATAL_ERROR "BUILD_SHARED_LIBS is needed to decide the minimum CMake version. "
+ "It should have been set by this point.")
+ endif()
+
+ if(APPLE)
+ set(supported_version "${QT_SUPPORTED_MIN_CMAKE_VERSION_FOR_USING_QT_APPLE}")
+ elseif(BUILD_SHARED_LIBS)
+ set(supported_version "${QT_SUPPORTED_MIN_CMAKE_VERSION_FOR_USING_QT_SHARED}")
+ else()
+ set(supported_version "${QT_SUPPORTED_MIN_CMAKE_VERSION_FOR_USING_QT_STATIC}")
+ endif()
+
+ set(${out_var} "${supported_version}" PARENT_SCOPE)
+endfunction()
+
+# Returns the computed minimum supported CMake version required to /build/ Qt.
+function(qt_internal_get_computed_min_cmake_version_for_building_qt out_var)
+ # An explicit override for those that take it upon themselves to fix the build system
+ # when using a CMake version lower than the one officially supported.
+ # Also useful for build testing locally with different minimum versions to observe different
+ # policy behaviors.
+ if(QT_FORCE_MIN_CMAKE_VERSION_FOR_BUILDING_QT)
+ set(computed_min_version "${QT_FORCE_MIN_CMAKE_VERSION_FOR_BUILDING_QT}")
+
+ # Set in QtBuildInternalsExtras.cmake, which means it was already computed as part of qtbase
+ # configuration.
+ elseif(QT_COMPUTED_MIN_CMAKE_VERSION_FOR_BUILDING_QT)
+ set(computed_min_version "${QT_COMPUTED_MIN_CMAKE_VERSION_FOR_BUILDING_QT}")
+
+ # No override was given and the version was not computed before, thus initialize with the
+ # default minimum.
+ else()
+ qt_internal_get_supported_min_cmake_version_for_building_qt(min_supported_version)
+ set(computed_min_version "${min_supported_version}")
+ endif()
+ set(${out_var} "${computed_min_version}" PARENT_SCOPE)
+endfunction()
+
+# Returns the computed minimum supported CMake version required to /use/ Qt.
+function(qt_internal_get_computed_min_cmake_version_for_using_qt out_var)
+ # Allow overriding the required minimum CMake version for user projects, without forcing
+ # each project developer to have to override it manually.
+ if(QT_FORCE_MIN_CMAKE_VERSION_FOR_USING_QT)
+ set(computed_min_version "${QT_FORCE_MIN_CMAKE_VERSION_FOR_USING_QT}")
+
+ # No override was given, thus initialize with the default minimum.
+ else()
+ qt_internal_get_supported_min_cmake_version_for_using_qt(min_supported_version)
+ set(computed_min_version "${min_supported_version}")
+ endif()
+ set(${out_var} "${computed_min_version}" PARENT_SCOPE)
+endfunction()
+
+# Returns the oldest CMake version for which NEW policies should be enabled.
+# It can be older than the minimum supported or computed CMake version, as it
+# is only used for policy settings. The currently running CMake must not be
+# older than this version though (doing so will result in an error).
+function(qt_internal_get_min_new_policy_cmake_version out_var)
+ # QT_MIN_NEW_POLICY_CMAKE_VERSION is set either in .cmake.conf or in
+ # QtBuildInternalsExtras.cmake when building a child repo.
+ set(lower_version "${QT_MIN_NEW_POLICY_CMAKE_VERSION}")
+ set(${out_var} "${lower_version}" PARENT_SCOPE)
+endfunction()
+
+# Returns the latest CMake version for which NEW policies should be enabled.
+# This cannot be less than the minimum CMake policy version or we will end up
+# specifying a version range with the max less than the min.
+function(qt_internal_get_max_new_policy_cmake_version out_var)
+ # QT_MAX_NEW_POLICY_CMAKE_VERSION is set either in .cmake.conf or in
+ # QtBuildInternalsExtras.cmake when building a child repo.
+ set(upper_version "${QT_MAX_NEW_POLICY_CMAKE_VERSION}")
+ qt_internal_get_min_new_policy_cmake_version(lower_version)
+ if(upper_version VERSION_LESS lower_version)
+ set(upper_version ${lower_version})
+ endif()
+ set(${out_var} "${upper_version}" PARENT_SCOPE)
+endfunction()
+
+function(qt_internal_check_and_warn_about_unsuitable_cmake_version)
+ # Don't show the warnings multiple times in a top-level build.
+ get_cmake_property(check_done _qt_unsuitable_cmake_version_check_done)
+ if(check_done)
+ return()
+ endif()
+ set_property(GLOBAL PROPERTY _qt_unsuitable_cmake_version_check_done TRUE)
+
+ qt_internal_warn_if_min_cmake_version_not_met()
+ qt_internal_warn_about_buggy_cmake_versions()
+endfunction()
+
+# Function to be used in downstream repos (like qtsvg) to require a minimum CMake version and warn
+# about unsuitable cmake versions.
+#
+# Such repos don't have the required version information at cmake_minimum_required() time, that's
+# why we provide this function to be called at a time when the info is available.
+function(qt_internal_require_suitable_cmake_version)
+ qt_internal_check_and_warn_about_unsuitable_cmake_version()
+ qt_internal_get_computed_min_cmake_version_for_building_qt(computed_min_version)
+
+ if(CMAKE_VERSION VERSION_LESS computed_min_version)
+ set(major_minor "${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}")
+ message(FATAL_ERROR
+ "CMake ${computed_min_version} or higher is required. "
+ "You are running version ${CMAKE_VERSION} "
+ "\nQt requires newer CMake features to build correctly. You can lower the minimum "
+ "required version by passing "
+ "-DQT_FORCE_MIN_CMAKE_VERSION_FOR_BUILDING_QT=${major_minor} when configuring Qt. "
+ "Building Qt with this CMake version is not officially supported. Use at your own risk."
+ )
+ endif()
+endfunction()
+
+function(qt_internal_warn_if_min_cmake_version_not_met)
+ qt_internal_get_supported_min_cmake_version_for_building_qt(min_supported_version)
+ qt_internal_get_computed_min_cmake_version_for_building_qt(computed_min_version)
+
+ if(NOT min_supported_version STREQUAL computed_min_version
+ AND computed_min_version VERSION_LESS min_supported_version)
+ message(WARNING
+ "The minimum required CMake version to build Qt is: '${min_supported_version}'. "
+ "You have explicitly chosen to require a lower minimum CMake version: '${computed_min_version}'. "
+ "Building Qt with this CMake version is not officially supported. Use at your own risk.")
+ endif()
+endfunction()
+
+function(qt_internal_warn_about_buggy_cmake_versions)
+ set(unsuitable_versions "")
+
+ # Touching a library's source file causes unnecessary rebuilding of unrelated targets.
+ # https://gitlab.kitware.com/cmake/cmake/-/issues/21020
+ list(APPEND unsuitable_versions "3.18.0")
+
+ # Ninja Multi-Config race condition overrides response files of different configurations
+ # https://gitlab.kitware.com/cmake/cmake/-/issues/20961
+ # https://gitlab.kitware.com/cmake/cmake/-/issues/21050 (follow up issue)
+ list(APPEND unsuitable_versions "3.18.1")
+
+ # AUTOMOC dependencies are not properly created when using Ninja Multi-Config.
+ # https://gitlab.kitware.com/cmake/cmake/-/issues/21118
+ #
+ # Also until 3.18.2 inclusive, AUTOMOC dependencies are out-of-date if a previously header
+ # disappears (for example when upgrading a compiler)
+ # https://gitlab.kitware.com/cmake/cmake/-/issues/21136
+ #
+ # Also multi-arch PCH doesn't work on iOS. Can't quite find the original upstream CMake issue
+ # but the Qt one was detected at https://codereview.qt-project.org/c/qt/qt5/+/310947
+ # And a follow up issue regarding PCH and -fembed-bitcode failing.
+ # https://gitlab.kitware.com/cmake/cmake/-/issues/21163
+ list(APPEND unsuitable_versions "3.18.2")
+
+ # Cyclic dependencies are created when mixing AUTOMOC/AUTOUIC with sources
+ # that have their SKIP_MOC or SKIP_UIC source file properties set to true.
+ # https://gitlab.kitware.com/cmake/cmake/-/issues/21977
+ list(APPEND unsuitable_versions "3.20.0")
+
+ # AUTOMOC can crash or hang when using a Qt that supports moc depfiles.
+ # Issues reported on Windows with Ninja and Makefiles, but it could be happening
+ # on other platforms too.
+ # https://gitlab.kitware.com/cmake/cmake/-/issues/22014
+ list(APPEND unsuitable_versions "3.20.1")
+
+ # Cyclic dependencies can happen when the AUTOMOC / AUTOUIC include directory is added as a
+ # target include directory.
+ # https://gitlab.kitware.com/cmake/cmake/-/merge_requests/6380
+ # https://gitlab.kitware.com/cmake/cmake/-/merge_requests/6359
+ # https://gitlab.kitware.com/cmake/cmake/-/issues/16776
+ list(APPEND unsuitable_versions "3.21.0")
+
+ # Changing a C++ source file can trigger rebuilds of a lot of other source files that might
+ # include AUTOGEN'ed headers or sources.
+ # https://gitlab.kitware.com/cmake/cmake/-/issues/22531
+ # Fixed in 3.21.2.
+ list(APPEND unsuitable_versions "3.21.1")
+
+ foreach(unsuitable_version ${unsuitable_versions})
+ if(CMAKE_VERSION VERSION_EQUAL unsuitable_version)
+ message(WARNING
+ "The CMake version you are using is known to cause issues when building Qt. "
+ "Please upgrade to a newer version. "
+ "CMake version used: '${unsuitable_version}'")
+ endif()
+ endforeach()
+
+ # Ninja Multi-Config was introduced in 3.17, but we recommend 3.18.
+ set(min_nmc_cmake_version "3.18.3")
+ if(CMAKE_GENERATOR STREQUAL "Ninja Multi-Config"
+ AND CMAKE_VERSION VERSION_LESS ${min_nmc_cmake_version})
+ message(WARNING
+ "You are using CMake ${CMAKE_VERSION} with the Ninja Multi-Config generator. "
+ "This combination is unsupported. "
+ "Please upgrade to at least CMake ${min_nmc_cmake_version}. ")
+ endif()
+endfunction()
+
+# Used to upgrade policies only when building Qt repositories.
+#
+# Functions don't have their own policy scope, so the policy settings modified
+# here will be those of the caller's policy scope. Note that these settings
+# will only apply to functions and macros defined after this function is called,
+# but not to any that are already defined. Ordinary CMake code not inside a
+# function or macro will be affected by these policy settings too.
+function(qt_internal_upgrade_cmake_policies)
+ qt_internal_get_computed_min_cmake_version_for_building_qt(lower_version)
+ qt_internal_get_max_new_policy_cmake_version(upper_version)
+ cmake_minimum_required(VERSION ${lower_version}...${upper_version})
+endfunction()
diff --git a/cmake/QtCompilerFlags.cmake b/cmake/QtCompilerFlags.cmake
index a376ac0097..f58f36b7a2 100644
--- a/cmake/QtCompilerFlags.cmake
+++ b/cmake/QtCompilerFlags.cmake
@@ -1,16 +1,23 @@
-# Set warnings. All compilers except MSVC support -Wall -Wextra
-# Allow opting out by setting a QT_COMPILE_WARNINGS_OFF property on targets. This would be the
-# equivalent of qmake's CONFIG += warn_off.
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+# Enable compiler warnings by default. All compilers except MSVC support -Wall -Wextra
+#
+# You can disable the warnings for specific targets (for instance containing 3rd party code)
+# by calling qt_disable_warnings(target). This will set the QT_COMPILE_OPTIONS_DISABLE_WARNINGS
+# property checked below, and is equivalent to qmake's CONFIG += warn_off.
set(_qt_compiler_warning_flags_on "")
-set(_qt_compiler_warning_flags_off "")
+set(_qt_compiler_warning_flags_off -w)
if (MSVC)
list(APPEND _qt_compiler_warning_flags_on /W3)
- list(APPEND _qt_compiler_warning_flags_off -W0)
else()
- list(APPEND _qt_compiler_warning_flags_on -Wall -Wextra)
- list(APPEND _qt_compiler_warning_flags_off -w)
+ if(CMAKE_CXX_COMPILER_ID STREQUAL "GHS") # There is no -Wextra flag for GHS compiler.
+ list(APPEND _qt_compiler_warning_flags_on -Wall)
+ else()
+ list(APPEND _qt_compiler_warning_flags_on -Wall -Wextra)
+ endif()
endif()
set(_qt_compiler_warning_flags_condition
@@ -18,8 +25,15 @@ set(_qt_compiler_warning_flags_condition
set(_qt_compiler_warning_flags_genex
"$<IF:${_qt_compiler_warning_flags_condition},${_qt_compiler_warning_flags_off},${_qt_compiler_warning_flags_on}>")
+set(_qt_compiler_warning_flags_language_condition
+ "$<COMPILE_LANGUAGE:CXX,C,OBJC,OBJCXX>")
+set(_qt_compiler_warning_flags_language_conditional_genex
+ "$<${_qt_compiler_warning_flags_language_condition}:${_qt_compiler_warning_flags_genex}>")
+
+
# Need to replace semicolons so that the list is not wrongly expanded in the add_compile_options
# call.
string(REPLACE ";" "$<SEMICOLON>"
- _qt_compiler_warning_flags_genex "${_qt_compiler_warning_flags_genex}")
-add_compile_options(${_qt_compiler_warning_flags_genex})
+ _qt_compiler_warning_flags_language_conditional_genex
+ "${_qt_compiler_warning_flags_language_conditional_genex}")
+add_compile_options(${_qt_compiler_warning_flags_language_conditional_genex})
diff --git a/cmake/QtCompilerOptimization.cmake b/cmake/QtCompilerOptimization.cmake
index fc2922089c..ac542e9451 100644
--- a/cmake/QtCompilerOptimization.cmake
+++ b/cmake/QtCompilerOptimization.cmake
@@ -1,14 +1,5 @@
-if (QCC)
- set(QT_CFLAGS_SSE2 "-msse2")
- set(QT_CFLAGS_SSE3 "-msse3")
- set(QT_CFLAGS_SSSE3 "-mssse3")
- set(QT_CFLAGS_SSE4_1 "-msse4.1")
- set(QT_CFLAGS_SSE4_2 "-msse4.2")
- set(QT_CFLAGS_AVX "-mavx")
- set(QT_CFLAGS_AVX2 "-mavx2")
- set(QT_CFLAGS_AESNI "-maes")
- set(QT_CFLAGS_SHANI "-msha")
-endif()
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
if (MSVC)
if (QT_64BIT)
@@ -25,11 +16,11 @@ if (MSVC)
set(QT_CFLAGS_AESNI "${QT_CFLAGS_SSE2}")
set(QT_CFLAGS_SHANI "${QT_CFLAGS_SSE2}")
- # FIXME to be Visual Studio version specific, like in mkspecs/common/msvc-version.conf
set(QT_CFLAGS_AVX "-arch:AVX")
set(QT_CFLAGS_AVX2 "-arch:AVX2")
set(QT_CFLAGS_F16C "-arch:AVX")
set(QT_CFLAGS_RDRND "")
+ set(QT_CFLAGS_RDSEED "")
set(QT_CFLAGS_AVX512F "-arch:AVX512")
set(QT_CFLAGS_AVX512ER "-arch:AVX512")
set(QT_CFLAGS_AVX512CD "-arch:AVX512")
@@ -39,86 +30,109 @@ if (MSVC)
set(QT_CFLAGS_AVX512VL "-arch:AVX512")
set(QT_CFLAGS_AVX512IFMA "-arch:AVX512")
set(QT_CFLAGS_AVX512VBMI "-arch:AVX512")
+ set(QT_CFLAGS_AVX512VBMI2 "-arch:AVX512")
+ set(QT_CFLAGS_VAES "")
endif()
-if(GCC OR CLANG)
- set(QT_CFLAGS_SSE2 "-msse2")
- set(QT_CFLAGS_SSE3 "-msse3")
- set(QT_CFLAGS_SSSE3 "-mssse3")
- set(QT_CFLAGS_SSE4_1 "-msse4.1")
- set(QT_CFLAGS_SSE4_2 "-msse4.2")
- set(QT_CFLAGS_F16C "-mf16c")
- set(QT_CFLAGS_RDRND "-mrdrnd")
- set(QT_CFLAGS_AVX "-mavx")
- set(QT_CFLAGS_AVX2 "-mavx2")
- set(QT_CFLAGS_ARCH_HASWELL "-march=core-avx2")
- set(QT_CFLAGS_AVX512F "-mavx512f")
- set(QT_CFLAGS_AVX512ER "-mavx512er")
- set(QT_CFLAGS_AVX512CD "-mavx512cd")
- set(QT_CFLAGS_AVX512PF "-mavx512pf")
- set(QT_CFLAGS_AVX512DQ "-mavx512dq")
- set(QT_CFLAGS_AVX512BW "-mavx512bw")
- set(QT_CFLAGS_AVX512VL "-mavx512vl")
- set(QT_CFLAGS_AVX512IFMA "-mavx512ifma")
- set(QT_CFLAGS_AVX512VBMI "-mavx512vbmi")
- set(QT_CFLAGS_AESNI "-maes")
- set(QT_CFLAGS_SHANI "-msha")
+if(GCC OR CLANG OR QCC)
+ set(__prefix)
+ if(MSVC AND CLANG)
+ set(__prefix "/clang:")
+ endif()
+ set(QT_CFLAGS_SSE2 "${__prefix}-msse2")
+ set(QT_CFLAGS_SSE3 "${__prefix}-msse3")
+ set(QT_CFLAGS_SSSE3 "${__prefix}-mssse3")
+ set(QT_CFLAGS_SSE4_1 "${__prefix}-msse4.1")
+ set(QT_CFLAGS_SSE4_2 "${__prefix}-msse4.2")
+ set(QT_CFLAGS_F16C "${__prefix}-mf16c")
+ set(QT_CFLAGS_RDRND "${__prefix}-mrdrnd")
+ set(QT_CFLAGS_RDSEED "${__prefix}-mrdseed")
+ set(QT_CFLAGS_AVX "${__prefix}-mavx")
+ set(QT_CFLAGS_AVX2 "${__prefix}-mavx2")
+ set(QT_CFLAGS_ARCH_HASWELL "${__prefix}-march=haswell")
+ set(QT_CFLAGS_AVX512F "${__prefix}-mavx512f")
+ set(QT_CFLAGS_AVX512ER "${__prefix}-mavx512er")
+ set(QT_CFLAGS_AVX512CD "${__prefix}-mavx512cd")
+ set(QT_CFLAGS_AVX512PF "${__prefix}-mavx512pf")
+ set(QT_CFLAGS_AVX512DQ "${__prefix}-mavx512dq")
+ set(QT_CFLAGS_AVX512BW "${__prefix}-mavx512bw")
+ set(QT_CFLAGS_AVX512VL "${__prefix}-mavx512vl")
+ set(QT_CFLAGS_AVX512IFMA "${__prefix}-mavx512ifma")
+ set(QT_CFLAGS_AVX512VBMI "${__prefix}-mavx512vbmi")
+ set(QT_CFLAGS_AVX512VBMI2 "${__prefix}-mavx512vbmi2")
+ set(QT_CFLAGS_AESNI "${__prefix}-maes")
+ set(QT_CFLAGS_SHANI "${__prefix}-msha")
+ set(QT_CFLAGS_VAES "${__prefix}-mvaes")
if(NOT UIKIT AND NOT QT_64BIT)
- set(QT_CFLAGS_NEON "-mfpu=neon")
+ set(QT_CFLAGS_NEON "${__prefix}-mfpu=neon")
+ endif()
+ set(QT_CFLAGS_MIPS_DSP "${__prefix}-mdsp")
+ set(QT_CFLAGS_MIPS_DSPR2 "${__prefix}-mdspr2")
+ unset(__prefix)
+endif()
+
+# Fall through is important, so that more specific flags that might be missing are set by the
+# previous base cases.
+# This mirrors qmake's mkspecs QMAKE_CFLAGS_OPTIMIZE assignments (mostly).
+#
+# TODO: Missing mkspecs flags we don't handle below: win32-clang-g++, win32-clang-msvc, rtems-base
+#
+# gcc and clang base
+if(GCC OR CLANG)
+ set(QT_CFLAGS_OPTIMIZE "-O2")
+ set(QT_CFLAGS_OPTIMIZE_FULL "-O3")
+ set(QT_CFLAGS_OPTIMIZE_DEBUG "-Og")
+ set(QT_CFLAGS_OPTIMIZE_SIZE "-Os")
+
+ if(CLANG)
+ set(QT_CFLAGS_OPTIMIZE_SIZE "-Oz")
endif()
- set(QT_CFLAGS_MIPS_DSP "-mdsp")
- set(QT_CFLAGS_MIPS_DSPR2 "-mdspr2")
endif()
-if (winrt) # FIXME: Correct variable
- set(QT_CFLAGS_SSE2 "-arch:SSE2")
- set(QT_CFLAGS_SSE3 "-arch:SSE2")
- set(QT_CFLAGS_SSSE3 "-arch:SSE2")
- set(QT_CFLAGS_SSE4_1 "-arch:SSE2")
- set(QT_CFLAGS_SSE4_2 "-arch:SSE2")
- set(QT_CFLAGS_AVX "-arch:AVX")
- set(QT_CFLAGS_AVX2 "-arch:AVX")
- set(QT_CFLAGS_AESNI "-arch:SSE2")
- set(QT_CFLAGS_SHANI "-arch:SSE2")
+# Flags that CMake might set, aka flags the compiler would see as valid values.
+if(GCC OR CLANG OR QCC)
+ set(QT_CFLAGS_OPTIMIZE_VALID_VALUES "-O0" "-O1" "-O2" "-O3" "-Os" "-Oz")
+endif()
+
+
+# Windows MSVC
+if(MSVC)
+ set(QT_CFLAGS_OPTIMIZE "-O2")
+ if(NOT CLANG)
+ # -Ob3 was introduced in Visual Studio 2019 version 16.0
+ # However clang-cl can't recognize it.
+ string(APPEND QT_CFLAGS_OPTIMIZE " -Ob3 ")
+ endif()
+ set(QT_CFLAGS_OPTIMIZE_DEBUG "-Od")
+ set(QT_CFLAGS_OPTIMIZE_SIZE "-O1")
+ set(QT_CFLAGS_OPTIMIZE_VALID_VALUES "/O2" "/O1" "/Od" "/Ob0" "/Ob1" "/Ob2" "/Ob3" "/O0" "-O0")
+
+ if(CLANG)
+ set(QT_CFLAGS_OPTIMIZE_FULL "/clang:-O3")
+ set(QT_CFLAGS_OPTIMIZE_SIZE "/clang:-Oz")
+ endif()
endif()
-if (ICC)
- if (MSVC)
- set(QT_CFLAGS_SSE2 "-QxSSE2")
- set(QT_CFLAGS_SSE3 "-QxSSE3")
- set(QT_CFLAGS_SSSE3 "-QxSSSE3")
- set(QT_CFLAGS_SSE4_1 "-QxSSE4.1")
- set(QT_CFLAGS_SSE4_2 "-QxSSE4.2")
- set(QT_CFLAGS_AVX "-QxAVX")
- set(QT_CFLAGS_AVX2 "-QxCORE-AVX2")
- set(QT_CFLAGS_AVX512F "-QxCOMMON-AVX512")
- set(QT_CFLAGS_AVX512CD "-QxCOMMON-AVX512")
- set(QT_CFLAGS_AVX512ER "-QxMIC-AVX512")
- set(QT_CFLAGS_AVX512PF "-QxMIC-AVX512")
- set(QT_CFLAGS_AVX512DQ "-QxCORE-AVX512")
- set(QT_CFLAGS_AVX512BW "-QxCORE-AVX512")
- set(QT_CFLAGS_AVX512VL "-QxCORE-AVX512")
- set(QT_CFLAGS_F16C "${QT_CFLAGS_AVX2}")
- set(QT_CFLAGS_AESNI "-QxSSE2")
- set(QT_CFLAGS_SHANI "-QxSSE4.2")
+# Android Clang
+if(CLANG AND ANDROID)
+ if(QT_FEATURE_ltcg)
+ # When using LTCG, the linker cannot cope with -Oz. See QTBUG-89472 for details.
+ set(QT_CFLAGS_OPTIMIZE "-O2")
+ set(QT_CFLAGS_OPTIMIZE_FULL "-O3")
else()
- set(QT_CFLAGS_SSE2 "-msse2")
- set(QT_CFLAGS_SSE3 "-msse3")
- set(QT_CFLAGS_SSSE3 "-mssse3")
- set(QT_CFLAGS_SSE4_1 "-msse4.1")
- set(QT_CFLAGS_SSE4_2 "-msse4.2")
- set(QT_CFLAGS_AVX "-march=core-avx")
- set(QT_CFLAGS_AVX2 "-march=core-avx2")
- set(QT_CFLAGS_AVX512F "-march=broadwell -xCOMMON-AVX512")
- set(QT_CFLAGS_AVX512CD "-march=broadwell -xCOMMON-AVX512")
- set(QT_CFLAGS_AVX512ER "-march=knl")
- set(QT_CFLAGS_AVX512PF "-march=knl")
- set(QT_CFLAGS_AVX512DQ "-march=skylake-avx512")
- set(QT_CFLAGS_AVX512BW "-march=skylake-avx512")
- set(QT_CFLAGS_AVX512VL "-march=skylake-avx512")
- set(QT_CFLAGS_AESNI "-maes")
- set(QT_CFLAGS_F16C "${QT_CFLAGS_AVX2}")
- set(QT_CFLAGS_RDRND "-mrdrnd")
- set(QT_CFLAGS_SHANI "-msha")
+ set(QT_CFLAGS_OPTIMIZE "-Oz")
+ set(QT_CFLAGS_OPTIMIZE_FULL "-Oz")
endif()
endif()
+
+# qcc
+if (QCC)
+ set(QT_CFLAGS_OPTIMIZE "-O2")
+ set(QT_CFLAGS_OPTIMIZE_FULL "-O3")
+endif()
+
+# Emscripten Clang
+if(WASM)
+ set(QT_CFLAGS_OPTIMIZE_DEBUG "-O2 -g") # -Og is not supported
+ set(QT_CFLAGS_SSE2 "-O2 -msimd128 -msse -msse2")
+endif()
diff --git a/cmake/QtConfig.cmake.in b/cmake/QtConfig.cmake.in
index 6a80b71de3..b5a21e391d 100644
--- a/cmake/QtConfig.cmake.in
+++ b/cmake/QtConfig.cmake.in
@@ -1,19 +1,16 @@
+# Copyright (C) 2024 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
@PACKAGE_INIT@
-if (CMAKE_CROSSCOMPILING AND CMAKE_SYSROOT)
- # When cross compiling with CMake any calls to pkg_check_modules() will
- # search into the host system instead of the target sysroot.
- # The current work around is based on the discussion found at
- # https://gitlab.kitware.com/cmake/cmake/-/merge_requests/4478
- set(ENV{PKG_CONFIG_DIR} "")
- set(ENV{PKG_CONFIG_LIBDIR} "${CMAKE_SYSROOT}/usr/lib/${CMAKE_LIBRARY_ARCHITECTURE}/pkgconfig")
- set(ENV{PKG_CONFIG_SYSROOT_DIR} ${CMAKE_SYSROOT})
-endif()
+cmake_minimum_required(VERSION @min_new_policy_version@...@max_new_policy_version@)
-# Slightly amended version of ./src/corelib/Qt6Config.cmake.in
-if (CMAKE_VERSION VERSION_LESS 3.1.0)
- message(FATAL_ERROR "Qt requires at least CMake version 3.1.0")
-endif()
+include("${CMAKE_CURRENT_LIST_DIR}/@INSTALL_CMAKE_NAMESPACE@ConfigExtras.cmake")
+include("${CMAKE_CURRENT_LIST_DIR}/QtPublicCMakeVersionHelpers.cmake")
+include("${CMAKE_CURRENT_LIST_DIR}/QtPublicCMakeHelpers.cmake")
+include("${CMAKE_CURRENT_LIST_DIR}/QtInstallPaths.cmake")
+
+__qt_internal_require_suitable_cmake_version_for_using_qt()
get_filename_component(_qt_cmake_dir "${CMAKE_CURRENT_LIST_DIR}/.." ABSOLUTE)
set(_qt_@PROJECT_VERSION_MAJOR@_config_cmake_dir "${CMAKE_CURRENT_LIST_DIR}")
@@ -21,7 +18,11 @@ set(_qt_@PROJECT_VERSION_MAJOR@_config_cmake_dir "${CMAKE_CURRENT_LIST_DIR}")
if (NOT QT_NO_CREATE_TARGETS)
include("${CMAKE_CURRENT_LIST_DIR}/@INSTALL_CMAKE_NAMESPACE@Targets.cmake")
if(NOT QT_NO_CREATE_VERSIONLESS_TARGETS)
- include("${CMAKE_CURRENT_LIST_DIR}/@INSTALL_CMAKE_NAMESPACE@VersionlessTargets.cmake")
+ if(CMAKE_VERSION VERSION_LESS 3.18 OR QT_USE_OLD_VERSION_LESS_TARGETS)
+ include("${CMAKE_CURRENT_LIST_DIR}/@INSTALL_CMAKE_NAMESPACE@VersionlessTargets.cmake")
+ else()
+ include("${CMAKE_CURRENT_LIST_DIR}/@INSTALL_CMAKE_NAMESPACE@VersionlessAliasTargets.cmake")
+ endif()
endif()
else()
# For examples using `find_package(...)` inside their CMakeLists.txt files:
@@ -32,43 +33,192 @@ else()
QT_VERSION_PATCH @PROJECT_VERSION_PATCH@)
endif()
-# if (NOT @INSTALL_CMAKE_NAMESPACE@_FIND_COMPONENTS)
-# set(@INSTALL_CMAKE_NAMESPACE@_NOT_FOUND_MESSAGE "The Qt package requires at least one component")
-# set(@INSTALL_CMAKE_NAMESPACE@_FOUND False)
-# return()
-# endif()
-
get_filename_component(_qt_import_prefix "${CMAKE_CURRENT_LIST_FILE}" PATH)
get_filename_component(_qt_import_prefix "${_qt_import_prefix}" REALPATH)
list(APPEND CMAKE_MODULE_PATH "${_qt_import_prefix}")
list(APPEND CMAKE_MODULE_PATH "${_qt_import_prefix}/3rdparty/extra-cmake-modules/find-modules")
list(APPEND CMAKE_MODULE_PATH "${_qt_import_prefix}/3rdparty/kwin")
-if(APPLE AND (NOT CMAKE_SYSTEM_NAME OR CMAKE_SYSTEM_NAME STREQUAL "Darwin"))
- # Add module directory to pick up custom Info.plist template for macOS
- list(APPEND CMAKE_MODULE_PATH "${_qt_import_prefix}/macos")
+if(APPLE)
+ if(NOT CMAKE_SYSTEM_NAME OR CMAKE_SYSTEM_NAME STREQUAL "Darwin")
+ set(__qt_internal_cmake_apple_support_files_path "${_qt_import_prefix}/macos")
+ elseif(CMAKE_SYSTEM_NAME STREQUAL "iOS")
+ set(__qt_internal_cmake_apple_support_files_path "${_qt_import_prefix}/ios")
+ elseif(CMAKE_SYSTEM_NAME STREQUAL "visionOS")
+ set(__qt_internal_cmake_apple_support_files_path "${_qt_import_prefix}/visionos")
+ endif()
+endif()
+
+# Public helpers available to all Qt packages.
+set(__qt_public_files_to_include
+ @QT_PUBLIC_FILES_TO_INCLUDE@
+)
+foreach(__qt_public_file_to_include IN LISTS __qt_public_files_to_include)
+ include("${__qt_public_file_to_include}")
+endforeach()
+
+if(NOT DEFINED QT_CMAKE_EXPORT_NAMESPACE)
+ set(QT_CMAKE_EXPORT_NAMESPACE @QT_CMAKE_EXPORT_NAMESPACE@)
+endif()
+
+set(QT_ADDITIONAL_PACKAGES_PREFIX_PATH "" CACHE STRING
+ "Additional directories where find(Qt6 ...) components are searched")
+set(QT_ADDITIONAL_HOST_PACKAGES_PREFIX_PATH "" CACHE STRING
+ "Additional directories where find(Qt6 ...) host Qt components are searched")
+
+__qt_internal_collect_additional_prefix_paths(_qt_additional_packages_prefix_paths
+ QT_ADDITIONAL_PACKAGES_PREFIX_PATH)
+__qt_internal_collect_additional_prefix_paths(_qt_additional_host_packages_prefix_paths
+ QT_ADDITIONAL_HOST_PACKAGES_PREFIX_PATH)
+
+__qt_internal_prefix_paths_to_roots(_qt_additional_host_packages_root_paths
+ "${_qt_additional_host_packages_prefix_paths}")
+
+__qt_internal_collect_additional_module_paths()
+
+# Propagate sanitizer flags to both internal Qt builds and user projects.
+# Allow opt-out in case if downstream projects handle it in a different way.
+set(QT_CONFIGURED_SANITIZER_OPTIONS "@ECM_ENABLE_SANITIZERS@")
+
+if(QT_CONFIGURED_SANITIZER_OPTIONS
+ AND NOT __qt_sanitizer_options_set
+ AND NOT QT_NO_ADD_SANITIZER_OPTIONS)
+ set(ECM_ENABLE_SANITIZERS "${QT_CONFIGURED_SANITIZER_OPTIONS}")
+ include(
+ "${CMAKE_CURRENT_LIST_DIR}/3rdparty/extra-cmake-modules/modules/ECMEnableSanitizers.cmake")
+endif()
+# Mark that the current directory scope has its sanitizer flags set.
+set(__qt_sanitizer_options_set TRUE)
+
+# Find required dependencies, if any.
+include(CMakeFindDependencyMacro)
+if(EXISTS "${CMAKE_CURRENT_LIST_DIR}/@INSTALL_CMAKE_NAMESPACE@Dependencies.cmake")
+ include("${CMAKE_CURRENT_LIST_DIR}/@INSTALL_CMAKE_NAMESPACE@Dependencies.cmake")
+
+ _qt_internal_suggest_dependency_debugging(@INSTALL_CMAKE_NAMESPACE@
+ __qt_@INSTALL_CMAKE_NAMESPACE@_pkg ${CMAKE_FIND_PACKAGE_NAME}_NOT_FOUND_MESSAGE)
+
+ if(NOT @INSTALL_CMAKE_NAMESPACE@_FOUND)
+ # Clear the components, no need to look for them if dependencies were not found, otherwise
+ # you get a wall of recursive error messages.
+ set(@INSTALL_CMAKE_NAMESPACE@_FIND_COMPONENTS "")
+ endif()
+endif()
+
+set(_@INSTALL_CMAKE_NAMESPACE@_FIND_PARTS_QUIET)
+if(@INSTALL_CMAKE_NAMESPACE@_FIND_QUIETLY)
+ set(_@INSTALL_CMAKE_NAMESPACE@_FIND_PARTS_QUIET QUIET)
+endif()
+
+set(__qt_use_no_default_path_for_qt_packages "NO_DEFAULT_PATH")
+if(QT_DISABLE_NO_DEFAULT_PATH_IN_QT_PACKAGES)
+ set(__qt_use_no_default_path_for_qt_packages "")
endif()
foreach(module ${@INSTALL_CMAKE_NAMESPACE@_FIND_COMPONENTS})
- find_package(@INSTALL_CMAKE_NAMESPACE@${module}
- ${_@INSTALL_CMAKE_NAMESPACE@_FIND_PARTS_QUIET}
- ${_@INSTALL_CMAKE_NAMESPACE@_FIND_PARTS_REQUIRED}
- PATHS ${_qt_cmake_dir} ${QT_EXAMPLES_CMAKE_PREFIX_PATH} NO_DEFAULT_PATH
- )
+ if(NOT "${QT_HOST_PATH}" STREQUAL ""
+ AND "${module}" MATCHES "Tools$"
+ AND NOT "${module}" MATCHES "UiTools$"
+ AND NOT "${module}" MATCHES "ShaderTools$"
+ AND NOT "${module}" MATCHES "^Tools$"
+ AND NOT QT_NO_FIND_HOST_TOOLS_PATH_MANIPULATION)
+ # Make sure that a Qt*Tools package is also looked up in QT_HOST_PATH.
+ # But don't match QtShaderTools and QtTools which are cross-compiled target package names.
+ # Allow opt out just in case.
+ get_filename_component(__qt_find_package_host_qt_path
+ "${Qt@PROJECT_VERSION_MAJOR@HostInfo_DIR}/.." ABSOLUTE)
+ set(__qt_backup_cmake_prefix_path "${CMAKE_PREFIX_PATH}")
+ set(__qt_backup_cmake_find_root_path "${CMAKE_FIND_ROOT_PATH}")
+ list(PREPEND CMAKE_PREFIX_PATH "${__qt_find_package_host_qt_path}"
+ ${_qt_additional_host_packages_prefix_paths})
+ list(PREPEND CMAKE_FIND_ROOT_PATH "${QT_HOST_PATH}"
+ ${_qt_additional_host_packages_root_paths})
+ endif()
+
+ _qt_internal_save_find_package_context_for_debugging(@INSTALL_CMAKE_NAMESPACE@${module})
+
+ if(NOT @INSTALL_CMAKE_NAMESPACE@${module}_FOUND)
+ find_package(@INSTALL_CMAKE_NAMESPACE@${module}
+ ${@INSTALL_CMAKE_NAMESPACE@_FIND_VERSION}
+ ${_@INSTALL_CMAKE_NAMESPACE@_FIND_PARTS_QUIET}
+ PATHS
+ ${QT_BUILD_CMAKE_PREFIX_PATH}
+ ${_qt_cmake_dir}
+ ${_qt_additional_packages_prefix_paths}
+ ${__qt_find_package_host_qt_path}
+ ${_qt_additional_host_packages_prefix_paths}
+ ${__qt_use_no_default_path_for_qt_packages}
+ )
+ endif()
+
+ if(NOT "${__qt_find_package_host_qt_path}" STREQUAL "")
+ set(CMAKE_PREFIX_PATH "${__qt_backup_cmake_prefix_path}")
+ set(CMAKE_FIND_ROOT_PATH "${__qt_backup_cmake_find_root_path}")
+ unset(__qt_backup_cmake_prefix_path)
+ unset(__qt_backup_cmake_find_root_path)
+ unset(__qt_find_package_host_qt_path)
+ endif()
+
if (NOT @INSTALL_CMAKE_NAMESPACE@${module}_FOUND)
- string(CONFIGURE ${_qt5_module_location_template} _expected_module_location @ONLY)
+ set(_qt_expected_component_config_path
+ "${_qt_cmake_dir}/@INSTALL_CMAKE_NAMESPACE@${module}/@INSTALL_CMAKE_NAMESPACE@${module}Config.cmake")
+ get_filename_component(
+ _qt_expected_component_dir_path "${_qt_expected_component_config_path}" DIRECTORY)
+
+ set(_qt_component_not_found_msg
+ "\nExpected Config file at \"${_qt_expected_component_config_path}\"")
+
+ if(EXISTS "${_qt_expected_component_config_path}")
+ string(APPEND _qt_component_not_found_msg " exists \n")
+ else()
+ string(APPEND _qt_component_not_found_msg " does NOT exist\n")
+ endif()
+
+ set(_qt_candidate_component_dir_path "${@INSTALL_CMAKE_NAMESPACE@${module}_DIR}")
- if (@INSTALL_CMAKE_NAMESPACE@_FIND_REQUIRED_${module})
- set(_Qt_NOTFOUND_MESSAGE "${_Qt_NOTFOUND_MESSAGE}Failed to find Qt component \"${module}\" config file at \"${_expected_module_location}\"\n")
+ if(_qt_candidate_component_dir_path AND
+ NOT _qt_expected_component_dir_path STREQUAL _qt_candidate_component_dir_path)
+ string(APPEND _qt_component_not_found_msg
+ "\n@INSTALL_CMAKE_NAMESPACE@${module}_DIR was computed by CMake or specified on the "
+ "command line by the user: \"${_qt_candidate_component_dir_path}\" "
+ "\nThe expected and computed paths are different, which might be the reason for "
+ "the package not to be found.")
+ endif()
+
+ if(@INSTALL_CMAKE_NAMESPACE@_FIND_REQUIRED_${module})
+ set(@INSTALL_CMAKE_NAMESPACE@_FOUND False)
+ set(_Qt_NOTFOUND_MESSAGE
+ "${_Qt_NOTFOUND_MESSAGE}Failed to find required Qt component \"${module}\". ${_qt_component_not_found_msg}")
+ set(_qt_full_component_name "@INSTALL_CMAKE_NAMESPACE@${module}")
+ _qt_internal_suggest_dependency_debugging(${_qt_full_component_name}
+ _qt_full_component_name _Qt_NOTFOUND_MESSAGE)
+ unset(_qt_full_component_name)
+ break()
elseif(NOT @INSTALL_CMAKE_NAMESPACE@_FIND_QUIETLY)
- message(WARNING "Failed to find Qt component \"${module}\" config file at \"${_expected_module_location}\"")
+ message(WARNING
+ "Failed to find optional Qt component \"${module}\". ${_qt_component_not_found_msg}")
endif()
- unset(_expected_module_location)
+ unset(_qt_expected_component_config_path)
+ unset(_qt_expected_component_dir_path)
+ unset(_qt_candidate_component_dir_path)
+ unset(_qt_component_not_found_msg)
endif()
endforeach()
-if (_Qt_NOTFOUND_MESSAGE)
+if(@INSTALL_CMAKE_NAMESPACE@_FIND_COMPONENTS AND _Qt_NOTFOUND_MESSAGE)
set(@INSTALL_CMAKE_NAMESPACE@_NOT_FOUND_MESSAGE "${_Qt_NOTFOUND_MESSAGE}")
- set(@INSTALL_CMAKE_NAMESPACE@_FOUND False)
+ unset(_Qt_NOTFOUND_MESSAGE)
+endif()
+
+if(@INSTALL_CMAKE_NAMESPACE@_FOUND
+ AND COMMAND _qt_internal_override_example_install_dir_to_dot
+ AND NOT _qt_internal_example_dir_set_to_dot)
+ _qt_internal_override_example_install_dir_to_dot()
+endif()
+
+__qt_internal_defer_promote_targets_in_dir_scope_to_global()
+if(CMAKE_VERSION VERSION_LESS 3.21)
+ __qt_internal_check_link_order_matters()
+ __qt_internal_check_cmp0099_available()
endif()
diff --git a/cmake/QtConfigDependencies.cmake.in b/cmake/QtConfigDependencies.cmake.in
new file mode 100644
index 0000000000..9824f8525c
--- /dev/null
+++ b/cmake/QtConfigDependencies.cmake.in
@@ -0,0 +1,27 @@
+# Copyright (C) 2024 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+set(@INSTALL_CMAKE_NAMESPACE@_FOUND FALSE)
+
+set(__qt_platform_requires_host_info_package "@platform_requires_host_info_package@")
+set(__qt_platform_initial_qt_host_path "@qt_host_path_absolute@")
+set(__qt_platform_initial_qt_host_path_cmake_dir "@qt_host_path_cmake_dir_absolute@")
+
+_qt_internal_setup_qt_host_path(
+ "${__qt_platform_requires_host_info_package}"
+ "${__qt_platform_initial_qt_host_path}"
+ "${__qt_platform_initial_qt_host_path_cmake_dir}")
+_qt_internal_find_host_info_package(${__qt_platform_requires_host_info_package})
+
+# note: _third_party_deps example: "ICU\\;FALSE\\;1.0\\;i18n uc data;ZLIB\\;FALSE\\;\\;"
+set(__qt_third_party_deps "@third_party_deps@")
+
+@third_party_extra@
+
+# Don't propagate REQUIRED so we don't immediately FATAL_ERROR, rather let the find_dependency calls
+# set _NOT_FOUND_MESSAGE which will be displayed by the includer of the Dependencies file.
+set(${CMAKE_FIND_PACKAGE_NAME}_FIND_REQUIRED FALSE)
+
+_qt_internal_find_third_party_dependencies(@INSTALL_CMAKE_NAMESPACE@ __qt_third_party_deps)
+
+set(@INSTALL_CMAKE_NAMESPACE@_FOUND TRUE)
diff --git a/cmake/QtConfigExtras.cmake.in b/cmake/QtConfigExtras.cmake.in
new file mode 100644
index 0000000000..06acd33c82
--- /dev/null
+++ b/cmake/QtConfigExtras.cmake.in
@@ -0,0 +1,7 @@
+# Copyright (C) 2024 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+set(QT_SUPPORTED_MIN_CMAKE_VERSION_FOR_USING_QT "@supported_min_version_for_using_qt@")
+set(QT_COMPUTED_MIN_CMAKE_VERSION_FOR_USING_QT "@computed_min_version_for_using_qt@")
+
+@QT_CONFIG_EXTRAS_CODE@
diff --git a/cmake/QtConfigureTimeExecutableCMakeLists.txt.in b/cmake/QtConfigureTimeExecutableCMakeLists.txt.in
new file mode 100644
index 0000000000..17acb37f0e
--- /dev/null
+++ b/cmake/QtConfigureTimeExecutableCMakeLists.txt.in
@@ -0,0 +1,26 @@
+# Copyright (C) 2024 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+cmake_minimum_required(VERSION 3.16)
+
+project(@configure_time_target@ LANGUAGES CXX)
+
+set(packages "@packages@")
+set(defines @defines@)
+set(compile_options @compile_options@)
+set(link_options @link_options@)
+set(output_directory @output_directory@)
+
+foreach(package IN LISTS packages)
+ find_package(${package} REQUIRED)
+endforeach()
+
+add_executable(@configure_time_target@ @win32@ @macosx_bundle@ @sources@)
+set_target_properties(@configure_time_target@ PROPERTIES
+ INCLUDE_DIRECTORIES "@include_directories@"
+ RUNTIME_OUTPUT_DIRECTORY "${output_directory}"
+)
+
+target_compile_options(@configure_time_target@ PRIVATE ${compile_options})
+target_compile_definitions(@configure_time_target@ PRIVATE ${defines})
+target_link_options(@configure_time_target@ PRIVATE ${link_options})
diff --git a/cmake/QtCopyFileIfDifferent.cmake b/cmake/QtCopyFileIfDifferent.cmake
new file mode 100644
index 0000000000..a27221ece8
--- /dev/null
+++ b/cmake/QtCopyFileIfDifferent.cmake
@@ -0,0 +1,18 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+# copy_if_different works incorrect in Windows if file size if bigger than 2GB.
+# See https://gitlab.kitware.com/cmake/cmake/-/issues/23052 and QTBUG-99491 for details.
+
+cmake_minimum_required(VERSION 3.16)
+
+set(copy_strategy "copy_if_different")
+if(CMAKE_HOST_WIN32)
+ file(SIZE "${SRC_FILE_PATH}" size)
+ # If file size is bigger than 2GB copy it unconditionally
+ if(size GREATER_EQUAL 2147483648)
+ set(copy_strategy "copy")
+ endif()
+endif()
+
+execute_process(COMMAND ${CMAKE_COMMAND} -E ${copy_strategy} "${SRC_FILE_PATH}" "${DST_FILE_PATH}")
diff --git a/cmake/QtDbusHelpers.cmake b/cmake/QtDbusHelpers.cmake
new file mode 100644
index 0000000000..26e98eff27
--- /dev/null
+++ b/cmake/QtDbusHelpers.cmake
@@ -0,0 +1,70 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+# helper to set up a qdbusxml2cpp rule
+function(qt_create_qdbusxml2cpp_command target infile)
+ cmake_parse_arguments(PARSE_ARGV 2 arg
+ "ADAPTOR;INTERFACE"
+ "BASENAME"
+ "FLAGS")
+ _qt_internal_validate_all_args_are_parsed(arg)
+
+ if((arg_ADAPTOR AND arg_INTERFACE) OR (NOT arg_ADAPTOR AND NOT arg_INTERFACE))
+ message(FATAL_ERROR "qt_create_dbusxml2cpp_command needs either ADAPTOR or INTERFACE.")
+ endif()
+
+ set(option "-a")
+ set(type "adaptor")
+ if (arg_INTERFACE)
+ set(option "-p")
+ set(type "interface")
+ endif()
+
+ if ("${arg_BASENAME}" STREQUAL "")
+ get_filename_component(file_dir "${infile}" DIRECTORY)
+ get_filename_component(file_name "${infile}" NAME_WLE)
+ get_filename_component(file_ext "${infile}" LAST_EXT)
+
+ if("${file_ext}" STREQUAL ".xml")
+ else()
+ message(FATAL_ERROR "DBUS ${type} input file is not xml.")
+ endif()
+
+ # use last part of io.qt.something.xml!
+ get_filename_component(file_ext "${file_name}" LAST_EXT)
+ if("x${file_ext}" STREQUAL "x")
+ else()
+ string(SUBSTRING "${file_ext}" 1 -1 file_name) # cut of leading '.'
+ endif()
+
+ string(TOLOWER "${file_name}" file_name)
+ set(file_name "${file_name}_${type}")
+ else()
+ set(file_name ${arg_BASENAME})
+ endif()
+
+ # Use absolute file path for the source file and set the current working directory to the
+ # current binary directory, because setting an absolute path for the header:source combo option
+ # does not work. Splitting on ":" breaks inside the dbus tool when running on Windows
+ # due to ":" being contained in the drive path (e.g C:\foo.h:C:\foo.cpp).
+ get_filename_component(absolute_in_file_path "${infile}" ABSOLUTE)
+
+ set(header_file "${file_name}.h")
+ set(source_file "${file_name}.cpp")
+
+ set(header_file_full "${CMAKE_CURRENT_BINARY_DIR}/${file_name}.h")
+ set(source_file_full "${CMAKE_CURRENT_BINARY_DIR}/${file_name}.cpp")
+
+ add_custom_command(OUTPUT "${header_file_full}" "${source_file_full}"
+ COMMAND ${QT_CMAKE_EXPORT_NAMESPACE}::qdbusxml2cpp ${arg_FLAGS} "${option}"
+ "${header_file}:${source_file}" "${absolute_in_file_path}"
+ DEPENDS "${absolute_in_file_path}" ${QT_CMAKE_EXPORT_NAMESPACE}::qdbusxml2cpp
+ WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}"
+ COMMAND_EXPAND_LISTS
+ VERBATIM)
+
+ target_sources("${target}" PRIVATE
+ "${header_file_full}"
+ "${source_file_full}"
+ )
+endfunction()
diff --git a/cmake/QtDeferredDependenciesHelpers.cmake b/cmake/QtDeferredDependenciesHelpers.cmake
new file mode 100644
index 0000000000..b233865727
--- /dev/null
+++ b/cmake/QtDeferredDependenciesHelpers.cmake
@@ -0,0 +1,31 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+# Defers the connection 'dependent' -> 'dependency'
+#
+# The actual connection can be made by calling qt_internal_add_deferred_dependencies.
+#
+function(qt_internal_defer_dependency dependent dependency)
+ set_property(GLOBAL APPEND PROPERTY QT_DEFERRED_DEPENDENCIES ${doc_target} ${tool_target})
+endfunction()
+
+# Adds dependencies between targets that have been deferred by calling qt_internal_defer_dependency.
+#
+# This function checks whether the connection can be made (the dependency target exists).
+# If the connection cannot be made, the deferred connection is left in the global property.
+# Potentially, some later call to qt_internal_add_deferred_dependencies will add it.
+#
+function(qt_internal_add_deferred_dependencies)
+ unset(unknown_deps)
+ get_property(deferred_deps GLOBAL PROPERTY QT_DEFERRED_DEPENDENCIES)
+ while(deferred_deps)
+ list(POP_FRONT deferred_deps dependent)
+ list(POP_FRONT deferred_deps dependency)
+ if (TARGET ${dependency})
+ add_dependencies(${dependent} ${dependency})
+ else()
+ list(APPEND unknown_deps ${dependent} ${dependency})
+ endif()
+ endwhile()
+ set_property(GLOBAL PROPERTY QT_DEFERRED_DEPENDENCIES ${unknown_deps})
+endfunction()
diff --git a/cmake/QtDocsHelpers.cmake b/cmake/QtDocsHelpers.cmake
new file mode 100644
index 0000000000..8b631e88ca
--- /dev/null
+++ b/cmake/QtDocsHelpers.cmake
@@ -0,0 +1,282 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+# This function adds a dependency between a doc-generating target like 'generate_docs_Gui'
+# and the necessary tool target like 'qdoc'.
+#
+# If the target is not yet existing, save the dependency connection in a global property.
+# The dependency is then added near the end of the top-level build after all subdirectories have
+# been handled.
+function(qt_internal_add_doc_tool_dependency doc_target tool_name)
+ qt_get_tool_target_name(tool_target ${tool_name})
+ if(TARGET ${tool_target})
+ add_dependencies(${doc_target} ${tool_target})
+ else()
+ qt_internal_defer_dependency(${doc_target} ${tool_target})
+ endif()
+endfunction()
+
+function(qt_internal_add_docs)
+ if(${ARGC} EQUAL 1)
+ # Function called from old generated CMakeLists.txt that was missing the target parameter
+ return()
+ endif()
+ set(error_msg "qt_add_docs called with wrong number of arguments. ")
+ list(APPEND error_msg
+ "Should be qt_add_docs\(target_name qdocconf "
+ "\[INDEX_DIRECTORIES EXTRA_INDEX_DIRS_LIST_TO_ENABLE_QDOC_RESOLVE_LINKS\]\)")
+ if(NOT ${ARGC} GREATER_EQUAL 2)
+ message(FATAL_ERROR ${error_msg})
+ return()
+ endif()
+
+ set(target ${ARGV0})
+ set(doc_project ${ARGV1})
+ set(qdoc_extra_args "")
+ # Check if there are more than 2 arguments and pass them
+ # as extra --indexdir arguments to qdoc in prepare and
+ # generate phases.
+ if (${ARGC} GREATER 2)
+ # The INDEX_DIRECTORIES key should enable passing a list of index
+ # directories as extra command-line arguments to qdoc.
+ set(qdocExtraArgs INDEX_DIRECTORIES)
+ cmake_parse_arguments(PARSE_ARGV 2 arg "" "" "${qdocExtraArgs}")
+ if(arg_UNPARSED_ARGUMENTS)
+ message(FATAL_ERROR ${error_msg})
+ return()
+ endif()
+ if(arg_INDEX_DIRECTORIES)
+ foreach(index_directory ${arg_INDEX_DIRECTORIES})
+ list(APPEND qdoc_extra_args "--indexdir" ${index_directory})
+ endforeach()
+ endif()
+ endif()
+
+
+ # If a target is not built (which can happen for tools when crosscompiling), we shouldn't try
+ # to generate docs.
+ if(NOT TARGET "${target}")
+ return()
+ endif()
+
+ set(tool_dependencies_enabled TRUE)
+ if(NOT "${QT_HOST_PATH}" STREQUAL "")
+ set(tool_dependencies_enabled FALSE)
+ set(doc_tools_bin "${QT_HOST_PATH}/${QT${PROJECT_VERSION_MAJOR}_HOST_INFO_BINDIR}")
+ set(doc_tools_libexec "${QT_HOST_PATH}/${QT${PROJECT_VERSION_MAJOR}_HOST_INFO_LIBEXECDIR}")
+ elseif(QT_SUPERBUILD)
+ set(doc_tools_bin "${QtBase_BINARY_DIR}/${INSTALL_BINDIR}")
+ set(doc_tools_libexec "${QtBase_BINARY_DIR}/${INSTALL_LIBEXECDIR}")
+ else()
+ set(doc_tools_bin "${QT_BUILD_INTERNALS_RELOCATABLE_INSTALL_PREFIX}/${INSTALL_BINDIR}")
+ set(doc_tools_libexec "${QT_BUILD_INTERNALS_RELOCATABLE_INSTALL_PREFIX}/${INSTALL_LIBEXECDIR}")
+ endif()
+
+ set(qdoc_bin "${doc_tools_bin}/qdoc${CMAKE_EXECUTABLE_SUFFIX}")
+ set(qtattributionsscanner_bin "${doc_tools_libexec}/qtattributionsscanner${CMAKE_EXECUTABLE_SUFFIX}")
+ set(qhelpgenerator_bin "${doc_tools_libexec}/qhelpgenerator${CMAKE_EXECUTABLE_SUFFIX}")
+
+ get_target_property(target_type ${target} TYPE)
+ if (NOT target_type STREQUAL "INTERFACE_LIBRARY")
+ get_target_property(target_bin_dir ${target} BINARY_DIR)
+ get_target_property(target_source_dir ${target} SOURCE_DIR)
+ else()
+ set(target_bin_dir ${CMAKE_CURRENT_BINARY_DIR})
+ set(target_source_dir ${CMAKE_CURRENT_SOURCE_DIR})
+ endif()
+ set(doc_output_dir "${target_bin_dir}/.doc")
+
+ # Generate include dir list
+ set(target_include_dirs_file "${doc_output_dir}/$<CONFIG>/includes.txt")
+
+
+ set(prop_prefix "")
+ if(target_type STREQUAL "INTERFACE_LIBRARY")
+ set(prop_prefix "INTERFACE_")
+ endif()
+ set(include_path_prop "${prop_prefix}INCLUDE_DIRECTORIES")
+
+ set(include_paths_property "$<TARGET_PROPERTY:${target},${include_path_prop}>")
+ if (NOT target_type STREQUAL "UTILITY")
+ file(GENERATE
+ OUTPUT ${target_include_dirs_file}
+ CONTENT "$<$<BOOL:${include_paths_property}>:-I$<JOIN:${include_paths_property},\n-I>>"
+ )
+ set(include_path_args "@${target_include_dirs_file}")
+ else()
+ set(include_path_args "")
+ endif()
+
+ get_filename_component(doc_target "${doc_project}" NAME_WLE)
+ if (QT_WILL_INSTALL)
+ set(qdoc_output_dir "${CMAKE_BINARY_DIR}/${INSTALL_DOCDIR}/${doc_target}")
+ set(qdoc_qch_output_dir "${CMAKE_BINARY_DIR}/${INSTALL_DOCDIR}")
+ set(index_dir "${CMAKE_BINARY_DIR}/${INSTALL_DOCDIR}")
+ else()
+ set(qdoc_output_dir "${QT_BUILD_INTERNALS_RELOCATABLE_INSTALL_PREFIX}/${INSTALL_DOCDIR}/${doc_target}")
+ set(qdoc_qch_output_dir "${QT_BUILD_INTERNALS_RELOCATABLE_INSTALL_PREFIX}/${INSTALL_DOCDIR}")
+ set(index_dir "${QT_BUILD_INTERNALS_RELOCATABLE_INSTALL_PREFIX}/${INSTALL_DOCDIR}")
+ endif()
+
+ # qtattributionsscanner
+ add_custom_target(qattributionsscanner_${target}
+ COMMAND ${qtattributionsscanner_bin}
+ ${PROJECT_SOURCE_DIR}
+ --basedir "${PROJECT_SOURCE_DIR}/.."
+ --filter "QDocModule=${doc_target}"
+ -o "${target_bin_dir}/codeattributions.qdoc"
+ )
+
+ # prepare docs target
+ set(prepare_qdoc_args
+ -outputdir "${qdoc_output_dir}"
+ "${target_source_dir}/${doc_project}"
+ -prepare
+ -indexdir "${index_dir}"
+ -no-link-errors
+ "${include_path_args}"
+ )
+ if(NOT QT_BUILD_ONLINE_DOCS)
+ list(PREPEND prepare_qdoc_args
+ -installdir "${QT_INSTALL_DIR}/${INSTALL_DOCDIR}"
+ ${qdoc_extra_args}
+ )
+ endif()
+
+ if(DEFINED ENV{QT_INSTALL_DOCS})
+ set(qt_install_docs_env "$ENV{QT_INSTALL_DOCS}")
+ elseif(QT_SUPERBUILD OR "${PROJECT_NAME}" STREQUAL "QtBase")
+ set(qt_install_docs_env "${QtBase_BINARY_DIR}/${INSTALL_DOCDIR}")
+ else()
+ set(qt_install_docs_env "${QT_BUILD_INTERNALS_RELOCATABLE_INSTALL_PREFIX}/${INSTALL_DOCDIR}")
+ endif()
+
+ set(qdoc_env_args
+ "QT_INSTALL_DOCS=\"${qt_install_docs_env}\""
+ "QT_VERSION=${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}"
+ "QT_VER=${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}"
+ "QT_VERSION_TAG=${PROJECT_VERSION_MAJOR}${PROJECT_VERSION_MINOR}${PROJECT_VERSION_PATCH}"
+ "BUILDDIR=${target_bin_dir}"
+ )
+
+ add_custom_target(prepare_docs_${target}
+ COMMAND ${CMAKE_COMMAND} -E env ${qdoc_env_args}
+ ${qdoc_bin}
+ ${prepare_qdoc_args}
+ )
+
+ add_dependencies(prepare_docs_${target} qattributionsscanner_${target})
+ if(NOT TARGET sync_all_public_headers)
+ add_custom_target(sync_all_public_headers)
+ endif()
+ add_dependencies(prepare_docs_${target} sync_all_public_headers)
+
+ # generate docs target
+ set(generate_qdoc_args
+ -outputdir "${qdoc_output_dir}"
+ "${target_source_dir}/${doc_project}"
+ -generate
+ -indexdir "${index_dir}"
+ "${include_path_args}"
+ )
+ if(NOT QT_BUILD_ONLINE_DOCS)
+ list(PREPEND generate_qdoc_args
+ -installdir "${QT_INSTALL_DIR}/${INSTALL_DOCDIR}"
+ ${qdoc_extra_args}
+ )
+ endif()
+
+ foreach(target_prefix generate_top_level_docs generate_repo_docs generate_docs)
+ set(depends_arg "")
+ if(tool_dependencies_enabled)
+ set(depends_arg DEPENDS ${qdoc_bin})
+ endif()
+ add_custom_target(${target_prefix}_${target}
+ ${depends_arg}
+ COMMAND ${CMAKE_COMMAND} -E env ${qdoc_env_args} ${qdoc_bin} ${generate_qdoc_args})
+ endforeach()
+
+ add_dependencies(generate_docs_${target} prepare_docs_${target})
+ add_dependencies(generate_repo_docs_${target} ${qt_docs_prepare_target_name})
+ add_dependencies(generate_top_level_docs_${target} prepare_docs)
+ add_dependencies(generate_docs generate_top_level_docs_${target})
+
+ # html docs target
+ add_custom_target(html_docs_${target})
+ add_dependencies(html_docs_${target} generate_docs_${target})
+
+ # generate .qch
+ set(qch_file_name ${doc_target}.qch)
+ set(qch_file_path ${qdoc_qch_output_dir}/${qch_file_name})
+
+ foreach(target_prefix qch_top_level_docs qch_repo_docs qch_docs)
+ set(depends_arg "")
+ if(tool_dependencies_enabled)
+ set(depends_arg DEPENDS ${qhelpgenerator_bin})
+ endif()
+ add_custom_target(${target_prefix}_${target}
+ ${depends_arg}
+ COMMAND ${qhelpgenerator_bin}
+ "${qdoc_output_dir}/${doc_target}.qhp"
+ -o "${qch_file_path}"
+ )
+ endforeach()
+ add_dependencies(qch_docs_${target} generate_docs_${target})
+ add_dependencies(qch_repo_docs_${target} ${qt_docs_generate_target_name})
+ add_dependencies(qch_top_level_docs_${target} generate_docs)
+ add_dependencies(qch_docs qch_top_level_docs_${target})
+
+ if (QT_WILL_INSTALL)
+ install(DIRECTORY "${qdoc_output_dir}/"
+ DESTINATION "${INSTALL_DOCDIR}/${doc_target}"
+ COMPONENT _install_html_docs_${target}
+ EXCLUDE_FROM_ALL
+ )
+
+ add_custom_target(install_html_docs_${target}
+ COMMAND ${CMAKE_COMMAND}
+ --install "${CMAKE_BINARY_DIR}"
+ --component _install_html_docs_${target}
+ COMMENT "Installing html docs for target ${target}"
+ )
+
+ install(FILES "${qch_file_path}"
+ DESTINATION "${INSTALL_DOCDIR}"
+ COMPONENT _install_qch_docs_${target}
+ EXCLUDE_FROM_ALL
+ )
+
+ add_custom_target(install_qch_docs_${target}
+ COMMAND ${CMAKE_COMMAND}
+ --install "${CMAKE_BINARY_DIR}"
+ --component _install_qch_docs_${target}
+ COMMENT "Installing qch docs for target ${target}"
+ )
+
+ else()
+ # Don't need to do anything when not installing
+ add_custom_target(install_html_docs_${target})
+ add_custom_target(install_qch_docs_${target})
+ endif()
+
+ add_custom_target(install_docs_${target})
+ add_dependencies(install_docs_${target} install_html_docs_${target} install_qch_docs_${target})
+
+ add_custom_target(docs_${target})
+ add_dependencies(docs_${target} html_docs_${target})
+ add_dependencies(docs_${target} qch_docs_${target})
+
+ add_dependencies(${qt_docs_prepare_target_name} prepare_docs_${target})
+ add_dependencies(${qt_docs_generate_target_name} generate_repo_docs_${target})
+ add_dependencies(${qt_docs_qch_target_name} qch_repo_docs_${target})
+ add_dependencies(${qt_docs_install_html_target_name} install_html_docs_${target})
+ add_dependencies(${qt_docs_install_qch_target_name} install_qch_docs_${target})
+
+ # Make sure that the necessary tools are built when running,
+ # for example 'cmake --build . --target generate_docs'.
+ if(tool_dependencies_enabled)
+ qt_internal_add_doc_tool_dependency(qattributionsscanner_${target} qtattributionsscanner)
+ qt_internal_add_doc_tool_dependency(prepare_docs_${target} qdoc)
+ qt_internal_add_doc_tool_dependency(qch_docs_${target} qhelpgenerator)
+ endif()
+endfunction()
diff --git a/cmake/QtExecutableHelpers.cmake b/cmake/QtExecutableHelpers.cmake
new file mode 100644
index 0000000000..fb96ca4db2
--- /dev/null
+++ b/cmake/QtExecutableHelpers.cmake
@@ -0,0 +1,537 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+# This function creates a CMake target for a generic console or GUI binary.
+# Please consider to use a more specific version target like the one created
+# by qt_add_test or qt_add_tool below.
+# One-value Arguments:
+# CORE_LIBRARY
+# The argument accepts 'Bootstrap' or 'None' values. If the argument value is set to
+# 'Bootstrap' the Qt::Bootstrap library is linked to the executable instead of Qt::Core.
+# The 'None' value points that core library is not necessary and avoids linking neither
+# Qt::Core or Qt::Bootstrap libraries. Otherwise the Qt::Core library will be publicly
+# linked to the executable target by default.
+function(qt_internal_add_executable name)
+ cmake_parse_arguments(PARSE_ARGV 1 arg
+ "${__qt_internal_add_executable_optional_args}"
+ "${__qt_internal_add_executable_single_args}"
+ "${__qt_internal_add_executable_multi_args}")
+ _qt_internal_validate_all_args_are_parsed(arg)
+
+ if ("x${arg_OUTPUT_DIRECTORY}" STREQUAL "x")
+ set(arg_OUTPUT_DIRECTORY "${QT_BUILD_DIR}/${INSTALL_BINDIR}")
+ endif()
+
+ get_filename_component(arg_OUTPUT_DIRECTORY "${arg_OUTPUT_DIRECTORY}"
+ ABSOLUTE BASE_DIR "${QT_BUILD_DIR}")
+
+ if ("x${arg_INSTALL_DIRECTORY}" STREQUAL "x")
+ set(arg_INSTALL_DIRECTORY "${INSTALL_BINDIR}")
+ endif()
+
+ _qt_internal_create_executable(${name})
+ qt_internal_mark_as_internal_target(${name})
+ if(ANDROID)
+ _qt_internal_android_executable_finalizer(${name})
+ endif()
+
+ if(arg_QT_APP AND QT_FEATURE_debug_and_release AND CMAKE_VERSION VERSION_GREATER_EQUAL "3.19.0")
+ set_property(TARGET "${name}"
+ PROPERTY EXCLUDE_FROM_ALL "$<NOT:$<CONFIG:${QT_MULTI_CONFIG_FIRST_CONFIG}>>")
+ endif()
+
+ if (arg_VERSION)
+ if(arg_VERSION MATCHES "[0-9]+\\.[0-9]+\\.[0-9]+\\.[0-9]+")
+ # nothing to do
+ elseif(arg_VERSION MATCHES "[0-9]+\\.[0-9]+\\.[0-9]+")
+ set(arg_VERSION "${arg_VERSION}.0")
+ elseif(arg_VERSION MATCHES "[0-9]+\\.[0-9]+")
+ set(arg_VERSION "${arg_VERSION}.0.0")
+ elseif (arg_VERSION MATCHES "[0-9]+")
+ set(arg_VERSION "${arg_VERSION}.0.0.0")
+ else()
+ message(FATAL_ERROR "Invalid version format")
+ endif()
+ endif()
+
+ if(arg_DELAY_TARGET_INFO)
+ # Delay the setting of target info properties if requested. Needed for scope finalization
+ # of Qt apps.
+ set_target_properties("${name}" PROPERTIES
+ QT_DELAYED_TARGET_VERSION "${arg_VERSION}"
+ QT_DELAYED_TARGET_PRODUCT "${arg_TARGET_PRODUCT}"
+ QT_DELAYED_TARGET_DESCRIPTION "${arg_TARGET_DESCRIPTION}"
+ QT_DELAYED_TARGET_COMPANY "${arg_TARGET_COMPANY}"
+ QT_DELAYED_TARGET_COPYRIGHT "${arg_TARGET_COPYRIGHT}"
+ )
+ else()
+ if(NOT arg_TARGET_DESCRIPTION)
+ set(arg_TARGET_DESCRIPTION "Qt ${name}")
+ endif()
+ qt_set_target_info_properties(${name} ${ARGN}
+ TARGET_DESCRIPTION ${arg_TARGET_DESCRIPTION}
+ TARGET_VERSION ${arg_VERSION})
+ endif()
+
+ if (WIN32 AND NOT arg_DELAY_RC)
+ _qt_internal_generate_win32_rc_file(${name})
+ endif()
+
+ qt_set_common_target_properties(${name})
+
+ qt_internal_add_repo_local_defines(${name})
+
+ if(ANDROID)
+ # The above call to qt_set_common_target_properties() sets the symbol
+ # visibility to hidden, but for Android, we need main() to not be hidden
+ # because it has to be loadable at runtime using dlopen().
+ set_property(TARGET ${name} PROPERTY C_VISIBILITY_PRESET default)
+ set_property(TARGET ${name} PROPERTY CXX_VISIBILITY_PRESET default)
+ endif()
+
+ qt_autogen_tools_initial_setup(${name})
+ qt_skip_warnings_are_errors_when_repo_unclean("${name}")
+
+ set(extra_libraries "")
+ if(arg_CORE_LIBRARY STREQUAL "Bootstrap")
+ list(APPEND extra_libraries ${QT_CMAKE_EXPORT_NAMESPACE}::Bootstrap)
+ elseif(NOT arg_CORE_LIBRARY STREQUAL "None")
+ list(APPEND extra_libraries ${QT_CMAKE_EXPORT_NAMESPACE}::Core)
+ endif()
+
+ set(private_includes
+ "${CMAKE_CURRENT_SOURCE_DIR}"
+ "${CMAKE_CURRENT_BINARY_DIR}"
+ ${arg_INCLUDE_DIRECTORIES}
+ )
+
+ if(arg_PUBLIC_LIBRARIES)
+ message(WARNING
+ "qt_internal_add_executable's PUBLIC_LIBRARIES option is deprecated, and will be "
+ "removed in a future Qt version. Use the LIBRARIES option instead.")
+ endif()
+
+ if(arg_NO_UNITY_BUILD)
+ set(arg_NO_UNITY_BUILD "NO_UNITY_BUILD")
+ else()
+ set(arg_NO_UNITY_BUILD "")
+ endif()
+
+ qt_internal_extend_target("${name}"
+ ${arg_NO_UNITY_BUILD}
+ SOURCES ${arg_SOURCES}
+ NO_PCH_SOURCES ${arg_NO_PCH_SOURCES}
+ NO_UNITY_BUILD_SOURCES ${arg_NO_UNITY_BUILD_SOURCES}
+ INCLUDE_DIRECTORIES ${private_includes}
+ DEFINES ${arg_DEFINES}
+ LIBRARIES
+ ${arg_LIBRARIES}
+ ${arg_PUBLIC_LIBRARIES}
+ Qt::PlatformCommonInternal
+ ${extra_libraries}
+ DBUS_ADAPTOR_SOURCES ${arg_DBUS_ADAPTOR_SOURCES}
+ DBUS_ADAPTOR_FLAGS ${arg_DBUS_ADAPTOR_FLAGS}
+ DBUS_INTERFACE_SOURCES ${arg_DBUS_INTERFACE_SOURCES}
+ DBUS_INTERFACE_FLAGS ${arg_DBUS_INTERFACE_FLAGS}
+ COMPILE_OPTIONS ${arg_COMPILE_OPTIONS}
+ LINK_OPTIONS ${arg_LINK_OPTIONS}
+ MOC_OPTIONS ${arg_MOC_OPTIONS}
+ ENABLE_AUTOGEN_TOOLS ${arg_ENABLE_AUTOGEN_TOOLS}
+ DISABLE_AUTOGEN_TOOLS ${arg_DISABLE_AUTOGEN_TOOLS}
+ )
+ set_target_properties("${name}" PROPERTIES
+ RUNTIME_OUTPUT_DIRECTORY "${arg_OUTPUT_DIRECTORY}"
+ LIBRARY_OUTPUT_DIRECTORY "${arg_OUTPUT_DIRECTORY}"
+ WIN32_EXECUTABLE "${arg_GUI}"
+ MACOSX_BUNDLE "${arg_GUI}"
+ )
+
+ qt_internal_set_exceptions_flags("${name}" ${arg_EXCEPTIONS})
+
+ if(WASM)
+ qt_internal_wasm_add_finalizers("${name}")
+ endif()
+
+ # Check if target needs to be excluded from all target. Also affects qt_install.
+ # Set by qt_exclude_tool_directories_from_default_target.
+ set(exclude_from_all FALSE)
+ if(__qt_exclude_tool_directories)
+ foreach(absolute_dir ${__qt_exclude_tool_directories})
+ string(FIND "${CMAKE_CURRENT_SOURCE_DIR}" "${absolute_dir}" dir_starting_pos)
+ if(dir_starting_pos EQUAL 0)
+ set(exclude_from_all TRUE)
+ set_target_properties("${name}" PROPERTIES EXCLUDE_FROM_ALL TRUE)
+ break()
+ endif()
+ endforeach()
+ endif()
+
+ if(NOT arg_NO_INSTALL)
+ set(additional_install_args "")
+ if(exclude_from_all)
+ list(APPEND additional_install_args EXCLUDE_FROM_ALL COMPONENT "ExcludedExecutables")
+ endif()
+
+ qt_get_cmake_configurations(cmake_configs)
+ foreach(cmake_config ${cmake_configs})
+ qt_get_install_target_default_args(
+ OUT_VAR install_targets_default_args
+ CMAKE_CONFIG "${cmake_config}"
+ ALL_CMAKE_CONFIGS "${cmake_configs}"
+ RUNTIME "${arg_INSTALL_DIRECTORY}"
+ LIBRARY "${arg_INSTALL_DIRECTORY}"
+ BUNDLE "${arg_INSTALL_DIRECTORY}")
+
+ # Make installation optional for targets that are not built by default in this config
+ if(NOT exclude_from_all AND arg_QT_APP AND QT_FEATURE_debug_and_release
+ AND NOT (cmake_config STREQUAL QT_MULTI_CONFIG_FIRST_CONFIG))
+ set(install_optional_arg "OPTIONAL")
+ else()
+ unset(install_optional_arg)
+ endif()
+
+ qt_install(TARGETS "${name}"
+ ${additional_install_args} # Needs to be before the DESTINATIONS.
+ ${install_optional_arg}
+ CONFIGURATIONS ${cmake_config}
+ ${install_targets_default_args})
+ endforeach()
+
+ if(NOT exclude_from_all AND arg_QT_APP AND QT_FEATURE_debug_and_release)
+ set(separate_debug_info_executable_arg "QT_EXECUTABLE")
+ else()
+ unset(separate_debug_info_executable_arg)
+ endif()
+ qt_enable_separate_debug_info(${name} "${arg_INSTALL_DIRECTORY}"
+ ${separate_debug_info_executable_arg}
+ ADDITIONAL_INSTALL_ARGS ${additional_install_args})
+ qt_internal_install_pdb_files(${name} "${arg_INSTALL_DIRECTORY}")
+ endif()
+
+ # If linking against Gui, make sure to also build the default QPA plugin.
+ # This makes the experience of an initial Qt configuration to build and run one single
+ # test / executable nicer.
+ get_target_property(linked_libs "${name}" LINK_LIBRARIES)
+ if("Qt::Gui" IN_LIST linked_libs AND TARGET qpa_default_plugins)
+ add_dependencies("${name}" qpa_default_plugins)
+ endif()
+
+ # For static plugins, we need to explicitly link to plugins we want to be
+ # loaded with the executable. User projects get that automatically, but
+ # for tools built as part of Qt, we can't use that mechanism because it
+ # would pollute the targets we export as part of an install and lead to
+ # circular dependencies. The logic here is a simpler equivalent of the
+ # more dynamic logic in QtPlugins.cmake.in, but restricted to only
+ # adding plugins that are provided by the same module as the module
+ # libraries the executable links to.
+ set(libs
+ ${arg_LIBRARIES}
+ ${arg_PUBLIC_LIBRARIES}
+ ${extra_libraries}
+ Qt::PlatformCommonInternal
+ )
+
+ set(deduped_libs "")
+ foreach(lib IN LISTS libs)
+ if(NOT TARGET "${lib}")
+ continue()
+ endif()
+
+ # Normalize module by stripping any leading "Qt::", because properties are set on the
+ # versioned target (either Gui when building the module, or Qt6::Gui when it's
+ # imported).
+ if(lib MATCHES "Qt::([-_A-Za-z0-9]+)")
+ set(new_lib "${QT_CMAKE_EXPORT_NAMESPACE}::${CMAKE_MATCH_1}")
+ if(TARGET "${new_lib}")
+ set(lib "${new_lib}")
+ endif()
+ endif()
+
+ # Unalias the target.
+ get_target_property(aliased_target ${lib} ALIASED_TARGET)
+ if(aliased_target)
+ set(lib ${aliased_target})
+ endif()
+
+ list(APPEND deduped_libs "${lib}")
+ endforeach()
+
+ list(REMOVE_DUPLICATES deduped_libs)
+
+ foreach(lib IN LISTS deduped_libs)
+ string(MAKE_C_IDENTIFIER "${name}_plugin_imports_${lib}" out_file)
+ string(APPEND out_file .cpp)
+
+ # Initialize plugins that are built in the same repository as the Qt module 'lib'.
+ set(class_names_regular
+ "$<GENEX_EVAL:$<TARGET_PROPERTY:${lib},_qt_initial_repo_plugin_class_names>>")
+
+ # Initialize plugins that are built in the current Qt repository, but are associated
+ # with a Qt module from a different repository (qtsvg's QSvgPlugin associated with
+ # qtbase's QtGui).
+ string(MAKE_C_IDENTIFIER "${PROJECT_NAME}" current_project_name)
+ set(prop_prefix "_qt_repo_${current_project_name}")
+ set(class_names_current_project
+ "$<GENEX_EVAL:$<TARGET_PROPERTY:${lib},${prop_prefix}_plugin_class_names>>")
+
+ # Only add separator if first list is not empty, so we don't trigger the file generation
+ # when all lists are empty.
+ set(class_names_separator "$<$<NOT:$<STREQUAL:${class_names_regular},>>:;>" )
+ set(class_names
+ "${class_names_regular}${class_names_separator}${class_names_current_project}")
+
+ set(out_file_path "${CMAKE_CURRENT_BINARY_DIR}/${out_file}")
+
+ file(GENERATE OUTPUT "${out_file_path}" CONTENT
+"// This file is auto-generated. Do not edit.
+#include <QtPlugin>
+
+Q_IMPORT_PLUGIN($<JOIN:${class_names},)\nQ_IMPORT_PLUGIN(>)
+"
+ CONDITION "$<NOT:$<STREQUAL:${class_names},>>"
+ )
+
+ # CMake versions earlier than 3.18.0 can't find the generated file for some reason,
+ # failing at generation phase.
+ # Explicitly marking the file as GENERATED fixes the issue.
+ set_source_files_properties("${out_file_path}" PROPERTIES GENERATED TRUE)
+
+ target_sources(${name} PRIVATE
+ "$<$<NOT:$<STREQUAL:${class_names},>>:${out_file_path}>"
+ )
+ target_link_libraries(${name} PRIVATE
+ "$<TARGET_PROPERTY:${lib},_qt_initial_repo_plugins>"
+ "$<TARGET_PROPERTY:${lib},${prop_prefix}_plugins>")
+ endforeach()
+
+endfunction()
+
+# This function compiles the target at configure time the very first time and creates the custom
+# ${target}_build that re-runs compilation at build time if necessary. The resulting executable is
+# imported under the provided target name. This function should only be used to compile tiny
+# executables with system dependencies only.
+# One-value Arguments:
+# CMAKELISTS_TEMPLATE
+# The CMakeLists.txt templated that is used to configure the project
+# for an executable. By default the predefined template from the Qt installation is used.
+# INSTALL_DIRECTORY
+# installation directory of the executable. Ignored if NO_INSTALL is set.
+# OUTPUT_NAME
+# the output name of an executable
+# CONFIG
+# the name of configuration that tool needs to be build with.
+# Multi-value Arguments:
+# PACKAGES
+# list of system packages are required to successfully build the project.
+# INCLUDES
+# list of include directories are required to successfully build the project.
+# DEFINES
+# list of definitions are required to successfully build the project.
+# COMPILE_OPTIONS
+# list of compiler options are required to successfully build the project.
+# LINK_OPTIONS
+# list of linker options are required to successfully build the project.
+# SOURCES
+# list of project sources.
+# CMAKE_FLAGS
+# specify flags of the form -DVAR:TYPE=VALUE to be passed to the cmake command-line used to
+# drive the test build.
+# Options:
+# WIN32
+# reflects the corresponding add_executable argument.
+# MACOSX_BUNDLE
+# reflects the corresponding add_executable argument.
+# NO_INSTALL
+# avoids installing the tool.
+function(qt_internal_add_configure_time_executable target)
+ set(one_value_args
+ CMAKELISTS_TEMPLATE
+ INSTALL_DIRECTORY
+ OUTPUT_NAME
+ CONFIG
+ )
+ set(multi_value_args
+ PACKAGES
+ INCLUDES
+ DEFINES
+ COMPILE_OPTIONS
+ LINK_OPTIONS
+ SOURCES
+ CMAKE_FLAGS
+ )
+ set(option_args WIN32 MACOSX_BUNDLE NO_INSTALL)
+ cmake_parse_arguments(PARSE_ARGV 1 arg
+ "${option_args}" "${one_value_args}" "${multi_value_args}")
+
+ set(target_binary_dir "${CMAKE_CURRENT_BINARY_DIR}/configure_time_bins")
+ if(arg_CONFIG)
+ set(CMAKE_TRY_COMPILE_CONFIGURATION "${arg_CONFIG}")
+ string(TOUPPER "_${arg_CONFIG}" config_suffix)
+ endif()
+
+ get_cmake_property(is_multi_config GENERATOR_IS_MULTI_CONFIG)
+ if(is_multi_config AND CMAKE_TRY_COMPILE_CONFIGURATION)
+ set(configuration_path "${CMAKE_TRY_COMPILE_CONFIGURATION}/")
+ set(config_build_arg "--config" "${CMAKE_TRY_COMPILE_CONFIGURATION}")
+ endif()
+
+ set(configure_time_target "${target}")
+ if(arg_OUTPUT_NAME)
+ set(configure_time_target "${arg_OUTPUT_NAME}")
+ endif()
+ set(target_binary "${configure_time_target}${CMAKE_EXECUTABLE_SUFFIX}")
+
+ set(install_dir "${INSTALL_BINDIR}")
+ if(arg_INSTALL_DIRECTORY)
+ set(install_dir "${arg_INSTALL_DIRECTORY}")
+ endif()
+
+ set(output_directory_relative "${install_dir}")
+ set(output_directory "${QT_BUILD_DIR}/${install_dir}")
+
+ set(target_binary_path_relative
+ "${output_directory_relative}/${configuration_path}${target_binary}")
+ set(target_binary_path
+ "${output_directory}/${configuration_path}${target_binary}")
+
+ get_filename_component(target_binary_path "${target_binary_path}" ABSOLUTE)
+
+ if(NOT DEFINED arg_SOURCES)
+ message(FATAL_ERROR "No SOURCES given to target: ${target}")
+ endif()
+ set(sources "${arg_SOURCES}")
+
+ # Timestamp file is required because CMake ignores 'add_custom_command' if we use only the
+ # binary file as the OUTPUT.
+ set(timestamp_file "${target_binary_dir}/${target_binary}_timestamp")
+ add_custom_command(OUTPUT "${target_binary_path}" "${timestamp_file}"
+ COMMAND
+ ${CMAKE_COMMAND} --build "${target_binary_dir}" --clean-first ${config_build_arg}
+ COMMAND
+ ${CMAKE_COMMAND} -E touch "${timestamp_file}"
+ DEPENDS
+ ${sources}
+ COMMENT
+ "Compiling ${target}"
+ VERBATIM
+ )
+
+ add_custom_target(${target}_build ALL
+ DEPENDS
+ "${target_binary_path}"
+ "${timestamp_file}"
+ )
+
+ set(should_build_at_configure_time TRUE)
+ if(QT_INTERNAL_HAVE_CONFIGURE_TIME_${target} AND
+ EXISTS "${target_binary_path}" AND EXISTS "${timestamp_file}")
+ set(last_ts 0)
+ foreach(source IN LISTS sources)
+ file(TIMESTAMP "${source}" ts "%s")
+ if(${ts} GREATER ${last_ts})
+ set(last_ts ${ts})
+ endif()
+ endforeach()
+
+ file(TIMESTAMP "${target_binary_path}" ts "%s")
+ if(${ts} GREATER_EQUAL ${last_ts})
+ set(should_build_at_configure_time FALSE)
+ endif()
+ endif()
+
+ set(cmake_flags_arg "")
+ if(arg_CMAKE_FLAGS)
+ set(cmake_flags_arg CMAKE_FLAGS "${arg_CMAKE_FLAGS}")
+ endif()
+
+ qt_internal_get_enabled_languages_for_flag_manipulation(enabled_languages)
+ foreach(lang IN LISTS enabled_languages)
+ set(compiler_flags_var "CMAKE_${lang}_FLAGS")
+ list(APPEND cmake_flags_arg "-D${compiler_flags_var}:STRING=${${compiler_flags_var}}")
+ if(arg_CONFIG)
+ set(compiler_flags_var_config "${compiler_flags_var}${config_suffix}")
+ list(APPEND cmake_flags_arg
+ "-D${compiler_flags_var_config}:STRING=${${compiler_flags_var_config}}")
+ endif()
+ endforeach()
+
+ qt_internal_get_target_link_types_for_flag_manipulation(target_link_types)
+ foreach(linker_type IN LISTS target_link_types)
+ set(linker_flags_var "CMAKE_${linker_type}_LINKER_FLAGS")
+ list(APPEND cmake_flags_arg "-D${linker_flags_var}:STRING=${${linker_flags_var}}")
+ if(arg_CONFIG)
+ set(linker_flags_var_config "${linker_flags_var}${config_suffix}")
+ list(APPEND cmake_flags_arg
+ "-D${linker_flags_var_config}:STRING=${${linker_flags_var_config}}")
+ endif()
+ endforeach()
+
+ if(NOT "${QT_INTERNAL_CMAKE_FLAGS_CONFIGURE_TIME_TOOL_${target}}" STREQUAL "${cmake_flags_arg}")
+ set(should_build_at_configure_time TRUE)
+ endif()
+
+ if(should_build_at_configure_time)
+ foreach(arg IN LISTS multi_value_args)
+ string(TOLOWER "${arg}" template_arg_name)
+ set(${template_arg_name} "")
+ if(DEFINED arg_${arg})
+ set(${template_arg_name} "${arg_${arg}}")
+ endif()
+ endforeach()
+
+ foreach(arg IN LISTS option_args)
+ string(TOLOWER "${arg}" template_arg_name)
+ set(${template_arg_name} "")
+ if(arg_${arg})
+ set(${template_arg_name} "${arg}")
+ endif()
+ endforeach()
+
+ file(MAKE_DIRECTORY "${target_binary_dir}")
+ set(template "${QT_CMAKE_DIR}/QtConfigureTimeExecutableCMakeLists.txt.in")
+ if(DEFINED arg_CMAKELISTS_TEMPLATE)
+ set(template "${arg_CMAKELISTS_TEMPLATE}")
+ endif()
+
+ configure_file("${template}" "${target_binary_dir}/CMakeLists.txt" @ONLY)
+
+ if(EXISTS "${target_binary_dir}/CMakeCache.txt")
+ file(REMOVE "${target_binary_dir}/CMakeCache.txt")
+ endif()
+
+ try_compile(result
+ "${target_binary_dir}"
+ "${target_binary_dir}"
+ ${target}
+ ${cmake_flags_arg}
+ OUTPUT_VARIABLE try_compile_output
+ )
+
+ set(QT_INTERNAL_CMAKE_FLAGS_CONFIGURE_TIME_TOOL_${target}
+ "${cmake_flags_arg}" CACHE INTERNAL "")
+
+ file(WRITE "${timestamp_file}" "")
+ set(QT_INTERNAL_HAVE_CONFIGURE_TIME_${target} ${result} CACHE INTERNAL
+ "Indicates that the configure-time target ${target} was built")
+ if(NOT result)
+ message(FATAL_ERROR "Unable to build ${target}: ${try_compile_output}")
+ endif()
+ endif()
+
+ add_executable(${target} IMPORTED GLOBAL)
+ add_executable(${QT_CMAKE_EXPORT_NAMESPACE}::${target} ALIAS ${target})
+ set_target_properties(${target} PROPERTIES
+ _qt_internal_configure_time_target TRUE
+ _qt_internal_configure_time_target_build_location "${target_binary_path_relative}"
+ IMPORTED_LOCATION "${target_binary_path}"
+ )
+
+ if(NOT arg_NO_INSTALL)
+ set_target_properties(${target} PROPERTIES
+ _qt_internal_configure_time_target_install_location
+ "${install_dir}/${target_binary}"
+ )
+ qt_path_join(target_install_dir ${QT_INSTALL_DIR} ${install_dir})
+ qt_install(PROGRAMS "${target_binary_path}" DESTINATION "${target_install_dir}")
+ endif()
+endfunction()
diff --git a/cmake/QtFeature.cmake b/cmake/QtFeature.cmake
index 5058a7f86b..96cb308b2c 100644
--- a/cmake/QtFeature.cmake
+++ b/cmake/QtFeature.cmake
@@ -1,7 +1,14 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+include(CheckCXXCompilerFlag)
+
function(qt_feature_module_begin)
- qt_parse_all_arguments(arg "qt_feature_module_begin"
+ cmake_parse_arguments(PARSE_ARGV 0 arg
"NO_MODULE;ONLY_EVALUATE_FEATURES"
- "LIBRARY;PRIVATE_FILE;PUBLIC_FILE" "PUBLIC_DEPENDENCIES;PRIVATE_DEPENDENCIES" ${ARGN})
+ "LIBRARY;PRIVATE_FILE;PUBLIC_FILE"
+ "PUBLIC_DEPENDENCIES;PRIVATE_DEPENDENCIES")
+ _qt_internal_validate_all_args_are_parsed(arg)
if(NOT arg_ONLY_EVALUATE_FEATURES)
if ("${arg_LIBRARY}" STREQUAL "" AND (NOT ${arg_NO_MODULE}))
@@ -35,24 +42,16 @@ function(qt_feature_module_begin)
set(__QtFeature_define_definitions "" PARENT_SCOPE)
endfunction()
-function(qt_feature_normalize_name name out_var)
- # Normalize the feature name to something CMake can deal with.
- if(name MATCHES "c\\+\\+")
- string(REGEX REPLACE "[^a-zA-Z0-9_]" "x" name "${name}")
- else()
- string(REGEX REPLACE "[^a-zA-Z0-9_]" "_" name "${name}")
- endif()
- set(${out_var} "${name}" PARENT_SCOPE)
-endfunction()
-
function(qt_feature feature)
set(original_name "${feature}")
qt_feature_normalize_name("${feature}" feature)
set_property(GLOBAL PROPERTY QT_FEATURE_ORIGINAL_NAME_${feature} "${original_name}")
- qt_parse_all_arguments(arg "qt_feature"
+ cmake_parse_arguments(PARSE_ARGV 1 arg
"PRIVATE;PUBLIC"
- "LABEL;PURPOSE;SECTION;" "AUTODETECT;CONDITION;ENABLE;DISABLE;EMIT_IF" ${ARGN})
+ "LABEL;PURPOSE;SECTION"
+ "AUTODETECT;CONDITION;ENABLE;DISABLE;EMIT_IF")
+ _qt_internal_validate_all_args_are_parsed(arg)
set(_QT_FEATURE_DEFINITION_${feature} ${ARGN} PARENT_SCOPE)
@@ -81,45 +80,25 @@ function(qt_evaluate_to_boolean expressionVar)
endif()
endfunction()
-function(qt_evaluate_config_expression resultVar)
+function(qt_internal_evaluate_config_expression resultVar outIdx startIdx)
set(result "")
- set(nestingLevel 0)
- set(skipNext OFF)
set(expression "${ARGN}")
list(LENGTH expression length)
+ math(EXPR memberIdx "${startIdx} - 1")
math(EXPR length "${length}-1")
- foreach(memberIdx RANGE ${length})
- if(${skipNext})
- set(skipNext OFF)
- continue()
- endif()
-
+ while(memberIdx LESS ${length})
+ math(EXPR memberIdx "${memberIdx} + 1")
list(GET expression ${memberIdx} member)
if("${member}" STREQUAL "(")
- if(${nestingLevel} GREATER 0)
- list(APPEND result ${member})
- endif()
- math(EXPR nestingLevel "${nestingLevel} + 1")
- continue()
+ math(EXPR memberIdx "${memberIdx} + 1")
+ qt_internal_evaluate_config_expression(sub_result memberIdx ${memberIdx} ${expression})
+ list(APPEND result ${sub_result})
elseif("${member}" STREQUAL ")")
- math(EXPR nestingLevel "${nestingLevel} - 1")
- if(nestingLevel LESS 0)
- break()
- endif()
- if(${nestingLevel} EQUAL 0)
- qt_evaluate_config_expression(result ${result})
- else()
- list(APPEND result ${member})
- endif()
- continue()
- elseif(${nestingLevel} GREATER 0)
- list(APPEND result ${member})
- continue()
+ break()
elseif("${member}" STREQUAL "NOT")
list(APPEND result ${member})
- continue()
elseif("${member}" STREQUAL "AND")
qt_evaluate_to_boolean(result)
if(NOT ${result})
@@ -144,7 +123,7 @@ function(qt_evaluate_config_expression resultVar)
set(lhs "${${lhs}}")
math(EXPR rhsIndex "${memberIdx}+1")
- set(skipNext ON)
+ set(memberIdx ${rhsIndex})
list(GET expression ${rhsIndex} rhs)
# We can't pass through an empty string with double quotes through various
@@ -164,7 +143,7 @@ function(qt_evaluate_config_expression resultVar)
list(APPEND result ${member})
endif()
- endforeach()
+ endwhile()
# The 'TARGET Gui' case is handled by qt_evaluate_to_boolean, by passing those tokens verbatim
# to if().
@@ -174,55 +153,220 @@ function(qt_evaluate_config_expression resultVar)
qt_evaluate_to_boolean(result)
endif()
+ # When in recursion, we must skip to the next closing parenthesis on nesting level 0. The outIdx
+ # must point to the matching closing parenthesis, and that's not the case if we're early exiting
+ # in AND/OR.
+ if(startIdx GREATER 0)
+ set(nestingLevel 1)
+ while(TRUE)
+ list(GET expression ${memberIdx} member)
+ if("${member}" STREQUAL ")")
+ math(EXPR nestingLevel "${nestingLevel} - 1")
+ if(nestingLevel EQUAL 0)
+ break()
+ endif()
+ elseif("${member}" STREQUAL "(")
+ math(EXPR nestingLevel "${nestingLevel} + 1")
+ endif()
+ math(EXPR memberIdx "${memberIdx} + 1")
+ endwhile()
+ endif()
+
+ set(${outIdx} ${memberIdx} PARENT_SCOPE)
set(${resultVar} ${result} PARENT_SCOPE)
endfunction()
-function(qt_feature_set_cache_value resultVar feature emit_if calculated label)
+function(qt_evaluate_config_expression resultVar)
+ qt_internal_evaluate_config_expression(result unused 0 ${ARGN})
+ set("${resultVar}" "${result}" PARENT_SCOPE)
+endfunction()
+
+function(_qt_internal_get_feature_condition_keywords out_var)
+ set(keywords "EQUAL" "LESS" "LESS_EQUAL" "GREATER" "GREATER_EQUAL" "STREQUAL" "STRLESS"
+ "STRLESS_EQUAL" "STRGREATER" "STRGREATER_EQUAL" "VERSION_EQUAL" "VERSION_LESS"
+ "VERSION_LESS_EQUAL" "VERSION_GREATER" "VERSION_GREATER_EQUAL" "MATCHES"
+ "EXISTS" "COMMAND" "DEFINED" "NOT" "AND" "OR" "TARGET" "EXISTS" "IN_LIST" "(" ")")
+ set(${out_var} "${keywords}" PARENT_SCOPE)
+endfunction()
+
+function(_qt_internal_dump_expression_values expression_dump expression)
+ set(dump "")
+ set(skipNext FALSE)
+ set(isTargetExpression FALSE)
+
+ _qt_internal_get_feature_condition_keywords(keywords)
+
+ list(LENGTH expression length)
+ math(EXPR length "${length}-1")
+
+ if(${length} LESS 0)
+ return()
+ endif()
+
+ foreach(memberIdx RANGE ${length})
+ if(${skipNext})
+ set(skipNext FALSE)
+ continue()
+ endif()
+
+ list(GET expression ${memberIdx} member)
+ if(NOT "${member}" IN_LIST keywords)
+ string(FIND "${member}" "QT_FEATURE_" idx)
+ if(idx EQUAL 0)
+ if(NOT DEFINED ${member})
+ list(APPEND dump "${member} not evaluated")
+ else()
+ list(APPEND dump "${member} = \"${${member}}\"")
+ endif()
+ elseif(isTargetExpression)
+ set(targetExpression "TARGET;${member}")
+ if(${targetExpression})
+ list(APPEND dump "TARGET ${member} found")
+ else()
+ list(APPEND dump "TARGET ${member} not found")
+ endif()
+ else()
+ list(APPEND dump "${member} = \"${${member}}\"")
+ endif()
+ set(isTargetExpression FALSE)
+ set(skipNext FALSE)
+ elseif("${member}" STREQUAL "TARGET")
+ set(isTargetExpression TRUE)
+ elseif("${member}" STREQUAL "STREQUAL")
+ set(skipNext TRUE)
+ else()
+ set(skipNext FALSE)
+ set(isTargetExpression FALSE)
+ endif()
+ endforeach()
+ string(JOIN "\n " ${expression_dump} ${dump})
+ set(${expression_dump} "${${expression_dump}}" PARENT_SCOPE)
+endfunction()
+
+# Stores the user provided value to FEATURE_${feature} if provided.
+# If not provided, stores ${computed} instead.
+# ${computed} is also stored when reconfiguring and the condition does not align with the user
+# provided value.
+#
+function(qt_feature_check_and_save_user_provided_value
+ resultVar feature condition condition_expression computed label)
if (DEFINED "FEATURE_${feature}")
- # Must set up the cache
- if (NOT (emit_if))
- message(FATAL_ERROR "Sanity check failed: FEATURE_${feature} that was not emitted was found in the CMakeCache.")
+ # Revisit new user provided value
+ set(user_value "${FEATURE_${feature}}")
+ string(TOUPPER "${user_value}" user_value_upper)
+ set(result "${user_value_upper}")
+
+ # If ${feature} depends on another dirty feature, reset the ${feature} value to
+ # ${computed}.
+ get_property(dirty_build GLOBAL PROPERTY _qt_dirty_build)
+ if(dirty_build)
+ _qt_internal_feature_compute_feature_dependencies(deps "${feature}")
+ if(deps)
+ get_property(dirty_features GLOBAL PROPERTY _qt_dirty_features)
+ foreach(dirty_feature ${dirty_features})
+ if(dirty_feature IN_LIST deps AND NOT "${result}" STREQUAL "${computed}")
+ set(result "${computed}")
+ message(WARNING
+ "Auto-resetting 'FEATURE_${feature}' from '${user_value_upper}' to "
+ "'${computed}', "
+ "because the dependent feature '${dirty_feature}' was marked dirty.")
+
+ # Append ${feature} as a new dirty feature.
+ set_property(GLOBAL APPEND PROPERTY _qt_dirty_features "${feature}")
+ break()
+ endif()
+ endforeach()
+ endif()
+
+ # If the build is marked as dirty and the feature doesn't meet its condition,
+ # reset its value to the computed one, which is likely OFF.
+ if(NOT condition AND result)
+ set(result "${computed}")
+ message(WARNING "Resetting 'FEATURE_${feature}' from '${user_value_upper}' to "
+ "'${computed}' because it doesn't meet its condition after reconfiguration. "
+ "Condition expression is: '${condition_expression}'")
+ endif()
endif()
- # Revisit value:
- set(cache "${FEATURE_${feature}}")
- set(booly_values OFF NO FALSE N ON YES TRUE Y)
- if ((cache IN_LIST booly_values) OR (cache GREATER_EQUAL 0))
- set(result "${cache}")
+ set(bool_values OFF NO FALSE N ON YES TRUE Y)
+ if ((result IN_LIST bool_values) OR (result GREATER_EQUAL 0))
+ # All good!
else()
- message(FATAL_ERROR "Sanity check failed: FEATURE_${feature} has invalid value \"${cache}\"!")
+ message(FATAL_ERROR
+ "Sanity check failed: FEATURE_${feature} has invalid value \"${result}\"!")
endif()
+
# Fix-up user-provided values
- set("FEATURE_${feature}" "${cache}" CACHE BOOL "${label}")
+ set("FEATURE_${feature}" "${result}" CACHE BOOL "${label}" FORCE)
else()
# Initial setup:
- if (emit_if)
- set("FEATURE_${feature}" "${calculated}" CACHE BOOL "${label}")
- set(result "${calculated}")
- else()
- set(result OFF)
- endif()
+ set(result "${computed}")
+ set("FEATURE_${feature}" "${result}" CACHE BOOL "${label}")
endif()
set("${resultVar}" "${result}" PARENT_SCOPE)
endfunction()
-macro(qt_feature_set_value feature cache emit_if condition label)
- set(result "${cache}")
+# Saves the final user value to QT_FEATURE_${feature}, after checking that the condition is met.
+macro(qt_feature_check_and_save_internal_value
+ feature saved_user_value condition label conditionExpression)
+ if(${saved_user_value})
+ set(result ON)
+ else()
+ set(result OFF)
+ endif()
- if (NOT (condition) AND (cache))
- message(SEND_ERROR "Feature \"${feature}\": Forcing to \"${cache}\" breaks its condition.")
+ if ((NOT condition) AND result)
+ _qt_internal_dump_expression_values(conditionDump "${conditionExpression}")
+ string(JOIN " " conditionString ${conditionExpression})
+ qt_configure_add_report_error("Feature \"${feature}\": Forcing to \"${result}\" breaks its \
+condition:\n ${conditionString}\nCondition values dump:\n ${conditionDump}\n" RECORD_ON_FEATURE_EVALUATION)
endif()
if (DEFINED "QT_FEATURE_${feature}")
message(FATAL_ERROR "Feature ${feature} is already defined when evaluating configure.cmake features for ${target}.")
endif()
set(QT_FEATURE_${feature} "${result}" CACHE INTERNAL "Qt feature: ${feature}")
+
+ # Add feature to build feature collection
+ list(APPEND QT_KNOWN_FEATURES "${feature}")
+ set(QT_KNOWN_FEATURES "${QT_KNOWN_FEATURES}" CACHE INTERNAL "" FORCE)
endmacro()
+macro(_qt_internal_parse_feature_definition feature)
+ cmake_parse_arguments(arg
+ "PRIVATE;PUBLIC"
+ "LABEL;PURPOSE;SECTION;"
+ "AUTODETECT;CONDITION;ENABLE;DISABLE;EMIT_IF"
+ ${_QT_FEATURE_DEFINITION_${feature}})
+endmacro()
+
+
+# The build system stores 2 CMake cache variables for each feature, to allow detecting value changes
+# during subsequent reconfigurations.
+#
+#
+# `FEATURE_foo` stores the user provided feature value for the current configuration run.
+# It can be set directly by the user.
+#
+# If a value is not provided on initial configuration, the value will be auto-computed based on the
+# various conditions of the feature.
+# TODO: Document the various conditions and how they relate to each other.
+#
+#
+# `QT_FEATURE_foo` stores the value of the feature from the previous configuration run.
+# Its value is updated once with the newest user provided value after some checks are performed.
+#
+# This variable also serves as the main source of truth throughout the build system code to check
+# if the feature is enabled, e.g. if(QT_FEATURE_foo)
+#
+# It is not meant to be set by the user. It is only modified by the build system.
+#
+# Comparing the values of QT_FEATURE_foo and FEATURE_foo, the build system can detect whether
+# the user changed the value for a feature and thus recompute any dependent features.
+#
function(qt_evaluate_feature feature)
- # If the feature was set explicitly by the user to be on or off, in the cache, then
- # there's nothing for us to do.
+ # If the feature was already evaluated as dependency nothing to do here.
if(DEFINED "QT_FEATURE_${feature}")
return()
endif()
@@ -232,13 +376,7 @@ function(qt_evaluate_feature feature)
message(FATAL_ERROR "Attempting to evaluate feature ${feature} but its definition is missing. Either the feature does not exist or a dependency to the module that defines it is missing")
endif()
- cmake_parse_arguments(arg
- "PRIVATE;PUBLIC"
- "LABEL;PURPOSE;SECTION;" "AUTODETECT;CONDITION;ENABLE;DISABLE;EMIT_IF" ${_QT_FEATURE_DEFINITION_${feature}})
-
- if(DEFINED QT_FEATURE_${feature})
- return()
- endif()
+ _qt_internal_parse_feature_definition("${feature}")
if("${arg_ENABLE}" STREQUAL "")
set(arg_ENABLE OFF)
@@ -260,13 +398,14 @@ function(qt_evaluate_feature feature)
qt_evaluate_config_expression(disable_result ${arg_DISABLE})
qt_evaluate_config_expression(enable_result ${arg_ENABLE})
+ qt_evaluate_config_expression(auto_detect ${arg_AUTODETECT})
if(${disable_result})
- set(result OFF)
- elseif((${enable_result}) OR (${arg_AUTODETECT}))
- set(result ${condition})
+ set(computed OFF)
+ elseif((${enable_result}) OR (${auto_detect}))
+ set(computed ${condition})
else()
# feature not auto-detected and not explicitly enabled
- set(result OFF)
+ set(computed OFF)
endif()
if("${arg_EMIT_IF}" STREQUAL "")
@@ -275,20 +414,97 @@ function(qt_evaluate_feature feature)
qt_evaluate_config_expression(emit_if ${arg_EMIT_IF})
endif()
- if (NOT (condition) AND (calculated))
- message(FATAL_ERROR "Sanity check failed: Feature ${feature} is enabled but condition does not hold true.")
+ # Warn about a feature which is not emitted, but the user explicitly provided a value for it.
+ if(NOT emit_if AND DEFINED FEATURE_${feature})
+ set(msg "")
+ string(APPEND msg
+ "Feature ${feature} is insignificant in this configuration, "
+ "ignoring related command line option(s).")
+ qt_configure_add_report_entry(TYPE WARNING MESSAGE "${msg}")
+
+ # Remove the cache entry so that the warning is not persisted and shown on every
+ # reconfiguration.
+ unset(FEATURE_${feature} CACHE)
endif()
- qt_feature_set_cache_value(cache "${feature}" "${emit_if}" "${result}" "${arg_LABEL}")
- qt_feature_set_value("${feature}" "${cache}" "${emit_if}" "${condition}" "${arg_LABEL}")
+ # Only save the user provided value if the feature was emitted.
+ if(emit_if)
+ qt_feature_check_and_save_user_provided_value(
+ saved_user_value
+ "${feature}" "${condition}" "${arg_CONDITION}" "${computed}" "${arg_LABEL}")
+ else()
+ # Make sure the feature internal value is OFF if not emitted.
+ set(saved_user_value OFF)
+ endif()
+
+ qt_feature_check_and_save_internal_value(
+ "${feature}" "${saved_user_value}" "${condition}" "${arg_LABEL}" "${arg_CONDITION}")
# Store each feature's label for summary info.
set(QT_FEATURE_LABEL_${feature} "${arg_LABEL}" CACHE INTERNAL "")
endfunction()
+# Collect feature names that ${feature} depends on, by inspecting the given expression.
+function(_qt_internal_feature_extract_feature_dependencies_from_expression out_var expression)
+ list(LENGTH expression length)
+ math(EXPR length "${length}-1")
+
+ if(length LESS 0)
+ set(${out_var} "" PARENT_SCOPE)
+ return()
+ endif()
+
+ set(deps "")
+
+ foreach(memberIdx RANGE ${length})
+ list(GET expression ${memberIdx} member)
+ if(member MATCHES "^QT_FEATURE_(.+)")
+ list(APPEND deps "${CMAKE_MATCH_1}")
+ endif()
+ endforeach()
+ set(${out_var} "${deps}" PARENT_SCOPE)
+endfunction()
+
+# Collect feature names that ${feature} depends on, based on feature names that appear
+# in the ${feature}'s condition expressions.
+function(_qt_internal_feature_compute_feature_dependencies out_var feature)
+ # Only compute the deps once per feature.
+ get_property(deps_computed GLOBAL PROPERTY _qt_feature_deps_computed_${feature})
+ if(deps_computed)
+ get_property(deps GLOBAL PROPERTY _qt_feature_deps_${feature})
+ set(${out_var} "${deps}" PARENT_SCOPE)
+ return()
+ endif()
+
+ _qt_internal_parse_feature_definition("${feature}")
+
+ set(options_to_check AUTODETECT CONDITION ENABLE DISABLE EMIT_IF)
+ set(deps "")
+
+ # Go through each option that takes condition expressions and collect the feature names.
+ foreach(option ${options_to_check})
+ set(option_value "${arg_${option}}")
+ if(option_value)
+ _qt_internal_feature_extract_feature_dependencies_from_expression(
+ option_deps "${option_value}")
+ if(option_deps)
+ list(APPEND deps ${option_deps})
+ endif()
+ endif()
+ endforeach()
+
+ set_property(GLOBAL PROPERTY _qt_feature_deps_computed_${feature} TRUE)
+ set_property(GLOBAL PROPERTY _qt_feature_deps_${feature} "${deps}")
+ set(${out_var} "${deps}" PARENT_SCOPE)
+endfunction()
+
function(qt_feature_config feature config_var_name)
qt_feature_normalize_name("${feature}" feature)
- qt_parse_all_arguments(arg "qt_feature_config" "NEGATE" "NAME" "" ${ARGN})
+ cmake_parse_arguments(PARSE_ARGV 2 arg
+ "NEGATE"
+ "NAME"
+ "")
+ _qt_internal_validate_all_args_are_parsed(arg)
# Store all the config related info in a unique variable key.
set(key_name "_QT_FEATURE_CONFIG_DEFINITION_${feature}_${config_var_name}")
@@ -348,7 +564,11 @@ endfunction()
function(qt_feature_definition feature name)
qt_feature_normalize_name("${feature}" feature)
- qt_parse_all_arguments(arg "qt_feature_definition" "NEGATE" "VALUE;PREREQUISITE" "" ${ARGN})
+ cmake_parse_arguments(PARSE_ARGV 2 arg
+ "NEGATE"
+ "VALUE;PREREQUISITE"
+ "")
+ _qt_internal_validate_all_args_are_parsed(arg)
# Store all the define related info in a unique variable key.
set(key_name "_QT_FEATURE_DEFINE_DEFINITION_${feature}_${name}")
@@ -375,9 +595,14 @@ function(qt_evaluate_feature_definition key)
set(expected OFF)
endif()
+ set(actual OFF)
+ if(QT_FEATURE_${arg_FEATURE})
+ set(actual ON)
+ endif()
+
set(msg "")
- if(QT_FEATURE_${arg_FEATURE} STREQUAL expected)
+ if(actual STREQUAL expected)
set(indent "")
if(arg_PREREQUISITE)
string(APPEND msg "#if ${arg_PREREQUISITE}\n")
@@ -399,7 +624,11 @@ function(qt_evaluate_feature_definition key)
endfunction()
function(qt_extra_definition name value)
- qt_parse_all_arguments(arg "qt_extra_definition" "PUBLIC;PRIVATE" "" "" ${ARGN})
+ cmake_parse_arguments(PARSE_ARGV 2 arg
+ "PUBLIC;PRIVATE"
+ ""
+ "")
+ _qt_internal_validate_all_args_are_parsed(arg)
if (arg_PUBLIC)
string(APPEND __QtFeature_public_extra "\n#define ${name} ${value}\n")
@@ -412,14 +641,16 @@ function(qt_extra_definition name value)
endfunction()
function(qt_internal_generate_feature_line line feature)
- if (QT_FEATURE_${feature} STREQUAL "ON")
+ string(TOUPPER "${QT_FEATURE_${feature}}" value)
+ if (value STREQUAL "ON")
set(line "#define QT_FEATURE_${feature} 1\n\n" PARENT_SCOPE)
- elseif(QT_FEATURE_${feature} STREQUAL "OFF")
+ elseif(value STREQUAL "OFF")
set(line "#define QT_FEATURE_${feature} -1\n\n" PARENT_SCOPE)
- elseif(QT_FEATURE_${feature} STREQUAL "UNSET")
+ elseif(value STREQUAL "UNSET")
set(line "#define QT_FEATURE_${feature} 0\n\n" PARENT_SCOPE)
else()
- message(FATAL_ERROR "${feature} has unexpected value \"${QT_FEATURE_${feature}}\"!")
+ message(FATAL_ERROR "${feature} has unexpected value \"${QT_FEATURE_${feature}}\"! "
+ "Valid values are ON, OFF and UNSET.")
endif()
endfunction()
@@ -447,6 +678,17 @@ function(qt_feature_evaluate_features list_of_paths)
qt_feature_module_end(ONLY_EVALUATE_FEATURES)
endfunction()
+function(qt_feature_record_summary_entries list_of_paths)
+ # Clean up any stale state just in case.
+ qt_feature_unset_state_vars()
+
+ set(__QtFeature_only_record_summary_entries TRUE)
+ foreach(path ${list_of_paths})
+ include("${path}")
+ endforeach()
+ qt_feature_unset_state_vars()
+endfunction()
+
function(qt_feature_module_end)
set(flags ONLY_EVALUATE_FEATURES)
set(options OUT_VAR_PREFIX)
@@ -469,10 +711,10 @@ function(qt_feature_module_end)
# Evaluate custom cache assignments.
foreach(cache_var_name ${__QtFeature_custom_enabled_cache_variables})
- set(${cache_var_name} ON CACHE BOOL "Force enabled by platform." FORCE)
+ set(${cache_var_name} ON CACHE BOOL "Force enabled by platform requirements." FORCE)
endforeach()
foreach(cache_var_name ${__QtFeature_custom_disabled_cache_variables})
- set(${cache_var_name} OFF CACHE BOOL "Force disabled by platform." FORCE)
+ set(${cache_var_name} OFF CACHE BOOL "Force disabled by platform requirements." FORCE)
endforeach()
set(enabled_public_features "")
@@ -520,29 +762,13 @@ function(qt_feature_module_end)
)
endif()
- # Extra header injections which have to have forwarding headers created by
- # qt_install_injections.
- # Skip creating forwarding headers if qt_feature_module_begin was called with NO_MODULE, aka
- # there is no include/<module_name> so there's no place to put the forwarding headers.
- if(__QtFeature_library)
- set(injections "")
- qt_compute_injection_forwarding_header("${__QtFeature_library}"
- SOURCE "${__QtFeature_public_file}"
- OUT_VAR injections)
- qt_compute_injection_forwarding_header("${__QtFeature_library}"
- SOURCE "${__QtFeature_private_file}" PRIVATE
- OUT_VAR injections)
-
- set(${arg_OUT_VAR_PREFIX}extra_library_injections ${injections} PARENT_SCOPE)
- endif()
-
if (NOT ("${target}" STREQUAL "NO_MODULE") AND NOT arg_ONLY_EVALUATE_FEATURES)
get_target_property(targetType "${target}" TYPE)
if("${targetType}" STREQUAL "INTERFACE_LIBRARY")
set(propertyPrefix "INTERFACE_")
else()
set(propertyPrefix "")
- set_property(TARGET "${target}" APPEND PROPERTY EXPORT_PROPERTIES "QT_ENABLED_PUBLIC_FEATURES;QT_DISABLED_PUBLIC_FEATURES;QT_ENABLED_PRIVATE_FEATURES;QT_DISABLED_PRIVATE_FEATURES;MODULE_PLUGIN_TYPES;QT_PLUGINS;QT_QMAKE_PUBLIC_CONFIG;QT_QMAKE_PRIVATE_CONFIG;QT_QMAKE_PUBLIC_QT_CONFIG")
+ set_property(TARGET "${target}" APPEND PROPERTY EXPORT_PROPERTIES "QT_ENABLED_PUBLIC_FEATURES;QT_DISABLED_PUBLIC_FEATURES;QT_ENABLED_PRIVATE_FEATURES;QT_DISABLED_PRIVATE_FEATURES;QT_QMAKE_PUBLIC_CONFIG;QT_QMAKE_PRIVATE_CONFIG;QT_QMAKE_PUBLIC_QT_CONFIG")
endif()
foreach(visibility public private)
string(TOUPPER "${visibility}" capitalVisibility)
@@ -585,6 +811,10 @@ function(qt_feature_module_end)
qt_feature_copy_global_config_features_to_core(${target})
endif()
+ qt_feature_unset_state_vars()
+endfunction()
+
+macro(qt_feature_unset_state_vars)
unset(__QtFeature_library PARENT_SCOPE)
unset(__QtFeature_public_features PARENT_SCOPE)
unset(__QtFeature_private_features PARENT_SCOPE)
@@ -600,7 +830,8 @@ function(qt_feature_module_end)
unset(__QtFeature_custom_enabled_features PARENT_SCOPE)
unset(__QtFeature_custom_disabled_features PARENT_SCOPE)
unset(__QtFeature_only_evaluate_features PARENT_SCOPE)
-endfunction()
+ unset(__QtFeature_only_record_summary_entries PARENT_SCOPE)
+endmacro()
function(qt_feature_copy_global_config_features_to_core target)
# CMake doesn't support setting custom properties on exported INTERFACE libraries
@@ -639,13 +870,47 @@ function(qt_feature_copy_global_config_features_to_core target)
endif()
endfunction()
+function(qt_internal_detect_dirty_features)
+ # We need to clean up QT_FEATURE_*, but only once per configuration cycle
+ get_property(qt_feature_clean GLOBAL PROPERTY _qt_feature_clean)
+ if(NOT qt_feature_clean AND NOT QT_NO_FEATURE_AUTO_RESET)
+ message(STATUS "Checking for feature set changes")
+ set_property(GLOBAL PROPERTY _qt_feature_clean TRUE)
+ foreach(feature ${QT_KNOWN_FEATURES})
+ if(DEFINED "FEATURE_${feature}" AND
+ NOT "${QT_FEATURE_${feature}}" STREQUAL "${FEATURE_${feature}}")
+ message(" '${feature}' was changed from ${QT_FEATURE_${feature}} "
+ "to ${FEATURE_${feature}}")
+ set(dirty_build TRUE)
+ set_property(GLOBAL APPEND PROPERTY _qt_dirty_features "${feature}")
+ endif()
+ unset("QT_FEATURE_${feature}" CACHE)
+ endforeach()
+
+ set(QT_KNOWN_FEATURES "" CACHE INTERNAL "" FORCE)
+
+ if(dirty_build)
+ set_property(GLOBAL PROPERTY _qt_dirty_build TRUE)
+ message(WARNING
+ "Due to detected feature set changes, dependent features "
+ "will be re-computed automatically. This might cause a lot of files to be rebuilt. "
+ "To disable this behavior, configure with -DQT_NO_FEATURE_AUTO_RESET=ON")
+ endif()
+ endif()
+endfunction()
+
+# Builds either a string of source code or a whole project to determine whether the build is
+# successful.
+#
+# Sets a TEST_${name}_OUTPUT variable with the build output, to the scope of the calling function.
+# Sets a TEST_${name} cache variable to either TRUE or FALSE if the build is successful or not.
function(qt_config_compile_test name)
if(DEFINED "TEST_${name}")
return()
endif()
cmake_parse_arguments(arg "" "LABEL;PROJECT_PATH;C_STANDARD;CXX_STANDARD"
- "COMPILE_OPTIONS;LIBRARIES;CODE;PACKAGES" ${ARGN})
+ "COMPILE_OPTIONS;LIBRARIES;CODE;PACKAGES;CMAKE_FLAGS" ${ARGN})
if(arg_PROJECT_PATH)
message(STATUS "Performing Test ${arg_LABEL}")
@@ -657,7 +922,19 @@ function(qt_config_compile_test name)
# If the repo has its own cmake modules, include those in the module path, so that various
# find_package calls work.
if(EXISTS "${PROJECT_SOURCE_DIR}/cmake")
- list(APPEND flags "-DCMAKE_MODULE_PATH:STRING=${PROJECT_SOURCE_DIR}/cmake")
+ set(must_append_module_path_flag TRUE)
+ set(flags_copy "${flags}")
+ set(flags)
+ foreach(flag IN LISTS flags_copy)
+ if(flag MATCHES "^-DCMAKE_MODULE_PATH:STRING=")
+ set(must_append_module_path_flag FALSE)
+ set(flag "${flag}\\;${PROJECT_SOURCE_DIR}/cmake")
+ endif()
+ list(APPEND flags "${flag}")
+ endforeach()
+ if(must_append_module_path_flag)
+ list(APPEND flags "-DCMAKE_MODULE_PATH:STRING=${PROJECT_SOURCE_DIR}/cmake")
+ endif()
endif()
# Pass which packages need to be found.
@@ -724,8 +1001,36 @@ function(qt_config_compile_test name)
endif()
endif()
- try_compile(HAVE_${name} "${CMAKE_BINARY_DIR}/config.tests/${name}" "${arg_PROJECT_PATH}"
- "${name}" CMAKE_FLAGS ${flags})
+ # Pass override values for CMAKE_SYSTEM_{PREFIX|FRAMEWORK}_PATH.
+ if(DEFINED QT_CMAKE_SYSTEM_PREFIX_PATH_BACKUP)
+ set(path_list ${CMAKE_SYSTEM_PREFIX_PATH})
+ string(REPLACE ";" "\\;" path_list "${path_list}")
+ list(APPEND flags "-DQT_CONFIG_COMPILE_TEST_CMAKE_SYSTEM_PREFIX_PATH=${path_list}")
+ endif()
+ if(DEFINED QT_CMAKE_SYSTEM_FRAMEWORK_PATH_BACKUP)
+ set(path_list ${CMAKE_SYSTEM_FRAMEWORK_PATH})
+ string(REPLACE ";" "\\;" path_list "${path_list}")
+ list(APPEND flags "-DQT_CONFIG_COMPILE_TEST_CMAKE_SYSTEM_FRAMEWORK_PATH=${path_list}")
+ endif()
+
+ if(NOT arg_CMAKE_FLAGS)
+ set(arg_CMAKE_FLAGS "")
+ endif()
+
+ # CI passes the project dir of the Qt repository as absolute path without drive letter:
+ # \Users\qt\work\qt\qtbase
+ # Ensure that arg_PROJECT_PATH is an absolute path with drive letter:
+ # C:/Users/qt/work/qt/qtbase
+ # This works around CMake upstream issue #22534.
+ if(CMAKE_HOST_WIN32)
+ get_filename_component(arg_PROJECT_PATH "${arg_PROJECT_PATH}" REALPATH)
+ endif()
+
+ try_compile(
+ HAVE_${name} "${CMAKE_BINARY_DIR}/config.tests/${name}" "${arg_PROJECT_PATH}" "${name}"
+ CMAKE_FLAGS ${flags} ${arg_CMAKE_FLAGS}
+ OUTPUT_VARIABLE try_compile_output
+ )
if(${HAVE_${name}})
set(status_label "Success")
@@ -740,6 +1045,7 @@ function(qt_config_compile_test name)
# fail instead of cmake abort later via CMAKE_REQUIRED_LIBRARIES.
string(FIND "${library}" "::" cmake_target_namespace_separator)
if(NOT cmake_target_namespace_separator EQUAL -1)
+ message(STATUS "Performing Test ${arg_LABEL} - Failed because ${library} not found")
set(HAVE_${name} FALSE)
break()
endif()
@@ -748,19 +1054,31 @@ function(qt_config_compile_test name)
if(NOT DEFINED HAVE_${name})
set(_save_CMAKE_C_STANDARD "${CMAKE_C_STANDARD}")
+ set(_save_CMAKE_C_STANDARD_REQUIRED "${CMAKE_C_STANDARD_REQUIRED}")
set(_save_CMAKE_CXX_STANDARD "${CMAKE_CXX_STANDARD}")
+ set(_save_CMAKE_CXX_STANDARD_REQUIRED "${CMAKE_CXX_STANDARD_REQUIRED}")
set(_save_CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS}")
+ set(_save_CMAKE_TRY_COMPILE_PLATFORM_VARIABLES "${CMAKE_TRY_COMPILE_PLATFORM_VARIABLES}")
if(arg_C_STANDARD)
set(CMAKE_C_STANDARD "${arg_C_STANDARD}")
+ set(CMAKE_C_STANDARD_REQUIRED OFF)
endif()
if(arg_CXX_STANDARD)
- set(CMAKE_CXX_STANDARD "${arg_CXX_STANDARD}")
+ if(${arg_CXX_STANDARD} LESS 23 OR ${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.20")
+ set(CMAKE_CXX_STANDARD "${arg_CXX_STANDARD}")
+ set(CMAKE_CXX_STANDARD_REQUIRED OFF)
+ endif()
endif()
set(CMAKE_REQUIRED_FLAGS ${arg_COMPILE_OPTIONS})
+ # Pass -stdlib=libc++ on if necessary
+ if (QT_FEATURE_stdlib_libcpp)
+ list(APPEND CMAKE_REQUIRED_FLAGS "-stdlib=libc++")
+ endif()
+
# For MSVC we need to explicitly pass -Zc:__cplusplus to get correct __cplusplus
# define values. According to common/msvc-version.conf the flag is supported starting
# with 1913.
@@ -771,17 +1089,38 @@ function(qt_config_compile_test name)
list(APPEND CMAKE_REQUIRED_FLAGS "-Zc:__cplusplus")
endif()
+ # Let CMake load our custom platform modules.
+ if(NOT QT_AVOID_CUSTOM_PLATFORM_MODULES)
+ list(APPEND CMAKE_TRY_COMPILE_PLATFORM_VARIABLES CMAKE_MODULE_PATH)
+ endif()
+
set(_save_CMAKE_REQUIRED_LIBRARIES "${CMAKE_REQUIRED_LIBRARIES}")
set(CMAKE_REQUIRED_LIBRARIES "${arg_LIBRARIES}")
- check_cxx_source_compiles("${arg_UNPARSED_ARGUMENTS} ${arg_CODE}" HAVE_${name})
+
+ # OUTPUT_VARIABLE is an internal undocumented variable of check_cxx_source_compiles
+ # since 3.23. Allow an opt out in case this breaks in the future.
+ set(try_compile_output "")
+ set(output_var "")
+ if(CMAKE_VERSION VERSION_GREATER_EQUAL "3.23"
+ AND NOT QT_INTERNAL_NO_TRY_COMPILE_OUTPUT_VARIABLE)
+ set(output_var OUTPUT_VARIABLE try_compile_output)
+ endif()
+
+ check_cxx_source_compiles(
+ "${arg_UNPARSED_ARGUMENTS} ${arg_CODE}" HAVE_${name} ${output_var}
+ )
set(CMAKE_REQUIRED_LIBRARIES "${_save_CMAKE_REQUIRED_LIBRARIES}")
set(CMAKE_C_STANDARD "${_save_CMAKE_C_STANDARD}")
+ set(CMAKE_C_STANDARD_REQUIRED "${_save_CMAKE_C_STANDARD_REQUIRED}")
set(CMAKE_CXX_STANDARD "${_save_CMAKE_CXX_STANDARD}")
+ set(CMAKE_CXX_STANDARD_REQUIRED "${_save_CMAKE_CXX_STANDARD_REQUIRED}")
set(CMAKE_REQUIRED_FLAGS "${_save_CMAKE_REQUIRED_FLAGS}")
+ set(CMAKE_TRY_COMPILE_PLATFORM_VARIABLES "${_save_CMAKE_TRY_COMPILE_PLATFORM_VARIABLES}")
endif()
endif()
+ set(TEST_${name}_OUTPUT "${try_compile_output}" PARENT_SCOPE)
set(TEST_${name} "${HAVE_${name}}" CACHE INTERNAL "${arg_LABEL}")
endfunction()
@@ -792,6 +1131,18 @@ function(qt_get_platform_try_compile_vars out_var)
# Use the regular variables that are used for source-based try_compile() calls.
set(flags "${CMAKE_TRY_COMPILE_PLATFORM_VARIABLES}")
+ # Pass custom flags.
+ list(APPEND flags "CMAKE_C_FLAGS")
+ list(APPEND flags "CMAKE_C_FLAGS_DEBUG")
+ list(APPEND flags "CMAKE_C_FLAGS_RELEASE")
+ list(APPEND flags "CMAKE_C_FLAGS_RELWITHDEBINFO")
+ list(APPEND flags "CMAKE_CXX_FLAGS")
+ list(APPEND flags "CMAKE_CXX_FLAGS_DEBUG")
+ list(APPEND flags "CMAKE_CXX_FLAGS_RELEASE")
+ list(APPEND flags "CMAKE_CXX_FLAGS_RELWITHDEBINFO")
+ list(APPEND flags "CMAKE_OBJCOPY")
+ list(APPEND flags "CMAKE_EXE_LINKER_FLAGS")
+
# Pass toolchain files.
if(CMAKE_TOOLCHAIN_FILE)
list(APPEND flags "CMAKE_TOOLCHAIN_FILE")
@@ -802,7 +1153,18 @@ function(qt_get_platform_try_compile_vars out_var)
# Pass language standard flags.
list(APPEND flags "CMAKE_C_STANDARD")
+ list(APPEND flags "CMAKE_C_STANDARD_REQUIRED")
list(APPEND flags "CMAKE_CXX_STANDARD")
+ list(APPEND flags "CMAKE_CXX_STANDARD_REQUIRED")
+
+ # Pass -stdlib=libc++ on if necessary
+ if (QT_FEATURE_stdlib_libcpp)
+ if(CMAKE_CXX_FLAGS)
+ string(APPEND CMAKE_CXX_FLAGS " -stdlib=libc++")
+ else()
+ set(CMAKE_CXX_FLAGS "-stdlib=libc++")
+ endif()
+ endif()
# Assemble the list with regular options.
set(flags_cmd_line "")
@@ -812,12 +1174,16 @@ function(qt_get_platform_try_compile_vars out_var)
endif()
endforeach()
+ # Let CMake load our custom platform modules.
+ if(NOT QT_AVOID_CUSTOM_PLATFORM_MODULES)
+ list(APPEND flags_cmd_line "-DCMAKE_MODULE_PATH:STRING=${QT_CMAKE_DIR}/platforms")
+ endif()
+
# Pass darwin specific options.
# The architectures need to be passed explicitly to project-based try_compile calls even on
# macOS, so that arm64 compilation works on Apple silicon.
- if(CMAKE_OSX_ARCHITECTURES)
- list(GET CMAKE_OSX_ARCHITECTURES 0 osx_first_arch)
-
+ qt_internal_get_first_osx_arch(osx_first_arch)
+ if(osx_first_arch)
# Do what qmake does, aka when doing a simulator_and_device build, build the
# target architecture test only with the first given architecture, which should be the
# device architecture, aka some variation of "arm" (armv7, arm64).
@@ -826,14 +1192,27 @@ function(qt_get_platform_try_compile_vars out_var)
if(UIKIT)
# Specify the sysroot, but only if not doing a simulator_and_device build.
# So keep the sysroot empty for simulator_and_device builds.
- if(QT_UIKIT_SDK)
- list(APPEND flags_cmd_line "-DCMAKE_OSX_SYSROOT:STRING=${QT_UIKIT_SDK}")
+ if(QT_APPLE_SDK)
+ list(APPEND flags_cmd_line "-DCMAKE_OSX_SYSROOT:STRING=${QT_APPLE_SDK}")
endif()
endif()
+ if(QT_NO_USE_FIND_PACKAGE_SYSTEM_ENVIRONMENT_PATH)
+ list(APPEND flags_cmd_line "-DCMAKE_FIND_USE_SYSTEM_ENVIRONMENT_PATH:BOOL=OFF")
+ endif()
set("${out_var}" "${flags_cmd_line}" PARENT_SCOPE)
endfunction()
+# Set out_var to the first value of CMAKE_OSX_ARCHITECTURES.
+# Sets an empty string if no architecture is present.
+function(qt_internal_get_first_osx_arch out_var)
+ set(value "")
+ if(CMAKE_OSX_ARCHITECTURES)
+ list(GET CMAKE_OSX_ARCHITECTURES 0 value)
+ endif()
+ set(${out_var} "${value}" PARENT_SCOPE)
+endfunction()
+
function(qt_config_compile_test_x86simd extension label)
if (DEFINED TEST_X86SIMD_${extension})
return()
@@ -844,7 +1223,7 @@ function(qt_config_compile_test_x86simd extension label)
qt_get_platform_try_compile_vars(platform_try_compile_vars)
list(APPEND flags ${platform_try_compile_vars})
- message(STATUS "Performing SIMD Test ${label}")
+ message(STATUS "Performing Test ${label} intrinsics")
try_compile("TEST_X86SIMD_${extension}"
"${CMAKE_CURRENT_BINARY_DIR}/config.tests/x86_simd_${extension}"
"${CMAKE_CURRENT_SOURCE_DIR}/config.tests/x86_simd"
@@ -855,12 +1234,12 @@ function(qt_config_compile_test_x86simd extension label)
else()
set(status_label "Failed")
endif()
- message(STATUS "Performing SIMD Test ${label} - ${status_label}")
+ message(STATUS "Performing Test ${label} intrinsics - ${status_label}")
set(TEST_subarch_${extension} "${TEST_X86SIMD_${extension}}" CACHE INTERNAL "${label}")
endfunction()
function(qt_config_compile_test_machine_tuple label)
- if(DEFINED TEST_MACHINE_TUPLE OR NOT LINUX OR ANDROID)
+ if(DEFINED TEST_MACHINE_TUPLE OR NOT (LINUX OR HURD) OR ANDROID)
return()
endif()
@@ -878,6 +1257,130 @@ function(qt_config_compile_test_machine_tuple label)
set(TEST_machine_tuple "${output}" CACHE INTERNAL "${label}")
endfunction()
+function(qt_config_compiler_supports_flag_test name)
+ if(DEFINED "TEST_${name}")
+ return()
+ endif()
+
+ cmake_parse_arguments(arg "" "LABEL;FLAG" "" ${ARGN})
+ check_cxx_compiler_flag("${arg_FLAG}" TEST_${name})
+ set(TEST_${name} "${TEST_${name}}" CACHE INTERNAL "${label}")
+endfunction()
+
+# gcc expects -fuse-ld=mold (no absolute path can be given) (gcc >= 12.1)
+# or an 'ld' symlink to 'mold' in a dir that is passed via -B flag (gcc < 12.1)
+#
+# clang expects -fuse-ld=mold
+# or -fuse-ld=<mold-abs-path>
+# or --ldpath=<mold-abs-path> (clang >= 12)
+# https://github.com/rui314/mold/#how-to-use
+# TODO: In the gcc < 12.1 case, the qt_internal_check_if_linker_is_available(mold) check will
+# always return TRUE because gcc will not error out if it is given a -B flag pointing to an
+# invalid dir, as well as when the the symlink to the linker in the -B dir is not actually
+# a valid linker.
+# It would be nice to handle that case in a better way, but it's not that important
+# given that gcc > 12.1 now supports -fuse-ld=mold
+# NOTE: In comparison to clang, in the gcc < 12.1 case, we pass the full path to where mold is
+# and that is recorded in PlatformCommonInternal's INTERFACE_LINK_OPTIONS target.
+# Moving such a Qt to a different machine and trying to build another repo won't
+# work because the recorded path will be invalid. This is not a problem with
+# the gcc >= 12.1 case
+function(qt_internal_get_mold_linker_flags out_var)
+ cmake_parse_arguments(PARSE_ARGV 1 arg "ERROR_IF_EMPTY" "" "")
+
+ find_program(QT_INTERNAL_LINKER_MOLD mold)
+
+ set(flag "")
+ if(QT_INTERNAL_LINKER_MOLD)
+ if(GCC)
+ if(CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL "12.1")
+ set(flag "-fuse-ld=mold")
+ else()
+ set(mold_linker_dir "${CMAKE_CURRENT_BINARY_DIR}/.qt_linker")
+ set(mold_linker_path "${mold_linker_dir}/ld")
+ if(NOT EXISTS "${mold_linker_dir}")
+ file(MAKE_DIRECTORY "${mold_linker_dir}")
+ endif()
+ if(NOT EXISTS "${mold_linker_path}")
+ file(CREATE_LINK
+ "${QT_INTERNAL_LINKER_MOLD}"
+ "${mold_linker_path}"
+ SYMBOLIC)
+ endif()
+ set(flag "-B${mold_linker_dir}")
+ endif()
+ elseif(CLANG)
+ if(CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL "12")
+ set(flag "--ld-path=mold")
+ else()
+ set(flag "-fuse-ld=mold")
+ endif()
+ endif()
+ endif()
+ if(arg_ERROR_IS_EMPTY AND NOT flag)
+ message(FATAL_ERROR "Could not determine the flags to use the mold linker.")
+ endif()
+ set(${out_var} "${flag}" PARENT_SCOPE)
+endfunction()
+
+function(qt_internal_get_active_linker_flags out_var)
+ set(flags "")
+ if(GCC OR CLANG)
+ if(QT_FEATURE_use_gold_linker)
+ list(APPEND flags "-fuse-ld=gold")
+ elseif(QT_FEATURE_use_bfd_linker)
+ list(APPEND flags "-fuse-ld=bfd")
+ elseif(QT_FEATURE_use_lld_linker)
+ list(APPEND flags "-fuse-ld=lld")
+ elseif(QT_FEATURE_use_mold_linker)
+ qt_internal_get_mold_linker_flags(mold_flags ERROR_IF_EMPTY)
+ list(APPEND flags "${mold_flags}")
+ endif()
+ endif()
+ set(${out_var} "${flags}" PARENT_SCOPE)
+endfunction()
+
+function(qt_internal_check_if_linker_is_available name)
+ if(DEFINED "TEST_${name}")
+ return()
+ endif()
+
+ cmake_parse_arguments(arg "" "LABEL;FLAG" "" ${ARGN})
+ set(flags "${arg_FLAG}")
+
+ set(CMAKE_REQUIRED_LINK_OPTIONS ${flags})
+ check_cxx_source_compiles("int main() { return 0; }" TEST_${name})
+ set(TEST_${name} "${TEST_${name}}" CACHE INTERNAL "${label}")
+endfunction()
+
+function(qt_config_linker_supports_flag_test name)
+ if(DEFINED "TEST_${name}")
+ return()
+ endif()
+
+ cmake_parse_arguments(arg "" "LABEL;FLAG" "" ${ARGN})
+ if(GCC OR CLANG)
+ set(flags "-Wl,--fatal-warnings,${arg_FLAG}")
+ elseif(MSVC)
+ set(flags "${arg_FLAG}")
+ else()
+ # We don't know how to pass linker options in a way that
+ # it reliably fails, so assume the detection failed.
+ set(TEST_${name} "0" CACHE INTERNAL "${label}")
+ return()
+ endif()
+
+ # Pass the linker that the main project uses to the compile test.
+ qt_internal_get_active_linker_flags(linker_flags)
+ if(linker_flags)
+ list(PREPEND flags ${linker_flags})
+ endif()
+
+ set(CMAKE_REQUIRED_LINK_OPTIONS ${flags})
+ check_cxx_source_compiles("int main() { return 0; }" TEST_${name})
+ set(TEST_${name} "${TEST_${name}}" CACHE INTERNAL "${label}")
+endfunction()
+
function(qt_make_features_available target)
if(NOT "${target}" MATCHES "^${QT_CMAKE_EXPORT_NAMESPACE}::[a-zA-Z0-9_-]*$")
message(FATAL_ERROR "${target} does not match ${QT_CMAKE_EXPORT_NAMESPACE}::[a-zA-Z0-9_-]*. INVALID NAME.")
@@ -901,7 +1404,15 @@ function(qt_make_features_available target)
endif()
foreach(feature IN ITEMS ${features})
if (DEFINED "QT_FEATURE_${feature}" AND NOT "${QT_FEATURE_${feature}}" STREQUAL "${value}")
- message(FATAL_ERROR "Feature ${feature} is already defined and has a different value when importing features from ${target}.")
+ message(WARNING
+ "This project was initially configured with the Qt feature \"${feature}\" "
+ "set to \"${QT_FEATURE_${feature}}\". While loading the "
+ "\"${target}\" package, the value of the feature "
+ "has changed to \"${value}\". That might cause a project rebuild due to "
+ "updated C++ headers. \n"
+ "In case of build issues, consider removing the CMakeCache.txt file and "
+ "reconfiguring the project."
+ )
endif()
set(QT_FEATURE_${feature} "${value}" CACHE INTERNAL "Qt feature: ${feature} (from target ${target})")
endforeach()
@@ -909,5 +1420,3 @@ function(qt_make_features_available target)
endforeach()
endforeach()
endfunction()
-
-
diff --git a/cmake/QtFeatureCommon.cmake b/cmake/QtFeatureCommon.cmake
new file mode 100644
index 0000000000..9b49d4fcac
--- /dev/null
+++ b/cmake/QtFeatureCommon.cmake
@@ -0,0 +1,12 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+function(qt_feature_normalize_name name out_var)
+ # Normalize the feature name to something CMake can deal with.
+ if(name MATCHES "c\\+\\+")
+ string(REGEX REPLACE "[^a-zA-Z0-9_]" "x" name "${name}")
+ else()
+ string(REGEX REPLACE "[^a-zA-Z0-9_]" "_" name "${name}")
+ endif()
+ set(${out_var} "${name}" PARENT_SCOPE)
+endfunction()
diff --git a/cmake/QtFindPackageHelpers.cmake b/cmake/QtFindPackageHelpers.cmake
new file mode 100644
index 0000000000..dd10bde75a
--- /dev/null
+++ b/cmake/QtFindPackageHelpers.cmake
@@ -0,0 +1,572 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+# This function recursively walks transitive link libraries of the given target
+# and promotes those targets to be IMPORTED_GLOBAL if they are not.
+#
+# This is required for .prl file generation in top-level builds, to make sure that imported 3rd
+# party library targets in any repo are made global, so there are no scoping issues.
+#
+# Only works if called from qt_find_package(), because the promotion needs to happen in the same
+# directory scope where the imported target is first created.
+#
+# Uses __qt_internal_walk_libs.
+function(qt_find_package_promote_targets_to_global_scope target)
+ __qt_internal_walk_libs("${target}" _discarded_out_var _discarded_out_var_2
+ "qt_find_package_targets_dict" "promote_global")
+endfunction()
+
+# As an optimization when using -developer-build, qt_find_package records which
+# packages were found during the initial configuration. Then on subsequent
+# reconfigurations it skips looking for packages that were not found on the
+# initial run.
+# For the build system to pick up a newly added qt_find_package call, you need to:
+# - Start with a clean build dir
+# - Or remove the <builddir>/CMakeCache.txt file and configure from scratch
+# - Or remove the QT_INTERNAL_PREVIOUSLY_FOUND_PACKAGES cache variable (by
+# editing CMakeCache.txt) and reconfigure.
+macro(qt_find_package)
+ # Get the target names we expect to be provided by the package.
+ set(find_package_options CONFIG NO_MODULE MODULE REQUIRED)
+ set(options ${find_package_options} MARK_OPTIONAL)
+ set(oneValueArgs MODULE_NAME QMAKE_LIB)
+ set(multiValueArgs PROVIDED_TARGETS COMPONENTS OPTIONAL_COMPONENTS)
+ cmake_parse_arguments(arg "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
+
+ # If some Qt internal project calls qt_find_package(WrapFreeType), but WrapFreeType was already
+ # found as part of a find_dependency() call from a ModuleDependencies.cmake file (or similar),
+ # and the provided target is also found, that means this might have been an unnecessary
+ # qt_find_package() call, because the dependency was already found via some other transitive
+ # dependency. Return early, so that CMake doesn't fail with an error with trying to promote the
+ # targets to be global. This behavior is not enabled by default, because there are cases
+ # when a regular find_package() (non qt_) can find a package (Freetype -> PNG), and a subsequent
+ # qt_find_package(PNG PROVIDED_TARGET PNG::PNG) still needs to succeed and register the provided
+ # targets. To enable the debugging behavior, set QT_DEBUG_QT_FIND_PACKAGE to 1.
+ set(_qt_find_package_skip_find_package FALSE)
+
+ # Skip looking for packages that were not found on initial configuration, because they likely
+ # won't be found again, and only waste configuration time.
+ # Speeds up reconfiguration configuration for certain platforms and repos.
+ # Due to this behavior being different from what general CMake projects expect, it is only
+ # done for -developer-builds.
+ if(QT_INTERNAL_PREVIOUSLY_FOUND_PACKAGES AND
+ NOT "${ARGV0}" IN_LIST QT_INTERNAL_PREVIOUSLY_FOUND_PACKAGES
+ AND "${ARGV0}" IN_LIST QT_INTERNAL_PREVIOUSLY_SEARCHED_PACKAGES)
+ set(_qt_find_package_skip_find_package TRUE)
+ endif()
+
+ set_property(GLOBAL APPEND PROPERTY _qt_previously_searched_packages "${ARGV0}")
+
+ if(QT_DEBUG_QT_FIND_PACKAGE AND ${ARGV0}_FOUND AND arg_PROVIDED_TARGETS)
+ set(_qt_find_package_skip_find_package TRUE)
+ foreach(qt_find_package_target_name ${arg_PROVIDED_TARGETS})
+ if(NOT TARGET ${qt_find_package_target_name})
+ set(_qt_find_package_skip_find_package FALSE)
+ endif()
+ endforeach()
+
+ if(_qt_find_package_skip_find_package)
+ message(AUTHOR_WARNING "qt_find_package(${ARGV0}) called even though the package "
+ "was already found. Consider removing the call.")
+ endif()
+ endif()
+
+ # When configure.cmake is included only to record summary entries, there's no point in looking
+ # for the packages.
+ if(__QtFeature_only_record_summary_entries)
+ set(_qt_find_package_skip_find_package TRUE)
+ endif()
+
+ # Get the version if specified.
+ set(package_version "")
+ if(${ARGC} GREATER_EQUAL 2)
+ if(${ARGV1} MATCHES "^[0-9\.]+$")
+ set(package_version "${ARGV1}")
+ endif()
+ endif()
+
+ if(arg_COMPONENTS)
+ # Re-append components to forward them.
+ list(APPEND arg_UNPARSED_ARGUMENTS "COMPONENTS;${arg_COMPONENTS}")
+ endif()
+ if(arg_OPTIONAL_COMPONENTS)
+ # Re-append optional components to forward them.
+ list(APPEND arg_UNPARSED_ARGUMENTS "OPTIONAL_COMPONENTS;${arg_OPTIONAL_COMPONENTS}")
+ endif()
+
+ # Don't look for packages in PATH if requested to.
+ if(QT_NO_USE_FIND_PACKAGE_SYSTEM_ENVIRONMENT_PATH)
+ set(_qt_find_package_use_system_env_backup "${CMAKE_FIND_USE_SYSTEM_ENVIRONMENT_PATH}")
+ set(CMAKE_FIND_USE_SYSTEM_ENVIRONMENT_PATH "OFF")
+ endif()
+
+ if(NOT (arg_CONFIG OR arg_NO_MODULE OR arg_MODULE) AND NOT _qt_find_package_skip_find_package)
+ # Try to find a config package first in quiet mode
+ set(config_package_arg ${arg_UNPARSED_ARGUMENTS})
+ list(APPEND config_package_arg "CONFIG;QUIET")
+ find_package(${config_package_arg})
+
+ # Double check that in config mode the targets become visible. Sometimes
+ # only the module mode creates the targets. For example with vcpkg, the sqlite
+ # package provides sqlite3-config.cmake, which offers multi-config targets but
+ # in their own way. CMake has FindSQLite3.cmake and with the original
+ # qt_find_package(SQLite3) call it is our intention to use the cmake package
+ # in module mode.
+ unset(_qt_any_target_found)
+ unset(_qt_should_unset_found_var)
+ if(${ARGV0}_FOUND AND arg_PROVIDED_TARGETS)
+ foreach(expected_target ${arg_PROVIDED_TARGETS})
+ if (TARGET ${expected_target})
+ set(_qt_any_target_found TRUE)
+ break()
+ endif()
+ endforeach()
+ if(NOT _qt_any_target_found)
+ set(_qt_should_unset_found_var TRUE)
+ endif()
+ endif()
+ # If we consider the package not to be found, make sure to unset both regular
+ # and CACHE vars, otherwise CMP0126 set to NEW might cause issues with
+ # packages not being found correctly.
+ if(NOT ${ARGV0}_FOUND OR _qt_should_unset_found_var)
+ unset(${ARGV0}_FOUND)
+ unset(${ARGV0}_FOUND CACHE)
+
+ # Unset the NOTFOUND ${package}_DIR var that might have been set by the previous
+ # find_package call, to get rid of "not found" messages in the feature summary
+ # if the package is found by the next find_package call.
+ if(DEFINED CACHE{${ARGV0}_DIR} AND NOT ${ARGV0}_DIR)
+ unset(${ARGV0}_DIR CACHE)
+ endif()
+ endif()
+ endif()
+
+ # Ensure the options are back in the original unparsed arguments
+ foreach(opt IN LISTS find_package_options)
+ if(arg_${opt})
+ list(APPEND arg_UNPARSED_ARGUMENTS ${opt})
+ endif()
+ endforeach()
+
+ # TODO: Handle packages with components where a previous component is already found.
+ # E.g. find_package(Qt6 COMPONENTS BuildInternals) followed by
+ # qt_find_package(Qt6 COMPONENTS Core) doesn't end up calling find_package(Qt6Core).
+ if (NOT ${ARGV0}_FOUND AND NOT _qt_find_package_skip_find_package)
+ # Call original function without our custom arguments.
+ find_package(${arg_UNPARSED_ARGUMENTS})
+ endif()
+
+ if(QT_NO_USE_FIND_PACKAGE_SYSTEM_ENVIRONMENT_PATH)
+ if("${_qt_find_package_use_system_env_backup}" STREQUAL "")
+ unset(CMAKE_FIND_USE_SYSTEM_ENVIRONMENT_PATH)
+ else()
+ set(CMAKE_FIND_USE_SYSTEM_ENVIRONMENT_PATH "${_qt_find_package_use_system_env_backup}")
+ endif()
+ endif()
+
+ if(${ARGV0}_FOUND)
+ # Record that the package was found, so that future reconfigurations can be sped up.
+ set_property(GLOBAL APPEND PROPERTY _qt_previously_found_packages "${ARGV0}")
+ endif()
+
+ if(${ARGV0}_FOUND AND arg_PROVIDED_TARGETS AND NOT _qt_find_package_skip_find_package)
+ # If package was found, associate each target with its package name. This will be used
+ # later when creating Config files for Qt libraries, to generate correct find_dependency()
+ # calls. Also make the provided targets global, so that the properties can be read in
+ # all scopes.
+ foreach(qt_find_package_target_name ${arg_PROVIDED_TARGETS})
+ if(TARGET ${qt_find_package_target_name})
+ # Allow usage of aliased targets by setting properties on the actual target
+ get_target_property(aliased_target ${qt_find_package_target_name} ALIASED_TARGET)
+ if(aliased_target)
+ set(qt_find_package_target_name ${aliased_target})
+ endif()
+
+ set_target_properties(${qt_find_package_target_name} PROPERTIES
+ INTERFACE_QT_PACKAGE_NAME ${ARGV0}
+ INTERFACE_QT_PACKAGE_IS_OPTIONAL ${arg_MARK_OPTIONAL})
+ if(package_version)
+ set_target_properties(${qt_find_package_target_name}
+ PROPERTIES INTERFACE_QT_PACKAGE_VERSION ${ARGV1})
+ endif()
+
+ if(arg_COMPONENTS)
+ string(REPLACE ";" " " components_as_string "${arg_COMPONENTS}")
+ set_property(TARGET ${qt_find_package_target_name}
+ PROPERTY INTERFACE_QT_PACKAGE_COMPONENTS ${components_as_string})
+ endif()
+
+ if(arg_OPTIONAL_COMPONENTS)
+ string(REPLACE ";" " " components_as_string "${arg_OPTIONAL_COMPONENTS}")
+ set_property(TARGET ${qt_find_package_target_name}
+ PROPERTY INTERFACE_QT_PACKAGE_OPTIONAL_COMPONENTS
+ ${components_as_string})
+ endif()
+
+ get_property(is_global TARGET ${qt_find_package_target_name} PROPERTY
+ IMPORTED_GLOBAL)
+ qt_internal_should_not_promote_package_target_to_global(
+ "${qt_find_package_target_name}" should_not_promote)
+ if(NOT is_global AND NOT should_not_promote)
+ __qt_internal_promote_target_to_global(${qt_find_package_target_name})
+ qt_find_package_promote_targets_to_global_scope(
+ "${qt_find_package_target_name}")
+ endif()
+ endif()
+
+ endforeach()
+
+ if(arg_MODULE_NAME AND arg_QMAKE_LIB
+ AND (NOT arg_QMAKE_LIB IN_LIST QT_QMAKE_LIBS_FOR_${arg_MODULE_NAME}))
+ set(QT_QMAKE_LIBS_FOR_${arg_MODULE_NAME}
+ ${QT_QMAKE_LIBS_FOR_${arg_MODULE_NAME}};${arg_QMAKE_LIB} CACHE INTERNAL "")
+ set(QT_TARGETS_OF_QMAKE_LIB_${arg_QMAKE_LIB} ${arg_PROVIDED_TARGETS} CACHE INTERNAL "")
+ foreach(provided_target ${arg_PROVIDED_TARGETS})
+ set(QT_QMAKE_LIB_OF_TARGET_${provided_target} ${arg_QMAKE_LIB} CACHE INTERNAL "")
+ endforeach()
+ endif()
+ endif()
+endmacro()
+
+# Save found packages in the cache. They will be read on next reconfiguration to skip looking
+# for packages that were not previously found.
+# Only applies to -developer-builds by default.
+# Can also be opted in or opted out via QT_INTERNAL_SAVE_PREVIOUSLY_FOUND_PACKAGES.
+# Opting out will need two reconfigurations to take effect.
+function(qt_internal_save_previously_visited_packages)
+ if(DEFINED QT_INTERNAL_SAVE_PREVIOUSLY_FOUND_PACKAGES)
+ set(should_save "${QT_INTERNAL_SAVE_PREVIOUSLY_FOUND_PACKAGES}")
+ else()
+ if(FEATURE_developer_build OR QT_FEATURE_developer_build)
+ set(should_save ON)
+ else()
+ set(should_save OFF)
+ endif()
+ endif()
+
+ if(NOT should_save)
+ # When the value is flipped to OFF, remove any previously saved packages.
+ unset(QT_INTERNAL_PREVIOUSLY_FOUND_PACKAGES CACHE)
+ unset(QT_INTERNAL_PREVIOUSLY_SEARCHED_PACKAGES CACHE)
+ return()
+ endif()
+
+ get_property(_qt_previously_found_packages GLOBAL PROPERTY _qt_previously_found_packages)
+ if(_qt_previously_found_packages)
+ list(REMOVE_DUPLICATES _qt_previously_found_packages)
+ set(QT_INTERNAL_PREVIOUSLY_FOUND_PACKAGES "${_qt_previously_found_packages}" CACHE INTERNAL
+ "List of CMake packages found during configuration using qt_find_package.")
+ endif()
+
+ get_property(_qt_previously_searched_packages GLOBAL PROPERTY _qt_previously_searched_packages)
+ if(_qt_previously_searched_packages)
+ list(REMOVE_DUPLICATES _qt_previously_searched_packages)
+ set(QT_INTERNAL_PREVIOUSLY_SEARCHED_PACKAGES
+ "${_qt_previously_searched_packages}" CACHE INTERNAL
+ "List of CMake packages searched during configuration using qt_find_package."
+ )
+ endif()
+endfunction()
+
+# Return qmake library name for the given target, e.g. return "vulkan" for "Vulkan::Vulkan".
+function(qt_internal_map_target_to_qmake_lib target out_var)
+ set(${out_var} "${QT_QMAKE_LIB_OF_TARGET_${target}}" PARENT_SCOPE)
+endfunction()
+
+# This function records a dependency between ${main_target_name} and ${dep_package_name}.
+# at the CMake package level.
+# E.g. The Tools package that provides the qtwaylandscanner target
+# needs to call find_package(WaylandScanner) (non-qt-package).
+# main_target_name = qtwaylandscanner
+# dep_package_name = WaylandScanner
+function(qt_record_extra_package_dependency main_target_name dep_package_name dep_package_version)
+ if(NOT TARGET "${main_target_name}")
+ qt_get_tool_target_name(main_target_name "${main_target_name}")
+ endif()
+ if (TARGET "${main_target_name}")
+ get_target_property(extra_packages "${main_target_name}" QT_EXTRA_PACKAGE_DEPENDENCIES)
+ if(NOT extra_packages)
+ set(extra_packages "")
+ endif()
+
+ list(APPEND extra_packages "${dep_package_name}\;${dep_package_version}")
+ set_target_properties("${main_target_name}" PROPERTIES QT_EXTRA_PACKAGE_DEPENDENCIES
+ "${extra_packages}")
+ endif()
+endfunction()
+
+# This function records a dependency between ${main_target_name} and ${dep_target_name}
+# at the CMake package level.
+# E.g. Qt6CoreConfig.cmake needs to find_package(Qt6EntryPointPrivate).
+# main_target_name = Core
+# dep_target_name = EntryPointPrivate
+# This is just a convenience function that deals with Qt targets and their associated packages
+# instead of raw package names.
+function(qt_record_extra_qt_package_dependency main_target_name dep_target_name
+ dep_package_version)
+ # EntryPointPrivate -> Qt6EntryPointPrivate.
+ qt_internal_qtfy_target(qtfied_target_name "${dep_target_name}")
+ qt_record_extra_package_dependency("${main_target_name}"
+ "${qtfied_target_name_versioned}" "${dep_package_version}")
+endfunction()
+
+# This function records a 'QtFooTools' package dependency for the ${main_target_name} target
+# onto the ${dep_package_name} tools package.
+# E.g. The QtWaylandCompositor package needs to call find_package(QtWaylandScannerTools).
+# main_target_name = WaylandCompositor
+# dep_package_name = Qt6WaylandScannerTools
+function(qt_record_extra_main_tools_package_dependency
+ main_target_name dep_package_name dep_package_version)
+ if(NOT TARGET "${main_target_name}")
+ qt_get_tool_target_name(main_target_name "${main_target_name}")
+ endif()
+ if (TARGET "${main_target_name}")
+ get_target_property(extra_packages "${main_target_name}"
+ QT_EXTRA_TOOLS_PACKAGE_DEPENDENCIES)
+ if(NOT extra_packages)
+ set(extra_packages "")
+ endif()
+
+ list(APPEND extra_packages "${dep_package_name}\;${dep_package_version}")
+ set_target_properties("${main_target_name}" PROPERTIES QT_EXTRA_TOOLS_PACKAGE_DEPENDENCIES
+ "${extra_packages}")
+ endif()
+endfunction()
+
+# This function records a 'QtFooTools' package dependency for the ${main_target_name} target
+# onto the ${dep_non_versioned_package_name} Tools package.
+# main_target_name = WaylandCompositor
+# dep_non_versioned_package_name = WaylandScannerTools
+# This is just a convenience function to avoid hardcoding the qtified version in the dep package
+# name.
+function(qt_record_extra_qt_main_tools_package_dependency main_target_name
+ dep_non_versioned_package_name
+ dep_package_version)
+ # WaylandScannerTools -> Qt6WaylandScannerTools.
+ qt_internal_qtfy_target(qtfied_package_name "${dep_non_versioned_package_name}")
+ qt_record_extra_main_tools_package_dependency(
+ "${main_target_name}" "${qtfied_package_name_versioned}" "${dep_package_version}")
+endfunction()
+
+# Record an extra 3rd party target as a dependency for ${main_target_name}.
+#
+# Adds a find_package(${dep_target_package_name}) in ${main_target_name}Dependencies.cmake.
+#
+# Needed to record a dependency on the package that provides WrapVulkanHeaders::WrapVulkanHeaders.
+# The package version, components, whether the package is optional, etc, are queried from the
+# ${dep_target} target properties.
+# Usually these are set at the qt_find_package() call site of a configure.cmake file e.g. using
+# Qt's MARK_OPTIONAL option.
+function(qt_record_extra_third_party_dependency main_target_name dep_target)
+ if(NOT TARGET "${main_target_name}")
+ qt_get_tool_target_name(main_target_name "${main_target_name}")
+ endif()
+ if(TARGET "${main_target_name}")
+ get_target_property(extra_deps "${main_target_name}" _qt_extra_third_party_dep_targets)
+ if(NOT extra_deps)
+ set(extra_deps "")
+ endif()
+
+ list(APPEND extra_deps "${dep_target}")
+ set_target_properties("${main_target_name}" PROPERTIES _qt_extra_third_party_dep_targets
+ "${extra_deps}")
+ endif()
+endfunction()
+
+# Sets out_var to TRUE if the non-namespaced ${lib} target is exported as part of Qt6Targets.cmake.
+function(qt_internal_is_lib_part_of_qt6_package lib out_var)
+ if (lib STREQUAL "Platform"
+ OR lib STREQUAL "GlobalConfig"
+ OR lib STREQUAL "GlobalConfigPrivate"
+ OR lib STREQUAL "PlatformModuleInternal"
+ OR lib STREQUAL "PlatformPluginInternal"
+ OR lib STREQUAL "PlatformToolInternal"
+ OR lib STREQUAL "PlatformCommonInternal"
+ )
+ set(${out_var} "TRUE" PARENT_SCOPE)
+ else()
+ set(${out_var} "FALSE" PARENT_SCOPE)
+ endif()
+endfunction()
+
+# Try to get the CMake package version of a Qt target.
+#
+# Query the target's _qt_package_version property, or try to read it from the CMake package version
+# variable set from calling find_package(Qt6${target}).
+# Not all targets will have a find_package _VERSION variable, for example if the target is an
+# executable.
+# A heuristic is used to handle QtFooPrivate module targets.
+# If no version can be found, fall back to ${PROJECT_VERSION} and issue a warning.
+function(qt_internal_get_package_version_of_target target package_version_out_var)
+ qt_internal_is_lib_part_of_qt6_package("${target}" is_part_of_qt6)
+
+ if(is_part_of_qt6)
+ # When building qtbase, Qt6_VERSION is not set (unless examples are built in-tree,
+ # non-ExternalProject). Use the Platform target's version instead which would be the
+ # equivalent.
+ if(TARGET "${QT_CMAKE_EXPORT_NAMESPACE}::Platform")
+ get_target_property(package_version
+ "${QT_CMAKE_EXPORT_NAMESPACE}::Platform" _qt_package_version)
+ endif()
+ if(NOT package_version)
+ set(package_version "${${QT_CMAKE_EXPORT_NAMESPACE}_VERSION}")
+ endif()
+ else()
+ # Try to get the version from the target.
+ # Try the Private target first and if it doesn't exist, try the non-Private target later.
+ if(TARGET "${QT_CMAKE_EXPORT_NAMESPACE}::${target}")
+ get_target_property(package_version
+ "${QT_CMAKE_EXPORT_NAMESPACE}::${target}" _qt_package_version)
+ endif()
+
+ # Try to get the version from the corresponding package version variable.
+ if(NOT package_version)
+ set(package_version "${${QT_CMAKE_EXPORT_NAMESPACE}${target}_VERSION}")
+ endif()
+
+ # Try non-Private target.
+ if(NOT package_version AND target MATCHES "(.*)Private$")
+ set(target "${CMAKE_MATCH_1}")
+ endif()
+
+ if(NOT package_version AND TARGET "${QT_CMAKE_EXPORT_NAMESPACE}::${target}")
+ get_target_property(package_version
+ "${QT_CMAKE_EXPORT_NAMESPACE}::${target}" _qt_package_version)
+ endif()
+
+ if(NOT package_version)
+ set(package_version "${${QT_CMAKE_EXPORT_NAMESPACE}${target}_VERSION}")
+ endif()
+ endif()
+
+ if(NOT package_version)
+ set(package_version "${PROJECT_VERSION}")
+ if(FEATURE_developer_build)
+ message(WARNING
+ "Could not determine package version of target ${target}. "
+ "Defaulting to project version ${PROJECT_VERSION}.")
+ endif()
+ endif()
+
+ set(${package_version_out_var} "${package_version}" PARENT_SCOPE)
+endfunction()
+
+# Get the CMake package name that contains / exported the Qt module target.
+function(qt_internal_get_package_name_of_target target package_name_out_var)
+ qt_internal_is_lib_part_of_qt6_package("${target}" is_part_of_qt6)
+
+ if(is_part_of_qt6)
+ set(package_name "${INSTALL_CMAKE_NAMESPACE}")
+ else()
+ # Get the package name from the module's target property.
+ # If not set, fallback to a name based on the target name.
+ #
+ # TODO: Remove fallback once sufficient time has passed, aka all developers updated
+ # their builds not to contain stale FooDependencies.cmakes files without the
+ # _qt_package_name property.
+ set(package_name "")
+ set(package_name_default "${INSTALL_CMAKE_NAMESPACE}${target}")
+ set(target_namespaced "${QT_CMAKE_EXPORT_NAMESPACE}::${target}")
+ if(TARGET "${target_namespaced}")
+ get_target_property(package_name_from_prop "${target_namespaced}" _qt_package_name)
+ if(package_name_from_prop)
+ set(package_name "${package_name_from_prop}")
+ endif()
+ endif()
+ if(NOT package_name)
+ message(WARNING
+ "Could not find target ${target_namespaced} to query its package name. "
+ "Defaulting to package name ${package_name_default}. Consider re-arranging the "
+ "project structure to ensure the target exists by this point."
+ )
+ set(package_name "${package_name_default}")
+ endif()
+ endif()
+
+ set(${package_name_out_var} "${package_name}" PARENT_SCOPE)
+endfunction()
+
+# This function stores the list of Qt targets a library depend on,
+# along with their version info, for usage in ${target}Depends.cmake file
+function(qt_register_target_dependencies target public_libs private_libs)
+ get_target_property(target_deps "${target}" _qt_target_deps)
+ if(NOT target_deps)
+ set(target_deps "")
+ endif()
+
+ get_target_property(target_type ${target} TYPE)
+ set(lib_list ${public_libs})
+
+ set(target_is_shared FALSE)
+ set(target_is_static FALSE)
+ if(target_type STREQUAL "SHARED_LIBRARY")
+ set(target_is_shared TRUE)
+ elseif(target_type STREQUAL "STATIC_LIBRARY")
+ set(target_is_static TRUE)
+ endif()
+
+ # Record 'Qt::Foo'-like private dependencies of static library targets, this will be used to
+ # generate find_dependency() calls.
+ #
+ # Private static library dependencies will become $<LINK_ONLY:> dependencies in
+ # INTERFACE_LINK_LIBRARIES.
+ if(target_is_static)
+ list(APPEND lib_list ${private_libs})
+ endif()
+
+ foreach(lib IN LISTS lib_list)
+ if("${lib}" MATCHES "^Qt::(.*)")
+ set(lib "${CMAKE_MATCH_1}")
+ elseif("${lib}" MATCHES "^${QT_CMAKE_EXPORT_NAMESPACE}::(.*)")
+ set(lib "${CMAKE_MATCH_1}")
+ else()
+ set(lib "")
+ endif()
+
+ if(lib)
+ qt_internal_get_package_name_of_target("${lib}" package_name)
+ qt_internal_get_package_version_of_target("${lib}" package_version)
+ list(APPEND target_deps "${package_name}\;${package_version}")
+ endif()
+ endforeach()
+
+ # Record 'Qt::Foo'-like shared private dependencies of shared library targets.
+ #
+ # Private shared library dependencies are listed in the target's
+ # IMPORTED_LINK_DEPENDENT_LIBRARIES and used in rpath-link calculation.
+ # See QTBUG-86533 for some details.
+ # We filter out static libraries and common platform targets, but include both SHARED and
+ # INTERFACE libraries. INTERFACE libraries in most cases will be FooPrivate libraries.
+ if(target_is_shared AND private_libs)
+ foreach(lib IN LISTS private_libs)
+ set(lib_namespaced "${lib}")
+ if("${lib}" MATCHES "^Qt::(.*)")
+ set(lib "${CMAKE_MATCH_1}")
+ elseif("${lib}" MATCHES "^${QT_CMAKE_EXPORT_NAMESPACE}::(.*)")
+ set(lib "${CMAKE_MATCH_1}")
+ else()
+ set(lib "")
+ endif()
+
+ if(lib)
+ set(lib "${CMAKE_MATCH_1}")
+
+ qt_internal_is_lib_part_of_qt6_package("${lib}" is_part_of_qt6)
+ get_target_property(lib_type "${lib_namespaced}" TYPE)
+ if(NOT lib_type STREQUAL "STATIC_LIBRARY" AND NOT is_part_of_qt6)
+ qt_internal_get_package_name_of_target("${lib}" package_name)
+ qt_internal_get_package_version_of_target("${lib}" package_version)
+ list(APPEND target_deps "${package_name}\;${package_version}")
+ endif()
+ endif()
+ endforeach()
+ endif()
+
+ set_target_properties("${target}" PROPERTIES _qt_target_deps "${target_deps}")
+endfunction()
+
+# Sets out_var to to TRUE if the target was marked to not be promoted to global scope.
+function(qt_internal_should_not_promote_package_target_to_global target out_var)
+ get_property(should_not_promote TARGET "${target}" PROPERTY _qt_no_promote_global)
+ set("${out_var}" "${should_not_promote}" PARENT_SCOPE)
+endfunction()
diff --git a/cmake/QtFindWrapConfigExtra.cmake.in b/cmake/QtFindWrapConfigExtra.cmake.in
index 6ecf43512c..d1706d7cab 100644
--- a/cmake/QtFindWrapConfigExtra.cmake.in
+++ b/cmake/QtFindWrapConfigExtra.cmake.in
@@ -1 +1,4 @@
+# Copyright (C) 2024 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
@extra_cmake_code@
diff --git a/cmake/QtFindWrapHelper.cmake b/cmake/QtFindWrapHelper.cmake
index beafad9ab3..a8d3da49d1 100644
--- a/cmake/QtFindWrapHelper.cmake
+++ b/cmake/QtFindWrapHelper.cmake
@@ -1,3 +1,6 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Creates an imported wrapper target that links against either a Qt bundled package
# or a system package.
#
diff --git a/cmake/QtFinishPkgConfigFile.cmake b/cmake/QtFinishPkgConfigFile.cmake
new file mode 100644
index 0000000000..3799621400
--- /dev/null
+++ b/cmake/QtFinishPkgConfigFile.cmake
@@ -0,0 +1,31 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+# Finish a preliminary .pc file.
+#
+# - Appends to each requirement the proper configuration postfix.
+# - Strips empty PkgConfig fields.
+#
+# This file is to be used in CMake script mode with the following variables set:
+# IN_FILE: path to the step 2 preliminary .pc file.
+# OUT_FILE: path to the .pc file that is going to be created.
+# POSTFIX: postfix for each requirement (optional).
+
+cmake_policy(SET CMP0057 NEW)
+file(STRINGS "${IN_FILE}" lines)
+set(content "")
+set(emptied "Libs:" "Cflags:" "Requires:")
+foreach(line ${lines})
+ if(POSTFIX)
+ if(line MATCHES "^Libs:")
+ string(REGEX REPLACE "( -lQt[^ ]+)" "\\1${POSTFIX}" line "${line}")
+ elseif(line MATCHES "^Requires:")
+ string(REGEX REPLACE "( Qt[^ ]+)" "\\1${POSTFIX}" line "${line}")
+ endif()
+ endif()
+ string(REGEX REPLACE " +$" "" line "${line}")
+ if(NOT line IN_LIST emptied)
+ string(APPEND content "${line}\n")
+ endif()
+endforeach()
+file(WRITE "${OUT_FILE}" "${content}")
diff --git a/cmake/QtFinishPrlFile.cmake b/cmake/QtFinishPrlFile.cmake
index 4b350b9339..1cf9377e6c 100644
--- a/cmake/QtFinishPrlFile.cmake
+++ b/cmake/QtFinishPrlFile.cmake
@@ -1,3 +1,6 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Finish a preliminary .prl file.
#
# - Replaces occurrences of the build libdir with $$[QT_INSTALL_LIBDIR].
@@ -7,17 +10,23 @@
# aka from "/usr/lib/x86_64-linux-gnu/libcups.so" to "-lcups"
# - Replaces Qt absolute framework paths into a combination of -F$$[QT_INSTALL_LIBS] and
# -framework QtFoo
-# - Prepends '-l' to values that are not absolute paths, and don't start with either '-l' or
-# '-framework'.
+# - Prepends '-l' to values that are not absolute paths, and don't start with a dash
+# aka, '-lfoo', '-framework', '-pthread'.
+#
+# The path to the final .prl file is stored in the input file as assignment to FINAL_PRL_FILE_PATH.
#
# This file is to be used in CMake script mode with the following variables set:
-# IN_FILE: path to the preliminary .prl file
-# OUT_FILE: path to the final .prl file that's going to be installed
-# QT_BUILD_LIBDIR: path to Qt's libdir when building (those paths get replaced)
+# IN_FILE: path to the step 1 preliminary .prl file
+# OUT_FILE: path to the step 2 preliminary .prl file that is going to be created
+# QT_LIB_DIRS: list of paths where Qt libraries are located.
+# This includes the install prefix and the current repo build dir.
+# These paths get replaced with relocatable paths or linker / framework flags.
# LIBRARY_SUFFIXES: list of known library extensions, e.g. .so;.a on Linux
# LIBRARY_PREFIXES: list of known library prefies, e.g. the "lib" in "libz" on on Linux
# LINK_LIBRARY_FLAG: flag used to link a shared library to an executable, e.g. -l on UNIX
+# IMPLICIT_LINK_DIRECTORIES: list of implicit linker search paths
+cmake_policy(SET CMP0007 NEW)
include("${CMAKE_CURRENT_LIST_DIR}/QtGenerateLibHelpers.cmake")
file(STRINGS "${IN_FILE}" lines)
@@ -26,18 +35,27 @@ set(qt_framework_search_path_inserted FALSE)
foreach(line ${lines})
if(line MATCHES "^RCC_OBJECTS = (.*)")
set(rcc_objects ${CMAKE_MATCH_1})
+ elseif(line MATCHES "^QMAKE_PRL_TARGET_PATH_FOR_CMAKE = (.*)")
+ set(target_library_path "${CMAKE_MATCH_1}")
elseif(line MATCHES "^QMAKE_PRL_LIBS_FOR_CMAKE = (.*)")
unset(adjusted_libs)
foreach(lib ${CMAKE_MATCH_1})
if("${lib}" STREQUAL "")
continue()
endif()
+
+ # Check if the absolute path represents a Qt module located either in Qt's
+ # $prefix/lib dir, or in the build dir of the repo.
if(IS_ABSOLUTE "${lib}")
- file(RELATIVE_PATH relative_lib "${QT_BUILD_LIBDIR}" "${lib}")
- if(IS_ABSOLUTE "${relative_lib}" OR (relative_lib MATCHES "^\\.\\."))
+ qt_internal_path_is_relative_to_qt_lib_path(
+ "${lib}" "${QT_LIB_DIRS}" lib_is_a_qt_module relative_lib)
+ if(NOT lib_is_a_qt_module)
+ # It's not a Qt module, extract the library name and prepend an -l to make
+ # it relocatable.
qt_transform_absolute_library_paths_to_link_flags(lib_with_link_flag "${lib}")
list(APPEND adjusted_libs "${lib_with_link_flag}")
else()
+ # Is a Qt module.
# Transform Qt framework paths into -framework flags.
if(relative_lib MATCHES "^(Qt(.+))\\.framework/")
if(NOT qt_framework_search_path_inserted)
@@ -46,19 +64,64 @@ foreach(line ${lines})
endif()
list(APPEND adjusted_libs "-framework" "${CMAKE_MATCH_1}")
else()
+ # Not a framework, transform the Qt module into relocatable relative path.
qt_strip_library_version_suffix(relative_lib "${relative_lib}")
list(APPEND adjusted_libs "$$[QT_INSTALL_LIBS]/${relative_lib}")
endif()
endif()
else()
- if(NOT lib MATCHES "^-l" AND NOT lib MATCHES "^-framework")
+ # Not absolute path, most likely a library name or a linker flag.
+ # If linker flag (like -framework, -lfoo, -pthread, keep it as-is).
+ if(NOT lib MATCHES "^-")
string(PREPEND lib "-l")
endif()
list(APPEND adjusted_libs "${lib}")
endif()
endforeach()
if(rcc_objects)
- list(APPEND adjusted_libs ${rcc_objects})
+ set(libs_to_prepend ${rcc_objects})
+
+ # By default, when qmake processes prl files, it first puts the processed library
+ # on the link line, followed by all values specified in QMAKE_PRL_LIBS.
+ # Because we add the resource object files into QMAKE_PRL_LIBS, this means they will
+ # also appear on the link line after the library.
+ # This causes issues on Linux because the linker may discard unreferenced symbols from
+ # the library, which are referenced by the resource object files.
+ # We can't control the placement of the library in relation to QMAKE_PRL_LIBS, but we
+ # can add the library one more time in QMAKE_PRL_LIBS, after the object files.
+ # qmake's UnixMakefileGenerator::findLibraries then takes care of deduplication, which
+ # keeps the last occurrence of the library on the link line, the one after the object
+ # files.
+ qt_internal_path_is_relative_to_qt_lib_path(
+ "${target_library_path}" "${QT_LIB_DIRS}" lib_is_a_qt_module relative_lib)
+ if(NOT lib_is_a_qt_module)
+ qt_internal_path_is_relative_to_qt_lib_path(
+ "${target_library_path}" "${QT_PLUGIN_DIRS}" lib_is_a_qt_plugin relative_lib)
+ endif()
+ if(NOT lib_is_a_qt_module AND NOT lib_is_a_qt_plugin)
+ qt_internal_path_is_relative_to_qt_lib_path(
+ "${target_library_path}" "${QT_QML_DIRS}" lib_is_a_qt_qml_plugin relative_lib)
+ endif()
+ if(NOT lib_is_a_qt_module AND NOT lib_is_a_qt_plugin AND NOT lib_is_a_qt_qml_plugin)
+ message(AUTHOR_WARNING
+ "Could not determine relative path for library ${target_library_path} when "
+ "generating prl file contents. An absolute path will be embedded, which "
+ "will cause issues if the Qt installation is relocated.")
+ list(APPEND libs_to_prepend "${target_library_path}")
+ else()
+ set(qmake_lib_path_prefix "$$[QT_PRL_INVALID_QMAKE_VARIABLE]")
+ if(lib_is_a_qt_module)
+ set(qmake_lib_path_prefix "$$[QT_INSTALL_LIBS]")
+ elseif(lib_is_a_qt_plugin)
+ set(qmake_lib_path_prefix "$$[QT_INSTALL_PLUGINS]")
+ elseif(lib_is_a_qt_qml_plugin)
+ set(qmake_lib_path_prefix "$$[QT_INSTALL_QML]")
+ endif()
+ qt_strip_library_version_suffix(relative_lib "${relative_lib}")
+ list(APPEND libs_to_prepend "${qmake_lib_path_prefix}/${relative_lib}")
+ endif()
+
+ list(PREPEND adjusted_libs ${libs_to_prepend})
endif()
list(JOIN adjusted_libs " " adjusted_libs_for_qmake)
string(APPEND content "QMAKE_PRL_LIBS = ${adjusted_libs_for_qmake}\n")
diff --git a/cmake/QtFlagHandlingHelpers.cmake b/cmake/QtFlagHandlingHelpers.cmake
new file mode 100644
index 0000000000..6a62b85c03
--- /dev/null
+++ b/cmake/QtFlagHandlingHelpers.cmake
@@ -0,0 +1,1139 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+# Sets '${var}' to a genex that extracts the target's property.
+# Sets 'have_${var}' to a genex that checks that the property has a
+# non-empty value.
+macro(qt_internal_genex_get_property var target property)
+ set(${var} "$<TARGET_PROPERTY:${target},${property}>")
+ set(have_${var} "$<BOOL:${${var}}>")
+endmacro()
+
+# Sets '${var}' to a genex that will join the given property values
+# using '${glue}' and will surround the entire output with '${prefix}'
+# and '${suffix}'.
+macro(qt_internal_genex_get_joined_property var target property prefix suffix glue)
+ qt_internal_genex_get_property("${var}" "${target}" "${property}")
+ set(${var}
+ "$<${have_${var}}:${prefix}$<JOIN:${${var}},${glue}>${suffix}>")
+endmacro()
+
+# This function generates LD version script for the target and uses it in the target linker line.
+# Function has two modes dependending on the specified arguments.
+# Arguments:
+# PRIVATE_CONTENT_FILE specifies the pre-cooked content of Qt_<version>_PRIVATE_API section.
+# Requires the content file available at build time.
+function(qt_internal_add_linker_version_script target)
+ if(WASM)
+ return()
+ endif()
+
+ cmake_parse_arguments(PARSE_ARGV 1 arg
+ ""
+ "PRIVATE_CONTENT_FILE"
+ "PRIVATE_HEADERS"
+ )
+ _qt_internal_validate_all_args_are_parsed(arg)
+
+ if(arg_PRIVATE_CONTENT_FILE AND arg_PRIVATE_HEADERS)
+ message(FATAL_ERROR "Both PRIVATE_CONTENT_FILE and PRIVATE_HEADERS are specified.")
+ endif()
+
+ if(TEST_ld_version_script)
+ # Create a list of mangled symbol matches for all "std::" symbols. This
+ # list will catch most symbols, but will miss global-namespace symbols
+ # that only have std parameters.
+ # See https://itanium-cxx-abi.github.io/cxx-abi/abi.html#mangle.name for reference
+ set(contents "NonQt {\nlocal:")
+
+ # For types: vtable, VTT, typeinfo, typeinfo name
+ foreach(ptrqualifier "" "P" "PK") # T, T *, const T * (volatile ignored)
+ string(APPEND contents "\n _ZT[VTIS]${ptrqualifier}S*;"
+ "_ZT[VTIS]${ptrqualifier}NS*;")
+ endforeach()
+
+ # For functions and variables
+ foreach(special ""
+ "G[VR]" # guard variables, extended-lifetime references
+ "GTt") # transaction entry points
+ foreach(cvqualifier "" "[VK]" "VK") # plain, const|volatile, const volatile
+ string(APPEND contents "\n ")
+ foreach(refqualifier "" "[RO]") # plain, & or &&
+ # For names in the std:: namespace, compression applies
+ # (https://itanium-cxx-abi.github.io/cxx-abi/abi.html#mangling-compression)
+ string(APPEND contents
+ " _Z${special}${cvqualifier}${refqualifier}S*;" # plain
+ " _Z${special}N${cvqualifier}${refqualifier}S*;" # nested name
+ )
+ endforeach()
+ endforeach()
+ endforeach()
+
+ string(APPEND contents "\n};\nQt_${PROJECT_VERSION_MAJOR}")
+ if(QT_FEATURE_elf_private_full_version)
+ string(APPEND contents ".${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}")
+ endif()
+ string(APPEND contents "_PRIVATE_API { qt_private_api_tag*;\n")
+ if(arg_PRIVATE_HEADERS)
+ foreach(ph ${arg_PRIVATE_HEADERS})
+ string(APPEND contents " @FILE:${ph}@\n")
+ endforeach()
+ else()
+ string(APPEND contents "@PRIVATE_CONTENT@")
+ endif()
+ string(APPEND contents "};\n")
+ set(current "Qt_${PROJECT_VERSION_MAJOR}")
+ string(APPEND contents "${current} {\n *;")
+
+ get_target_property(target_type ${target} TYPE)
+ if(NOT target_type STREQUAL "INTERFACE_LIBRARY")
+ set(genex_prefix "\n ")
+ set(genex_glue "$<SEMICOLON>\n ")
+ set(genex_suffix "$<SEMICOLON>")
+ qt_internal_genex_get_joined_property(
+ linker_exports "${target}" _qt_extra_linker_script_exports
+ "${genex_prefix}" "${genex_suffix}" "${genex_glue}"
+ )
+ string(APPEND contents "${linker_exports}")
+ endif()
+ string(APPEND contents "\n};\n")
+
+ if(NOT target_type STREQUAL "INTERFACE_LIBRARY")
+ set(property_genex "$<TARGET_PROPERTY:${target},_qt_extra_linker_script_content>")
+ set(check_genex "$<BOOL:${property_genex}>")
+ string(APPEND contents
+ "$<${check_genex}:${property_genex}>")
+ endif()
+
+ set(infile "${CMAKE_CURRENT_BINARY_DIR}/${target}.version.in")
+ set(outfile "${CMAKE_CURRENT_BINARY_DIR}/${target}.version")
+
+ file(GENERATE OUTPUT "${infile}" CONTENT "${contents}")
+
+ if(NOT arg_PRIVATE_CONTENT_FILE)
+ set(arg_PRIVATE_CONTENT_FILE "")
+ endif()
+ set(generator_command ${CMAKE_COMMAND}
+ "-DIN_FILE=${infile}"
+ "-DPRIVATE_CONTENT_FILE=${arg_PRIVATE_CONTENT_FILE}"
+ "-DOUT_FILE=${outfile}"
+ -P "${QT_CMAKE_DIR}/QtGenerateVersionScript.cmake"
+ )
+ set(generator_dependencies
+ "${arg_PRIVATE_CONTENT_FILE}"
+ "${QT_CMAKE_DIR}/QtGenerateVersionScript.cmake"
+ )
+
+ add_custom_command(
+ OUTPUT "${outfile}"
+ COMMAND ${generator_command}
+ DEPENDS ${generator_dependencies}
+ WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
+ COMMENT "Generating version linker script for target ${target}"
+ VERBATIM
+ )
+ add_custom_target(${target}_version_script DEPENDS ${outfile})
+ add_dependencies(${target} ${target}_version_script)
+ target_link_options(${target} PRIVATE "-Wl,--version-script,${outfile}")
+ endif()
+endfunction()
+
+function(qt_internal_add_link_flags_no_undefined target)
+ if (NOT QT_BUILD_SHARED_LIBS OR WASM)
+ return()
+ endif()
+ if (VXWORKS)
+ # VxWorks requires thread_local-related symbols to be found at
+ # runtime, resulting in linker error when no-undefined flag is
+ # set and thread_local is used
+ return()
+ endif()
+ if(CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang")
+ # ld64 defaults to -undefined,error, and in Xcode 15
+ # passing this option is deprecated, causing a warning.
+ return()
+ endif()
+ if ((GCC OR CLANG) AND NOT MSVC)
+ if(CLANG AND QT_FEATURE_sanitizer)
+ return()
+ endif()
+ set(previous_CMAKE_REQUIRED_LINK_OPTIONS ${CMAKE_REQUIRED_LINK_OPTIONS})
+
+ set(CMAKE_REQUIRED_LINK_OPTIONS "-Wl,-undefined,error")
+ check_cxx_source_compiles("int main() {}" HAVE_DASH_UNDEFINED_SYMBOLS)
+ if(HAVE_DASH_UNDEFINED_SYMBOLS)
+ set(no_undefined_flag "-Wl,-undefined,error")
+ endif()
+
+ set(CMAKE_REQUIRED_LINK_OPTIONS "-Wl,--no-undefined")
+ check_cxx_source_compiles("int main() {}" HAVE_DASH_DASH_NO_UNDEFINED)
+ if(HAVE_DASH_DASH_NO_UNDEFINED)
+ set(no_undefined_flag "-Wl,--no-undefined")
+ endif()
+
+ set(CMAKE_REQUIRED_LINK_OPTIONS ${previous_CMAKE_REQUIRED_LINK_OPTIONS})
+
+ if (NOT HAVE_DASH_UNDEFINED_SYMBOLS AND NOT HAVE_DASH_DASH_NO_UNDEFINED)
+ message(FATAL_ERROR "Platform linker doesn't support erroring upon encountering undefined symbols. Target:\"${target}\".")
+ endif()
+ target_link_options("${target}" PRIVATE "${no_undefined_flag}")
+ endif()
+endfunction()
+
+function(qt_internal_apply_gc_binaries_conditional target visibility)
+ # Should only be applied when the feature is enabled, aka for static builds.
+ if(NOT QT_FEATURE_gc_binaries)
+ return()
+ endif()
+ qt_internal_apply_gc_binaries("${target}" "${visibility}")
+endfunction()
+
+function(qt_internal_apply_gc_binaries target visibility)
+ set(possible_visibilities PRIVATE INTERFACE PUBLIC)
+ if(NOT visibility IN_LIST possible_visibilities)
+ message(FATAL_ERROR "Visibitily setting must be one of PRIVATE, INTERFACE or PUBLIC.")
+ endif()
+
+ string(JOIN "" clang_or_gcc_begin
+ "$<$<OR:"
+ "$<CXX_COMPILER_ID:GNU>,"
+ "$<CXX_COMPILER_ID:Clang>,"
+ "$<CXX_COMPILER_ID:AppleClang>,"
+ "$<CXX_COMPILER_ID:IntelLLVM>"
+ ">:"
+ )
+ set(clang_or_gcc_end ">")
+
+ if ((GCC OR CLANG) AND NOT WASM AND NOT UIKIT AND NOT MSVC)
+ if(APPLE)
+ set(gc_sections_flag "-Wl,-dead_strip")
+ elseif(SOLARIS)
+ set(gc_sections_flag "-Wl,-z,ignore")
+ elseif(LINUX OR BSD OR WIN32 OR ANDROID)
+ set(gc_sections_flag "-Wl,--gc-sections")
+ endif()
+
+ # Save the flag value with and without genex wrapping, so we can remove the wrapping
+ # when generating .pc pkgconfig files.
+ set_property(GLOBAL PROPERTY _qt_internal_gc_sections_without_genex "${gc_sections_flag}")
+
+ set(gc_sections_flag
+ "${clang_or_gcc_begin}${gc_sections_flag}${clang_or_gcc_end}")
+
+ set_property(GLOBAL PROPERTY _qt_internal_gc_sections_with_genex "${gc_sections_flag}")
+ endif()
+ if(gc_sections_flag)
+ target_link_options("${target}" ${visibility} "${gc_sections_flag}")
+ endif()
+
+ if((GCC OR CLANG) AND NOT WASM AND NOT UIKIT AND NOT MSVC)
+ set(split_sections_flags
+ "${clang_or_gcc_begin}-ffunction-sections;-fdata-sections${clang_or_gcc_end}")
+ endif()
+ if(split_sections_flags)
+ target_compile_options("${target}" ${visibility} "${split_sections_flags}")
+ endif()
+endfunction()
+
+function(qt_internal_apply_intel_cet target visibility)
+ if(NOT QT_FEATURE_intelcet)
+ return()
+ endif()
+
+ set(possible_visibilities PRIVATE INTERFACE PUBLIC)
+ if(NOT visibility IN_LIST possible_visibilities)
+ message(FATAL_ERROR "Visibitily setting must be one of PRIVATE, INTERFACE or PUBLIC.")
+ endif()
+
+ if(GCC)
+ string(JOIN "" flags
+ "$<$<OR:"
+ "$<CXX_COMPILER_ID:GNU>,"
+ "$<CXX_COMPILER_ID:Clang>,"
+ "$<CXX_COMPILER_ID:AppleClang>"
+ ">:-mshstk>")
+ endif()
+ if(flags)
+ target_compile_options("${target}" ${visibility} "${flags}")
+ endif()
+endfunction()
+
+function(qt_internal_library_deprecation_level result)
+ # QT_DISABLE_DEPRECATED_UP_TO controls which version we use as a cut-off
+ # compiling in to the library. E.g. if it is set to QT_VERSION then no
+ # code which was deprecated before QT_VERSION will be compiled in.
+ if (NOT DEFINED QT_DISABLE_DEPRECATED_UP_TO)
+ if(WIN32)
+ # On Windows, due to the way DLLs work, we need to export all functions,
+ # including the inlines
+ list(APPEND deprecations "QT_DISABLE_DEPRECATED_UP_TO=0x040800")
+ else()
+ # On other platforms, Qt's own compilation does need to compile the Qt 5.0 API
+ list(APPEND deprecations "QT_DISABLE_DEPRECATED_UP_TO=0x050000")
+ endif()
+ else()
+ list(APPEND deprecations "QT_DISABLE_DEPRECATED_UP_TO=${QT_DISABLE_DEPRECATED_UP_TO}")
+ endif()
+ # QT_WARN_DEPRECATED_UP_TO controls the upper-bound of deprecation
+ # warnings that are emitted. E.g. if it is set to 0x060500 then all use of
+ # things deprecated in or before 6.5.0 will be warned against.
+ list(APPEND deprecations "QT_WARN_DEPRECATED_UP_TO=0x070000")
+ set("${result}" "${deprecations}" PARENT_SCOPE)
+endfunction()
+
+# Sets the exceptions flags for the given target according to exceptions_on
+function(qt_internal_set_exceptions_flags target exceptions_on)
+ set(_defs "")
+ set(_flag "")
+ if(exceptions_on)
+ if(MSVC)
+ set(_flag "/EHsc")
+ if((MSVC_VERSION GREATER_EQUAL 1929) AND NOT CLANG)
+ # Use the undocumented compiler flag to make our binary smaller on x64.
+ # https://devblogs.microsoft.com/cppblog/making-cpp-exception-handling-smaller-x64/
+ # NOTE: It seems we'll use this new exception handling model unconditionally without
+ # this hack since some unknown MSVC version.
+ set(_flag ${_flag} "/d2FH4")
+ endif()
+ else()
+ set(_flag "-fexceptions")
+ endif()
+ else()
+ set(_defs "QT_NO_EXCEPTIONS")
+ if(MSVC)
+ set(_flag "/EHs-c-" "/wd4530" "/wd4577")
+ else()
+ set(_flag "-fno-exceptions")
+ endif()
+ endif()
+
+ target_compile_definitions("${target}" PRIVATE ${_defs})
+ target_compile_options("${target}" PRIVATE ${_flag})
+endfunction()
+
+function(qt_skip_warnings_are_errors target)
+ get_target_property(target_type "${target}" TYPE)
+ if(target_type STREQUAL "INTERFACE_LIBRARY")
+ return()
+ endif()
+ set_target_properties("${target}" PROPERTIES QT_SKIP_WARNINGS_ARE_ERRORS ON)
+endfunction()
+
+function(qt_skip_warnings_are_errors_when_repo_unclean target)
+ if(QT_REPO_NOT_WARNINGS_CLEAN)
+ qt_skip_warnings_are_errors("${target}")
+ endif()
+endfunction()
+
+function(qt_disable_warnings target)
+ get_target_property(target_type "${target}" TYPE)
+ if(target_type STREQUAL "INTERFACE_LIBRARY")
+ return()
+ endif()
+ set_target_properties("${target}" PROPERTIES QT_COMPILE_OPTIONS_DISABLE_WARNINGS ON)
+endfunction()
+
+function(qt_set_symbol_visibility_preset target value)
+ get_target_property(target_type "${target}" TYPE)
+ if(target_type STREQUAL "INTERFACE_LIBRARY")
+ return()
+ endif()
+
+ set_target_properties("${target}" PROPERTIES C_VISIBILITY_PRESET "${value}")
+ set_target_properties("${target}" PROPERTIES CXX_VISIBILITY_PRESET "${value}")
+ set_target_properties("${target}" PROPERTIES OBJC_VISIBILITY_PRESET "${value}")
+ set_target_properties("${target}" PROPERTIES OBJCXX_VISIBILITY_PRESET "${value}")
+endfunction()
+
+function(qt_set_symbol_visibility_hidden target)
+ qt_set_symbol_visibility_preset("${target}" "hidden")
+endfunction()
+
+function(qt_set_language_standards)
+ ## Use the latest standard the compiler supports (same as qt_common.prf)
+ if (QT_FEATURE_cxx2b)
+ set(CMAKE_CXX_STANDARD 23 PARENT_SCOPE)
+ elseif (QT_FEATURE_cxx20)
+ set(CMAKE_CXX_STANDARD 20 PARENT_SCOPE)
+ else()
+ set(CMAKE_CXX_STANDARD 17 PARENT_SCOPE)
+ endif()
+ set(CMAKE_CXX_STANDARD_REQUIRED ON PARENT_SCOPE)
+
+ set(CMAKE_C_STANDARD 11 PARENT_SCOPE)
+ set(CMAKE_C_STANDARD_REQUIRED ON PARENT_SCOPE)
+endfunction()
+
+function(qt_set_language_standards_interface_compile_features target)
+ # Regardless of which C++ standard is used to build Qt itself, require C++17 when building
+ # Qt applications using CMake (because the Qt header files use C++17 features).
+ set(cpp_feature "cxx_std_17")
+ target_compile_features("${target}" INTERFACE ${cpp_feature})
+endfunction()
+
+function(qt_set_msvc_cplusplus_options target visibility)
+ # For MSVC we need to explicitly pass -Zc:__cplusplus to get correct __cplusplus.
+ # Check qt_config_compile_test for more info.
+ if(MSVC AND MSVC_VERSION GREATER_EQUAL 1913)
+ set(flags "-Zc:__cplusplus" "-permissive-")
+ target_compile_options("${target}" ${visibility}
+ "$<$<AND:$<CXX_COMPILER_ID:MSVC>,$<COMPILE_LANGUAGE:CXX>>:${flags}>")
+ endif()
+endfunction()
+
+function(qt_enable_utf8_sources target)
+ set(utf8_flags "")
+ if(MSVC)
+ list(APPEND utf8_flags "$<$<CXX_COMPILER_ID:MSVC>:-utf-8>")
+ endif()
+
+ if(utf8_flags)
+ # Allow opting out by specifying the QT_NO_UTF8_SOURCE target property.
+ set(opt_out_condition "$<NOT:$<BOOL:$<TARGET_PROPERTY:QT_NO_UTF8_SOURCE>>>")
+ # Only set the compiler option for C and C++.
+ set(language_condition "$<COMPILE_LANGUAGE:C,CXX>")
+ # Compose the full condition.
+ set(genex_condition "$<AND:${opt_out_condition},${language_condition}>")
+ set(utf8_flags "$<${genex_condition}:${utf8_flags}>")
+ target_compile_options("${target}" INTERFACE "${utf8_flags}")
+ endif()
+endfunction()
+
+function(qt_internal_enable_unicode_defines)
+ if(WIN32)
+ set(no_unicode_condition
+ "$<NOT:$<BOOL:$<TARGET_PROPERTY:QT_NO_UNICODE_DEFINES>>>")
+ target_compile_definitions(Platform
+ INTERFACE "$<${no_unicode_condition}:UNICODE$<SEMICOLON>_UNICODE>")
+ endif()
+endfunction()
+
+# Saves the list of known optimization flags for the current compiler in out_var.
+#
+# Mostly used for removing them before adding new ones.
+function(qt_internal_get_all_possible_optimization_flag_values out_var)
+ set(flag_values "")
+ set(vars QT_CFLAGS_OPTIMIZE QT_CFLAGS_OPTIMIZE_FULL
+ QT_CFLAGS_OPTIMIZE_DEBUG QT_CFLAGS_OPTIMIZE_SIZE)
+ foreach(optimize_var ${vars})
+ set(value "${${optimize_var}}")
+ if(value)
+ list(APPEND flag_values "${value}")
+ endif()
+ endforeach()
+
+ # Additional flag values which might not be used in qmake mkspecs, but might be set by CMake,
+ # aka flags that are recognized by the compile which we might want to remove.
+ if(QT_CFLAGS_OPTIMIZE_VALID_VALUES)
+ list(APPEND flag_values ${QT_CFLAGS_OPTIMIZE_VALID_VALUES})
+ endif()
+
+ set("${out_var}" "${flag_values}" PARENT_SCOPE)
+endfunction()
+
+# Return's the current compiler's optimize_full flags if available.
+# Otherwise returns the regular optimization level flag.
+function(qt_internal_get_optimize_full_flags out_var)
+ set(optimize_full_flags "${QT_CFLAGS_OPTIMIZE_FULL}")
+ if(NOT optimize_full_flags)
+ set(optimize_full_flags "${QT_CFLAGS_OPTIMIZE}")
+ endif()
+ set(${out_var} "${optimize_full_flags}" PARENT_SCOPE)
+endfunction()
+
+# Prints the compiler and linker flags for each configuration, language and target type.
+#
+# Usually it would print the cache variables, but one may also override the variables
+# in a specific directory scope, so this is useful for debugging.
+#
+# Basically dumps either scoped or cached
+# CMAKE_<LANG>_FLAGS_CONFIG> and CMAKE_<TYPE>_LINKER_FLAGS_<CONFIG> variables.
+
+function(qt_internal_print_optimization_flags_values)
+ qt_internal_get_enabled_languages_for_flag_manipulation(languages)
+ qt_internal_get_configs_for_flag_manipulation(configs)
+ qt_internal_get_target_link_types_for_flag_manipulation(target_link_types)
+
+ qt_internal_print_optimization_flags_values_helper(
+ "${languages}" "${configs}" "${target_link_types}")
+endfunction()
+
+# Helper function for printing the optimization flags.
+function(qt_internal_print_optimization_flags_values_helper languages configs target_link_types)
+ foreach(lang ${languages})
+ set(flag_var_name "CMAKE_${lang}_FLAGS")
+ message(STATUS "${flag_var_name}: ${${flag_var_name}}")
+
+ foreach(config ${configs})
+ set(flag_var_name "CMAKE_${lang}_FLAGS_${config}")
+ message(STATUS "${flag_var_name}: ${${flag_var_name}}")
+ endforeach()
+ endforeach()
+
+ foreach(t ${target_link_types})
+ set(flag_var_name "CMAKE_${t}_LINKER_FLAGS")
+ message(STATUS "${flag_var_name}: ${${flag_var_name}}")
+
+ foreach(config ${configs})
+ set(flag_var_name "CMAKE_${t}_LINKER_FLAGS_${config}")
+ message(STATUS "${flag_var_name}: ${${flag_var_name}}")
+ endforeach()
+ endforeach()
+endfunction()
+
+# Saves the list of configs for which flag manipulation will occur.
+function(qt_internal_get_configs_for_flag_manipulation out_var)
+ set(configs RELEASE RELWITHDEBINFO MINSIZEREL DEBUG)
+
+ # Opt into additional non-standard configs for flag removal only.
+ if(QT_ADDITIONAL_OPTIMIZATION_FLAG_CONFIGS)
+ list(APPEND configs ${QT_ADDITIONAL_OPTIMIZATION_FLAG_CONFIGS})
+ endif()
+
+ set(${out_var} "${configs}" PARENT_SCOPE)
+endfunction()
+
+# Saves the list of target link types for which flag manipulation will occur.
+function(qt_internal_get_target_link_types_for_flag_manipulation out_var)
+ set(target_link_types EXE SHARED MODULE STATIC)
+ set(${out_var} "${target_link_types}" PARENT_SCOPE)
+endfunction()
+
+# Saves list of enabled languages for which it is safe to manipulate compilation flags.
+function(qt_internal_get_enabled_languages_for_flag_manipulation out_var)
+ # Limit flag modification to c-like code. We don't want to accidentally add incompatible
+ # flags to MSVC's RC or Swift.
+ set(languages_to_process ASM C CXX OBJC OBJCXX)
+ get_property(globally_enabled_languages GLOBAL PROPERTY ENABLED_LANGUAGES)
+ set(enabled_languages "")
+ foreach(lang ${languages_to_process})
+ if(lang IN_LIST globally_enabled_languages)
+ list(APPEND enabled_languages "${lang}")
+ endif()
+ endforeach()
+ set(${out_var} "${enabled_languages}" PARENT_SCOPE)
+endfunction()
+
+# Helper function used to update compiler and linker flags further below
+function(qt_internal_replace_flags_impl flag_var_name match_string replace_string IN_CACHE)
+ # This must come before cache variable modification because setting the
+ # cache variable with FORCE will overwrite the non-cache variable, but
+ # we need to use the original value on entry to this function.
+
+ # Handle an empty input string and an empty match string as a set().
+ if(match_string STREQUAL "" AND "${${flag_var_name}}" STREQUAL "")
+ set(${flag_var_name} "${replace_string}" PARENT_SCOPE)
+ else()
+ string(REPLACE
+ "${match_string}" "${replace_string}"
+ ${flag_var_name} "${${flag_var_name}}")
+ string(STRIP "${${flag_var_name}}" ${flag_var_name})
+ set(${flag_var_name} "${${flag_var_name}}" PARENT_SCOPE)
+ endif()
+
+ if(IN_CACHE)
+ # We must not use the non-cache variable's value because toolchain files
+ # might be appending things to the cache variable's value and storing it
+ # in a non-cache variable (e.g. Android NDK toolchain file does this).
+ # Work exclusively on cache variable value only.
+ get_property(help_text CACHE "${flag_var_name}" PROPERTY HELPSTRING)
+
+ # Handle an empty input string and an empty match string as a set().
+ if(match_string STREQUAL "" AND "$CACHE{${flag_var_name}}" STREQUAL "")
+ set(${flag_var_name} "${replace_string}" CACHE STRING "${help_text}" FORCE)
+ else()
+ set(mod_flags "$CACHE{${flag_var_name}}")
+ string(REPLACE
+ "${match_string}" "${replace_string}"
+ mod_flags "${mod_flags}")
+ string(STRIP "${mod_flags}" mod_flags)
+ set(${flag_var_name} "${mod_flags}" CACHE STRING "${help_text}" FORCE)
+ endif()
+ endif()
+endfunction()
+
+# Helper function used to update compiler and linker flags further below
+function(qt_internal_remove_flags_impl flag_var_name flag_values IN_CACHE)
+ cmake_parse_arguments(arg "REGEX" "" "" ${ARGN})
+ set(replace_type REPLACE)
+ if(arg_REGEX)
+ list(PREPEND replace_type REGEX)
+ endif()
+
+ # This must come before cache variable modification because setting the
+ # cache variable with FORCE will overwrite the non-cache variable in this
+ # function scope, but we need to use the original value before that change.
+ foreach(flag_value IN LISTS flag_values)
+ string(${replace_type} "${flag_value}" " " ${flag_var_name} "${${flag_var_name}}")
+ endforeach()
+ string(STRIP "${${flag_var_name}}" ${flag_var_name})
+ set(${flag_var_name} "${${flag_var_name}}" PARENT_SCOPE)
+
+ if(IN_CACHE)
+ # We must not use the non-cache variable's value because toolchain files
+ # might be appending things to the cache variable's value and storing it
+ # in a non-cache variable (e.g. Android NDK toolchain file does this).
+ # Work exclusively on cache variable value only.
+ set(mod_flags $CACHE{${flag_var_name}})
+ foreach(flag_value IN LISTS flag_values)
+ string(${replace_type} "${flag_value}" " " mod_flags "${mod_flags}")
+ endforeach()
+ string(STRIP "${mod_flags}" mod_flags)
+ get_property(help_text CACHE ${flag_var_name} PROPERTY HELPSTRING)
+ set(${flag_var_name} "${mod_flags}" CACHE STRING "${help_text}" FORCE)
+ endif()
+endfunction()
+
+# Helper function used to update compiler and linker flags further below
+function(qt_internal_add_flags_impl flag_var_name flags IN_CACHE)
+ # This must come before cache variable modification because setting the
+ # cache variable with FORCE will overwrite the non-cache variable, but
+ # we need to use the original value on entry to this function.
+ set(${flag_var_name} "${${flag_var_name}} ${flags}")
+ string(STRIP "${${flag_var_name}}" ${flag_var_name})
+ set(${flag_var_name} "${${flag_var_name}}" PARENT_SCOPE)
+
+ if(IN_CACHE)
+ # We must not use the non-cache variable's value because toolchain files
+ # might be appending things to the cache variable's value and storing it
+ # in a non-cache variable (e.g. Android NDK toolchain file does this).
+ # Work exclusively on cache variable value only.
+ set(mod_flags "$CACHE{${flag_var_name}} ${flags}")
+ string(STRIP "${mod_flags}" mod_flags)
+ get_property(help_text CACHE ${flag_var_name} PROPERTY HELPSTRING)
+ set(${flag_var_name} "${mod_flags}" CACHE STRING "${help_text}" FORCE)
+ endif()
+endfunction()
+
+
+# Removes all known compiler optimization flags for the given CONFIGS, for all enabled 'safe'
+# languages. The flag variables are always updated in the calling scope, even if they did not
+# exist beforehand.
+#
+# IN_CACHE - remove them from the corresponding cache variable too. Note that the cache
+# variable may have a different value to the non-cache variable.
+# CONFIGS - should be a list of upper case configs like DEBUG, RELEASE, RELWITHDEBINFO.
+# LANGUAGES - optional list of languages like 'C', 'CXX', for which to remove the flags
+# if not provided, defaults to the list of enabled C-like languages
+function(qt_internal_remove_known_optimization_flags)
+ cmake_parse_arguments(PARSE_ARGV 0 arg
+ "IN_CACHE"
+ ""
+ "CONFIGS;LANGUAGES")
+ _qt_internal_validate_all_args_are_parsed(arg)
+
+ if(NOT arg_CONFIGS)
+ message(FATAL_ERROR
+ "You must specify at least one configuration for which to remove the flags.")
+ endif()
+
+ if(arg_LANGUAGES)
+ set(enabled_languages "${arg_LANGUAGES}")
+ else()
+ qt_internal_get_enabled_languages_for_flag_manipulation(enabled_languages)
+ endif()
+
+ qt_internal_get_all_possible_optimization_flag_values(flag_values)
+ set(configs ${arg_CONFIGS})
+
+ foreach(lang ${enabled_languages})
+ foreach(config ${configs})
+ set(flag_var_name "CMAKE_${lang}_FLAGS_${config}")
+ qt_internal_remove_flags_impl(${flag_var_name} "${flag_values}" "${arg_IN_CACHE}")
+ set(${flag_var_name} "${${flag_var_name}}" PARENT_SCOPE)
+ endforeach()
+ endforeach()
+endfunction()
+
+# Removes specified flags from CMAKE_<LANGUAGES>_FLAGS[_CONFIGS] variables
+#
+# Option Arguments:
+# IN_CACHE
+# Enables flags removal from CACHE
+# REGEX
+# Enables the flag processing as a regular expression.
+#
+# Multi-value Arguments:
+# CONFIGS
+# List of configurations that need to clear flags. Clears all configs by default if not
+# specified.
+#
+# LANGUAGES
+# List of LANGUAGES that need clear flags. Clears all languages by default if not
+# specified.
+function(qt_internal_remove_compiler_flags flags)
+ cmake_parse_arguments(PARSE_ARGV 1 arg
+ "IN_CACHE;REGEX"
+ ""
+ "CONFIGS;LANGUAGES"
+ )
+ _qt_internal_validate_all_args_are_parsed(arg)
+
+ if("${flags}" STREQUAL "")
+ message(WARNING "qt_internal_remove_compiler_flags was called without any flags specified.")
+ return()
+ endif()
+
+ if(arg_LANGUAGES)
+ set(languages "${arg_LANGUAGES}")
+ else()
+ qt_internal_get_enabled_languages_for_flag_manipulation(languages)
+ endif()
+
+ if(arg_CONFIGS)
+ set(configs "${arg_CONFIGS}")
+ else()
+ qt_internal_get_configs_for_flag_manipulation(configs)
+ endif()
+
+ if(arg_REGEX)
+ list(APPEND extra_options "REGEX")
+ endif()
+
+ foreach(lang ${languages})
+ set(flag_var_name "CMAKE_${lang}_FLAGS")
+ qt_internal_remove_flags_impl(${flag_var_name}
+ "${flags}"
+ "${arg_IN_CACHE}"
+ ${extra_options}
+ )
+ set(${flag_var_name} "${${flag_var_name}}" PARENT_SCOPE)
+ foreach(config ${configs})
+ set(flag_var_name "CMAKE_${lang}_FLAGS_${config}")
+ qt_internal_remove_flags_impl(${flag_var_name}
+ "${flags}"
+ "${arg_IN_CACHE}"
+ ${extra_options}
+ )
+ set(${flag_var_name} "${${flag_var_name}}" PARENT_SCOPE)
+ endforeach()
+ endforeach()
+endfunction()
+
+# Adds compiler flags for the given CONFIGS in the calling scope. Can also update the cache
+# if asked to do so. The flag variables are always updated in the calling scope, even if they
+# did not exist beforehand.
+#
+# FLAGS - should be a single string of flags separated by spaces.
+# IN_CACHE - add them to the corresponding cache variable too. Note that the cache
+# variable may have a different value to the non-cache variable.
+# CONFIGS - should be a list of upper case configs like DEBUG, RELEASE, RELWITHDEBINFO.
+# LANGUAGES - optional list of languages like 'C', 'CXX', for which to add the flags
+# if not provided, defaults to the list of enabled C-like languages
+function(qt_internal_add_compiler_flags)
+ cmake_parse_arguments(PARSE_ARGV 0 arg
+ "IN_CACHE"
+ "FLAGS"
+ "CONFIGS;LANGUAGES")
+ _qt_internal_validate_all_args_are_parsed(arg)
+
+ if(NOT arg_CONFIGS)
+ message(FATAL_ERROR
+ "You must specify at least one configuration for which to add the flags.")
+ endif()
+ if(NOT arg_FLAGS)
+ message(FATAL_ERROR "You must specify at least one flag to add.")
+ endif()
+
+ if(arg_LANGUAGES)
+ set(enabled_languages "${arg_LANGUAGES}")
+ else()
+ qt_internal_get_enabled_languages_for_flag_manipulation(enabled_languages)
+ endif()
+
+ set(configs ${arg_CONFIGS})
+
+ foreach(lang ${enabled_languages})
+ foreach(config ${configs})
+ set(flag_var_name "CMAKE_${lang}_FLAGS_${config}")
+ qt_internal_add_flags_impl(${flag_var_name} "${arg_FLAGS}" "${arg_IN_CACHE}")
+ set(${flag_var_name} "${${flag_var_name}}" PARENT_SCOPE)
+ endforeach()
+ endforeach()
+endfunction()
+
+# Convenience function that adds compiler flags for all release configurations.
+# The flag variables are always updated in the calling scope, even if they did not
+# exist beforehand.
+#
+# FLAGS - should be a single string of flags separated by spaces.
+# IN_CACHE - add them to the corresponding cache variable too. Note that the cache
+# variable may have a different value to the non-cache variable.
+# LANGUAGES - optional list of languages like 'C', 'CXX', for which to add the flags
+# if not provided, defaults to the list of enabled C-like languages
+function(qt_internal_add_compiler_flags_for_release_configs)
+ cmake_parse_arguments(PARSE_ARGV 0 arg
+ "IN_CACHE"
+ "FLAGS"
+ "LANGUAGES")
+ _qt_internal_validate_all_args_are_parsed(arg)
+
+ set(args "")
+
+ if(arg_LANGUAGES)
+ set(enabled_languages "${arg_LANGUAGES}")
+ else()
+ qt_internal_get_enabled_languages_for_flag_manipulation(enabled_languages)
+ endif()
+
+ set(configs RELEASE RELWITHDEBINFO MINSIZEREL)
+
+ list(APPEND args CONFIGS ${configs})
+
+ if(arg_FLAGS)
+ list(APPEND args FLAGS "${arg_FLAGS}")
+ endif()
+
+ if(arg_IN_CACHE)
+ list(APPEND args IN_CACHE)
+ endif()
+ list(APPEND args LANGUAGES ${enabled_languages})
+
+ qt_internal_add_compiler_flags(${args})
+
+ foreach(lang ${enabled_languages})
+ foreach(config ${configs})
+ set(flag_var_name "CMAKE_${lang}_FLAGS_${config}")
+ set("${flag_var_name}" "${${flag_var_name}}" PARENT_SCOPE)
+ endforeach()
+ endforeach()
+endfunction()
+
+# Convenience function that replaces all optimization flags with the equivalent of '-O3'
+# (optimize_full) flag for all release configs.
+#
+# This is the equivalent of qmake's CONFIG += optimize_full.
+# It is meant to be called in a subdirectory scope to enable full optimizations for a particular
+# Qt module, like Core or Gui.
+function(qt_internal_add_optimize_full_flags)
+ cmake_parse_arguments(PARSE_ARGV 0 arg
+ "IN_CACHE"
+ ""
+ "")
+ _qt_internal_validate_all_args_are_parsed(arg)
+
+ # QT_USE_DEFAULT_CMAKE_OPTIMIZATION_FLAGS disables forced full optimization.
+ if(QT_USE_DEFAULT_CMAKE_OPTIMIZATION_FLAGS)
+ return()
+ endif()
+
+ # Assume that FEATURE_optimize_full has higher priority. But if FEATURE_optimize_full is OFF,
+ # flags are set by FEATURE_optimize_size should remain unchanged.
+ if(QT_FEATURE_optimize_size AND NOT QT_FEATURE_optimize_full)
+ return()
+ endif()
+
+ set(args "")
+ if(arg_IN_CACHE)
+ list(APPEND args IN_CACHE)
+ endif()
+
+ qt_internal_get_enabled_languages_for_flag_manipulation(enabled_languages)
+ set(configs RELEASE RELWITHDEBINFO)
+ if(QT_FEATURE_optimize_full) # Assume that FEATURE_optimize_full has higher priority.
+ list(APPEND configs MINSIZEREL)
+ endif()
+
+ qt_internal_remove_known_optimization_flags(${args} CONFIGS ${configs})
+
+ # If the respective compiler doesn't have optimize_full flags, use regular optimization flags.
+ # Mainly MSVC.
+ qt_internal_get_optimize_full_flags(optimize_full_flags)
+ list(APPEND args FLAGS "${optimize_full_flags}")
+
+ qt_internal_add_compiler_flags_for_release_configs(${args})
+
+ foreach(lang ${enabled_languages})
+ foreach(config ${configs})
+ set(flag_var_name "CMAKE_${lang}_FLAGS_${config}")
+ set("${flag_var_name}" "${${flag_var_name}}" PARENT_SCOPE)
+ endforeach()
+ endforeach()
+endfunction()
+
+# Convenience function to replace a compiler flag with another one, for the given configurations
+# for all enabled 'safe' languages.
+# Essentially a glorified string(REPLACE).
+# Can be used to remove compiler flags.
+# The flag variables are always updated in the calling scope, even if they did not
+# exist beforehand.
+#
+# match_string - string to match
+# replace_string - replacement string
+# IN_CACHE - replace them in the corresponding cache variable too. Note that the cache
+# variable may have a different value to the non-cache variable.
+# CONFIGS - should be a list of upper case configs like DEBUG, RELEASE, RELWITHDEBINFO.
+# LANGUAGES - optional list of languages like 'C', 'CXX', for which to replace the flags
+# if not provided, defaults to the list of enabled C-like languages
+function(qt_internal_replace_compiler_flags match_string replace_string)
+ cmake_parse_arguments(PARSE_ARGV 2 arg
+ "IN_CACHE"
+ ""
+ "CONFIGS;LANGUAGES")
+ _qt_internal_validate_all_args_are_parsed(arg)
+
+ if(NOT arg_CONFIGS)
+ message(FATAL_ERROR
+ "You must specify at least one configuration for which to replace the flags.")
+ endif()
+
+ if(arg_LANGUAGES)
+ set(enabled_languages "${arg_LANGUAGES}")
+ else()
+ qt_internal_get_enabled_languages_for_flag_manipulation(enabled_languages)
+ endif()
+ set(configs ${arg_CONFIGS})
+
+ foreach(lang ${enabled_languages})
+ foreach(config ${configs})
+ set(flag_var_name "CMAKE_${lang}_FLAGS_${config}")
+ qt_internal_replace_flags_impl(${flag_var_name}
+ "${match_string}" "${replace_string}" "${arg_IN_CACHE}")
+ set(${flag_var_name} "${${flag_var_name}}" PARENT_SCOPE)
+ endforeach()
+ endforeach()
+endfunction()
+
+# Convenience function to add linker flags, for the given configurations and target link types.
+# The flag variables are always updated in the calling scope, even if they did not exist beforehand.
+#
+# FLAGS - should be a single string of flags separated by spaces.
+# IN_CACHE - add them to the corresponding cache variable too. Note that the cache
+# variable may have a different value to the non-cache variable.
+# CONFIGS - should be a list of upper case configs like DEBUG, RELEASE, RELWITHDEBINFO.
+# TYPES - should be a list of target link types as expected by CMake's
+# CMAKE_<LINKER_TYPE>_LINKER_FLAGS_<CONFIG> cache variable.
+# e.g EXE, MODULE, SHARED, STATIC.
+function(qt_internal_add_linker_flags)
+ cmake_parse_arguments(PARSE_ARGV 0 arg
+ "IN_CACHE"
+ "FLAGS"
+ "CONFIGS;TYPES")
+ _qt_internal_validate_all_args_are_parsed(arg)
+
+ if(NOT arg_TYPES)
+ message(FATAL_ERROR
+ "You must specify at least one linker target type for which to add the flags.")
+ endif()
+ if(NOT arg_CONFIGS)
+ message(FATAL_ERROR
+ "You must specify at least one configuration for which to add the flags.")
+ endif()
+ if(NOT arg_FLAGS)
+ message(FATAL_ERROR "You must specify at least one flag to add.")
+ endif()
+
+ set(configs ${arg_CONFIGS})
+ set(target_link_types ${arg_TYPES})
+
+ foreach(config ${configs})
+ foreach(t ${target_link_types})
+ set(flag_var_name "CMAKE_${t}_LINKER_FLAGS_${config}")
+ qt_internal_add_flags_impl(${flag_var_name} "${arg_FLAGS}" "${arg_IN_CACHE}")
+ set(${flag_var_name} "${${flag_var_name}}" PARENT_SCOPE)
+ endforeach()
+ endforeach()
+endfunction()
+
+# Convenience function to replace a linker flag with another one, for the given configurations
+# and target link types.
+# Essentially a glorified string(REPLACE).
+# Can be used to remove linker flags.
+# The flag variables are always updated in the calling scope, even if they did not exist beforehand.
+#
+# match_string - string to match
+# replace_string - replacement string
+# IN_CACHE - replace them in the corresponding cache variable too. Note that the cache
+# variable may have a different value to the non-cache variable.
+# CONFIGS - should be a list of upper case configs like DEBUG, RELEASE, RELWITHDEBINFO.
+# TYPES - should be a list of target link types as expected by CMake's
+# CMAKE_<LINKER_TYPE>_LINKER_FLAGS_<CONFIG> cache variable.
+# e.g EXE, MODULE, SHARED, STATIC.
+function(qt_internal_replace_linker_flags match_string replace_string)
+ cmake_parse_arguments(PARSE_ARGV 2 arg
+ "IN_CACHE"
+ ""
+ "CONFIGS;TYPES")
+ _qt_internal_validate_all_args_are_parsed(arg)
+
+ if(NOT arg_TYPES)
+ message(FATAL_ERROR
+ "You must specify at least one linker target type for which to replace the flags.")
+ endif()
+ if(NOT arg_CONFIGS)
+ message(FATAL_ERROR
+ "You must specify at least one configuration for which to replace the flags.")
+ endif()
+
+ set(configs ${arg_CONFIGS})
+ set(target_link_types ${arg_TYPES})
+
+ foreach(config ${configs})
+ foreach(t ${target_link_types})
+ set(flag_var_name "CMAKE_${t}_LINKER_FLAGS_${config}")
+ qt_internal_replace_flags_impl(${flag_var_name}
+ "${match_string}" "${replace_string}" "${arg_IN_CACHE}")
+ set(${flag_var_name} "${${flag_var_name}}" PARENT_SCOPE)
+ endforeach()
+ endforeach()
+endfunction()
+
+# This function finds the optimization flags set by the default CMake platform modules or toolchain
+# files and replaces them with flags that Qt qmake builds expect, for all the usual
+# CMAKE_BUILD_TYPE configurations.
+# This normalizes things like using -O2 for both Release and RelWithDebInfo, among other compilation
+# flags. Also some linker flags specific to MSVC.
+# See QTBUG-85992 for details.
+#
+# Note that both the calling scope and the CMake cache are updated.
+function(qt_internal_set_up_config_optimizations_like_in_qmake)
+ # Allow opt out.
+ if(QT_USE_DEFAULT_CMAKE_OPTIMIZATION_FLAGS)
+ return()
+ endif()
+
+ qt_internal_get_enabled_languages_for_flag_manipulation(enabled_languages)
+ qt_internal_get_configs_for_flag_manipulation(configs)
+ qt_internal_get_target_link_types_for_flag_manipulation(target_link_types)
+
+ # You can set QT_DEBUG_OPTIMIZATION_FLAGS to see the before and after results.
+ if(QT_DEBUG_OPTIMIZATION_FLAGS)
+ message(STATUS "")
+ message(STATUS "DEBUG: Original CMake optimization flags.\n")
+ qt_internal_print_optimization_flags_values_helper("${enabled_languages}" "${configs}"
+ "${target_link_types}")
+ endif()
+
+ # Remove known optimization flags.
+ qt_internal_remove_known_optimization_flags(IN_CACHE CONFIGS ${configs})
+
+ # Re-add optimization flags as per qmake mkspecs.
+ foreach(lang ${enabled_languages})
+ foreach(config ${configs})
+ set(flag_var_name "CMAKE_${lang}_FLAGS_${config}")
+ set(value_to_append "")
+
+ # Release and RelWithDebInfo should get the same base optimization flags.
+ if(config STREQUAL "RELEASE" AND QT_CFLAGS_OPTIMIZE)
+ set(value_to_append "${QT_CFLAGS_OPTIMIZE}")
+ elseif(config STREQUAL "RELWITHDEBINFO" AND QT_CFLAGS_OPTIMIZE)
+ set(value_to_append "${QT_CFLAGS_OPTIMIZE}")
+
+ # MinSizeRel should get the optimize size flag if available, otherwise the regular
+ # release flag.
+ elseif(config STREQUAL "MINSIZEREL")
+ if(QT_CFLAGS_OPTIMIZE_SIZE)
+ set(value_to_append "${QT_CFLAGS_OPTIMIZE_SIZE}")
+ else()
+ set(value_to_append "${QT_CFLAGS_OPTIMIZE}")
+ endif()
+ endif()
+
+ # Debug should get the OPTIMIZE_DEBUG flag if the respective feature is ON.
+ if(config STREQUAL "DEBUG" AND QT_FEATURE_optimize_debug)
+ set(value_to_append "${QT_CFLAGS_OPTIMIZE_DEBUG}")
+ endif()
+
+ set(configs_for_optimize_size RELEASE RELWITHDEBINFO)
+ if(QT_FEATURE_optimize_size AND config IN_LIST configs_for_optimize_size)
+ set(value_to_append "${QT_CFLAGS_OPTIMIZE_SIZE}")
+ endif()
+
+ # Check if the fake 'optimize_full' feature is enabled.
+ # Use the max optimization level flag for all release configs, effectively
+ # overriding any previous setting.
+ set(configs_for_optimize RELEASE RELWITHDEBINFO MINSIZEREL)
+ if(QT_FEATURE_optimize_full AND config IN_LIST configs_for_optimize)
+ qt_internal_get_optimize_full_flags(optimize_full_flags)
+ set(value_to_append "${optimize_full_flags}")
+ endif()
+
+ # Assign value to the cache entry.
+ if(value_to_append)
+ qt_internal_add_flags_impl(${flag_var_name} "${value_to_append}" TRUE)
+ # Delay updating the calling scope's variables to the end of this function
+ endif()
+
+ endforeach()
+ endforeach()
+
+ if(MSVC)
+ # Handle MSVC /INCREMENTAL flag which should not be enabled for Release configurations.
+ # First remove them from all configs, and re-add INCREMENTAL for Debug only.
+ set(flag_values "/INCREMENTAL:YES" "/INCREMENTAL:NO" "/INCREMENTAL")
+ foreach(flag_value ${flag_values})
+ qt_internal_replace_linker_flags(
+ "${flag_value}" ""
+ CONFIGS ${configs}
+ TYPES ${target_link_types}
+ IN_CACHE)
+ endforeach()
+
+ set(flag_value "/INCREMENTAL:NO")
+ qt_internal_add_linker_flags(
+ FLAGS "${flag_value}"
+ CONFIGS RELEASE RELWITHDEBINFO MINSIZEREL
+ TYPES EXE SHARED MODULE # when linking static libraries, link.exe can't recognize this parameter, clang-cl will error out.
+ IN_CACHE)
+ qt_internal_remove_compiler_flags("(^| )/EH[scra-]*( |$)" LANGUAGES CXX CONFIGS ${configs} IN_CACHE REGEX)
+ endif()
+
+ # Allow opting into generating debug info in object files with a fake feature.
+ # This would allow us to enable caching with sccache.
+ # See QTQAINFRA-3934 for details.
+ if(MSVC AND QT_FEATURE_msvc_obj_debug_info)
+ qt_internal_replace_compiler_flags(
+ "/Zi" "/Z7"
+ CONFIGS RELWITHDEBINFO DEBUG
+ TYPES ${target_link_types}
+ IN_CACHE)
+ endif()
+
+ # Legacy Android toolchain file adds the `-g` flag to CMAKE_<LANG>_FLAGS, as a
+ # result, our release build ends up containing debug symbols. To avoid that, we
+ # remove the flag from CMAKE_<LANGL>_FLAGS and add
+ # it to CMAKE_<LANG>_FLAGS_DEBUG.
+ #
+ # Note:
+ # The new `android.toolchain.cmake` file does not have this problem, but
+ # it has other issues, eg., https://github.com/android/ndk/issues/1693, so we
+ # cannot force it. While we do load the new toolchain, it automatically falls
+ # back to the legacy toolchain, ie., `android-legacy.toolchain.cmake` which
+ # has the problem described above.
+ #
+ # Todo:
+ # When the new toolchain is fixed, and it doesn't fall back to the legacy
+ # anymore by default, then we should be able to remove this workaround.
+ if(ANDROID AND ANDROID_COMPILER_FLAGS MATCHES "(^| )-g")
+ qt_internal_remove_compiler_flags("-g")
+ qt_internal_add_compiler_flags(FLAGS "-g" CONFIGS DEBUG RELWITHDEBINFO)
+ endif()
+
+ # Update all relevant flags in the calling scope
+ foreach(lang ${enabled_languages})
+ set(flag_var_name "CMAKE_${lang}_FLAGS")
+ set(${flag_var_name} "${${flag_var_name}}" PARENT_SCOPE)
+
+ foreach(config ${configs})
+ set(flag_var_name "CMAKE_${lang}_FLAGS_${config}")
+ set(${flag_var_name} "${${flag_var_name}}" PARENT_SCOPE)
+ endforeach()
+ endforeach()
+
+ foreach(t ${target_link_types})
+ set(flag_var_name "CMAKE_${t}_LINKER_FLAGS")
+ set(${flag_var_name} "${${flag_var_name}}" PARENT_SCOPE)
+
+ foreach(config ${configs})
+ set(flag_var_name "CMAKE_${t}_LINKER_FLAGS_${config}")
+ set(${flag_var_name} "${${flag_var_name}}" PARENT_SCOPE)
+ endforeach()
+ endforeach()
+
+ if(QT_DEBUG_OPTIMIZATION_FLAGS)
+ message(STATUS "")
+ message(STATUS "DEBUG: Modified optimization flags to mirror qmake mkspecs.\n")
+ qt_internal_print_optimization_flags_values_helper("${enabled_languages}" "${configs}"
+ "${target_link_types}")
+ endif()
+endfunction()
diff --git a/cmake/QtFrameworkHelpers.cmake b/cmake/QtFrameworkHelpers.cmake
new file mode 100644
index 0000000000..750caf2cb8
--- /dev/null
+++ b/cmake/QtFrameworkHelpers.cmake
@@ -0,0 +1,228 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+macro(qt_find_apple_system_frameworks)
+ if(APPLE)
+ qt_internal_find_apple_system_framework(FWAppKit AppKit)
+ qt_internal_find_apple_system_framework(FWCFNetwork CFNetwork)
+ qt_internal_find_apple_system_framework(FWAssetsLibrary AssetsLibrary)
+ qt_internal_find_apple_system_framework(FWPhotos Photos)
+ qt_internal_find_apple_system_framework(FWAudioToolbox AudioToolbox)
+ qt_internal_find_apple_system_framework(FWApplicationServices ApplicationServices)
+ qt_internal_find_apple_system_framework(FWCarbon Carbon)
+ qt_internal_find_apple_system_framework(FWCoreFoundation CoreFoundation)
+ qt_internal_find_apple_system_framework(FWCoreServices CoreServices)
+ qt_internal_find_apple_system_framework(FWCoreGraphics CoreGraphics)
+ qt_internal_find_apple_system_framework(FWCoreText CoreText)
+ qt_internal_find_apple_system_framework(FWCoreVideo CoreVideo)
+ qt_internal_find_apple_system_framework(FWCryptoTokenKit CryptoTokenKit)
+ qt_internal_find_apple_system_framework(FWDiskArbitration DiskArbitration)
+ qt_internal_find_apple_system_framework(FWFoundation Foundation)
+ qt_internal_find_apple_system_framework(FWIOBluetooth IOBluetooth)
+ qt_internal_find_apple_system_framework(FWIOKit IOKit)
+ qt_internal_find_apple_system_framework(FWIOSurface IOSurface)
+ qt_internal_find_apple_system_framework(FWImageIO ImageIO)
+ qt_internal_find_apple_system_framework(FWMetal Metal)
+ qt_internal_find_apple_system_framework(FWMobileCoreServices MobileCoreServices)
+ qt_internal_find_apple_system_framework(FWQuartzCore QuartzCore)
+ qt_internal_find_apple_system_framework(FWSecurity Security)
+ qt_internal_find_apple_system_framework(FWSystemConfiguration SystemConfiguration)
+ qt_internal_find_apple_system_framework(FWUIKit UIKit)
+ qt_internal_find_apple_system_framework(FWCoreLocation CoreLocation)
+ qt_internal_find_apple_system_framework(FWCoreMotion CoreMotion)
+ qt_internal_find_apple_system_framework(FWWatchKit WatchKit)
+ qt_internal_find_apple_system_framework(FWGameController GameController)
+ qt_internal_find_apple_system_framework(FWCoreBluetooth CoreBluetooth)
+ qt_internal_find_apple_system_framework(FWAVFoundation AVFoundation)
+ qt_internal_find_apple_system_framework(FWContacts Contacts)
+ qt_internal_find_apple_system_framework(FWEventKit EventKit)
+ qt_internal_find_apple_system_framework(FWHealthKit HealthKit)
+ qt_internal_find_apple_system_framework(FWUniformTypeIdentifiers UniformTypeIdentifiers)
+ endif()
+endmacro()
+
+# Given framework_name == 'IOKit', sets non-cache variable 'FWIOKit' to '-framework IOKit' in
+# the calling directory scope if the framework is found, or 'IOKit-NOTFOUND'.
+function(qt_internal_find_apple_system_framework out_var framework_name)
+ # To avoid creating many FindFoo.cmake files for each apple system framework, populate each
+ # FWFoo variable with '-framework Foo' instead of an absolute path to the framework. This makes
+ # the generated CMake target files relocatable, so that Xcode SDK absolute paths are not
+ # hardcoded, like with Xcode11.app on the CI.
+ # We might revisit this later.
+ set(cache_var_name "${out_var}Internal")
+
+ find_library(${cache_var_name} "${framework_name}")
+
+ if(${cache_var_name} AND ${cache_var_name} MATCHES ".framework$")
+ set(${out_var} "-framework ${framework_name}" PARENT_SCOPE)
+ else()
+ set(${out_var} "${out_var}-NOTFOUND" PARENT_SCOPE)
+ endif()
+endfunction()
+
+# Copy header files to the framework's Headers directory
+# Use this function for header files that
+# - are not added as source files to the target
+# - are not marked as PUBLIC_HEADER
+# - or are private and supposed to end up in the 6.7.8/QtXYZ/private subdir.
+function(qt_copy_framework_headers target)
+ get_target_property(is_fw ${target} FRAMEWORK)
+ if(NOT "${is_fw}")
+ return()
+ endif()
+
+ set(options)
+ set(oneValueArgs)
+ set(multiValueArgs PUBLIC PRIVATE QPA RHI SSG)
+ cmake_parse_arguments(arg "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
+
+ qt_internal_get_framework_info(fw ${target})
+ get_target_property(output_dir ${target} LIBRARY_OUTPUT_DIRECTORY)
+ set(output_dir_PUBLIC "${output_dir}/${fw_versioned_header_dir}")
+ set(output_dir_PRIVATE "${output_dir}/${fw_private_module_header_dir}/private")
+ set(output_dir_QPA "${output_dir}/${fw_private_module_header_dir}/qpa")
+ set(output_dir_RHI "${output_dir}/${fw_private_module_header_dir}/rhi")
+ set(output_dir_SSG "${output_dir}/${fw_private_module_header_dir}/ssg")
+
+ qt_internal_module_info(module "${target}")
+
+ set(out_files "")
+ set(in_files "")
+ set(out_dirs "")
+ set(copy_commands "")
+ foreach(type IN ITEMS PUBLIC PRIVATE QPA RHI SSG)
+ set(in_files_${type} "")
+ set(fw_output_header_dir "${output_dir_${type}}")
+ list(APPEND out_dirs "${fw_output_header_dir}")
+ foreach(hdr IN LISTS arg_${type})
+ get_filename_component(in_file_path ${hdr} ABSOLUTE)
+ get_filename_component(in_file_name ${hdr} NAME)
+ set(out_file_path "${fw_output_header_dir}/${in_file_name}")
+ list(APPEND out_files ${out_file_path})
+ list(APPEND in_files_${type} "${in_file_path}")
+ endforeach()
+ if(in_files_${type})
+ list(APPEND copy_commands
+ COMMAND ${CMAKE_COMMAND} -E copy ${in_files_${type}} "${fw_output_header_dir}")
+ list(APPEND in_files ${in_files_${type}})
+ endif()
+ endforeach()
+
+ list(REMOVE_DUPLICATES out_files)
+ list(REMOVE_DUPLICATES in_files)
+
+ set(copy_fw_sync_headers_command
+ "${CMAKE_COMMAND}" -E copy_directory
+ "${module_build_interface_include_dir}/.syncqt_staging"
+ "${output_dir}/${fw_versioned_header_dir}"
+ )
+
+ if(CMAKE_GENERATOR MATCHES "^Ninja")
+ add_custom_command(
+ OUTPUT "${output_dir}/${fw_versioned_header_dir}"
+ DEPENDS ${target}_sync_headers
+ COMMAND ${copy_fw_sync_headers_command}
+ VERBATIM
+ )
+ add_custom_target(${target}_copy_fw_sync_headers
+ DEPENDS "${output_dir}/${fw_versioned_header_dir}")
+ else()
+ add_custom_target(${target}_copy_fw_sync_headers
+ COMMAND ${copy_fw_sync_headers_command})
+ endif()
+
+ if(out_files)
+ add_custom_command(
+ OUTPUT ${out_files}
+ DEPENDS ${target}_copy_fw_sync_headers ${in_files}
+ COMMAND
+ ${CMAKE_COMMAND} -E make_directory ${out_dirs}
+ ${copy_commands}
+ VERBATIM
+ COMMENT "Copy the ${target} header files to the framework directory"
+ )
+ set_property(TARGET ${target} APPEND PROPERTY
+ QT_COPIED_FRAMEWORK_HEADERS "${out_files}")
+ endif()
+endfunction()
+
+function(qt_internal_generate_fake_framework_header target)
+ # Hack to create the "Headers" symlink in the framework:
+ # Create a fake header file and copy it into the framework by marking it as PUBLIC_HEADER.
+ # CMake now takes care of creating the symlink.
+ set(fake_header "${CMAKE_CURRENT_BINARY_DIR}/${target}_fake_header.h")
+ qt_internal_get_main_cmake_configuration(main_config)
+ file(GENERATE OUTPUT "${fake_header}" CONTENT "// ignore this file\n"
+ CONDITION "$<CONFIG:${main_config}>")
+ target_sources(${target} PRIVATE "${fake_header}")
+ set_source_files_properties("${fake_header}" PROPERTIES GENERATED ON)
+ set_property(TARGET ${target} APPEND PROPERTY PUBLIC_HEADER "${fake_header}")
+endfunction()
+
+function(qt_finalize_framework_headers_copy target)
+ get_target_property(target_type ${target} TYPE)
+ if(${target_type} STREQUAL "INTERFACE_LIBRARY")
+ return()
+ endif()
+ get_target_property(is_fw ${target} FRAMEWORK)
+ if(NOT "${is_fw}")
+ return()
+ endif()
+ get_target_property(headers ${target} QT_COPIED_FRAMEWORK_HEADERS)
+ if(headers)
+ qt_internal_generate_fake_framework_header(${target})
+
+ # Add a target, e.g. Core_framework_headers, that triggers the header copy.
+ add_custom_target(${target}_framework_headers DEPENDS ${headers})
+ add_dependencies(${target} ${target}_framework_headers)
+ endif()
+endfunction()
+
+# Collects the framework related information and paths from the target properties.
+# Output variables:
+# <out_var>_name framework base name, e.g. 'QtCore'.
+# <out_var>_dir framework base directory, e.g. 'QtCore.framework'.
+# <out_var>_version framework version, e.g. 'A', 'B' etc.
+# <out_var>_bundle_version framework bundle version, same as the PROJECT_VERSION, e.g. '6.0.0'.
+# <out_var>_header_dir top-level header directory, e.g. 'QtCore.framework/Headers'.
+# <out_var>_versioned_header_dir header directory for specific framework version,
+# e.g. 'QtCore.framework/Versions/A/Headers'
+# <out_var>_private_header_dir header directory for the specific framework version and
+# framework bundle version e.g. 'QtCore.framework/Versions/A/Headers/6.0.0'
+# <out_var>_private_module_header_dir private header directory for the specific framework
+# version, framework bundle version and tailing module name, e.g.
+# 'QtCore.framework/Versions/A/Headers/6.0.0/Core'
+function(qt_internal_get_framework_info out_var target)
+ get_target_property(${out_var}_version ${target} FRAMEWORK_VERSION)
+ get_target_property(${out_var}_bundle_version ${target} MACOSX_FRAMEWORK_BUNDLE_VERSION)
+
+ # The module name might be different of the actual target name
+ # and we want to use the Qt'fied module name as a framework identifier.
+ get_target_property(module_interface_name ${target} _qt_module_interface_name)
+ if(module_interface_name)
+ qt_internal_qtfy_target(module ${module_interface_name})
+ else()
+ qt_internal_qtfy_target(module ${target})
+ endif()
+
+ set(${out_var}_name "${module}")
+ set(${out_var}_dir "${${out_var}_name}.framework")
+ set(${out_var}_header_dir "${${out_var}_dir}/Headers")
+ if(UIKIT)
+ # iOS frameworks do not version their headers
+ set(${out_var}_versioned_header_dir "${${out_var}_header_dir}")
+ else()
+ set(${out_var}_versioned_header_dir "${${out_var}_dir}/Versions/${${out_var}_version}/Headers")
+ endif()
+ set(${out_var}_private_header_dir "${${out_var}_versioned_header_dir}/${${out_var}_bundle_version}")
+ set(${out_var}_private_module_header_dir "${${out_var}_private_header_dir}/${module}")
+
+ set(${out_var}_name "${${out_var}_name}" PARENT_SCOPE)
+ set(${out_var}_dir "${${out_var}_dir}" PARENT_SCOPE)
+ set(${out_var}_header_dir "${${out_var}_header_dir}" PARENT_SCOPE)
+ set(${out_var}_version "${${out_var}_version}" PARENT_SCOPE)
+ set(${out_var}_bundle_version "${${out_var}_bundle_version}" PARENT_SCOPE)
+ set(${out_var}_versioned_header_dir "${${out_var}_versioned_header_dir}" PARENT_SCOPE)
+ set(${out_var}_private_header_dir "${${out_var}_private_header_dir}" PARENT_SCOPE)
+ set(${out_var}_private_module_header_dir "${${out_var}_private_module_header_dir}" PARENT_SCOPE)
+endfunction()
diff --git a/cmake/QtGenerateExtPri.cmake b/cmake/QtGenerateExtPri.cmake
index 02ac675d4e..b79ef2b721 100644
--- a/cmake/QtGenerateExtPri.cmake
+++ b/cmake/QtGenerateExtPri.cmake
@@ -1,3 +1,6 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generate a qt_ext_XXX.pri file.
#
# - Replaces occurrences of the build libdir with $$[QT_INSTALL_LIBDIR/get].
diff --git a/cmake/QtGenerateLibHelpers.cmake b/cmake/QtGenerateLibHelpers.cmake
index 06de484ac4..3ffe354fd8 100644
--- a/cmake/QtGenerateLibHelpers.cmake
+++ b/cmake/QtGenerateLibHelpers.cmake
@@ -1,3 +1,6 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Given "/usr/lib/x86_64-linux-gnu/libcups.so"
# Returns "cups" or an empty string if the file is not an absolute library path.
# Aka it strips the "lib" prefix, the .so extension and the base path.
@@ -6,11 +9,12 @@ function(qt_get_library_name_without_prefix_and_suffix out_var file_path)
if(IS_ABSOLUTE "${file_path}")
get_filename_component(basename "${file_path}" NAME_WE)
get_filename_component(ext "${file_path}" EXT)
+ string(TOLOWER "${ext}" ext_lower)
foreach(libsuffix ${LIBRARY_SUFFIXES})
# Handle weird prefix extensions like in the case of
# "/usr/lib/x86_64-linux-gnu/libglib-2.0.so"
# it's ".0.so".
- if(ext MATCHES "^(\\.[0-9]+)*${libsuffix}(\\.[0-9]+)*")
+ if(ext_lower MATCHES "^(\\.[0-9]+)*${libsuffix}(\\.[0-9]+)*")
set(is_linkable_library TRUE)
set(weird_numbered_extension "${CMAKE_MATCH_1}")
break()
@@ -64,6 +68,14 @@ function(qt_transform_absolute_library_paths_to_link_flags out_var library_path_
foreach(library_path ${library_path_list})
qt_get_library_with_link_flag(lib_name_with_link_flag "${library_path}")
if(lib_name_with_link_flag)
+ string(TOLOWER "${IMPLICIT_LINK_DIRECTORIES}" IMPLICIT_LINK_DIRECTORIES_LOWER)
+ get_filename_component(dir "${library_path}" DIRECTORY)
+ string(TOLOWER "${dir}" dir_lower)
+ # If library_path isn't in default link directories, we should add it to link flags.
+ list(FIND IMPLICIT_LINK_DIRECTORIES_LOWER "${dir_lower}" index)
+ if(${index} EQUAL -1)
+ list(APPEND out_list "-L\"${dir}\"")
+ endif()
list(APPEND out_list "${lib_name_with_link_flag}")
else()
list(APPEND out_list "${library_path}")
@@ -88,3 +100,26 @@ function(qt_strip_library_version_suffix out_var file_path)
endif()
set(${out_var} "${final_value}" PARENT_SCOPE)
endfunction()
+
+# Checks if `input_path` is relative to at least one path given in the list of `qt_lib_paths`.
+# Sets TRUE or FALSE in `out_var_is_relative`.
+# Assigns the relative path to `out_var_relative_path` if the path is relative, otherwise assigns
+# the original path.
+function(qt_internal_path_is_relative_to_qt_lib_path
+ input_path qt_lib_paths out_var_is_relative out_var_relative_path)
+ set(is_relative "FALSE")
+ set(relative_path_value "${input_path}")
+
+ foreach(qt_lib_path ${qt_lib_paths})
+ file(RELATIVE_PATH relative_path "${qt_lib_path}" "${input_path}")
+ if(IS_ABSOLUTE "${relative_path}" OR (relative_path MATCHES "^\\.\\."))
+ set(is_relative "FALSE")
+ else()
+ set(is_relative "TRUE")
+ set(relative_path_value "${relative_path}")
+ break()
+ endif()
+ endforeach()
+ set(${out_var_is_relative} "${is_relative}" PARENT_SCOPE)
+ set(${out_var_relative_path} "${relative_path_value}" PARENT_SCOPE)
+endfunction()
diff --git a/cmake/QtGenerateLibPri.cmake b/cmake/QtGenerateLibPri.cmake
index d4e0d04682..bde42b7723 100644
--- a/cmake/QtGenerateLibPri.cmake
+++ b/cmake/QtGenerateLibPri.cmake
@@ -1,3 +1,6 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generate a qt_lib_XXX.pri file.
#
# This file is to be used in CMake script mode with the following variables set:
@@ -7,6 +10,7 @@
# LIBRARY_SUFFIXES: list of known library extensions, e.g. .so;.a on Linux
# LIBRARY_PREFIXES: list of known library prefies, e.g. the "lib" in "libz" on on Linux
# LINK_LIBRARY_FLAG: flag used to link a shared library to an executable, e.g. -l on UNIX
+# IMPLICIT_LINK_DIRECTORIES: list of implicit linker search paths
#
# QMAKE_LIBS_XXX values are split into QMAKE_LIBS_XXX_DEBUG and QMAKE_LIBS_XXX_RELEASE if
# debug_and_release was detected. The CMake configuration "Debug" is considered for the _DEBUG
@@ -15,6 +19,7 @@
# The library values are transformed from an absolute path into link flags
# aka from "/usr/lib/x86_64-linux-gnu/libcups.so" to "-lcups".
+cmake_policy(SET CMP0007 NEW)
cmake_policy(SET CMP0057 NEW)
# Create a qmake-style list from the passed arguments and store it in ${out_var}.
@@ -62,11 +67,10 @@ foreach(lib ${known_libs})
qt_transform_absolute_library_paths_to_link_flags(value_release "${value_release}")
if(value_debug STREQUAL value_release)
- if(value_debug)
- qmake_list(value_debug ${value_debug})
- string(APPEND content "QMAKE_LIBS_${lib} = ${value_debug}\n")
- endif()
+ qmake_list(value_debug ${value_debug})
+ string(APPEND content "QMAKE_LIBS_${lib} = ${value_debug}\n")
else()
+ string(APPEND content "QMAKE_LIBS_${lib} =\n")
if(value_debug)
qmake_list(value_debug ${value_debug})
string(APPEND content "QMAKE_LIBS_${lib}_DEBUG = ${value_debug}\n")
@@ -88,11 +92,13 @@ foreach(lib ${known_libs})
set(value ${QMAKE_${infix}_${lib}_${cfg}})
if(infix STREQUAL "LIBS")
qt_transform_absolute_library_paths_to_link_flags(value "${value}")
+ elseif("${value}" STREQUAL "")
+ # Do not write empty entries, but ensure to write at least
+ # the QMAKE_LIBS_FOO entry to make the lib 'foo' known.
+ continue()
endif()
- if(value)
- qmake_list(value ${value})
- string(APPEND content "QMAKE_${infix}_${lib} = ${value}\n")
- endif()
+ qmake_list(value ${value})
+ string(APPEND content "QMAKE_${infix}_${lib} = ${value}\n")
endforeach()
endforeach()
file(WRITE "${OUT_FILE}" "${content}")
diff --git a/cmake/QtGenerateVersionScript.cmake b/cmake/QtGenerateVersionScript.cmake
new file mode 100644
index 0000000000..3e856169fe
--- /dev/null
+++ b/cmake/QtGenerateVersionScript.cmake
@@ -0,0 +1,15 @@
+cmake_minimum_required(VERSION 3.16)
+
+if(EXISTS "${PRIVATE_CONTENT_FILE}")
+ file(READ "${PRIVATE_CONTENT_FILE}" PRIVATE_CONTENT)
+endif()
+
+if(NOT EXISTS "${IN_FILE}")
+ message(FATAL_ERROR "Input file ${IN_FILE} doesn't exists")
+endif()
+
+if(OUT_FILE STREQUAL "")
+ message(FATAL_ERROR "Output file is not specified")
+endif()
+
+configure_file("${IN_FILE}" "${OUT_FILE}" @ONLY)
diff --git a/cmake/QtGlobalStateHelpers.cmake b/cmake/QtGlobalStateHelpers.cmake
new file mode 100644
index 0000000000..2df89486c8
--- /dev/null
+++ b/cmake/QtGlobalStateHelpers.cmake
@@ -0,0 +1,88 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+function(qt_internal_clear_qt_repo_known_modules)
+ set(QT_REPO_KNOWN_MODULES "" CACHE INTERNAL "Known current repo Qt modules" FORCE)
+endfunction()
+
+function(qt_internal_add_qt_repo_known_module)
+ set(QT_REPO_KNOWN_MODULES ${QT_REPO_KNOWN_MODULES} ${ARGN}
+ CACHE INTERNAL "Known current repo Qt modules" FORCE)
+endfunction()
+
+function(qt_internal_get_qt_repo_known_modules out_var)
+ set("${out_var}" "${QT_REPO_KNOWN_MODULES}" PARENT_SCOPE)
+endfunction()
+
+# Gets the list of all known Qt modules both found and that were built as part of the
+# current project.
+function(qt_internal_get_qt_all_known_modules out_var)
+ qt_internal_get_qt_repo_known_modules(repo_known_modules)
+ set(known_modules ${QT_ALL_MODULES_FOUND_VIA_FIND_PACKAGE} ${repo_known_modules})
+ list(REMOVE_DUPLICATES known_modules)
+ set("${out_var}" "${known_modules}" PARENT_SCOPE)
+endfunction()
+
+macro(qt_internal_set_qt_known_plugins)
+ set(QT_KNOWN_PLUGINS ${ARGN} CACHE INTERNAL "Known Qt plugins" FORCE)
+endmacro()
+
+### Global plug-in types handling ###
+# QT_REPO_KNOWN_PLUGIN_TYPES and QT_ALL_PLUGIN_TYPES_FOUND_VIA_FIND_PACKAGE
+# hold a list of plug-in types (e.G. "imageformats;bearer")
+function(qt_internal_clear_qt_repo_known_plugin_types)
+ set(QT_REPO_KNOWN_PLUGIN_TYPES "" CACHE INTERNAL "Known current repo Qt plug-in types" FORCE)
+endfunction()
+
+function(qt_internal_add_plugin_types target plugin_types)
+ # Update the variable containing the list of plugins for the given plugin type
+ foreach(plugin_type ${plugin_types})
+ qt_get_sanitized_plugin_type("${plugin_type}" plugin_type)
+ set_property(TARGET "${target}" APPEND PROPERTY MODULE_PLUGIN_TYPES "${plugin_type}")
+ qt_internal_add_qt_repo_known_plugin_types("${plugin_type}")
+ endforeach()
+
+ # Save the non-sanitized plugin type values for qmake consumption via .pri files.
+ set_property(TARGET "${target}"
+ APPEND PROPERTY QMAKE_MODULE_PLUGIN_TYPES "${plugin_types}")
+
+ # Export the plugin types.
+ get_property(export_properties TARGET ${target} PROPERTY EXPORT_PROPERTIES)
+ if(NOT MODULE_PLUGIN_TYPES IN_LIST export_properties)
+ set_property(TARGET ${target} APPEND PROPERTY
+ EXPORT_PROPERTIES MODULE_PLUGIN_TYPES)
+ endif()
+endfunction()
+
+function(qt_internal_add_qt_repo_known_plugin_types)
+ set(QT_REPO_KNOWN_PLUGIN_TYPES ${QT_REPO_KNOWN_PLUGIN_TYPES} ${ARGN}
+ CACHE INTERNAL "Known current repo Qt plug-in types" FORCE)
+endfunction()
+
+function(qt_internal_get_qt_repo_known_plugin_types out_var)
+ set("${out_var}" "${QT_REPO_KNOWN_PLUGIN_TYPES}" PARENT_SCOPE)
+endfunction()
+
+function(qt_internal_get_qt_all_known_plugin_types out_var)
+ qt_internal_get_qt_repo_known_plugin_types(repo_known_plugin_types)
+ set(known ${QT_ALL_PLUGIN_TYPES_FOUND_VIA_FIND_PACKAGE} ${repo_known_plugin_types})
+ list(REMOVE_DUPLICATES known)
+ set("${out_var}" "${known}" PARENT_SCOPE)
+endfunction()
+
+macro(qt_internal_append_known_modules_with_tools module)
+ if(NOT ${module} IN_LIST QT_KNOWN_MODULES_WITH_TOOLS)
+ set(QT_KNOWN_MODULES_WITH_TOOLS "${QT_KNOWN_MODULES_WITH_TOOLS};${module}"
+ CACHE INTERNAL "Known Qt modules with tools" FORCE)
+ set(QT_KNOWN_MODULE_${module}_TOOLS ""
+ CACHE INTERNAL "Known Qt module ${module} tools" FORCE)
+ endif()
+endmacro()
+
+macro(qt_internal_append_known_module_tool module tool)
+ if(NOT ${tool} IN_LIST QT_KNOWN_MODULE_${module}_TOOLS)
+ list(APPEND QT_KNOWN_MODULE_${module}_TOOLS "${tool}")
+ set(QT_KNOWN_MODULE_${module}_TOOLS "${QT_KNOWN_MODULE_${module}_TOOLS}"
+ CACHE INTERNAL "Known Qt module ${module} tools" FORCE)
+ endif()
+endmacro()
diff --git a/cmake/QtHeadersClean.cmake b/cmake/QtHeadersClean.cmake
new file mode 100644
index 0000000000..f47ac1754c
--- /dev/null
+++ b/cmake/QtHeadersClean.cmake
@@ -0,0 +1,282 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+# Add a custom ${module_target}_headersclean_check target that builds each header in
+# ${module_headers} with a custom set of defines. This makes sure our public headers
+# are self-contained, and also compile with more strict compiler options.
+function(qt_internal_add_headersclean_target module_target module_headers)
+ if(INPUT_headersclean AND WASM)
+ message(FATAL_ERROR "The headersclean targets are not supported on WASM platform.")
+ endif()
+
+ get_target_property(no_headersclean_check ${module_target} _qt_no_headersclean_check)
+ if(no_headersclean_check)
+ return()
+ endif()
+
+ set(hclean_headers "")
+ foreach(header IN LISTS module_headers)
+ get_filename_component(header_name "${header}" NAME)
+ if(header_name MATCHES "^q[^_]+\\.h$" AND NOT header_name MATCHES ".*(global|exports)\\.h")
+ list(APPEND hclean_headers "${header}")
+ endif()
+ endforeach()
+
+ # Make sure that the header compiles with our strict options
+ set(hcleanDEFS -DQT_NO_CAST_TO_ASCII
+ -DQT_NO_CAST_FROM_ASCII
+ -DQT_NO_URL_CAST_FROM_STRING
+ -DQT_NO_CAST_FROM_BYTEARRAY
+ -DQT_NO_CONTEXTLESS_CONNECT
+ -DQT_NO_KEYWORDS
+ -DQT_TYPESAFE_FLAGS
+ -DQT_USE_QSTRINGBUILDER
+ -DQT_USE_FAST_OPERATOR_PLUS)
+
+ set(compiler_to_run "${CMAKE_CXX_COMPILER}")
+ if(CMAKE_CXX_COMPILER_LAUNCHER)
+ list(PREPEND compiler_to_run "${CMAKE_CXX_COMPILER_LAUNCHER}")
+ endif()
+
+ set(prop_prefix "")
+ get_target_property(target_type "${module_target}" TYPE)
+ if(target_type STREQUAL "INTERFACE_LIBRARY")
+ set(prop_prefix "INTERFACE_")
+ endif()
+
+ set(target_includes_genex
+ "$<TARGET_PROPERTY:${module_target},${prop_prefix}INCLUDE_DIRECTORIES>")
+ set(includes_exist_genex "$<BOOL:${target_includes_genex}>")
+ set(target_includes_joined_genex
+ "$<${includes_exist_genex}:-I$<JOIN:${target_includes_genex},;-I>>")
+
+ get_cmake_property(is_multi_config GENERATOR_IS_MULTI_CONFIG)
+ if(is_multi_config)
+ list(GET CMAKE_CONFIGURATION_TYPES 0 first_config_type)
+ set(config_suffix "$<$<NOT:$<CONFIG:${first_config_type}>>:-$<CONFIG>>")
+ endif()
+
+ # qmake doesn't seem to add the defines that are set by the header_only_module when checking the
+ # the cleanliness of the module's header files.
+ # This allows us to bypass an error with CMake 3.18 and lower when trying to evaluate
+ # genex-enhanced compile definitions. An example of that is in
+ # qttools/src/designer/src/uiplugin/CMakeLists.txt which ends up causing the following error
+ # message:
+ # CMake Error at qtbase/cmake/QtModuleHelpers.cmake:35 (add_library):
+ # INTERFACE_LIBRARY targets may only have whitelisted properties. The
+ # property "QT_PLUGIN_CLASS_NAME" is not allowed.
+ # Call Stack (most recent call first):
+ # src/designer/src/uiplugin/CMakeLists.txt:7 (qt_internal_add_module)
+ if(NOT target_type STREQUAL "INTERFACE_LIBRARY")
+ set(target_defines_genex
+ "$<TARGET_PROPERTY:${module_target},${prop_prefix}COMPILE_DEFINITIONS>")
+ set(defines_exist_genex "$<BOOL:${target_defines_genex}>")
+ set(target_defines_joined_genex
+ "$<${defines_exist_genex}:-D$<JOIN:${target_defines_genex},;-D>>")
+ endif()
+
+ # TODO: FIXME
+ # Passing COMPILE_OPTIONS can break add_custom_command() if the values contain genexes
+ # that add_custom_command does not support.
+ #
+ # Such a case happens on Linux where libraries linking against Threads::Threads bring in a
+ # '<$<COMPILE_LANG_AND_ID:CUDA,NVIDIA>' genex.
+ #
+ # If this is really required for headersclean (and qmake's headerclean implementation does
+ # actually pass all flags of the associated target), we'll have to replace the genex usage
+ # with an implementation that recursively processes a target's dependencies property
+ # to compile an expanded list of values for COMPILE_OPTIONS, and then filter out any genexes.
+ #
+ # This is similar to the proposed workaround at
+ # https://gitlab.kitware.com/cmake/cmake/-/issues/21074#note_814979
+ #
+ # See also https://gitlab.kitware.com/cmake/cmake/-/issues/21336
+ #
+ #set(target_compile_options_genex "$<TARGET_PROPERTY:${module_target},COMPILE_OPTIONS>")
+ #set(compile_options_exist_genex "$<BOOL:${target_compile_options_genex}>")
+ #set(target_compile_options_joined_genex
+ # "$<${compile_options_exist_genex}:$<JOIN:${target_compile_options_genex},;>>")
+
+ set(target_compile_flags_genex
+ "$<TARGET_PROPERTY:${module_target},${prop_prefix}COMPILE_FLAGS>")
+ set(compile_flags_exist_genex "$<BOOL:${target_compile_flags_genex}>")
+ set(target_compile_flags_joined_genex
+ "$<${compile_flags_exist_genex}:$<JOIN:${target_compile_flags_genex},;>>")
+
+ if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU"
+ OR "${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang|IntelLLVM")
+
+ # Compile header in strict C++20 mode. Enable further warnings.
+ set(hcleanFLAGS -std=c++2a
+ -Wall -Wextra -Werror -pedantic-errors
+ -Woverloaded-virtual -Wshadow -Wundef -Wfloat-equal
+ -Wnon-virtual-dtor -Wpointer-arith -Wformat-security
+ -Wchar-subscripts -Wold-style-cast
+ -fno-operator-names)
+
+ if(QT_FEATURE_reduce_relocations AND UNIX)
+ list(APPEND hcleanFLAGS -fPIC)
+ endif()
+
+ if (NOT ((TEST_architecture_arch STREQUAL arm)
+ OR (TEST_architecture_arch STREQUAL mips)))
+ list(APPEND hcleanFLAGS -Wcast-align)
+ endif()
+
+ if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
+ list(APPEND hcleanFLAGS -Wzero-as-null-pointer-constant
+ -Wdouble-promotion -Wfloat-conversion)
+ endif()
+
+ if ("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang|IntelLLVM")
+ list(APPEND hcleanFLAGS -Wshorten-64-to-32)
+ endif()
+
+ separate_arguments(cxx_flags NATIVE_COMMAND ${CMAKE_CXX_FLAGS})
+
+ if(APPLE AND CMAKE_OSX_SYSROOT)
+ list(APPEND cxx_flags "${CMAKE_CXX_SYSROOT_FLAG}" "${CMAKE_OSX_SYSROOT}")
+ endif()
+
+ if(APPLE AND QT_FEATURE_framework)
+ # For some reason CMake doesn't generate -iframework flags from the INCLUDE_DIRECTORIES
+ # generator expression we provide, so pass it explicitly and hope for the best.
+ list(APPEND framework_includes
+ "-iframework" "${QT_BUILD_INTERNALS_RELOCATABLE_INSTALL_PREFIX}/${INSTALL_LIBDIR}")
+
+ # If additional package prefixes are provided, we consider they can contain frameworks
+ # as well.
+ foreach(prefix IN LISTS _qt_additional_packages_prefix_paths)
+ __qt_internal_reverse_prefix_path_from_cmake_dir(path "${path}")
+
+ set(libdir "${prefix}/${INSTALL_LIBDIR}")
+ if(EXISTS "${libdir}")
+ list(APPEND framework_includes
+ "-iframework" "${libdir}")
+ endif()
+ endforeach()
+ endif()
+
+ set(compiler_command_line
+ "${compiler_to_run}" "-c" "${cxx_flags}"
+ "${target_compile_flags_joined_genex}"
+ "${target_defines_joined_genex}"
+ "${hcleanFLAGS}"
+ "${target_includes_joined_genex}"
+ "${framework_includes}"
+ "${hcleanDEFS}"
+
+ )
+ string(JOIN " " compiler_command_line_variables
+ "-xc++"
+ "\${INPUT_HEADER_FILE}"
+ "-o"
+ "\${OUTPUT_ARTIFACT}"
+ )
+ set(input_header_path_type ABSOLUTE)
+ elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
+ # Note we can't enable -Za, as it does not support certain key Microsoft SDK header files
+ # we use. Microsoft suggests to use /permissive- instead, which is implicity set by
+ # -std:c++latest.
+ set(hcleanFLAGS -std:c++latest -Zc:__cplusplus -WX -W4 -EHsc)
+
+ # Because we now add `-DNOMINMAX` to `PlatformCommonInternal`.
+ set(hcleanUDEFS -UNOMINMAX)
+
+ # cl.exe needs a source path
+ get_filename_component(source_path "${QT_MKSPECS_DIR}/features/data/dummy.cpp" REALPATH)
+
+ set(compiler_command_line
+ "${compiler_to_run}" "-nologo" "-c" "${CMAKE_CXX_FLAGS}"
+ "${target_compile_flags_joined_genex}"
+ "${target_defines_joined_genex}"
+ "${hcleanFLAGS}"
+ "${target_includes_joined_genex}"
+ "${hcleanDEFS}"
+ "${hcleanUDEFS}"
+ )
+ string(JOIN " " compiler_command_line_variables
+ "-FI"
+ "\${INPUT_HEADER_FILE}"
+ "-Fo\${OUTPUT_ARTIFACT}"
+ "${source_path}"
+ )
+
+ set(input_header_path_type REALPATH)
+ else()
+ message(FATAL_ERROR "CMAKE_CXX_COMPILER_ID \"${CMAKE_CXX_COMPILER_ID}\" is not supported"
+ " for the headersclean check.")
+ endif()
+
+ qt_internal_module_info(module ${module_target})
+
+ unset(header_check_exceptions)
+ set(header_check_exceptions
+ "${CMAKE_CURRENT_BINARY_DIR}/${module}_header_check_exceptions")
+ set(headers_check_parameters
+ "${CMAKE_CURRENT_BINARY_DIR}/${module_target}HeadersCheckParameters${config_suffix}.cmake")
+ string(JOIN "\n" headers_check_parameters_content
+ "set(HEADER_CHECK_EXCEPTIONS"
+ " \"${header_check_exceptions}\")"
+ "set(HEADER_CHECK_COMPILER_COMMAND_LINE"
+ " \[\[$<JOIN:${compiler_command_line},\]\]\n \[\[>\]\]\n"
+ " ${compiler_command_line_variables}"
+ ")"
+ )
+ file(GENERATE OUTPUT "${headers_check_parameters}"
+ CONTENT "${headers_check_parameters_content}")
+
+ set(sync_headers_dep "${module_target}_sync_headers")
+
+ foreach(header ${hclean_headers})
+ # We need realpath here to make sure path starts with drive letter
+ get_filename_component(input_path "${header}" ${input_header_path_type})
+
+ get_filename_component(input_file_name ${input_path} NAME)
+ set(artifact_path "${CMAKE_CURRENT_BINARY_DIR}/header_check/${input_file_name}.o")
+
+ unset(input_base_dir)
+ if(input_path MATCHES "${CMAKE_BINARY_DIR}")
+ set(input_base_dir "${CMAKE_BINARY_DIR}")
+ elseif(input_path MATCHES "${CMAKE_SOURCE_DIR}")
+ set(input_base_dir "${CMAKE_SOURCE_DIR}")
+ endif()
+
+ if(input_base_dir AND IS_ABSOLUTE "${input_base_dir}" AND IS_ABSOLUTE "${input_path}")
+ file(RELATIVE_PATH comment_header_path "${input_base_dir}" "${input_path}")
+ else()
+ set(comment_header_path "${input_path}")
+ endif()
+
+ add_custom_command(
+ OUTPUT "${artifact_path}"
+ COMMENT "headersclean: Checking header ${comment_header_path}"
+ COMMAND ${CMAKE_COMMAND} -E make_directory "${CMAKE_CURRENT_BINARY_DIR}/header_check"
+ COMMAND ${CMAKE_COMMAND}
+ -DINPUT_HEADER_FILE=${input_path}
+ -DOUTPUT_ARTIFACT=${artifact_path}
+ -DPARAMETERS=${headers_check_parameters}
+ -P "${QT_CMAKE_DIR}/QtModuleHeadersCheck.cmake"
+ IMPLICIT_DEPENDS CXX
+ VERBATIM
+ COMMAND_EXPAND_LISTS
+ DEPENDS
+ ${headers_check_parameters}
+ ${sync_headers_dep}
+ ${input_path}
+ ${header_check_exceptions}
+ )
+ list(APPEND hclean_artifacts "${artifact_path}")
+ endforeach()
+
+ add_custom_target(${module_target}_headersclean_check
+ COMMENT "headersclean: Checking headers in ${module}"
+ DEPENDS ${hclean_artifacts}
+ VERBATIM)
+
+ if(NOT TARGET headersclean_check)
+ add_custom_target(headersclean_check ALL)
+ endif()
+
+ add_dependencies(headersclean_check ${module_target}_headersclean_check)
+endfunction()
diff --git a/cmake/QtHostInfoConfig.cmake.in b/cmake/QtHostInfoConfig.cmake.in
index cec9552c77..a1d069ec01 100644
--- a/cmake/QtHostInfoConfig.cmake.in
+++ b/cmake/QtHostInfoConfig.cmake.in
@@ -1,3 +1,6 @@
+# Copyright (C) 2024 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
@PACKAGE_INIT@
set(@var_prefix@BINDIR "@INSTALL_BINDIR@")
@@ -19,3 +22,4 @@ set(@var_prefix@QMAKE_MKSPEC "@QT_QMAKE_TARGET_MKSPEC@")
set(@var_prefix@ARCH "@TEST_architecture_arch@")
set(@var_prefix@SUBARCHS "@TEST_subarch_result@")
set(@var_prefix@BUILDABI "@TEST_buildAbi@")
+set(@var_prefix@IS_SHARED_LIBS_BUILD "@BUILD_SHARED_LIBS@")
diff --git a/cmake/QtInitProject.cmake b/cmake/QtInitProject.cmake
new file mode 100644
index 0000000000..a42f59f5c8
--- /dev/null
+++ b/cmake/QtInitProject.cmake
@@ -0,0 +1,214 @@
+# Copyright (C) 2023 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+cmake_minimum_required(VERSION 3.16)
+
+if(NOT PROJECT_DIR)
+ set(PROJECT_DIR "${CMAKE_SOURCE_DIR}")
+endif()
+
+get_filename_component(project_name "${PROJECT_DIR}" NAME)
+
+get_filename_component(project_abs_dir "${PROJECT_DIR}" ABSOLUTE)
+if(NOT IS_DIRECTORY "${project_abs_dir}")
+ message(FATAL_ERROR "Unable to scan ${project_abs_dir}. The directory doesn't exist.")
+endif()
+
+set(known_extensions "")
+set(types "")
+
+# The function allows extending the capabilities of this script and establishes simple relation
+# chains between the file types.
+# Option Arguments:
+# EXPERIMENTAL
+# Marks that the support of the following files is experimental and the required Qt modules
+# are in Technical preview state.
+# DEPRECATED
+# Marks that the support of the following files will be discontinued soon and the required
+# Qt modules are deprecated.
+# One-value Arguments:
+# TEMPLATE
+# The CMake code template. Use the '@files@' string for the files substitution.
+# Multi-value Arguments:
+# EXTENSIONS
+# List of the file extensions treated as this source 'type'.
+# MODULES
+# List of Qt modules required for these file types.
+# DEPENDS
+# The prerequisite source 'type' needed by this source 'type'
+macro(handle_type type)
+ cmake_parse_arguments(arg
+ "EXPERIMENTAL;DEPRECATED"
+ "TEMPLATE"
+ "EXTENSIONS;MODULES;DEPENDS"
+ ${ARGN}
+ )
+
+ if(NOT arg_EXTENSIONS)
+ message(FATAL_ERROR "Unexpected call handle_type of with no EXTENSIONS specified."
+ " This is the Qt issue, please report a bug at https://bugreports.qt.io.")
+ endif()
+ set(unique_extensions_subset "${known_extensions}")
+ list(REMOVE_ITEM unique_extensions_subset ${arg_EXTENSIONS})
+ if(NOT "${known_extensions}" STREQUAL "${unique_extensions_subset}")
+ message(FATAL_ERROR "${type} contains duplicated extensions, this is not supported."
+ " This is the Qt issue, please report a bug at https://bugreports.qt.io.")
+ endif()
+ set(${type}_file_extensions "${arg_EXTENSIONS}")
+
+ if(NOT arg_TEMPLATE)
+ message(FATAL_ERROR "Unexpected call handle_type of with no TEMPLATE specified."
+ " This is the Qt issue, please report a bug at https://bugreports.qt.io.")
+ endif()
+ set(${type}_template "${arg_TEMPLATE}")
+
+ if(arg_MODULES)
+ set(${type}_required_modules "${arg_MODULES}")
+ endif()
+
+ list(APPEND types ${type})
+
+ if(arg_EXPERIMENTAL)
+ set(${type}_is_experimental TRUE)
+ else()
+ set(${type}_is_experimental FALSE)
+ endif()
+
+ if(arg_DEPRECATED)
+ set(${type}_is_deprecated TRUE)
+ else()
+ set(${type}_is_deprecated FALSE)
+ endif()
+
+ if(arg_DEPENDS)
+ set(${type}_dependencies ${arg_DEPENDS})
+ endif()
+endmacro()
+
+handle_type(cpp EXTENSIONS .c .cc .cpp .cxx .h .hh .hxx .hpp MODULES Core TEMPLATE
+"\n\nqt_add_executable(${project_name}
+ @files@
+)"
+)
+
+handle_type(qml EXTENSIONS .qml .js .mjs MODULES Gui Qml Quick TEMPLATE
+"\n\nqt_add_qml_module(${project_name}
+ URI ${project_name}
+ OUTPUT_DIRECTORY qml
+ VERSION 1.0
+ RESOURCE_PREFIX /qt/qml
+ QML_FILES
+ @files@
+)"
+)
+
+handle_type(ui EXTENSIONS .ui MODULES Gui Widgets DEPENDS cpp TEMPLATE
+"\n\ntarget_sources(${project_name}
+ PRIVATE
+ @files@
+)"
+)
+
+handle_type(qrc EXTENSIONS .qrc DEPENDS cpp TEMPLATE
+"\n\nqt_add_resources(${project_name}_resources @files@)
+target_sources(${project_name}
+ PRIVATE
+ \\\${${project_name}_resources}
+)"
+)
+
+handle_type(protobuf EXPERIMENTAL EXTENSIONS .proto MODULES Protobuf Grpc TEMPLATE
+"\n\nqt_add_protobuf(${project_name}
+ GENERATE_PACKAGE_SUBFOLDERS
+ PROTO_FILES
+ @files@
+)"
+)
+
+set(extra_packages "")
+file(GLOB_RECURSE files RELATIVE "${project_abs_dir}" "${project_abs_dir}/*")
+foreach(f IN LISTS files)
+ get_filename_component(file_extension "${f}" LAST_EXT)
+ string(TOLOWER "${file_extension}" file_extension)
+
+ foreach(type IN LISTS types)
+ if(file_extension IN_LIST ${type}_file_extensions)
+ list(APPEND ${type}_sources "${f}")
+ list(APPEND packages ${${type}_required_modules})
+ if(${type}_is_experimental)
+ message("We found files with the following extensions in your directory:"
+ " ${${type}_file_extensions}\n"
+ "Note that the modules ${${type}_required_modules} are"
+ " in the technical preview state.")
+ endif()
+ if(${type}_is_deprecated)
+ message("We found files with the following extensions in your directory:"
+ " ${${type}_file_extensions}\n"
+ "Note that the modules ${${type}_required_modules} are deprecated.")
+ endif()
+ break()
+ endif()
+ endforeach()
+endforeach()
+
+if(packages)
+ list(REMOVE_DUPLICATES packages)
+ list(JOIN packages " " packages_string)
+ list(JOIN packages "\n Qt::" deps_string)
+ set(deps_string "Qt::${deps_string}")
+endif()
+
+set(content
+"cmake_minimum_required(VERSION 3.16)
+project(${project_name} LANGUAGES CXX)
+
+find_package(Qt6 REQUIRED COMPONENTS ${packages_string})
+qt_standard_project_setup()"
+)
+
+set(has_useful_sources FALSE)
+foreach(type IN LISTS types)
+ if(${type}_sources)
+ set(skip FALSE)
+ foreach(dep IN LISTS ${type}_dependencies)
+ if(NOT ${dep}_sources)
+ set(skip TRUE)
+ message("Sources of type ${${type}_file_extensions} cannot live in the project"
+ " without ${${dep}_file_extensions} files. Skipping.")
+ break()
+ endif()
+ endforeach()
+ if(skip)
+ continue()
+ endif()
+
+ set(has_useful_sources TRUE)
+ string(REGEX MATCH "( +)@files@" unused "${${type}_template}")
+ list(JOIN ${type}_sources "\n${CMAKE_MATCH_1}" ${type}_sources)
+ string(REPLACE "@files@" "${${type}_sources}" ${type}_content
+ "${${type}_template}")
+ string(APPEND content "${${type}_content}")
+ endif()
+endforeach()
+
+string(APPEND content "\n\ntarget_link_libraries(${project_name}
+ PRIVATE
+ ${deps_string}
+)\n"
+)
+
+if(EXISTS "${project_abs_dir}/CMakeLists.txt")
+ message(FATAL_ERROR "Project is already initialized in current directory."
+ " Please remove CMakeLists.txt if you want to regenerate the project.")
+endif()
+
+if(NOT has_useful_sources)
+ message(FATAL_ERROR "Could not find any files to generate the project.")
+endif()
+file(WRITE "${project_abs_dir}/CMakeLists.txt" "${content}")
+
+message("The project file is successfully generated. To build the project run:"
+ "\nmkdir build"
+ "\ncd build"
+ "\nqt-cmake ${project_abs_dir}"
+ "\ncmake --build ${project_abs_dir}"
+)
diff --git a/cmake/QtInstallHelpers.cmake b/cmake/QtInstallHelpers.cmake
new file mode 100644
index 0000000000..deab48cda5
--- /dev/null
+++ b/cmake/QtInstallHelpers.cmake
@@ -0,0 +1,249 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+# Wraps install() command. In a prefix build, simply passes along arguments to install().
+# In a non-prefix build, handles association of targets to export names, and also calls export().
+function(qt_install)
+ set(flags)
+ set(options EXPORT DESTINATION NAMESPACE)
+ set(multiopts TARGETS)
+ cmake_parse_arguments(arg "${flags}" "${options}" "${multiopts}" ${ARGN})
+
+ if(arg_TARGETS)
+ set(is_install_targets TRUE)
+ endif()
+
+ # In a prefix build, always invoke install() without modification.
+ # In a non-prefix build, pass install(TARGETS) commands to allow
+ # association of targets to export names, so we can later use the export names
+ # in export() commands.
+ if(QT_WILL_INSTALL OR is_install_targets)
+ install(${ARGV})
+ endif()
+
+ # When install(EXPORT) is called, also call export(EXPORT)
+ # to generate build tree target files.
+ if(NOT is_install_targets AND arg_EXPORT)
+ # For prefixed builds (both top-level and per-repo) export build tree CMake Targets files so
+ # they can be used in CMake ExternalProjects. One such case is examples built as
+ # ExternalProjects as part of the Qt build.
+ # In a top-level build the exported config files are placed under qtbase/lib/cmake.
+ # In a per-repo build, they will be placed in each repo's build dir/lib/cmake.
+ if(QT_WILL_INSTALL)
+ qt_path_join(arg_DESTINATION "${QT_BUILD_DIR}" "${arg_DESTINATION}")
+ endif()
+
+ set(namespace_option "")
+ if(arg_NAMESPACE)
+ set(namespace_option NAMESPACE ${arg_NAMESPACE})
+ endif()
+ export(EXPORT ${arg_EXPORT}
+ ${namespace_option}
+ FILE "${arg_DESTINATION}/${arg_EXPORT}.cmake")
+ endif()
+endfunction()
+
+# Copies files using file(COPY) signature in non-prefix builds.
+function(qt_non_prefix_copy)
+ if(NOT QT_WILL_INSTALL)
+ file(${ARGV})
+ endif()
+endfunction()
+
+# Retrieve the permissions that are set by install(PROGRAMS).
+function(qt_get_install_executable_permissions out_var)
+ set(default_permissions ${CMAKE_INSTALL_DEFAULT_DIRECTORY_PERMISSIONS})
+ if(NOT default_permissions)
+ set(default_permissions OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ)
+ endif()
+ set(executable_permissions ${default_permissions} OWNER_EXECUTE)
+ if(GROUP_READ IN_LIST default_permissions)
+ list(APPEND executable_permissions GROUP_EXECUTE)
+ endif()
+ if(WORLD_READ IN_LIST default_permissions)
+ list(APPEND executable_permissions WORLD_EXECUTE)
+ endif()
+ set(${out_var} ${executable_permissions} PARENT_SCOPE)
+endfunction()
+
+# Use case is installing files in a prefix build, or copying them to the correct build dir
+# in a non-prefix build.
+# Pass along arguments as you would pass them to install().
+# Only supports FILES, PROGRAMS and DIRECTORY signature, and without fancy things
+# like OPTIONAL or RENAME or COMPONENT.
+function(qt_copy_or_install)
+ set(flags FILES PROGRAMS DIRECTORY)
+ set(options)
+ set(multiopts)
+ cmake_parse_arguments(arg "${flags}" "${options}" "${multiopts}" ${ARGN})
+
+ # Remember which option has to be passed to the install command.
+ set(copy_arguments "")
+ set(argv_copy ${ARGV})
+ if(arg_FILES)
+ set(install_option "FILES")
+ elseif(arg_PROGRAMS)
+ set(install_option "PROGRAMS")
+ qt_get_install_executable_permissions(executable_permissions)
+ list(APPEND copy_arguments FILE_PERMISSIONS ${executable_permissions})
+ elseif(arg_DIRECTORY)
+ set(install_option "DIRECTORY")
+ endif()
+
+ list(REMOVE_AT argv_copy 0)
+ qt_install(${install_option} ${argv_copy})
+ qt_non_prefix_copy(COPY ${argv_copy} ${copy_arguments})
+endfunction()
+
+# Create a versioned hard-link for the given target, or a program
+# E.g. "bin/qmake6" -> "bin/qmake".
+#
+# One-value Arguments:
+# WORKING_DIRECTORY
+# The directory where the original file is already placed.
+# SUFFIX
+# The program file extension, only used for PROGRAMS
+# Multi-value Arguments:
+# TARGETS
+# List of targets for which the versioned link will be created.
+# If targets are given, BASE_NAME and SUFFIX will be derived from it.
+# PROGRAMS
+# List of program file names for which the versioned link will be created.
+#
+#
+# NOTE: This assumes that TARGETS, or PROGRAMS are already installed in the
+# WORKING_DIRECTORY.
+#
+# In a multi-config build, create the link for the main config only.
+function(qt_internal_install_versioned_link)
+ if(NOT QT_WILL_INSTALL)
+ return()
+ endif()
+
+ if(NOT QT_CREATE_VERSIONED_HARD_LINK)
+ return()
+ endif()
+
+ set(options)
+ set(oneValueArgs "WORKING_DIRECTORY;SUFFIX")
+ set(multiValueArgs "TARGETS;PROGRAMS")
+ cmake_parse_arguments(arg "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
+
+ if(arg_TARGETS)
+ foreach(target "${arg_TARGETS}")
+ _qt_internal_create_versioned_link_or_copy("${arg_WORKING_DIRECTORY}"
+ $<TARGET_FILE_BASE_NAME:${target}>
+ $<TARGET_FILE_SUFFIX:${target}>)
+ endforeach()
+ endif()
+
+ if(arg_PROGRAMS)
+ foreach(program "${arg_PROGRAMS}")
+ _qt_internal_create_versioned_link_or_copy("${arg_WORKING_DIRECTORY}"
+ "${program}"
+ "${arg_SUFFIX}")
+ endforeach()
+ endif()
+endfunction()
+
+# Generate a script for creating a hard-link between the base_name, and
+# base_name${PROJECT_VERSION_MAJOR}.
+#
+# If no hard link can be created, make a copy instead.
+function(_qt_internal_create_versioned_link_or_copy install_dir base_name suffix)
+ qt_path_join(install_base_file_path "$\{qt_full_install_prefix}"
+ "${install_dir}" "${base_name}")
+ set(original "${install_base_file_path}${suffix}")
+ set(linkname "${install_base_file_path}${PROJECT_VERSION_MAJOR}${suffix}")
+ set(code "set(qt_full_install_prefix \"$\{CMAKE_INSTALL_PREFIX}\")"
+ " if(NOT \"$ENV\{DESTDIR}\" STREQUAL \"\")"
+ )
+
+ if(CMAKE_HOST_WIN32)
+ list(APPEND code
+ " if(qt_full_install_prefix MATCHES \"^[a-zA-Z]:\")"
+ " string(SUBSTRING \"$\{qt_full_install_prefix}\" 2 -1 qt_full_install_prefix)"
+ " endif()"
+ )
+ endif()
+ list(APPEND code
+ " string(PREPEND qt_full_install_prefix \"$ENV\{DESTDIR}\")"
+ " endif()"
+ " message(STATUS \"Creating hard link ${original} -> ${linkname}\")"
+ " file(CREATE_LINK \"${original}\" \"${linkname}\" COPY_ON_ERROR)")
+
+ if(QT_GENERATOR_IS_MULTI_CONFIG)
+ # Wrap the code in a configuration check,
+ # because install(CODE) does not support a CONFIGURATIONS argument.
+ qt_create_case_insensitive_regex(main_config_regex ${QT_MULTI_CONFIG_FIRST_CONFIG})
+ list(PREPEND code "if(\"\${CMAKE_INSTALL_CONFIG_NAME}\" MATCHES \"${main_config_regex}\")")
+ list(APPEND code "endif()")
+ endif()
+
+ list(JOIN code "\n" code)
+ install(CODE "${code}")
+endfunction()
+
+# Use case is copying files or directories in a non-prefix build with each build, so that changes
+# are available each time, this is useful for some Android templates that are needed for building,
+# apks and need to sync changes each time a build is started
+function(qt_internal_copy_at_build_time)
+ set(flags)
+ set(options TARGET DESTINATION)
+ set(multiopts FILES DIRECTORIES)
+ cmake_parse_arguments(arg "${flags}" "${options}" "${multiopts}" ${ARGN})
+
+ file(MAKE_DIRECTORY "${arg_DESTINATION}")
+
+ unset(outputs)
+ foreach(dir_to_copy IN LISTS arg_DIRECTORIES)
+ get_filename_component(file_name "${dir_to_copy}" NAME)
+ set(destination_file_name "${arg_DESTINATION}/${file_name}")
+
+ file(GLOB_RECURSE all_files_in_dir RELATIVE "${dir_to_copy}" "${dir_to_copy}/*")
+ set(dir_outputs ${all_files_in_dir})
+ set(dir_deps ${all_files_in_dir})
+
+ list(TRANSFORM dir_outputs PREPEND "${destination_file_name}/")
+ list(TRANSFORM dir_deps PREPEND "${dir_to_copy}/")
+
+ add_custom_command(OUTPUT ${dir_outputs}
+ COMMAND ${CMAKE_COMMAND} -E copy_directory ${dir_to_copy} "${destination_file_name}"
+ DEPENDS ${dir_deps}
+ COMMENT "Copying directory ${dir_to_copy} to ${arg_DESTINATION}."
+ )
+ list(APPEND outputs ${dir_outputs})
+ endforeach()
+
+ unset(file_outputs)
+ unset(files_to_copy)
+ foreach(path_to_copy IN LISTS arg_FILES)
+ get_filename_component(file_name "${path_to_copy}" NAME)
+ set(destination_file_name "${arg_DESTINATION}/${file_name}")
+
+ list(APPEND file_outputs "${destination_file_name}")
+ list(APPEND files_to_copy "${path_to_copy}")
+ endforeach()
+
+ if(files_to_copy)
+ add_custom_command(OUTPUT ${file_outputs}
+ COMMAND ${CMAKE_COMMAND} -E copy_if_different ${files_to_copy} ${arg_DESTINATION}
+ DEPENDS ${files_to_copy}
+ COMMENT "Copying files ${files_to_copy} to ${arg_DESTINATION}."
+ )
+ list(APPEND outputs ${file_outputs})
+ endif()
+
+ get_property(count GLOBAL PROPERTY _qt_internal_copy_at_build_time_count)
+ if(NOT count)
+ set(count 0)
+ endif()
+
+ add_custom_target(qt_internal_copy_at_build_time_${count} DEPENDS ${outputs})
+ if(arg_TARGET)
+ add_dependencies(${arg_TARGET} qt_internal_copy_at_build_time_${count})
+ endif()
+
+ math(EXPR count "${count} + 1")
+ set_property(GLOBAL PROPERTY _qt_internal_copy_at_build_time_count ${count})
+endfunction()
diff --git a/cmake/QtInstallPaths.cmake.in b/cmake/QtInstallPaths.cmake.in
new file mode 100644
index 0000000000..977fffd0e4
--- /dev/null
+++ b/cmake/QtInstallPaths.cmake.in
@@ -0,0 +1,16 @@
+# install layout information, following what qmake -query provides
+get_filename_component(QT@PROJECT_VERSION_MAJOR@_INSTALL_PREFIX
+ ${CMAKE_CURRENT_LIST_DIR}/../@QT_INVERSE_CONFIG_INSTALL_DIR@ ABSOLUTE)
+set(QT@PROJECT_VERSION_MAJOR@_INSTALL_ARCHDATA "@INSTALL_ARCHDATADIR@")
+set(QT@PROJECT_VERSION_MAJOR@_INSTALL_BINS "@INSTALL_BINDIR@")
+set(QT@PROJECT_VERSION_MAJOR@_INSTALL_CONFIGURATION "@INSTALL_SYSCONFDIR@")
+set(QT@PROJECT_VERSION_MAJOR@_INSTALL_DATA "@INSTALL_DATADIR@")
+set(QT@PROJECT_VERSION_MAJOR@_INSTALL_DOCS "@INSTALL_DOCDIR@")
+set(QT@PROJECT_VERSION_MAJOR@_INSTALL_EXAMPLES "@INSTALL_EXAMPLESDIR@")
+set(QT@PROJECT_VERSION_MAJOR@_INSTALL_HEADERS "@INSTALL_INCLUDEDIR@")
+set(QT@PROJECT_VERSION_MAJOR@_INSTALL_LIBS "@INSTALL_LIBDIR@")
+set(QT@PROJECT_VERSION_MAJOR@_INSTALL_LIBEXECS "@INSTALL_LIBEXECDIR@")
+set(QT@PROJECT_VERSION_MAJOR@_INSTALL_PLUGINS "@INSTALL_PLUGINSDIR@")
+set(QT@PROJECT_VERSION_MAJOR@_INSTALL_QML "@INSTALL_QMLDIR@")
+set(QT@PROJECT_VERSION_MAJOR@_INSTALL_TESTS "@INSTALL_TESTSDIR@")
+set(QT@PROJECT_VERSION_MAJOR@_INSTALL_TRANSLATIONS "@INSTALL_TRANSLATIONSDIR@")
diff --git a/cmake/QtInternalTargets.cmake b/cmake/QtInternalTargets.cmake
index c7da00c3f4..d7eadc1a73 100644
--- a/cmake/QtInternalTargets.cmake
+++ b/cmake/QtInternalTargets.cmake
@@ -1,16 +1,21 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
-function(qt_internal_set_warnings_are_errors_flags target)
+
+function(qt_internal_set_warnings_are_errors_flags target target_scope)
set(flags "")
- if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
- # Regular clang 3.0+
- if (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL "3.0.0")
- list(APPEND flags -Werror -Wno-error=\#warnings -Wno-error=deprecated-declarations)
- endif()
- elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "AppleClang")
- # using AppleClang
- # Apple clang 4.0+
- if (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL "4.0.0" AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS_EQUAL "9.2")
- list(APPEND flags -Werror -Wno-error=\#warnings -Wno-error=deprecated-declarations)
+ if (CLANG AND NOT MSVC)
+ list(APPEND flags -Werror -Wno-error=\#warnings -Wno-error=deprecated-declarations)
+ if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") # as in: not AppleClang
+ if (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL "10.0.0")
+ # We do mixed enum arithmetic all over the place:
+ list(APPEND flags -Wno-error=deprecated-enum-enum-conversion)
+ endif()
+ if (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL "14.0.0")
+ # Clang 14 introduced these two but we are not clean for it.
+ list(APPEND flags -Wno-error=deprecated-copy-with-user-provided-copy)
+ list(APPEND flags -Wno-error=unused-but-set-variable)
+ endif()
endif()
elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
# using GCC
@@ -32,86 +37,166 @@ function(qt_internal_set_warnings_are_errors_flags target)
list(APPEND flags -Wno-error=format-overflow)
endif()
+ if (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL "10.0.0")
+ # GCC 10 has a number of bugs in -Wstringop-overflow. Do not make them an error.
+ # https://gcc.gnu.org/bugzilla/show_bug.cgi?id=92955
+ # https://gcc.gnu.org/bugzilla/show_bug.cgi?id=94335
+ # https://gcc.gnu.org/bugzilla/show_bug.cgi?id=101134
+ list(APPEND flags -Wno-error=stringop-overflow)
+ endif()
+
+ if (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL "11.0.0")
+ # We do mixed enum arithmetic all over the place:
+ list(APPEND flags -Wno-error=deprecated-enum-enum-conversion -Wno-error=deprecated-enum-float-conversion)
+
+ # GCC has some false positive, and it specifically comes through in MINGW
+ if (MINGW)
+ list(APPEND flags -Wno-error=stringop-overread)
+ endif()
+ endif()
+
+ if (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL "11.0.0" AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS "11.2.0")
+ # GCC 11.1 has a regression in the integrated preprocessor, so disable it as a workaround (QTBUG-93360)
+ # https://gcc.gnu.org/bugzilla/show_bug.cgi?id=100796
+ # This in turn triggers a fallthrough warning in cborparser.c, so we disable this warning.
+ list(APPEND flags -no-integrated-cpp -Wno-implicit-fallthrough)
+ endif()
+
# Work-around for bug https://code.google.com/p/android/issues/detail?id=58135
if (ANDROID)
list(APPEND flags -Wno-error=literal-suffix)
endif()
- elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Intel")
- # Intel CC 13.0 +, on Linux only
- if (LINUX)
- if (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL "13.0.0")
- # 177: function "entity" was declared but never referenced
- # (too aggressive; ICC reports even for functions created due to template instantiation)
- # 1224: #warning directive
- # 1478: function "entity" (declared at line N) was declared deprecated
- # 1786: function "entity" (declared at line N of "file") was declared deprecated ("message")
- # 1881: argument must be a constant null pointer value
- # (NULL in C++ is usually a literal 0)
- list(APPEND flags -Werror -ww177,1224,1478,1786,1881)
- endif()
- endif()
elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
- # In qmake land, currently warnings as errors are only enabled for
- # MSVC 2012, 2013, 2015.
- # Respectively MSVC_VERRSIONs are: 1700-1799, 1800-1899, 1900-1909.
- if(MSVC_VERSION GREATER_EQUAL 1700 AND MSVC_VERSION LESS_EQUAL 1909)
+ # Only enable for versions of MSVC that are known to work
+ # 1939 is Visual Studio 2022 version 17.0
+ if(MSVC_VERSION LESS_EQUAL 1939)
list(APPEND flags /WX)
endif()
endif()
set(warnings_are_errors_enabled_genex
"$<NOT:$<BOOL:$<TARGET_PROPERTY:QT_SKIP_WARNINGS_ARE_ERRORS>>>")
- # Apprently qmake only adds -Werror to CXX and OBJCXX files, not C files. We have to do the
+ # Apparently qmake only adds -Werror to CXX and OBJCXX files, not C files. We have to do the
# same otherwise MinGW builds break when building 3rdparty\md4c\md4c.c (and probably on other
# platforms too).
set(cxx_only_genex "$<OR:$<COMPILE_LANGUAGE:CXX>,$<COMPILE_LANGUAGE:OBJCXX>>")
set(final_condition_genex "$<AND:${warnings_are_errors_enabled_genex},${cxx_only_genex}>")
set(flags_generator_expression "$<${final_condition_genex}:${flags}>")
- target_compile_options("${target}" INTERFACE "${flags_generator_expression}")
+
+ target_compile_options("${target}" ${target_scope} "${flags_generator_expression}")
+endfunction()
+
+# The function adds a global 'definition' to the platform internal targets and the target
+# property-based switch to disable the definition.
+# Arguments:
+# VALUE optional value that the definition will take.
+# SCOPE the list of scopes the definition needs to be set for. If the SCOPE is not specified the
+# definition is added to PlatformCommonInternal target.
+# Possible values:
+# MODULE - set the definition for all Qt modules
+# PLUGIN - set the definition for all Qt plugins
+# TOOL - set the definition for all Qt tools
+# APP - set the definition for all Qt applications
+# TODO: Add a tests specific platform target and the definition scope for it.
+function(qt_internal_add_global_definition definition)
+ set(optional_args)
+ set(single_value_args VALUE)
+ set(multi_value_args SCOPE)
+ cmake_parse_arguments(arg
+ "${optional_args}"
+ "${single_value_args}"
+ "${multi_value_args}"
+ ${ARGN}
+ )
+
+ set(scope_MODULE PlatformModuleInternal)
+ set(scope_PLUGIN PlatformPluginInternal)
+ set(scope_TOOL PlatformToolInternal)
+ set(scope_APP PlatformAppInternal)
+
+ set(undef_property_name "QT_INTERNAL_UNDEF_${definition}")
+
+ if(DEFINED arg_VALUE)
+ set(definition "${definition}=${arg_VALUE}")
+ endif()
+
+ set(definition_genex
+ "$<$<NOT:$<BOOL:$<TARGET_PROPERTY:${undef_property_name}>>>:${definition}>")
+
+ if(NOT DEFINED arg_SCOPE)
+ target_compile_definitions(PlatformCommonInternal INTERFACE "${definition_genex}")
+ else()
+ foreach(scope IN LISTS arg_SCOPE)
+ if(NOT DEFINED scope_${scope})
+ message(FATAL_ERROR "Unknown scope ${scope}.")
+ endif()
+ target_compile_definitions("${scope_${scope}}" INTERFACE "${definition_genex}")
+ endforeach()
+ endif()
endfunction()
add_library(PlatformCommonInternal INTERFACE)
-add_library(Qt::PlatformCommonInternal ALIAS PlatformCommonInternal)
+qt_internal_add_target_aliases(PlatformCommonInternal)
+target_link_libraries(PlatformCommonInternal INTERFACE Platform)
add_library(PlatformModuleInternal INTERFACE)
-add_library(Qt::PlatformModuleInternal ALIAS PlatformModuleInternal)
+qt_internal_add_target_aliases(PlatformModuleInternal)
target_link_libraries(PlatformModuleInternal INTERFACE PlatformCommonInternal)
add_library(PlatformPluginInternal INTERFACE)
-add_library(Qt::PlatformPluginInternal ALIAS PlatformPluginInternal)
+qt_internal_add_target_aliases(PlatformPluginInternal)
target_link_libraries(PlatformPluginInternal INTERFACE PlatformCommonInternal)
add_library(PlatformAppInternal INTERFACE)
-add_library(Qt::PlatformAppInternal ALIAS PlatformAppInternal)
+qt_internal_add_target_aliases(PlatformAppInternal)
target_link_libraries(PlatformAppInternal INTERFACE PlatformCommonInternal)
add_library(PlatformToolInternal INTERFACE)
-add_library(Qt::PlatformToolInternal ALIAS PlatformToolInternal)
+qt_internal_add_target_aliases(PlatformToolInternal)
target_link_libraries(PlatformToolInternal INTERFACE PlatformAppInternal)
+qt_internal_add_global_definition(QT_NO_JAVA_STYLE_ITERATORS)
+qt_internal_add_global_definition(QT_NO_QASCONST)
+qt_internal_add_global_definition(QT_NO_QEXCHANGE)
+qt_internal_add_global_definition(QT_NO_NARROWING_CONVERSIONS_IN_CONNECT)
+qt_internal_add_global_definition(QT_EXPLICIT_QFILE_CONSTRUCTION_FROM_PATH)
+qt_internal_add_global_definition(QT_USE_QSTRINGBUILDER SCOPE PLUGIN TOOL MODULE)
+qt_internal_add_global_definition(QT_NO_FOREACH)
+
if(WARNINGS_ARE_ERRORS)
- qt_internal_set_warnings_are_errors_flags(PlatformModuleInternal)
- qt_internal_set_warnings_are_errors_flags(PlatformPluginInternal)
- qt_internal_set_warnings_are_errors_flags(PlatformAppInternal)
+ qt_internal_set_warnings_are_errors_flags(PlatformModuleInternal INTERFACE)
+ qt_internal_set_warnings_are_errors_flags(PlatformPluginInternal INTERFACE)
+ qt_internal_set_warnings_are_errors_flags(PlatformAppInternal INTERFACE)
endif()
if(WIN32)
# Needed for M_PI define. Same as mkspecs/features/qt_module.prf.
# It's set for every module being built, but it's not propagated to user apps.
target_compile_definitions(PlatformModuleInternal INTERFACE _USE_MATH_DEFINES)
+ # Not disabling min/max macros may result in unintended substitutions of std::min/max
+ target_compile_definitions(PlatformCommonInternal INTERFACE NOMINMAX)
endif()
if(FEATURE_largefile AND UNIX)
target_compile_definitions(PlatformCommonInternal
INTERFACE "_LARGEFILE64_SOURCE;_LARGEFILE_SOURCE")
endif()
-# We can't use the gold linker on android with the NDK, which is the default
-# linker. To build our own target we will use the lld linker.
-if (ANDROID)
- target_link_options(PlatformModuleInternal INTERFACE -fuse-ld=lld)
+if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang" AND CMAKE_SYSTEM_NAME STREQUAL "Windows")
+ # Clang will otherwise show error about inline method conflicting with dllimport class attribute in tools
+ # (this was tested with Clang 10)
+ # error: 'QString::operator[]' redeclared inline; 'dllimport' attribute ignored [-Werror,-Wignored-attributes]
+ target_compile_options(PlatformCommonInternal INTERFACE -Wno-ignored-attributes)
endif()
+target_compile_definitions(PlatformCommonInternal INTERFACE QT_NO_NARROWING_CONVERSIONS_IN_CONNECT)
target_compile_definitions(PlatformCommonInternal INTERFACE $<$<NOT:$<CONFIG:Debug>>:QT_NO_DEBUG>)
+if(FEATURE_developer_build)
+ # This causes an ABI break on Windows, so we cannot unconditionally
+ # enable it. Keep it for developer builds only for now.
+ ### Qt 7: remove the if.
+ target_compile_definitions(PlatformCommonInternal INTERFACE QT_STRICT_QLIST_ITERATORS)
+endif()
+
function(qt_internal_apply_bitcode_flags target)
# See mkspecs/features/uikit/bitcode.prf
set(release_flags "-fembed-bitcode")
@@ -123,10 +208,17 @@ function(qt_internal_apply_bitcode_flags target)
set(bitcode_flags "$<${is_enabled_genex}:${flags_genex}>")
- target_link_options("${target}" INTERFACE ${bitcode_flags})
target_compile_options("${target}" INTERFACE ${bitcode_flags})
endfunction()
+# Function guards linker options that are applicable for internal Qt targets only from propagating
+# them to user projects.
+function(qt_internal_platform_link_options target scope)
+ set(options ${ARGN})
+ set(is_internal_target_genex "$<BOOL:$<TARGET_PROPERTY:_qt_is_internal_target>>")
+ target_link_options(${target} ${scope} "$<${is_internal_target_genex}:${options}>")
+endfunction()
+
# Apple deprecated the entire OpenGL API in favor of Metal, which
# we are aware of, so silence the deprecation warnings in code.
# This does not apply to user-code, which will need to silence
@@ -137,27 +229,50 @@ elseif(UIKIT)
target_compile_definitions(PlatformCommonInternal INTERFACE GLES_SILENCE_DEPRECATION)
endif()
-if(UIKIT)
- # Do what mkspecs/features/uikit/default_pre.prf does, aka enable sse2 for
- # simulator_and_device_builds.
- if(FEATURE_simulator_and_device)
- # Setting the definition on PlatformCommonInternal behaves slightly differently from what
- # is done in qmake land. This way the define is not propagated to tests, examples, or
- # user projects built with qmake, but only modules, plugins and tools.
- # TODO: Figure out if this ok or not (sounds ok to me).
- target_compile_definitions(PlatformCommonInternal INTERFACE QT_COMPILER_SUPPORTS_SSE2)
+if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "AppleClang")
+ if(CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL "14.0.0")
+ # Xcode 14's Clang will emit objc_msgSend stubs by default, which ld
+ # from earlier Xcode versions will fail to understand when linking
+ # against static libraries with these stubs. Disable the stubs explicitly,
+ # for as long as we do support Xcode < 14.
+ set(is_static_lib "$<STREQUAL:$<TARGET_PROPERTY:TYPE>,STATIC_LIBRARY>")
+ set(is_objc "$<COMPILE_LANGUAGE:OBJC,OBJCXX>")
+ set(is_static_and_objc "$<AND:${is_static_lib},${is_objc}>")
+ target_compile_options(PlatformCommonInternal INTERFACE
+ "$<${is_static_and_objc}:-fno-objc-msgsend-selector-stubs>"
+ )
endif()
- qt_internal_apply_bitcode_flags(PlatformCommonInternal)
+
+ # A bug in Xcode 15 adds duplicate flags to the linker. In addition, the
+ # `-warn_duplicate_libraries` is now enabled by default which may result
+ # in several 'duplicate libraries warning'.
+ # - https://gitlab.kitware.com/cmake/cmake/-/issues/25297 and
+ # - https://indiestack.com/2023/10/xcode-15-duplicate-library-linker-warnings/
+ set(is_xcode15 "$<VERSION_GREATER_EQUAL:$<CXX_COMPILER_VERSION>,15>")
+ set(not_disabled "$<NOT:$<BOOL:$<TARGET_PROPERTY:QT_NO_DISABLE_WARN_DUPLICATE_LIBRARIES>>>")
+ target_link_options(PlatformCommonInternal INTERFACE
+ "$<$<AND:${not_disabled},${is_xcode15}>:LINKER:-no_warn_duplicate_libraries>")
+endif()
+
+if(MSVC)
+ target_compile_definitions(PlatformCommonInternal INTERFACE
+ "_CRT_SECURE_NO_WARNINGS"
+ "$<$<STREQUAL:$<TARGET_PROPERTY:TYPE>,SHARED_LIBRARY>:_WINDLL>"
+ )
+endif()
+
+if(WASM AND QT_FEATURE_sse2)
+ target_compile_definitions(PlatformCommonInternal INTERFACE QT_COMPILER_SUPPORTS_SSE2)
endif()
# Taken from mkspecs/common/msvc-version.conf and mkspecs/common/msvc-desktop.conf
-if (MSVC)
+if (MSVC AND NOT CLANG)
if (MSVC_VERSION GREATER_EQUAL 1799)
target_compile_options(PlatformCommonInternal INTERFACE
-FS
-Zc:rvalueCast
-Zc:inline
- )
+ )
endif()
if (MSVC_VERSION GREATER_EQUAL 1899)
target_compile_options(PlatformCommonInternal INTERFACE
@@ -165,31 +280,142 @@ if (MSVC)
-Zc:throwingNew
)
endif()
- if (MSVC_VERSION GREATER_EQUAL 1909)
+ if (MSVC_VERSION GREATER_EQUAL 1909) # MSVC 2017
target_compile_options(PlatformCommonInternal INTERFACE
-Zc:referenceBinding
+ -Zc:ternary
+ )
+ endif()
+ if (MSVC_VERSION GREATER_EQUAL 1919) # MSVC 2019
+ target_compile_options(PlatformCommonInternal INTERFACE
+ -Zc:externConstexpr
+ #-Zc:lambda # Buggy. TODO: Enable again when stable enough.
+ #-Zc:preprocessor # breaks build due to bug in default Windows SDK 10.0.19041
)
endif()
- target_compile_options(PlatformCommonInternal INTERFACE -Zc:wchar_t)
+ target_compile_options(PlatformCommonInternal INTERFACE
+ -Zc:wchar_t
+ -bigobj
+ )
+
+ target_compile_options(PlatformCommonInternal INTERFACE
+ $<$<NOT:$<CONFIG:Debug>>:-guard:cf -Gw>
+ )
- target_link_options(PlatformCommonInternal INTERFACE
- -DYNAMICBASE -NXCOMPAT
- $<$<CONFIG:Release>:-OPT:REF>
- $<$<CONFIG:RelWithDebInfo>:-OPT:REF>
+ qt_internal_platform_link_options(PlatformCommonInternal INTERFACE
+ -DYNAMICBASE -NXCOMPAT -LARGEADDRESSAWARE
+ $<$<NOT:$<CONFIG:Debug>>:-OPT:REF -OPT:ICF -GUARD:CF>
)
endif()
+if(MINGW)
+ target_compile_options(PlatformCommonInternal INTERFACE -Wa,-mbig-obj)
+endif()
+
if (GCC AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL "9.2")
target_compile_options(PlatformCommonInternal INTERFACE $<$<COMPILE_LANGUAGE:CXX>:-Wsuggest-override>)
endif()
+# Hardening options
+if(QT_FEATURE_intelcet)
+ if(MSVC)
+ qt_internal_platform_link_options(PlatformCommonInternal INTERFACE -CETCOMPAT)
+ else()
+ target_compile_options(PlatformCommonInternal INTERFACE -fcf-protection=full)
+ endif()
+endif()
+
+if(QT_FEATURE_glibc_fortify_source)
+ set(is_optimized_build "$<OR:$<NOT:$<CONFIG:Debug>>,$<BOOL:${QT_FEATURE_optimize_debug}>>")
+ # Some compilers may define _FORTIFY_SOURCE by default when optimizing, remove it
+ # before defining our own
+ target_compile_options(PlatformCommonInternal BEFORE INTERFACE "$<${is_optimized_build}:-U_FORTIFY_SOURCE>")
+ if(TEST_glibc_234)
+ target_compile_options(PlatformCommonInternal INTERFACE "$<${is_optimized_build}:-D_FORTIFY_SOURCE=3>")
+ else()
+ target_compile_options(PlatformCommonInternal INTERFACE "$<${is_optimized_build}:-D_FORTIFY_SOURCE=2>")
+ endif()
+endif()
+
+if(QT_FEATURE_trivial_auto_var_init_pattern)
+ target_compile_options(PlatformCommonInternal INTERFACE -ftrivial-auto-var-init=pattern)
+endif()
+
+if(QT_FEATURE_stack_protector)
+ target_compile_options(PlatformCommonInternal INTERFACE -fstack-protector-strong)
+endif()
+
+if(QT_FEATURE_stack_clash_protection)
+ target_compile_options(PlatformCommonInternal INTERFACE -fstack-clash-protection)
+endif()
+
+if(QT_FEATURE_libstdcpp_assertions)
+ target_compile_definitions(PlatformCommonInternal INTERFACE _GLIBCXX_ASSERTIONS)
+endif()
+
+if(QT_FEATURE_libcpp_hardening)
+ target_compile_definitions(PlatformCommonInternal INTERFACE -D_LIBCPP_HARDENING_MODE=$<IF:$<CONFIG:Debug>,_LIBCPP_HARDENING_MODE_EXTENSIVE,_LIBCPP_HARDENING_MODE_FAST>)
+endif()
+
+if(QT_FEATURE_relro_now_linker)
+ qt_internal_platform_link_options(PlatformCommonInternal INTERFACE "-Wl,-z,relro,-z,now")
+endif()
+
+
+if(QT_FEATURE_force_asserts)
+ target_compile_definitions(PlatformCommonInternal INTERFACE QT_FORCE_ASSERTS)
+endif()
+
+if(DEFINED QT_EXTRA_DEFINES)
+ target_compile_definitions(PlatformCommonInternal INTERFACE ${QT_EXTRA_DEFINES})
+endif()
+
+if(DEFINED QT_EXTRA_INCLUDEPATHS)
+ target_include_directories(PlatformCommonInternal INTERFACE ${QT_EXTRA_INCLUDEPATHS})
+endif()
+
+if(DEFINED QT_EXTRA_LIBDIRS)
+ target_link_directories(PlatformCommonInternal INTERFACE ${QT_EXTRA_LIBDIRS})
+endif()
+
+if(DEFINED QT_EXTRA_FRAMEWORKPATHS AND APPLE)
+ list(TRANSFORM QT_EXTRA_FRAMEWORKPATHS PREPEND "-F" OUTPUT_VARIABLE __qt_fw_flags)
+ target_compile_options(PlatformCommonInternal INTERFACE ${__qt_fw_flags})
+ qt_internal_platform_link_options(PlatformCommonInternal INTERFACE ${__qt_fw_flags})
+ unset(__qt_fw_flags)
+endif()
+
+qt_internal_get_active_linker_flags(__qt_internal_active_linker_flags)
+if(__qt_internal_active_linker_flags)
+ qt_internal_platform_link_options(PlatformCommonInternal INTERFACE
+ "${__qt_internal_active_linker_flags}")
+endif()
+unset(__qt_internal_active_linker_flags)
+
+if(QT_FEATURE_enable_gdb_index)
+ qt_internal_platform_link_options(PlatformCommonInternal INTERFACE "-Wl,--gdb-index")
+endif()
+
+if(QT_FEATURE_enable_new_dtags)
+ qt_internal_platform_link_options(PlatformCommonInternal INTERFACE "-Wl,--enable-new-dtags")
+endif()
+
+function(qt_internal_apply_coverage_flags)
+ if(QT_FEATURE_coverage_gcov)
+ target_compile_options(PlatformCommonInternal INTERFACE
+ "$<$<CONFIG:Debug>:--coverage>")
+ target_link_options(PlatformCommonInternal INTERFACE "$<$<CONFIG:Debug>:--coverage>")
+ endif()
+endfunction()
+qt_internal_apply_coverage_flags()
+
function(qt_get_implicit_sse2_genex_condition out_var)
set(is_shared_lib "$<STREQUAL:$<TARGET_PROPERTY:TYPE>,SHARED_LIBRARY>")
set(is_static_lib "$<STREQUAL:$<TARGET_PROPERTY:TYPE>,STATIC_LIBRARY>")
set(is_static_qt_build "$<NOT:$<BOOL:${QT_BUILD_SHARED_LIBS}>>")
- set(is_staitc_lib_during_static_qt_build "$<AND:${is_static_qt_build},${is_static_lib}>")
- set(enable_sse2_condition "$<OR:${is_shared_lib},${is_staitc_lib_during_static_qt_build}>")
+ set(is_static_lib_during_static_qt_build "$<AND:${is_static_qt_build},${is_static_lib}>")
+ set(enable_sse2_condition "$<OR:${is_shared_lib},${is_static_lib_during_static_qt_build}>")
set(${out_var} "${enable_sse2_condition}" PARENT_SCOPE)
endfunction()
@@ -214,15 +440,7 @@ qt_auto_detect_implicit_sse2()
function(qt_auto_detect_fpmath)
# fpmath configuration adjustment in qt_module.prf
set(fpmath_supported FALSE)
- if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
- if (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL "3.4")
- set(fpmath_supported TRUE)
- endif()
- elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "AppleClang")
- if (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL "5.1")
- set(fpmath_supported TRUE)
- endif()
- elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
+ if ("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang|GNU|IntelLLVM")
set(fpmath_supported TRUE)
endif()
if(fpmath_supported AND TEST_architecture_arch STREQUAL "i386" AND __implicit_sse2_for_qt_modules_enabled)
@@ -238,16 +456,27 @@ function(qt_handle_apple_app_extension_api_only)
# Build Qt libraries with -fapplication-extension. Needed to avoid linker warnings
# transformed into errors on darwin platforms.
set(flags "-fapplication-extension")
- set(genex_condition "$<NOT:$<BOOL:$<TARGET_PROPERTY:QT_NO_APP_EXTENSION_ONLY_API>>>")
- set(flags "$<${genex_condition}:${flags}>")
+
+ # The flags should only be applied to internal Qt libraries like modules and plugins.
+ # The reason why we use a custom property to apply the flags is because there's no other
+ # way to prevent the link options spilling out into user projects if the target that links
+ # against PlatformXInternal is a static library.
+ # The exported static library's INTERFACE_LINK_LIBRARIES property would contain
+ # $<LINK_ONLY:PlatformXInternal> and PlatformXInternal's INTERFACE_LINK_OPTIONS would be
+ # applied to a user project target.
+ # So to contain the spilling out of the flags, we ensure the link options are only added
+ # to internal Qt libraries that are marked with the property.
+ set(not_disabled "$<NOT:$<BOOL:$<TARGET_PROPERTY:QT_NO_APP_EXTENSION_ONLY_API>>>")
+ set(is_qt_internal_library "$<BOOL:$<TARGET_PROPERTY:_qt_is_internal_library>>")
+
+ set(condition "$<AND:${not_disabled},${is_qt_internal_library}>")
+
+ set(flags "$<${condition}:${flags}>")
target_compile_options(PlatformModuleInternal INTERFACE ${flags})
target_link_options(PlatformModuleInternal INTERFACE ${flags})
target_compile_options(PlatformPluginInternal INTERFACE ${flags})
target_link_options(PlatformPluginInternal INTERFACE ${flags})
endif()
endfunction()
-function(qt_disable_apple_app_extension_api_only target)
- set_target_properties("${target}" PROPERTIES QT_NO_APP_EXTENSION_ONLY_API TRUE)
-endfunction()
qt_handle_apple_app_extension_api_only()
diff --git a/cmake/QtJavaHelpers.cmake b/cmake/QtJavaHelpers.cmake
new file mode 100644
index 0000000000..ec9b611c5e
--- /dev/null
+++ b/cmake/QtJavaHelpers.cmake
@@ -0,0 +1,30 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+# This function can be used to compile java sources into a jar package.
+
+function(qt_internal_add_jar target)
+ set(options)
+ set(oneValueArgs OUTPUT_DIR)
+ set(multiValueArgs INCLUDE_JARS SOURCES)
+ cmake_parse_arguments(arg "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
+
+ set(javac_target_version "${QT_ANDROID_JAVAC_TARGET}")
+ if (NOT javac_target_version)
+ set(javac_target_version "8")
+ endif()
+
+ set(javac_source_version "${QT_ANDROID_JAVAC_SOURCE}")
+ if (NOT javac_source_version)
+ set(javac_source_version "8")
+ endif()
+
+ set(CMAKE_JAVA_COMPILE_FLAGS -source "${javac_source_version}" -target "${javac_target_version}"
+ -Xlint:unchecked,cast,divzero,fallthrough,overrides,path -classpath "${QT_ANDROID_JAR}")
+ add_jar(${ARGV})
+
+ foreach(f IN LISTS arg_SOURCES)
+ _qt_internal_expose_source_file_to_ide(${target} "${f}")
+ endforeach()
+
+endfunction()
diff --git a/cmake/QtLalrHelpers.cmake b/cmake/QtLalrHelpers.cmake
new file mode 100644
index 0000000000..a63d8e9504
--- /dev/null
+++ b/cmake/QtLalrHelpers.cmake
@@ -0,0 +1,77 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+# Match the pattern 'regex' in 'input_line', replace the match with 'replacement'
+# and set that result in 'out_var' in the parent scope.
+function(qt_regex_match_and_get input_line regex replacement out_var)
+ string(REGEX MATCH "${regex}" match "${input_line}")
+ if(match)
+ string(REGEX REPLACE "${regex}" "${replacement}" match "${input_line}")
+ string(STRIP ${match} match)
+ set(${out_var} "${match}" PARENT_SCOPE)
+ endif()
+endfunction()
+
+# Match 'regex' in a list of lines. When found, set the value to 'out_var' and break early.
+function(qt_qlalr_find_option_in_list input_list regex out_var)
+ foreach(line ${input_list})
+ qt_regex_match_and_get("${line}" "${regex}" "\\1" option)
+ if(option)
+ string(TOLOWER ${option} option)
+ set(${out_var} "${option}" PARENT_SCOPE)
+ return()
+ endif()
+ endforeach()
+ message(FATAL_ERROR "qt_qlalr_find_option_in_list: Could not extract ${out_var}")
+endfunction()
+
+# Generate a few output files using qlalr, and assign those to 'consuming_target'.
+# 'input_file_list' is a list of 'foo.g' file paths.
+# 'flags' are extra flags to be passed to qlalr.
+function(qt_process_qlalr consuming_target input_file_list flags)
+ # Don't try to extend_target when cross compiling an imported host target (like a tool).
+ qt_is_imported_target("${consuming_target}" is_imported)
+ if(is_imported)
+ return()
+ endif()
+
+ qt_internal_is_skipped_test(skipped ${consuming_target})
+ if(skipped)
+ return()
+ endif()
+ qt_internal_is_in_test_batch(in_batch ${consuming_target})
+ if(in_batch)
+ _qt_internal_test_batch_target_name(consuming_target)
+ endif()
+
+ foreach(input_file ${input_file_list})
+ file(STRINGS ${input_file} input_file_lines)
+ qt_qlalr_find_option_in_list("${input_file_lines}" "^%parser(.+)" "parser")
+ qt_qlalr_find_option_in_list("${input_file_lines}" "^%decl(.+)" "decl")
+ qt_qlalr_find_option_in_list("${input_file_lines}" "^%impl(.+)" "impl")
+ get_filename_component(base_file_name ${input_file} NAME_WE)
+
+ # Pass a relative input file path to qlalr to generate relative #line directives.
+ if(IS_ABSOLUTE "${input_file}")
+ set(absolute_input_file "${input_file}")
+ else()
+ get_filename_component(absolute_input_file "${input_file}" ABSOLUTE)
+ endif()
+ file(RELATIVE_PATH relative_input_file "${CMAKE_CURRENT_BINARY_DIR}"
+ "${absolute_input_file}")
+
+ set(cpp_file "${parser}.cpp")
+ set(private_file "${CMAKE_CURRENT_BINARY_DIR}/${parser}_p.h")
+ set(decl_file "${CMAKE_CURRENT_BINARY_DIR}/${decl}")
+ set(impl_file "${impl}")
+ add_custom_command(
+ OUTPUT ${cpp_file} ${private_file} ${decl_file} ${impl_file}
+ COMMAND ${QT_CMAKE_EXPORT_NAMESPACE}::qlalr ${flags} ${relative_input_file}
+ DEPENDS ${QT_CMAKE_EXPORT_NAMESPACE}::qlalr
+ MAIN_DEPENDENCY ${input_file}
+ VERBATIM
+ )
+ target_sources(${consuming_target} PRIVATE ${cpp_file} ${impl_file}
+ ${private_file} ${decl_file})
+ endforeach()
+endfunction()
diff --git a/cmake/QtMkspecHelpers.cmake b/cmake/QtMkspecHelpers.cmake
new file mode 100644
index 0000000000..cd08daa2c4
--- /dev/null
+++ b/cmake/QtMkspecHelpers.cmake
@@ -0,0 +1,146 @@
+# Copyright (C) 2023 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+macro(qt_internal_set_mkspecs_dir)
+ # Find the path to mkspecs/, depending on whether we are building as part of a standard qtbuild,
+ # or a module against an already installed version of qt.
+ if(NOT QT_MKSPECS_DIR)
+ if("${QT_BUILD_INTERNALS_PATH}" STREQUAL "")
+ get_filename_component(QT_MKSPECS_DIR "${CMAKE_CURRENT_LIST_DIR}/../mkspecs" ABSOLUTE)
+ else()
+ # We can rely on QT_BUILD_INTERNALS_RELOCATABLE_INSTALL_PREFIX being set by
+ # QtBuildInternalsExtra.cmake.
+ get_filename_component(
+ QT_MKSPECS_DIR
+ "${QT_BUILD_INTERNALS_RELOCATABLE_INSTALL_PREFIX}/${INSTALL_MKSPECSDIR}" ABSOLUTE)
+ endif()
+ set(QT_MKSPECS_DIR "${QT_MKSPECS_DIR}" CACHE INTERNAL "")
+ endif()
+endmacro()
+
+macro(qt_internal_setup_platform_definitions_and_mkspec)
+ # Platform define path, etc.
+ if(WIN32)
+ set(QT_DEFAULT_PLATFORM_DEFINITIONS WIN32 _ENABLE_EXTENDED_ALIGNED_STORAGE)
+ if(QT_64BIT)
+ list(APPEND QT_DEFAULT_PLATFORM_DEFINITIONS WIN64 _WIN64)
+ endif()
+
+ if(CLANG)
+ if(CMAKE_CXX_COMPILER_FRONTEND_VARIANT STREQUAL "MSVC" OR MSVC)
+ set(QT_DEFAULT_MKSPEC win32-clang-msvc)
+ elseif(CMAKE_CXX_COMPILER_FRONTEND_VARIANT STREQUAL "GNU" OR MINGW)
+ set(QT_DEFAULT_MKSPEC win32-clang-g++)
+ endif()
+ elseif(MSVC)
+ if(CMAKE_SYSTEM_PROCESSOR STREQUAL "arm64")
+ set(QT_DEFAULT_MKSPEC win32-arm64-msvc)
+ else()
+ set(QT_DEFAULT_MKSPEC win32-msvc)
+ endif()
+ elseif(MINGW)
+ set(QT_DEFAULT_MKSPEC win32-g++)
+ list(APPEND QT_DEFAULT_PLATFORM_DEFINITIONS MINGW_HAS_SECURE_API=1)
+ endif()
+ elseif(LINUX)
+ if(GCC)
+ set(QT_DEFAULT_MKSPEC linux-g++)
+ elseif(CLANG)
+ set(QT_DEFAULT_MKSPEC linux-clang)
+ endif()
+ elseif(ANDROID)
+ if(GCC)
+ set(QT_DEFAULT_MKSPEC android-g++)
+ elseif(CLANG)
+ set(QT_DEFAULT_MKSPEC android-clang)
+ endif()
+ elseif(IOS)
+ set(QT_DEFAULT_MKSPEC macx-ios-clang)
+ elseif(APPLE)
+ set(QT_DEFAULT_MKSPEC macx-clang)
+ elseif(WASM)
+ if(WASM64)
+ set(QT_DEFAULT_MKSPEC wasm-emscripten-64)
+ else()
+ set(QT_DEFAULT_MKSPEC wasm-emscripten)
+ endif()
+ elseif(QNX)
+ # Certain POSIX defines are not set if we don't compile with -std=gnuXX
+ set(QT_ENABLE_CXX_EXTENSIONS ON)
+
+ list(APPEND QT_DEFAULT_PLATFORM_DEFINITIONS _FORTIFY_SOURCE=2 _REENTRANT)
+
+ set(compiler_aarch64le aarch64le)
+ set(compiler_armle-v7 armv7le)
+ set(compiler_x86-64 x86_64)
+ set(compiler_x86 x86)
+ foreach(arch aarch64le armle-v7 x86-64 x86)
+ if (CMAKE_CXX_COMPILER_TARGET MATCHES "${compiler_${arch}}$")
+ set(QT_DEFAULT_MKSPEC qnx-${arch}-qcc)
+ endif()
+ endforeach()
+ elseif(FREEBSD)
+ if(CLANG)
+ set(QT_DEFAULT_MKSPEC freebsd-clang)
+ elseif(GCC)
+ set(QT_DEFAULT_MKSPEC freebsd-g++)
+ endif()
+ elseif(NETBSD)
+ set(QT_DEFAULT_MKSPEC netbsd-g++)
+ elseif(OPENBSD)
+ set(QT_DEFAULT_MKSPEC openbsd-g++)
+ elseif(SOLARIS)
+ if(GCC)
+ if(QT_64BIT)
+ set(QT_DEFAULT_MKSPEC solaris-g++-64)
+ else()
+ set(QT_DEFAULT_MKSPEC solaris-g++)
+ endif()
+ else()
+ if(QT_64BIT)
+ set(QT_DEFAULT_MKSPEC solaris-cc-64)
+ else()
+ set(QT_DEFAULT_MKSPEC solaris-cc)
+ endif()
+ endif()
+ elseif(HURD)
+ set(QT_DEFAULT_MKSPEC hurd-g++)
+ endif()
+
+ if(NOT QT_QMAKE_TARGET_MKSPEC)
+ set(QT_QMAKE_TARGET_MKSPEC "${QT_DEFAULT_MKSPEC}" CACHE STRING "QMake target mkspec")
+ endif()
+
+ if(CMAKE_CROSSCOMPILING)
+ set(QT_QMAKE_HOST_MKSPEC "${QT${PROJECT_VERSION_MAJOR}_HOST_INFO_QMAKE_MKSPEC}")
+ else()
+ set(QT_QMAKE_HOST_MKSPEC "${QT_QMAKE_TARGET_MKSPEC}")
+ endif()
+
+ if(NOT QT_QMAKE_TARGET_MKSPEC OR NOT EXISTS "${QT_MKSPECS_DIR}/${QT_QMAKE_TARGET_MKSPEC}")
+ if(NOT QT_QMAKE_TARGET_MKSPEC)
+ set(reason
+ "Platform is not detected. Please make sure your build environment is configured"
+ " properly or specify it manually using QT_QMAKE_TARGET_MKSPEC variable and one of"
+ " the known platforms.")
+ else()
+ set(reason "Unknown platform ${QT_QMAKE_TARGET_MKSPEC}")
+ endif()
+
+ file(GLOB known_platforms
+ LIST_DIRECTORIES true
+ RELATIVE "${QT_MKSPECS_DIR}"
+ "${QT_MKSPECS_DIR}/*"
+ )
+ list(JOIN known_platforms "\n " known_platforms)
+ message(FATAL_ERROR "${reason}\n"
+ "Known platforms:\n ${known_platforms}")
+ endif()
+
+ if(NOT DEFINED QT_DEFAULT_PLATFORM_DEFINITIONS)
+ set(QT_DEFAULT_PLATFORM_DEFINITIONS "")
+ endif()
+
+ set(QT_PLATFORM_DEFINITIONS ${QT_DEFAULT_PLATFORM_DEFINITIONS}
+ CACHE STRING "Qt platform specific pre-processor defines")
+endmacro()
diff --git a/cmake/QtModuleConfig.cmake.in b/cmake/QtModuleConfig.cmake.in
index 37527d1da6..06a7daad71 100644
--- a/cmake/QtModuleConfig.cmake.in
+++ b/cmake/QtModuleConfig.cmake.in
@@ -1,5 +1,10 @@
+# Copyright (C) 2024 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
@PACKAGE_INIT@
+cmake_minimum_required(VERSION @min_new_policy_version@...@max_new_policy_version@)
+
include(CMakeFindDependencyMacro)
get_filename_component(_import_prefix "${CMAKE_CURRENT_LIST_FILE}" PATH)
@@ -12,13 +17,21 @@ get_filename_component(_import_prefix "${_import_prefix}" REALPATH)
# Find required dependencies, if any.
if(EXISTS "${CMAKE_CURRENT_LIST_DIR}/@INSTALL_CMAKE_NAMESPACE@@target@Dependencies.cmake")
include("${CMAKE_CURRENT_LIST_DIR}/@INSTALL_CMAKE_NAMESPACE@@target@Dependencies.cmake")
+ _qt_internal_suggest_dependency_debugging(@target@
+ __qt_@target@_pkg ${CMAKE_FIND_PACKAGE_NAME}_NOT_FOUND_MESSAGE)
+endif()
+
+# If *ConfigDependencies.cmake exists, the variable value will be defined there.
+# Don't override it in that case.
+if(NOT DEFINED "@INSTALL_CMAKE_NAMESPACE@@target@_FOUND")
+ set("@INSTALL_CMAKE_NAMESPACE@@target@_FOUND" TRUE)
endif()
-if (NOT QT_NO_CREATE_TARGETS)
+if (NOT QT_NO_CREATE_TARGETS AND @INSTALL_CMAKE_NAMESPACE@@target@_FOUND)
include("${CMAKE_CURRENT_LIST_DIR}/@INSTALL_CMAKE_NAMESPACE@@target@Targets.cmake")
- if(NOT QT_NO_CREATE_VERSIONLESS_TARGETS)
- include("${CMAKE_CURRENT_LIST_DIR}/@INSTALL_CMAKE_NAMESPACE@@target@VersionlessTargets.cmake")
- endif()
+ include("${CMAKE_CURRENT_LIST_DIR}/@INSTALL_CMAKE_NAMESPACE@@target@AdditionalTargetInfo.cmake")
+ include("${CMAKE_CURRENT_LIST_DIR}/@INSTALL_CMAKE_NAMESPACE@@target@ExtraProperties.cmake"
+ OPTIONAL)
# DEPRECATED
# Provide old style variables for includes, compile definitions, etc.
@@ -61,15 +74,25 @@ if (NOT QT_NO_CREATE_TARGETS)
${_@QT_CMAKE_EXPORT_NAMESPACE@@target@_OWN_PRIVATE_INCLUDE_DIRS})
foreach(_module_dep ${_@QT_CMAKE_EXPORT_NAMESPACE@@target@_MODULE_DEPENDENCIES})
- list(APPEND @QT_CMAKE_EXPORT_NAMESPACE@@target@_INCLUDE_DIRS
+ if(_module_dep MATCHES ".+Private$")
+ set(_private_suffix "Private")
+ else()
+ set(_private_suffix "")
+ endif()
+ list(APPEND @QT_CMAKE_EXPORT_NAMESPACE@@target@${_private_suffix}_INCLUDE_DIRS
${@QT_CMAKE_EXPORT_NAMESPACE@${_module_dep}_INCLUDE_DIRS})
- list(APPEND @QT_CMAKE_EXPORT_NAMESPACE@@target@_PRIVATE_INCLUDE_DIRS
+ list(APPEND @QT_CMAKE_EXPORT_NAMESPACE@@target@${_private_suffix}_PRIVATE_INCLUDE_DIRS
${@QT_CMAKE_EXPORT_NAMESPACE@${_module_dep}_PRIVATE_INCLUDE_DIRS})
- list(APPEND @QT_CMAKE_EXPORT_NAMESPACE@@target@_DEFINITIONS
+ if(_private_suffix)
+ list(APPEND @QT_CMAKE_EXPORT_NAMESPACE@@target@_PRIVATE_INCLUDE_DIRS
+ ${@QT_CMAKE_EXPORT_NAMESPACE@${_module_dep}_PRIVATE_INCLUDE_DIRS})
+ endif()
+ list(APPEND @QT_CMAKE_EXPORT_NAMESPACE@@target@${_private_suffix}_DEFINITIONS
${@QT_CMAKE_EXPORT_NAMESPACE@${_module_dep}_DEFINITIONS})
- list(APPEND @QT_CMAKE_EXPORT_NAMESPACE@@target@_COMPILE_DEFINITIONS
+ list(APPEND @QT_CMAKE_EXPORT_NAMESPACE@@target@${_private_suffix}_COMPILE_DEFINITIONS
${@QT_CMAKE_EXPORT_NAMESPACE@${_module_dep}_COMPILE_DEFINITIONS})
endforeach()
+ unset(_private_suffix)
list(REMOVE_DUPLICATES @QT_CMAKE_EXPORT_NAMESPACE@@target@_INCLUDE_DIRS)
list(REMOVE_DUPLICATES @QT_CMAKE_EXPORT_NAMESPACE@@target@_PRIVATE_INCLUDE_DIRS)
@@ -77,33 +100,54 @@ if (NOT QT_NO_CREATE_TARGETS)
list(REMOVE_DUPLICATES @QT_CMAKE_EXPORT_NAMESPACE@@target@_COMPILE_DEFINITIONS)
endif()
-foreach(extra_cmake_include @extra_cmake_includes@)
- include("${CMAKE_CURRENT_LIST_DIR}/${extra_cmake_include}")
-endforeach()
-
-include(${_qt_@PROJECT_VERSION_MAJOR@_config_cmake_dir}/QtFeature.cmake)
+if (TARGET @QT_CMAKE_EXPORT_NAMESPACE@::@target@)
+ qt_make_features_available(@QT_CMAKE_EXPORT_NAMESPACE@::@target@)
-qt_make_features_available(@QT_CMAKE_EXPORT_NAMESPACE@::@target@)
+ foreach(extra_cmake_include @extra_cmake_includes@)
+ include("${CMAKE_CURRENT_LIST_DIR}/${extra_cmake_include}")
+ endforeach()
-set("@INSTALL_CMAKE_NAMESPACE@@target@_FOUND" TRUE)
-if(EXISTS "${CMAKE_CURRENT_LIST_DIR}/@INSTALL_CMAKE_NAMESPACE@@target@Plugins.cmake")
- include("${CMAKE_CURRENT_LIST_DIR}/@INSTALL_CMAKE_NAMESPACE@@target@Plugins.cmake")
-endif()
+ if(EXISTS "${CMAKE_CURRENT_LIST_DIR}/@INSTALL_CMAKE_NAMESPACE@@target@Plugins.cmake")
+ include("${CMAKE_CURRENT_LIST_DIR}/@INSTALL_CMAKE_NAMESPACE@@target@Plugins.cmake")
+ endif()
-list(APPEND QT_ALL_MODULES_FOUND_VIA_FIND_PACKAGE "@target@")
+ list(APPEND QT_ALL_MODULES_FOUND_VIA_FIND_PACKAGE "@target@")
-get_target_property(_qt_module_target_type "@INSTALL_CMAKE_NAMESPACE@::@target@" TYPE)
-if(NOT _qt_module_target_type STREQUAL "INTERFACE_LIBRARY")
- get_target_property(_qt_module_plugin_types
- @INSTALL_CMAKE_NAMESPACE@::@target@ MODULE_PLUGIN_TYPES)
- if(_qt_module_plugin_types)
- list(APPEND QT_ALL_PLUGIN_TYPES_FOUND_VIA_FIND_PACKAGE "${_qt_module_plugin_types}")
+ get_target_property(_qt_module_target_type "@INSTALL_CMAKE_NAMESPACE@::@target@" TYPE)
+ if(NOT _qt_module_target_type STREQUAL "INTERFACE_LIBRARY")
+ get_target_property(_qt_module_plugin_types
+ @INSTALL_CMAKE_NAMESPACE@::@target@ MODULE_PLUGIN_TYPES)
+ if(_qt_module_plugin_types)
+ list(APPEND QT_ALL_PLUGIN_TYPES_FOUND_VIA_FIND_PACKAGE "${_qt_module_plugin_types}")
+ endif()
endif()
-endif()
-# Load Module's BuildIntenals should any exist
-if (@INSTALL_CMAKE_NAMESPACE@BuildInternals_DIR AND
+ # Load Module's BuildInternals should any exist
+ if (@INSTALL_CMAKE_NAMESPACE@BuildInternals_DIR AND
EXISTS "${CMAKE_CURRENT_LIST_DIR}/@INSTALL_CMAKE_NAMESPACE@@target@BuildInternals.cmake")
- include("${CMAKE_CURRENT_LIST_DIR}/@INSTALL_CMAKE_NAMESPACE@@target@BuildInternals.cmake")
+ include("${CMAKE_CURRENT_LIST_DIR}/@INSTALL_CMAKE_NAMESPACE@@target@BuildInternals.cmake")
+ endif()
+
+ if(NOT QT_NO_CREATE_VERSIONLESS_TARGETS)
+ if(CMAKE_VERSION VERSION_LESS 3.18 OR QT_USE_OLD_VERSION_LESS_TARGETS)
+ include("${CMAKE_CURRENT_LIST_DIR}/@INSTALL_CMAKE_NAMESPACE@@target@VersionlessTargets.cmake")
+ else()
+ include("${CMAKE_CURRENT_LIST_DIR}/@INSTALL_CMAKE_NAMESPACE@@target@VersionlessAliasTargets.cmake")
+ endif()
+ endif()
+else()
+
+ set(@INSTALL_CMAKE_NAMESPACE@@target@_FOUND FALSE)
+ if(NOT DEFINED @INSTALL_CMAKE_NAMESPACE@@target@_NOT_FOUND_MESSAGE)
+ set(@INSTALL_CMAKE_NAMESPACE@@target@_NOT_FOUND_MESSAGE
+ "Target \"@QT_CMAKE_EXPORT_NAMESPACE@::@target@\" was not found.")
+
+ if(QT_NO_CREATE_TARGETS)
+ string(APPEND @INSTALL_CMAKE_NAMESPACE@@target@_NOT_FOUND_MESSAGE
+ "Possibly due to QT_NO_CREATE_TARGETS being set to TRUE and thus "
+ "${CMAKE_CURRENT_LIST_DIR}/@INSTALL_CMAKE_NAMESPACE@@target@Targets.cmake was not "
+ "included to define the target.")
+ endif()
+ endif()
endif()
diff --git a/cmake/QtModuleDependencies.cmake.in b/cmake/QtModuleDependencies.cmake.in
index 56819f8816..ba5922d1e2 100644
--- a/cmake/QtModuleDependencies.cmake.in
+++ b/cmake/QtModuleDependencies.cmake.in
@@ -1,92 +1,46 @@
-# Make sure @INSTALL_CMAKE_NAMESPACE@ is found before anything else.
-find_dependency(@INSTALL_CMAKE_NAMESPACE@ @PROJECT_VERSION@
- PATHS "${CMAKE_CURRENT_LIST_DIR}/.." ${QT_EXAMPLES_CMAKE_PREFIX_PATH} NO_DEFAULT_PATH
-)
-if (NOT @INSTALL_CMAKE_NAMESPACE@_FOUND)
- set(@INSTALL_CMAKE_NAMESPACE@@target@_FOUND FALSE)
- return()
-endif()
-
-# note: _third_party_deps example: "ICU\\;1.0\\;i18n uc data;ZLIB\\;\\;"
-set(_third_party_deps "@third_party_deps@")
-
-foreach(_target_dep ${_third_party_deps})
- list(GET _target_dep 0 pkg)
- list(GET _target_dep 1 version)
- list(GET _target_dep 2 components)
- set(find_package_args "${pkg}")
- if(version)
- list(APPEND find_package_args "${version}")
- endif()
+# Copyright (C) 2024 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
- if(components)
- string(REPLACE " " ";" components "${components}")
- find_dependency(${find_package_args} COMPONENTS ${components})
- else()
- find_dependency(${find_package_args})
- endif()
-
- if (NOT ${pkg}_FOUND)
- set(@INSTALL_CMAKE_NAMESPACE@@target@_FOUND FALSE)
- return()
- endif()
-endforeach()
-
-# Find Qt tool package.
-set(_tool_deps "@main_module_tool_deps@")
+# Make sure @INSTALL_CMAKE_NAMESPACE@ is found before anything else.
+set(@INSTALL_CMAKE_NAMESPACE@@target@_FOUND FALSE)
-# The tools do not provide linkage targets but executables, where a mismatch
-# between 32-bit target and 64-bit host does not matter.
-set(BACKUP_@target@_CMAKE_SIZEOF_VOID_P "${CMAKE_SIZEOF_VOID_P}")
-set(CMAKE_SIZEOF_VOID_P "")
+if("${_qt_cmake_dir}" STREQUAL "")
+ set(_qt_cmake_dir "${QT_TOOLCHAIN_RELOCATABLE_CMAKE_DIR}")
+endif()
+set(__qt_use_no_default_path_for_qt_packages "NO_DEFAULT_PATH")
+if(QT_DISABLE_NO_DEFAULT_PATH_IN_QT_PACKAGES)
+ set(__qt_use_no_default_path_for_qt_packages "")
+endif()
-if(QT_HOST_PATH)
- # Make sure that the tools find the host tools first
- set(BACKUP_@target@_CMAKE_PREFIX_PATH ${CMAKE_PREFIX_PATH})
- set(BACKUP_@target@_CMAKE_FIND_ROOT_PATH ${CMAKE_FIND_ROOT_PATH})
- list(PREPEND CMAKE_PREFIX_PATH "${QT_HOST_PATH_CMAKE_DIR}")
- list(PREPEND CMAKE_FIND_ROOT_PATH "${QT_HOST_PATH}")
+# Don't propagate REQUIRED so we don't immediately FATAL_ERROR, rather let the find_dependency calls
+# set _NOT_FOUND_MESSAGE which will be displayed by the includer of the Dependencies file.
+set(${CMAKE_FIND_PACKAGE_NAME}_FIND_REQUIRED FALSE)
+
+if(NOT @INSTALL_CMAKE_NAMESPACE@_FOUND)
+ find_dependency(@INSTALL_CMAKE_NAMESPACE@ @main_qt_package_version@
+ PATHS
+ ${QT_BUILD_CMAKE_PREFIX_PATH}
+ "${CMAKE_CURRENT_LIST_DIR}/.."
+ "${_qt_cmake_dir}"
+ ${_qt_additional_packages_prefix_paths}
+ ${__qt_use_no_default_path_for_qt_packages}
+ )
endif()
-foreach(_target_dep ${_tool_deps})
- list(GET _target_dep 0 pkg)
- list(GET _target_dep 1 version)
- find_dependency(${pkg} ${version})
+# note: _third_party_deps example: "ICU\\;FALSE\\;1.0\\;i18n uc data;ZLIB\\;FALSE\\;\\;"
+set(__qt_@target@_third_party_deps "@third_party_deps@")
+_qt_internal_find_third_party_dependencies("@target@" __qt_@target@_third_party_deps)
- if (NOT ${pkg}_FOUND)
- set(@INSTALL_CMAKE_NAMESPACE@@target@_FOUND FALSE)
- set(CMAKE_SIZEOF_VOID_P "${BACKUP_@target@_CMAKE_SIZEOF_VOID_P}")
- if(QT_HOST_PATH)
- set(CMAKE_PREFIX_PATH ${BACKUP_@target@_CMAKE_PREFIX_PATH})
- set(CMAKE_FIND_ROOT_PATH ${BACKUP_@target@_CMAKE_FIND_ROOT_PATH})
- endif()
- return()
- endif()
-endforeach()
-if(QT_HOST_PATH)
- set(CMAKE_PREFIX_PATH ${BACKUP_@target@_CMAKE_PREFIX_PATH})
- set(CMAKE_FIND_ROOT_PATH ${BACKUP_@target@_CMAKE_FIND_ROOT_PATH})
-endif()
-set(CMAKE_SIZEOF_VOID_P "${BACKUP_@target@_CMAKE_SIZEOF_VOID_P}")
+# Find Qt tool package.
+set(__qt_@target@_tool_deps "@main_module_tool_deps@")
+_qt_internal_find_tool_dependencies("@target@" __qt_@target@_tool_deps)
# note: target_deps example: "Qt6Core\;5.12.0;Qt6Gui\;5.12.0"
-set(_target_deps "@target_deps@")
-foreach(_target_dep ${_target_deps})
- list(GET _target_dep 0 pkg)
- list(GET _target_dep 1 version)
-
- if (NOT ${pkg}_FOUND)
- find_dependency(${pkg} ${version}
- PATHS "${CMAKE_CURRENT_LIST_DIR}/.." ${QT_EXAMPLES_CMAKE_PREFIX_PATH} NO_DEFAULT_PATH
- )
- endif()
-
- if (NOT ${pkg}_FOUND)
- set(@INSTALL_CMAKE_NAMESPACE@@target@_FOUND FALSE)
- return()
- endif()
-endforeach()
+set(__qt_@target@_target_deps "@target_deps@")
+set(__qt_@target@_find_dependency_paths "${CMAKE_CURRENT_LIST_DIR}/.." "${_qt_cmake_dir}")
+_qt_internal_find_qt_dependencies("@target@" __qt_@target@_target_deps
+ __qt_@target@_find_dependency_paths)
set(_@QT_CMAKE_EXPORT_NAMESPACE@@target@_MODULE_DEPENDENCIES "@qt_module_dependencies@")
-
+set(@INSTALL_CMAKE_NAMESPACE@@target@_FOUND TRUE)
diff --git a/cmake/QtModuleHeadersCheck.cmake b/cmake/QtModuleHeadersCheck.cmake
new file mode 100644
index 0000000000..39053f3e10
--- /dev/null
+++ b/cmake/QtModuleHeadersCheck.cmake
@@ -0,0 +1,34 @@
+cmake_minimum_required(VERSION 3.16)
+# The PARAMETERS file should specify the following variables for the correct work of
+# this script:
+# HEADER_CHECK_EXCEPTIONS - path to file that contains exceptions.
+# The file is created by syncqt.
+#
+# HEADER_CHECK_COMPILER_COMMAND_LINE - compiler command line
+include("${PARAMETERS}")
+
+if(EXISTS ${HEADER_CHECK_EXCEPTIONS})
+ file(READ ${HEADER_CHECK_EXCEPTIONS} header_check_exception_list)
+endif()
+
+get_filename_component(header "${INPUT_HEADER_FILE}" REALPATH)
+file(TO_CMAKE_PATH "${header}" header)
+foreach(exception IN LISTS header_check_exception_list)
+ file(TO_CMAKE_PATH "${exception}" exception)
+ if(exception STREQUAL header)
+ file(WRITE "${OUTPUT_ARTIFACT}" "skipped")
+ return()
+ endif()
+endforeach()
+
+execute_process(COMMAND ${HEADER_CHECK_COMPILER_COMMAND_LINE}
+ RESULT_VARIABLE result
+ OUTPUT_VARIABLE output
+ ERROR_VARIABLE output
+)
+
+if(NOT result EQUAL 0)
+ message(FATAL_ERROR "${INPUT_HEADER_FILE} header check"
+ " failed: ${HEADER_CHECK_COMPILER_COMMAND_LINE}\n"
+ " ${output}")
+endif()
diff --git a/cmake/QtModuleHelpers.cmake b/cmake/QtModuleHelpers.cmake
new file mode 100644
index 0000000000..ba03173073
--- /dev/null
+++ b/cmake/QtModuleHelpers.cmake
@@ -0,0 +1,1410 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+macro(qt_internal_get_internal_add_module_keywords option_args single_args multi_args)
+ set(${option_args}
+ STATIC
+ EXCEPTIONS
+ INTERNAL_MODULE
+ HEADER_MODULE
+ DISABLE_TOOLS_EXPORT
+ SKIP_DEPENDS_INCLUDE
+ NO_MODULE_HEADERS
+ NO_SYNC_QT
+ NO_PRIVATE_MODULE
+ NO_CONFIG_HEADER_FILE
+ NO_ADDITIONAL_TARGET_INFO
+ NO_GENERATE_METATYPES
+ NO_HEADERSCLEAN_CHECK
+ GENERATE_CPP_EXPORTS # deprecated
+ NO_GENERATE_CPP_EXPORTS
+ NO_UNITY_BUILD
+ )
+ set(${single_args}
+ MODULE_INCLUDE_NAME
+ MODULE_INTERFACE_NAME
+ CONFIG_MODULE_NAME
+ PRECOMPILED_HEADER
+ CONFIGURE_FILE_PATH
+ CPP_EXPORT_HEADER_BASE_NAME
+ EXTERNAL_HEADERS_DIR
+ PRIVATE_HEADER_FILTERS
+ QPA_HEADER_FILTERS
+ RHI_HEADER_FILTERS
+ SSG_HEADER_FILTERS
+ HEADER_SYNC_SOURCE_DIRECTORY
+ ${__default_target_info_args}
+ )
+ set(${multi_args}
+ QMAKE_MODULE_CONFIG
+ EXTRA_CMAKE_FILES
+ EXTRA_CMAKE_INCLUDES
+ EXTERNAL_HEADERS
+ POLICIES
+ ${__default_private_args}
+ ${__default_public_args}
+ ${__default_private_module_args}
+ )
+endmacro()
+
+# The function helps to wrap module include paths with the header existence check.
+function(qt_internal_append_include_directories_with_headers_check target list_to_append type)
+ string(TOLOWER "${type}" type)
+ string(JOIN "" has_headers_check
+ "$<BOOL:"
+ "$<TARGET_PROPERTY:"
+ "$<TARGET_NAME:${target}>,"
+ "_qt_module_has_${type}_headers"
+ ">"
+ ">"
+ )
+ foreach(directory IN LISTS ARGN)
+ list(APPEND ${list_to_append}
+ "$<${has_headers_check}:${directory}>")
+ endforeach()
+ set(${list_to_append} "${${list_to_append}}" PARENT_SCOPE)
+endfunction()
+
+# This is the main entry function for creating a Qt module, that typically
+# consists of a library, public header files, private header files and configurable
+# features.
+#
+# A CMake target with the specified target parameter is created. If the current source
+# directory has a configure.cmake file, then that is also processed for feature definition
+# and testing. Any features defined as well as any features coming from dependencies to
+# this module are imported into the scope of the calling feature.
+#
+# Target is without leading "Qt". So e.g. the "QtCore" module has the target "Core".
+#
+# Options:
+# NO_ADDITIONAL_TARGET_INFO
+# Don't generate a Qt6*AdditionalTargetInfo.cmake file.
+# The caller is responsible for creating one.
+#
+# MODULE_INTERFACE_NAME
+# The custom name of the module interface. This name is used as a part of the include paths
+# associated with the module and other interface names. The default value is the target name.
+# If the INTERNAL_MODULE option is specified, MODULE_INTERFACE_NAME is not specified and the
+# target name ends with the suffix 'Private', the MODULE_INTERFACE_NAME value defaults to the
+# non-suffixed target name, e.g.:
+# For the SomeInternalModulePrivate target, the MODULE_INTERFACE_NAME will be
+# SomeInternalModule
+#
+# HEADER_MODULE
+# Creates an interface library instead of following the Qt configuration default. Mutually
+# exclusive with STATIC.
+#
+# STATIC
+# Creates a static library instead of following the Qt configuration default. Mutually
+# exclusive with HEADER_MODULE.
+#
+# EXTERNAL_HEADERS
+# A explicit list of non qt headers (like 3rdparty) to be installed.
+# Note this option overrides install headers used as PUBLIC_HEADER by cmake install(TARGET)
+# otherwise set by syncqt.
+#
+# EXTERNAL_HEADERS_DIR
+# A module directory with non qt headers (like 3rdparty) to be installed.
+# Note this option overrides install headers used as PUBLIC_HEADER by cmake install(TARGET)
+# otherwise set by syncqt.
+#
+# PRIVATE_HEADER_FILTERS
+# The regular expressions that filter private header files out of target sources.
+# The value must use the following format 'regex1|regex2|regex3'.
+#
+# QPA_HEADER_FILTERS
+# The regular expressions that filter QPA header files out of target sources.
+# The value must use the following format 'regex1|regex2|regex3'.
+#
+# RHI_HEADER_FILTERS
+# The regular expressions that filter RHI header files out of target sources.
+# The value must use the following format 'regex1|regex2|regex3'.
+#
+# SSG_HEADER_FILTERS
+# The regular expressions that filter ssg header files out of target sources.
+# The value must use the following format 'regex1|regex2|regex3'.
+#
+# HEADER_SYNC_SOURCE_DIRECTORY
+# The source directory for header sync procedure. Header files outside this directory will be
+# ignored by syncqt. The specifying this directory allows to skip the parsing of the whole
+# CMAKE_CURRENT_SOURCE_DIR for the header files that needs to be synced and only parse the
+# single subdirectory, that meanwhile can be outside the CMAKE_CURRENT_SOURCE_DIR tree.
+function(qt_internal_add_module target)
+ qt_internal_get_internal_add_module_keywords(
+ module_option_args
+ module_single_args
+ module_multi_args
+ )
+
+ cmake_parse_arguments(PARSE_ARGV 1 arg
+ "${module_option_args}"
+ "${module_single_args}"
+ "${module_multi_args}"
+ )
+ _qt_internal_validate_all_args_are_parsed(arg)
+
+ set(is_internal_module FALSE)
+ if(arg_INTERNAL_MODULE)
+ set(is_internal_module TRUE)
+ set(arg_INTERNAL_MODULE "INTERNAL_MODULE")
+ set(arg_NO_PRIVATE_MODULE TRUE)
+ # Assume the interface name of the internal module should be the module name without the
+ # 'Private' suffix.
+ if(NOT arg_MODULE_INTERFACE_NAME)
+ if(target MATCHES "(.*)Private$")
+ set(arg_MODULE_INTERFACE_NAME "${CMAKE_MATCH_1}")
+ else()
+ message(WARNING "The internal module target should end with the 'Private' suffix.")
+ endif()
+ endif()
+ else()
+ unset(arg_INTERNAL_MODULE)
+ endif()
+
+ if(NOT arg_MODULE_INTERFACE_NAME)
+ set(arg_MODULE_INTERFACE_NAME "${target}")
+ endif()
+
+ ### Define Targets:
+ if(arg_HEADER_MODULE)
+ set(type_to_create INTERFACE)
+ elseif(arg_STATIC)
+ set(type_to_create STATIC)
+ else()
+ # Use default depending on Qt configuration.
+ set(type_to_create "")
+ endif()
+
+ _qt_internal_add_library("${target}" ${type_to_create})
+ qt_internal_mark_as_internal_library("${target}")
+
+ get_target_property(target_type ${target} TYPE)
+
+ set(is_interface_lib 0)
+ set(is_shared_lib 0)
+ set(is_static_lib 0)
+ if(target_type STREQUAL "INTERFACE_LIBRARY")
+ set(is_interface_lib 1)
+ elseif(target_type STREQUAL "STATIC_LIBRARY")
+ set(is_static_lib 1)
+ elseif(target_type STREQUAL "SHARED_LIBRARY")
+ set(is_shared_lib 1)
+ else()
+ message(FATAL_ERROR "Invalid target type '${target_type}' for Qt module '${target}'")
+ endif()
+
+ if(NOT arg_NO_SYNC_QT AND NOT arg_NO_MODULE_HEADERS AND arg_MODULE_INCLUDE_NAME)
+ # qt_internal_module_info uses this property if it's set, so it must be
+ # specified before the qt_internal_module_info call.
+ set_target_properties(${target} PROPERTIES
+ _qt_module_include_name ${arg_MODULE_INCLUDE_NAME}
+ )
+ endif()
+
+ set_target_properties(${target} PROPERTIES
+ _qt_module_interface_name "${arg_MODULE_INTERFACE_NAME}"
+ _qt_package_version "${PROJECT_VERSION}"
+ _qt_package_name "${INSTALL_CMAKE_NAMESPACE}${target}"
+ )
+ set(export_properties
+ "_qt_module_interface_name"
+ "_qt_package_version"
+ "_qt_package_name"
+ )
+ if(NOT is_internal_module)
+ set_target_properties(${target} PROPERTIES
+ _qt_is_public_module TRUE
+ )
+ list(APPEND export_properties
+ "_qt_is_public_module"
+ )
+ if(NOT ${arg_NO_PRIVATE_MODULE})
+ set_target_properties(${target} PROPERTIES
+ _qt_private_module_target_name "${target}Private"
+ )
+ list(APPEND export_properties
+ "_qt_private_module_target_name"
+ )
+ endif()
+ endif()
+
+ set_property(TARGET ${target} APPEND PROPERTY EXPORT_PROPERTIES "${export_properties}")
+
+ qt_internal_module_info(module "${target}")
+ qt_internal_add_qt_repo_known_module("${target}")
+ if(arg_INTERNAL_MODULE)
+ set_target_properties(${target} PROPERTIES _qt_is_internal_module TRUE)
+ set_property(TARGET ${target} APPEND PROPERTY EXPORT_PROPERTIES _qt_is_internal_module)
+ endif()
+
+ if(NOT arg_CONFIG_MODULE_NAME)
+ set(arg_CONFIG_MODULE_NAME "${module_lower}")
+ endif()
+
+ set(module_config_header "qt${arg_CONFIG_MODULE_NAME}-config.h")
+ set(module_config_private_header "qt${arg_CONFIG_MODULE_NAME}-config_p.h")
+ # qt<module>-config.h/-config_p.h header files are not marked as GENERATED automatically
+ # for old CMake versions. Set the property explicitly here.
+ set_source_files_properties("${module_config_header}" "${module_config_private_header}"
+ PROPERTIES
+ GENERATED TRUE
+ SKIP_AUTOGEN TRUE
+ )
+
+ # Module define needs to take into account the config module name.
+ string(TOUPPER "${arg_CONFIG_MODULE_NAME}" module_define_infix)
+ string(REPLACE "-" "_" module_define_infix "${module_define_infix}")
+ string(REPLACE "." "_" module_define_infix "${module_define_infix}")
+
+ set(property_prefix "INTERFACE_")
+ if(NOT arg_HEADER_MODULE)
+ set(property_prefix "")
+ endif()
+
+ if(arg_INTERNAL_MODULE)
+ string(APPEND arg_CONFIG_MODULE_NAME "_private")
+ endif()
+ set_target_properties(${target} PROPERTIES
+ _qt_config_module_name "${arg_CONFIG_MODULE_NAME}"
+ ${property_prefix}QT_QMAKE_MODULE_CONFIG "${arg_QMAKE_MODULE_CONFIG}")
+ set_property(TARGET "${target}" APPEND PROPERTY EXPORT_PROPERTIES _qt_config_module_name)
+
+ set(is_framework 0)
+ if(QT_FEATURE_framework AND NOT ${arg_HEADER_MODULE} AND NOT ${arg_STATIC})
+ set(is_framework 1)
+ set_target_properties(${target} PROPERTIES
+ FRAMEWORK TRUE
+ FRAMEWORK_VERSION "A" # Not based on Qt major version
+ MACOSX_FRAMEWORK_IDENTIFIER org.qt-project.${module}
+ MACOSX_FRAMEWORK_BUNDLE_VERSION ${PROJECT_VERSION}
+ MACOSX_FRAMEWORK_SHORT_VERSION_STRING ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}
+ )
+ qt_internal_get_framework_info(fw ${target})
+ endif()
+
+ if(NOT QT_FEATURE_no_direct_extern_access AND QT_FEATURE_reduce_relocations AND
+ UNIX AND NOT is_interface_lib)
+ # On x86 and x86-64 systems with ELF binaries (especially Linux), due to
+ # a new optimization in GCC 5.x in combination with a recent version of
+ # GNU binutils, compiling Qt applications with -fPIE is no longer
+ # enough.
+ # Applications now need to be compiled with the -fPIC option if the Qt option
+ # \"reduce relocations\" is active.
+ target_compile_options(${target} INTERFACE -fPIC)
+ if(GCC AND is_shared_lib)
+ target_link_options(${target} PRIVATE LINKER:-Bsymbolic-functions)
+ endif()
+ endif()
+
+ if((FEATURE_ltcg OR CMAKE_INTERPROCEDURAL_OPTIMIZATION) AND GCC AND is_static_lib)
+ # CMake <= 3.19 appends -fno-fat-lto-objects for all library types if
+ # CMAKE_INTERPROCEDURAL_OPTIMIZATION is enabled. Static libraries need
+ # the opposite compiler option.
+ # (https://gitlab.kitware.com/cmake/cmake/-/issues/21696)
+ target_compile_options(${target} PRIVATE -ffat-lto-objects)
+ endif()
+
+ qt_internal_add_target_aliases("${target}")
+ qt_skip_warnings_are_errors_when_repo_unclean("${target}")
+ _qt_internal_apply_strict_cpp("${target}")
+
+ # No need to compile Q_IMPORT_PLUGIN-containing files for non-executables.
+ if(is_static_lib)
+ _qt_internal_disable_static_default_plugins("${target}")
+ endif()
+
+ # Add _private target to link against the private headers:
+ set(target_private "${target}Private")
+ if(NOT ${arg_NO_PRIVATE_MODULE})
+ add_library("${target_private}" INTERFACE)
+ qt_internal_add_target_aliases("${target_private}")
+ set_target_properties(${target_private} PROPERTIES
+ _qt_config_module_name ${arg_CONFIG_MODULE_NAME}_private
+ _qt_package_version "${PROJECT_VERSION}"
+ _qt_package_name "${INSTALL_CMAKE_NAMESPACE}${target}"
+ _qt_is_private_module TRUE
+ _qt_public_module_target_name "${target}"
+ )
+ set(export_properties
+ "_qt_config_module_name"
+ "_qt_package_version"
+ "_qt_package_name"
+ "_qt_is_private_module"
+ "_qt_public_module_target_name"
+ )
+ set_property(TARGET "${target_private}" APPEND PROPERTY
+ EXPORT_PROPERTIES "${export_properties}")
+ endif()
+
+ # FIXME: This workaround is needed because the deployment logic
+ # for iOS and WASM just copies/embeds the directly linked library,
+ # which will just be a versioned symlink to the actual library.
+ if((UIKIT OR WASM) AND BUILD_SHARED_LIBS)
+ set(version_args "")
+ else()
+ set(version_args
+ VERSION ${PROJECT_VERSION}
+ SOVERSION ${PROJECT_VERSION_MAJOR})
+ endif()
+
+ if(NOT arg_HEADER_MODULE)
+ set_target_properties(${target} PROPERTIES
+ LIBRARY_OUTPUT_DIRECTORY "${QT_BUILD_DIR}/${INSTALL_LIBDIR}"
+ RUNTIME_OUTPUT_DIRECTORY "${QT_BUILD_DIR}/${INSTALL_BINDIR}"
+ ARCHIVE_OUTPUT_DIRECTORY "${QT_BUILD_DIR}/${INSTALL_LIBDIR}"
+ ${version_args}
+ )
+ qt_set_target_info_properties(${target} ${ARGN})
+ qt_handle_multi_config_output_dirs("${target}")
+
+ if(NOT BUILD_SHARED_LIBS AND LINUX)
+ # Horrible workaround for static build failures due to incorrect static library link
+ # order. By increasing the multiplicity to 3, each library cycle will be repeated
+ # 3 times on the link line, reducing the probability of undefined symbols at
+ # link time.
+ # These failures are only observed on Linux with the ld linker (not sure about
+ # ld.gold).
+ # Allow opting out and modifying the value via cache value, in case if we urgently
+ # need to increase it without waiting for the qtbase change to propagate to
+ # other dependent repos.
+ # The proper fix will be to get rid of the cycles in the future.
+ # See QTBUG-83498 for details.
+ set(default_link_cycle_multiplicity "3")
+ if(DEFINED QT_LINK_CYCLE_MULTIPLICITY)
+ set(default_link_cycle_multiplicity "${QT_LINK_CYCLE_MULTIPLICITY}")
+ endif()
+ if(default_link_cycle_multiplicity)
+ set_property(TARGET "${target}"
+ PROPERTY
+ LINK_INTERFACE_MULTIPLICITY "${default_link_cycle_multiplicity}")
+ endif()
+ endif()
+
+ if (arg_SKIP_DEPENDS_INCLUDE)
+ set_target_properties(${target} PROPERTIES _qt_module_skip_depends_include TRUE)
+ set_property(TARGET "${target}" APPEND PROPERTY
+ EXPORT_PROPERTIES _qt_module_skip_depends_include)
+ endif()
+ if(is_framework)
+ set_target_properties(${target} PROPERTIES
+ OUTPUT_NAME ${fw_name}
+ )
+ else()
+ set_target_properties(${target} PROPERTIES
+ OUTPUT_NAME "${INSTALL_CMAKE_NAMESPACE}${module_interface_name}${QT_LIBINFIX}"
+ )
+ endif()
+
+ qt_set_common_target_properties(${target})
+
+ if (WIN32 AND BUILD_SHARED_LIBS)
+ _qt_internal_generate_win32_rc_file(${target})
+ endif()
+ endif()
+
+ # Module headers:
+ set_property(TARGET "${target}" APPEND PROPERTY EXPORT_PROPERTIES _qt_module_has_headers)
+ if(${arg_NO_MODULE_HEADERS} OR ${arg_NO_SYNC_QT})
+ set_target_properties("${target}" PROPERTIES
+ _qt_module_has_headers OFF)
+ else()
+ set_property(TARGET ${target} APPEND PROPERTY EXPORT_PROPERTIES _qt_module_include_name)
+ set_target_properties("${target}" PROPERTIES
+ _qt_module_include_name "${module_include_name}"
+ _qt_module_has_headers ON
+ )
+
+ set(sync_source_directory "${CMAKE_CURRENT_SOURCE_DIR}")
+ if(arg_HEADER_SYNC_SOURCE_DIRECTORY)
+ set(sync_source_directory "${arg_HEADER_SYNC_SOURCE_DIRECTORY}")
+ endif()
+ set_target_properties(${target} PROPERTIES
+ _qt_sync_source_directory "${sync_source_directory}")
+ # We should not generate export headers if module is defined as pure STATIC.
+ # Static libraries don't need to export their symbols, and corner cases when sources are
+ # also used in shared libraries, should be handled manually.
+ if((NOT arg_NO_GENERATE_CPP_EXPORTS OR arg_GENERATE_CPP_EXPORTS) AND NOT arg_STATIC
+ AND NOT arg_HEADER_MODULE)
+ if(arg_CPP_EXPORT_HEADER_BASE_NAME)
+ set(cpp_export_header_base_name
+ "CPP_EXPORT_HEADER_BASE_NAME;${arg_CPP_EXPORT_HEADER_BASE_NAME}"
+ )
+ endif()
+ qt_internal_generate_cpp_global_exports(${target} ${module_define_infix}
+ "${cpp_export_header_base_name}"
+ )
+ endif()
+
+ set(module_depends_header
+ "${module_build_interface_include_dir}/${module_include_name}Depends")
+ set_source_files_properties("${module_depends_header}" PROPERTIES GENERATED TRUE)
+ set_target_properties(${target} PROPERTIES _qt_module_depends_header
+ "${module_depends_header}")
+ if(NOT ${arg_HEADER_MODULE})
+ set(module_header "${module_build_interface_include_dir}/${module_include_name}")
+ set_property(TARGET "${target}" PROPERTY MODULE_HEADER
+ "${module_header}")
+ endif()
+
+ set(qpa_filter_regex "")
+ if(arg_QPA_HEADER_FILTERS)
+ set(qpa_filter_regex "${arg_QPA_HEADER_FILTERS}")
+ endif()
+ set_target_properties(${target}
+ PROPERTIES _qt_module_qpa_headers_filter_regex "${qpa_filter_regex}")
+
+ set(rhi_filter_regex "")
+ if(arg_RHI_HEADER_FILTERS)
+ set(rhi_filter_regex "${arg_RHI_HEADER_FILTERS}")
+ endif()
+ set_target_properties(${target}
+ PROPERTIES _qt_module_rhi_headers_filter_regex "${rhi_filter_regex}")
+
+ set(ssg_filter_regex "")
+ if(arg_SSG_HEADER_FILTERS)
+ set(ssg_filter_regex "${arg_SSG_HEADER_FILTERS}")
+ endif()
+ set_target_properties(${target}
+ PROPERTIES _qt_module_ssg_headers_filter_regex "${ssg_filter_regex}")
+
+ set(private_filter_regex ".+_p(ch)?\\.h")
+ if(arg_PRIVATE_HEADER_FILTERS)
+ set(private_filter_regex "${private_filter_regex}|${arg_PRIVATE_HEADER_FILTERS}")
+ endif()
+ set_target_properties(${target}
+ PROPERTIES _qt_module_private_headers_filter_regex "${private_filter_regex}")
+
+ # If EXTERNAL_HEADERS_DIR is set we install the specified directory and keep the structure
+ # without taking into the account the CMake source tree and syncqt outputs.
+ if(arg_EXTERNAL_HEADERS_DIR)
+ set_property(TARGET ${target}
+ PROPERTY _qt_external_headers_dir "${arg_EXTERNAL_HEADERS_DIR}")
+ qt_install(DIRECTORY "${arg_EXTERNAL_HEADERS_DIR}/"
+ DESTINATION "${module_install_interface_include_dir}"
+ )
+ endif()
+ endif()
+
+ if(arg_NO_HEADERSCLEAN_CHECK OR arg_NO_MODULE_HEADERS OR arg_NO_SYNC_QT
+ OR NOT INPUT_headersclean)
+ set_target_properties("${target}" PROPERTIES _qt_no_headersclean_check ON)
+ endif()
+
+ if(NOT arg_HEADER_MODULE)
+ # Plugin types associated to a module
+ if(NOT "x${arg_PLUGIN_TYPES}" STREQUAL "x")
+ qt_internal_add_plugin_types("${target}" "${arg_PLUGIN_TYPES}")
+ endif()
+ endif()
+
+ qt_internal_library_deprecation_level(deprecation_define)
+
+ if(NOT arg_HEADER_MODULE)
+ qt_autogen_tools_initial_setup(${target})
+ endif()
+
+ set(private_includes
+ "$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>"
+ "$<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}>"
+ ${arg_INCLUDE_DIRECTORIES}
+ )
+
+ set(public_includes "")
+ set(public_headers_list "public_includes")
+ if(is_framework)
+ set(public_headers_list "private_includes")
+ endif()
+
+ # Make sure the BUILD_INTERFACE include paths come before the framework headers, so that the
+ # the compiler prefers the build dir includes.
+ #
+ # Make sure to add non-framework "build_dir/include" as an include path for moc to find the
+ # currently built module headers. qmake does this too.
+ # Framework-style include paths are found by moc when cmQtAutoMocUic.cxx detects frameworks by
+ # looking at an include path and detecting a "QtFoo.framework/Headers" path.
+ # Make sure to create such paths for both the the BUILD_INTERFACE and the INSTALL_INTERFACE.
+ #
+ # Only add syncqt headers if they exist.
+ # This handles cases like QmlDevToolsPrivate which do not have their own headers, but borrow
+ # them from another module.
+ if(NOT arg_NO_SYNC_QT AND NOT arg_NO_MODULE_HEADERS)
+ # Don't include private headers unless they exist, aka syncqt created them.
+ qt_internal_append_include_directories_with_headers_check(${target}
+ private_includes PRIVATE
+ "$<BUILD_INTERFACE:${module_build_interface_versioned_include_dir}>"
+ "$<BUILD_INTERFACE:${module_build_interface_versioned_inner_include_dir}>"
+ )
+
+ list(APPEND public_includes
+ # For the syncqt headers
+ "$<BUILD_INTERFACE:${repo_build_interface_include_dir}>"
+ "$<BUILD_INTERFACE:${module_build_interface_include_dir}>")
+ endif()
+
+ if(is_framework)
+ set(fw_install_dir "${INSTALL_LIBDIR}/${fw_dir}")
+ set(fw_install_header_dir "${INSTALL_LIBDIR}/${fw_header_dir}")
+ set(fw_output_header_dir "${QT_BUILD_DIR}/${fw_install_header_dir}")
+ list(APPEND public_includes
+ # Add the framework Headers subdir, so that non-framework-style includes work. The
+ # BUILD_INTERFACE Headers symlink was previously claimed not to exist at the relevant
+ # time, and a fully specified Header path was used instead. This doesn't seem to be a
+ # problem anymore.
+ "$<BUILD_INTERFACE:${fw_output_header_dir}>"
+ "$<INSTALL_INTERFACE:${fw_install_header_dir}>"
+
+ # Add the lib/Foo.framework dir as an include path to let CMake generate
+ # the -F compiler flag for framework-style includes to work.
+ # Make sure it is added AFTER the lib/Foo.framework/Headers include path,
+ # to mitigate issues like QTBUG-101718 and QTBUG-101775 where an include like
+ # #include <QtCore> might cause moc to include the QtCore framework shared library
+ # instead of the actual header.
+ "$<INSTALL_INTERFACE:${fw_install_dir}>"
+ )
+ endif()
+
+ if(NOT arg_NO_MODULE_HEADERS AND NOT arg_NO_SYNC_QT)
+ # For the syncqt headers
+ list(APPEND ${public_headers_list}
+ "$<INSTALL_INTERFACE:${module_install_interface_include_dir}>")
+
+ # To support finding Qt module includes that are not installed into the main Qt prefix.
+ # Use case: A Qt module built by Conan installed into a prefix other than the main prefix.
+ # This does duplicate the include path set on Qt6::Platform target, but CMake is smart
+ # enough to deduplicate the include paths on the command line.
+ # Frameworks are automatically handled by CMake in cmLocalGenerator::GetIncludeFlags()
+ # by additionally passing the 'QtFoo.framework/..' dir with an -iframework argument.
+ list(APPEND ${public_headers_list} "$<INSTALL_INTERFACE:${INSTALL_INCLUDEDIR}>")
+ endif()
+ list(APPEND ${public_headers_list} ${arg_PUBLIC_INCLUDE_DIRECTORIES})
+
+ set(defines_for_extend_target "")
+
+ if(NOT arg_HEADER_MODULE)
+ list(APPEND defines_for_extend_target
+ QT_NO_CAST_TO_ASCII QT_ASCII_CAST_WARNINGS
+ QT_MOC_COMPAT #we don't need warnings from calling moc code in our generated code
+ QT_DEPRECATED_WARNINGS
+ QT_BUILDING_QT
+ QT_BUILD_${module_define_infix}_LIB ### FIXME: use QT_BUILD_ADDON for Add-ons or remove if we don't have add-ons anymore
+ ${deprecation_define}
+ )
+ list(APPEND arg_LIBRARIES Qt::PlatformModuleInternal)
+ endif()
+
+ qt_internal_add_repo_local_defines("${target}")
+
+ if(arg_NO_UNITY_BUILD)
+ set(arg_NO_UNITY_BUILD "NO_UNITY_BUILD")
+ else()
+ set(arg_NO_UNITY_BUILD "")
+ endif()
+
+ if(NOT arg_EXTERNAL_HEADERS)
+ set(arg_EXTERNAL_HEADERS "")
+ endif()
+
+ qt_internal_extend_target("${target}"
+ ${arg_NO_UNITY_BUILD}
+ SOURCES
+ ${arg_SOURCES}
+ ${arg_EXTERNAL_HEADERS}
+ NO_UNITY_BUILD_SOURCES
+ ${arg_NO_UNITY_BUILD_SOURCES}
+ INCLUDE_DIRECTORIES
+ ${private_includes}
+ SYSTEM_INCLUDE_DIRECTORIES
+ ${arg_SYSTEM_INCLUDE_DIRECTORIES}
+ PUBLIC_INCLUDE_DIRECTORIES
+ ${public_includes}
+ PUBLIC_DEFINES
+ ${arg_PUBLIC_DEFINES}
+ DEFINES
+ ${arg_DEFINES}
+ ${defines_for_extend_target}
+ PUBLIC_LIBRARIES ${arg_PUBLIC_LIBRARIES}
+ LIBRARIES ${arg_LIBRARIES}
+ PRIVATE_MODULE_INTERFACE ${arg_PRIVATE_MODULE_INTERFACE}
+ FEATURE_DEPENDENCIES ${arg_FEATURE_DEPENDENCIES}
+ DBUS_ADAPTOR_SOURCES ${arg_DBUS_ADAPTOR_SOURCES}
+ DBUS_ADAPTOR_FLAGS ${arg_DBUS_ADAPTOR_FLAGS}
+ DBUS_INTERFACE_SOURCES ${arg_DBUS_INTERFACE_SOURCES}
+ DBUS_INTERFACE_FLAGS ${arg_DBUS_INTERFACE_FLAGS}
+ COMPILE_OPTIONS ${arg_COMPILE_OPTIONS}
+ PUBLIC_COMPILE_OPTIONS ${arg_PUBLIC_COMPILE_OPTIONS}
+ LINK_OPTIONS ${arg_LINK_OPTIONS}
+ PUBLIC_LINK_OPTIONS ${arg_PUBLIC_LINK_OPTIONS}
+ MOC_OPTIONS ${arg_MOC_OPTIONS}
+ ENABLE_AUTOGEN_TOOLS ${arg_ENABLE_AUTOGEN_TOOLS}
+ DISABLE_AUTOGEN_TOOLS ${arg_DISABLE_AUTOGEN_TOOLS}
+ PRECOMPILED_HEADER ${arg_PRECOMPILED_HEADER}
+ NO_PCH_SOURCES ${arg_NO_PCH_SOURCES}
+ )
+
+ # The public module define is not meant to be used when building the module itself,
+ # it's only meant to be used for consumers of the module,
+ # thus we can't use qt_internal_extend_target()'s PUBLIC_DEFINES option.
+ target_compile_definitions(${target} INTERFACE QT_${module_define_infix}_LIB)
+
+ if(NOT arg_EXCEPTIONS AND NOT ${arg_HEADER_MODULE})
+ qt_internal_set_exceptions_flags("${target}" FALSE)
+ elseif(arg_EXCEPTIONS)
+ qt_internal_set_exceptions_flags("${target}" TRUE)
+ endif()
+
+ set(configureFile "${CMAKE_CURRENT_SOURCE_DIR}/configure.cmake")
+ if(arg_CONFIGURE_FILE_PATH)
+ set(configureFile "${arg_CONFIGURE_FILE_PATH}")
+ endif()
+ if(EXISTS "${configureFile}" AND NOT arg_NO_CONFIG_HEADER_FILE)
+ qt_feature_module_begin(
+ LIBRARY "${target}"
+ PUBLIC_FILE "${module_config_header}"
+ PRIVATE_FILE "${module_config_private_header}"
+ PUBLIC_DEPENDENCIES ${arg_FEATURE_DEPENDENCIES}
+ PRIVATE_DEPENDENCIES ${arg_FEATURE_DEPENDENCIES}
+ )
+ include(${configureFile})
+ qt_feature_module_end("${target}")
+
+ qt_internal_extend_target("${target}"
+ SOURCES
+ "${CMAKE_CURRENT_BINARY_DIR}/${module_config_header}"
+ "${CMAKE_CURRENT_BINARY_DIR}/${module_config_private_header}"
+ )
+ endif()
+
+ # Handle creation of cmake files for consumers of find_package().
+ set(path_suffix "${INSTALL_CMAKE_NAMESPACE}${target}")
+ qt_path_join(config_build_dir ${QT_CONFIG_BUILD_DIR} ${path_suffix})
+ qt_path_join(config_install_dir ${QT_CONFIG_INSTALL_DIR} ${path_suffix})
+
+ set(extra_cmake_files)
+ set(extra_cmake_includes)
+ if (EXISTS "${CMAKE_CURRENT_LIST_DIR}/${INSTALL_CMAKE_NAMESPACE}${target}Macros.cmake")
+ list(APPEND extra_cmake_files "${CMAKE_CURRENT_LIST_DIR}/${INSTALL_CMAKE_NAMESPACE}${target}Macros.cmake")
+ list(APPEND extra_cmake_includes "${INSTALL_CMAKE_NAMESPACE}${target}Macros.cmake")
+ endif()
+
+ if (EXISTS "${CMAKE_CURRENT_LIST_DIR}/${INSTALL_CMAKE_NAMESPACE}${target}ConfigExtras.cmake.in")
+ if(target STREQUAL Core)
+ if(NOT "${QT_NAMESPACE}" STREQUAL "")
+ string(MAKE_C_IDENTIFIER "${QT_NAMESPACE}" qt_namespace_sanity)
+ if(NOT "${QT_NAMESPACE}" STREQUAL "${qt_namespace_sanity}")
+ message(FATAL_ERROR "QT_NAMESPACE is not a valid C++ identifier: "
+ "${QT_NAMESPACE}.")
+ endif()
+ string(JOIN "" qtcore_namespace_definition
+ "set_property(TARGET \${__qt_core_target} "
+ "APPEND PROPERTY INTERFACE_COMPILE_DEFINITIONS QT_NAMESPACE=${QT_NAMESPACE})"
+ )
+ endif()
+
+ set(extra_cmake_code "")
+ # Add some variables for compatibility with Qt5 config files.
+ if(QT_FEATURE_reduce_exports)
+ string(APPEND qtcore_extra_cmake_code "
+set(QT_VISIBILITY_AVAILABLE TRUE)")
+ endif()
+ if(QT_LIBINFIX)
+ string(APPEND qtcore_extra_cmake_code "
+set(QT_LIBINFIX \"${QT_LIBINFIX}\")")
+ endif()
+
+ # Store whether find_package(Qt6Foo) should succeed if Qt6FooTools is missing.
+ if(QT_ALLOW_MISSING_TOOLS_PACKAGES)
+ string(APPEND qtcore_extra_cmake_code "
+set(QT_ALLOW_MISSING_TOOLS_PACKAGES TRUE)")
+ endif()
+ endif()
+
+ configure_file("${CMAKE_CURRENT_LIST_DIR}/${INSTALL_CMAKE_NAMESPACE}${target}ConfigExtras.cmake.in"
+ "${config_build_dir}/${INSTALL_CMAKE_NAMESPACE}${target}ConfigExtras.cmake"
+ @ONLY)
+ list(APPEND extra_cmake_files "${config_build_dir}/${INSTALL_CMAKE_NAMESPACE}${target}ConfigExtras.cmake")
+ list(APPEND extra_cmake_includes "${INSTALL_CMAKE_NAMESPACE}${target}ConfigExtras.cmake")
+ endif()
+
+ foreach(cmake_file IN LISTS arg_EXTRA_CMAKE_FILES)
+ get_filename_component(basename ${cmake_file} NAME)
+ file(COPY ${cmake_file} DESTINATION ${config_build_dir})
+ list(APPEND extra_cmake_files "${config_build_dir}/${basename}")
+
+ # Make sure touched extra cmake files cause a reconfigure, so they get re-copied.
+ set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS "${cmake_file}")
+ endforeach()
+ list(APPEND extra_cmake_includes ${arg_EXTRA_CMAKE_INCLUDES})
+
+ set(extra_cmake_code "")
+
+ if(arg_POLICIES)
+ set(policies "")
+ foreach(policy IN LISTS arg_POLICIES)
+ list(APPEND policies "set(QT_KNOWN_POLICY_${policy} TRUE)")
+
+ # When building Qt, tests and examples might expect a policy to be known, but they
+ # won't be known depending on which scope or when a find_package(Module) with the
+ # respective policy is called. Check the global list of known policies to accommodate
+ # that.
+ set_property(GLOBAL APPEND PROPERTY _qt_global_known_policies "${policy}")
+ endforeach()
+ list(JOIN policies "\n" policies_str)
+ string(APPEND extra_cmake_code "${policies_str}\n")
+ endif()
+
+ # Generate metatypes
+ if (NOT ${arg_NO_GENERATE_METATYPES} AND NOT target_type STREQUAL "INTERFACE_LIBRARY")
+ set(args "")
+ if(QT_WILL_INSTALL)
+ set(metatypes_install_dir "${INSTALL_ARCHDATADIR}/metatypes")
+ list(APPEND args
+ __QT_INTERNAL_INSTALL __QT_INTERNAL_INSTALL_DIR "${metatypes_install_dir}")
+ endif()
+ qt6_extract_metatypes(${target} ${args})
+ endif()
+
+ qt_internal_get_min_new_policy_cmake_version(min_new_policy_version)
+ qt_internal_get_max_new_policy_cmake_version(max_new_policy_version)
+ configure_package_config_file(
+ "${QT_CMAKE_DIR}/QtModuleConfig.cmake.in"
+ "${config_build_dir}/${INSTALL_CMAKE_NAMESPACE}${target}Config.cmake"
+ INSTALL_DESTINATION "${config_install_dir}"
+ )
+
+ if (EXISTS "${CMAKE_CURRENT_LIST_DIR}/${INSTALL_CMAKE_NAMESPACE}${target}BuildInternals.cmake")
+ configure_file("${CMAKE_CURRENT_LIST_DIR}/${INSTALL_CMAKE_NAMESPACE}${target}BuildInternals.cmake"
+ "${config_build_dir}/${INSTALL_CMAKE_NAMESPACE}${target}BuildInternals.cmake"
+ @ONLY)
+ list(APPEND extra_cmake_files "${config_build_dir}/${INSTALL_CMAKE_NAMESPACE}${target}BuildInternals.cmake")
+ endif()
+
+ write_basic_package_version_file(
+ "${config_build_dir}/${INSTALL_CMAKE_NAMESPACE}${target}ConfigVersionImpl.cmake"
+ VERSION ${PROJECT_VERSION}
+ COMPATIBILITY AnyNewerVersion
+ )
+ qt_internal_write_qt_package_version_file(
+ "${INSTALL_CMAKE_NAMESPACE}${target}"
+ "${config_build_dir}/${INSTALL_CMAKE_NAMESPACE}${target}ConfigVersion.cmake"
+ )
+ qt_install(FILES
+ "${config_build_dir}/${INSTALL_CMAKE_NAMESPACE}${target}Config.cmake"
+ "${config_build_dir}/${INSTALL_CMAKE_NAMESPACE}${target}ConfigVersion.cmake"
+ "${config_build_dir}/${INSTALL_CMAKE_NAMESPACE}${target}ConfigVersionImpl.cmake"
+ ${extra_cmake_files}
+ DESTINATION "${config_install_dir}"
+ COMPONENT Devel
+ )
+
+ file(COPY ${extra_cmake_files} DESTINATION "${config_build_dir}")
+ set(exported_targets ${target})
+ if(NOT ${arg_NO_PRIVATE_MODULE})
+ list(APPEND exported_targets ${target_private})
+ endif()
+ set(export_name "${INSTALL_CMAKE_NAMESPACE}${target}Targets")
+
+ qt_install(TARGETS ${exported_targets}
+ EXPORT ${export_name}
+ RUNTIME DESTINATION ${INSTALL_BINDIR}
+ LIBRARY DESTINATION ${INSTALL_LIBDIR}
+ ARCHIVE DESTINATION ${INSTALL_LIBDIR}
+ FRAMEWORK DESTINATION ${INSTALL_LIBDIR}
+ )
+
+ if(BUILD_SHARED_LIBS)
+ qt_apply_rpaths(TARGET "${target}" INSTALL_PATH "${INSTALL_LIBDIR}" RELATIVE_RPATH)
+ qt_internal_apply_staging_prefix_build_rpath_workaround()
+ endif()
+
+ if (ANDROID AND NOT arg_HEADER_MODULE)
+ # Record install library location so it can be accessed by
+ # qt_internal_android_dependencies without having to specify it again.
+ set_target_properties(${target} PROPERTIES
+ QT_ANDROID_MODULE_INSTALL_DIR ${INSTALL_LIBDIR})
+ endif()
+
+ qt_install(EXPORT ${export_name}
+ NAMESPACE ${QT_CMAKE_EXPORT_NAMESPACE}::
+ DESTINATION ${config_install_dir})
+
+ if(NOT arg_NO_ADDITIONAL_TARGET_INFO)
+ qt_internal_export_additional_targets_file(
+ TARGETS ${exported_targets}
+ EXPORT_NAME_PREFIX ${INSTALL_CMAKE_NAMESPACE}${target}
+ CONFIG_INSTALL_DIR "${config_install_dir}")
+ endif()
+
+ qt_internal_export_modern_cmake_config_targets_file(
+ TARGETS ${exported_targets}
+ EXPORT_NAME_PREFIX ${INSTALL_CMAKE_NAMESPACE}${target}
+ CONFIG_BUILD_DIR "${config_build_dir}"
+ CONFIG_INSTALL_DIR "${config_install_dir}"
+ )
+
+ qt_internal_export_genex_properties(TARGETS ${target}
+ EXPORT_NAME_PREFIX ${INSTALL_CMAKE_NAMESPACE}${target}
+ CONFIG_INSTALL_DIR "${config_install_dir}"
+ )
+
+ ### fixme: cmake is missing a built-in variable for this. We want to apply it only to modules and plugins
+ # that belong to Qt.
+ if(NOT arg_HEADER_MODULE)
+ qt_internal_add_link_flags_no_undefined("${target}")
+ endif()
+
+ set(interface_includes "")
+
+ # Handle cases like QmlDevToolsPrivate which do not have their own headers, but rather borrow them
+ # from another module.
+ if(NOT arg_NO_SYNC_QT AND NOT arg_NO_MODULE_HEADERS)
+ list(APPEND interface_includes "$<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}>")
+
+ # syncqt does not create a private header directory like 'include/6.0/QtFoo' unless
+ # the module has foo_p.h header files. For QtZlib, there are no such private headers, so we
+ # need to make sure not to add such include paths unless the directory exists, otherwise
+ # consumers of the module will fail at CMake generation time stating that
+ # INTERFACE_INCLUDE_DIRECTORIES contains a non-existent path.
+ qt_internal_append_include_directories_with_headers_check(${target}
+ interface_includes PRIVATE
+ "$<BUILD_INTERFACE:${module_build_interface_versioned_include_dir}>"
+ "$<BUILD_INTERFACE:${module_build_interface_versioned_inner_include_dir}>"
+ )
+
+ if(is_framework)
+ set(fw_install_private_header_dir "${INSTALL_LIBDIR}/${fw_private_header_dir}")
+ set(fw_install_private_module_header_dir
+ "${INSTALL_LIBDIR}/${fw_private_module_header_dir}")
+ qt_internal_append_include_directories_with_headers_check(${target}
+ interface_includes PRIVATE
+ "$<INSTALL_INTERFACE:${fw_install_private_header_dir}>"
+ "$<INSTALL_INTERFACE:${fw_install_private_module_header_dir}>"
+ )
+ else()
+ qt_internal_append_include_directories_with_headers_check(${target}
+ interface_includes PRIVATE
+ "$<INSTALL_INTERFACE:${module_install_interface_versioned_include_dir}>"
+ "$<INSTALL_INTERFACE:${module_install_interface_versioned_inner_include_dir}>"
+ )
+ endif()
+ endif()
+
+ if(arg_INTERNAL_MODULE)
+ target_include_directories("${target}" INTERFACE ${interface_includes})
+ elseif(NOT ${arg_NO_PRIVATE_MODULE})
+ target_include_directories("${target_private}" INTERFACE ${interface_includes})
+ target_link_libraries("${target_private}" INTERFACE "${target}")
+ endif()
+
+ set(debug_install_dir "${INSTALL_LIBDIR}")
+ if (MINGW)
+ set(debug_install_dir "${INSTALL_BINDIR}")
+ endif()
+ qt_enable_separate_debug_info(${target} "${debug_install_dir}")
+ set(pdb_install_dir "${INSTALL_BINDIR}")
+ if(NOT is_shared_lib)
+ set(pdb_install_dir "${INSTALL_LIBDIR}")
+ endif()
+ qt_internal_install_pdb_files(${target} "${pdb_install_dir}")
+
+ if (arg_NO_PRIVATE_MODULE)
+ set(arg_NO_PRIVATE_MODULE "NO_PRIVATE_MODULE")
+ else()
+ unset(arg_NO_PRIVATE_MODULE)
+ endif()
+
+ qt_describe_module(${target})
+ qt_add_list_file_finalizer(qt_finalize_module ${target} ${arg_INTERNAL_MODULE} ${arg_NO_PRIVATE_MODULE})
+endfunction()
+
+function(qt_internal_apply_apple_privacy_manifest target)
+ if(APPLE)
+ # Privacy manifest
+ get_target_property(is_framework ${target} FRAMEWORK)
+ if(is_framework)
+ get_target_property(privacy_manifest ${target} _qt_privacy_manifest)
+ if(NOT privacy_manifest)
+ set(privacy_manifest
+ "${__qt_internal_cmake_apple_support_files_path}/PrivacyInfo.xcprivacy")
+ endif()
+ target_sources("${target}" PRIVATE "${privacy_manifest}")
+ set_property(TARGET "${target}" APPEND PROPERTY RESOURCE "${privacy_manifest}")
+ endif()
+ endif()
+endfunction()
+
+function(qt_finalize_module target)
+ qt_internal_collect_module_headers(module_headers ${target})
+
+ # qt_internal_install_module_headers needs to be called before
+ # qt_finalize_framework_headers_copy, because the last uses the QT_COPIED_FRAMEWORK_HEADERS
+ # property which supposed to be updated inside every qt_internal_install_module_headers
+ # call.
+ qt_internal_add_headersclean_target(${target} "${module_headers_public}")
+ qt_internal_target_sync_headers(${target} "${module_headers_all}"
+ "${module_headers_generated}")
+ get_target_property(module_depends_header ${target} _qt_module_depends_header)
+ qt_internal_install_module_headers(${target}
+ PUBLIC ${module_headers_public} "${module_depends_header}"
+ PRIVATE ${module_headers_private}
+ QPA ${module_headers_qpa}
+ RHI ${module_headers_rhi}
+ SSG ${module_headers_ssg}
+ )
+
+ qt_finalize_framework_headers_copy(${target})
+ qt_generate_prl_file(${target} "${INSTALL_LIBDIR}")
+ qt_generate_module_pri_file("${target}" ${ARGN})
+ qt_internal_generate_pkg_config_file(${target})
+ qt_internal_apply_apple_privacy_manifest(${target})
+endfunction()
+
+# Get a set of Qt module related values based on the target.
+#
+# The function uses the _qt_module_interface_name and _qt_module_include_name target properties to
+# preform values for the output variables. _qt_module_interface_name it's the basic name of module
+# without "Qtfication" and the "Private" suffix if we speak about INTERNAL_MODULEs. Typical value of
+# the _qt_module_interface_name is the provided to qt_internal_add_module ${target} name, e.g. Core.
+# _qt_module_interface_name is used to preform all the include paths unless the
+# _qt_module_include_name property is specified. _qt_module_include_name is legacy property that
+# replaces the module name in include paths and has a higher priority than the
+# _qt_module_interface_name property.
+#
+# When doing qt_internal_module_info(foo Core) this method will set the following variables in
+# the caller's scope:
+# * foo with the value "QtCore"
+# * foo_versioned with the value "Qt6Core" (based on major Qt version)
+# * foo_upper with the value "CORE"
+# * foo_lower with the value "core"
+# * foo_include_name with the value"QtCore"
+# Usually the module name from ${foo} is used, but the name might be different if the
+# MODULE_INCLUDE_NAME argument is set when creating the module.
+# * foo_versioned_include_dir with the value "QtCore/6.2.0"
+# * foo_versioned_inner_include_dir with the value "QtCore/6.2.0/QtCore"
+# * foo_private_include_dir with the value "QtCore/6.2.0/QtCore/private"
+# * foo_qpa_include_dir with the value "QtCore/6.2.0/QtCore/qpa"
+# * foo_rhi_include_dir with the value "QtCore/6.2.0/QtCore/rhi"
+# * foo_ssg_include_dir with the value "QtQuick3D/6.2.0/QtQuick3D/ssg"
+# * foo_interface_name the interface name of the module stored in _qt_module_interface_name
+# property, e.g. Core.
+#
+# The function also sets a bunch of module include paths for the build and install interface.
+# Variables that contains these paths start with foo_build_interface_ and foo_install_interface_
+# accordingly.
+# The following variables are set in the caller's scope:
+# * foo_<build|install>_interface_include_dir with
+# qtbase_build_dir/include/QtCore for build interface and
+# include/QtCore for install interface.
+# * foo_<build|install>_interface_versioned_include_dir with
+# qtbase_build_dir/include/QtCore/6.2.0 for build interface and
+# include/QtCore/6.2.0 for install interface.
+# * foo_<build|install>_versioned_inner_include_dir with
+# qtbase_build_dir/include/QtCore/6.2.0/QtCore for build interface and
+# include/QtCore/6.2.0/QtCore for install interface.
+# * foo_<build|install>_private_include_dir with
+# qtbase_build_dir/include/QtCore/6.2.0/QtCore/private for build interface and
+# include/QtCore/6.2.0/QtCore/private for install interface.
+# * foo_<build|install>_qpa_include_dir with
+# qtbase_build_dir/include/QtCore/6.2.0/QtCore/qpa for build interface and
+# include/QtCore/6.2.0/QtCore/qpa for install interface.
+# * foo_<build|install>_rhi_include_dir with
+# qtbase_build_dir/include/QtCore/6.2.0/QtCore/rhi for build interface and
+# include/QtCore/6.2.0/QtCore/rhi for install interface.
+# * foo_<build|install>_ssg_include_dir with
+# qtbase_build_dir/include/<module>/x.y.z/<module>/ssg for build interface and
+# include/<module>/x.y.z/<module>/ssg for install interface.
+# The following values are set by the function and might be useful in caller's scope:
+# * repo_install_interface_include_dir contains path to the top-level repository include directory,
+# e.g. qtbase_build_dir/include
+# * repo_install_interface_include_dir contains path to the non-prefixed top-level include
+# directory is used for the installation, e.g. include
+# Note: that for non-prefixed Qt configurations the build interface paths will start with
+# <build_directory>/qtbase/include, e.g foo_build_interface_include_dir of the Qml module looks
+# like qt_toplevel_build_dir/qtbase/include/QtQml
+function(qt_internal_module_info result target)
+ if(result STREQUAL "repo")
+ message(FATAL_ERROR "'repo' keyword is reserved for internal use, please specify \
+the different base name for the module info variables.")
+ endif()
+
+ get_target_property(module_interface_name ${target} _qt_module_interface_name)
+ if(NOT module_interface_name)
+ message(FATAL_ERROR "${target} is not a module.")
+ endif()
+
+ qt_internal_qtfy_target(module ${module_interface_name})
+
+ get_target_property("${result}_include_name" ${target} _qt_module_include_name)
+ if(NOT ${result}_include_name)
+ set("${result}_include_name" "${module}")
+ endif()
+
+ set("${result}_versioned_include_dir"
+ "${${result}_include_name}/${PROJECT_VERSION}")
+ set("${result}_versioned_inner_include_dir"
+ "${${result}_versioned_include_dir}/${${result}_include_name}")
+ set("${result}_private_include_dir"
+ "${${result}_versioned_inner_include_dir}/private")
+ set("${result}_qpa_include_dir"
+ "${${result}_versioned_inner_include_dir}/qpa")
+ set("${result}_rhi_include_dir"
+ "${${result}_versioned_inner_include_dir}/rhi")
+ set("${result}_ssg_include_dir"
+ "${${result}_versioned_inner_include_dir}/ssg")
+
+ # Module build interface directories
+ set(repo_build_interface_include_dir "${QT_BUILD_DIR}/include")
+ set("${result}_build_interface_include_dir"
+ "${repo_build_interface_include_dir}/${${result}_include_name}")
+ set("${result}_build_interface_versioned_include_dir"
+ "${repo_build_interface_include_dir}/${${result}_versioned_include_dir}")
+ set("${result}_build_interface_versioned_inner_include_dir"
+ "${repo_build_interface_include_dir}/${${result}_versioned_inner_include_dir}")
+ set("${result}_build_interface_private_include_dir"
+ "${repo_build_interface_include_dir}/${${result}_private_include_dir}")
+ set("${result}_build_interface_qpa_include_dir"
+ "${repo_build_interface_include_dir}/${${result}_qpa_include_dir}")
+ set("${result}_build_interface_rhi_include_dir"
+ "${repo_build_interface_include_dir}/${${result}_rhi_include_dir}")
+ set("${result}_build_interface_ssg_include_dir"
+ "${repo_build_interface_include_dir}/${${result}_ssg_include_dir}")
+
+ # Module install interface directories
+ set(repo_install_interface_include_dir "${INSTALL_INCLUDEDIR}")
+ set("${result}_install_interface_include_dir"
+ "${repo_install_interface_include_dir}/${${result}_include_name}")
+ set("${result}_install_interface_versioned_include_dir"
+ "${repo_install_interface_include_dir}/${${result}_versioned_include_dir}")
+ set("${result}_install_interface_versioned_inner_include_dir"
+ "${repo_install_interface_include_dir}/${${result}_versioned_inner_include_dir}")
+ set("${result}_install_interface_private_include_dir"
+ "${repo_install_interface_include_dir}/${${result}_private_include_dir}")
+ set("${result}_install_interface_qpa_include_dir"
+ "${repo_install_interface_include_dir}/${${result}_qpa_include_dir}")
+ set("${result}_install_interface_rhi_include_dir"
+ "${repo_install_interface_include_dir}/${${result}_rhi_include_dir}")
+ set("${result}_install_interface_ssg_include_dir"
+ "${repo_install_interface_include_dir}/${${result}_ssg_include_dir}")
+
+ set("${result}" "${module}" PARENT_SCOPE)
+ set("${result}_versioned" "${module_versioned}" PARENT_SCOPE)
+ string(TOUPPER "${module_interface_name}" upper)
+ string(TOLOWER "${module_interface_name}" lower)
+ set("${result}_upper" "${upper}" PARENT_SCOPE)
+ set("${result}_lower" "${lower}" PARENT_SCOPE)
+ set("${result}_include_name" "${${result}_include_name}" PARENT_SCOPE)
+ set("${result}_versioned_include_dir" "${${result}_versioned_include_dir}" PARENT_SCOPE)
+ set("${result}_versioned_inner_include_dir"
+ "${${result}_versioned_inner_include_dir}" PARENT_SCOPE)
+ set("${result}_private_include_dir" "${${result}_private_include_dir}" PARENT_SCOPE)
+ set("${result}_qpa_include_dir" "${${result}_qpa_include_dir}" PARENT_SCOPE)
+ set("${result}_rhi_include_dir" "${${result}_rhi_include_dir}" PARENT_SCOPE)
+ set("${result}_ssg_include_dir" "${${result}_ssg_include_dir}" PARENT_SCOPE)
+ set("${result}_interface_name" "${module_interface_name}" PARENT_SCOPE)
+
+ # Setting module build interface directories in parent scope
+ set(repo_build_interface_include_dir "${repo_build_interface_include_dir}" PARENT_SCOPE)
+ set("${result}_build_interface_include_dir"
+ "${${result}_build_interface_include_dir}" PARENT_SCOPE)
+ set("${result}_build_interface_versioned_include_dir"
+ "${${result}_build_interface_versioned_include_dir}" PARENT_SCOPE)
+ set("${result}_build_interface_versioned_inner_include_dir"
+ "${${result}_build_interface_versioned_inner_include_dir}" PARENT_SCOPE)
+ set("${result}_build_interface_private_include_dir"
+ "${${result}_build_interface_private_include_dir}" PARENT_SCOPE)
+ set("${result}_build_interface_qpa_include_dir"
+ "${${result}_build_interface_qpa_include_dir}" PARENT_SCOPE)
+ set("${result}_build_interface_rhi_include_dir"
+ "${${result}_build_interface_rhi_include_dir}" PARENT_SCOPE)
+ set("${result}_build_interface_ssg_include_dir"
+ "${${result}_build_interface_ssg_include_dir}" PARENT_SCOPE)
+
+ # Setting module install interface directories in parent scope
+ set(repo_install_interface_include_dir "${repo_install_interface_include_dir}" PARENT_SCOPE)
+ set("${result}_install_interface_include_dir"
+ "${${result}_install_interface_include_dir}" PARENT_SCOPE)
+ set("${result}_install_interface_versioned_include_dir"
+ "${${result}_install_interface_versioned_include_dir}" PARENT_SCOPE)
+ set("${result}_install_interface_versioned_inner_include_dir"
+ "${${result}_install_interface_versioned_inner_include_dir}" PARENT_SCOPE)
+ set("${result}_install_interface_private_include_dir"
+ "${${result}_install_interface_private_include_dir}" PARENT_SCOPE)
+ set("${result}_install_interface_qpa_include_dir"
+ "${${result}_install_interface_qpa_include_dir}" PARENT_SCOPE)
+ set("${result}_install_interface_rhi_include_dir"
+ "${${result}_install_interface_rhi_include_dir}" PARENT_SCOPE)
+ set("${result}_install_interface_ssg_include_dir"
+ "${${result}_install_interface_ssg_include_dir}" PARENT_SCOPE)
+endfunction()
+
+function(qt_internal_list_to_json_array out_var list_var)
+ set(result "")
+ foreach(item IN LISTS ${list_var})
+ if(NOT "${result}" STREQUAL "")
+ string(APPEND result ", ")
+ endif()
+ string(APPEND result "\"${item}\"")
+ endforeach()
+ set("${out_var}" "[${result}]" PARENT_SCOPE)
+endfunction()
+
+# Generate a module description file based on the template in ModuleDescription.json.in
+function(qt_describe_module target)
+ set(path_suffix "${INSTALL_DESCRIPTIONSDIR}")
+ qt_path_join(build_dir ${QT_BUILD_DIR} ${path_suffix})
+ qt_path_join(install_dir ${QT_INSTALL_DIR} ${path_suffix})
+
+ set(descfile_in "${QT_CMAKE_DIR}/ModuleDescription.json.in")
+ set(descfile_out "${build_dir}/${target}.json")
+ string(TOLOWER "${PROJECT_NAME}" lower_case_project_name)
+ set(cross_compilation "false")
+ if(CMAKE_CROSSCOMPILING)
+ set(cross_compilation "true")
+ endif()
+ set(extra_module_information "")
+
+ get_target_property(target_type ${target} TYPE)
+ if(NOT target_type STREQUAL "INTERFACE_LIBRARY")
+ get_target_property(plugin_types ${target} QMAKE_MODULE_PLUGIN_TYPES)
+ if(plugin_types)
+ qt_internal_list_to_json_array(plugin_types plugin_types)
+ string(APPEND extra_module_information "\n \"plugin_types\": ${plugin_types},")
+ endif()
+ endif()
+
+ get_target_property(is_internal ${target} _qt_is_internal_module)
+ if(is_internal)
+ string(APPEND extra_module_information "\n \"internal\": true,")
+ endif()
+
+ set(extra_build_information "")
+ if(NOT QT_NAMESPACE STREQUAL "")
+ string(APPEND extra_build_information "
+ \"namespace\": \"${QT_NAMESPACE}\",")
+ endif()
+ if(ANDROID)
+ string(APPEND extra_build_information "
+ \"android\": {
+ \"api_version\": \"${QT_ANDROID_API_VERSION}\",
+ \"ndk\": {
+ \"version\": \"${ANDROID_NDK_REVISION}\"
+ }
+ },")
+ endif()
+ configure_file("${descfile_in}" "${descfile_out}")
+
+ qt_install(FILES "${descfile_out}" DESTINATION "${install_dir}")
+endfunction()
+
+function(qt_internal_generate_cpp_global_exports target module_define_infix)
+ cmake_parse_arguments(arg
+ ""
+ "CPP_EXPORT_HEADER_BASE_NAME"
+ "" ${ARGN}
+ )
+
+ qt_internal_module_info(module "${target}")
+
+ set(header_base_name "qt${module_lower}exports")
+ if(arg_CPP_EXPORT_HEADER_BASE_NAME)
+ set(header_base_name "${arg_CPP_EXPORT_HEADER_BASE_NAME}")
+ endif()
+ # Is used as a part of the header guard define.
+ string(TOUPPER "${header_base_name}" header_base_name_upper)
+
+ set(generated_header_path
+ "${module_build_interface_include_dir}/${header_base_name}.h"
+ )
+
+ configure_file("${QT_CMAKE_DIR}/modulecppexports.h.in"
+ "${generated_header_path}" @ONLY
+ )
+
+ set(${out_public_header} "${generated_header_path}" PARENT_SCOPE)
+ target_sources(${target} PRIVATE "${generated_header_path}")
+ set_source_files_properties("${generated_header_path}" PROPERTIES GENERATED TRUE)
+endfunction()
+
+function(qt_internal_install_module_headers target)
+ set(options)
+ set(one_value_args)
+ set(multi_value_args PUBLIC PRIVATE QPA RHI SSG)
+ cmake_parse_arguments(arg "${options}" "${one_value_args}" "${multi_value_args}" ${ARGN})
+
+ qt_internal_module_info(module ${target})
+
+ get_target_property(target_type ${target} TYPE)
+ set(is_interface_lib FALSE)
+ if(target_type STREQUAL "INTERFACE_LIBRARY")
+ set(is_interface_lib TRUE)
+ else()
+ get_target_property(is_framework ${target} FRAMEWORK)
+ endif()
+
+
+ foreach(header_type IN LISTS multi_value_args)
+ if(NOT arg_${header_type})
+ set(arg_${header_type} "")
+ endif()
+ endforeach()
+
+ if(is_framework)
+ qt_copy_framework_headers(${target}
+ PUBLIC ${arg_PUBLIC}
+ PRIVATE ${arg_PRIVATE}
+ QPA ${arg_QPA}
+ RHI ${arg_RHI}
+ SSG ${arg_SSG}
+ )
+ else()
+ if(arg_PUBLIC)
+ qt_install(FILES ${arg_PUBLIC}
+ DESTINATION "${module_install_interface_include_dir}")
+ endif()
+ if(arg_PRIVATE)
+ qt_install(FILES ${arg_PRIVATE}
+ DESTINATION "${module_install_interface_private_include_dir}")
+ endif()
+ if(arg_QPA)
+ qt_install(FILES ${arg_QPA} DESTINATION "${module_install_interface_qpa_include_dir}")
+ endif()
+ if(arg_RHI)
+ qt_install(FILES ${arg_RHI} DESTINATION "${module_install_interface_rhi_include_dir}")
+ endif()
+ if(arg_SSG)
+ qt_install(FILES ${arg_SSG} DESTINATION "${module_install_interface_ssg_include_dir}")
+ endif()
+ endif()
+endfunction()
+
+function(qt_internal_collect_module_headers out_var target)
+ set(${out_var}_public "")
+ set(${out_var}_private "")
+ set(${out_var}_qpa "")
+ set(${out_var}_rhi "")
+ set(${out_var}_ssg "")
+ set(${out_var}_all "")
+
+ qt_internal_get_target_sources(sources ${target})
+
+ get_target_property(target_type ${target} TYPE)
+ if(target_type STREQUAL "INTERFACE_LIBRARY")
+ set(source_dir "${CMAKE_CURRENT_SOURCE_DIR}")
+ set(binary_dir "${CMAKE_CURRENT_BINARY_DIR}")
+ else()
+ get_target_property(source_dir ${target} SOURCE_DIR)
+ get_target_property(binary_dir ${target} BINARY_DIR)
+ endif()
+ get_filename_component(source_dir "${source_dir}" ABSOLUTE)
+ get_filename_component(binary_dir "${binary_dir}" ABSOLUTE)
+
+ get_target_property(is_3rdparty_library ${target} _qt_module_is_3rdparty_header_library)
+
+ get_target_property(public_filter ${target} _qt_module_public_headers_filter_regex)
+ get_target_property(private_filter ${target} _qt_module_private_headers_filter_regex)
+ get_target_property(qpa_filter ${target} _qt_module_qpa_headers_filter_regex)
+ get_target_property(rhi_filter ${target} _qt_module_rhi_headers_filter_regex)
+ get_target_property(ssg_filter ${target} _qt_module_ssg_headers_filter_regex)
+
+ set(condition_independent_headers_warning "")
+ foreach(file_path IN LISTS sources)
+ get_filename_component(file_name "${file_path}" NAME)
+ if(NOT file_name MATCHES ".+\\.h$")
+ continue()
+ endif()
+
+ get_source_file_property(non_module_header ${file_path} _qt_non_module_header)
+ if(non_module_header)
+ continue()
+ endif()
+
+ get_filename_component(file_path "${file_path}" ABSOLUTE)
+
+ string(FIND "${file_path}" "${source_dir}" source_dir_pos)
+ if(source_dir_pos EQUAL 0)
+ set(is_outside_module_source_dir FALSE)
+ else()
+ set(is_outside_module_source_dir TRUE)
+ endif()
+
+ get_source_file_property(is_generated "${file_path}" GENERATED)
+ # Skip all header files outside the module source directory, except the generated files.
+ if(is_outside_module_source_dir AND NOT is_generated)
+ continue()
+ endif()
+
+ get_source_file_property(condition ${file_path} _qt_extend_target_condition)
+ if(NOT condition STREQUAL "" AND NOT condition STREQUAL "NOTFOUND")
+ list(JOIN condition " " condition_string)
+ string(APPEND condition_independent_headers_warning
+ "\nFile:\n ${file_path}"
+ "\nCondition:\n ${condition_string}")
+ endif()
+
+ if(is_outside_module_source_dir)
+ set(base_dir "${binary_dir}")
+ else()
+ set(base_dir "${source_dir}")
+ endif()
+
+ file(RELATIVE_PATH file_path_rel "${base_dir}" "${file_path}")
+ if(file_path_rel MATCHES "3rdparty/.+" AND NOT is_3rdparty_library)
+ set(is_3rdparty_header TRUE)
+ else()
+ set(is_3rdparty_header FALSE)
+ endif()
+ list(APPEND ${out_var}_all "${file_path}")
+ if(qpa_filter AND file_name MATCHES "${qpa_filter}")
+ list(APPEND ${out_var}_qpa "${file_path}")
+ elseif(rhi_filter AND file_name MATCHES "${rhi_filter}")
+ list(APPEND ${out_var}_rhi "${file_path}")
+ elseif(ssg_filter AND file_name MATCHES "${ssg_filter}")
+ list(APPEND ${out_var}_ssg "${file_path}")
+ elseif(private_filter AND file_name MATCHES "${private_filter}")
+ list(APPEND ${out_var}_private "${file_path}")
+ elseif((NOT public_filter OR file_name MATCHES "${public_filter}")
+ AND NOT is_3rdparty_header)
+ list(APPEND ${out_var}_public "${file_path}")
+ endif()
+ if(is_generated)
+ list(APPEND ${out_var}_generated "${file_path}")
+ endif()
+ endforeach()
+
+ if(NOT condition_independent_headers_warning STREQUAL "" AND QT_FEATURE_developer_build)
+ message(AUTHOR_WARNING "Condition is ignored when adding the following header file(s) to"
+ " the ${target} module:"
+ "${condition_independent_headers_warning}"
+ "\nThe usage of the file(s) is not properly isolated in this or other modules according"
+ " to the condition. This warning is for the Qt maintainers. Please make sure that file"
+ " include(s) are guarded with the appropriate macros in the Qt code. If files should be"
+ " added to the module unconditionally, please move them to the common SOURCES section"
+ " in the qt_internal_add_module call.")
+ endif()
+
+
+ set(header_types public private qpa rhi ssg)
+ set(has_header_types_properties "")
+ foreach(header_type IN LISTS header_types)
+ get_target_property(current_propety_value ${target} _qt_module_has_${header_type}_headers)
+ if(${out_var}_${header_type})
+ list(APPEND has_header_types_properties
+ _qt_module_has_${header_type}_headers TRUE)
+ endif()
+
+ set(${out_var}_${header_type} "${${out_var}_${header_type}}" PARENT_SCOPE)
+ endforeach()
+ set(${out_var}_all "${${out_var}_all}" PARENT_SCOPE)
+ set(${out_var}_generated "${${out_var}_generated}" PARENT_SCOPE)
+
+ if(has_header_types_properties)
+ set_target_properties(${target} PROPERTIES ${has_header_types_properties})
+ endif()
+ set_property(TARGET ${target} APPEND PROPERTY
+ EXPORT_PROPERTIES
+ _qt_module_has_public_headers
+ _qt_module_has_private_headers
+ _qt_module_has_qpa_headers
+ _qt_module_has_rhi_headers
+ _qt_module_has_ssg_headers
+ )
+endfunction()
diff --git a/cmake/QtModuleToolsConfig.cmake.in b/cmake/QtModuleToolsConfig.cmake.in
index 79ca620c13..ec447aa55b 100644
--- a/cmake/QtModuleToolsConfig.cmake.in
+++ b/cmake/QtModuleToolsConfig.cmake.in
@@ -1,17 +1,33 @@
+# Copyright (C) 2024 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
@PACKAGE_INIT@
+cmake_minimum_required(VERSION @min_new_policy_version@...@max_new_policy_version@)
+
include(CMakeFindDependencyMacro)
-if (NOT QT_NO_CREATE_TARGETS)
- # Find required dependencies, if any.
- if(EXISTS "${CMAKE_CURRENT_LIST_DIR}/@INSTALL_CMAKE_NAMESPACE@@target@Dependencies.cmake")
- include("${CMAKE_CURRENT_LIST_DIR}/@INSTALL_CMAKE_NAMESPACE@@target@Dependencies.cmake")
- endif()
+# Find required dependencies, if any.
+if(EXISTS "${CMAKE_CURRENT_LIST_DIR}/@INSTALL_CMAKE_NAMESPACE@@target@Dependencies.cmake")
+ include("${CMAKE_CURRENT_LIST_DIR}/@INSTALL_CMAKE_NAMESPACE@@target@Dependencies.cmake")
+endif()
+# If *Dependencies.cmake exists, the variable value will be defined there.
+# Don't override it in that case.
+if(NOT DEFINED "@INSTALL_CMAKE_NAMESPACE@@target@_FOUND")
+ set("@INSTALL_CMAKE_NAMESPACE@@target@_FOUND" TRUE)
+endif()
+
+if (NOT QT_NO_CREATE_TARGETS AND @INSTALL_CMAKE_NAMESPACE@@target@_FOUND)
include("${CMAKE_CURRENT_LIST_DIR}/@INSTALL_CMAKE_NAMESPACE@@target@Targets.cmake")
+ include("${CMAKE_CURRENT_LIST_DIR}/@INSTALL_CMAKE_NAMESPACE@@target@AdditionalTargetInfo.cmake")
if(NOT QT_NO_CREATE_VERSIONLESS_TARGETS)
include("${CMAKE_CURRENT_LIST_DIR}/@INSTALL_CMAKE_NAMESPACE@@target@VersionlessTargets.cmake")
endif()
endif()
+foreach(extra_cmake_include @extra_cmake_includes@)
+ include("${CMAKE_CURRENT_LIST_DIR}/${extra_cmake_include}")
+endforeach()
+
@extra_cmake_statements@
diff --git a/cmake/QtModuleToolsDependencies.cmake.in b/cmake/QtModuleToolsDependencies.cmake.in
index 46c60b8484..b2504a0943 100644
--- a/cmake/QtModuleToolsDependencies.cmake.in
+++ b/cmake/QtModuleToolsDependencies.cmake.in
@@ -1,16 +1,16 @@
-# Find "ModuleTools" dependencies, which are other ModuleTools packages.
-set(_tool_deps "@package_deps@")
-foreach(_target_dep ${_tool_deps})
- list(GET _target_dep 0 pkg)
- list(GET _target_dep 1 version)
+# Copyright (C) 2024 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
- if (NOT ${pkg}_FOUND)
- find_dependency(${pkg} ${version})
- endif()
+# Find "ModuleTools" dependencies, which are other ModuleTools packages.
+set(@INSTALL_CMAKE_NAMESPACE@@target@_FOUND FALSE)
+set(__qt_@target@_tool_deps "@package_deps@")
+foreach(__qt_@target@_target_dep ${__qt_@target@_tool_deps})
+ list(GET __qt_@target@_target_dep 0 __qt_@target@_pkg)
+ list(GET __qt_@target@_target_dep 1 __qt_@target@_version)
- if (NOT ${pkg}_FOUND)
- set(@INSTALL_CMAKE_NAMESPACE@@target@_FOUND FALSE)
- return()
+ if (NOT ${__qt_@target@_pkg}_FOUND)
+ find_dependency(${__qt_@target@_pkg} ${__qt_@target@_version})
endif()
endforeach()
+set(@INSTALL_CMAKE_NAMESPACE@@target@_FOUND TRUE)
diff --git a/cmake/QtModuleToolsVersionlessTargets.cmake.in b/cmake/QtModuleToolsVersionlessTargets.cmake.in
index 6d0f57e039..bc861a77b6 100644
--- a/cmake/QtModuleToolsVersionlessTargets.cmake.in
+++ b/cmake/QtModuleToolsVersionlessTargets.cmake.in
@@ -1,6 +1,9 @@
+# Copyright (C) 2024 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
foreach(__qt_tool @tool_targets_non_prefixed@)
if(NOT TARGET Qt::${__qt_tool} AND TARGET Qt6::${__qt_tool})
- add_executable(Qt::${__qt_tool} IMPORTED)
+ add_executable(Qt::${__qt_tool} IMPORTED GLOBAL)
# Check all the usual imported location properties to find one that contains a path.
foreach(__qt_imported_location_config
diff --git a/cmake/QtNoLinkTargetHelpers.cmake b/cmake/QtNoLinkTargetHelpers.cmake
new file mode 100644
index 0000000000..59dc3ff5ac
--- /dev/null
+++ b/cmake/QtNoLinkTargetHelpers.cmake
@@ -0,0 +1,58 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+function(qt_create_nolink_target target dependee_target)
+ if(NOT TARGET "${target}")
+ message(FATAL_ERROR "${target} does not exist when trying to build a nolink target.")
+ endif()
+ get_target_property(type "${target}" TYPE)
+ if(type STREQUAL EXECUTABLE)
+ message(FATAL_ERROR "${target} must be a library of some kind.")
+ endif()
+ if(type STREQUAL OBJECT_LIBRARY)
+ message(FATAL_ERROR "${target} must not be an object library.")
+ endif()
+
+ # Strip off the namespace prefix, so from Vulkan::Vulkan to Vulkan, and then append _nolink.
+ string(REGEX REPLACE "^.*::" "" non_prefixed_target ${target})
+ set(nolink_target "${non_prefixed_target}_nolink")
+
+ # Create the nolink interface target, assign the properties from the original target,
+ # associate the nolink target with the same export which contains
+ # the target that uses the _nolink target.
+ # Also create a namespaced alias of the form ${target}::${target}_nolink which is used by
+ # our modules.
+ # Also create a Qt namespaced alias target, because when exporting via install(EXPORT)
+ # Vulkan::Vulkan_nolink transforms into Qt6::Vulkan_nolink, and the latter needs to be an
+ # accessible alias for standalone tests.
+ if(NOT TARGET "${nolink_target}")
+ add_library("${nolink_target}" INTERFACE)
+ set(prefixed_nolink_target "${target}_nolink")
+
+ # When configuring an example with qmake, if QtGui is built with Vulkan support but the
+ # user's machine where Qt is installed doesn't have Vulkan, qmake doesn't fail saying
+ # that vulkan is not installed. Instead it silently configures and just doesn't add
+ # the include headers.
+ # To mimic that in CMake, if the Vulkan CMake package is not found, we shouldn't fail
+ # at generation time saying that the Vulkan target does not exist. Instead check with a
+ # genex that the target exists to query the properties, otherwise just silently continue.
+ # FIXME: If we figure out that such behavior should only be applied to Vulkan, and not the
+ # other _nolink targets, we'll have to modify this to be configurable.
+ set(target_exists_genex "$<TARGET_EXISTS:${target}>")
+ set(props_to_set INTERFACE_INCLUDE_DIRECTORIES INTERFACE_SYSTEM_INCLUDE_DIRECTORIES
+ INTERFACE_COMPILE_DEFINITIONS INTERFACE_COMPILE_OPTIONS
+ INTERFACE_COMPILE_FEATURES)
+ foreach(prop ${props_to_set})
+ set_target_properties(
+ "${nolink_target}" PROPERTIES
+ ${prop} $<${target_exists_genex}:$<TARGET_PROPERTY:${target},${prop}>>
+ )
+ endforeach()
+
+ add_library(${prefixed_nolink_target} ALIAS ${nolink_target})
+ add_library("${INSTALL_CMAKE_NAMESPACE}::${nolink_target}" ALIAS ${nolink_target})
+
+ set(export_name "${INSTALL_CMAKE_NAMESPACE}${dependee_target}Targets")
+ qt_install(TARGETS ${nolink_target} EXPORT ${export_name})
+ endif()
+endfunction()
diff --git a/cmake/QtPkgConfigHelpers.cmake b/cmake/QtPkgConfigHelpers.cmake
new file mode 100644
index 0000000000..dbe736c438
--- /dev/null
+++ b/cmake/QtPkgConfigHelpers.cmake
@@ -0,0 +1,164 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+function(qt_internal_collect_direct_target_dependencies target targets_out_var)
+ __qt_internal_walk_libs("${target}" "${targets_out_var}" _rcc_objects
+ "qt_direct_targets_dict" "direct_targets")
+ set("${targets_out_var}" "${${targets_out_var}}" PARENT_SCOPE)
+endfunction()
+
+macro(qt_internal_set_pkg_config_cpp_flags var options flag)
+ set(tmpopts "${options}")
+ list(FILTER tmpopts EXCLUDE REGEX "\\$<BUILD_INTERFACE:[^,>]+>")
+ list(FILTER tmpopts EXCLUDE REGEX "\\$<TARGET_PROPERTY:[^,>]+>")
+ list(TRANSFORM tmpopts REPLACE "\\$<\\$<LINK_LANGUAGE:[^,>]+>:([^,>]+)>" "\\1")
+ list(TRANSFORM tmpopts REPLACE "\\$<INSTALL_INTERFACE:([^,>]+)>" "\\1")
+ list(TRANSFORM tmpopts REPLACE ">" "$<ANGLE-R>")
+ list(TRANSFORM tmpopts REPLACE "," "$<COMMA>")
+ set(${var} "$<$<BOOL:${tmpopts}>:${flag}$<JOIN:$<REMOVE_DUPLICATES:${tmpopts}>, ${flag}>>")
+ unset(tmpopts)
+endmacro()
+
+# Create a Qt6*.pc file intended for pkg-config consumption.
+function(qt_internal_generate_pkg_config_file module)
+ # TODO: PkgConfig is supported under MSVC with pkgconf (github.com/pkgconf/pkgconf)
+ if((NOT UNIX OR QT_FEATURE_framework)
+ AND NOT MINGW OR CMAKE_VERSION VERSION_LESS "3.20" OR ANDROID)
+ return()
+ endif()
+ if(NOT BUILD_SHARED_LIBS)
+ return()
+ endif()
+
+ set(pkgconfig_file "${QT_CMAKE_EXPORT_NAMESPACE}${module}")
+ set(pkgconfig_name "${QT_CMAKE_EXPORT_NAMESPACE} ${module}")
+ set(pkgconfig_description "Qt ${module} module")
+ set(target "${QT_CMAKE_EXPORT_NAMESPACE}::${module}")
+ set(is_interface_library "$<STREQUAL:$<TARGET_PROPERTY:${target},TYPE>,INTERFACE_LIBRARY>")
+ # The flags macro expanded this variables so it's better to set them at
+ # their corresponding PkgConfig string.
+ set(includedir "\${includedir}")
+ set(mkspecsdir "\${mkspecsdir}")
+
+ get_target_property(is_internal_module ${target} _qt_is_internal_module)
+ if(is_internal_module)
+ return()
+ endif()
+
+ get_target_property(loose_link_options ${target} INTERFACE_LINK_OPTIONS)
+ get_target_property(loose_compile_defs ${target} INTERFACE_COMPILE_DEFINITIONS)
+ get_target_property(loose_include_dirs ${target} INTERFACE_INCLUDE_DIRECTORIES)
+ list(TRANSFORM loose_include_dirs REPLACE "${INSTALL_INCLUDEDIR}" "\${includedir}")
+ list(TRANSFORM loose_include_dirs REPLACE "${INSTALL_MKSPECSDIR}" "\${mkspecsdir}")
+
+ # Remove genex wrapping around gc_sections flag because we can't evaluate genexes like
+ # $<CXX_COMPILER_ID> in file(GENERATE). And given that .pc files don't support dynamic
+ # evaluation like the $<CXX_COMPILER_ID> genex, distros will be expected to patch the .pc
+ # files according to which compiler they intend to be used with.
+ get_property(gc_sections_with_genex GLOBAL PROPERTY _qt_internal_gc_sections_with_genex)
+ get_property(gc_sections_without_genex GLOBAL PROPERTY _qt_internal_gc_sections_without_genex)
+ if(loose_link_options AND gc_sections_with_genex AND gc_sections_without_genex)
+ string(REPLACE "${gc_sections_with_genex}" "${gc_sections_without_genex}"
+ loose_link_options "${loose_link_options}")
+ endif()
+
+ qt_internal_set_pkg_config_cpp_flags(link_options "${loose_link_options}" "")
+ qt_internal_set_pkg_config_cpp_flags(compile_defs "${loose_compile_defs}" -D)
+ qt_internal_set_pkg_config_cpp_flags(include_dirs "${loose_include_dirs}" -I)
+ if("${include_dirs}" MATCHES "\\${mkspecsdir}")
+ set(contains_mkspecs TRUE)
+ endif()
+
+ # TODO: Handle macOS framework builds
+ qt_internal_collect_direct_target_dependencies(${target} loose_target_requires)
+ foreach(dep IN LISTS loose_target_requires)
+ if(dep MATCHES "^Qt::")
+ string(REGEX REPLACE "Qt" "${QT_CMAKE_EXPORT_NAMESPACE}" dep ${dep})
+ else()
+ # TODO: Figure out a way to get non-Qt requirements PkgConfig files.
+ continue()
+ endif()
+ if(NOT TARGET ${dep})
+ continue()
+ endif()
+ get_target_property(is_internal_module ${dep} _qt_is_internal_module)
+ if(is_internal_module OR dep MATCHES ".*Platform.*Internal")
+ continue()
+ endif()
+ get_target_property(type ${dep} TYPE)
+ if(type STREQUAL "INTERFACE_LIBRARY")
+ if(dep MATCHES "(.*)Private")
+ set(dep "${CMAKE_MATCH_1}")
+ endif()
+ get_target_property(type ${dep} TYPE)
+ endif()
+ string(REGEX REPLACE "::" "" req ${dep})
+ if(type STREQUAL "STATIC_LIBRARY")
+ list(APPEND target_libs -l${req})
+ else()
+ list(APPEND target_requires ${req})
+ endif()
+ endforeach()
+ string(APPEND link_options " $<JOIN:$<REMOVE_DUPLICATES:${target_libs}>, >")
+
+ qt_path_join(path_suffix "${INSTALL_LIBDIR}" pkgconfig)
+ qt_path_join(build_dir "${QT_BUILD_DIR}" "${path_suffix}")
+ qt_path_join(install_dir "${QT_INSTALL_DIR}" "${path_suffix}")
+
+ set(step_prefix "preliminary_pc_for_${pkgconfig_file}")
+ qt_path_join(template_pc "${QT_CMAKE_DIR}" PkgConfigLibrary.pc.in)
+ qt_path_join(pc_step1_path "${build_dir}" ${step_prefix}_step1.pc)
+ qt_path_join(pc_step2_path "${build_dir}" ${step_prefix}_$<CONFIG>_step2.pc)
+
+ configure_file("${template_pc}" "${pc_step1_path}" @ONLY)
+
+ file(GENERATE OUTPUT "${pc_step2_path}" INPUT "${pc_step1_path}")
+
+ if(QT_GENERATOR_IS_MULTI_CONFIG)
+ set(configs ${CMAKE_CONFIGURATION_TYPES})
+ set(rels ${configs})
+ list(FILTER rels INCLUDE REGEX "(Release|RelWithDebInfo|MinSizeRel)")
+ if(rels)
+ list(GET rels 0 release)
+ endif()
+ else()
+ set(configs ${CMAKE_BUILD_TYPE})
+ set(release ${configs})
+ endif()
+
+ foreach(config ${configs})
+ if(config STREQUAL "Debug" AND CMAKE_DEBUG_POSTFIX)
+ set(postfix ${CMAKE_DEBUG_POSTFIX})
+ elseif(NOT config STREQUAL release)
+ string(TOLOWER "_${config}" postfix)
+ else()
+ set(postfix "")
+ endif()
+
+ set(extra_args "")
+ if(NOT postfix STREQUAL "")
+ list(APPEND extra_args "-DPOSTFIX=${postfix}")
+ endif()
+
+ qt_path_join(pc_step2_path "${build_dir}" ${step_prefix}_${config}_step2.pc)
+ qt_path_join(final_pc_path "${build_dir}" ${pkgconfig_file}${postfix}.pc)
+
+ add_custom_command(
+ OUTPUT "${final_pc_path}"
+ DEPENDS "${pc_step2_path}"
+ "${QT_CMAKE_DIR}/QtFinishPkgConfigFile.cmake"
+ COMMAND ${CMAKE_COMMAND}
+ "-DIN_FILE=${pc_step2_path}"
+ "-DOUT_FILE=${final_pc_path}"
+ ${extra_args}
+ -P "${QT_CMAKE_DIR}/QtFinishPkgConfigFile.cmake"
+ VERBATIM
+ COMMENT "Generating pc file for target ${target}"
+ )
+
+ # This is inspired by https://gitlab.kitware.com/cmake/cmake/-/issues/20842
+ target_sources(${module} PRIVATE "${final_pc_path}")
+
+ qt_install(FILES "${final_pc_path}" DESTINATION "${install_dir}")
+ endforeach()
+endfunction()
diff --git a/cmake/QtPlatformAndroid.cmake b/cmake/QtPlatformAndroid.cmake
index 15f40f42c3..e4253b75d7 100644
--- a/cmake/QtPlatformAndroid.cmake
+++ b/cmake/QtPlatformAndroid.cmake
@@ -1,26 +1,22 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
#
# Self contained Platform Settings for Android
#
-# Note: This file is used both by the internal and public builds.
+# Note: This file is used by the internal builds.
#
#
-# Public variables:
+# Variables:
# QT_ANDROID_JAR
# Location of the adroid sdk jar for java code
-# QT_ANDROID_APIVERSION
+# QT_ANDROID_API_VERSION
# Android API version
-# QT_ANDROID_SDK_BUILD_TOOLS_VERSION
-# Detected Android sdk build tools version
-#
-# Public functions:
-#
-# qt_android_generate_deployment_settings()
-# Generate the deployment settings json file for a cmake target.
#
if (NOT DEFINED ANDROID_SDK_ROOT)
- message(FATAL_ERROR "Please provide the location of the Android SDK directory via -DANDROID_SDK_ROOT=<path to Adndroid SDK>")
+ message(FATAL_ERROR "Please provide the location of the Android SDK directory via -DANDROID_SDK_ROOT=<path to Android SDK>")
endif()
if (NOT IS_DIRECTORY "${ANDROID_SDK_ROOT}")
@@ -40,28 +36,66 @@ function(qt_get_android_sdk_jar_for_api api out_jar_location)
endfunction()
# Minimum recommend android SDK api version
-set(QT_ANDROID_API_VERSION "android-28")
+set(QT_ANDROID_API_VERSION "android-33")
-# Locate android.jar
-set(QT_ANDROID_JAR "${ANDROID_SDK_ROOT}/platforms/${QT_ANDROID_API_VERSION}/android.jar")
-if(NOT EXISTS "${QT_ANDROID_JAR}")
- # Locate the highest available platform
- file(GLOB android_platforms
- LIST_DIRECTORIES true
- RELATIVE "${ANDROID_SDK_ROOT}/platforms"
- "${ANDROID_SDK_ROOT}/platforms/*")
- # If list is not empty
- if(android_platforms)
- list(SORT android_platforms)
- list(REVERSE android_platforms)
- list(GET android_platforms 0 android_platform_latest)
+function(qt_internal_sort_android_platforms out_var)
+ if(CMAKE_VERSION GREATER_EQUAL 3.18)
+ set(platforms ${ARGN})
+ list(SORT platforms COMPARE NATURAL)
+ else()
+ # Simulate natural sorting:
+ # - prepend every platform with its version as three digits, zero-padded
+ # - regular sort
+ # - remove the padded version prefix
+ set(platforms)
+ foreach(platform IN LISTS ARGN)
+ set(version "000")
+ if(platform MATCHES ".*-([0-9]+)$")
+ set(version ${CMAKE_MATCH_1})
+ string(LENGTH "${version}" version_length)
+ math(EXPR padding_length "3 - ${version_length}")
+ string(REPEAT "0" ${padding_length} padding)
+ string(PREPEND version ${padding})
+ endif()
+ list(APPEND platforms "${version}~${platform}")
+ endforeach()
+ list(SORT platforms)
+ list(TRANSFORM platforms REPLACE "^.*~" "")
+ endif()
+ set("${out_var}" "${platforms}" PARENT_SCOPE)
+endfunction()
+
+macro(qt_internal_get_android_platform_version out_var android_platform)
+ string(REGEX REPLACE ".*-([0-9]+)$" "\\1" ${out_var} "${android_platform}")
+endmacro()
+
+# Locate the highest available platform
+file(GLOB android_platforms
+ LIST_DIRECTORIES true
+ RELATIVE "${ANDROID_SDK_ROOT}/platforms"
+ "${ANDROID_SDK_ROOT}/platforms/*")
+# If list is not empty
+if(android_platforms)
+ qt_internal_sort_android_platforms(android_platforms ${android_platforms})
+ list(REVERSE android_platforms)
+ list(GET android_platforms 0 android_platform_latest)
+
+ qt_internal_get_android_platform_version(latest_platform_version
+ "${android_platform_latest}")
+ qt_internal_get_android_platform_version(required_platform_version
+ "${QT_ANDROID_API_VERSION}")
+
+ if("${latest_platform_version}" VERSION_GREATER "${required_platform_version}")
set(QT_ANDROID_API_VERSION ${android_platform_latest})
- set(QT_ANDROID_JAR "${ANDROID_SDK_ROOT}/platforms/${QT_ANDROID_API_VERSION}/android.jar")
endif()
endif()
+set(QT_ANDROID_JAR "${ANDROID_SDK_ROOT}/platforms/${QT_ANDROID_API_VERSION}/android.jar")
if(NOT EXISTS "${QT_ANDROID_JAR}")
- message(FATAL_ERROR "No suitable Android SDK platform found. Minimum version is ${QT_ANDROID_API_VERSION}")
+ message(FATAL_ERROR
+ "No suitable Android SDK platform found in '${ANDROID_SDK_ROOT}/platforms'."
+ " Minimum version is ${QT_ANDROID_API_VERSION}"
+ )
endif()
message(STATUS "Using Android SDK API ${QT_ANDROID_API_VERSION} from ${ANDROID_SDK_ROOT}/platforms")
@@ -72,21 +106,6 @@ include(UseJava)
# Find JDK 8.0
find_package(Java 1.8 COMPONENTS Development REQUIRED)
-# Locate newest android sdk build tools
-if (NOT QT_ANDROID_SDK_BUILD_TOOLS_VERSION)
- file(GLOB android_build_tools
- LIST_DIRECTORIES true
- RELATIVE "${ANDROID_SDK_ROOT}/build-tools"
- "${ANDROID_SDK_ROOT}/build-tools/*")
- if (NOT android_build_tools)
- message(FATAL_ERROR "Could not locate Android SDK build tools under \"${ANDROID_SDK}/build-tools\"")
- endif()
- list(SORT android_build_tools)
- list(REVERSE android_build_tools)
- list(GET android_build_tools 0 android_build_tools_latest)
- set(QT_ANDROID_SDK_BUILD_TOOLS_VERSION ${android_build_tools_latest})
-endif()
-
# Ensure we are using the shared version of libc++
if(NOT ANDROID_STL STREQUAL c++_shared)
message(FATAL_ERROR "The Qt libraries on Android only supports the shared library configuration of stl. Please use -DANDROID_STL=\"c++_shared\" as configuration argument.")
@@ -131,231 +150,44 @@ define_property(TARGET
define_property(TARGET
PROPERTY
- QT_ANDROID_DEPLOYMENT_SETTINGS_FILE
+ QT_ANDROID_APPLICATION_ARGUMENTS
BRIEF_DOCS
- " "
+ "This variable can be used to specify command-line arguments to the Android app."
FULL_DOCS
- " "
+ "Specifies extra command-line arguments to the Android app using the AndroidManifest.xml with the tag android.app.arguments."
)
-# Generate deployment tool json
-function(qt_android_generate_deployment_settings target)
- # Information extracted from mkspecs/features/android/android_deployment_settings.prf
- if (NOT TARGET ${target})
- message(SEND_ERROR "${target} is not a cmake target")
- return()
- endif()
-
- get_target_property(target_type ${target} TYPE)
-
- if (NOT "${target_type}" STREQUAL "MODULE_LIBRARY")
- message(SEND_ERROR "QT_ANDROID_GENERATE_DEPLOYMENT_SETTINGS only works on Module targets")
- return()
- endif()
-
- get_target_property(target_source_dir ${target} SOURCE_DIR)
- get_target_property(target_binary_dir ${target} BINARY_DIR)
- get_target_property(target_output_name ${target} OUTPUT_NAME)
- if (NOT target_output_name)
- set(target_output_name ${target})
- endif()
- set(deploy_file "${target_binary_dir}/android-lib${target_output_name}.so-deployment-settings.json")
-
- set(file_contents "{\n")
- # content begin
- string(APPEND file_contents
- " \"description\": \"This file is generated by cmake to be read by androiddeployqt and should not be modified by hand.\",\n")
-
- # Host Qt Android install path
- if (NOT QT_BUILDING_QT)
- set(file_check "${Qt6_DIR}/plugins/platforms/android/libqtforandroid_${CMAKE_ANDROID_ARCH_ABI}.so")
- if (NOT EXISTS ${file_check})
- message(SEND_ERROR "Detected Qt installation does not contain libqtforandroid.so. This is most likely due to the installation not being a build of Qt for Android. Please update your settings.")
- return()
- endif()
- set(qt_android_install_dir ${Qt6_Dir})
- else()
- # Building from source, use the same install prefix
- set(qt_android_install_dir ${CMAKE_INSTALL_PREFIX})
- endif()
-
- file(TO_NATIVE_PATH "${qt_android_install_dir}" qt_android_install_dir_native)
- string(APPEND file_contents
- " \"qt\": \"${qt_android_install_dir_native}\",\n")
-
- # Android SDK path
- file(TO_NATIVE_PATH "${ANDROID_SDK_ROOT}" android_sdk_root_native)
- string(APPEND file_contents
- " \"sdk\": \"${android_sdk_root_native}\",\n")
-
- # Android SDK Build Tools Revision
- string(APPEND file_contents
- " \"sdkBuildToolsRevision\": \"${QT_ANDROID_SDK_BUILD_TOOLS_VERSION}\",\n")
-
- # Android NDK
- file(TO_NATIVE_PATH "${ANDROID_NDK}" android_ndk_root_native)
- string(APPEND file_contents
- " \"ndk\": \"${android_ndk_root_native}\",\n")
-
- # Setup LLVM toolchain
- string(APPEND file_contents
- " \"toolchain-prefix\": \"llvm\",\n")
- string(APPEND file_contents
- " \"tool-prefix\": \"llvm\",\n")
- string(APPEND file_contents
- " \"useLLVM\": true,\n")
-
- # NDK Toolchain Version
- string(APPEND file_contents
- " \"toolchain-version\": \"${CMAKE_ANDROID_NDK_TOOLCHAIN_VERSION}\",\n")
-
- # NDK Host
- string(APPEND file_contents
- " \"ndk-host\": \"${ANDROID_NDK_HOST_SYSTEM_NAME}\",\n")
-
- if (CMAKE_ANDROID_ARCH_ABI STREQUAL "x86")
- set(arch_value "i686-linux-android")
- elseif (CMAKE_ANDROID_ARCH_ABI STREQUAL "x86_64")
- set(arch_value "x86_64-linux-android")
- elseif (CMAKE_ANDROID_ARCH_ABI STREQUAL "arm64-v8a")
- set(arch_value "aarch64-linux-android")
- else()
- set(arch_value "arm-linux-androideabi")
- endif()
-
- # Architecture
- string(APPEND file_contents
- " \"architectures\": { \"${CMAKE_ANDROID_ARCH_ABI}\" : \"${arch_value}\" },\n")
-
- # deployment dependencies
- get_target_property(android_deployment_dependencies
- ${target} QT_ANDROID_DEPLOYMENT_DEPENDENCIES)
- if (android_deployment_dependencies)
- list(JOIN android_deployment_dependencies "," android_deployment_dependencies)
- string(APPEND file_contents
- " \"deployment-dependencies\": \"${android_deployment_dependencies}\",\n")
- endif()
-
- # Extra plugins
- get_target_property(android_extra_plugins
- ${target} QT_ANDROID_EXTRA_PLUGINS)
- if (android_extra_plugins)
- list(JOIN android_extra_plugins "," android_extra_plugins)
- string(APPEND file_contents
- " \"android-extra-plugins\": \"${android_extra_plugins}\",\n")
- endif()
-
- # Extra libs
- get_target_property(android_extra_libs
- ${target} QT_ANDROID_EXTRA_LIBS)
- if (android_extra_libs)
- list(JOIN android_extra_libs "," android_extra_libs)
- string(APPEND file_contents
- " \"android-extra-libs\": \"${android_extra_libs}\",\n")
- endif()
-
- # package source dir
- get_target_property(android_package_source_dir
- ${target} QT_ANDROID_PACKAGE_SOURCE_DIR)
- if (android_package_source_dir)
- file(TO_NATIVE_PATH "${android_package_source_dir}" android_package_source_dir_native)
- string(APPEND file_contents
- " \"android-package-source-directory\": \"${android_package_source_dir_native}\",\n")
-endif()
-
- #TODO: ANDROID_VERSION_NAME, doesn't seem to be used?
-
- #TODO: ANDROID_VERSION_CODE, doesn't seem to be used?
-
- get_target_property(qml_import_path ${target} QT_QML_IMPORT_PATH)
- if (qml_import_path)
- file(TO_NATIVE_PATH "${qml_import_path}" qml_import_path_native)
- string(APPEND file_contents
- " \"qml-import-path\": \"${qml_import_path_native}\",\n")
- endif()
-
- get_target_property(qml_root_path ${target} QT_QML_ROOT_PATH)
- if(NOT qml_root_path)
- set(qml_root_path "${target_source_dir}")
- endif()
- file(TO_NATIVE_PATH "${qml_root_path}" qml_root_path_native)
- string(APPEND file_contents
- " \"qml-root-path\": \"${qml_root_path_native}\",\n")
-
- # App binary
- string(APPEND file_contents
- " \"application-binary\": \"${target_output_name}\",\n")
-
- # Override qmlimportscanner binary path
- set(qml_importscanner_binary_path "${QT_HOST_PATH}/bin/qmlimportscanner")
- if (WIN32)
- string(APPEND qml_importscanner_binary_path ".exe")
- endif()
- file(TO_NATIVE_PATH "${qml_importscanner_binary_path}" qml_importscanner_binary_path_native)
- string(APPEND file_contents
- " \"qml-importscanner-binary\" : \"${qml_importscanner_binary_path_native}\",\n")
-
- # Last item in json file
-
- # base location of stdlibc++, will be suffixed by androiddeploy qt
- set(android_ndk_stdlib_base_path
- "${ANDROID_NDK}/toolchains/llvm/prebuilt/linux-x86_64/sysroot/usr/lib/"
- )
- string(APPEND file_contents
- " \"stdcpp-path\": \"${android_ndk_stdlib_base_path}\"\n")
-
- # content end
- string(APPEND file_contents "}\n")
-
- file(WRITE ${deploy_file} ${file_contents})
-
- set_target_properties(${target}
- PROPERTIES
- QT_ANDROID_DEPLOYMENT_SETTINGS_FILE ${deploy_file}
- )
-endfunction()
-
-function(qt_android_apply_arch_suffix target)
- get_target_property(target_type ${target} TYPE)
- if (target_type STREQUAL "SHARED_LIBRARY" OR target_type STREQUAL "MODULE_LIBRARY")
- set_property(TARGET "${target}" PROPERTY SUFFIX "_${CMAKE_ANDROID_ARCH_ABI}.so")
- elseif (target_type STREQUAL "STATIC_LIBRARY")
- set_property(TARGET "${target}" PROPERTY SUFFIX "_${CMAKE_ANDROID_ARCH_ABI}.a")
- endif()
-endfunction()
-
-# Add custom target to package the APK
-function(qt_android_add_apk_target target)
- get_target_property(deployment_file ${target} QT_ANDROID_DEPLOYMENT_SETTINGS_FILE)
- if (NOT deployment_file)
- message(FATAL_ERROR "Target ${target} is not a valid android executable target\n")
- endif()
-
- set(deployment_tool "${QT_HOST_PATH}/bin/androiddeployqt")
- set(apk_dir "$<TARGET_PROPERTY:${target},BINARY_DIR>/android-build")
- add_custom_target(${target}_prepare_apk_dir
- DEPENDS ${target}
- COMMAND ${CMAKE_COMMAND}
- -E copy $<TARGET_FILE:${target}>
- "${apk_dir}/libs/${CMAKE_ANDROID_ARCH_ABI}/$<TARGET_FILE_NAME:${target}>"
- COMMENT "Copying ${target} binarty to apk folder"
- )
-
- add_custom_target(${target}_make_apk
- DEPENDS ${target}_prepare_apk_dir
- COMMAND ${deployment_tool}
- --input ${deployment_file}
- --output ${apk_dir}
- COMMENT "Creating APK for ${target}"
- )
-endfunction()
+define_property(TARGET
+ PROPERTY
+ QT_ANDROID_DEPLOYMENT_SETTINGS_FILE
+ BRIEF_DOCS
+ "This variable is used to specify the deployment settings JSON file for androiddeployqt."
+ FULL_DOCS
+ "This variable points to the path of the deployment settings JSON file, which holds properties required by androiddeployqt to package the Android app."
+)
+define_property(TARGET
+ PROPERTY
+ QT_ANDROID_SYSTEM_LIBS_PREFIX
+ BRIEF_DOCS
+ "This variable is used to specify a path to Qt libraries on the target device in Android."
+ FULL_DOCS
+ "This variable can be used to provide a custom system library path to use for library loading lookup on Android. This is necessary when using Qt libraries installed outside an app's default native (JNI) library directory."
+)
-# Add a test for Android which will be run by the android test runner tool
-function(qt_android_add_test target)
+define_property(TARGET
+ PROPERTY
+ QT_ANDROID_NO_DEPLOY_QT_LIBS
+ BRIEF_DOCS
+ "This variable is used to control whether Qt libraries should be deployed inside the APK on Android."
+ FULL_DOCS
+ "This variable can be used to exclude Qt shared libraries from being packaged inside the APK when deploying on Android. Not supported when deploying as Android Application Bundle."
+)
- set(deployment_tool "${QT_HOST_PATH}/bin/androiddeployqt")
- set(test_runner "${QT_HOST_PATH}/bin/androidtestrunner")
+# Returns test execution arguments for Android targets
+function(qt_internal_android_test_arguments target timeout out_test_runner out_test_arguments)
+ set(${out_test_runner} "${QT_HOST_PATH}/${QT${PROJECT_VERSION_MAJOR}_HOST_INFO_BINDIR}/androidtestrunner" PARENT_SCOPE)
+ set(deployment_tool "${QT_HOST_PATH}/${QT${PROJECT_VERSION_MAJOR}_HOST_INFO_BINDIR}/androiddeployqt")
get_target_property(deployment_file ${target} QT_ANDROID_DEPLOYMENT_SETTINGS_FILE)
if (NOT deployment_file)
@@ -363,16 +195,20 @@ function(qt_android_add_test target)
endif()
set(target_binary_dir "$<TARGET_PROPERTY:${target},BINARY_DIR>")
- set(apk_dir "${target_binary_dir}/android-build")
-
- add_test(NAME "${target}"
- COMMAND "${test_runner}"
- --androiddeployqt "${deployment_tool} --input ${deployment_file}"
- --adb "${ANDROID_SDK_ROOT}/platform-tools/adb"
- --path "${apk_dir}"
- --skip-install-root
- --make "${CMAKE_COMMAND} --build ${CMAKE_BINARY_DIR} --target ${target}_make_apk"
- --apk "${apk_dir}/${target}.apk"
- --verbose
+ if(QT_USE_TARGET_ANDROID_BUILD_DIR)
+ set(apk_dir "${target_binary_dir}/android-build-${target}")
+ else()
+ set(apk_dir "${target_binary_dir}/android-build")
+ endif()
+ set(${out_test_arguments}
+ "--path" "${apk_dir}"
+ "--adb" "${ANDROID_SDK_ROOT}/platform-tools/adb"
+ "--skip-install-root"
+ "--make" "\"${CMAKE_COMMAND}\" --build ${CMAKE_BINARY_DIR} --target ${target}_make_apk"
+ "--apk" "${apk_dir}/${target}.apk"
+ "--ndk-stack" "${ANDROID_NDK_ROOT}/ndk-stack"
+ "--timeout" "${timeout}"
+ "--verbose"
+ PARENT_SCOPE
)
endfunction()
diff --git a/cmake/QtPlatformSupport.cmake b/cmake/QtPlatformSupport.cmake
index 1c428afe73..9f8498e42c 100644
--- a/cmake/QtPlatformSupport.cmake
+++ b/cmake/QtPlatformSupport.cmake
@@ -1,3 +1,6 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
function(qt_set01 result)
if (${ARGN})
set("${result}" 1 PARENT_SCOPE)
@@ -9,30 +12,35 @@ endfunction()
qt_set01(LINUX CMAKE_SYSTEM_NAME STREQUAL "Linux")
qt_set01(HPUX CMAKE_SYSTEM_NAME STREQUAL "HPUX")
qt_set01(ANDROID CMAKE_SYSTEM_NAME STREQUAL "Android") # FIXME: How to identify this?
-qt_set01(NACL CMAKE_SYSTEM_NAME STREQUAL "NaCl") # FIXME: How to identify this?
qt_set01(INTEGRITY CMAKE_SYSTEM_NAME STREQUAL "Integrity") # FIXME: How to identify this?
qt_set01(VXWORKS CMAKE_SYSTEM_NAME STREQUAL "VxWorks") # FIXME: How to identify this?
qt_set01(QNX CMAKE_SYSTEM_NAME STREQUAL "QNX") # FIXME: How to identify this?
qt_set01(OPENBSD CMAKE_SYSTEM_NAME STREQUAL "OpenBSD") # FIXME: How to identify this?
qt_set01(FREEBSD CMAKE_SYSTEM_NAME STREQUAL "FreeBSD") # FIXME: How to identify this?
qt_set01(NETBSD CMAKE_SYSTEM_NAME STREQUAL "NetBSD") # FIXME: How to identify this?
-qt_set01(WASM CMAKE_SYSTEM_NAME STREQUAL "Emscripten")
+qt_set01(WASM CMAKE_SYSTEM_NAME STREQUAL "Emscripten" OR EMSCRIPTEN)
+qt_set01(WASM64 QT_QMAKE_TARGET_MKSPEC STREQUAL "wasm-emscripten-64")
+qt_set01(SOLARIS CMAKE_SYSTEM_NAME STREQUAL "SunOS")
+qt_set01(HURD CMAKE_SYSTEM_NAME STREQUAL "GNU")
-qt_set01(BSD APPLE OR OPENBSD OR FREEBSD OR NETBSD)
+# This is the only reliable way we can determine the webOS platform as the yocto recipe adds this
+# compile definition into its generated toolchain.cmake file
+qt_set01(WEBOS CMAKE_CXX_FLAGS MATCHES "-D__WEBOS__")
-qt_set01(WINRT WIN32 AND CMAKE_VS_PLATFORM_TOOSLET STREQUAL "winrt") # FIXME: How to identify this?
+qt_set01(BSD APPLE OR OPENBSD OR FREEBSD OR NETBSD)
qt_set01(IOS APPLE AND CMAKE_SYSTEM_NAME STREQUAL "iOS")
qt_set01(TVOS APPLE AND CMAKE_SYSTEM_NAME STREQUAL "tvOS")
qt_set01(WATCHOS APPLE AND CMAKE_SYSTEM_NAME STREQUAL "watchOS")
-qt_set01(UIKIT APPLE AND (IOS OR TVOS OR WATCHOS))
+qt_set01(VISIONOS APPLE AND CMAKE_SYSTEM_NAME STREQUAL "visionOS")
+qt_set01(UIKIT APPLE AND (IOS OR TVOS OR WATCHOS OR VISIONOS))
qt_set01(MACOS APPLE AND NOT UIKIT)
qt_set01(GCC CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
-qt_set01(CLANG CMAKE_CXX_COMPILER_ID MATCHES "Clang")
+qt_set01(CLANG CMAKE_CXX_COMPILER_ID MATCHES "Clang|IntelLLVM")
qt_set01(APPLECLANG CMAKE_CXX_COMPILER_ID MATCHES "AppleClang")
-qt_set01(ICC CMAKE_C_COMPILER MATCHES "icc|icl")
-qt_set01(QCC CMAKE_C_COMPILER MATCHES "qcc") # FIXME: How to identify this?
+qt_set01(IntelLLVM CMAKE_CXX_COMPILER_ID STREQUAL "IntelLLVM")
+qt_set01(QCC CMAKE_CXX_COMPILER_ID STREQUAL "QCC") # CMP0047
if(CMAKE_SIZEOF_VOID_P EQUAL 8)
set(QT_64BIT TRUE)
diff --git a/cmake/QtPlatformTargetHelpers.cmake b/cmake/QtPlatformTargetHelpers.cmake
new file mode 100644
index 0000000000..f1976b9975
--- /dev/null
+++ b/cmake/QtPlatformTargetHelpers.cmake
@@ -0,0 +1,98 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+# Defines the public Qt::Platform target, which serves as a dependency for all internal Qt target
+# as well as user projects consuming Qt.
+function(qt_internal_setup_public_platform_target)
+ qt_internal_get_platform_definition_include_dir(
+ install_interface_definition_dir
+ build_interface_definition_dir
+ )
+
+ ## QtPlatform Target:
+ add_library(Platform INTERFACE)
+ add_library(Qt::Platform ALIAS Platform)
+ add_library(${INSTALL_CMAKE_NAMESPACE}::Platform ALIAS Platform)
+ target_include_directories(Platform
+ INTERFACE
+ $<BUILD_INTERFACE:${build_interface_definition_dir}>
+ $<BUILD_INTERFACE:${PROJECT_BINARY_DIR}/include>
+ $<INSTALL_INTERFACE:${install_interface_definition_dir}>
+ $<INSTALL_INTERFACE:${INSTALL_INCLUDEDIR}>
+ )
+ target_compile_definitions(Platform INTERFACE ${QT_PLATFORM_DEFINITIONS})
+
+ set_target_properties(Platform PROPERTIES
+ _qt_package_version "${PROJECT_VERSION}"
+ )
+ set_property(TARGET Platform
+ APPEND PROPERTY
+ EXPORT_PROPERTIES "_qt_package_version")
+
+ # When building on android we need to link against the logging library
+ # in order to satisfy linker dependencies. Both of these libraries are part of
+ # the NDK.
+ if (ANDROID)
+ target_link_libraries(Platform INTERFACE log)
+ endif()
+
+ if (QT_FEATURE_stdlib_libcpp)
+ target_compile_options(Platform INTERFACE "$<$<COMPILE_LANGUAGE:CXX>:-stdlib=libc++>")
+ set(libc_link_option "-stdlib=libc++")
+ if(CMAKE_VERSION VERSION_GREATER_EQUAL "3.18")
+ set(libc_link_option "$<$<LINK_LANGUAGE:CXX>:-stdlib=libc++>")
+ endif()
+ target_link_options(Platform INTERFACE "${libc_link_option}")
+ endif()
+ if (QT_FEATURE_no_direct_extern_access)
+ target_compile_options(Platform INTERFACE "$<$<CXX_COMPILER_ID:GNU>:-mno-direct-extern-access>")
+ target_compile_options(Platform INTERFACE "$<$<CXX_COMPILER_ID:Clang>:-fno-direct-access-external-data>")
+ endif()
+
+ # Qt checks if a given platform supports 128 bit integers
+ # by checking if __SIZEOF_128__ is defined
+ # VXWORKS doesn't support 128 bit integers
+ # but it uses clang which defines __SIZEOF_128__
+ # which breaks the detection mechanism
+ if(VXWORKS)
+ target_compile_definitions(Platform INTERFACE "-DQT_NO_INT128")
+ endif()
+
+ qt_set_msvc_cplusplus_options(Platform INTERFACE)
+
+ # Propagate minimum C++ 17 via Platform to Qt consumers (apps), after the global features
+ # are computed.
+ qt_set_language_standards_interface_compile_features(Platform)
+
+ # By default enable utf8 sources for both Qt and Qt consumers. Can be opted out.
+ qt_enable_utf8_sources(Platform)
+
+ # By default enable unicode on WIN32 platforms for both Qt and Qt consumers. Can be opted out.
+ qt_internal_enable_unicode_defines(Platform)
+
+ # Generate a pkgconfig for Qt::Platform.
+ qt_internal_generate_pkg_config_file(Platform)
+endfunction()
+
+function(qt_internal_get_platform_definition_include_dir install_interface build_interface)
+ # Used by consumers of prefix builds via INSTALL_INTERFACE (relative path).
+ set(${install_interface} "${INSTALL_MKSPECSDIR}/${QT_QMAKE_TARGET_MKSPEC}" PARENT_SCOPE)
+
+ # Used by qtbase in prefix builds via BUILD_INTERFACE
+ set(build_interface_base_dir
+ "${CMAKE_CURRENT_LIST_DIR}/../mkspecs"
+ )
+
+ # Used by qtbase and consumers in non-prefix builds via BUILD_INTERFACE
+ if(NOT QT_WILL_INSTALL)
+ set(build_interface_base_dir
+ "${QT_BUILD_DIR}/${INSTALL_MKSPECSDIR}"
+ )
+ endif()
+
+ get_filename_component(build_interface_dir
+ "${build_interface_base_dir}/${QT_QMAKE_TARGET_MKSPEC}"
+ ABSOLUTE
+ )
+ set(${build_interface} "${build_interface_dir}" PARENT_SCOPE)
+endfunction()
diff --git a/cmake/QtPluginConfig.cmake.in b/cmake/QtPluginConfig.cmake.in
index 5fde0bc511..1dc30b0338 100644
--- a/cmake/QtPluginConfig.cmake.in
+++ b/cmake/QtPluginConfig.cmake.in
@@ -1,7 +1,21 @@
+# Copyright (C) 2024 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
include_guard(DIRECTORY)
+if(DEFINED QT_REPO_DEPENDENCIES AND NOT QT_INTERNAL_BUILD_STANDALONE_PARTS)
+ # We're building a Qt repository.
+ # Skip this plugin if it has not been provided by one of this repo's dependencies.
+ string(TOLOWER "@PROJECT_NAME@" lower_case_project_name)
+ if(NOT lower_case_project_name IN_LIST QT_REPO_DEPENDENCIES)
+ return()
+ endif()
+endif()
+
@PACKAGE_INIT@
+cmake_minimum_required(VERSION @min_new_policy_version@...@max_new_policy_version@)
+
include(CMakeFindDependencyMacro)
get_filename_component(_import_prefix "${CMAKE_CURRENT_LIST_FILE}" PATH)
@@ -9,9 +23,10 @@ get_filename_component(_import_prefix "${_import_prefix}" REALPATH)
if (NOT QT_NO_CREATE_TARGETS)
# Find required dependencies, if any.
- if(EXISTS "${CMAKE_CURRENT_LIST_DIR}/@target@Dependencies.cmake")
- include("${CMAKE_CURRENT_LIST_DIR}/@target@Dependencies.cmake")
+ if(EXISTS "${CMAKE_CURRENT_LIST_DIR}/@INSTALL_CMAKE_NAMESPACE@@target@Dependencies.cmake")
+ include("${CMAKE_CURRENT_LIST_DIR}/@INSTALL_CMAKE_NAMESPACE@@target@Dependencies.cmake")
endif()
include("${CMAKE_CURRENT_LIST_DIR}/@INSTALL_CMAKE_NAMESPACE@@target@Targets.cmake")
+ include("${CMAKE_CURRENT_LIST_DIR}/@INSTALL_CMAKE_NAMESPACE@@target@AdditionalTargetInfo.cmake")
endif()
diff --git a/cmake/QtPluginDependencies.cmake.in b/cmake/QtPluginDependencies.cmake.in
index f25d0bed43..bcbb9bb5db 100644
--- a/cmake/QtPluginDependencies.cmake.in
+++ b/cmake/QtPluginDependencies.cmake.in
@@ -1,42 +1,21 @@
-# note: _third_party_deps example: "ICU\\;1.0\\;i18n uc data;ZLIB\\;\\;"
-set(_third_party_deps "@third_party_deps@")
+# Copyright (C) 2024 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
-foreach(_target_dep ${_third_party_deps})
- list(GET _target_dep 0 pkg)
- list(GET _target_dep 1 version)
- list(GET _target_dep 2 components)
- set(find_package_args "${pkg}")
- if(version)
- list(APPEND find_package_args "${version}")
- endif()
+set(@target@_FOUND FALSE)
- if(components)
- string(REPLACE " " ";" components "${components}")
- find_dependency(${find_package_args} COMPONENTS ${components})
- else()
- find_dependency(${find_package_args})
- endif()
+# note: _third_party_deps example: "ICU\\;FALSE\\;1.0\\;i18n uc data;ZLIB\\;FALSE\\;\\;"
+set(__qt_@target@_third_party_deps "@third_party_deps@")
+_qt_internal_find_third_party_dependencies("@target@" __qt_@target@_third_party_deps)
- if (NOT ${pkg}_FOUND)
- set(@target@_FOUND FALSE)
- return()
- endif()
-endforeach()
+set(__qt_use_no_default_path_for_qt_packages "NO_DEFAULT_PATH")
+if(QT_DISABLE_NO_DEFAULT_PATH_IN_QT_PACKAGES)
+ set(__qt_use_no_default_path_for_qt_packages "")
+endif()
# note: target_deps example: "Qt6Core\;5.12.0;Qt6Gui\;5.12.0"
-set(_target_deps "@target_deps@")
-foreach(_target_dep ${_target_deps})
- list(GET _target_dep 0 pkg)
- list(GET _target_dep 1 version)
+set(__qt_@target@_target_deps "@target_deps@")
+set(__qt_@target@_find_dependency_paths "@find_dependency_paths@")
+_qt_internal_find_qt_dependencies("@target@" __qt_@target@_target_deps
+ __qt_@target@_find_dependency_paths)
- if (NOT ${pkg}_FOUND)
- find_dependency(${pkg} ${version}
- PATHS "${CMAKE_CURRENT_LIST_DIR}/.." ${QT_EXAMPLES_CMAKE_PREFIX_PATH} NO_DEFAULT_PATH
- )
- endif()
-
- if (NOT ${pkg}_FOUND)
- set(@target@_FOUND FALSE)
- return()
- endif()
-endforeach()
+set(@target@_FOUND TRUE)
diff --git a/cmake/QtPluginHelpers.cmake b/cmake/QtPluginHelpers.cmake
new file mode 100644
index 0000000000..9437d4236d
--- /dev/null
+++ b/cmake/QtPluginHelpers.cmake
@@ -0,0 +1,625 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+# Note that these are only the keywords that are unique to qt_internal_add_plugin().
+# That function also supports the keywords defined by _qt_internal_get_add_plugin_keywords().
+macro(qt_internal_get_internal_add_plugin_keywords option_args single_args multi_args)
+ set(${option_args}
+ EXCEPTIONS
+ ALLOW_UNDEFINED_SYMBOLS
+ SKIP_INSTALL
+ NO_UNITY_BUILD
+ )
+ set(${single_args}
+ OUTPUT_DIRECTORY
+ INSTALL_DIRECTORY
+ ARCHIVE_INSTALL_DIRECTORY
+ ${__default_target_info_args}
+ )
+ set(${multi_args}
+ ${__default_private_args}
+ ${__default_public_args}
+ DEFAULT_IF
+ )
+endmacro()
+
+# This is the main entry point for defining Qt plugins.
+# A CMake target is created with the given target.
+# The target name should end with "Plugin" so static plugins are linked automatically.
+# The PLUGIN_TYPE parameter is needed to place the plugin into the correct plugins/ sub-directory.
+function(qt_internal_add_plugin target)
+ qt_internal_set_qt_known_plugins("${QT_KNOWN_PLUGINS}" "${target}")
+
+ _qt_internal_get_add_plugin_keywords(
+ public_option_args
+ public_single_args
+ public_multi_args
+ )
+ qt_internal_get_internal_add_plugin_keywords(
+ internal_option_args
+ internal_single_args
+ internal_multi_args
+ )
+ set(option_args ${public_option_args} ${internal_option_args})
+ set(single_args ${public_single_args} ${internal_single_args})
+ set(multi_args ${public_multi_args} ${internal_multi_args})
+
+ cmake_parse_arguments(PARSE_ARGV 1 arg
+ "${option_args}"
+ "${single_args}"
+ "${multi_args}"
+ )
+ _qt_internal_validate_all_args_are_parsed(arg)
+
+ # Put this behind a cache option for now. It's too noisy for general use
+ # until most repos are updated.
+ option(QT_WARN_PLUGIN_PUBLIC_KEYWORDS "Warn if a plugin specifies a PUBLIC keyword" ON)
+ if(QT_WARN_PLUGIN_PUBLIC_KEYWORDS)
+ foreach(publicKeyword IN LISTS __default_public_args)
+ if(NOT "${arg_${publicKeyword}}" STREQUAL "")
+ string(REPLACE "PUBLIC_" "" privateKeyword "${publicKeyword}")
+ message(AUTHOR_WARNING
+ "Plugins are not intended to be linked to. "
+ "They should not have any public properties, but ${target} "
+ "sets ${publicKeyword} to the following value:\n"
+ " ${arg_${publicKeyword}}\n"
+ "Update your project to use ${privateKeyword} instead.\n")
+ endif()
+ endforeach()
+ endif()
+
+ qt_remove_args(plugin_args
+ ARGS_TO_REMOVE
+ ${internal_option_args}
+ ${internal_single_args}
+ ${internal_multi_args}
+ ALL_ARGS
+ ${option_args}
+ ${single_args}
+ ${multi_args}
+ ARGS
+ ${ARGN}
+ )
+
+ # When creating a static plugin, retrieve the plugin initializer target name, but don't
+ # automatically propagate the plugin initializer.
+ list(APPEND plugin_args
+ __QT_INTERNAL_NO_PROPAGATE_PLUGIN_INITIALIZER
+ OUTPUT_TARGETS plugin_init_target
+ )
+
+ qt6_add_plugin(${target} ${plugin_args})
+ qt_internal_mark_as_internal_library(${target})
+
+ get_target_property(target_type "${target}" TYPE)
+ if(plugin_init_target AND TARGET "${plugin_init_target}")
+ qt_internal_add_target_aliases("${plugin_init_target}")
+ endif()
+
+ set(plugin_type "")
+ # TODO: Transitional: Remove the TYPE option handling after all repos have been converted to use
+ # PLUGIN_TYPE.
+ if(arg_TYPE)
+ set(plugin_type "${arg_TYPE}")
+ elseif(arg_PLUGIN_TYPE)
+ set(plugin_type "${arg_PLUGIN_TYPE}")
+ endif()
+
+ if((NOT plugin_type STREQUAL "qml_plugin") AND (NOT target MATCHES "(.*)Plugin$"))
+ message(AUTHOR_WARNING "The internal plugin target name '${target}' should end with the 'Plugin' suffix.")
+ endif()
+
+ qt_get_sanitized_plugin_type("${plugin_type}" plugin_type_escaped)
+
+ set(output_directory_default "${QT_BUILD_DIR}/${INSTALL_PLUGINSDIR}/${plugin_type}")
+ set(install_directory_default "${INSTALL_PLUGINSDIR}/${plugin_type}")
+
+ qt_internal_check_directory_or_type(OUTPUT_DIRECTORY "${arg_OUTPUT_DIRECTORY}" "${plugin_type}"
+ "${output_directory_default}" output_directory)
+ if (NOT arg_SKIP_INSTALL)
+ qt_internal_check_directory_or_type(INSTALL_DIRECTORY "${arg_INSTALL_DIRECTORY}"
+ "${plugin_type}"
+ "${install_directory_default}" install_directory)
+ set(archive_install_directory ${arg_ARCHIVE_INSTALL_DIRECTORY})
+ if (NOT archive_install_directory AND install_directory)
+ set(archive_install_directory "${install_directory}")
+ endif()
+ endif()
+
+ qt_set_target_info_properties(${target} ${ARGN})
+
+ set_target_properties(${target} PROPERTIES
+ _qt_package_version "${PROJECT_VERSION}"
+ )
+ set_property(TARGET ${target}
+ APPEND PROPERTY
+ EXPORT_PROPERTIES "_qt_package_version")
+
+ # Override the OUTPUT_NAME that qt6_add_plugin() set, we need to account for
+ # QT_LIBINFIX, which is specific to building Qt.
+ # Make sure the Qt6 plugin library names are like they were in Qt5 qmake land.
+ # Whereas the Qt6 CMake target names are like the Qt5 CMake target names.
+ get_target_property(output_name ${target} OUTPUT_NAME)
+ set_property(TARGET "${target}" PROPERTY OUTPUT_NAME "${output_name}${QT_LIBINFIX}")
+
+ # Add a custom target with the Qt5 qmake name for a more user friendly ninja experience.
+ if(arg_OUTPUT_NAME AND NOT TARGET "${output_name}")
+ # But don't create such a target if it would just differ in case from "${target}"
+ # and we're not using Ninja. See https://gitlab.kitware.com/cmake/cmake/-/issues/21915
+ string(TOUPPER "${output_name}" uc_output_name)
+ string(TOUPPER "${target}" uc_target)
+ if(NOT uc_output_name STREQUAL uc_target OR CMAKE_GENERATOR MATCHES "^Ninja")
+ add_custom_target("${output_name}")
+ add_dependencies("${output_name}" "${target}")
+ endif()
+ endif()
+
+ qt_set_common_target_properties("${target}")
+ qt_internal_add_target_aliases("${target}")
+ qt_skip_warnings_are_errors_when_repo_unclean("${target}")
+ _qt_internal_apply_strict_cpp("${target}")
+
+ set_target_properties("${target}" PROPERTIES
+ LIBRARY_OUTPUT_DIRECTORY "${output_directory}"
+ RUNTIME_OUTPUT_DIRECTORY "${output_directory}"
+ ARCHIVE_OUTPUT_DIRECTORY "${output_directory}"
+ QT_PLUGIN_TYPE "${plugin_type_escaped}"
+ # Save the non-sanitized plugin type values for qmake consumption via .pri files.
+ QT_QMAKE_PLUGIN_TYPE "${plugin_type}"
+ )
+
+ qt_handle_multi_config_output_dirs("${target}")
+
+ qt_internal_library_deprecation_level(deprecation_define)
+
+ qt_autogen_tools_initial_setup(${target})
+
+ unset(plugin_install_package_suffix)
+
+ # The generic plugins should be enabled by default.
+ # But platform plugins should always be disabled by default, and only one is enabled
+ # based on the platform (condition specified in arg_DEFAULT_IF).
+ if(plugin_type_escaped STREQUAL "platforms")
+ set(_default_plugin 0)
+ else()
+ set(_default_plugin 1)
+ endif()
+
+ if(DEFINED arg_DEFAULT_IF)
+ if(${arg_DEFAULT_IF})
+ set(_default_plugin 1)
+ else()
+ set(_default_plugin 0)
+ endif()
+ endif()
+
+ # Save the Qt module in the plug-in's properties and vice versa
+ if(NOT plugin_type_escaped STREQUAL "qml_plugin")
+ qt_internal_get_module_for_plugin("${target}" "${plugin_type_escaped}" qt_module)
+
+ set(qt_module_target "${QT_CMAKE_EXPORT_NAMESPACE}::${qt_module}")
+ if(NOT TARGET "${qt_module_target}")
+ message(FATAL_ERROR "Failed to associate Qt plugin with Qt module. ${qt_module_target} is not a known CMake target")
+ endif()
+
+ set_target_properties("${target}" PROPERTIES QT_MODULE "${qt_module}")
+ set(plugin_install_package_suffix "${qt_module}")
+
+
+ get_target_property(aliased_target ${qt_module_target} ALIASED_TARGET)
+ if(aliased_target)
+ set(qt_module_target ${aliased_target})
+ endif()
+ get_target_property(is_imported_qt_module ${qt_module_target} IMPORTED)
+
+ if(NOT is_imported_qt_module)
+ # This QT_PLUGINS assignment is only used by QtPostProcessHelpers to decide if a
+ # QtModulePlugins.cmake file should be generated.
+ set_property(TARGET "${qt_module_target}" APPEND PROPERTY QT_PLUGINS "${target}")
+ else()
+ # The _qt_plugins property is considered when collecting the plugins in
+ # deployment process. The usecase is following:
+ # QtModuleX is built separately and installed, so it's imported.
+ # The plugin is built in some application build tree and its PLUGIN_TYPE is associated
+ # with QtModuleX.
+ set_property(TARGET "${qt_module_target}" APPEND PROPERTY _qt_plugins "${target}")
+ endif()
+
+ set(plugin_target_versioned "${QT_CMAKE_EXPORT_NAMESPACE}::${target}")
+ get_target_property(type "${plugin_target_versioned}" TYPE)
+ if(type STREQUAL STATIC_LIBRARY)
+ # Associate plugin with its Qt module when both are both built in the same repository.
+ # Check that by comparing the PROJECT_NAME of each.
+ # This covers auto-linking of the majority of plugins to executables and in-tree tests.
+ # Linking of plugins in standalone tests (when the Qt module will be an imported target)
+ # is handled instead by the complicated genex logic in QtModulePlugins.cmake.in.
+ set(is_plugin_and_module_in_same_project FALSE)
+ if(NOT is_imported_qt_module)
+ get_target_property(module_source_dir ${qt_module_target} SOURCE_DIR)
+ get_directory_property(module_project_name
+ DIRECTORY ${module_source_dir}
+ DEFINITION PROJECT_NAME
+ )
+ if(module_project_name STREQUAL PROJECT_NAME)
+ set(is_plugin_and_module_in_same_project TRUE)
+ endif()
+
+ # When linking static plugins with the special logic in qt_internal_add_executable,
+ # make sure to skip non-default plugins.
+ if(is_plugin_and_module_in_same_project AND _default_plugin)
+ set_property(TARGET ${qt_module_target} APPEND PROPERTY
+ _qt_initial_repo_plugins
+ "${target}")
+ set_property(TARGET ${qt_module_target} APPEND PROPERTY
+ _qt_initial_repo_plugin_class_names
+ "$<TARGET_PROPERTY:${target},QT_PLUGIN_CLASS_NAME>"
+ )
+ endif()
+ endif()
+
+ # Associate plugin with its Qt module when the plugin is built in the current repository
+ # but the module is built in a different repository (qtsvg's QSvgPlugin associated with
+ # qtbase's QtGui).
+ # The association is done in a separate property, to ensure that reconfiguring in-tree tests
+ # in qtbase doesn't accidentally cause linking to a plugin from a previously built qtsvg.
+ # Needed for in-tree tests like in qtsvg, qtimageformats.
+ # This is done for each Qt module regardless if it's an imported target or not, to handle
+ # both per-repo and top-level builds (in per-repo build of qtsvg QtGui is imported, in a
+ # top-level build Gui is not imported, but in both cases qtsvg tests need to link to
+ # QSvgPlugin).
+ #
+ # TODO: Top-level in-tree tests and qdeclarative per-repo in-tree tests that depend on
+ # static Qml plugins won't work due to the requirement of running qmlimportscanner
+ # at configure time, but qmlimportscanner is not built at that point. Moving the
+ # execution of qmlimportscanner to build time is non-trivial because qmlimportscanner
+ # not only generates a cpp file to compile but also outputs a list of static plugins
+ # that should be linked and there is no straightforward way to tell CMake to link
+ # against a list of libraries that was discovered at build time (apart from
+ # response files, which apparently might not work on all platforms).
+ # qmake doesn't have this problem because each project is configured separately so
+ # qmlimportscanner is always built by the time it needs to be run for a test.
+ if(NOT is_plugin_and_module_in_same_project AND _default_plugin)
+ string(MAKE_C_IDENTIFIER "${PROJECT_NAME}" current_project_name)
+ set(prop_prefix "_qt_repo_${current_project_name}")
+ set_property(TARGET ${qt_module_target} APPEND PROPERTY
+ ${prop_prefix}_plugins "${target}")
+ set_property(TARGET ${qt_module_target} APPEND PROPERTY
+ ${prop_prefix}_plugin_class_names
+ "$<TARGET_PROPERTY:${target},QT_PLUGIN_CLASS_NAME>"
+ )
+ endif()
+ endif()
+
+ qt_internal_add_autogen_sync_header_dependencies(${target} ${qt_module_target})
+ endif()
+
+ # Change the configuration file install location for qml plugins into the Qml package location.
+ if(plugin_type_escaped STREQUAL "qml_plugin" AND TARGET "${INSTALL_CMAKE_NAMESPACE}::Qml")
+ set(plugin_install_package_suffix "Qml/QmlPlugins")
+ endif()
+
+ # Save the install package suffix as a property, so that the Dependencies file is placed
+ # in the correct location.
+ if(plugin_install_package_suffix)
+ set_target_properties("${target}" PROPERTIES
+ _qt_plugin_install_package_suffix "${plugin_install_package_suffix}")
+ endif()
+
+ if(TARGET qt_plugins)
+ add_dependencies(qt_plugins "${target}")
+ endif()
+
+ # Record plugin for current repo.
+ if(qt_repo_plugins AND TARGET ${qt_repo_plugins})
+ add_dependencies(${qt_repo_plugins} "${target}")
+ endif()
+
+ if(plugin_type STREQUAL "platforms")
+ if(TARGET qpa_plugins)
+ add_dependencies(qpa_plugins "${target}")
+ endif()
+
+ if(_default_plugin AND TARGET qpa_default_plugins)
+ add_dependencies(qpa_default_plugins "${target}")
+ endif()
+ endif()
+
+ set_property(TARGET "${target}" PROPERTY QT_DEFAULT_PLUGIN "${_default_plugin}")
+ set_property(TARGET "${target}" APPEND PROPERTY EXPORT_PROPERTIES "QT_PLUGIN_CLASS_NAME;QT_PLUGIN_TYPE;QT_MODULE;QT_DEFAULT_PLUGIN")
+
+ set(private_includes
+ "${CMAKE_CURRENT_SOURCE_DIR}"
+ "${CMAKE_CURRENT_BINARY_DIR}"
+ # For the syncqt headers
+ "$<BUILD_INTERFACE:${QT_BUILD_DIR}/include>"
+ ${arg_INCLUDE_DIRECTORIES}
+ )
+
+ set(public_includes
+ ${arg_PUBLIC_INCLUDE_DIRECTORIES}
+ )
+
+ if(arg_NO_UNITY_BUILD)
+ set(arg_NO_UNITY_BUILD "NO_UNITY_BUILD")
+ else()
+ set(arg_NO_UNITY_BUILD "")
+ endif()
+
+ qt_internal_extend_target("${target}"
+ ${arg_NO_UNITY_BUILD}
+ SOURCES ${arg_SOURCES}
+ NO_PCH_SOURCES
+ ${arg_NO_PCH_SOURCES}
+ NO_UNITY_BUILD_SOURCES
+ ${arg_NO_UNITY_BUILD_SOURCES}
+ INCLUDE_DIRECTORIES
+ ${private_includes}
+ SYSTEM_INCLUDE_DIRECTORIES
+ ${arg_SYSTEM_INCLUDE_DIRECTORIES}
+ PUBLIC_INCLUDE_DIRECTORIES
+ ${public_includes}
+ LIBRARIES ${arg_LIBRARIES} Qt::PlatformPluginInternal
+ PUBLIC_LIBRARIES ${arg_PUBLIC_LIBRARIES}
+ DEFINES
+ ${arg_DEFINES}
+ ${deprecation_define}
+ PUBLIC_DEFINES
+ ${arg_PUBLIC_DEFINES}
+ FEATURE_DEPENDENCIES ${arg_FEATURE_DEPENDENCIES}
+ DBUS_ADAPTOR_SOURCES ${arg_DBUS_ADAPTOR_SOURCES}
+ DBUS_ADAPTOR_FLAGS ${arg_DBUS_ADAPTOR_FLAGS}
+ DBUS_INTERFACE_SOURCES ${arg_DBUS_INTERFACE_SOURCES}
+ DBUS_INTERFACE_FLAGS ${arg_DBUS_INTERFACE_FLAGS}
+ COMPILE_OPTIONS ${arg_COMPILE_OPTIONS}
+ PUBLIC_COMPILE_OPTIONS ${arg_PUBLIC_COMPILE_OPTIONS}
+ LINK_OPTIONS ${arg_LINK_OPTIONS}
+ PUBLIC_LINK_OPTIONS ${arg_PUBLIC_LINK_OPTIONS}
+ MOC_OPTIONS ${arg_MOC_OPTIONS}
+ ENABLE_AUTOGEN_TOOLS ${arg_ENABLE_AUTOGEN_TOOLS}
+ DISABLE_AUTOGEN_TOOLS ${arg_DISABLE_AUTOGEN_TOOLS}
+ )
+
+ qt_internal_add_repo_local_defines("${target}")
+
+ qt_internal_set_exceptions_flags("${target}" ${arg_EXCEPTIONS})
+
+
+ set(qt_libs_private "")
+ qt_internal_get_qt_all_known_modules(known_modules)
+ foreach(it ${known_modules})
+ list(FIND arg_LIBRARIES "Qt::${it}Private" pos)
+ if(pos GREATER -1)
+ list(APPEND qt_libs_private "Qt::${it}Private")
+ endif()
+ endforeach()
+
+ qt_register_target_dependencies("${target}" "${arg_PUBLIC_LIBRARIES}" "${qt_libs_private}")
+
+ if(target_type STREQUAL STATIC_LIBRARY)
+ if(qt_module_target)
+ qt_internal_link_internal_platform_for_object_library("${plugin_init_target}")
+ endif()
+ endif()
+
+ if (NOT arg_SKIP_INSTALL)
+ # Handle creation of cmake files for consumers of find_package().
+ # If we are part of a Qt module, the plugin cmake files are installed as part of that
+ # module.
+ # For qml plugins, they are all installed into the QtQml package location for automatic
+ # discovery.
+ if(plugin_install_package_suffix)
+ set(path_suffix "${INSTALL_CMAKE_NAMESPACE}${plugin_install_package_suffix}")
+ else()
+ set(path_suffix "${INSTALL_CMAKE_NAMESPACE}${target}")
+ endif()
+
+ qt_path_join(config_build_dir ${QT_CONFIG_BUILD_DIR} ${path_suffix})
+ qt_path_join(config_install_dir ${QT_CONFIG_INSTALL_DIR} ${path_suffix})
+
+ qt_internal_export_additional_targets_file(
+ TARGETS ${target} ${plugin_init_target}
+ EXPORT_NAME_PREFIX ${INSTALL_CMAKE_NAMESPACE}${target}
+ CONFIG_INSTALL_DIR "${config_install_dir}")
+
+ qt_internal_get_min_new_policy_cmake_version(min_new_policy_version)
+ qt_internal_get_max_new_policy_cmake_version(max_new_policy_version)
+ configure_package_config_file(
+ "${QT_CMAKE_DIR}/QtPluginConfig.cmake.in"
+ "${config_build_dir}/${INSTALL_CMAKE_NAMESPACE}${target}Config.cmake"
+ INSTALL_DESTINATION "${config_install_dir}"
+ )
+ write_basic_package_version_file(
+ "${config_build_dir}/${INSTALL_CMAKE_NAMESPACE}${target}ConfigVersionImpl.cmake"
+ VERSION ${PROJECT_VERSION}
+ COMPATIBILITY AnyNewerVersion
+ )
+ qt_internal_write_qt_package_version_file(
+ "${INSTALL_CMAKE_NAMESPACE}${target}"
+ "${config_build_dir}/${INSTALL_CMAKE_NAMESPACE}${target}ConfigVersion.cmake"
+ )
+
+ qt_install(FILES
+ "${config_build_dir}/${INSTALL_CMAKE_NAMESPACE}${target}Config.cmake"
+ "${config_build_dir}/${INSTALL_CMAKE_NAMESPACE}${target}ConfigVersion.cmake"
+ "${config_build_dir}/${INSTALL_CMAKE_NAMESPACE}${target}ConfigVersionImpl.cmake"
+ DESTINATION "${config_install_dir}"
+ COMPONENT Devel
+ )
+
+ # Make the export name of plugins be consistent with modules, so that
+ # qt_add_resource adds its additional targets to the same export set in a static Qt build.
+ set(export_name "${INSTALL_CMAKE_NAMESPACE}${target}Targets")
+ qt_install(TARGETS
+ "${target}"
+ ${plugin_init_target}
+ EXPORT ${export_name}
+ RUNTIME DESTINATION "${install_directory}"
+ LIBRARY DESTINATION "${install_directory}"
+ OBJECTS DESTINATION "${install_directory}"
+ ARCHIVE DESTINATION "${archive_install_directory}"
+ )
+ qt_install(EXPORT ${export_name}
+ NAMESPACE ${QT_CMAKE_EXPORT_NAMESPACE}::
+ DESTINATION "${config_install_dir}"
+ )
+ if(BUILD_SHARED_LIBS)
+ qt_apply_rpaths(TARGET "${target}" INSTALL_PATH "${install_directory}" RELATIVE_RPATH)
+ qt_internal_apply_staging_prefix_build_rpath_workaround()
+ endif()
+ endif()
+
+ if (NOT arg_ALLOW_UNDEFINED_SYMBOLS)
+ ### fixme: cmake is missing a built-in variable for this. We want to apply it only to
+ # modules and plugins that belong to Qt.
+ qt_internal_add_link_flags_no_undefined("${target}")
+ endif()
+
+ qt_internal_add_linker_version_script(${target})
+ set(finalizer_extra_args "")
+ if(NOT arg_SKIP_INSTALL)
+ list(APPEND finalizer_extra_args INSTALL_PATH "${install_directory}")
+ endif()
+ qt_add_list_file_finalizer(qt_finalize_plugin ${target} ${finalizer_extra_args})
+
+ if(NOT arg_SKIP_INSTALL)
+ qt_enable_separate_debug_info(${target} "${install_directory}")
+ qt_internal_install_pdb_files(${target} "${install_directory}")
+ endif()
+endfunction()
+
+function(qt_finalize_plugin target)
+ cmake_parse_arguments(arg "" "INSTALL_PATH" "" ${ARGN})
+ if(WIN32 AND BUILD_SHARED_LIBS)
+ _qt_internal_generate_win32_rc_file("${target}")
+ endif()
+
+ # Generate .prl and .pri files for static plugins.
+ get_target_property(target_type "${target}" TYPE)
+ if(target_type STREQUAL STATIC_LIBRARY)
+ if(arg_INSTALL_PATH)
+ qt_generate_prl_file(${target} "${arg_INSTALL_PATH}")
+ endif()
+
+ # There's no point in generating pri files for qml plugins.
+ # We didn't do it in Qt5 times.
+ get_target_property(plugin_type "${target}" QT_PLUGIN_TYPE)
+ if(NOT plugin_type STREQUAL "qml_plugin")
+ qt_generate_plugin_pri_file("${target}")
+ endif()
+ endif()
+endfunction()
+
+function(qt_get_sanitized_plugin_type plugin_type out_var)
+ # Used to handle some edge cases such as platforms/darwin
+ string(REGEX REPLACE "[-/]" "_" plugin_type "${plugin_type}")
+ set("${out_var}" "${plugin_type}" PARENT_SCOPE)
+endfunction()
+
+# Utility function to find the module to which a plug-in belongs.
+function(qt_internal_get_module_for_plugin target target_type out_var)
+ qt_internal_get_qt_all_known_modules(known_modules)
+
+ qt_get_sanitized_plugin_type("${target_type}" target_type)
+ foreach(qt_module ${known_modules})
+ get_target_property(module_type "${QT_CMAKE_EXPORT_NAMESPACE}::${qt_module}" TYPE)
+ # Assuming interface libraries can't have plugins. Otherwise we'll need to fix the property
+ # name, because the current one would be invalid for interface libraries.
+ if(module_type STREQUAL "INTERFACE_LIBRARY")
+ continue()
+ endif()
+
+ get_target_property(plugin_types
+ "${QT_CMAKE_EXPORT_NAMESPACE}::${qt_module}"
+ MODULE_PLUGIN_TYPES)
+ if(plugin_types AND target_type IN_LIST plugin_types)
+ set("${out_var}" "${qt_module}" PARENT_SCOPE)
+ return()
+ endif()
+ endforeach()
+ message(FATAL_ERROR "The plug-in '${target}' does not belong to any Qt module.")
+endfunction()
+
+function(qt_internal_add_darwin_permission_plugin permission)
+ string(TOLOWER "${permission}" permission_lower)
+ string(TOUPPER "${permission}" permission_upper)
+ set(permission_source_file "platform/darwin/qdarwinpermissionplugin_${permission_lower}.mm")
+ set(plugin_target "QDarwin${permission}PermissionPlugin")
+ set(plugin_name "qdarwin${permission_lower}permission")
+ qt_internal_add_plugin(${plugin_target}
+ STATIC # Force static, even in shared builds
+ OUTPUT_NAME ${plugin_name}
+ PLUGIN_TYPE permissions
+ DEFAULT_IF FALSE
+ SOURCES
+ ${permission_source_file}
+ DEFINES
+ QT_DARWIN_PERMISSION_PLUGIN=${permission}
+ LIBRARIES
+ Qt::Core
+ Qt::CorePrivate
+ ${FWFoundation}
+ NO_UNITY_BUILD # disable unity build: the same file is built with two different preprocessor defines.
+ )
+
+ # Disable PCH since CMake falls over on single .mm source targets
+ set_target_properties(${plugin_target} PROPERTIES
+ DISABLE_PRECOMPILE_HEADERS ON
+ )
+
+ # Generate plugin JSON file
+ set(content "{ \"Permissions\": [ \"Q${permission}Permission\" ] }")
+ get_target_property(plugin_build_dir "${plugin_target}" BINARY_DIR)
+ set(output_file "${plugin_build_dir}/${plugin_target}.json")
+ qt_configure_file(OUTPUT "${output_file}" CONTENT "${content}")
+
+ # Associate required usage descriptions
+ set(usage_descriptions_property "_qt_info_plist_usage_descriptions")
+ set_target_properties(${plugin_target} PROPERTIES
+ ${usage_descriptions_property} "NS${permission}UsageDescription"
+ )
+ set_property(TARGET ${plugin_target} APPEND PROPERTY
+ EXPORT_PROPERTIES ${usage_descriptions_property}
+ )
+ set(usage_descriptions_genex "$<JOIN:$<TARGET_PROPERTY:${plugin_target},${usage_descriptions_property}>, >")
+ set(extra_plugin_pri_content
+ "QT_PLUGIN.${plugin_name}.usage_descriptions = ${usage_descriptions_genex}"
+ )
+
+ # Support granular check and request implementations
+ set(separate_request_source_file
+ "${plugin_build_dir}/qdarwinpermissionplugin_${permission_lower}_request.mm")
+ set(separate_request_genex
+ "$<BOOL:$<TARGET_PROPERTY:${plugin_target},_qt_darwin_permissison_separate_request>>")
+ file(GENERATE OUTPUT "${separate_request_source_file}" CONTENT
+ "
+ #define BUILDING_PERMISSION_REQUEST 1
+ #include \"${CMAKE_CURRENT_SOURCE_DIR}/${permission_source_file}\"
+ "
+ CONDITION "${separate_request_genex}"
+ )
+ if(CMAKE_VERSION VERSION_LESS "3.18")
+ set_property(SOURCE "${separate_request_source_file}" PROPERTY GENERATED TRUE)
+ set_property(SOURCE "${separate_request_source_file}" PROPERTY SKIP_UNITY_BUILD_INCLUSION TRUE)
+ endif()
+ target_sources(${plugin_target} PRIVATE
+ "$<${separate_request_genex}:${separate_request_source_file}>"
+ )
+
+ set_property(TARGET ${plugin_target} APPEND PROPERTY
+ EXPORT_PROPERTIES _qt_darwin_permissison_separate_request
+ )
+ set(permission_request_symbol "_QDarwin${permission}PermissionRequest")
+ set(permission_request_flag "-Wl,-u,${permission_request_symbol}")
+ set(has_usage_description_property "_qt_has_${plugin_target}_usage_description")
+ set(has_usage_description_genex "$<BOOL:$<TARGET_PROPERTY:${has_usage_description_property}>>")
+ target_link_options(${plugin_target} INTERFACE
+ "$<$<AND:${separate_request_genex},${has_usage_description_genex}>:${permission_request_flag}>")
+ list(APPEND extra_plugin_pri_content
+ "QT_PLUGIN.${plugin_name}.request_flag = $<${separate_request_genex}:${permission_request_flag}>"
+ )
+
+ # Expose properties to qmake
+ set_property(TARGET ${plugin_target} PROPERTY
+ QT_PLUGIN_PRI_EXTRA_CONTENT ${extra_plugin_pri_content}
+ )
+endfunction()
diff --git a/cmake/QtPlugins.cmake.in b/cmake/QtPlugins.cmake.in
index 91884302c6..e668a4cbef 100644
--- a/cmake/QtPlugins.cmake.in
+++ b/cmake/QtPlugins.cmake.in
@@ -1,131 +1,14 @@
-include_guard(DIRECTORY)
+# Copyright (C) 2024 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+include_guard(DIRECTORY)
@QT_MODULE_PLUGIN_INCLUDES@
-if(NOT @BUILD_SHARED_LIBS@)
- set(_module_target "@INSTALL_CMAKE_NAMESPACE@::@QT_MODULE@")
- # Properties can't be set on aliased targets, so make sure to unalias the target. This is needed
- # when Qt examples are built as part of the Qt build itself.
- get_target_property(_aliased_target ${_module_target} ALIASED_TARGET)
- if(_aliased_target)
- set(_module_target ${_aliased_target})
- endif()
- unset(_aliased_target)
-
- set(_default_plugins_are_enabled "$<NOT:$<STREQUAL:$<GENEX_EVAL:$<TARGET_PROPERTY:QT_DEFAULT_PLUGINS>>,0>>")
- # Make sure to boolify the result of the expression, in case if the returned property value
- # is empty.
- set(_default_plugins_are_enabled_wrapped "$<BOOL:${_default_plugins_are_enabled}>")
- set(_manual_plugins_genex "$<GENEX_EVAL:$<TARGET_PROPERTY:QT_PLUGINS>>")
- set(_no_plugins_genex "$<GENEX_EVAL:$<TARGET_PROPERTY:QT_NO_PLUGINS>>")
-
- # In super builds the rules below pollute the dependency rule for the
- # plugin target when it's being build, causing cyclic dependencies.
- # to overcome this, we check if the current target where this rule evaluates
- # has a QT_BUILD_PROJECT_NAME equal to the current PROJECT_NAME.
- # If so we disable the injection of plugin link rules to avoid cyclic
- # dependencies.
- if (@QT_SUPERBUILD@)
- set(_build_allow_plugin_link_rules_genex "$<NOT:$<STREQUAL:$<TARGET_PROPERTY:QT_BUILD_PROJECT_NAME>,@PROJECT_NAME@>>")
- else()
- set(_build_allow_plugin_link_rules_genex 1)
- endif()
-
- # The code in here uses the properties defined in qt_import_plugins (Qt6CoreMacros.cmake)
- foreach(target @qt_plugins@)
- set(_plugin_target "@INSTALL_CMAKE_NAMESPACE@::${target}")
- set(_plugin_target_versionless "Qt::${target}")
- get_target_property(_classname "${_plugin_target}" QT_PLUGIN_CLASS_NAME)
- if(NOT _classname)
- message("Warning: plugin ${_plugin_target} has no class name, skipping.")
- continue()
- endif()
-
- get_target_property(_plugin_type "${_plugin_target}" QT_PLUGIN_TYPE)
- if(NOT _plugin_type)
- message("Warning: plugin ${_plugin_target} has no type ('${_plugin_type}'), skipping.")
- continue()
- endif()
-
- list(APPEND "QT_ALL_PLUGINS_FOUND_BY_FIND_PACKAGE_${_plugin_type}" "${target}")
-
- set(_plugin_is_default "$<TARGET_PROPERTY:${_plugin_target},QT_DEFAULT_PLUGIN>")
-
- # INCLUDE
- set(_plugin_is_whitelisted "$<IN_LIST:${_plugin_target},${_manual_plugins_genex}>")
- set(_plugin_versionless_is_whitelisted
- "$<IN_LIST:${_plugin_target_versionless},${_manual_plugins_genex}>")
-
- # Note: qt_import_plugins sets the QT_PLUGINS_${_plugin_type} to "-"
- # when excluding it with EXCLUDE_BY_TYPE,
- # which ensures that no plug-in will be supported unless explicitly re-added afterwards.
- string(CONCAT _plugin_is_not_blacklisted
- "$<AND:"
- "$<NOT:" # EXCLUDE
- "$<IN_LIST:${_plugin_target},${_no_plugins_genex}>"
- ">,"
- "$<NOT:"
- "$<IN_LIST:${_plugin_target_versionless},${_no_plugins_genex}>"
- ">,"
- # Excludes both plugins targeted by EXCLUDE_BY_TYPE and not included in
- # INCLUDE_BY_TYPE.
- "$<STREQUAL:,$<GENEX_EVAL:$<TARGET_PROPERTY:QT_PLUGINS_${_plugin_type}>>>"
- ">"
- )
-
- # Support INCLUDE_BY_TYPE
- string(CONCAT _plugin_is_in_type_whitelist
- "$<IN_LIST:"
- "${_plugin_target},"
- "$<GENEX_EVAL:"
- "$<TARGET_PROPERTY:QT_PLUGINS_${_plugin_type}>"
- ">"
- ">"
- )
- string(CONCAT _plugin_versionless_is_in_type_whitelist
- "$<IN_LIST:"
- "${_plugin_target_versionless},"
- "$<GENEX_EVAL:"
- "$<TARGET_PROPERTY:QT_PLUGINS_${_plugin_type}>"
- ">"
- ">"
- )
-
- # Complete condition that defines whether a static plugin is linked
- string(CONCAT _plugin_condition
- "$<BOOL:$<AND:"
- "${_build_allow_plugin_link_rules_genex},"
- "$<OR:"
- "${_plugin_is_whitelisted},"
- "${_plugin_versionless_is_whitelisted},"
- "${_plugin_is_in_type_whitelist},"
- "${_plugin_versionless_is_in_type_whitelist},"
- "$<AND:"
- "${_default_plugins_are_enabled_wrapped},"
- "${_plugin_is_default},"
- "${_plugin_is_not_blacklisted}"
- ">"
- ">"
- ">>"
- )
-
- # If this condition is true, we link against the plug-in
- set(_plugin_genex "$<${_plugin_condition}:${_plugin_target}>")
- target_link_libraries(${_module_target} INTERFACE "${_plugin_genex}")
-
- set(_generated_qt_plugin_file_name
- "${CMAKE_CURRENT_BINARY_DIR}/qt_@QT_MODULE@_${target}.cpp")
- set(_generated_qt_plugin_file_name_template "${_generated_qt_plugin_file_name}.in")
- set(_generated_qt_plugin_file_content "#include <QtPlugin>\nQ_IMPORT_PLUGIN(${_classname})")
-
- # Generate a source file to import that plug-in. Has to be done with configure_file,
- # because file(GENERATE) and target_sources has issues with scopes.
- file(WRITE "${_generated_qt_plugin_file_name_template}"
- "${_generated_qt_plugin_file_content}")
- configure_file("${_generated_qt_plugin_file_name_template}"
- "${_generated_qt_plugin_file_name}")
+# Distributions should probably change this default.
+if(NOT DEFINED QT_SKIP_AUTO_PLUGIN_INCLUSION)
+ set(QT_SKIP_AUTO_PLUGIN_INCLUSION OFF)
+endif()
- target_sources(${_module_target} INTERFACE
- "$<${_plugin_condition}:${_generated_qt_plugin_file_name}>")
- endforeach()
+if(NOT QT_NO_CREATE_TARGETS AND NOT QT_SKIP_AUTO_PLUGIN_INCLUSION)
+ __qt_internal_include_plugin_packages(@QT_MODULE@)
endif()
diff --git a/cmake/QtPostProcess.cmake b/cmake/QtPostProcess.cmake
index f31e429233..f69448c14a 100644
--- a/cmake/QtPostProcess.cmake
+++ b/cmake/QtPostProcess.cmake
@@ -1,572 +1,9 @@
-function(qt_internal_write_depends_file module)
- set(outfile "${QT_BUILD_DIR}/${INSTALL_INCLUDEDIR}/${module}/${module}Depends")
- set(contents "/* This file was generated by cmake with the info from ${module} target. */\n")
- string(APPEND contents "#ifdef __cplusplus /* create empty PCH in C mode */\n")
- foreach (m ${ARGN})
- string(APPEND contents "# include <Qt${m}/Qt${m}>\n")
- endforeach()
- string(APPEND contents "#endif\n")
-
- file(GENERATE OUTPUT "${outfile}" CONTENT "${contents}")
-endfunction()
-
-macro(qt_collect_third_party_deps target)
- set(_target_is_static OFF)
- get_target_property(_target_type ${target} TYPE)
- if (${_target_type} STREQUAL "STATIC_LIBRARY")
- set(_target_is_static ON)
- endif()
- unset(_target_type)
- # If we are doing a non-static Qt build, we only want to propagate public dependencies.
- # If we are doing a static Qt build, we need to propagate all dependencies.
- set(depends_var "public_depends")
- if(_target_is_static)
- set(depends_var "depends")
- endif()
- unset(_target_is_static)
-
- foreach(dep ${${depends_var}})
- # Gather third party packages that should be found when using the Qt module.
- # Also handle nolink target dependencies.
- string(REGEX REPLACE "_nolink$" "" base_dep "${dep}")
- if(NOT base_dep STREQUAL dep)
- # Resets target name like Vulkan_nolink to Vulkan, because we need to call
- # find_package(Vulkan).
- set(dep ${base_dep})
- endif()
-
- if(TARGET ${dep})
- list(FIND third_party_deps_seen ${dep} dep_seen)
-
- get_target_property(package_name ${dep} INTERFACE_QT_PACKAGE_NAME)
- if(dep_seen EQUAL -1 AND package_name)
- list(APPEND third_party_deps_seen ${dep})
- get_target_property(package_version ${dep} INTERFACE_QT_PACKAGE_VERSION)
- if(NOT package_version)
- set(package_version "")
- endif()
-
- get_target_property(package_components ${dep} INTERFACE_QT_PACKAGE_COMPONENTS)
- if(NOT package_components)
- set(package_components "")
- endif()
-
- list(APPEND third_party_deps
- "${package_name}\;${package_version}\;${package_components}")
- endif()
- endif()
- endforeach()
-endmacro()
-
-function(qt_internal_create_module_depends_file target)
- get_target_property(target_type "${target}" TYPE)
- if(target_type STREQUAL "INTERFACE_LIBRARY")
- set(arg_HEADER_MODULE ON)
- else()
- set(arg_HEADER_MODULE OFF)
- endif()
-
- set(depends "")
- if(target_type STREQUAL "STATIC_LIBRARY" AND NOT arg_HEADER_MODULE)
- get_target_property(depends "${target}" LINK_LIBRARIES)
- endif()
-
- get_target_property(public_depends "${target}" INTERFACE_LINK_LIBRARIES)
-
- # Used for collecting Qt module dependencies that should be find_package()'d in
- # ModuleDependencies.cmake.
- get_target_property(target_deps "${target}" _qt_target_deps)
- set(target_deps_seen "")
- set(qt_module_dependencies "")
-
- if(NOT arg_HEADER_MODULE)
- get_target_property(extra_depends "${target}" QT_EXTRA_PACKAGE_DEPENDENCIES)
- endif()
- if(NOT extra_depends STREQUAL "${extra_depends}-NOTFOUND")
- list(APPEND target_deps "${extra_depends}")
- endif()
-
- # Used for assembling the content of an include/Module/ModuleDepends.h header.
- set(qtdeps "")
-
- # Used for collecting third party dependencies that should be find_package()'d in
- # ModuleDependencies.cmake.
- set(third_party_deps "")
- set(third_party_deps_seen "")
-
- # Used for collecting Qt tool dependencies that should be find_package()'d in
- # ModuleToolsDependencies.cmake.
- set(tool_deps "")
- set(tool_deps_seen "")
-
- # Used for collecting Qt tool dependencies that should be find_package()'d in
- # ModuleDependencies.cmake.
- set(main_module_tool_deps "")
-
- qt_internal_get_qt_all_known_modules(known_modules)
-
- set(all_depends ${depends} ${public_depends})
- foreach (dep ${all_depends})
- # Normalize module by stripping leading "Qt::" and trailing "Private"
- if (dep MATCHES "Qt::(.*)")
- set(dep "${CMAKE_MATCH_1}")
- if (TARGET Qt::${dep})
- get_target_property(dep_type Qt::${dep} TYPE)
- if (NOT dep_type STREQUAL "INTERFACE_LIBRARY")
- get_target_property(skip_module_depends_include Qt::${dep} QT_MODULE_SKIP_DEPENDS_INCLUDE)
- if (skip_module_depends_include)
- continue()
- endif()
- endif()
- endif()
- endif()
- if (dep MATCHES "(.*)Private")
- set(dep "${CMAKE_MATCH_1}")
- endif()
-
- list(FIND known_modules "${dep}" _pos)
- if (_pos GREATER -1)
- list(APPEND qtdeps "${dep}")
-
- # Make the ModuleTool package depend on dep's ModuleTool package.
- list(FIND tool_deps_seen ${dep} dep_seen)
- if(dep_seen EQUAL -1 AND ${dep} IN_LIST QT_KNOWN_MODULES_WITH_TOOLS)
- list(APPEND tool_deps_seen ${dep})
- list(APPEND tool_deps
- "${INSTALL_CMAKE_NAMESPACE}${dep}Tools\;${PROJECT_VERSION}")
- endif()
- endif()
- endforeach()
-
- qt_collect_third_party_deps(${target})
-
- # Add dependency to the main ModuleTool package to ModuleDependencies file.
- if(${target} IN_LIST QT_KNOWN_MODULES_WITH_TOOLS)
- set(main_module_tool_deps
- "${INSTALL_CMAKE_NAMESPACE}${target}Tools\;${PROJECT_VERSION}")
- endif()
-
- # Dirty deduplication hack because of https://gitlab.kitware.com/cmake/cmake/issues/19200
- foreach(dep ${target_deps})
- if(dep)
- list(FIND target_deps_seen "${dep}" dep_seen)
- if(dep_seen EQUAL -1)
- list(LENGTH dep len)
- if(NOT (len EQUAL 2))
- message(FATAL_ERROR "List '${dep}' should look like QtFoo;version")
- endif()
- list(GET dep 0 dep_name)
- list(GET dep 1 dep_ver)
-
- # Skip over Qt6 dependency, because we will manually handle it in the Dependencies
- # file before everything else, to ensure that find_package(Qt6Core)-style works.
- if(dep_name STREQUAL INSTALL_CMAKE_NAMESPACE)
- continue()
- endif()
-
- list(APPEND target_deps_seen "${dep_name}\;${dep_ver}")
-
- if (dep_name MATCHES "${INSTALL_CMAKE_NAMESPACE}(.*)")
- list(APPEND qt_module_dependencies "${CMAKE_MATCH_1}")
- endif()
- endif()
- endif()
- endforeach()
- set(target_deps "${target_deps_seen}")
-
- if (DEFINED qtdeps)
- list(REMOVE_DUPLICATES qtdeps)
- endif()
-
- get_target_property(hasModuleHeaders "${target}" INTERFACE_MODULE_HAS_HEADERS)
- if (${hasModuleHeaders})
- get_target_property(module_include_name "${target}" INTERFACE_MODULE_INCLUDE_NAME)
- qt_internal_write_depends_file(${module_include_name} ${qtdeps})
- endif()
-
- if(third_party_deps OR main_module_tool_deps OR target_deps)
- set(path_suffix "${INSTALL_CMAKE_NAMESPACE}${target}")
- qt_path_join(config_build_dir ${QT_CONFIG_BUILD_DIR} ${path_suffix})
- qt_path_join(config_install_dir ${QT_CONFIG_INSTALL_DIR} ${path_suffix})
-
- # Configure and install ModuleDependencies file.
- configure_file(
- "${QT_CMAKE_DIR}/QtModuleDependencies.cmake.in"
- "${config_build_dir}/${INSTALL_CMAKE_NAMESPACE}${target}Dependencies.cmake"
- @ONLY
- )
-
- qt_install(FILES
- "${config_build_dir}/${INSTALL_CMAKE_NAMESPACE}${target}Dependencies.cmake"
- DESTINATION "${config_install_dir}"
- COMPONENT Devel
- )
-
- endif()
- if(tool_deps)
- # The value of the property will be used by qt_export_tools.
- set_property(TARGET "${target}" PROPERTY _qt_tools_package_deps "${tool_deps}")
- endif()
-endfunction()
-
-function(qt_internal_create_plugin_depends_file target)
- get_target_property(qt_module "${target}" QT_MODULE)
- get_target_property(depends "${target}" LINK_LIBRARIES)
- get_target_property(public_depends "${target}" INTERFACE_LINK_LIBRARIES)
- get_target_property(target_deps "${target}" _qt_target_deps)
- set(target_deps_seen "")
-
- qt_collect_third_party_deps(${target})
-
- # Dirty hack because https://gitlab.kitware.com/cmake/cmake/issues/19200
- foreach(dep ${target_deps})
- if(dep)
- list(FIND target_deps_seen "${dep}" dep_seen)
- if(dep_seen EQUAL -1)
- list(LENGTH dep len)
- if(NOT (len EQUAL 2))
- message(FATAL_ERROR "List '${dep}' should look like QtFoo;version")
- endif()
- list(GET dep 0 dep_name)
- list(GET dep 1 dep_ver)
-
- list(APPEND target_deps_seen "${dep_name}\;${dep_ver}")
- endif()
- endif()
- endforeach()
- set(target_deps "${target_deps_seen}")
-
- if(third_party_deps OR target_deps)
- # Setup build and install paths
- if(qt_module)
- set(path_suffix "${INSTALL_CMAKE_NAMESPACE}${qt_module}")
- else()
- set(path_suffix "${INSTALL_CMAKE_NAMESPACE}${target}")
- endif()
-
- qt_path_join(config_build_dir ${QT_CONFIG_BUILD_DIR} ${path_suffix})
- qt_path_join(config_install_dir ${QT_CONFIG_INSTALL_DIR} ${path_suffix})
-
- # Configure and install ModuleDependencies file.
- configure_file(
- "${QT_CMAKE_DIR}/QtPluginDependencies.cmake.in"
- "${config_build_dir}/${target}Dependencies.cmake"
- @ONLY
- )
-
- qt_install(FILES
- "${config_build_dir}/${target}Dependencies.cmake"
- DESTINATION "${config_install_dir}"
- COMPONENT Devel
- )
- endif()
-endfunction()
-
-# Create Depends.cmake & Depends.h files for all modules and plug-ins.
-function(qt_internal_create_depends_files)
- qt_internal_get_qt_repo_known_modules(repo_known_modules)
-
- foreach (target ${repo_known_modules})
- qt_internal_create_module_depends_file(${target})
- endforeach()
-
- foreach (target ${QT_KNOWN_PLUGINS})
- qt_internal_create_plugin_depends_file(${target})
- endforeach()
-endfunction()
-
-# This function creates the Qt<Module>Plugins.cmake used to list all
-# the plug-in target files.
-function(qt_internal_create_plugins_files)
- # The plugins cmake configuration is only needed for static builds. Dynamic builds don't need
- # the application to link against plugins at build time.
- if(QT_BUILD_SHARED_LIBS)
- return()
- endif()
- qt_internal_get_qt_repo_known_modules(repo_known_modules)
-
- message("Generating Plugins files for ${repo_known_modules}...")
- foreach (QT_MODULE ${repo_known_modules})
- get_target_property(target_type "${QT_MODULE}" TYPE)
- if(target_type STREQUAL "INTERFACE_LIBRARY")
- # No plugins are provided by a header only module.
- continue()
- endif()
- qt_path_join(config_build_dir ${QT_CONFIG_BUILD_DIR} ${INSTALL_CMAKE_NAMESPACE}${QT_MODULE})
- qt_path_join(config_install_dir ${QT_CONFIG_INSTALL_DIR} ${INSTALL_CMAKE_NAMESPACE}${QT_MODULE})
- set(QT_MODULE_PLUGIN_INCLUDES "")
-
- get_target_property(qt_plugins "${QT_MODULE}" QT_PLUGINS)
- if(qt_plugins)
- foreach (pluginTarget ${qt_plugins})
- set(QT_MODULE_PLUGIN_INCLUDES "${QT_MODULE_PLUGIN_INCLUDES}include(\"\${CMAKE_CURRENT_LIST_DIR}/${pluginTarget}Config.cmake\")\n")
- endforeach()
- configure_file(
- "${QT_CMAKE_DIR}/QtPlugins.cmake.in"
- "${config_build_dir}/${INSTALL_CMAKE_NAMESPACE}${QT_MODULE}Plugins.cmake"
- @ONLY
- )
- qt_install(FILES
- "${config_build_dir}/${INSTALL_CMAKE_NAMESPACE}${QT_MODULE}Plugins.cmake"
- DESTINATION "${config_install_dir}"
- COMPONENT Devel
- )
- endif()
- endforeach()
-endfunction()
-
-function(qt_generate_install_prefixes out_var)
- set(content "\n")
- set(vars INSTALL_BINDIR INSTALL_INCLUDEDIR INSTALL_LIBDIR INSTALL_MKSPECSDIR INSTALL_ARCHDATADIR
- INSTALL_PLUGINSDIR INSTALL_LIBEXECDIR INSTALL_QMLDIR INSTALL_DATADIR INSTALL_DOCDIR
- INSTALL_TRANSLATIONSDIR INSTALL_SYSCONFDIR INSTALL_EXAMPLESDIR INSTALL_TESTSDIR
- INSTALL_DESCRIPTIONSDIR)
-
- foreach(var ${vars})
- get_property(docstring CACHE "${var}" PROPERTY HELPSTRING)
- string(APPEND content "set(${var} \"${${var}}\" CACHE STRING \"${docstring}\" FORCE)\n")
- endforeach()
-
- set(${out_var} "${content}" PARENT_SCOPE)
-endfunction()
-
-function(qt_wrap_string_in_if_multi_config content out_var)
- set(${out_var} "
-get_property(__qt_is_multi_config GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
-if(__qt_is_multi_config)
-${content}endif()
-unset(__qt_is_multi_config)\n" PARENT_SCOPE)
-endfunction()
-
-function(qt_wrap_string_in_if_ninja_multi_config content out_var)
- set(${out_var} "if(CMAKE_GENERATOR STREQUAL \"Ninja Multi-Config\")
-${content}endif()\n" PARENT_SCOPE)
-endfunction()
-
-function(qt_create_hostinfo_package)
- set(package "${INSTALL_CMAKE_NAMESPACE}HostInfo")
- qt_path_join(config_file_path "${QT_CONFIG_BUILD_DIR}/${package}/${package}Config.cmake")
- qt_path_join(install_destination ${QT_CONFIG_INSTALL_DIR} ${package})
- set(var_prefix "QT${PROJECT_VERSION_MAJOR}_HOST_INFO_")
- configure_package_config_file(
- "${CMAKE_CURRENT_LIST_DIR}/QtHostInfoConfig.cmake.in"
- "${config_file_path}"
- INSTALL_DESTINATION "${install_destination}"
- NO_SET_AND_CHECK_MACRO
- NO_CHECK_REQUIRED_COMPONENTS_MACRO)
- qt_install(FILES "${config_file_path}" DESTINATION "${install_destination}")
-endfunction()
-
-function(qt_generate_build_internals_extra_cmake_code)
- if(PROJECT_NAME STREQUAL "QtBase")
- qt_create_hostinfo_package()
-
- foreach(var IN LISTS QT_BASE_CONFIGURE_TESTS_VARS_TO_EXPORT)
- string(APPEND QT_EXTRA_BUILD_INTERNALS_VARS "set(${var} \"${${var}}\" CACHE INTERNAL \"\")\n")
- endforeach()
-
- set(QT_SOURCE_TREE "${QtBase_SOURCE_DIR}")
- qt_path_join(extra_file_path
- ${QT_CONFIG_BUILD_DIR}
- ${INSTALL_CMAKE_NAMESPACE}BuildInternals/QtBuildInternalsExtra.cmake)
-
- if(CMAKE_BUILD_TYPE)
- # Need to force set, because CMake itself initializes a value for CMAKE_BUILD_TYPE
- # at the start of project configuration (with an empty value),
- # so we need to force override it.
- string(APPEND QT_EXTRA_BUILD_INTERNALS_VARS
- "set(CMAKE_BUILD_TYPE \"${CMAKE_BUILD_TYPE}\" CACHE STRING \"Choose the type of build.\" FORCE)\n")
-
- endif()
- if(CMAKE_CONFIGURATION_TYPES)
- string(APPEND multi_config_specific
- " set(CMAKE_CONFIGURATION_TYPES \"${CMAKE_CONFIGURATION_TYPES}\" CACHE STRING \"\" FORCE)\n")
- endif()
- if(CMAKE_TRY_COMPILE_CONFIGURATION)
- string(APPEND multi_config_specific
- " set(CMAKE_TRY_COMPILE_CONFIGURATION \"${CMAKE_TRY_COMPILE_CONFIGURATION}\")\n")
- endif()
- if(multi_config_specific)
- qt_wrap_string_in_if_multi_config(
- "${multi_config_specific}"
- multi_config_specific)
- string(APPEND QT_EXTRA_BUILD_INTERNALS_VARS "${multi_config_specific}")
- endif()
-
- if(QT_MULTI_CONFIG_FIRST_CONFIG)
- string(APPEND QT_EXTRA_BUILD_INTERNALS_VARS
- "\nset(QT_MULTI_CONFIG_FIRST_CONFIG \"${QT_MULTI_CONFIG_FIRST_CONFIG}\")\n")
- endif()
- # When building standalone tests against a multi-config Qt, we want to choose the first
- # configuration, rather than default to Debug.
- if(multi_config_specific)
- string(APPEND QT_EXTRA_BUILD_INTERNALS_VARS "
-if(QT_BUILD_STANDALONE_TESTS)
- set(CMAKE_BUILD_TYPE \"\${QT_MULTI_CONFIG_FIRST_CONFIG}\" CACHE STRING \"Choose the type of build.\" FORCE)
-endif()\n")
- endif()
-
- if(CMAKE_CROSS_CONFIGS)
- string(APPEND ninja_multi_config_specific
- " set(CMAKE_CROSS_CONFIGS \"${CMAKE_CROSS_CONFIGS}\" CACHE STRING \"\")\n")
- endif()
- if(CMAKE_DEFAULT_BUILD_TYPE)
- string(APPEND ninja_multi_config_specific
- " set(CMAKE_DEFAULT_BUILD_TYPE \"${CMAKE_DEFAULT_BUILD_TYPE}\" CACHE STRING \"\")\n")
- endif()
- if(CMAKE_DEFAULT_CONFIGS)
- string(APPEND ninja_multi_config_specific
- " set(CMAKE_DEFAULT_CONFIGS \"${CMAKE_DEFAULT_CONFIGS}\" CACHE STRING \"\")\n")
- endif()
- if(ninja_multi_config_specific)
- qt_wrap_string_in_if_ninja_multi_config(
- "${ninja_multi_config_specific}"
- ninja_multi_config_specific)
- string(APPEND QT_EXTRA_BUILD_INTERNALS_VARS "${ninja_multi_config_specific}")
- endif()
-
- if(DEFINED BUILD_WITH_PCH)
- string(APPEND QT_EXTRA_BUILD_INTERNALS_VARS
- "set(BUILD_WITH_PCH \"${BUILD_WITH_PCH}\" CACHE STRING \"\")\n")
- endif()
-
- if(CMAKE_CROSSCOMPILING AND QT_BUILD_TOOLS_WHEN_CROSSCOMPILING)
- string(APPEND QT_EXTRA_BUILD_INTERNALS_VARS
- "set(QT_BUILD_TOOLS_WHEN_CROSSCOMPILING \"TRUE\" CACHE BOOL \"\" FORCE)\n")
- endif()
-
- if(ECM_ENABLE_SANITIZERS)
- string(APPEND QT_EXTRA_BUILD_INTERNALS_VARS
- "set(ECM_ENABLE_SANITIZERS \"${ECM_ENABLE_SANITIZERS}\" CACHE BOOL \"\" FORCE)\n")
- endif()
-
- # Rpath related things that need to be re-used when building other repos.
- string(APPEND QT_EXTRA_BUILD_INTERNALS_VARS
- "set(CMAKE_INSTALL_RPATH \"${CMAKE_INSTALL_RPATH}\" CACHE STRING \"\")\n")
- if(DEFINED QT_DISABLE_RPATH)
- string(APPEND QT_EXTRA_BUILD_INTERNALS_VARS
- "set(QT_DISABLE_RPATH \"${QT_DISABLE_RPATH}\" CACHE STRING \"\")\n")
- endif()
- if(DEFINED QT_EXTRA_RPATHS)
- string(APPEND QT_EXTRA_BUILD_INTERNALS_VARS
- "set(QT_EXTRA_RPATHS \"${QT_EXTRA_RPATHS}\" CACHE STRING \"\")\n")
- endif()
-
- # Save pkg-config feature value to be able to query it internally as soon as BuildInternals
- # package is loaded. This is to avoid any pkg-config package from being found when
- # find_package(Qt6Core) is called in case if the feature was disabled.
- string(APPEND QT_EXTRA_BUILD_INTERNALS_VARS "
-if(NOT QT_SKIP_BUILD_INTERNALS_PKG_CONFIG_FEATURE)
- set(FEATURE_pkg_config \"${FEATURE_pkg_config}\" CACHE STRING \"Using pkg-config\" FORCE)
-endif()\n")
-
- # The OpenSSL root dir needs to be saved so that repos other than qtbase (like qtopcua) can
- # still successfully find_package(WrapOpenSSL) in the CI.
- # qmake saves any additional include paths passed via the configure like '-I/foo'
- # in mkspecs/qmodule.pri, so this file is the closest equivalent.
- if(DEFINED OPENSSL_ROOT_DIR)
- file(TO_CMAKE_PATH "${OPENSSL_ROOT_DIR}" openssl_root_cmake_path)
- string(APPEND QT_EXTRA_BUILD_INTERNALS_VARS
- "set(OPENSSL_ROOT_DIR \"${openssl_root_cmake_path}\" CACHE STRING \"\")\n")
- endif()
-
- if(NOT "${CMAKE_STAGING_PREFIX}" STREQUAL "")
- string(APPEND QT_EXTRA_BUILD_INTERNALS_VARS
- "
-# If no explicit CMAKE_STAGING_PREFIX is provided, force set the original Qt staging prefix,
-if(\"$\{CMAKE_STAGING_PREFIX}\" STREQUAL \"\"
- AND NOT QT_BUILD_INTERNALS_NO_FORCE_SET_STAGING_PREFIX)
- set(CMAKE_STAGING_PREFIX \"${CMAKE_STAGING_PREFIX}\" CACHE PATH
- \"Staging path prefix, prepended onto install directories on the host machine.\" FORCE)
-endif()
-")
- endif()
-
- qt_generate_install_prefixes(install_prefix_content)
-
- string(APPEND QT_EXTRA_BUILD_INTERNALS_VARS "${install_prefix_content}")
-
- qt_compute_relative_path_from_cmake_config_dir_to_prefix()
- configure_file(
- "${CMAKE_CURRENT_LIST_DIR}/QtBuildInternalsExtra.cmake.in"
- "${extra_file_path}"
- @ONLY
- )
- endif()
-endfunction()
-
-# For every Qt module check if there any android dependencies that require
-# processing.
-function(qt_modules_process_android_dependencies)
- qt_internal_get_qt_repo_known_modules(repo_known_modules)
- foreach (target ${repo_known_modules})
- qt_android_dependencies(${target})
- endforeach()
-endfunction()
-
-function(qt_create_tools_config_files)
- # Create packages like Qt6CoreTools/Qt6CoreToolsConfig.cmake.
- foreach(module_name ${QT_KNOWN_MODULES_WITH_TOOLS})
- qt_export_tools("${module_name}")
- endforeach()
-endfunction()
-
-function(qt_internal_create_config_file_for_standalone_tests)
- set(standalone_tests_config_dir "StandaloneTests")
- qt_path_join(config_build_dir
- ${QT_CONFIG_BUILD_DIR}
- "${INSTALL_CMAKE_NAMESPACE}BuildInternals" "${standalone_tests_config_dir}")
- qt_path_join(config_install_dir
- ${QT_CONFIG_INSTALL_DIR}
- "${INSTALL_CMAKE_NAMESPACE}BuildInternals" "${standalone_tests_config_dir}")
-
- # Filter out bundled system libraries. Otherwise when looking for their dependencies
- # (like PNG for Freetype) FindWrapPNG is searched for during configuration of
- # standalone tests, and it can happen that Core or Gui features are not
- # imported early enough, which means FindWrapPNG will try to find a system PNG library instead
- # of the bundled one.
- set(modules)
- foreach(m ${QT_REPO_KNOWN_MODULES})
- get_target_property(target_type "${m}" TYPE)
-
- # Interface libraries are never bundled system libraries (hopefully).
- if(target_type STREQUAL "INTERFACE_LIBRARY")
- list(APPEND modules "${m}")
- continue()
- endif()
-
- get_target_property(is_3rd_party "${m}" QT_MODULE_IS_3RDPARTY_LIBRARY)
- if(NOT is_3rd_party)
- list(APPEND modules "${m}")
- endif()
- endforeach()
-
- list(JOIN modules " " QT_REPO_KNOWN_MODULES_STRING)
- string(STRIP "${QT_REPO_KNOWN_MODULES_STRING}" QT_REPO_KNOWN_MODULES_STRING)
-
- # Skip generating and installing file if no modules were built. This make sure not to install
- # anything when build qtx11extras on macOS for example.
- if(NOT QT_REPO_KNOWN_MODULES_STRING)
- return()
- endif()
-
- # Ceate a Config file that calls find_package on the modules that were built as part
- # of the current repo. This is used for standalone tests.
- configure_file(
- "${QT_CMAKE_DIR}/QtStandaloneTestsConfig.cmake.in"
- "${config_build_dir}/${PROJECT_NAME}TestsConfig.cmake"
- @ONLY
- )
- qt_install(FILES
- "${config_build_dir}/${PROJECT_NAME}TestsConfig.cmake"
- DESTINATION "${config_install_dir}"
- COMPONENT Devel
- )
-endfunction()
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
qt_internal_create_depends_files()
qt_generate_build_internals_extra_cmake_code()
-qt_internal_create_plugins_files()
+qt_internal_create_plugins_auto_inclusion_files()
qt_internal_create_config_file_for_standalone_tests()
# Needs to run after qt_internal_create_depends_files.
@@ -576,11 +13,5 @@ if (ANDROID)
qt_modules_process_android_dependencies()
endif()
-# Install prl files
-get_property(prl_install_dirs GLOBAL PROPERTY QT_PRL_INSTALL_DIRS)
-foreach(prl_install_dir ${prl_install_dirs})
- qt_install(DIRECTORY "${PROJECT_BINARY_DIR}/${prl_install_dir}/"
- DESTINATION ${prl_install_dir}
- FILES_MATCHING PATTERN "*.prl"
- )
-endforeach()
+qt_internal_install_prl_files()
+qt_internal_generate_user_facing_tools_info()
diff --git a/cmake/QtPostProcessHelpers.cmake b/cmake/QtPostProcessHelpers.cmake
new file mode 100644
index 0000000000..0a207f6634
--- /dev/null
+++ b/cmake/QtPostProcessHelpers.cmake
@@ -0,0 +1,881 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+function(qt_internal_write_depends_file target)
+ get_target_property(module_depends_header ${target} _qt_module_depends_header)
+ set(outfile "${module_depends_header}")
+ set(contents "/* This file was generated by cmake with the info from ${target} target. */\n")
+ string(APPEND contents "#ifdef __cplusplus /* create empty PCH in C mode */\n")
+ foreach (m ${ARGN})
+ string(APPEND contents "# include <${m}/${m}>\n")
+ endforeach()
+ string(APPEND contents "#endif\n")
+
+ file(GENERATE OUTPUT "${outfile}" CONTENT "${contents}")
+endfunction()
+
+macro(qt_collect_third_party_deps target)
+ set(_target_is_static OFF)
+ get_target_property(_target_type ${target} TYPE)
+ if (${_target_type} STREQUAL "STATIC_LIBRARY")
+ set(_target_is_static ON)
+ endif()
+ unset(_target_type)
+ # If we are doing a non-static Qt build, we only want to propagate public dependencies.
+ # If we are doing a static Qt build, we need to propagate all dependencies.
+ set(depends_var "public_depends")
+ if(_target_is_static)
+ set(depends_var "depends")
+ endif()
+ unset(_target_is_static)
+
+ foreach(dep ${${depends_var}} ${optional_public_depends} ${extra_third_party_deps})
+ # Gather third party packages that should be found when using the Qt module.
+ # Also handle nolink target dependencies.
+ string(REGEX REPLACE "_nolink$" "" base_dep "${dep}")
+ if(NOT base_dep STREQUAL dep)
+ # Resets target name like Vulkan_nolink to Vulkan, because we need to call
+ # find_package(Vulkan).
+ set(dep ${base_dep})
+ endif()
+
+ # Strip any directory scope tokens.
+ __qt_internal_strip_target_directory_scope_token("${dep}" dep)
+ if(TARGET ${dep})
+ list(FIND third_party_deps_seen ${dep} dep_seen)
+
+ get_target_property(package_name ${dep} INTERFACE_QT_PACKAGE_NAME)
+ if(dep_seen EQUAL -1 AND package_name)
+ list(APPEND third_party_deps_seen ${dep})
+ get_target_property(package_is_optional ${dep} INTERFACE_QT_PACKAGE_IS_OPTIONAL)
+ if(NOT package_is_optional AND dep IN_LIST optional_public_depends)
+ set(package_is_optional TRUE)
+ endif()
+ get_target_property(package_version ${dep} INTERFACE_QT_PACKAGE_VERSION)
+ if(NOT package_version)
+ set(package_version "")
+ endif()
+
+ get_target_property(package_components ${dep} INTERFACE_QT_PACKAGE_COMPONENTS)
+ if(NOT package_components)
+ set(package_components "")
+ endif()
+
+ get_target_property(package_optional_components ${dep}
+ INTERFACE_QT_PACKAGE_OPTIONAL_COMPONENTS)
+ if(NOT package_optional_components)
+ set(package_optional_components "")
+ endif()
+
+ list(APPEND third_party_deps
+ "${package_name}\;${package_is_optional}\;${package_version}\;${package_components}\;${package_optional_components}")
+ endif()
+ endif()
+ endforeach()
+endmacro()
+
+# Filter the dependency targets to collect unique set of the dependencies.
+# non-Private and Private targets are treated as the single object in this context
+# since they are defined by the same CMake package. For internal modules
+# the CMake package will be always Private.
+function(qt_internal_remove_qt_dependency_duplicates out_deps deps)
+ set(${out_deps} "")
+ foreach(dep ${deps})
+ if(dep)
+ list(FIND ${out_deps} "${dep}" dep_seen)
+
+ if(dep_seen EQUAL -1)
+ list(LENGTH dep len)
+ if(NOT (len EQUAL 2))
+ message(FATAL_ERROR "List '${dep}' should look like QtFoo;version")
+ endif()
+ list(GET dep 0 dep_name)
+ list(GET dep 1 dep_ver)
+
+ # Skip over Qt6 dependency, because we will manually handle it in the Dependencies
+ # file before everything else, to ensure that find_package(Qt6Core)-style works.
+ if(dep_name STREQUAL "${INSTALL_CMAKE_NAMESPACE}")
+ continue()
+ endif()
+ list(APPEND ${out_deps} "${dep_name}\;${dep_ver}")
+ endif()
+ endif()
+ endforeach()
+ set(${out_deps} "${${out_deps}}" PARENT_SCOPE)
+endfunction()
+
+function(qt_internal_create_module_depends_file target)
+ get_target_property(target_type "${target}" TYPE)
+ set(is_interface_lib FALSE)
+ if(target_type STREQUAL "INTERFACE_LIBRARY")
+ set(is_interface_lib TRUE)
+ endif()
+
+ set(depends "")
+ if(target_type STREQUAL "STATIC_LIBRARY")
+ get_target_property(depends "${target}" LINK_LIBRARIES)
+ endif()
+
+ get_target_property(public_depends "${target}" INTERFACE_LINK_LIBRARIES)
+
+ unset(optional_public_depends)
+ if(TARGET "${target}Private")
+ get_target_property(optional_public_depends "${target}Private" INTERFACE_LINK_LIBRARIES)
+ endif()
+
+ # Used for collecting Qt module dependencies that should be find_package()'d in
+ # ModuleDependencies.cmake.
+ get_target_property(target_deps "${target}" _qt_target_deps)
+ set(target_deps_seen "")
+ set(qt_module_dependencies "")
+
+ if(NOT is_interface_lib)
+ get_target_property(extra_depends "${target}" QT_EXTRA_PACKAGE_DEPENDENCIES)
+ endif()
+ if(NOT extra_depends MATCHES "-NOTFOUND$")
+ list(APPEND target_deps "${extra_depends}")
+ endif()
+
+ # Extra 3rd party targets who's packages should be considered dependencies.
+ get_target_property(extra_third_party_deps "${target}" _qt_extra_third_party_dep_targets)
+ if(NOT extra_third_party_deps)
+ set(extra_third_party_deps "")
+ endif()
+
+ # Used for assembling the content of an include/Module/ModuleDepends.h header.
+ set(qtdeps "")
+
+ # Used for collecting third party dependencies that should be find_package()'d in
+ # ModuleDependencies.cmake.
+ set(third_party_deps "")
+ set(third_party_deps_seen "")
+
+ # Used for collecting Qt tool dependencies that should be find_package()'d in
+ # ModuleToolsDependencies.cmake.
+ set(tool_deps "")
+ set(tool_deps_seen "")
+
+ # Used for collecting Qt tool dependencies that should be find_package()'d in
+ # ModuleDependencies.cmake.
+ set(main_module_tool_deps "")
+
+ # Extra QtFooModuleTools packages to be added as dependencies to
+ # QtModuleDependencies.cmake. Needed for QtWaylandCompositor / QtWaylandClient.
+ if(NOT is_interface_lib)
+ get_target_property(extra_tools_package_dependencies "${target}"
+ QT_EXTRA_TOOLS_PACKAGE_DEPENDENCIES)
+ if(extra_tools_package_dependencies)
+ list(APPEND main_module_tool_deps "${extra_tools_package_dependencies}")
+ endif()
+ endif()
+
+ qt_internal_get_qt_all_known_modules(known_modules)
+
+ set(all_depends ${depends} ${public_depends})
+ foreach (dep ${all_depends})
+ # Normalize module by stripping leading "Qt::" and trailing "Private"
+ if (dep MATCHES "(Qt|${QT_CMAKE_EXPORT_NAMESPACE})::([-_A-Za-z0-9]+)")
+ set(dep "${CMAKE_MATCH_2}")
+ set(real_dep_target "Qt::${dep}")
+
+ if(TARGET "${real_dep_target}")
+ get_target_property(is_versionless_target "${real_dep_target}"
+ _qt_is_versionless_target)
+ if(is_versionless_target)
+ set(real_dep_target "${QT_CMAKE_EXPORT_NAMESPACE}::${dep}")
+ endif()
+
+ get_target_property(skip_module_depends_include "${real_dep_target}"
+ _qt_module_skip_depends_include)
+ if(skip_module_depends_include)
+ continue()
+ endif()
+
+ get_target_property(module_has_headers "${real_dep_target}"
+ _qt_module_has_headers)
+ if(NOT module_has_headers)
+ continue()
+ endif()
+ endif()
+ endif()
+
+ list(FIND known_modules "${dep}" _pos)
+ if (_pos GREATER -1)
+ qt_internal_module_info(module ${QT_CMAKE_EXPORT_NAMESPACE}::${dep})
+ list(APPEND qtdeps ${module})
+
+ # Make the ModuleTool package depend on dep's ModuleTool package.
+ list(FIND tool_deps_seen ${dep} dep_seen)
+ if(dep_seen EQUAL -1 AND ${dep} IN_LIST QT_KNOWN_MODULES_WITH_TOOLS)
+ qt_internal_get_package_version_of_target("${dep}" dep_package_version)
+ list(APPEND tool_deps_seen ${dep})
+ list(APPEND tool_deps
+ "${INSTALL_CMAKE_NAMESPACE}${dep}Tools\;${dep_package_version}")
+ endif()
+ endif()
+ endforeach()
+
+ qt_collect_third_party_deps(${target})
+
+ # Add dependency to the main ModuleTool package to ModuleDependencies file.
+ if(${target} IN_LIST QT_KNOWN_MODULES_WITH_TOOLS)
+ qt_internal_get_package_version_of_target("${target}" main_module_tool_package_version)
+ list(APPEND main_module_tool_deps
+ "${INSTALL_CMAKE_NAMESPACE}${target}Tools\;${main_module_tool_package_version}")
+ endif()
+
+ foreach(dep ${target_deps})
+ if(NOT dep MATCHES ".+Private$" AND
+ dep MATCHES "${INSTALL_CMAKE_NAMESPACE}(.+)")
+ # target_deps contains elements that are a pair of target name and version,
+ # e.g. 'Core\;6.2'
+ # After the extracting from the target_deps list, the element becomes a list itself,
+ # because it loses escape symbol before the semicolon, so ${CMAKE_MATCH_1} is the list:
+ # Core;6.2.
+ # We need to store only the target name in the qt_module_dependencies variable.
+ list(GET CMAKE_MATCH_1 0 dep_name)
+ if(dep_name)
+ list(APPEND qt_module_dependencies "${dep_name}")
+ endif()
+ endif()
+ endforeach()
+ list(REMOVE_DUPLICATES qt_module_dependencies)
+
+ qt_internal_remove_qt_dependency_duplicates(target_deps "${target_deps}")
+
+
+ if (DEFINED qtdeps)
+ list(REMOVE_DUPLICATES qtdeps)
+ endif()
+
+ get_target_property(hasModuleHeaders "${target}" _qt_module_has_headers)
+ if (${hasModuleHeaders})
+ qt_internal_write_depends_file(${target} ${qtdeps})
+ endif()
+
+ if(third_party_deps OR main_module_tool_deps OR target_deps)
+ set(path_suffix "${INSTALL_CMAKE_NAMESPACE}${target}")
+ qt_path_join(config_build_dir ${QT_CONFIG_BUILD_DIR} ${path_suffix})
+ qt_path_join(config_install_dir ${QT_CONFIG_INSTALL_DIR} ${path_suffix})
+
+ # All module packages should look for the Qt6 package version that qtbase was originally
+ # built as.
+ qt_internal_get_package_version_of_target(Platform main_qt_package_version)
+
+ # Configure and install ModuleDependencies file.
+ configure_file(
+ "${QT_CMAKE_DIR}/QtModuleDependencies.cmake.in"
+ "${config_build_dir}/${INSTALL_CMAKE_NAMESPACE}${target}Dependencies.cmake"
+ @ONLY
+ )
+
+ qt_install(FILES
+ "${config_build_dir}/${INSTALL_CMAKE_NAMESPACE}${target}Dependencies.cmake"
+ DESTINATION "${config_install_dir}"
+ COMPONENT Devel
+ )
+
+ message(TRACE "Recorded dependencies for module: ${target}\n"
+ " Qt dependencies: ${target_deps}\n"
+ " 3rd-party dependencies: ${third_party_deps}")
+ endif()
+ if(tool_deps)
+ # The value of the property will be used by qt_export_tools.
+ set_property(TARGET "${target}" PROPERTY _qt_tools_package_deps "${tool_deps}")
+ endif()
+endfunction()
+
+function(qt_internal_create_plugin_depends_file target)
+ get_target_property(plugin_install_package_suffix "${target}" _qt_plugin_install_package_suffix)
+ get_target_property(depends "${target}" LINK_LIBRARIES)
+ get_target_property(public_depends "${target}" INTERFACE_LINK_LIBRARIES)
+ get_target_property(target_deps "${target}" _qt_target_deps)
+ unset(optional_public_depends)
+ set(target_deps_seen "")
+
+
+ # Extra 3rd party targets who's packages should be considered dependencies.
+ get_target_property(extra_third_party_deps "${target}" _qt_extra_third_party_dep_targets)
+ if(NOT extra_third_party_deps)
+ set(extra_third_party_deps "")
+ endif()
+
+ qt_collect_third_party_deps(${target})
+
+ qt_internal_remove_qt_dependency_duplicates(target_deps "${target_deps}")
+
+ if(third_party_deps OR target_deps)
+ # Setup build and install paths
+
+ # Plugins should look for their dependencies in their associated module package folder as
+ # well as the Qt6 package folder which is stored by the Qt6 package in _qt_cmake_dir.
+ set(find_dependency_paths "\${CMAKE_CURRENT_LIST_DIR}/..;\${_qt_cmake_dir}")
+ if(plugin_install_package_suffix)
+ set(path_suffix "${INSTALL_CMAKE_NAMESPACE}${plugin_install_package_suffix}")
+ if(plugin_install_package_suffix MATCHES "/QmlPlugins")
+ # Qml plugins are one folder deeper.
+ set(find_dependency_paths "\${CMAKE_CURRENT_LIST_DIR}/../..;\${_qt_cmake_dir}")
+ endif()
+
+ else()
+ set(path_suffix "${INSTALL_CMAKE_NAMESPACE}${target}")
+ endif()
+
+ qt_path_join(config_build_dir ${QT_CONFIG_BUILD_DIR} ${path_suffix})
+ qt_path_join(config_install_dir ${QT_CONFIG_INSTALL_DIR} ${path_suffix})
+
+ # Configure and install ModuleDependencies file.
+ configure_file(
+ "${QT_CMAKE_DIR}/QtPluginDependencies.cmake.in"
+ "${config_build_dir}/${INSTALL_CMAKE_NAMESPACE}${target}Dependencies.cmake"
+ @ONLY
+ )
+
+ qt_install(FILES
+ "${config_build_dir}/${INSTALL_CMAKE_NAMESPACE}${target}Dependencies.cmake"
+ DESTINATION "${config_install_dir}"
+ COMPONENT Devel
+ )
+
+ message(TRACE "Recorded dependencies for plugin: ${target}\n"
+ " Qt dependencies: ${target_deps}\n"
+ " 3rd-party dependencies: ${third_party_deps}")
+ endif()
+endfunction()
+
+function(qt_internal_create_qt6_dependencies_file)
+ # This is used for substitution in the configured file.
+ set(target "${INSTALL_CMAKE_NAMESPACE}")
+
+ # This is the actual target we're querying.
+ set(actual_target Platform)
+ get_target_property(public_depends "${actual_target}" INTERFACE_LINK_LIBRARIES)
+ unset(depends)
+ unset(optional_public_depends)
+
+ # We need to collect third party deps that are set on the public Platform target,
+ # like Threads::Threads.
+ # This mimics find_package part of the CONFIG += thread assignment in mkspecs/features/qt.prf.
+ qt_collect_third_party_deps(${actual_target})
+
+ # For Threads we also need to write an extra variable assignment.
+ set(third_party_extra "")
+ if(third_party_deps MATCHES "Threads")
+ string(APPEND third_party_extra "if(NOT QT_NO_THREADS_PREFER_PTHREAD_FLAG)
+ set(THREADS_PREFER_PTHREAD_FLAG TRUE)
+endif()")
+ endif()
+
+ _qt_internal_determine_if_host_info_package_needed(platform_requires_host_info_package)
+
+ if(platform_requires_host_info_package)
+ # TODO: Figure out how to make the initial QT_HOST_PATH var relocatable in relation
+ # to the target CMAKE_INSTALL_DIR, if at all possible to do so in a reliable way.
+ get_filename_component(qt_host_path_absolute "${QT_HOST_PATH}" ABSOLUTE)
+ get_filename_component(qt_host_path_cmake_dir_absolute
+ "${Qt${PROJECT_VERSION_MAJOR}HostInfo_DIR}/.." ABSOLUTE)
+ endif()
+
+ if(third_party_deps OR platform_requires_host_info_package)
+ # Setup build and install paths.
+ set(path_suffix "${INSTALL_CMAKE_NAMESPACE}")
+
+ qt_path_join(config_build_dir ${QT_CONFIG_BUILD_DIR} ${path_suffix})
+ qt_path_join(config_install_dir ${QT_CONFIG_INSTALL_DIR} ${path_suffix})
+
+ # Configure and install QtDependencies file.
+ configure_file(
+ "${QT_CMAKE_DIR}/QtConfigDependencies.cmake.in"
+ "${config_build_dir}/${target}Dependencies.cmake"
+ @ONLY
+ )
+
+ qt_install(FILES
+ "${config_build_dir}/${target}Dependencies.cmake"
+ DESTINATION "${config_install_dir}"
+ COMPONENT Devel
+ )
+ endif()
+endfunction()
+
+# Create Depends.cmake & Depends.h files for all modules and plug-ins.
+function(qt_internal_create_depends_files)
+ qt_internal_get_qt_repo_known_modules(repo_known_modules)
+
+ if(PROJECT_NAME STREQUAL "QtBase")
+ qt_internal_create_qt6_dependencies_file()
+ endif()
+
+ foreach (target ${repo_known_modules})
+ qt_internal_create_module_depends_file(${target})
+ endforeach()
+
+ foreach (target ${QT_KNOWN_PLUGINS})
+ qt_internal_create_plugin_depends_file(${target})
+ endforeach()
+endfunction()
+
+# This function creates Qt<Module>Plugins.cmake files used to include all
+# the plugin Config files that belong to that module.
+function(qt_internal_create_plugins_auto_inclusion_files)
+ # For static library builds, the plugin targets need to be available for linking.
+ # For shared library builds, the plugin targets are useful for deployment purposes.
+ qt_internal_get_qt_repo_known_modules(repo_known_modules)
+
+ set(modules_with_plugins "")
+ foreach (QT_MODULE ${repo_known_modules})
+ get_target_property(target_type "${QT_MODULE}" TYPE)
+ if(target_type STREQUAL "INTERFACE_LIBRARY")
+ # No plugins are provided by a header only module.
+ continue()
+ endif()
+ qt_path_join(config_build_dir ${QT_CONFIG_BUILD_DIR} ${INSTALL_CMAKE_NAMESPACE}${QT_MODULE})
+ qt_path_join(config_install_dir ${QT_CONFIG_INSTALL_DIR} ${INSTALL_CMAKE_NAMESPACE}${QT_MODULE})
+ set(QT_MODULE_PLUGIN_INCLUDES "")
+
+ if(QT_MODULE STREQUAL "Qml")
+ set(QT_MODULE_PLUGIN_INCLUDES "${QT_MODULE_PLUGIN_INCLUDES}
+# Qml plugin targets might have dependencies on other qml plugin targets, but the Targets.cmake
+# files are included in the order that file(GLOB) returns, which means certain targets that are
+# referenced might not have been created yet, and \${CMAKE_FIND_PACKAGE_NAME}_NOT_FOUND_MESSAGE
+# might be set to a message saying those targets don't exist.
+#
+# Postpone checking of which targets don't exist until all Qml PluginConfig.cmake files have been
+# included, by including all the files one more time and checking for errors at each step.
+#
+# TODO: Find a better way to deal with this, perhaps by using find_package() instead of include
+# for the Qml PluginConfig.cmake files.
+
+# Distributions should probably change this default.
+if(NOT DEFINED QT_SKIP_AUTO_QML_PLUGIN_INCLUSION)
+ set(QT_SKIP_AUTO_QML_PLUGIN_INCLUSION OFF)
+endif()
+
+set(__qt_qml_plugins_config_file_list \"\")
+set(__qt_qml_plugins_glob_prefixes \"\${CMAKE_CURRENT_LIST_DIR}\")
+
+# Allow passing additional prefixes where we will glob for PluginConfig.cmake files.
+if(QT_ADDITIONAL_QML_PLUGIN_GLOB_PREFIXES)
+ foreach(__qt_qml_plugin_glob_prefix IN LISTS QT_ADDITIONAL_QML_PLUGIN_GLOB_PREFIXES)
+ if(__qt_qml_plugin_glob_prefix)
+ list(APPEND __qt_qml_plugins_glob_prefixes \"\${__qt_qml_plugin_glob_prefix}\")
+ endif()
+ endforeach()
+endif()
+
+list(REMOVE_DUPLICATES __qt_qml_plugins_glob_prefixes)
+
+foreach(__qt_qml_plugin_glob_prefix IN LISTS __qt_qml_plugins_glob_prefixes)
+ file(GLOB __qt_qml_plugins_glob_config_file_list
+ \"\${__qt_qml_plugin_glob_prefix}/QmlPlugins/${INSTALL_CMAKE_NAMESPACE}*Config.cmake\")
+ if(__qt_qml_plugins_glob_config_file_list)
+ list(APPEND __qt_qml_plugins_config_file_list \${__qt_qml_plugins_glob_config_file_list})
+ endif()
+endforeach()
+
+if (__qt_qml_plugins_config_file_list AND NOT QT_SKIP_AUTO_QML_PLUGIN_INCLUSION)
+ # First round of inclusions ensure all qml plugin targets are brought into scope.
+ foreach(__qt_qml_plugin_config_file \${__qt_qml_plugins_config_file_list})
+ include(\${__qt_qml_plugin_config_file})
+
+ # Temporarily unset any failure markers and mark the Qml package as found.
+ unset(\${CMAKE_FIND_PACKAGE_NAME}_NOT_FOUND_MESSAGE)
+ set(\${CMAKE_FIND_PACKAGE_NAME}_FOUND TRUE)
+ endforeach()
+
+ # For the second round of inclusions, check and bail out early if there are errors.
+ foreach(__qt_qml_plugin_config_file \${__qt_qml_plugins_config_file_list})
+ include(\${__qt_qml_plugin_config_file})
+
+ if(\${CMAKE_FIND_PACKAGE_NAME}_NOT_FOUND_MESSAGE)
+ string(APPEND \${CMAKE_FIND_PACKAGE_NAME}_NOT_FOUND_MESSAGE
+ \"\nThe message was set in \${__qt_qml_plugin_config_file} \")
+ set(\${CMAKE_FIND_PACKAGE_NAME}_FOUND FALSE)
+ return()
+ endif()
+ endforeach()
+
+endif()")
+ endif()
+
+ get_target_property(module_plugin_types "${QT_MODULE}" MODULE_PLUGIN_TYPES)
+ if(module_plugin_types OR QT_MODULE_PLUGIN_INCLUDES)
+ list(APPEND modules_with_plugins "${QT_MODULE}")
+ configure_file(
+ "${QT_CMAKE_DIR}/QtPlugins.cmake.in"
+ "${config_build_dir}/${INSTALL_CMAKE_NAMESPACE}${QT_MODULE}Plugins.cmake"
+ @ONLY
+ )
+ qt_install(FILES
+ "${config_build_dir}/${INSTALL_CMAKE_NAMESPACE}${QT_MODULE}Plugins.cmake"
+ DESTINATION "${config_install_dir}"
+ COMPONENT Devel
+ )
+ endif()
+ endforeach()
+ if(modules_with_plugins)
+ message(STATUS "Generated QtModulePlugins.cmake files for the following modules:"
+ " ${modules_with_plugins}")
+ endif()
+endfunction()
+
+function(qt_generate_install_prefixes out_var)
+ set(content "\n")
+ set(vars INSTALL_BINDIR INSTALL_INCLUDEDIR INSTALL_LIBDIR INSTALL_MKSPECSDIR INSTALL_ARCHDATADIR
+ INSTALL_PLUGINSDIR INSTALL_LIBEXECDIR INSTALL_QMLDIR INSTALL_DATADIR INSTALL_DOCDIR
+ INSTALL_TRANSLATIONSDIR INSTALL_SYSCONFDIR INSTALL_EXAMPLESDIR INSTALL_TESTSDIR
+ INSTALL_DESCRIPTIONSDIR)
+
+ foreach(var ${vars})
+ get_property(docstring CACHE "${var}" PROPERTY HELPSTRING)
+ string(APPEND content "set(${var} \"${${var}}\" CACHE STRING \"${docstring}\" FORCE)\n")
+ endforeach()
+
+ set(${out_var} "${content}" PARENT_SCOPE)
+endfunction()
+
+function(qt_wrap_string_in_if_multi_config content out_var)
+ set(${out_var} "
+get_property(__qt_is_multi_config GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
+if(__qt_is_multi_config)
+${content}endif()
+unset(__qt_is_multi_config)\n" PARENT_SCOPE)
+endfunction()
+
+function(qt_wrap_string_in_if_ninja_multi_config content out_var)
+ set(${out_var} "if(CMAKE_GENERATOR STREQUAL \"Ninja Multi-Config\")
+${content}endif()\n" PARENT_SCOPE)
+endfunction()
+
+function(qt_create_hostinfo_package)
+ set(package "${INSTALL_CMAKE_NAMESPACE}HostInfo")
+ qt_path_join(config_file_path "${QT_CONFIG_BUILD_DIR}/${package}/${package}Config.cmake")
+ qt_path_join(install_destination ${QT_CONFIG_INSTALL_DIR} ${package})
+ set(var_prefix "QT${PROJECT_VERSION_MAJOR}_HOST_INFO_")
+ configure_package_config_file(
+ "${CMAKE_CURRENT_LIST_DIR}/QtHostInfoConfig.cmake.in"
+ "${config_file_path}"
+ INSTALL_DESTINATION "${install_destination}"
+ NO_SET_AND_CHECK_MACRO
+ NO_CHECK_REQUIRED_COMPONENTS_MACRO)
+ qt_install(FILES "${config_file_path}" DESTINATION "${install_destination}")
+endfunction()
+
+function(qt_generate_build_internals_extra_cmake_code)
+ if(PROJECT_NAME STREQUAL "QtBase")
+ qt_create_hostinfo_package()
+
+ foreach(var IN LISTS QT_BASE_CONFIGURE_TESTS_VARS_TO_EXPORT)
+ string(APPEND QT_EXTRA_BUILD_INTERNALS_VARS "set(${var} \"${${var}}\" CACHE INTERNAL \"\")\n")
+ endforeach()
+
+ set(QT_SOURCE_TREE "${QtBase_SOURCE_DIR}")
+ qt_path_join(extra_file_path
+ ${QT_CONFIG_BUILD_DIR}
+ ${INSTALL_CMAKE_NAMESPACE}BuildInternals/QtBuildInternalsExtra.cmake)
+
+ if(CMAKE_BUILD_TYPE)
+ string(APPEND QT_EXTRA_BUILD_INTERNALS_VARS
+ "
+# Used by qt_internal_set_cmake_build_type.
+set(__qt_internal_initial_qt_cmake_build_type \"${CMAKE_BUILD_TYPE}\")
+")
+ endif()
+ if(CMAKE_CONFIGURATION_TYPES)
+ string(APPEND multi_config_specific
+ " set(CMAKE_CONFIGURATION_TYPES \"${CMAKE_CONFIGURATION_TYPES}\" CACHE STRING \"\" FORCE)\n")
+ endif()
+ if(CMAKE_TRY_COMPILE_CONFIGURATION)
+ string(APPEND multi_config_specific
+ " set(CMAKE_TRY_COMPILE_CONFIGURATION \"${CMAKE_TRY_COMPILE_CONFIGURATION}\")\n")
+ endif()
+ if(multi_config_specific)
+ qt_wrap_string_in_if_multi_config(
+ "${multi_config_specific}"
+ multi_config_specific)
+ string(APPEND QT_EXTRA_BUILD_INTERNALS_VARS "${multi_config_specific}")
+ endif()
+
+ if(QT_MULTI_CONFIG_FIRST_CONFIG)
+ string(APPEND QT_EXTRA_BUILD_INTERNALS_VARS
+ "\nset(QT_MULTI_CONFIG_FIRST_CONFIG \"${QT_MULTI_CONFIG_FIRST_CONFIG}\")\n")
+ endif()
+
+ if(CMAKE_CROSS_CONFIGS)
+ string(APPEND ninja_multi_config_specific
+ " set(CMAKE_CROSS_CONFIGS \"${CMAKE_CROSS_CONFIGS}\" CACHE STRING \"\")\n")
+ endif()
+ if(CMAKE_DEFAULT_BUILD_TYPE)
+ string(APPEND ninja_multi_config_specific
+ " set(CMAKE_DEFAULT_BUILD_TYPE \"${CMAKE_DEFAULT_BUILD_TYPE}\" CACHE STRING \"\")\n")
+ endif()
+ if(CMAKE_DEFAULT_CONFIGS)
+ string(APPEND ninja_multi_config_specific
+ " set(CMAKE_DEFAULT_CONFIGS \"${CMAKE_DEFAULT_CONFIGS}\" CACHE STRING \"\")\n")
+ endif()
+ if(ninja_multi_config_specific)
+ qt_wrap_string_in_if_ninja_multi_config(
+ "${ninja_multi_config_specific}"
+ ninja_multi_config_specific)
+ string(APPEND QT_EXTRA_BUILD_INTERNALS_VARS "${ninja_multi_config_specific}")
+ endif()
+
+ if(DEFINED BUILD_WITH_PCH)
+ string(APPEND QT_EXTRA_BUILD_INTERNALS_VARS
+ "set(BUILD_WITH_PCH \"${BUILD_WITH_PCH}\" CACHE STRING \"\")\n")
+ endif()
+
+ if(DEFINED QT_IS_MACOS_UNIVERSAL)
+ string(APPEND QT_EXTRA_BUILD_INTERNALS_VARS
+ "set(QT_IS_MACOS_UNIVERSAL \"${QT_IS_MACOS_UNIVERSAL}\" CACHE BOOL \"\")\n")
+ endif()
+
+ if(DEFINED QT_APPLE_SDK)
+ string(APPEND QT_EXTRA_BUILD_INTERNALS_VARS
+ "set(QT_APPLE_SDK \"${QT_APPLE_SDK}\" CACHE BOOL \"\")\n")
+ endif()
+
+ if(QT_FORCE_FIND_TOOLS)
+ string(APPEND QT_EXTRA_BUILD_INTERNALS_VARS
+ "set(QT_FORCE_FIND_TOOLS \"TRUE\" CACHE BOOL \"\" FORCE)\n")
+ endif()
+
+ if(QT_FORCE_BUILD_TOOLS)
+ string(APPEND QT_EXTRA_BUILD_INTERNALS_VARS
+ "set(QT_FORCE_BUILD_TOOLS \"TRUE\" CACHE BOOL \"\" FORCE)\n")
+ endif()
+
+ if(QT_INTERNAL_EXAMPLES_INSTALL_PREFIX)
+ file(TO_CMAKE_PATH
+ "${QT_INTERNAL_EXAMPLES_INSTALL_PREFIX}" examples_install_prefix)
+ string(APPEND QT_EXTRA_BUILD_INTERNALS_VARS
+ "set(QT_INTERNAL_EXAMPLES_INSTALL_PREFIX \"${examples_install_prefix}\" CACHE STRING \"\")\n")
+ endif()
+
+ # Save the default qpa platform.
+ # Used by qtwayland/src/plugins/platforms/qwayland-generic/CMakeLists.txt. Otherwise
+ # the DEFAULT_IF condition is evaluated incorrectly.
+ if(DEFINED QT_QPA_DEFAULT_PLATFORM)
+ string(APPEND QT_EXTRA_BUILD_INTERNALS_VARS
+ "set(QT_QPA_DEFAULT_PLATFORM \"${QT_QPA_DEFAULT_PLATFORM}\" CACHE STRING \"\")\n")
+ endif()
+
+ # Save minimum and policy-related CMake versions to ensure the same minimum is
+ # checked for when building other downstream repos (qtsvg, etc) and the policy settings
+ # will be consistent unless the downstream repos explicitly override them.
+ # Policy settings can be overridden per-repo, but the minimum CMake version is global for all of
+ # Qt.
+ qt_internal_get_supported_min_cmake_version_for_building_qt(
+ supported_min_version_for_building_qt)
+ qt_internal_get_computed_min_cmake_version_for_building_qt(
+ computed_min_version_for_building_qt)
+ qt_internal_get_min_new_policy_cmake_version(min_new_policy_version)
+ qt_internal_get_max_new_policy_cmake_version(max_new_policy_version)
+
+ # Rpath related things that need to be re-used when building other repos.
+ string(APPEND QT_EXTRA_BUILD_INTERNALS_VARS
+ "set(CMAKE_INSTALL_RPATH \"${CMAKE_INSTALL_RPATH}\" CACHE STRING \"\")\n")
+ if(DEFINED QT_DISABLE_RPATH)
+ string(APPEND QT_EXTRA_BUILD_INTERNALS_VARS
+ "set(QT_DISABLE_RPATH \"${QT_DISABLE_RPATH}\" CACHE STRING \"\")\n")
+ endif()
+ if(DEFINED QT_EXTRA_DEFINES)
+ string(APPEND QT_EXTRA_BUILD_INTERNALS_VARS
+ "set(QT_EXTRA_DEFINES \"${QT_EXTRA_DEFINES}\" CACHE STRING \"\")\n")
+ endif()
+ if(DEFINED QT_EXTRA_INCLUDEPATHS)
+ string(APPEND QT_EXTRA_BUILD_INTERNALS_VARS
+ "set(QT_EXTRA_INCLUDEPATHS \"${QT_EXTRA_INCLUDEPATHS}\" CACHE STRING \"\")\n")
+ endif()
+ if(DEFINED QT_EXTRA_FRAMEWORKPATHS)
+ string(APPEND QT_EXTRA_BUILD_INTERNALS_VARS
+ "set(QT_EXTRA_FRAMEWORKPATHS \"${QT_EXTRA_FRAMEWORKPATHS}\" CACHE STRING \"\")\n")
+ endif()
+ if(DEFINED QT_EXTRA_LIBDIRS)
+ string(APPEND QT_EXTRA_BUILD_INTERNALS_VARS
+ "set(QT_EXTRA_LIBDIRS \"${QT_EXTRA_LIBDIRS}\" CACHE STRING \"\")\n")
+ endif()
+ if(DEFINED QT_EXTRA_RPATHS)
+ string(APPEND QT_EXTRA_BUILD_INTERNALS_VARS
+ "set(QT_EXTRA_RPATHS \"${QT_EXTRA_RPATHS}\" CACHE STRING \"\")\n")
+ endif()
+ if(DEFINED QT_DISABLE_DEPRECATED_UP_TO)
+ string(APPEND QT_EXTRA_BUILD_INTERNALS_VARS
+ "set(QT_DISABLE_DEPRECATED_UP_TO \"${QT_DISABLE_DEPRECATED_UP_TO}\""
+ " CACHE STRING \"\")\n")
+ endif()
+
+ # Save pkg-config feature value to be able to query it internally as soon as BuildInternals
+ # package is loaded. This is to avoid any pkg-config package from being found when
+ # find_package(Qt6Core) is called in case if the feature was disabled.
+ string(APPEND QT_EXTRA_BUILD_INTERNALS_VARS "
+if(NOT QT_SKIP_BUILD_INTERNALS_PKG_CONFIG_FEATURE)
+ set(FEATURE_pkg_config \"${FEATURE_pkg_config}\" CACHE BOOL \"Using pkg-config\" FORCE)
+endif()\n")
+
+ # The OpenSSL root dir needs to be saved so that repos other than qtbase (like qtopcua) can
+ # still successfully find_package(WrapOpenSSL) in the CI.
+ # qmake saves any additional include paths passed via the configure like '-I/foo'
+ # in mkspecs/qmodule.pri, so this file is the closest equivalent.
+ if(DEFINED OPENSSL_ROOT_DIR)
+ file(TO_CMAKE_PATH "${OPENSSL_ROOT_DIR}" openssl_root_cmake_path)
+ string(APPEND QT_EXTRA_BUILD_INTERNALS_VARS
+ "set(OPENSSL_ROOT_DIR \"${openssl_root_cmake_path}\" CACHE STRING \"\")\n")
+ endif()
+
+ qt_generate_install_prefixes(install_prefix_content)
+
+ string(APPEND QT_EXTRA_BUILD_INTERNALS_VARS "${install_prefix_content}")
+
+ if(DEFINED OpenGL_GL_PREFERENCE)
+ string(APPEND QT_EXTRA_BUILD_INTERNALS_VARS
+ "
+# Use the OpenGL_GL_PREFERENCE value qtbase was built with. But do not FORCE it.
+set(OpenGL_GL_PREFERENCE \"${OpenGL_GL_PREFERENCE}\" CACHE STRING \"\")
+")
+ endif()
+
+ string(APPEND QT_EXTRA_BUILD_INTERNALS_VARS
+ "
+set(QT_COPYRIGHT \"${QT_COPYRIGHT}\" CACHE STRING \"\")
+")
+
+ # Add the apple version requirements to the BuildInternals extra code, so the info is
+ # available when configuring a standalone test.
+ # Otherwise when QtSetup is included after a
+ # find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+ # call, Qt6ConfigExtras.cmake is not included yet, the requirements are not available and
+ # _qt_internal_check_apple_sdk_and_xcode_versions() would fail.
+ _qt_internal_export_apple_sdk_and_xcode_version_requirements(apple_requirements)
+ if(apple_requirements)
+ string(APPEND QT_EXTRA_BUILD_INTERNALS_VARS "
+${apple_requirements}
+")
+ endif()
+
+ qt_compute_relative_path_from_cmake_config_dir_to_prefix()
+ configure_file(
+ "${CMAKE_CURRENT_LIST_DIR}/QtBuildInternalsExtra.cmake.in"
+ "${extra_file_path}"
+ @ONLY
+ )
+ endif()
+endfunction()
+
+# For every Qt module check if there any android dependencies that require
+# processing.
+function(qt_modules_process_android_dependencies)
+ qt_internal_get_qt_repo_known_modules(repo_known_modules)
+ foreach (target ${repo_known_modules})
+ qt_internal_android_dependencies(${target})
+ endforeach()
+endfunction()
+
+function(qt_create_tools_config_files)
+ # Create packages like Qt6CoreTools/Qt6CoreToolsConfig.cmake.
+ foreach(module_name ${QT_KNOWN_MODULES_WITH_TOOLS})
+ qt_export_tools("${module_name}")
+ endforeach()
+endfunction()
+
+function(qt_internal_create_config_file_for_standalone_tests)
+ set(standalone_tests_config_dir "StandaloneTests")
+ qt_path_join(config_build_dir
+ ${QT_CONFIG_BUILD_DIR}
+ "${INSTALL_CMAKE_NAMESPACE}BuildInternals" "${standalone_tests_config_dir}")
+ qt_path_join(config_install_dir
+ ${QT_CONFIG_INSTALL_DIR}
+ "${INSTALL_CMAKE_NAMESPACE}BuildInternals" "${standalone_tests_config_dir}")
+
+ # Filter out bundled system libraries. Otherwise when looking for their dependencies
+ # (like PNG for Freetype) FindWrapPNG is searched for during configuration of
+ # standalone tests, and it can happen that Core or Gui features are not
+ # imported early enough, which means FindWrapPNG will try to find a system PNG library instead
+ # of the bundled one.
+ set(modules)
+ foreach(m ${QT_REPO_KNOWN_MODULES})
+ get_target_property(target_type "${m}" TYPE)
+
+ # Interface libraries are never bundled system libraries (hopefully).
+ if(target_type STREQUAL "INTERFACE_LIBRARY")
+ list(APPEND modules "${m}")
+ continue()
+ endif()
+
+ get_target_property(is_3rd_party "${m}" _qt_module_is_3rdparty_library)
+ if(NOT is_3rd_party)
+ list(APPEND modules "${m}")
+ endif()
+ endforeach()
+
+ list(JOIN modules " " QT_REPO_KNOWN_MODULES_STRING)
+ string(STRIP "${QT_REPO_KNOWN_MODULES_STRING}" QT_REPO_KNOWN_MODULES_STRING)
+
+ # Skip generating and installing file if no modules were built. This make sure not to install
+ # anything when build qtx11extras on macOS for example.
+ if(NOT QT_REPO_KNOWN_MODULES_STRING)
+ return()
+ endif()
+
+ # Create a Config file that calls find_package on the modules that were built as part
+ # of the current repo. This is used for standalone tests.
+ qt_internal_get_standalone_parts_config_file_name(tests_config_file_name)
+
+ # Standalone tests Config files should follow the main versioning scheme.
+ qt_internal_get_package_version_of_target(Platform main_qt_package_version)
+
+ configure_file(
+ "${QT_CMAKE_DIR}/QtStandaloneTestsConfig.cmake.in"
+ "${config_build_dir}/${tests_config_file_name}"
+ @ONLY
+ )
+ qt_install(FILES
+ "${config_build_dir}/${tests_config_file_name}"
+ DESTINATION "${config_install_dir}"
+ COMPONENT Devel
+ )
+endfunction()
+
+function(qt_internal_install_prl_files)
+ # Get locations relative to QT_BUILD_DIR from which prl files should be installed.
+ get_property(prl_install_dirs GLOBAL PROPERTY QT_PRL_INSTALL_DIRS)
+
+ # Clear the list of install dirs so the previous values don't pollute the list of install dirs
+ # for the next repository in a top-level build.
+ set_property(GLOBAL PROPERTY QT_PRL_INSTALL_DIRS "")
+
+ foreach(prl_install_dir ${prl_install_dirs})
+ qt_install(DIRECTORY "${QT_BUILD_DIR}/${prl_install_dir}/"
+ DESTINATION ${prl_install_dir}
+ FILES_MATCHING PATTERN "*.prl"
+ )
+ endforeach()
+endfunction()
+
+function(qt_internal_generate_user_facing_tools_info)
+ if("${INSTALL_PUBLICBINDIR}" STREQUAL "")
+ return()
+ endif()
+ get_property(user_facing_tool_targets GLOBAL PROPERTY QT_USER_FACING_TOOL_TARGETS)
+ set(lines "")
+ foreach(target ${user_facing_tool_targets})
+ get_target_property(filename ${target} OUTPUT_NAME)
+ if(NOT filename)
+ set(filename ${target})
+ endif()
+ set(linkname ${filename})
+ if(APPLE)
+ get_target_property(is_macos_bundle ${target} MACOSX_BUNDLE )
+ if(is_macos_bundle)
+ set(filename "${filename}.app/Contents/MacOS/${filename}")
+ endif()
+ endif()
+ qt_path_join(tool_target_path "${CMAKE_INSTALL_PREFIX}" "${INSTALL_BINDIR}" "${filename}")
+ qt_path_join(tool_link_path "${INSTALL_PUBLICBINDIR}" "${linkname}${PROJECT_VERSION_MAJOR}")
+ list(APPEND lines "${tool_target_path} ${tool_link_path}")
+ endforeach()
+ string(REPLACE ";" "\n" content "${lines}")
+ string(APPEND content "\n")
+ set(out_file "${PROJECT_BINARY_DIR}/user_facing_tool_links.txt")
+ file(WRITE "${out_file}" "${content}")
+endfunction()
diff --git a/cmake/QtPrecompiledHeadersHelpers.cmake b/cmake/QtPrecompiledHeadersHelpers.cmake
new file mode 100644
index 0000000000..fe38413407
--- /dev/null
+++ b/cmake/QtPrecompiledHeadersHelpers.cmake
@@ -0,0 +1,34 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+function(qt_update_precompiled_header target precompiled_header)
+ if (precompiled_header AND BUILD_WITH_PCH)
+ set_property(TARGET "${target}" APPEND PROPERTY "PRECOMPILE_HEADERS" "$<$<OR:$<COMPILE_LANGUAGE:CXX>,$<COMPILE_LANGUAGE:OBJCXX>>:${precompiled_header}>")
+ endif()
+endfunction()
+
+function(qt_update_precompiled_header_with_library target library)
+ if (TARGET "${library}")
+ get_target_property(TARGET_TYPE "${library}" TYPE)
+ if (NOT TARGET_TYPE STREQUAL "INTERFACE_LIBRARY")
+ get_target_property(HEADER "${library}" MODULE_HEADER)
+ qt_update_precompiled_header("${target}" "${HEADER}")
+ endif()
+ endif()
+endfunction()
+
+function(qt_update_ignore_pch_source target sources)
+ if (sources)
+ set_source_files_properties(${sources} PROPERTIES
+ SKIP_PRECOMPILE_HEADERS ON
+ SKIP_UNITY_BUILD_INCLUSION ON)
+ endif()
+endfunction()
+
+function(qt_ignore_pch_obj_c_sources target sources)
+ # No obj-cxx PCH support for versions lower than 3.16.
+ if(CMAKE_VERSION VERSION_LESS 3.16.0)
+ list(FILTER sources INCLUDE REGEX "\\.mm$")
+ qt_update_ignore_pch_source("${target}" "${sources}")
+ endif()
+endfunction()
diff --git a/cmake/QtPriHelpers.cmake b/cmake/QtPriHelpers.cmake
new file mode 100644
index 0000000000..f410dc9b2a
--- /dev/null
+++ b/cmake/QtPriHelpers.cmake
@@ -0,0 +1,1055 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+# Extracts the 3rdparty libraries for the module ${module_name}
+# and stores the information in cmake language in
+# ${output_root_dir}/$<CONFIG>/${output_file_name}.
+#
+# This function "follows" INTERFACE_LIBRARY targets to "real" targets
+# and collects defines, include dirs and lib dirs on the way.
+function(qt_generate_qmake_libraries_pri_content module_name output_root_dir output_file_name)
+ set(content "")
+
+ # Set up a regular expression that matches all implicit include dirs
+ set(implicit_include_dirs_regex "")
+ foreach(dir ${CMAKE_CXX_IMPLICIT_INCLUDE_DIRECTORIES})
+ qt_re_escape(regex "${dir}")
+ list(APPEND implicit_include_dirs_regex "^${regex}$")
+ endforeach()
+ list(JOIN implicit_include_dirs_regex "|" implicit_include_dirs_regex)
+
+ foreach(lib ${QT_QMAKE_LIBS_FOR_${module_name}})
+ set(lib_targets ${QT_TARGETS_OF_QMAKE_LIB_${lib}})
+ string(TOUPPER ${lib} uclib)
+ string(REPLACE "-" "_" uclib "${uclib}")
+ set(lib_defines "")
+ set(lib_incdir "")
+ set(lib_libdir "")
+ set(lib_libs "")
+ set(seen_targets "")
+ while(lib_targets)
+ list(POP_BACK lib_targets lib_target)
+ if(TARGET ${lib_target})
+ if(${lib_target} IN_LIST seen_targets)
+ continue()
+ endif()
+ list(APPEND seen_targets ${lib_target})
+ get_target_property(lib_target_type ${lib_target} TYPE)
+ if(lib_target_type STREQUAL "INTERFACE_LIBRARY")
+ get_target_property(iface_libs ${lib_target} INTERFACE_LINK_LIBRARIES)
+ if(iface_libs)
+ list(PREPEND lib_targets ${iface_libs})
+ endif()
+ else()
+ list(APPEND lib_libs "$<TARGET_LINKER_FILE:${lib_target}>")
+ endif()
+ list(APPEND lib_libdir "$<TARGET_PROPERTY:${lib_target},INTERFACE_LINK_DIRECTORIES>")
+
+ get_target_property(skip_include_dir "${lib_target}" _qt_skip_include_dir_for_pri)
+ if(skip_include_dir)
+ set(target_include_dir "")
+ else()
+ set(target_include_dir
+ "$<TARGET_PROPERTY:${lib_target},INTERFACE_INCLUDE_DIRECTORIES>")
+ endif()
+
+ list(APPEND lib_incdir "${target_include_dir}")
+ list(APPEND lib_defines "$<TARGET_PROPERTY:${lib_target},INTERFACE_COMPILE_DEFINITIONS>")
+ else()
+ if(lib_target MATCHES "/([^/]+).framework$")
+ list(APPEND lib_libs "-framework" "${CMAKE_MATCH_1}")
+ else()
+ list(APPEND lib_libs "${lib_target}")
+ endif()
+ endif()
+ endwhile()
+
+ # Wrap in $<REMOVE_DUPLICATES:...> but not the libs, because
+ # we would have to preserve the right order for the linker.
+ foreach(sfx libdir incdir defines)
+ string(PREPEND lib_${sfx} "$<REMOVE_DUPLICATES:")
+ string(APPEND lib_${sfx} ">")
+ endforeach()
+
+ # Filter out implicit include directories
+ if(implicit_include_dirs_regex)
+ string(PREPEND lib_incdir "$<FILTER:")
+ string(APPEND lib_incdir ",EXCLUDE,${implicit_include_dirs_regex}>")
+ endif()
+
+ set(uccfg $<UPPER_CASE:$<CONFIG>>)
+ string(APPEND content "list(APPEND known_libs ${uclib})
+set(QMAKE_LIBS_${uclib}_${uccfg} \"${lib_libs}\")
+set(QMAKE_LIBDIR_${uclib}_${uccfg} \"${lib_libdir}\")
+set(QMAKE_INCDIR_${uclib}_${uccfg} \"${lib_incdir}\")
+set(QMAKE_DEFINES_${uclib}_${uccfg} \"${lib_defines}\")
+")
+ if(QT_QMAKE_LIB_DEPS_${lib})
+ string(APPEND content "set(QMAKE_DEPENDS_${uclib}_CC, ${deps})
+set(QMAKE_DEPENDS_${uclib}_LD, ${deps})
+")
+ endif()
+ endforeach()
+
+ file(GENERATE
+ OUTPUT "${output_root_dir}/$<CONFIG>/${output_file_name}"
+ CONTENT "${content}"
+ )
+endfunction()
+
+# Retrieves the public Qt module dependencies of the given Qt module or Qt Private module.
+# The returned dependencies are "config module names", not target names.
+#
+# PRIVATE (OPTIONAL):
+# Retrieve private dependencies only. Dependencies that appear in both, LINK_LIBRARIES and
+# INTERFACE_LINK_LIBRARIES are discarded.
+#
+function(qt_get_direct_module_dependencies target out_var)
+ cmake_parse_arguments(arg "PRIVATE" "" "" ${ARGN})
+ set(dependencies "")
+ get_target_property(target_type ${target} TYPE)
+ if(arg_PRIVATE)
+ if(target_type STREQUAL "INTERFACE_LIBRARY")
+ set(libs)
+ else()
+ get_target_property(libs ${target} LINK_LIBRARIES)
+ list(REMOVE_DUPLICATES libs)
+ endif()
+ get_target_property(public_libs ${target} INTERFACE_LINK_LIBRARIES)
+ list(REMOVE_DUPLICATES public_libs)
+
+ # Remove all Qt::Foo and Qt6::Foo from libs that also appear in public_libs.
+ set(libs_to_remove "")
+ foreach(lib IN LISTS public_libs)
+ list(APPEND libs_to_remove "${lib}")
+ if(lib MATCHES "^Qt::(.*)")
+ list(APPEND libs_to_remove "${QT_CMAKE_EXPORT_NAMESPACE}::${CMAKE_MATCH_1}")
+ elseif(lib MATCHES "^{QT_CMAKE_EXPORT_NAMESPACE}::(.*)")
+ list(APPEND libs_to_remove "Qt::${CMAKE_MATCH_1}")
+ endif()
+ endforeach()
+
+ list(REMOVE_DUPLICATES libs_to_remove)
+ list(REMOVE_ITEM libs ${libs_to_remove})
+ else()
+ get_target_property(libs ${target} INTERFACE_LINK_LIBRARIES)
+ endif()
+ if(NOT libs)
+ set(libs "")
+ endif()
+ while(libs)
+ list(POP_FRONT libs lib)
+ string(GENEX_STRIP "${lib}" lib)
+ if(NOT lib OR NOT TARGET "${lib}")
+ continue()
+ endif()
+ get_target_property(lib_type ${lib} TYPE)
+ get_target_property(aliased_target ${lib} ALIASED_TARGET)
+ if(TARGET "${aliased_target}")
+ # If versionless target is alias, use what the alias points to.
+ list(PREPEND libs "${aliased_target}")
+ continue()
+ endif()
+ if(lib_type STREQUAL "OBJECT_LIBRARY")
+ # Skip object libraries, because they're already part of ${target}.
+ continue()
+ elseif(lib_type STREQUAL "STATIC_LIBRARY" AND target_type STREQUAL "SHARED_LIBRARY")
+ # Skip static libraries if ${target} is a shared library.
+ continue()
+ endif()
+ get_target_property(lib_config_module_name ${lib} "_qt_config_module_name")
+ if(lib_config_module_name)
+ list(APPEND dependencies ${lib_config_module_name})
+ endif()
+ endwhile()
+ set(${out_var} ${dependencies} PARENT_SCOPE)
+endfunction()
+
+# Return a list of qmake library names for a given list of targets.
+# For example, Foo::Foo_nolink is mapped to foo/nolink.
+# Also targets with the _qt_is_nolink_target property are mapped to nolink as well.
+function(qt_internal_map_targets_to_qmake_libs out_var)
+ set(result "")
+ foreach(target ${ARGN})
+ # Unwrap optional targets. Needed for Vulkan.
+ if(target MATCHES "^\\$<TARGET_NAME_IF_EXISTS:(.*)>$")
+ set(target ${CMAKE_MATCH_1})
+ endif()
+
+ set(is_no_link_target FALSE)
+
+ # First case of detecting nolink targets (possibly not needed anymore)
+ string(REGEX REPLACE "_nolink$" "" stripped_target "${target}")
+ if(NOT target STREQUAL stripped_target)
+ set(is_no_link_target TRUE)
+ endif()
+
+ # Second case of detecting nolink targets.
+ if(TARGET "${target}")
+ get_target_property(marked_as_no_link_target "${target}" _qt_is_nolink_target)
+ if(marked_as_no_link_target)
+ set(is_no_link_target TRUE)
+ endif()
+ endif()
+
+ qt_internal_map_target_to_qmake_lib(${stripped_target} qmake_lib)
+ if(NOT "${qmake_lib}" STREQUAL "")
+ if(is_no_link_target)
+ string(APPEND qmake_lib "/nolink")
+ endif()
+ list(APPEND result "${qmake_lib}")
+ endif()
+ endforeach()
+ set(${out_var} "${result}" PARENT_SCOPE)
+endfunction()
+
+# Retrieve the runtime dependencies of module ${target}.
+# The runtime dependencies are what in CMake is called IMPORTED_LINK_DEPENDENT_LIBRARIES.
+# This function returns the dependencies in out_var, separated by space.
+#
+# PUBLIC_DEPENDENCIES:
+# List of the module's public dependencies.
+# The dependencies are expected to be config module names.
+#
+# PUBLIC (OPTIONAL):
+# Specifies that target is a public module.
+# If not specified, a private module is assumed.
+#
+function(qt_internal_get_module_run_dependencies out_var target)
+ cmake_parse_arguments(arg "PUBLIC" "" "PUBLIC_DEPENDENCIES" ${ARGN})
+
+ # Private dependencies of the module are runtime dependencies.
+ qt_get_direct_module_dependencies(${target} run_dependencies PRIVATE)
+
+ # If ${target} is a public module then public dependencies
+ # of the private module are also runtime dependencies.
+ if(arg_PUBLIC AND TARGET ${target}Private)
+ qt_get_direct_module_dependencies(${target}Private qt_for_private)
+
+ # FooPrivate depends on Foo, but we must not record this dependency in run_depends.
+ get_target_property(config_module_name ${target} _qt_config_module_name)
+ list(REMOVE_ITEM qt_for_private ${config_module_name})
+
+ list(APPEND run_dependencies ${qt_for_private})
+ endif()
+
+ list(REMOVE_DUPLICATES run_dependencies)
+
+ # If foo-private is a private dependency and foo is a public dependency,
+ # we don't have to add foo-private as runtime dependency.
+ set(deps_to_remove "")
+ foreach(dep IN LISTS run_dependencies)
+ if(NOT dep MATCHES "(.*)_private$")
+ continue()
+ endif()
+
+ # Is foo a public dependency?
+ list(FIND arg_PUBLIC_DEPENDENCIES "${CMAKE_MATCH_1}" idx)
+ if(idx GREATER -1)
+ list(APPEND deps_to_remove "${dep}")
+ endif()
+ endforeach()
+ if(NOT "${deps_to_remove}" STREQUAL "")
+ list(REMOVE_ITEM run_dependencies ${deps_to_remove})
+ endif()
+
+ list(JOIN run_dependencies " " run_dependencies)
+ set("${out_var}" "${run_dependencies}" PARENT_SCOPE)
+endfunction()
+
+# Generates module .pri files for consumption by qmake
+function(qt_generate_module_pri_file target)
+ set(flags INTERNAL_MODULE NO_PRIVATE_MODULE)
+ set(options)
+ set(multiopts)
+ cmake_parse_arguments(arg "${flags}" "${options}" "${multiopts}" ${ARGN})
+
+ qt_internal_module_info(module "${target}")
+ set(pri_files)
+
+ set(property_prefix)
+
+ get_target_property(target_type ${target} TYPE)
+ set(is_interface_lib FALSE)
+ if(target_type STREQUAL "INTERFACE_LIBRARY")
+ set(is_interface_lib TRUE)
+ endif()
+ if(is_interface_lib)
+ set(property_prefix "INTERFACE_")
+ endif()
+
+ get_target_property(enabled_features "${target}"
+ "${property_prefix}QT_ENABLED_PUBLIC_FEATURES")
+ get_target_property(disabled_features "${target}"
+ "${property_prefix}QT_DISABLED_PUBLIC_FEATURES")
+ get_target_property(enabled_private_features "${target}"
+ "${property_prefix}QT_ENABLED_PRIVATE_FEATURES")
+ get_target_property(disabled_private_features "${target}"
+ "${property_prefix}QT_DISABLED_PRIVATE_FEATURES")
+ qt_correct_features(enabled_features "${enabled_features}")
+ qt_correct_features(disabled_features "${disabled_features}")
+ qt_correct_features(enabled_private_features "${enabled_private_features}")
+ qt_correct_features(disabled_private_features "${disabled_private_features}")
+
+ get_target_property(module_internal_config "${target}"
+ "${property_prefix}QT_MODULE_INTERNAL_CONFIG")
+ get_target_property(module_pri_extra_content "${target}"
+ "${property_prefix}QT_MODULE_PRI_EXTRA_CONTENT")
+ get_target_property(module_ldflags "${target}"
+ "${property_prefix}QT_MODULE_LDFLAGS")
+ get_target_property(module_depends "${target}"
+ "${property_prefix}QT_MODULE_DEPENDS")
+
+ foreach(var enabled_features disabled_features enabled_private_features disabled_private_features
+ module_internal_config module_pri_extra_content module_ldflags module_depends)
+ if(${var} STREQUAL "${var}-NOTFOUND")
+ set(${var} "")
+ else()
+ string (REPLACE ";" " " ${var} "${${var}}")
+ endif()
+ endforeach()
+
+ list(APPEND module_internal_config v2)
+
+ if(arg_INTERNAL_MODULE)
+ list(APPEND module_internal_config internal_module)
+ endif()
+ get_target_property(target_type ${target} TYPE)
+ if (NOT target_type STREQUAL "INTERFACE_LIBRARY")
+ get_target_property(is_fw ${target} FRAMEWORK)
+ if(is_fw)
+ list(APPEND module_internal_config lib_bundle)
+ endif()
+ endif()
+ if(target_type STREQUAL "STATIC_LIBRARY")
+ list(APPEND module_internal_config staticlib)
+ endif()
+
+ if(QT_FEATURE_ltcg)
+ list(APPEND module_internal_config ltcg)
+ endif()
+
+ list(JOIN module_internal_config " " joined_module_internal_config)
+
+ get_target_property(config_module_name ${target} _qt_config_module_name)
+ get_target_property(qmake_module_config ${target} ${property_prefix}QT_QMAKE_MODULE_CONFIG)
+ if (is_interface_lib)
+ list(APPEND qmake_module_config "no_link")
+ endif()
+ if(qmake_module_config)
+ string(REPLACE ";" " " module_build_config "${qmake_module_config}")
+ set(module_build_config "\nQT.${config_module_name}.CONFIG = ${module_build_config}")
+ else()
+ set(module_build_config "")
+ endif()
+
+ if(is_fw)
+ qt_internal_get_framework_info(fw ${target})
+ set(framework_base_path "$$QT_MODULE_LIB_BASE")
+ set(public_module_includes "${framework_base_path}/${fw_header_dir}")
+ set(public_module_frameworks "${framework_base_path}")
+ set(private_module_includes "${framework_base_path}/${fw_private_header_dir} \
+${framework_base_path}/${fw_private_module_header_dir}")
+ else()
+ set(public_module_includes "$$QT_MODULE_INCLUDE_BASE $$QT_MODULE_INCLUDE_BASE/${module}")
+ set(public_module_frameworks "")
+ set(private_module_includes "$$QT_MODULE_INCLUDE_BASE/${module_versioned_include_dir} \
+$$QT_MODULE_INCLUDE_BASE/${module_versioned_inner_include_dir}")
+ endif()
+
+ if(is_interface_lib)
+ set(module_name_in_pri "")
+ else()
+ get_target_property(module_name_in_pri ${target} OUTPUT_NAME)
+ endif()
+
+ get_target_property(hasModuleHeaders ${target} _qt_module_has_headers)
+ if (NOT hasModuleHeaders)
+ unset(public_module_includes)
+ unset(private_module_includes)
+ endif()
+
+ set(pri_data_cmake_file "qt_lib_${config_module_name}_private.cmake")
+
+ set(config_module_name_base "${config_module_name}")
+
+ if (arg_INTERNAL_MODULE)
+ # Internal module pri needs to provide private headers
+ set(public_module_includes "${public_module_includes} ${private_module_includes}")
+ endif()
+
+ qt_path_join(target_path ${QT_BUILD_DIR} ${INSTALL_MKSPECSDIR}/modules)
+
+ unset(private_module_frameworks)
+ if(is_interface_lib)
+ set(module_plugin_types "")
+ else()
+ get_target_property(module_plugin_types ${target} QMAKE_MODULE_PLUGIN_TYPES)
+ if(module_plugin_types)
+ list(JOIN module_plugin_types " " module_plugin_types)
+ else()
+ set(module_plugin_types "")
+ endif()
+ endif()
+
+ set(module_plugin_types_assignment "")
+ if(module_plugin_types)
+ set(module_plugin_types_assignment
+ "\nQT.${config_module_name}.plugin_types = ${module_plugin_types}")
+ endif()
+
+ qt_get_direct_module_dependencies(${target} public_module_dependencies_list)
+ list(JOIN public_module_dependencies_list " " public_module_dependencies)
+ set(public_module_dependencies "${module_depends} ${public_module_dependencies}")
+
+ qt_path_join(pri_file_name "${target_path}" "qt_lib_${config_module_name}.pri")
+ list(APPEND pri_files "${pri_file_name}")
+
+ # Don't use $<TARGET_PROPERTY:${target},INTERFACE_COMPILE_DEFINITIONS> genex because that
+ # will compute the transitive list of all defines for a module (so Gui would get Core
+ #defines too). Instead query just the public defines on the target.
+ get_target_property(target_defines "${target}" INTERFACE_COMPILE_DEFINITIONS)
+
+ # We must filter out expressions of the form $<TARGET_PROPERTY:name>, because
+ # 1. They cannot be used in file(GENERATE) content.
+ # 2. They refer to the consuming target we have no access to here.
+ list(FILTER target_defines EXCLUDE REGEX "\\$<TARGET_PROPERTY:[^,>]+>")
+ list(JOIN target_defines " " joined_target_defines)
+
+ set(extra_assignments "")
+ if(NOT QT_BUILD_SHARED_LIBS AND target STREQUAL Gui)
+ set(extra_assignments "\nQT_DEFAULT_QPA_PLUGIN = q${QT_QPA_DEFAULT_PLATFORM}")
+ endif()
+
+ # Map the public dependencies of the target to qmake library names.
+ get_target_property(dep_targets ${target} INTERFACE_LINK_LIBRARIES)
+ qt_internal_map_targets_to_qmake_libs(module_uses ${dep_targets})
+ list(JOIN module_uses " " joined_module_uses)
+
+ # Retrieve the public module's runtime dependencies.
+ qt_internal_get_module_run_dependencies(public_module_run_dependencies ${target}
+ PUBLIC
+ PUBLIC_DEPENDENCIES "${public_module_dependencies_list}")
+
+ set(content "QT.${config_module_name}.VERSION = ${PROJECT_VERSION}
+QT.${config_module_name}.name = ${module}
+QT.${config_module_name}.module = ${module_name_in_pri}
+QT.${config_module_name}.libs = $$QT_MODULE_LIB_BASE
+QT.${config_module_name}.ldflags = ${module_ldflags}
+QT.${config_module_name}.includes = ${public_module_includes}
+QT.${config_module_name}.frameworks = ${public_module_frameworks}
+QT.${config_module_name}.bins = $$QT_MODULE_BIN_BASE${module_plugin_types_assignment}
+QT.${config_module_name}.depends = ${public_module_dependencies}
+")
+ if(NOT "${public_module_run_dependencies}" STREQUAL "")
+ string(APPEND content
+ "QT.${config_module_name}.run_depends = ${public_module_run_dependencies}\n")
+ endif()
+ string(APPEND content
+ "QT.${config_module_name}.uses = ${joined_module_uses}
+QT.${config_module_name}.module_config = ${joined_module_internal_config}${module_build_config}
+QT.${config_module_name}.DEFINES = ${joined_target_defines}
+QT.${config_module_name}.enabled_features = ${enabled_features}
+QT.${config_module_name}.disabled_features = ${disabled_features}${extra_assignments}
+QT_CONFIG += ${enabled_features}
+QT_MODULES += ${config_module_name_base}
+${module_pri_extra_content}
+")
+ file(GENERATE OUTPUT "${pri_file_name}" CONTENT "${content}")
+
+ if (NOT arg_NO_PRIVATE_MODULE AND NOT arg_INTERNAL_MODULE)
+ set(pri_data_cmake_file "qt_lib_${config_module_name}_private.cmake")
+ qt_generate_qmake_libraries_pri_content(${config_module_name} "${CMAKE_CURRENT_BINARY_DIR}"
+ ${pri_data_cmake_file})
+
+ set(private_pri_file_name "qt_lib_${config_module_name}_private.pri")
+
+ set(private_module_dependencies "")
+ if(NOT is_interface_lib)
+ qt_get_direct_module_dependencies(${target}Private private_module_dependencies)
+ endif()
+ list(JOIN private_module_dependencies " " private_module_dependencies)
+
+ # Private modules always have internal_module config set, as per qmake.
+ list(APPEND module_internal_config internal_module)
+ list(JOIN module_internal_config " " joined_module_internal_config)
+
+ # Map the public dependencies of the private module to qmake library names.
+ get_target_property(dep_targets ${target}Private INTERFACE_LINK_LIBRARIES)
+ qt_internal_map_targets_to_qmake_libs(private_module_uses ${dep_targets})
+ list(JOIN private_module_uses " " joined_private_module_uses)
+
+ # Retrieve the private module's runtime dependencies.
+ qt_internal_get_module_run_dependencies(private_module_run_dependencies ${target}Private
+ PUBLIC_DEPENDENCIES "${dep_targets}")
+
+ # Generate a preliminary qt_lib_XXX_private.pri file
+ set(content
+ "QT.${config_module_name}_private.VERSION = ${PROJECT_VERSION}
+QT.${config_module_name}_private.name = ${module}
+QT.${config_module_name}_private.module =
+QT.${config_module_name}_private.libs = $$QT_MODULE_LIB_BASE
+QT.${config_module_name}_private.includes = ${private_module_includes}
+QT.${config_module_name}_private.frameworks = ${private_module_frameworks}
+QT.${config_module_name}_private.depends = ${private_module_dependencies}
+")
+ if(NOT "${private_module_run_dependencies}" STREQUAL "")
+ string(APPEND content
+ "QT.${config_module_name}_private.run_depends = ${private_module_run_dependencies}
+")
+ endif()
+ string(APPEND content
+ "QT.${config_module_name}_private.uses = ${joined_private_module_uses}
+QT.${config_module_name}_private.module_config = ${joined_module_internal_config}
+QT.${config_module_name}_private.enabled_features = ${enabled_private_features}
+QT.${config_module_name}_private.disabled_features = ${disabled_private_features}")
+ file(GENERATE
+ OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/${private_pri_file_name}"
+ CONTENT "${content}")
+
+ if(QT_GENERATOR_IS_MULTI_CONFIG)
+ set(configs ${CMAKE_CONFIGURATION_TYPES})
+ else()
+ set(configs ${CMAKE_BUILD_TYPE})
+ endif()
+ set(inputs "${CMAKE_CURRENT_BINARY_DIR}/${private_pri_file_name}")
+ foreach(cfg ${configs})
+ list(APPEND inputs "${CMAKE_CURRENT_BINARY_DIR}/${cfg}/${pri_data_cmake_file}")
+ endforeach()
+
+ qt_path_join(private_pri_file_path "${target_path}" "${private_pri_file_name}")
+ list(APPEND pri_files "${private_pri_file_path}")
+
+ set(library_prefixes ${CMAKE_SHARED_LIBRARY_PREFIX} ${CMAKE_STATIC_LIBRARY_PREFIX})
+ set(library_suffixes
+ ${CMAKE_SHARED_LIBRARY_SUFFIX}
+ ${CMAKE_EXTRA_SHARED_LIBRARY_SUFFIXES}
+ ${CMAKE_STATIC_LIBRARY_SUFFIX})
+ if(MSVC)
+ set(link_library_flag "-l")
+ file(TO_CMAKE_PATH "$ENV{LIB};${CMAKE_CXX_IMPLICIT_LINK_DIRECTORIES}" implicit_link_directories)
+ else()
+ set(link_library_flag ${CMAKE_LINK_LIBRARY_FLAG})
+ set(implicit_link_directories ${CMAKE_CXX_IMPLICIT_LINK_DIRECTORIES})
+ endif()
+ add_custom_command(
+ OUTPUT "${private_pri_file_path}"
+ DEPENDS ${inputs}
+ "${QT_CMAKE_DIR}/QtGenerateLibPri.cmake"
+ "${QT_CMAKE_DIR}/QtGenerateLibHelpers.cmake"
+ COMMAND ${CMAKE_COMMAND} "-DIN_FILES=${inputs}" "-DOUT_FILE=${private_pri_file_path}"
+ "-DLIBRARY_PREFIXES=${library_prefixes}"
+ "-DLIBRARY_SUFFIXES=${library_suffixes}"
+ "-DLINK_LIBRARY_FLAG=${link_library_flag}"
+ "-DCONFIGS=${configs}"
+ "-DIMPLICIT_LINK_DIRECTORIES=${implicit_link_directories}"
+ -P "${QT_CMAKE_DIR}/QtGenerateLibPri.cmake"
+ VERBATIM)
+ # add_dependencies has no effect when adding interface libraries. So need to add the
+ # '_lib_pri' targets to ALL to make sure that the related rules executed.
+ unset(add_pri_target_to_all)
+ if(is_interface_lib)
+ set(add_pri_target_to_all ALL)
+ endif()
+ add_custom_target(${target}_lib_pri ${add_pri_target_to_all}
+ DEPENDS "${private_pri_file_path}")
+ add_dependencies(${target} ${target}_lib_pri)
+ endif()
+
+ qt_install(FILES "${pri_files}" DESTINATION ${INSTALL_MKSPECSDIR}/modules)
+endfunction()
+
+# Generates qt_ext_XXX.pri files for consumption by qmake
+function(qt_generate_3rdparty_lib_pri_file target lib pri_file_var)
+ if(NOT lib)
+ # Don't write a pri file for projects that don't set QMAKE_LIB_NAME yet.
+ return()
+ endif()
+
+ if(QT_GENERATOR_IS_MULTI_CONFIG)
+ set(configs ${CMAKE_CONFIGURATION_TYPES})
+ else()
+ set(configs ${CMAKE_BUILD_TYPE})
+ endif()
+
+ file(GENERATE
+ OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/$<CONFIG>/qt_ext_${lib}.cmake"
+ CONTENT "set(cfg $<CONFIG>)
+set(incdir $<TARGET_PROPERTY:${target},INTERFACE_INCLUDE_DIRECTORIES>)
+set(defines $<TARGET_PROPERTY:${target},INTERFACE_COMPILE_DEFINITIONS>)
+set(libs $<TARGET_FILE:${target}>)
+")
+
+ set(inputs "")
+ foreach(cfg ${configs})
+ list(APPEND inputs "${CMAKE_CURRENT_BINARY_DIR}/${cfg}/qt_ext_${lib}.cmake")
+ endforeach()
+
+ qt_path_join(pri_target_path ${QT_BUILD_DIR} ${INSTALL_MKSPECSDIR}/modules)
+ qt_path_join(pri_file "${pri_target_path}" "qt_ext_${lib}.pri")
+ qt_path_join(qt_build_libdir ${QT_BUILD_DIR} ${INSTALL_LIBDIR})
+ add_custom_command(
+ OUTPUT "${pri_file}"
+ DEPENDS ${inputs} "${QT_CMAKE_DIR}/QtGenerateExtPri.cmake"
+ COMMAND ${CMAKE_COMMAND} "-DIN_FILES=${inputs}" "-DOUT_FILE=${pri_file}" -DLIB=${lib}
+ "-DCONFIGS=${configs}"
+ "-DQT_BUILD_LIBDIR=${qt_build_libdir}"
+ -P "${QT_CMAKE_DIR}/QtGenerateExtPri.cmake"
+ VERBATIM)
+ add_custom_target(${target}_ext_pri DEPENDS "${pri_file}")
+ add_dependencies(${target} ${target}_ext_pri)
+ set(${pri_file_var} ${pri_file} PARENT_SCOPE)
+endfunction()
+
+# Generates qt_plugin_XXX.pri files for consumption by qmake
+#
+# QT_PLUGIN.XXX.EXTENDS is set to "-" for the following plugin types:
+# - generic
+# - platform, if the plugin is not the default QPA plugin
+# Otherwise, this variable is empty.
+function(qt_generate_plugin_pri_file target)
+ get_target_property(plugin_name ${target} OUTPUT_NAME)
+ get_target_property(plugin_type ${target} QT_PLUGIN_TYPE)
+ get_target_property(qmake_plugin_type ${target} QT_QMAKE_PLUGIN_TYPE)
+ get_target_property(default_plugin ${target} QT_DEFAULT_PLUGIN)
+ get_target_property(plugin_class_name ${target} QT_PLUGIN_CLASS_NAME)
+ get_target_property(plugin_pri_extra_content ${target} QT_PLUGIN_PRI_EXTRA_CONTENT)
+
+ foreach(var plugin_pri_extra_content)
+ if(${var} STREQUAL "${var}-NOTFOUND")
+ set(${var} "")
+ else()
+ string(REPLACE ";" "\n" ${var} "${${var}}")
+ endif()
+ endforeach()
+
+ set(plugin_extends "")
+ if(NOT default_plugin)
+ set(plugin_extends "-")
+ endif()
+
+ set(plugin_deps "")
+ get_target_property(target_deps ${target} _qt_target_deps)
+ foreach(dep ${target_deps})
+ list(GET dep 0 dep_name)
+ qt_get_qmake_module_name(dep_name ${dep_name})
+ list(APPEND plugin_deps ${dep_name})
+ endforeach()
+ list(REMOVE_DUPLICATES plugin_deps)
+ list(JOIN plugin_deps " " plugin_deps)
+
+ list(APPEND module_config v2)
+ get_target_property(target_type ${target} TYPE)
+ if(target_type STREQUAL "STATIC_LIBRARY")
+ list(APPEND module_config staticlib)
+ endif()
+ list(JOIN module_config " " module_config)
+
+ qt_path_join(pri_target_path ${QT_BUILD_DIR} ${INSTALL_MKSPECSDIR}/modules)
+ qt_path_join(pri_file "${pri_target_path}" "qt_plugin_${plugin_name}.pri")
+
+ set(content "QT_PLUGIN.${plugin_name}.TYPE = ${qmake_plugin_type}
+QT_PLUGIN.${plugin_name}.EXTENDS = ${plugin_extends}
+QT_PLUGIN.${plugin_name}.DEPENDS = ${plugin_deps}
+QT_PLUGIN.${plugin_name}.CLASS_NAME = ${plugin_class_name}
+QT_PLUGIN.${plugin_name}.module_config = ${module_config}
+QT_PLUGINS += ${plugin_name}
+${plugin_pri_extra_content}"
+)
+
+ file(GENERATE OUTPUT "${pri_file}" CONTENT "${content}")
+
+ qt_install(FILES "${pri_file}" DESTINATION "${INSTALL_MKSPECSDIR}/modules")
+endfunction()
+
+# Creates mkspecs/qconfig.pri which contains public global features among other things.
+function(qt_generate_global_config_pri_file)
+ qt_path_join(qconfig_pri_target_path ${PROJECT_BINARY_DIR} ${INSTALL_MKSPECSDIR})
+ qt_path_join(qconfig_pri_target_path "${qconfig_pri_target_path}" "qconfig.pri")
+
+ get_target_property(enabled_features GlobalConfig INTERFACE_QT_ENABLED_PUBLIC_FEATURES)
+ get_target_property(disabled_features GlobalConfig INTERFACE_QT_DISABLED_PUBLIC_FEATURES)
+
+ qt_correct_features(corrected_enabled_features "${enabled_features}")
+ qt_correct_features(corrected_disabled_features "${disabled_features}")
+
+ string (REPLACE ";" " " corrected_enabled_features "${corrected_enabled_features}")
+ string (REPLACE ";" " " corrected_disabled_features "${corrected_disabled_features}")
+
+ # Add some required CONFIG entries.
+ set(config_entries "")
+ if(CMAKE_BUILD_TYPE STREQUAL Debug)
+ list(APPEND config_entries "debug")
+ elseif(CMAKE_BUILD_TYPE STREQUAL Release)
+ list(APPEND config_entries "release")
+ endif()
+ list(APPEND config_entries "${qt_build_config_type}")
+ string (REPLACE ";" " " config_entries "${config_entries}")
+
+ get_target_property(public_config GlobalConfig INTERFACE_QT_QMAKE_PUBLIC_CONFIG)
+ get_target_property(qt_public_config GlobalConfig INTERFACE_QT_QMAKE_PUBLIC_QT_CONFIG)
+ qt_correct_config(corrected_public_config "${public_config}")
+ qt_correct_config(corrected_qt_public_config "${qt_public_config}")
+ qt_guess_qmake_build_config(qmake_build_config)
+ list(APPEND corrected_qt_public_config ${qmake_build_config})
+
+ list(JOIN corrected_public_config " " public_config_joined)
+ list(JOIN corrected_qt_public_config " " qt_public_config_joined)
+
+ set(content "")
+ if(GCC OR CLANG AND NOT "${CMAKE_SYSROOT}" STREQUAL "")
+ string(APPEND content "!host_build {
+ QMAKE_CFLAGS += --sysroot=\$\$[QT_SYSROOT]
+ QMAKE_CXXFLAGS += --sysroot=\$\$[QT_SYSROOT]
+ QMAKE_LFLAGS += --sysroot=\$\$[QT_SYSROOT]
+}
+")
+ endif()
+
+ if(CMAKE_CROSSCOMPILING)
+ string(APPEND content "host_build {
+ QT_ARCH = ${QT${PROJECT_VERSION_MAJOR}_HOST_INFO_ARCH}
+ QT_BUILDABI = ${QT${PROJECT_VERSION_MAJOR}_HOST_INFO_BUILDABI}
+ QT_TARGET_ARCH = ${TEST_architecture_arch}
+ QT_TARGET_BUILDABI = ${TEST_buildAbi}
+} else {
+ QT_ARCH = ${TEST_architecture_arch}
+ QT_BUILDABI = ${TEST_buildAbi}
+ QT_LIBCPP_ABI_TAG = ${TEST_libcppabiTag}
+}
+")
+ else()
+ string(APPEND content "QT_ARCH = ${TEST_architecture_arch}
+QT_BUILDABI = ${TEST_buildAbi}
+QT_LIBCPP_ABI_TAG = ${TEST_libcppabiTag}
+")
+ endif()
+
+ string(APPEND content "QT.global.enabled_features = ${corrected_enabled_features}
+QT.global.disabled_features = ${corrected_disabled_features}
+QT.global.disabled_features += release build_all
+QT_CONFIG += ${qt_public_config_joined}
+CONFIG += ${config_entries} ${public_config_joined}
+QT_VERSION = ${PROJECT_VERSION}
+QT_MAJOR_VERSION = ${PROJECT_VERSION_MAJOR}
+QT_MINOR_VERSION = ${PROJECT_VERSION_MINOR}
+QT_PATCH_VERSION = ${PROJECT_VERSION_PATCH}
+")
+
+ set(extra_statements "")
+ if(QT_NAMESPACE)
+ list(APPEND extra_statements "QT_NAMESPACE = ${QT_NAMESPACE}")
+ endif()
+
+ if(QT_LIBINFIX)
+ list(APPEND extra_statements "QT_LIBINFIX = ${QT_LIBINFIX}")
+ endif()
+
+ if(APPLECLANG)
+ set(compiler_version_major_var_name "QT_APPLE_CLANG_MAJOR_VERSION")
+ set(compiler_version_minor_var_name "QT_APPLE_CLANG_MINOR_VERSION")
+ set(compiler_version_patch_var_name "QT_APPLE_CLANG_PATCH_VERSION")
+ elseif(IntelLLVM)
+ set(compiler_version_major_var_name "QT_INTELLLVM_MAJOR_VERSION")
+ set(compiler_version_minor_var_name "QT_INTELLLVM_MINOR_VERSION")
+ set(compiler_version_patch_var_name "QT_INTELLLVM_PATCH_VERSION")
+ elseif(CLANG)
+ set(compiler_version_major_var_name "QT_CLANG_MAJOR_VERSION")
+ set(compiler_version_minor_var_name "QT_CLANG_MINOR_VERSION")
+ set(compiler_version_patch_var_name "QT_CLANG_PATCH_VERSION")
+ elseif(GCC)
+ set(compiler_version_major_var_name "QT_GCC_MAJOR_VERSION")
+ set(compiler_version_minor_var_name "QT_GCC_MINOR_VERSION")
+ set(compiler_version_patch_var_name "QT_GCC_PATCH_VERSION")
+ elseif(MSVC)
+ set(compiler_version_major_var_name "QT_MSVC_MAJOR_VERSION")
+ set(compiler_version_minor_var_name "QT_MSVC_MINOR_VERSION")
+ set(compiler_version_patch_var_name "QT_MSVC_PATCH_VERSION")
+ endif()
+
+ if(compiler_version_major_var_name)
+ list(APPEND extra_statements
+ "${compiler_version_major_var_name} = ${QT_COMPILER_VERSION_MAJOR}")
+ list(APPEND extra_statements
+ "${compiler_version_minor_var_name} = ${QT_COMPILER_VERSION_MINOR}")
+ list(APPEND extra_statements
+ "${compiler_version_patch_var_name} = ${QT_COMPILER_VERSION_PATCH}")
+ endif()
+
+ if(APPLE)
+ list(APPEND extra_statements "QT_MAC_SDK_VERSION = ${QT_MAC_SDK_VERSION}")
+ if(NOT CMAKE_SYSTEM_NAME OR CMAKE_SYSTEM_NAME STREQUAL "Darwin")
+ # macOS
+ list(APPEND extra_statements
+ "QMAKE_MACOSX_DEPLOYMENT_TARGET = ${CMAKE_OSX_DEPLOYMENT_TARGET}")
+ list(APPEND extra_statements
+ "QT_MAC_SDK_VERSION_MIN = ${QT_SUPPORTED_MIN_MACOS_SDK_VERSION}")
+ list(APPEND extra_statements
+ "QT_MAC_SDK_VERSION_MAX = ${QT_SUPPORTED_MAX_MACOS_SDK_VERSION}")
+ elseif(CMAKE_SYSTEM_NAME STREQUAL iOS)
+ list(APPEND extra_statements
+ "QMAKE_IOS_DEPLOYMENT_TARGET = ${CMAKE_OSX_DEPLOYMENT_TARGET}")
+ list(APPEND extra_statements
+ "QT_MAC_SDK_VERSION_MIN = ${QT_SUPPORTED_MIN_IOS_SDK_VERSION}")
+ list(APPEND extra_statements
+ "QT_MAC_SDK_VERSION_MAX = ${QT_SUPPORTED_MAX_IOS_SDK_VERSION}")
+ endif()
+
+ if (CMAKE_OSX_ARCHITECTURES)
+ list(APPEND architectures "${CMAKE_OSX_ARCHITECTURES}")
+ string (REPLACE ";" " " architectures "${architectures}")
+ else()
+ set(architectures "$$QT_ARCH")
+ endif()
+ list(APPEND extra_statements "QT_ARCHS = ${architectures}")
+ endif()
+
+ if(WASM)
+ list(APPEND extra_statements
+ "QT_EMCC_VERSION = ${EMCC_VERSION}")
+ endif()
+ if(extra_statements)
+ string(REPLACE ";" "\n" extra_statements "${extra_statements}")
+ string(APPEND content "\n${extra_statements}\n")
+ endif()
+
+ file(GENERATE
+ OUTPUT "${qconfig_pri_target_path}"
+ CONTENT "${content}"
+ )
+ qt_install(FILES "${qconfig_pri_target_path}" DESTINATION ${INSTALL_MKSPECSDIR})
+endfunction()
+
+# Creates mkspecs/qdevice.pri which contains target device information for cross-builds.
+# The content of QT_QMAKE_DEVICE_OPTIONS is written verbatim into qdevice.pri.
+function(qt_generate_global_device_pri_file)
+ if(NOT CMAKE_CROSSCOMPILING)
+ return()
+ endif()
+
+ qt_path_join(qdevice_pri_target_path ${PROJECT_BINARY_DIR} ${INSTALL_MKSPECSDIR} "qdevice.pri")
+
+ set(content "")
+ foreach(opt ${QT_QMAKE_DEVICE_OPTIONS})
+ string(APPEND content "${opt}\n")
+ endforeach()
+
+ # Write android specific device info.
+ if(ANDROID)
+ file(TO_CMAKE_PATH ${ANDROID_SDK_ROOT} ANDROID_SDK_ROOT)
+ string(APPEND content "DEFAULT_ANDROID_SDK_ROOT = ${ANDROID_SDK_ROOT}\n")
+ file(TO_CMAKE_PATH ${ANDROID_NDK} ANDROID_NDK)
+ string(APPEND content "DEFAULT_ANDROID_NDK_ROOT = ${ANDROID_NDK}\n")
+
+ set(android_platform "android-23")
+ if(ANDROID_PLATFORM)
+ set(android_platform "${ANDROID_PLATFORM}")
+ elseif(ANDROID_NATIVE_API_LEVEL)
+ set(android_platform "android-${ANDROID_NATIVE_API_LEVEL}")
+ endif()
+ string(APPEND content "DEFAULT_ANDROID_PLATFORM = ${android_platform}\n")
+
+ string(APPEND content "DEFAULT_ANDROID_NDK_HOST = ${ANDROID_HOST_TAG}\n")
+
+ # TODO: QTBUG-80943 When we eventually support Android multi-abi, this should be changed.
+ string(APPEND content "DEFAULT_ANDROID_ABIS = ${ANDROID_ABI}\n")
+
+ if(QT_ANDROID_JAVAC_SOURCE)
+ string(APPEND content "ANDROID_JAVAC_SOURCE_VERSION = ${QT_ANDROID_JAVAC_SOURCE}\n")
+ endif()
+ if(QT_ANDROID_JAVAC_TARGET)
+ string(APPEND content "ANDROID_JAVAC_TARGET_VERSION = ${QT_ANDROID_JAVAC_TARGET}\n")
+ endif()
+ endif()
+
+ if(QT_APPLE_SDK)
+ string(APPEND content "QMAKE_MAC_SDK = ${QT_APPLE_SDK}\n")
+ endif()
+
+ set(gcc_machine_dump "")
+ if(TEST_machine_tuple)
+ set(gcc_machine_dump "${TEST_machine_tuple}")
+ endif()
+ string(APPEND content "GCC_MACHINE_DUMP = ${gcc_machine_dump}\n")
+
+ file(GENERATE OUTPUT "${qdevice_pri_target_path}" CONTENT "${content}")
+ qt_install(FILES "${qdevice_pri_target_path}" DESTINATION ${INSTALL_MKSPECSDIR})
+endfunction()
+
+function(qt_get_build_parts out_var)
+ set(parts "libs")
+
+ if(QT_BUILD_EXAMPLES AND QT_BUILD_EXAMPLES_BY_DEFAULT)
+ list(APPEND parts "examples")
+ endif()
+
+ if(QT_BUILD_TESTS AND QT_BUILD_TESTS_BY_DEFAULT)
+ list(APPEND parts "tests")
+ endif()
+
+ if(NOT CMAKE_CROSSCOMPILING OR QT_FORCE_BUILD_TOOLS)
+ list(APPEND parts "tools")
+ endif()
+
+ set(${out_var} ${parts} PARENT_SCOPE)
+endfunction()
+
+# Creates mkspecs/qmodule.pri which contains private global features among other things.
+function(qt_generate_global_module_pri_file)
+ qt_path_join(qmodule_pri_target_path ${PROJECT_BINARY_DIR} ${INSTALL_MKSPECSDIR})
+ qt_path_join(qmodule_pri_target_path "${qmodule_pri_target_path}" "qmodule.pri")
+
+ get_target_property(enabled_features GlobalConfig INTERFACE_QT_ENABLED_PRIVATE_FEATURES)
+ get_target_property(disabled_features GlobalConfig INTERFACE_QT_DISABLED_PRIVATE_FEATURES)
+
+ qt_correct_features(corrected_enabled_features "${enabled_features}")
+ qt_correct_features(corrected_disabled_features "${disabled_features}")
+
+ string (REPLACE ";" " " corrected_enabled_features "${corrected_enabled_features}")
+ string (REPLACE ";" " " corrected_disabled_features "${corrected_disabled_features}")
+
+ set(corrected_private_config "")
+ get_target_property(private_config GlobalConfig INTERFACE_QT_QMAKE_PRIVATE_CONFIG)
+ qt_correct_config(corrected_private_config "${private_config}")
+ list(JOIN corrected_private_config " " private_config_joined)
+
+ set(content "")
+ if(DEFINED QT_EXTRA_DEFINES)
+ list(JOIN QT_EXTRA_DEFINES " " value)
+ string(APPEND content "EXTRA_DEFINES += ${value}\n")
+ endif()
+ if(DEFINED QT_EXTRA_INCLUDEPATHS)
+ qt_to_qmake_path_list(value ${QT_EXTRA_INCLUDEPATHS})
+ string(APPEND content "EXTRA_INCLUDEPATH += ${value}\n")
+ endif()
+ if(DEFINED QT_EXTRA_LIBDIRS)
+ qt_to_qmake_path_list(value ${QT_EXTRA_LIBDIRS})
+ string(APPEND content "EXTRA_LIBDIR += ${value}\n")
+ endif()
+ if(DEFINED QT_EXTRA_FRAMEWORKPATHS)
+ qt_to_qmake_path_list(value ${QT_EXTRA_FRAMEWORKPATHS})
+ string(APPEND content "EXTRA_FRAMEWORKPATH += ${value}\n")
+ endif()
+
+ set(arch "${TEST_architecture_arch}")
+ list(JOIN TEST_subarch_result " " subarchs)
+ if(CMAKE_CROSSCOMPILING)
+ set(host_arch "${QT${PROJECT_VERSION_MAJOR}_HOST_INFO_ARCH}")
+ list(JOIN QT${PROJECT_VERSION_MAJOR}_HOST_INFO_SUBARCHS " " host_subarchs)
+ string(APPEND content "host_build {
+ QT_CPU_FEATURES.${host_arch} = ${host_subarchs}
+} else {
+ QT_CPU_FEATURES.${arch} = ${subarchs}
+}
+")
+ else()
+ string(APPEND content "QT_CPU_FEATURES.${arch} = ${subarchs}\n")
+ endif()
+
+ string(APPEND content "QT.global_private.enabled_features = ${corrected_enabled_features}
+QT.global_private.disabled_features = ${corrected_disabled_features}
+CONFIG += ${private_config_joined}
+")
+ if(PKG_CONFIG_FOUND)
+ string(APPEND content "PKG_CONFIG_EXECUTABLE = ${PKG_CONFIG_EXECUTABLE}\n")
+ endif()
+
+ string(APPEND content "QT_COORD_TYPE = ${QT_COORD_TYPE}\n")
+
+ qt_get_build_parts(build_parts)
+ string(REPLACE ";" " " build_parts "${build_parts}")
+ string(APPEND content "QT_BUILD_PARTS = ${build_parts}\n")
+
+ if(QT_EXTRA_RPATHS)
+ list(JOIN QT_EXTRA_RPATHS " " extra_rpaths)
+ string(APPEND content "EXTRA_RPATHS += ${extra_rpaths}")
+ endif()
+
+ set(preliminary_pri_root "${CMAKE_CURRENT_BINARY_DIR}/mkspecs/preliminary")
+ set(pri_data_cmake_file "qmodule.cmake")
+ qt_generate_qmake_libraries_pri_content(global ${preliminary_pri_root} ${pri_data_cmake_file})
+
+ # Generate a preliminary qmodule.pri file
+ set(preliminary_pri_file_path "${preliminary_pri_root}/qmodule.pri")
+ file(GENERATE
+ OUTPUT ${preliminary_pri_file_path}
+ CONTENT "${content}"
+ )
+
+ if(QT_GENERATOR_IS_MULTI_CONFIG)
+ set(configs ${CMAKE_CONFIGURATION_TYPES})
+ else()
+ set(configs ${CMAKE_BUILD_TYPE})
+ endif()
+ set(inputs ${preliminary_pri_file_path})
+ foreach(cfg ${configs})
+ list(APPEND inputs "${preliminary_pri_root}/${cfg}/${pri_data_cmake_file}")
+ endforeach()
+
+ set(library_prefixes ${CMAKE_SHARED_LIBRARY_PREFIX} ${CMAKE_STATIC_LIBRARY_PREFIX})
+ set(library_suffixes
+ ${CMAKE_SHARED_LIBRARY_SUFFIX}
+ ${CMAKE_EXTRA_SHARED_LIBRARY_SUFFIXES}
+ ${CMAKE_STATIC_LIBRARY_SUFFIX})
+ if(MSVC)
+ set(link_library_flag "-l")
+ file(TO_CMAKE_PATH "$ENV{LIB};${CMAKE_CXX_IMPLICIT_LINK_DIRECTORIES}" implicit_link_directories)
+ else()
+ set(link_library_flag ${CMAKE_LINK_LIBRARY_FLAG})
+ set(implicit_link_directories ${CMAKE_CXX_IMPLICIT_LINK_DIRECTORIES})
+ endif()
+ add_custom_command(
+ OUTPUT "${qmodule_pri_target_path}"
+ DEPENDS ${inputs}
+ "${QT_CMAKE_DIR}/QtGenerateLibPri.cmake"
+ "${QT_CMAKE_DIR}/QtGenerateLibHelpers.cmake"
+ COMMAND ${CMAKE_COMMAND} "-DIN_FILES=${inputs}" "-DOUT_FILE=${qmodule_pri_target_path}"
+ "-DLIBRARY_PREFIXES=${library_prefixes}"
+ "-DLIBRARY_SUFFIXES=${library_suffixes}"
+ "-DLINK_LIBRARY_FLAG=${link_library_flag}"
+ "-DCONFIGS=${configs}"
+ "-DIMPLICIT_LINK_DIRECTORIES=${implicit_link_directories}"
+ -P "${QT_CMAKE_DIR}/QtGenerateLibPri.cmake"
+ VERBATIM)
+ add_custom_target(qmodule_pri DEPENDS "${qmodule_pri_target_path}")
+ qt_install(FILES "${qmodule_pri_target_path}" DESTINATION ${INSTALL_MKSPECSDIR})
+endfunction()
+
+function(qt_correct_features out_var features)
+ set(corrected_features "")
+ foreach(feature ${features})
+ get_property(feature_original_name GLOBAL PROPERTY "QT_FEATURE_ORIGINAL_NAME_${feature}")
+ list(APPEND corrected_features "${feature_original_name}")
+ endforeach()
+ set(${out_var} ${corrected_features} PARENT_SCOPE)
+endfunction()
+
+# Get original names for config values (which correspond to feature names) and use them if they
+# exist, otherwise just use the config value (which might be the case when a config value has
+# a custom name).
+function(qt_correct_config out_var config)
+ set(corrected_config "")
+ foreach(name ${config})
+ # Is the config value a known feature?
+ get_property(feature_original_name GLOBAL PROPERTY "QT_FEATURE_ORIGINAL_NAME_${name}")
+ if(feature_original_name)
+ list(APPEND corrected_config "${feature_original_name}")
+ continue()
+ endif()
+
+ # Is the config value a negated known feature, e.g. no_foo?
+ # Then add the config value no-foo.
+ if(name MATCHES "^no_(.*)")
+ get_property(feature_original_name GLOBAL PROPERTY
+ "QT_FEATURE_ORIGINAL_NAME_${CMAKE_MATCH_1}")
+ if(feature_original_name)
+ list(APPEND corrected_config "no-${feature_original_name}")
+ continue()
+ endif()
+ endif()
+
+ # The config value is no known feature. Add the value as is.
+ list(APPEND corrected_config "${name}")
+ endforeach()
+ set(${out_var} ${corrected_config} PARENT_SCOPE)
+endfunction()
diff --git a/cmake/QtPrlHelpers.cmake b/cmake/QtPrlHelpers.cmake
new file mode 100644
index 0000000000..45bfaedcdf
--- /dev/null
+++ b/cmake/QtPrlHelpers.cmake
@@ -0,0 +1,216 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+# Collects the library dependencies of a target.
+# As well as rcc object file dependencies.
+# This takes into account transitive usage requirements.
+function(qt_collect_libs target libs_out_var rcc_objects_out_var)
+ __qt_internal_walk_libs("${target}" "${libs_out_var}"
+ "${rcc_objects_out_var}" "qt_collect_libs_dict" "collect_libs")
+ set("${libs_out_var}" "${${libs_out_var}}" PARENT_SCOPE)
+
+ set(${rcc_objects_out_var} "${${rcc_objects_out_var}}" PARENT_SCOPE)
+
+endfunction()
+
+# Generate a qmake .prl file for the given target.
+# The install_dir argument is a relative path, for example "lib".
+function(qt_generate_prl_file target install_dir)
+ get_target_property(target_type ${target} TYPE)
+ if(target_type STREQUAL "INTERFACE_LIBRARY")
+ return()
+ endif()
+
+ unset(prl_config)
+ set(is_static FALSE)
+ if(target_type STREQUAL "STATIC_LIBRARY")
+ list(APPEND prl_config static)
+ set(is_static TRUE)
+ elseif(target_type STREQUAL "SHARED_LIBRARY")
+ list(APPEND prl_config shared)
+ endif()
+ if (NOT target_type STREQUAL "INTERFACE_LIBRARY")
+ get_target_property(is_fw ${target} FRAMEWORK)
+ if(is_fw)
+ list(APPEND prl_config lib_bundle)
+ endif()
+ endif()
+ list(JOIN prl_config " " prl_config)
+
+ set(rcc_objects "")
+ set(prl_step1_content_libs "")
+ if(NOT is_static AND WIN32)
+ # Do nothing. Prl files for shared libraries on Windows shouldn't have the libs listed,
+ # as per qt_build_config.prf and the conditional CONFIG+=explicitlib assignment.
+ else()
+ set(prl_libs "")
+ qt_collect_libs(${target} prl_libs prl_rcc_objects)
+ if(prl_libs)
+ set(prl_step1_content_libs "QMAKE_PRL_LIBS_FOR_CMAKE = ${prl_libs}\n")
+ endif()
+ if(prl_rcc_objects)
+ list(APPEND rcc_objects ${prl_rcc_objects})
+ endif()
+ endif()
+
+ if(rcc_objects AND QT_WILL_INSTALL)
+ list(TRANSFORM rcc_objects PREPEND "$$[QT_INSTALL_PREFIX]/")
+ endif()
+
+ # Generate a preliminary .prl file that contains absolute paths to all libraries
+ if(MINGW)
+ # For MinGW, qmake doesn't have a lib prefix in prl files.
+ set(prefix_for_final_prl_name "")
+ else()
+ set(prefix_for_final_prl_name "$<TARGET_FILE_PREFIX:${target}>")
+ endif()
+
+ # For frameworks, the prl file should be placed under the Resources subdir.
+ get_target_property(is_framework ${target} FRAMEWORK)
+ if(is_framework)
+ get_target_property(fw_version ${target} FRAMEWORK_VERSION)
+ string(APPEND prefix_for_final_prl_name "Versions/${fw_version}/Resources/")
+ endif()
+
+ # What follows is a complicated setup for generating configuration-specific
+ # prl files. It has to be this way, because add_custom_command doesn't support
+ # generator expressions in OUTPUT or DEPENDS.
+ # To circumvent that, we create well known file names with file(GENERATE)
+ # with configuration specific content, which are then fed to add_custom_command
+ # that uses these genex-less file names. The actual command will extract the info
+ # from the configuration-specific files, and create a properly named final prl file.
+
+ # The file is named according to a pattern, that is then used in the
+ # add_custom_command.
+ set(prl_step1_name_prefix "preliminary_prl_for_${target}_step1_")
+ set(prl_step1_name_suffix ".prl" )
+ qt_path_join(prl_step1_path
+ "${CMAKE_CURRENT_BINARY_DIR}"
+ "${prl_step1_name_prefix}$<CONFIG>${prl_step1_name_suffix}")
+
+ # Same, except instead of containing the prl contents, it will contain the final prl file
+ # name computed via a generator expression.
+ set(prl_meta_info_name_prefix "preliminary_prl_meta_info_for_${target}_")
+ set(prl_meta_info_name_suffix ".txt")
+ qt_path_join(prl_meta_info_path
+ "${CMAKE_CURRENT_BINARY_DIR}"
+ "${prl_meta_info_name_prefix}$<CONFIG>${prl_meta_info_name_suffix}")
+
+ # The final prl file name that will be embedded in the file above.
+ set(final_prl_file_name "${prefix_for_final_prl_name}$<TARGET_FILE_BASE_NAME:${target}>")
+ if(ANDROID)
+ string(APPEND final_prl_file_name "_${CMAKE_ANDROID_ARCH_ABI}")
+ endif()
+ string(APPEND final_prl_file_name ".prl")
+ qt_path_join(final_prl_file_path "${QT_BUILD_DIR}/${install_dir}" "${final_prl_file_name}")
+
+ # Generate the prl content and its final file name into configuration specific files
+ # whose names we know, and can be used in add_custom_command.
+ set(prl_step1_content
+ "RCC_OBJECTS = ${rcc_objects}
+QMAKE_PRL_TARGET = $<TARGET_LINKER_FILE_NAME:${target}>
+QMAKE_PRL_TARGET_PATH_FOR_CMAKE = $<TARGET_LINKER_FILE:${target}>
+QMAKE_PRL_CONFIG = ${prl_config}
+QMAKE_PRL_VERSION = ${PROJECT_VERSION}
+${prl_step1_content_libs}
+")
+
+ file(GENERATE
+ OUTPUT "${prl_step1_path}"
+ CONTENT "${prl_step1_content}")
+ file(GENERATE
+ OUTPUT "${prl_meta_info_path}"
+ CONTENT
+ "FINAL_PRL_FILE_PATH = ${final_prl_file_path}")
+
+ set(library_prefixes ${CMAKE_SHARED_LIBRARY_PREFIX} ${CMAKE_STATIC_LIBRARY_PREFIX})
+ set(library_suffixes
+ ${CMAKE_SHARED_LIBRARY_SUFFIX}
+ ${CMAKE_EXTRA_SHARED_LIBRARY_SUFFIXES}
+ ${CMAKE_STATIC_LIBRARY_SUFFIX})
+
+ if(QT_GENERATOR_IS_MULTI_CONFIG)
+ set(configs ${CMAKE_CONFIGURATION_TYPES})
+ else()
+ set(configs ${CMAKE_BUILD_TYPE})
+ endif()
+
+ set(qt_lib_dirs "${QT_BUILD_DIR}/${INSTALL_LIBDIR}")
+ if(QT_WILL_INSTALL)
+ list(APPEND qt_lib_dirs
+ "${QT_BUILD_INTERNALS_RELOCATABLE_INSTALL_PREFIX}/${INSTALL_LIBDIR}")
+ endif()
+
+ set(qt_plugin_dirs "${QT_BUILD_DIR}/${INSTALL_PLUGINSDIR}")
+ if(QT_WILL_INSTALL)
+ list(APPEND qt_plugin_dirs
+ "${QT_BUILD_INTERNALS_RELOCATABLE_INSTALL_PREFIX}/${INSTALL_PLUGINSDIR}")
+ endif()
+
+ set(qt_qml_dirs "${QT_BUILD_DIR}/${INSTALL_QMLDIR}")
+ if(QT_WILL_INSTALL)
+ list(APPEND qt_qml_dirs
+ "${QT_BUILD_INTERNALS_RELOCATABLE_INSTALL_PREFIX}/${INSTALL_QMLDIR}")
+ endif()
+
+ foreach(config ${configs})
+ # Output file for dependency tracking, and which will contain the final content.
+ qt_path_join(prl_step2_path
+ "${CMAKE_CURRENT_BINARY_DIR}" "preliminary_prl_for_${target}_step2_${config}.prl")
+
+ # Input dependency names that are constructed for each config manually
+ # (no genexes allowed).
+ qt_path_join(prl_step1_path
+ "${CMAKE_CURRENT_BINARY_DIR}"
+ "${prl_step1_name_prefix}${config}${prl_step1_name_suffix}")
+ qt_path_join(prl_meta_info_path
+ "${CMAKE_CURRENT_BINARY_DIR}"
+ "${prl_meta_info_name_prefix}${config}${prl_meta_info_name_suffix}")
+ if(MSVC)
+ set(link_library_flag "-l")
+ file(TO_CMAKE_PATH "$ENV{LIB};${CMAKE_CXX_IMPLICIT_LINK_DIRECTORIES}" implicit_link_directories)
+ else()
+ set(link_library_flag ${CMAKE_LINK_LIBRARY_FLAG})
+ set(implicit_link_directories ${CMAKE_CXX_IMPLICIT_LINK_DIRECTORIES})
+ endif()
+ add_custom_command(
+ OUTPUT "${prl_step2_path}"
+ DEPENDS "${prl_step1_path}"
+ "${prl_meta_info_path}"
+ "${QT_CMAKE_DIR}/QtFinishPrlFile.cmake"
+ "${QT_CMAKE_DIR}/QtGenerateLibHelpers.cmake"
+ COMMAND ${CMAKE_COMMAND}
+ "-DIN_FILE=${prl_step1_path}"
+ "-DIN_META_FILE=${prl_meta_info_path}"
+ "-DOUT_FILE=${prl_step2_path}"
+ "-DLIBRARY_PREFIXES=${library_prefixes}"
+ "-DLIBRARY_SUFFIXES=${library_suffixes}"
+ "-DLINK_LIBRARY_FLAG=${link_library_flag}"
+ "-DQT_LIB_DIRS=${qt_lib_dirs}"
+ "-DQT_PLUGIN_DIRS=${qt_plugin_dirs}"
+ "-DQT_QML_DIRS=${qt_qml_dirs}"
+ "-DIMPLICIT_LINK_DIRECTORIES=${implicit_link_directories}"
+ -P "${QT_CMAKE_DIR}/QtFinishPrlFile.cmake"
+ VERBATIM
+ COMMENT "Generating prl file for target ${target}"
+ )
+
+ # Tell the target to depend on the preliminary prl file, to ensure the custom command
+ # is executed. As a side-effect, this will also create the final prl file that
+ # is named appropriately. It should not be specified as a BYPRODUCT.
+ # This allows proper per-file dependency tracking, without having to resort on a POST_BUILD
+ # step, which means that relinking would happen as well as transitive rebuilding of any
+ # dependees.
+ # This is inspired by https://gitlab.kitware.com/cmake/cmake/-/issues/20842
+ target_sources(${target} PRIVATE "${prl_step2_path}")
+ endforeach()
+
+ # Installation of the .prl file happens globally elsewhere,
+ # because we have no clue here what the actual file name is.
+ # What we know however, is the directory where the prl file is created.
+ # Save that for later, to install all prl files from that directory.
+ get_property(prl_install_dirs GLOBAL PROPERTY QT_PRL_INSTALL_DIRS)
+ if(NOT install_dir IN_LIST prl_install_dirs)
+ set_property(GLOBAL APPEND PROPERTY QT_PRL_INSTALL_DIRS "${install_dir}")
+ endif()
+endfunction()
diff --git a/cmake/QtProcessConfigureArgs.cmake b/cmake/QtProcessConfigureArgs.cmake
index 55c4fbfe05..53235ee9d9 100644
--- a/cmake/QtProcessConfigureArgs.cmake
+++ b/cmake/QtProcessConfigureArgs.cmake
@@ -1,181 +1,1058 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# This script reads Qt configure arguments from config.opt,
# translates the arguments to CMake arguments and calls CMake.
#
# This file is to be used in CMake script mode with the following variables set:
# OPTFILE: A text file containing the options that were passed to configure
# with one option per line.
+# MODULE_ROOT: The source directory of the module to be built.
+# If empty, qtbase/top-level is assumed.
+# TOP_LEVEL: TRUE, if this is a top-level build.
+
+include(${CMAKE_CURRENT_LIST_DIR}/QtFeatureCommon.cmake)
+include(${CMAKE_CURRENT_LIST_DIR}/QtBuildInformation.cmake)
cmake_policy(SET CMP0007 NEW)
+cmake_policy(SET CMP0057 NEW)
set(cmake_args "")
macro(push)
list(APPEND cmake_args ${ARGN})
endmacro()
-macro(calculate_state)
- set(state ON)
- if(CMAKE_MATCH_1 MATCHES "no-?")
- set(state OFF)
- endif()
-endmacro()
-
macro(pop_path_argument)
list(POP_FRONT configure_args path)
string(REGEX REPLACE "^\"(.*)\"$" "\\1" path "${path}")
file(TO_CMAKE_PATH "${path}" path)
endmacro()
-get_filename_component(source_dir ".." ABSOLUTE BASE_DIR "${CMAKE_CURRENT_LIST_DIR}")
+function(is_non_empty_valid_arg arg value)
+ if(value STREQUAL "")
+ message(FATAL_ERROR "Value supplied to command line option '${arg}' is empty.")
+ elseif(value MATCHES "^-.*")
+ message(FATAL_ERROR
+ "Value supplied to command line option '${arg}' is invalid: ${value}")
+ endif()
+endfunction()
+
+function(warn_in_per_repo_build arg)
+ if(NOT TOP_LEVEL)
+ message(WARNING "Command line option ${arg} is only effective in top-level builds")
+ endif()
+endfunction()
+
+function(is_valid_qt_hex_version arg version)
+ if(NOT version MATCHES "^0x[0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F]$")
+ message(FATAL_ERROR "Incorrect version ${version} specified for ${arg}")
+ endif()
+endfunction()
+
+if("${MODULE_ROOT}" STREQUAL "")
+ # If MODULE_ROOT is not set, assume that we want to build qtbase or top-level.
+ get_filename_component(MODULE_ROOT ".." ABSOLUTE BASE_DIR "${CMAKE_CURRENT_LIST_DIR}")
+ set(qtbase_or_top_level_build TRUE)
+else()
+ # If MODULE_ROOT is passed without drive letter, we try to add it to the path.
+ # The check is necessary; otherwise, `get_filename_component` returns an empty string.
+ if(NOT MODULE_ROOT STREQUAL ".")
+ get_filename_component(MODULE_ROOT "." REALPATH BASE_DIR "${MODULE_ROOT}")
+ endif()
+ set(qtbase_or_top_level_build FALSE)
+endif()
+set(configure_filename "configure.cmake")
+set(commandline_filename "qt_cmdline.cmake")
+if(TOP_LEVEL)
+ get_filename_component(MODULE_ROOT "../.." ABSOLUTE BASE_DIR "${CMAKE_CURRENT_LIST_DIR}")
+ file(GLOB commandline_files "${MODULE_ROOT}/*/${commandline_filename}")
+ if(EXISTS "${MODULE_ROOT}/${commandline_filename}")
+ list(PREPEND commandline_files "${MODULE_ROOT}/${commandline_filename}")
+ endif()
+else()
+ set(commandline_files "${MODULE_ROOT}/${commandline_filename}")
+endif()
file(STRINGS "${OPTFILE}" configure_args)
+
+# list(TRANSFORM ...) unexpectedly removes semicolon escaping in list items. So the list arguments
+# seem to be broken. The 'bracket argument' suppresses this behavior. Right before forwarding
+# command line arguments to the cmake call, 'bracket arguments' are replaced by escaped semicolons
+# back.
+list(TRANSFORM configure_args REPLACE ";" "[[;]]")
+
list(FILTER configure_args EXCLUDE REGEX "^[ \t]*$")
list(TRANSFORM configure_args STRIP)
unset(generator)
-set(auto_detect_generator TRUE)
-unset(build_configs)
+set(auto_detect_compiler TRUE)
+set(auto_detect_generator ${qtbase_or_top_level_build})
+set(no_prefix_option FALSE)
unset(device_options)
-unset(extra_rpaths)
-while(configure_args)
+unset(options_json_file)
+set_property(GLOBAL PROPERTY UNHANDLED_ARGS "")
+while(NOT "${configure_args}" STREQUAL "")
list(POP_FRONT configure_args arg)
- if(arg STREQUAL "-cmake")
- # ignore
- elseif(arg STREQUAL "-cmake-generator")
+ if(arg STREQUAL "-cmake-generator")
list(POP_FRONT configure_args generator)
elseif(arg STREQUAL "-cmake-use-default-generator")
set(auto_detect_generator FALSE)
- elseif(arg STREQUAL "-top-level")
- get_filename_component(source_dir "../.." ABSOLUTE BASE_DIR "${CMAKE_CURRENT_LIST_DIR}")
+ elseif(arg STREQUAL "-no-guess-compiler")
+ set(auto_detect_compiler FALSE)
+ elseif(arg STREQUAL "-list-features")
+ set(list_features TRUE)
+ elseif(arg MATCHES "^-h(elp)?$")
+ set(display_module_help TRUE)
+ elseif(arg STREQUAL "-write-options-for-conan")
+ list(POP_FRONT configure_args options_json_file)
elseif(arg STREQUAL "-skip")
- list(POP_FRONT configure_args qtrepo)
- push("-DBUILD_${qtrepo}=OFF")
- elseif(arg STREQUAL "-opensource")
- # to be done
- elseif(arg STREQUAL "-commercial")
- # to be done
- elseif(arg STREQUAL "-confirm-license")
- # to be done
- elseif(arg MATCHES "^-(no)?make")
- calculate_state()
- list(POP_FRONT configure_args component)
- if(component STREQUAL "tests")
- push(-DBUILD_TESTING=${state})
- elseif(component STREQUAL "examples")
- push(-DBUILD_EXAMPLES=${state})
- else()
- string(TOUPPER "${component}" uc_component)
- push(-DQT_NO_MAKE_${uc_component}=${state})
- endif()
- elseif(arg MATCHES "^-(no-)?feature")
- calculate_state()
- list(POP_FRONT configure_args feature)
- push("-DFEATURE_${feature}=${state}")
- elseif(arg MATCHES "^-(no-)?pch")
- calculate_state()
- push("-DBUILD_WITH_PCH=${state}")
- elseif(arg MATCHES "^-system-(.*)")
- list(POP_FRONT configure_args lib)
- push("-DFEATURE_system_${lib}=ON")
- elseif(arg MATCHES "^-qt-(.*)")
- list(POP_FRONT configure_args lib)
- push("-DFEATURE_system_${lib}=OFF")
- elseif(arg MATCHES "^-sanitize=(.*)")
- push("-DECM_ENABLE_SANITIZERS=${CMAKE_MATCH_1}")
- elseif(arg STREQUAL "-ccache")
- push(-DQT_USE_CCACHE=ON)
- elseif(arg STREQUAL "-developer-build")
- push(-DFEATURE_developer_build=ON)
- elseif(arg STREQUAL "-prefix")
- pop_path_argument()
- push("-DCMAKE_INSTALL_PREFIX=${path}")
- elseif(arg STREQUAL "-extprefix")
- pop_path_argument()
- push("-DCMAKE_STAGING_PREFIX=${path}")
- elseif(arg STREQUAL "-hostprefix")
- message(FATAL_ERROR "${arg} is not supported in the CMake build.")
- elseif(arg STREQUAL "-external-hostbindir")
- # This points to the bin directory of the Qt installation.
- # This can be multiple levels deep and we cannot deduce the QT_HOST_PATH safely.
- message(FATAL_ERROR "${arg} is not supported anymore. Use -qt-host-path <dir> instead.")
+ warn_in_per_repo_build("${arg}")
+ list(POP_FRONT configure_args qtrepos)
+ is_non_empty_valid_arg("${arg}" "${qtrepos}")
+ list(TRANSFORM qtrepos REPLACE "," ";")
+ foreach(qtrepo IN LISTS qtrepos)
+ push("-DBUILD_${qtrepo}=OFF")
+ endforeach()
+ elseif(arg STREQUAL "-skip-tests")
+ list(POP_FRONT configure_args qtrepos)
+ is_non_empty_valid_arg("${arg}" "${qtrepos}")
+ list(TRANSFORM qtrepos REPLACE "," ";")
+ foreach(qtrepo IN LISTS qtrepos)
+ push("-DQT_BUILD_TESTS_PROJECT_${qtrepo}=OFF")
+ endforeach()
+ elseif(arg STREQUAL "-skip-examples")
+ list(POP_FRONT configure_args qtrepos)
+ is_non_empty_valid_arg("${arg}" "${qtrepos}")
+ list(TRANSFORM qtrepos REPLACE "," ";")
+ foreach(qtrepo IN LISTS qtrepos)
+ push("-DQT_BUILD_EXAMPLES_PROJECT_${qtrepo}=OFF")
+ endforeach()
+ elseif(arg STREQUAL "-submodules")
+ warn_in_per_repo_build("${arg}")
+ list(POP_FRONT configure_args submodules)
+ is_non_empty_valid_arg("${arg}" "${submodules}")
+ list(TRANSFORM submodules REPLACE "," "[[;]]")
+ push("-DQT_BUILD_SUBMODULES=${submodules}")
elseif(arg STREQUAL "-qt-host-path")
pop_path_argument()
push("-DQT_HOST_PATH=${path}")
- elseif(arg MATCHES "^-host.*dir")
- message(FATAL_ERROR "${arg} is not supported anymore.")
- elseif(arg MATCHES
- "^-(bin|lib|archdata|libexec|qml|data|doc|translation|sysconf|examples|tests)dir$")
- string(TOUPPER "${CMAKE_MATCH_1}" type)
- list(POP_FRONT configure_args dir)
- push("-DINSTALL_${type}DIR=${dir}")
- elseif(arg STREQUAL "-plugindir")
- list(POP_FRONT configure_args dir)
- push("-DINSTALL_PLUGINSDIR=${dir}")
- elseif(arg STREQUAL "-release")
- set(build_configs "Release")
- elseif(arg STREQUAL "-debug")
- set(build_configs "Debug")
- elseif(arg STREQUAL "-debug-and-release")
- set(build_configs Debug Release)
- elseif(arg STREQUAL "-force-debug-info")
- set(force_debug_info ON)
- elseif(arg STREQUAL "-shared")
- push("-DBUILD_SHARED_LIBS=ON")
- elseif(arg STREQUAL "-static")
- push("-DBUILD_SHARED_LIBS=OFF")
- elseif(arg MATCHES "^-(no-)?framework")
- calculate_state()
- push("-DFEATURE_framework=${state}")
- elseif(arg MATCHES "^-x?platform$")
- list(POP_FRONT configure_args mkspec)
- push("-DQT_QMAKE_TARGET_MKSPEC=${mkspec}")
- elseif(arg STREQUAL "-device")
- list(POP_FRONT configure_args mkspec)
- push("-DQT_QMAKE_TARGET_MKSPEC=devices/${mkspec}")
- elseif(arg STREQUAL "-device-option")
- list(POP_FRONT configure_args opt)
- list(APPEND device_options "${opt}")
- elseif(arg STREQUAL "-qtnamespace")
- list(POP_FRONT configure_args namespace)
- push("-DQT_NAMESPACE=${namespace}")
- elseif(arg STREQUAL "-c++std")
- list(POP_FRONT configure_args edition)
- string(REGEX REPLACE "^c\\+\\+" "" edition "${edition}")
- push("-DCMAKE_CXX_STANDARD=${edition}")
- elseif(arg STREQUAL "-rpath")
+ elseif(arg STREQUAL "-hostdatadir")
pop_path_argument()
- list(APPEND extra_rpaths "${path}")
+ if(NOT path MATCHES "(^|/)mkspecs$")
+ string(APPEND path "/mkspecs")
+ endif()
+ push("-DINSTALL_MKSPECSDIR=${path}")
+ elseif(arg STREQUAL "-developer-build")
+ set(developer_build TRUE)
+ push("-DFEATURE_developer_build=ON")
+ elseif(arg STREQUAL "-no-prefix")
+ set(no_prefix_option TRUE)
+ push("-DFEATURE_no_prefix=ON")
+ elseif(arg STREQUAL "-cmake-file-api")
+ set(cmake_file_api TRUE)
+ elseif(arg STREQUAL "-no-cmake-file-api")
+ set(cmake_file_api FALSE)
+ elseif(arg STREQUAL "-verbose")
+ list(APPEND cmake_args "--log-level=STATUS")
+ elseif(arg STREQUAL "-disable-deprecated-up-to")
+ list(POP_FRONT configure_args version)
+ is_valid_qt_hex_version("${arg}" "${version}")
+ push("-DQT_DISABLE_DEPRECATED_UP_TO=${version}")
elseif(arg STREQUAL "--")
# Everything after this argument will be passed to CMake verbatim.
- push(${configure_args})
+ list(APPEND cmake_args "${configure_args}")
break()
else()
- message(FATAL_ERROR "Unknown configure argument: ${arg}")
+ set_property(GLOBAL APPEND PROPERTY UNHANDLED_ARGS "${arg}")
+ endif()
+endwhile()
+
+# Read the specified manually generator value from CMake command line.
+# The '-cmake-generator' argument has higher priority than CMake command line.
+if(NOT generator)
+ set(is_next_arg_generator_name FALSE)
+ foreach(arg IN LISTS cmake_args)
+ if(is_next_arg_generator_name)
+ set(is_next_arg_generator_name FALSE)
+ if(NOT arg MATCHES "^-.*")
+ set(generator "${arg}")
+ set(auto_detect_generator FALSE)
+ endif()
+ elseif(arg MATCHES "^-G(.*)")
+ set(generator "${CMAKE_MATCH_1}")
+ if(generator)
+ set(auto_detect_generator FALSE)
+ else()
+ set(is_next_arg_generator_name TRUE)
+ endif()
+ endif()
+ endforeach()
+endif()
+
+# Attempt to detect the generator type, either single or multi-config
+if("${generator}" STREQUAL "Xcode"
+ OR "${generator}" STREQUAL "Ninja Multi-Config"
+ OR "${generator}" MATCHES "^Visual Studio")
+ set(multi_config ON)
+else()
+ set(multi_config OFF)
+endif()
+
+# Tell the build system we are configuring via the configure script so we can act on that.
+# The cache variable is unset at the end of configuration.
+push("-DQT_INTERNAL_CALLED_FROM_CONFIGURE:BOOL=TRUE")
+
+if(FRESH_REQUESTED)
+ push("-DQT_INTERNAL_FRESH_REQUESTED:BOOL=TRUE")
+ if(CMAKE_VERSION VERSION_GREATER_EQUAL "3.24")
+ push("--fresh")
+ else()
+ file(REMOVE_RECURSE "${CMAKE_BINARY_DIR}/CMakeCache.txt"
+ "${CMAKE_BINARY_DIR}/CMakeFiles")
+ endif()
+endif()
+
+####################################################################################################
+# Define functions/macros that are called in configure.cmake files
+#
+# Every function that's called in a configure.cmake file must be defined here.
+# Most are empty stubs.
+####################################################################################################
+
+set_property(GLOBAL PROPERTY COMMANDLINE_KNOWN_FEATURES "")
+
+function(qt_feature feature)
+ cmake_parse_arguments(arg "" "PURPOSE;SECTION;" "" ${ARGN})
+ set_property(GLOBAL APPEND PROPERTY COMMANDLINE_KNOWN_FEATURES "${feature}")
+ set_property(GLOBAL PROPERTY COMMANDLINE_FEATURE_PURPOSE_${feature} "${arg_PURPOSE}")
+ set_property(GLOBAL PROPERTY COMMANDLINE_FEATURE_SECTION_${feature} "${arg_SECTION}")
+endfunction()
+
+function(find_package)
+ message(FATAL_ERROR "find_package must not be used directly in configure.cmake. "
+ "Use qt_find_package or guard the call with an if(NOT QT_CONFIGURE_RUNNING) block.")
+endfunction()
+
+macro(defstub name)
+ function(${name})
+ endfunction()
+endmacro()
+
+defstub(qt_add_qmake_lib_dependency)
+defstub(qt_config_compile_test)
+defstub(qt_config_compile_test_machine_tuple)
+defstub(qt_config_compile_test_x86simd)
+defstub(qt_config_compiler_supports_flag_test)
+defstub(qt_config_linker_supports_flag_test)
+defstub(qt_configure_add_report_entry)
+defstub(qt_configure_add_summary_build_mode)
+defstub(qt_configure_add_summary_build_parts)
+defstub(qt_configure_add_summary_build_type_and_config)
+defstub(qt_configure_add_summary_entry)
+defstub(qt_configure_add_summary_section)
+defstub(qt_configure_end_summary_section)
+defstub(qt_extra_definition)
+defstub(qt_feature_config)
+defstub(qt_feature_definition)
+defstub(qt_find_package)
+defstub(set_package_properties)
+defstub(qt_qml_find_python)
+defstub(qt_set01)
+defstub(qt_internal_check_if_linker_is_available)
+
+####################################################################################################
+# Define functions/macros that are called in qt_cmdline.cmake files
+####################################################################################################
+
+unset(commandline_known_options)
+unset(commandline_custom_handlers)
+set(commandline_nr_of_prefixes 0)
+
+macro(qt_commandline_subconfig subconfig)
+ list(APPEND commandline_subconfigs "${subconfig}")
+endmacro()
+
+macro(qt_commandline_custom handler)
+ list(APPEND commandline_custom_handlers ${handler})
+endmacro()
+
+function(qt_commandline_option name)
+ set(options CONTROLS_FEATURE)
+ set(oneValueArgs TYPE NAME VALUE)
+ set(multiValueArgs VALUES MAPPING)
+ cmake_parse_arguments(arg "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
+
+ set(commandline_known_options "${commandline_known_options};${name}" PARENT_SCOPE)
+ set(commandline_option_${name} "${arg_TYPE}" PARENT_SCOPE)
+ set(input_name ${name})
+ if(NOT "${arg_NAME}" STREQUAL "")
+ set(input_name ${arg_NAME})
+ set(commandline_option_${name}_variable "${arg_NAME}" PARENT_SCOPE)
+ endif()
+ set(mapping_type "${arg_TYPE}")
+ if(arg_CONTROLS_FEATURE)
+ set(mapping_type "boolean")
+ endif()
+ set_property(GLOBAL PROPERTY INPUTTYPE_${input_name} "${mapping_type}")
+ if(NOT "${arg_VALUE}" STREQUAL "")
+ set(commandline_option_${name}_value "${arg_VALUE}" PARENT_SCOPE)
+ endif()
+ if(arg_VALUES)
+ set(commandline_option_${name}_values ${arg_VALUES} PARENT_SCOPE)
+ elseif(arg_MAPPING)
+ set(commandline_option_${name}_mapping ${arg_MAPPING} PARENT_SCOPE)
+ endif()
+endfunction()
+
+# Add the common command line options for every qt repo.
+macro(qt_add_common_commandline_options)
+ qt_commandline_option(headersclean TYPE boolean)
+endmacro()
+
+function(qt_commandline_prefix arg var)
+ set(idx ${commandline_nr_of_prefixes})
+ set(commandline_prefix_${idx} "${arg}" "${var}" PARENT_SCOPE)
+ math(EXPR n "${commandline_nr_of_prefixes} + 1")
+ set(commandline_nr_of_prefixes ${n} PARENT_SCOPE)
+endfunction()
+
+# Check the following variable in configure.cmake files to guard code that is not covered by the
+# stub functions above.
+set(QT_CONFIGURE_RUNNING ON)
+
+
+####################################################################################################
+# Load qt_cmdline.cmake files
+####################################################################################################
+
+qt_add_common_commandline_options()
+
+while(commandline_files)
+ list(POP_FRONT commandline_files commandline_file)
+ get_filename_component(commandline_file_directory "${commandline_file}" DIRECTORY)
+ set(configure_file "${commandline_file_directory}/${configure_filename}")
+ unset(commandline_subconfigs)
+ if(EXISTS "${configure_file}")
+ include("${configure_file}")
+ endif()
+ if(EXISTS "${commandline_file}")
+ include("${commandline_file}")
+ endif()
+
+ if(commandline_subconfigs)
+ list(TRANSFORM commandline_subconfigs PREPEND "${commandline_file_directory}/")
+ list(TRANSFORM commandline_subconfigs APPEND "/${commandline_filename}")
+ list(PREPEND commandline_files "${commandline_subconfigs}")
endif()
endwhile()
-if(force_debug_info)
+get_property(commandline_known_features GLOBAL PROPERTY COMMANDLINE_KNOWN_FEATURES)
+
+####################################################################################################
+# Process the data from the qt_cmdline.cmake files
+####################################################################################################
+
+function(qtConfAddNote)
+ message(${ARGV})
+endfunction()
+
+function(qtConfAddWarning)
+ message(WARNING ${ARGV})
+endfunction()
+
+function(qtConfAddError)
+ message(FATAL_ERROR ${ARGV})
+endfunction()
+
+set_property(GLOBAL PROPERTY CONFIG_INPUTS "")
+
+function(qtConfCommandlineSetInput name val)
+ if(NOT "${commandline_option_${name}_variable}" STREQUAL "")
+ set(name "${commandline_option_${name}_variable}")
+ endif()
+ if(NOT "${INPUT_${name}}" STREQUAL "")
+ set(oldval "${INPUT_${name}}")
+ if("${oldval}" STREQUAL "${val}")
+ qtConfAddNote("Option '${name}' with value '${val}' was specified twice")
+ else()
+ qtConfAddNote("Overriding option '${name}' with '${val}' (was: '${oldval}')")
+ endif()
+ endif()
+
+ set_property(GLOBAL PROPERTY INPUT_${name} "${val}")
+ set_property(GLOBAL APPEND PROPERTY CONFIG_INPUTS ${name})
+endfunction()
+
+function(qtConfCommandlineAppendInput name val)
+ get_property(oldval GLOBAL PROPERTY INPUT_${name})
+ if(NOT "${oldval}" STREQUAL "")
+ string(PREPEND val "${oldval};")
+ endif()
+ qtConfCommandlineSetInput(${name} "${val}")
+endfunction()
+
+function(qtConfCommandlineSetInputType input_name type_name)
+ set_property(GLOBAL PROPERTY INPUTTYPE_${input_name} "${type_name}")
+endfunction()
+
+function(qtConfCommandlineSetBooleanInput name val)
+ qtConfCommandlineSetInput(${name} ${val})
+ qtConfCommandlineSetInputType(${name} boolean)
+endfunction()
+
+function(qtConfCommandlineEnableFeature name)
+ qtConfCommandlineSetBooleanInput(${name} yes)
+endfunction()
+
+function(qtConfCommandlineDisableFeature name)
+ qtConfCommandlineSetBooleanInput(${name} no)
+endfunction()
+
+function(qtConfValidateValue opt val out_var)
+ set(${out_var} TRUE PARENT_SCOPE)
+
+ set(valid_values ${commandline_option_${arg}_values})
+ list(LENGTH valid_values n)
+ if(n EQUAL 0)
+ return()
+ endif()
+
+ foreach(v ${valid_values})
+ if(val STREQUAL v)
+ return()
+ endif()
+ endforeach()
+
+ set(${out_var} FALSE PARENT_SCOPE)
+ list(JOIN valid_values " " valid_values_str)
+ qtConfAddError("Invalid value '${val}' supplied to command line option '${opt}'."
+ "\nAllowed values: ${valid_values_str}\n")
+endfunction()
+
+function(qt_commandline_mapped_enum_value opt key out_var)
+ unset(result)
+ set(mapping ${commandline_option_${opt}_mapping})
+ while(mapping)
+ list(POP_FRONT mapping mapping_key)
+ list(POP_FRONT mapping mapping_value)
+ if(mapping_key STREQUAL key)
+ set(result "${mapping_value}")
+ break()
+ endif()
+ endwhile()
+ set(${out_var} "${result}" PARENT_SCOPE)
+endfunction()
+
+function(qtConfHasNextCommandlineArg out_var)
+ get_property(args GLOBAL PROPERTY UNHANDLED_ARGS)
+ list(LENGTH args n)
+ if(n GREATER 0)
+ set(result TRUE)
+ else()
+ set(result FALSE)
+ endif()
+ set(${out_var} ${result} PARENT_SCOPE)
+endfunction()
+
+function(qtConfPeekNextCommandlineArg out_var)
+ get_property(args GLOBAL PROPERTY UNHANDLED_ARGS)
+ list(GET args 0 result)
+ set(${out_var} ${result} PARENT_SCOPE)
+endfunction()
+
+function(qtConfGetNextCommandlineArg out_var)
+ get_property(args GLOBAL PROPERTY UNHANDLED_ARGS)
+ list(POP_FRONT args result)
+ set_property(GLOBAL PROPERTY UNHANDLED_ARGS ${args})
+ set(${out_var} ${result} PARENT_SCOPE)
+endfunction()
+
+function(qt_commandline_boolean arg val nextok)
+ if("${val}" STREQUAL "")
+ set(val "yes")
+ endif()
+ if(NOT val STREQUAL "yes" AND NOT val STREQUAL "no")
+ message(FATAL_ERROR "Invalid value '${val}' given for boolean command line option '${arg}'.")
+ endif()
+ qtConfCommandlineSetInput("${arg}" "${val}")
+endfunction()
+
+function(qt_commandline_string arg val nextok)
+ if(nextok)
+ qtConfGetNextCommandlineArg(val)
+ if("${val}" MATCHES "^-")
+ qtConfAddError("No value supplied to command line options '${opt}'.")
+ endif()
+ endif()
+ qtConfValidateValue("${opt}" "${val}" success)
+ if(success)
+ qtConfCommandlineSetInput("${opt}" "${val}")
+ endif()
+endfunction()
+
+function(qt_commandline_optionalString arg val nextok)
+ if("${val}" STREQUAL "")
+ if(nextok)
+ qtConfPeekNextCommandlineArg(val)
+ endif()
+ if(val MATCHES "^-.*|[A-Z0-9_+]=.*" OR val STREQUAL "")
+ set(val "yes")
+ else()
+ qtConfGetNextCommandlineArg(val)
+ endif()
+ endif()
+ qtConfValidateValue("${arg}" "${val}" success)
+ if(success)
+ qtConfCommandlineSetInput("${arg}" "${val}")
+ endif()
+endfunction()
+
+function(qt_commandline_addString arg val nextok)
+ if("${val}" STREQUAL "" AND nextok)
+ qtConfGetNextCommandlineArg(val)
+ endif()
+ if(val MATCHES "^-.*" OR val STREQUAL "")
+ qtConfAddError("No value supplied to command line option '${arg}'.")
+ endif()
+ qtConfValidateValue("${arg}" "${val}" success)
+ if(success)
+ if(DEFINED command_line_option_${arg}_variable)
+ set(arg ${command_line_option_${arg}_variable})
+ endif()
+ set_property(GLOBAL APPEND PROPERTY "INPUT_${arg}" "${val}")
+ set_property(GLOBAL APPEND PROPERTY CONFIG_INPUTS ${arg})
+ endif()
+endfunction()
+
+function(qt_commandline_enum arg val nextok)
+ if("${val}" STREQUAL "")
+ set(val "yes")
+ endif()
+ unset(mapped)
+ if(DEFINED "commandline_option_${arg}_mapping")
+ qt_commandline_mapped_enum_value("${arg}" "${val}" mapped)
+ elseif(DEFINED "commandline_option_${arg}_values")
+ if(val IN_LIST commandline_option_${arg}_values)
+ set(mapped ${val})
+ endif()
+ endif()
+ if("${mapped}" STREQUAL "")
+ qtConfAddError("Invalid value '${val}' supplied to command line option '${arg}'.")
+ endif()
+ qtConfCommandlineSetInput("${arg}" "${mapped}")
+endfunction()
+
+function(qt_commandline_void arg val nextok)
+ if(NOT "${val}" STREQUAL "")
+ qtConfAddError("Command line option '${arg}' expects no argument ('${val}' given).")
+ endif()
+ if(DEFINED commandline_option_${arg}_value)
+ set(val ${commandline_option_${arg}_value})
+ endif()
+ if("${val}" STREQUAL "")
+ set(val yes)
+ endif()
+ qtConfCommandlineSetInput("${arg}" "${val}")
+endfunction()
+
+function(qt_call_function func)
+ set(call_code "${func}(")
+ math(EXPR n "${ARGC} - 1")
+ foreach(i RANGE 1 ${n})
+ string(APPEND call_code "\"${ARGV${i}}\" ")
+ endforeach()
+ string(APPEND call_code ")")
+ string(REPLACE "\\" "\\\\" call_code "${call_code}")
+ if(${CMAKE_VERSION} VERSION_LESS "3.18.0")
+ set(incfile qt_tmp_func_call.cmake)
+ file(WRITE "${incfile}" "${call_code}")
+ include(${incfile})
+ file(REMOVE "${incfile}")
+ else()
+ cmake_language(EVAL CODE "${call_code}")
+ endif()
+endfunction()
+
+if(display_module_help)
+ message([[
+Options:
+ -help, -h ............ Display this help screen
+
+ -feature-<feature> ... Enable <feature>
+ -no-feature-<feature> Disable <feature> [none]
+ -list-features ....... List available features. Note that some features
+ have dedicated command line options as well.
+]])
+
+ set(help_file "${MODULE_ROOT}/config_help.txt")
+ if(EXISTS "${help_file}")
+ file(READ "${help_file}" content)
+ message("${content}")
+ endif()
+
+ return()
+endif()
+
+if(list_features)
+ unset(lines)
+ foreach(feature ${commandline_known_features})
+ get_property(section GLOBAL PROPERTY COMMANDLINE_FEATURE_SECTION_${feature})
+ get_property(purpose GLOBAL PROPERTY COMMANDLINE_FEATURE_PURPOSE_${feature})
+ if(purpose)
+ if(NOT "${section}" STREQUAL "")
+ string(APPEND section ": ")
+ endif()
+ qt_configure_get_padded_string("${feature}" "${section}${purpose}" line
+ PADDING_LENGTH 25 MIN_PADDING 1)
+ list(APPEND lines "${line}")
+ endif()
+ endforeach()
+ list(SORT lines)
+ list(JOIN lines "\n" lines)
+ message("${lines}")
+ return()
+endif()
+
+function(write_options_json_file)
+ if(qtbase_or_top_level_build)
+ # Add options that are handled directly by this script.
+ qt_commandline_option(qt-host-path TYPE string)
+ qt_commandline_option(no-guess-compiler TYPE void)
+ endif()
+
+ set(indent " ")
+ set(content
+ "{"
+ "${indent}\"options\": {")
+ string(APPEND indent " ")
+ list(LENGTH commandline_known_options commandline_known_options_length)
+ set(i 1)
+ foreach(opt ${commandline_known_options})
+ list(APPEND content "${indent}\"${opt}\": {")
+ string(APPEND indent " ")
+ list(APPEND content "${indent}\"type\": \"${commandline_option_${opt}}\",")
+ if(NOT "${commandline_option_${opt}_values}" STREQUAL "")
+ set(values "${commandline_option_${opt}_values}")
+ list(TRANSFORM values PREPEND "\"")
+ list(TRANSFORM values APPEND "\"")
+ list(JOIN values ", " values)
+ list(APPEND content "${indent}\"values\": [${values}]")
+ elseif(NOT "${commandline_option_${opt}_mapping}" STREQUAL "")
+ list(LENGTH commandline_option_${opt}_mapping last)
+ math(EXPR last "${last} - 1")
+ set(values "")
+ list(APPEND content "${indent}\"values\": [")
+ foreach(k RANGE 0 "${last}" 2)
+ list(GET commandline_option_${opt}_mapping ${k} value)
+ list(APPEND values ${value})
+ endforeach()
+ list(TRANSFORM values PREPEND "\"")
+ list(TRANSFORM values APPEND "\"")
+ list(JOIN values ", " values)
+ list(APPEND content
+ "${indent} ${values}"
+ "${indent}]")
+ else()
+ list(APPEND content "${indent}\"values\": []")
+ endif()
+ string(SUBSTRING "${indent}" 4 -1 indent)
+ math(EXPR i "${i} + 1")
+ if(i LESS commandline_known_options_length)
+ list(APPEND content "${indent}},")
+ else()
+ list(APPEND content "${indent}}")
+ endif()
+ endforeach()
+ string(SUBSTRING "${indent}" 4 -1 indent)
+
+ set(features ${commandline_known_features})
+ list(TRANSFORM features PREPEND "\"")
+ list(TRANSFORM features APPEND "\"")
+ list(JOIN features ", " features)
+
+ list(APPEND content
+ "${indent}},"
+ "${indent}\"features\": [${features}]"
+ "}")
+ string(REPLACE ";" "\n" content "${content}")
+ file(WRITE "${options_json_file}" "${content}")
+endfunction()
+
+if(options_json_file)
+ write_options_json_file()
+ return()
+endif()
+
+set(cmake_var_assignments)
+
+while(1)
+ qtConfHasNextCommandlineArg(has_next)
+ if(NOT has_next)
+ break()
+ endif()
+ qtConfGetNextCommandlineArg(arg)
+
+ set(handled FALSE)
+ foreach(func ${commandline_custom_handlers})
+ qt_call_function("qt_commandline_${func}" handled "${arg}")
+ if(handled)
+ break()
+ endif()
+ endforeach()
+ if(handled)
+ continue()
+ endif()
+
+ # Handle variable assignments
+ if(arg MATCHES "^([a-zA-Z0-9_][a-zA-Z0-9_-]*)=(.*)")
+ list(APPEND cmake_var_assignments "${arg}")
+ continue()
+ endif()
+
+ # parse out opt and val
+ set(nextok FALSE)
+ if(arg MATCHES "^--?enable-(.*)")
+ set(opt "${CMAKE_MATCH_1}")
+ set(val "yes")
+ # Handle builtin [-no]-feature-xxx
+ elseif(arg MATCHES "^--?(no-)?feature-(.*)")
+ set(opt "${CMAKE_MATCH_2}")
+ if(NOT opt IN_LIST commandline_known_features)
+ qtConfAddError("Enabling/Disabling unknown feature '${opt}'.")
+ endif()
+ if("${CMAKE_MATCH_1}" STREQUAL "")
+ set(val "ON")
+ else()
+ set(val "OFF")
+ endif()
+ qt_feature_normalize_name("${opt}" normalized_feature_name)
+ push(-DFEATURE_${normalized_feature_name}=${val})
+ continue()
+ elseif(arg MATCHES "^--?(disable|no)-(.*)")
+ set(opt "${CMAKE_MATCH_2}")
+ set(val "no")
+ elseif(arg MATCHES "^--([^=]+)=(.*)")
+ set(opt "${CMAKE_MATCH_1}")
+ set(val "${CMAKE_MATCH_2}")
+ elseif(arg MATCHES "^--(.*)")
+ set(opt "${CMAKE_MATCH_1}")
+ unset(val)
+ elseif(arg MATCHES "^-(.*)")
+ set(nextok TRUE)
+ set(opt "${CMAKE_MATCH_1}")
+ unset(val)
+ if(NOT DEFINED commandline_option_${opt} AND opt MATCHES "(qt|system)-(.*)")
+ set(opt "${CMAKE_MATCH_2}")
+ set(val "${CMAKE_MATCH_1}")
+ endif()
+ else()
+ qtConfAddError("Invalid command line parameter '${arg}'.")
+ endif()
+
+ set(type ${commandline_option_${opt}})
+ if("${type}" STREQUAL "")
+ # No match in the regular options, try matching the prefixes
+ math(EXPR n "${commandline_nr_of_prefixes} - 1")
+ foreach(i RANGE ${n})
+ list(GET commandline_prefix_${i} 0 pfx)
+ if(arg MATCHES "^-${pfx}(.*)")
+ list(GET commandline_prefix_${i} 1 opt)
+ set(val "${CMAKE_MATCH_1}")
+ set(type addString)
+ break()
+ endif()
+ endforeach()
+ endif()
+
+ if("${type}" STREQUAL "")
+ qtConfAddError("Unknown command line option '${arg}'.")
+ endif()
+
+ if(NOT COMMAND "qt_commandline_${type}")
+ qtConfAddError("Unknown type '${type}' for command line option '${opt}'.")
+ endif()
+ qt_call_function("qt_commandline_${type}" "${opt}" "${val}" "${nextok}")
+endwhile()
+
+####################################################################################################
+# Translate some of the INPUT_xxx values to CMake arguments
+####################################################################################################
+
+# Turn the global properties into proper variables
+get_property(config_inputs GLOBAL PROPERTY CONFIG_INPUTS)
+list(REMOVE_DUPLICATES config_inputs)
+foreach(var ${config_inputs})
+ get_property(INPUT_${var} GLOBAL PROPERTY INPUT_${var})
+ if("${commandline_input_type}" STREQUAL "")
+ get_property(commandline_input_${var}_type GLOBAL PROPERTY INPUTTYPE_${var})
+ endif()
+endforeach()
+
+macro(drop_input name)
+ list(REMOVE_ITEM config_inputs ${name})
+endmacro()
+
+macro(translate_boolean_input name cmake_var)
+ if("${INPUT_${name}}" STREQUAL "yes")
+ push("-D${cmake_var}=ON")
+ drop_input(${name})
+ elseif("${INPUT_${name}}" STREQUAL "no")
+ push("-D${cmake_var}=OFF")
+ drop_input(${name})
+ endif()
+endmacro()
+
+macro(translate_string_input name cmake_var)
+ if(DEFINED INPUT_${name})
+ push("-D${cmake_var}=${INPUT_${name}}")
+ drop_input(${name})
+ endif()
+endmacro()
+
+macro(translate_path_input name cmake_var)
+ if(DEFINED INPUT_${name})
+ set(path "${INPUT_${name}}")
+ string(REGEX REPLACE "^\"(.*)\"$" "\\1" path "${path}")
+ file(TO_CMAKE_PATH "${path}" path)
+ push("-D${cmake_var}=${path}")
+ drop_input(${name})
+ endif()
+endmacro()
+
+macro(translate_list_input name cmake_var)
+ if(DEFINED INPUT_${name})
+ list(JOIN INPUT_${name} "[[;]]" value)
+ list(APPEND cmake_args "-D${cmake_var}=${value}")
+ drop_input(${name})
+ endif()
+endmacro()
+
+# Check whether to guess the compiler for the given language.
+#
+# Sets ${out_var} to FALSE if one of the following holds:
+# - the environment variable ${env_var} is non-empty
+# - the CMake variable ${cmake_var} is set on the command line
+#
+# Otherwise, ${out_var} is set to TRUE.
+function(check_whether_to_guess_compiler out_var env_var cmake_var)
+ set(result TRUE)
+ if(NOT "$ENV{${env_var}}" STREQUAL "")
+ set(result FALSE)
+ else()
+ set(filtered_args ${cmake_args})
+ list(FILTER filtered_args INCLUDE REGEX "^(-D)?${cmake_var}=")
+ if(NOT "${filtered_args}" STREQUAL "")
+ set(result FALSE)
+ endif()
+ endif()
+ set(${out_var} ${result} PARENT_SCOPE)
+endfunction()
+
+# Try to guess the mkspec from the -platform configure argument.
+function(guess_compiler_from_mkspec)
+ if(NOT auto_detect_compiler)
+ return()
+ endif()
+
+ check_whether_to_guess_compiler(guess_c_compiler CC CMAKE_C_COMPILER)
+ check_whether_to_guess_compiler(guess_cxx_compiler CXX CMAKE_CXX_COMPILER)
+ if(NOT guess_c_compiler AND NOT guess_cxx_compiler)
+ return()
+ endif()
+
+ string(REGEX MATCH "(^|;)-DQT_QMAKE_TARGET_MKSPEC=\([^;]+\)" m "${cmake_args}")
+ set(mkspec ${CMAKE_MATCH_2})
+ set(c_compiler "")
+ set(cxx_compiler "")
+ if(mkspec MATCHES "-clang-msvc$")
+ set(c_compiler "clang-cl")
+ set(cxx_compiler "clang-cl")
+ elseif(mkspec MATCHES "-clang(-|$)" AND NOT mkspec MATCHES "android")
+ set(c_compiler "clang")
+ set(cxx_compiler "clang++")
+ elseif(mkspec MATCHES "-msvc(-|$)")
+ set(c_compiler "cl")
+ set(cxx_compiler "cl")
+ endif()
+ if(guess_c_compiler AND NOT c_compiler STREQUAL "")
+ push("-DCMAKE_C_COMPILER=${c_compiler}")
+ endif()
+ if(guess_cxx_compiler AND NOT cxx_compiler STREQUAL "")
+ push("-DCMAKE_CXX_COMPILER=${cxx_compiler}")
+ endif()
+ if(mkspec MATCHES "-libc\\+\\+$")
+ push("-DFEATURE_stdlib_libcpp=ON")
+ endif()
+ set(cmake_args "${cmake_args}" PARENT_SCOPE)
+endfunction()
+
+function(check_qt_build_parts type)
+ set(input "INPUT_${type}")
+ set(buildFlag "TRUE")
+ if("${type}" STREQUAL "nomake")
+ set(buildFlag "FALSE")
+ endif()
+
+ list(APPEND knownParts "tests" "examples" "benchmarks" "manual-tests" "minimal-static-tests")
+
+ foreach(part ${${input}})
+ if(part IN_LIST knownParts)
+ qt_feature_normalize_name("${part}" partUpperCase)
+ string(TOUPPER "${partUpperCase}" partUpperCase)
+ push("-DQT_BUILD_${partUpperCase}=${buildFlag}")
+ continue()
+ elseif("${part}" STREQUAL "tools" AND "${type}" STREQUAL "make")
+ # default true ignored
+ continue()
+ endif()
+ qtConfAddWarning("'-${type} ${part}' is not implemented yet.")
+ endforeach()
+ set(cmake_args "${cmake_args}" PARENT_SCOPE)
+endfunction()
+
+drop_input(commercial)
+drop_input(confirm-license)
+translate_boolean_input(precompile_header BUILD_WITH_PCH)
+translate_boolean_input(unity_build QT_UNITY_BUILD)
+translate_string_input(unity_build_batch_size QT_UNITY_BUILD_BATCH_SIZE)
+translate_boolean_input(ccache QT_USE_CCACHE)
+translate_boolean_input(vcpkg QT_USE_VCPKG)
+translate_boolean_input(shared BUILD_SHARED_LIBS)
+translate_boolean_input(warnings_are_errors WARNINGS_ARE_ERRORS)
+translate_boolean_input(qtinlinenamespace QT_INLINE_NAMESPACE)
+translate_string_input(qt_namespace QT_NAMESPACE)
+translate_string_input(qt_libinfix QT_LIBINFIX)
+translate_string_input(qreal QT_COORD_TYPE)
+translate_path_input(prefix CMAKE_INSTALL_PREFIX)
+translate_path_input(extprefix CMAKE_STAGING_PREFIX)
+foreach(kind bin lib archdata libexec qml data doc sysconf examples tests)
+ string(TOUPPER ${kind} uc_kind)
+ translate_path_input(${kind}dir INSTALL_${uc_kind}DIR)
+endforeach()
+translate_path_input(headerdir INSTALL_INCLUDEDIR)
+translate_path_input(plugindir INSTALL_PLUGINSDIR)
+translate_path_input(translationdir INSTALL_TRANSLATIONSDIR)
+
+if(NOT "${INPUT_device}" STREQUAL "")
+ push("-DQT_QMAKE_TARGET_MKSPEC=devices/${INPUT_device}")
+ drop_input(device)
+endif()
+translate_string_input(platform QT_QMAKE_TARGET_MKSPEC)
+translate_string_input(xplatform QT_QMAKE_TARGET_MKSPEC)
+guess_compiler_from_mkspec()
+translate_string_input(qpa_default_platform QT_QPA_DEFAULT_PLATFORM)
+
+translate_path_input(android-sdk ANDROID_SDK_ROOT)
+translate_path_input(android-ndk ANDROID_NDK_ROOT)
+if(DEFINED INPUT_android-ndk-platform)
+ drop_input(android-ndk-platform)
+ push("-DANDROID_PLATFORM=${INPUT_android-ndk-platform}")
+endif()
+if(DEFINED INPUT_android-abis)
+ if(INPUT_android-abis MATCHES ",")
+ qtConfAddError("The -android-abis option cannot handle more than one ABI "
+ "when building with CMake.")
+ endif()
+ translate_string_input(android-abis ANDROID_ABI)
+endif()
+translate_string_input(android-javac-source QT_ANDROID_JAVAC_SOURCE)
+translate_string_input(android-javac-target QT_ANDROID_JAVAC_TARGET)
+
+translate_string_input(sdk QT_APPLE_SDK)
+
+drop_input(make)
+drop_input(nomake)
+translate_boolean_input(install-examples-sources QT_INSTALL_EXAMPLES_SOURCES)
+
+check_qt_build_parts(nomake)
+check_qt_build_parts(make)
+
+drop_input(debug)
+drop_input(release)
+drop_input(debug_and_release)
+drop_input(force_debug_info)
+unset(build_configs)
+if(INPUT_debug)
+ set(build_configs Debug)
+elseif("${INPUT_debug}" STREQUAL "no")
+ set(build_configs Release)
+elseif(INPUT_debug_and_release)
+ set(build_configs Release Debug)
+endif()
+if(INPUT_force_debug_info)
list(TRANSFORM build_configs REPLACE "^Release$" "RelWithDebInfo")
endif()
+# Code coverage handling
+drop_input(gcov)
+if(INPUT_gcov)
+ if(NOT "${INPUT_coverage}" STREQUAL "")
+ if(NOT "${INPUT_coverage}" STREQUAL "gcov")
+ qtConfAddError("The -gcov argument is provided, but -coverage is set"
+ " to ${INPUT_coverage}")
+ endif()
+ else()
+ set(INPUT_coverage "gcov")
+ list(APPEND config_inputs coverage)
+ endif()
+endif()
+if(NOT "${INPUT_coverage}" STREQUAL "")
+ if(build_configs)
+ if(NOT "Debug" IN_LIST build_configs)
+ qtConfAddError("The -coverage argument requires Qt configured with 'Debug' config.")
+ endif()
+ else()
+ set(build_configs "Debug")
+ endif()
+endif()
+
list(LENGTH build_configs nr_of_build_configs)
-if(nr_of_build_configs EQUAL 1)
+if(nr_of_build_configs EQUAL 1 AND NOT multi_config)
push("-DCMAKE_BUILD_TYPE=${build_configs}")
-elseif(nr_of_build_configs GREATER 1)
+elseif(nr_of_build_configs GREATER 1 OR multi_config)
set(multi_config ON)
- string(REPLACE ";" "\\;" escaped_build_configs "${build_configs}")
+ string(REPLACE ";" "[[;]]" escaped_build_configs "${build_configs}")
# We must not use the push macro here to avoid variable expansion.
# That would destroy our escaping.
list(APPEND cmake_args "-DCMAKE_CONFIGURATION_TYPES=${escaped_build_configs}")
endif()
-if(device_options)
- unset(escaped_device_options)
- list(JOIN device_options "\\;" escaped_device_options)
- list(APPEND cmake_args "-DQT_QMAKE_DEVICE_OPTIONS=${escaped_device_options}")
+drop_input(ltcg)
+if("${INPUT_ltcg}" STREQUAL "yes")
+ foreach(config ${build_configs})
+ string(TOUPPER "${config}" ucconfig)
+ if(NOT ucconfig STREQUAL "DEBUG")
+ push("-DCMAKE_INTERPROCEDURAL_OPTIMIZATION_${ucconfig}=ON")
+ endif()
+ endforeach()
+endif()
+
+translate_list_input(device-option QT_QMAKE_DEVICE_OPTIONS)
+translate_list_input(defines QT_EXTRA_DEFINES)
+translate_list_input(fpaths QT_EXTRA_FRAMEWORKPATHS)
+translate_list_input(includes QT_EXTRA_INCLUDEPATHS)
+translate_list_input(lpaths QT_EXTRA_LIBDIRS)
+translate_list_input(rpaths QT_EXTRA_RPATHS)
+
+if(cmake_file_api OR (developer_build AND NOT DEFINED cmake_file_api))
+ foreach(file cache-v2 cmakeFiles-v1 codemodel-v2 toolchains-v1)
+ file(WRITE "${CMAKE_BINARY_DIR}/.cmake/api/v1/query/${file}" "")
+ endforeach()
endif()
-if(extra_rpaths)
- unset(escaped_paths)
- list(JOIN extra_rpaths "\\;" escaped_paths)
- list(APPEND cmake_args "-DQT_EXTRA_RPATHS=${escaped_paths}")
+# Translate unhandled input variables to either -DINPUT_foo=value or -DFEATURE_foo=ON/OFF. If the
+# input's name matches a feature name and the corresponding command-line option's type is boolean
+# then we assume it's controlling a feature.
+foreach(input ${config_inputs})
+ qt_feature_normalize_name("${input}" cmake_input)
+ if("${commandline_input_${input}_type}" STREQUAL "boolean"
+ AND input IN_LIST commandline_known_features)
+ translate_boolean_input("${input}" "FEATURE_${cmake_input}")
+ else()
+ push("-DINPUT_${cmake_input}=${INPUT_${input}}")
+ endif()
+endforeach()
+
+if(no_prefix_option AND DEFINED INPUT_prefix)
+ qtConfAddError("Can't specify both -prefix and -no-prefix options at the same time.")
endif()
if(NOT generator AND auto_detect_generator)
@@ -188,7 +1065,7 @@ if(NOT generator AND auto_detect_generator)
else()
if(CMAKE_HOST_UNIX)
set(generator "Unix Makefiles")
- elseif(CMAKE_HOST_WINDOWS)
+ elseif(CMAKE_HOST_WIN32)
find_program(msvc_compiler cl.exe)
if(msvc_compiler)
set(generator "NMake Makefiles")
@@ -202,11 +1079,37 @@ if(NOT generator AND auto_detect_generator)
endif()
endif()
endif()
+
+if(multi_config
+ AND NOT "${generator}" STREQUAL "Xcode"
+ AND NOT "${generator}" STREQUAL "Ninja Multi-Config"
+ AND NOT "${generator}" MATCHES "^Visual Studio")
+ message(FATAL_ERROR "Multi-config build is only supported by Xcode, Ninja Multi-Config and \
+Visual Studio generators. Current generator is \"${generator}\".
+Note: Use '-cmake-generator <generator name>' option to specify the generator manually.")
+endif()
+
if(generator)
push(-G "${generator}")
endif()
-push("${source_dir}")
+# Add CMake variable assignments near the end to allow users to overwrite what configure sets.
+foreach(arg IN LISTS cmake_var_assignments)
+ push("-D${arg}")
+endforeach()
+
+push("${MODULE_ROOT}")
+
+if(INPUT_sysroot)
+ qtConfAddWarning("The -sysroot option is deprecated and no longer has any effect. "
+ "It is recommended to use a toolchain file instead, i.e., "
+ "-DCMAKE_TOOLCHAIN_FILE=<filename>. "
+ "Alternatively, you may use -DCMAKE_SYSROOT option "
+ "to pass the sysroot to CMake.\n")
+endif()
+
+# Restore the escaped semicolons in arguments that are lists
+list(TRANSFORM cmake_args REPLACE "\\[\\[;\\]\\]" "\\\\;")
execute_process(COMMAND "${CMAKE_COMMAND}" ${cmake_args}
COMMAND_ECHO STDOUT
diff --git a/cmake/QtProperties.cmake b/cmake/QtProperties.cmake
index a12fa53252..708b60fe0d 100644
--- a/cmake/QtProperties.cmake
+++ b/cmake/QtProperties.cmake
@@ -1,3 +1,6 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
define_property(TARGET
PROPERTY
QT_PLUGINS
@@ -105,3 +108,13 @@ define_property(TARGET
FULL_DOCS
"Specifies the qml module's version."
)
+
+define_property(GLOBAL
+ PROPERTY
+ QT_TARGETS_FOLDER
+ BRIEF_DOCS
+ "Name of the FOLDER for targets internally created by AUTOGEN and Qt's CMake API."
+ FULL_DOCS
+ "This property is used to initialize AUTOGEN_TARGETS_FOLDER and the FOLDER property of
+ internal targets created by Qt's CMake commands."
+)
diff --git a/cmake/QtPublicAppleHelpers.cmake b/cmake/QtPublicAppleHelpers.cmake
new file mode 100644
index 0000000000..5f7a7719b5
--- /dev/null
+++ b/cmake/QtPublicAppleHelpers.cmake
@@ -0,0 +1,954 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+function(_qt_internal_handle_ios_launch_screen target)
+ # Check if user provided a launch screen path via a variable.
+ set(launch_screen "")
+
+ # Check if the project provided a launch screen path via a variable.
+ # This variable is currently in Technical Preview.
+ if(QT_IOS_LAUNCH_SCREEN)
+ set(launch_screen "${QT_IOS_LAUNCH_SCREEN}")
+ endif()
+
+ # Check if the project provided a launch screen path via a target property, it takes precedence
+ # over the variable.
+ # This property is currently in Technical Preview.
+ get_target_property(launch_screen_from_prop "${target}" QT_IOS_LAUNCH_SCREEN)
+ if(launch_screen_from_prop)
+ set(launch_screen "${launch_screen_from_prop}")
+ endif()
+
+ # If the project hasn't provided a launch screen file path, use a copy of the template
+ # that qmake uses.
+ # It needs to be a copy because configure_file can't handle all the escaped double quotes
+ # present in the qmake template file.
+ set(is_default_launch_screen FALSE)
+ if(NOT launch_screen AND NOT QT_NO_SET_DEFAULT_IOS_LAUNCH_SCREEN)
+ set(is_default_launch_screen TRUE)
+ set(launch_screen
+ "${__qt_internal_cmake_apple_support_files_path}/LaunchScreen.storyboard")
+ endif()
+
+ # Check that the launch screen exists.
+ if(launch_screen)
+ if(NOT IS_ABSOLUTE "${launch_screen}")
+ message(FATAL_ERROR
+ "Provided launch screen value should be an absolute path: '${launch_screen}'")
+ endif()
+
+ if(NOT EXISTS "${launch_screen}")
+ message(FATAL_ERROR
+ "Provided launch screen file does not exist: '${launch_screen}'")
+ endif()
+ endif()
+
+ if(launch_screen AND NOT QT_NO_ADD_IOS_LAUNCH_SCREEN_TO_BUNDLE)
+ get_filename_component(launch_screen_name "${launch_screen}" NAME)
+
+ # Make a copy of the default launch screen template for this target and replace the
+ # label inside the template with the target name.
+ if(is_default_launch_screen)
+ # Configure our default template and place it in the build dir.
+ set(launch_screen_in_path "${launch_screen}")
+
+ string(MAKE_C_IDENTIFIER "${target}" target_identifier)
+ set(launch_screen_out_dir
+ "${CMAKE_CURRENT_BINARY_DIR}/.qt/launch_screen_storyboards/${target_identifier}")
+
+ set(launch_screen_out_path
+ "${launch_screen_out_dir}/${launch_screen_name}")
+
+ file(MAKE_DIRECTORY "${launch_screen_out_dir}")
+
+ configure_file("${launch_screen_in_path}" "${launch_screen_out_path}" COPYONLY)
+
+ set(final_launch_screen_path "${launch_screen_out_path}")
+ else()
+ set(final_launch_screen_path "${launch_screen}")
+ endif()
+
+ # Add the launch screen storyboard file as a source file, otherwise CMake doesn't consider
+ # it as a resource file and MACOSX_PACKAGE_LOCATION processing will be skipped.
+ target_sources("${target}" PRIVATE "${final_launch_screen_path}")
+
+ # Ensure Xcode compiles the storyboard file and installs the compiled storyboard .nib files
+ # into the app bundle.
+ # We use target_sources and the MACOSX_PACKAGE_LOCATION source file property for that
+ # instead of the RESOURCE target property, becaues the latter could potentially end up
+ # needlessly installing the source storyboard file.
+ #
+ # We can't rely on policy CMP0118 since user project controls it.
+ set(scope_args)
+ if(CMAKE_VERSION VERSION_GREATER_EQUAL "3.18")
+ set(scope_args TARGET_DIRECTORY ${target})
+ endif()
+ set_source_files_properties("${final_launch_screen_path}" ${scope_args}
+ PROPERTIES MACOSX_PACKAGE_LOCATION Resources)
+
+ # Save the launch screen name, so its value is added as an UILaunchStoryboardName entry
+ # in the Qt generated Info.plist file.
+ # Xcode expects an Info.plist storyboard entry without an extension.
+ get_filename_component(launch_screen_base_name "${launch_screen}" NAME_WE)
+ set_target_properties("${target}" PROPERTIES
+ _qt_ios_launch_screen_name "${launch_screen_name}"
+ _qt_ios_launch_screen_base_name "${launch_screen_base_name}"
+ _qt_ios_launch_screen_path "${final_launch_screen_path}")
+ endif()
+endfunction()
+
+function(_qt_internal_find_ios_development_team_id out_var)
+ get_property(team_id GLOBAL PROPERTY _qt_internal_ios_development_team_id)
+ get_property(team_id_computed GLOBAL PROPERTY _qt_internal_ios_development_team_id_computed)
+ if(team_id_computed)
+ # Just in case if the value is non-empty but still booly FALSE.
+ if(NOT team_id)
+ set(team_id "")
+ endif()
+ set("${out_var}" "${team_id}" PARENT_SCOPE)
+ return()
+ endif()
+
+ set_property(GLOBAL PROPERTY _qt_internal_ios_development_team_id_computed "TRUE")
+
+ set(home_dir "$ENV{HOME}")
+ set(xcode_preferences_path "${home_dir}/Library/Preferences/com.apple.dt.Xcode.plist")
+
+ # Extract the first account name (email) from the user's Xcode preferences
+ message(DEBUG "Trying to extract an Xcode development team id from '${xcode_preferences_path}'")
+ execute_process(COMMAND "/usr/libexec/PlistBuddy"
+ -x -c "print IDEProvisioningTeams" "${xcode_preferences_path}"
+ OUTPUT_VARIABLE teams_xml
+ ERROR_VARIABLE plist_error)
+
+ # Parsing state.
+ set(is_free "")
+ set(current_team_id "")
+ set(parsing_is_free FALSE)
+ set(parsing_team_id FALSE)
+ set(first_team_id "")
+
+ # Parse the xml output and return the first encountered non-free team id. If no non-free team id
+ # is found, return the first encountered free team id.
+ # If no team is found, return an empty string.
+ #
+ # Example input:
+ #<plist version="1.0">
+ #<dict>
+ # <key>marty@planet.local</key>
+ # <array>
+ # <dict>
+ # <key>isFreeProvisioningTeam</key>
+ # <false/>
+ # <key>teamID</key>
+ # <string>AAA</string>
+ # ...
+ # </dict>
+ # <dict>
+ # <key>isFreeProvisioningTeam</key>
+ # <true/>
+ # <key>teamID</key>
+ # <string>BBB</string>
+ # ...
+ # </dict>
+ # </array>
+ #</dict>
+ #</plist>
+ if(teams_xml AND NOT plist_error)
+ string(REPLACE "\n" ";" teams_xml_lines "${teams_xml}")
+
+ foreach(xml_line ${teams_xml_lines})
+ string(STRIP "${xml_line}" xml_line)
+ if(xml_line STREQUAL "<dict>")
+ # Clean any previously found values when a new team dict is matched.
+ set(is_free "")
+ set(current_team_id "")
+
+ elseif(xml_line STREQUAL "<key>isFreeProvisioningTeam</key>")
+ set(parsing_is_free TRUE)
+
+ elseif(parsing_is_free)
+ set(parsing_is_free FALSE)
+
+ if(xml_line MATCHES "true")
+ set(is_free TRUE)
+ else()
+ set(is_free FALSE)
+ endif()
+
+ elseif(xml_line STREQUAL "<key>teamID</key>")
+ set(parsing_team_id TRUE)
+
+ elseif(parsing_team_id)
+ set(parsing_team_id FALSE)
+ if(xml_line MATCHES "<string>([^<]+)</string>")
+ set(current_team_id "${CMAKE_MATCH_1}")
+ else()
+ continue()
+ endif()
+
+ string(STRIP "${current_team_id}" current_team_id)
+
+ # If this is the first team id we found so far, remember that, regardless if's free
+ # or not.
+ if(NOT first_team_id AND current_team_id)
+ set(first_team_id "${current_team_id}")
+ endif()
+
+ # Break early if we found a non-free team id and use it, because we prefer
+ # a non-free team for signing, just like qmake.
+ if(NOT is_free AND current_team_id)
+ set(first_team_id "${current_team_id}")
+ break()
+ endif()
+ endif()
+ endforeach()
+ endif()
+
+ if(NOT first_team_id)
+ message(DEBUG "Failed to extract an Xcode development team id.")
+ set("${out_var}" "" PARENT_SCOPE)
+ else()
+ message(DEBUG "Successfully extracted the first encountered Xcode development team id.")
+ set_property(GLOBAL PROPERTY _qt_internal_ios_development_team_id "${first_team_id}")
+ set("${out_var}" "${first_team_id}" PARENT_SCOPE)
+ endif()
+endfunction()
+
+function(_qt_internal_get_apple_bundle_identifier_prefix out_var)
+ get_property(prefix GLOBAL PROPERTY _qt_internal_ios_bundle_identifier_prefix)
+ get_property(prefix_computed GLOBAL PROPERTY
+ _qt_internal_ios_bundle_identifier_prefix_computed)
+ if(prefix_computed)
+ # Just in case if the value is non-empty but still booly FALSE.
+ if(NOT prefix)
+ set(prefix "")
+ endif()
+ set("${out_var}" "${prefix}" PARENT_SCOPE)
+ return()
+ endif()
+
+ set_property(GLOBAL PROPERTY _qt_internal_ios_bundle_identifier_prefix_computed "TRUE")
+
+ set(home_dir "$ENV{HOME}")
+ set(xcode_preferences_path "${home_dir}/Library/Preferences/com.apple.dt.Xcode.plist")
+
+ message(DEBUG "Trying to extract the default bundle identifier prefix from Xcode preferences.")
+ execute_process(COMMAND "/usr/libexec/PlistBuddy"
+ -c "print IDETemplateOptions:bundleIdentifierPrefix"
+ "${xcode_preferences_path}"
+ OUTPUT_VARIABLE prefix
+ ERROR_VARIABLE prefix_error)
+ if(prefix AND NOT prefix_error)
+ message(DEBUG "Successfully extracted the default bundle identifier prefix.")
+ string(STRIP "${prefix}" prefix)
+ else()
+ message(DEBUG "Failed to extract the default bundle identifier prefix.")
+ endif()
+
+ if(prefix AND NOT prefix_error)
+ set_property(GLOBAL PROPERTY _qt_internal_ios_bundle_identifier_prefix "${prefix}")
+ set("${out_var}" "${prefix}" PARENT_SCOPE)
+ else()
+ set("${out_var}" "" PARENT_SCOPE)
+ endif()
+endfunction()
+
+function(_qt_internal_escape_rfc_1034_identifier value out_var)
+ # According to https://datatracker.ietf.org/doc/html/rfc1034#section-3.5
+ # we can only use letters, digits, dot (.) and hyphens (-).
+ # Underscores are not allowed.
+ string(REGEX REPLACE "[^A-Za-z0-9.]" "-" value "${value}")
+
+ set("${out_var}" "${value}" PARENT_SCOPE)
+endfunction()
+
+function(_qt_internal_get_default_apple_bundle_identifier target out_var)
+ _qt_internal_get_apple_bundle_identifier_prefix(prefix)
+ if(NOT prefix)
+ set(prefix "com.yourcompany")
+
+ # For a better out-of-the-box experience, try to create a unique prefix by appending
+ # the sha1 of the team id, if one is found.
+ _qt_internal_find_ios_development_team_id(team_id)
+ if(team_id)
+ string(SHA1 hash "${team_id}")
+ string(SUBSTRING "${hash}" 0 8 infix)
+ string(APPEND prefix ".${infix}")
+ endif()
+
+ if(CMAKE_GENERATOR STREQUAL "Xcode")
+ message(WARNING
+ "No organization bundle identifier prefix could be retrieved from Xcode preferences. \
+ This can lead to code signing issues due to a non-unique bundle \
+ identifier. Please set up an organization prefix by creating a new project within \
+ Xcode, or consider providing a custom bundle identifier by specifying the \
+ MACOSX_BUNDLE_GUI_IDENTIFIER or XCODE_ATTRIBUTE_PRODUCT_BUNDLE_IDENTIFIER property."
+ )
+ endif()
+ endif()
+
+ # Escape the prefix according to rfc 1034, it's important for code-signing. If an invalid
+ # identifier is used, calling xcodebuild on the command line says that no provisioning profile
+ # could be found, with no additional error message. If one opens the generated project with
+ # Xcode and clicks on 'Try again' to get a new profile, it shows a semi-useful error message
+ # that the identifier is invalid.
+ _qt_internal_escape_rfc_1034_identifier("${prefix}" prefix)
+
+ if(CMAKE_GENERATOR STREQUAL "Xcode")
+ set(identifier "${prefix}.$(PRODUCT_NAME:rfc1034identifier)")
+ else()
+ set(identifier "${prefix}.${target}")
+ endif()
+
+ set("${out_var}" "${identifier}" PARENT_SCOPE)
+endfunction()
+
+function(_qt_internal_set_placeholder_apple_bundle_version target)
+ # If user hasn't provided neither a bundle version nor a bundle short version string for the
+ # app, set a placeholder value for both which will add them to the generated Info.plist file.
+ # This is required so that the app launches in the simulator (but apparently not for running
+ # on-device).
+ get_target_property(bundle_version "${target}" MACOSX_BUNDLE_BUNDLE_VERSION)
+ get_target_property(bundle_short_version "${target}" MACOSX_BUNDLE_SHORT_VERSION_STRING)
+
+ if(NOT MACOSX_BUNDLE_BUNDLE_VERSION AND
+ NOT MACOSX_BUNDLE_SHORT_VERSION_STRING AND
+ NOT bundle_version AND
+ NOT bundle_short_version AND
+ NOT QT_NO_SET_XCODE_BUNDLE_VERSION
+ )
+ get_target_property(version "${target}" VERSION)
+ if(NOT version)
+ set(version "${PROJECT_VERSION}")
+ if(NOT version)
+ set(version "1.0.0")
+ endif()
+ endif()
+
+ # Use x.y for short version and x.y.z for full version
+ # Any versions longer than this will fail App Store
+ # submission.
+ string(REPLACE "." ";" version_list ${version})
+ list(LENGTH version_list version_list_length)
+ list(GET version_list 0 version_major)
+ set(bundle_short_version "${version_major}")
+ if(version_list_length GREATER 1)
+ list(GET version_list 1 version_minor)
+ string(APPEND bundle_short_version ".${version_minor}")
+ endif()
+ set(bundle_version "${bundle_short_version}")
+ if(version_list_length GREATER 2)
+ list(GET version_list 2 version_patch)
+ string(APPEND bundle_version ".${version_patch}")
+ endif()
+
+
+ if(NOT CMAKE_XCODE_ATTRIBUTE_MARKETING_VERSION
+ AND NOT QT_NO_SET_XCODE_ATTRIBUTE_MARKETING_VERSION
+ AND NOT CMAKE_XCODE_ATTRIBUTE_CURRENT_PROJECT_VERSION
+ AND NOT QT_NO_SET_XCODE_ATTRIBUTE_CURRENT_PROJECT_VERSION
+ AND CMAKE_GENERATOR STREQUAL "Xcode")
+ get_target_property(marketing_version "${target}"
+ XCODE_ATTRIBUTE_MARKETING_VERSION)
+ get_target_property(current_project_version "${target}"
+ XCODE_ATTRIBUTE_CURRENT_PROJECT_VERSION)
+ if(NOT marketing_version AND NOT current_project_version)
+ set_target_properties("${target}"
+ PROPERTIES
+ XCODE_ATTRIBUTE_CURRENT_PROJECT_VERSION "${bundle_version}"
+ XCODE_ATTRIBUTE_MARKETING_VERSION "${bundle_short_version}"
+ )
+ set(bundle_version "$(CURRENT_PROJECT_VERSION)")
+ set(bundle_short_version "$(MARKETING_VERSION)")
+ endif()
+ endif()
+
+ set_target_properties("${target}"
+ PROPERTIES
+ MACOSX_BUNDLE_BUNDLE_VERSION "${bundle_version}"
+ MACOSX_BUNDLE_SHORT_VERSION_STRING "${bundle_short_version}"
+ )
+ endif()
+endfunction()
+
+function(_qt_internal_set_xcode_development_team_id target)
+ # If user hasn't provided a development team id, try to find the first one specified
+ # in the Xcode preferences.
+ if(NOT CMAKE_XCODE_ATTRIBUTE_DEVELOPMENT_TEAM AND NOT QT_NO_SET_XCODE_DEVELOPMENT_TEAM_ID)
+ get_target_property(existing_team_id "${target}" XCODE_ATTRIBUTE_DEVELOPMENT_TEAM)
+ if(NOT existing_team_id)
+ _qt_internal_find_ios_development_team_id(team_id)
+ set_target_properties("${target}"
+ PROPERTIES XCODE_ATTRIBUTE_DEVELOPMENT_TEAM "${team_id}")
+ endif()
+ endif()
+endfunction()
+
+function(_qt_internal_set_apple_bundle_identifier target)
+ # Skip all logic if requested.
+ if(QT_NO_SET_XCODE_BUNDLE_IDENTIFIER)
+ return()
+ endif()
+
+ # There are two fields to consider: the CFBundleIdentifier key (ie., cmake_bundle_identifier)
+ # to be written to Info.plist and the PRODUCT_BUNDLE_IDENTIFIER (ie., xcode_bundle_identifier)
+ # property to set in the Xcode project. The `cmake_bundle_identifier` set by
+ # MACOSX_BUNDLE_GUI_IDENTIFIER applies to both Xcode, and other generators, while
+ # `xcode_bundle_identifier` set by XCODE_ATTRIBUTE_PRODUCT_BUNDLE_IDENTIFIER is
+ # Xcode specific.
+ #
+ # If Ninja is the generator, we set the value of `MACOSX_BUNDLE_GUI_IDENTIFIER`
+ # and don't touch the `XCODE_ATTRIBUTE_PRODUCT_BUNDLE_IDENTIFIER`.
+ # If Xcode is the generator, we set the value of `XCODE_ATTRIBUTE_PRODUCT_BUNDLE_IDENTIFIER`,
+ # and additionally, to silence a Xcode's warning, we set the `MACOSX_BUNDLE_GUI_IDENTIFIER` to
+ # `${PRODUCT_BUNDLE_IDENTIFIER}` so that Xcode could sort it out.
+
+ get_target_property(existing_cmake_bundle_identifier "${target}"
+ MACOSX_BUNDLE_GUI_IDENTIFIER)
+ get_target_property(existing_xcode_bundle_identifier "${target}"
+ XCODE_ATTRIBUTE_PRODUCT_BUNDLE_IDENTIFIER)
+
+ set(is_cmake_bundle_identifier_given FALSE)
+ if(existing_cmake_bundle_identifier)
+ set(is_cmake_bundle_identifier_given TRUE)
+ elseif(MACOSX_BUNDLE_GUI_IDENTIFIER)
+ set(is_cmake_bundle_identifier_given TRUE)
+ set(existing_cmake_bundle_identifier ${MACOSX_BUNDLE_GUI_IDENTIFIER})
+ endif()
+
+ set(is_xcode_bundle_identifier_given FALSE)
+ if(existing_xcode_bundle_identifier)
+ set(is_xcode_bundle_identifier_given TRUE)
+ elseif(CMAKE_XCODE_ATTRIBUTE_PRODUCT_BUNDLE_IDENTIFIER)
+ set(is_xcode_bundle_identifier_given TRUE)
+ set(existing_xcode_bundle_identifier ${CMAKE_XCODE_ATTRIBUTE_PRODUCT_BUNDLE_IDENTIFIER})
+ endif()
+
+ if(is_cmake_bundle_identifier_given
+ AND is_xcode_bundle_identifier_given
+ AND NOT existing_cmake_bundle_identifier STREQUAL existing_xcode_bundle_identifier)
+ message(WARNING
+ "MACOSX_BUNDLE_GUI_IDENTIFIER and XCODE_ATTRIBUTE_PRODUCT_BUNDLE_IDENTIFIER "
+ "are set to different values. You only need to set one of them. ")
+ endif()
+
+ if(NOT is_xcode_bundle_identifier_given
+ AND NOT is_cmake_bundle_identifier_given)
+ _qt_internal_get_default_apple_bundle_identifier("${target}" bundle_id)
+ elseif(is_cmake_bundle_identifier_given)
+ set(bundle_id ${existing_cmake_bundle_identifier})
+ elseif(is_xcode_bundle_identifier_given)
+ set(bundle_id ${existing_xcode_bundle_identifier})
+ endif()
+
+ if(CMAKE_GENERATOR STREQUAL "Xcode")
+ set_target_properties("${target}"
+ PROPERTIES
+ XCODE_ATTRIBUTE_PRODUCT_BUNDLE_IDENTIFIER "${bundle_id}"
+ MACOSX_BUNDLE_GUI_IDENTIFIER "$(PRODUCT_BUNDLE_IDENTIFIER)")
+ else()
+ set_target_properties("${target}"
+ PROPERTIES
+ MACOSX_BUNDLE_GUI_IDENTIFIER "${bundle_id}")
+ endif()
+endfunction()
+
+function(_qt_internal_set_xcode_targeted_device_family target)
+ if(NOT CMAKE_XCODE_ATTRIBUTE_TARGETED_DEVICE_FAMILY
+ AND NOT QT_NO_SET_XCODE_TARGETED_DEVICE_FAMILY)
+ get_target_property(existing_device_family
+ "${target}" XCODE_ATTRIBUTE_TARGETED_DEVICE_FAMILY)
+ if(NOT existing_device_family)
+ set(device_family_iphone_and_ipad "1,2")
+ set_target_properties("${target}"
+ PROPERTIES
+ XCODE_ATTRIBUTE_TARGETED_DEVICE_FAMILY
+ "${device_family_iphone_and_ipad}")
+ endif()
+ endif()
+endfunction()
+
+function(_qt_internal_set_xcode_code_sign_style target)
+ if(NOT CMAKE_XCODE_ATTRIBUTE_CODE_SIGN_STYLE
+ AND NOT QT_NO_SET_XCODE_CODE_SIGN_STYLE)
+ get_target_property(existing_code_style
+ "${target}" XCODE_ATTRIBUTE_CODE_SIGN_STYLE)
+ if(NOT existing_code_style)
+ set(existing_code_style "Automatic")
+ set_target_properties("${target}"
+ PROPERTIES
+ XCODE_ATTRIBUTE_CODE_SIGN_STYLE
+ "${existing_code_style}")
+ endif()
+ endif()
+endfunction()
+
+# Workaround for https://gitlab.kitware.com/cmake/cmake/-/issues/15183
+function(_qt_internal_set_xcode_install_path target)
+ if(NOT CMAKE_XCODE_ATTRIBUTE_INSTALL_PATH
+ AND NOT QT_NO_SET_XCODE_INSTALL_PATH)
+ get_target_property(existing_install_path
+ "${target}" XCODE_ATTRIBUTE_INSTALL_PATH)
+ if(NOT existing_install_path)
+ set_target_properties("${target}"
+ PROPERTIES
+ XCODE_ATTRIBUTE_INSTALL_PATH
+ "$(inherited)")
+ endif()
+ endif()
+endfunction()
+
+function(_qt_internal_set_xcode_bundle_display_name target)
+ # We want the value of CFBundleDisplayName to be ${PRODUCT_NAME}, but we can't put that
+ # into the Info.plist.in template file directly, because the implicit configure_file(Info.plist)
+ # done by CMake is not using the @ONLY option, so CMake would treat the assignment as
+ # variable expansion. Escaping using backslashes does not help.
+ # Work around it by assigning the dollar char to a separate cache var, and expand it, so that
+ # the final value in the file will be ${PRODUCT_NAME}, to be evaluated at build time by Xcode.
+ set(QT_INTERNAL_DOLLAR_VAR "$" CACHE STRING "")
+endfunction()
+
+# Adds ${PRODUCT_NAME} to the Info.plist file, which is then evaluated by Xcode itself.
+function(_qt_internal_set_xcode_bundle_name target)
+ if(QT_NO_SET_XCODE_BUNDLE_NAME)
+ return()
+ endif()
+
+ get_target_property(existing_bundle_name "${target}" MACOSX_BUNDLE_BUNDLE_NAME)
+ if(NOT MACOSX_BUNDLE_BUNDLE_NAME AND NOT existing_bundle_name)
+ if(CMAKE_GENERATOR STREQUAL Xcode)
+ set_target_properties("${target}"
+ PROPERTIES
+ MACOSX_BUNDLE_BUNDLE_NAME "$(PRODUCT_NAME)")
+ else()
+ set_target_properties("${target}"
+ PROPERTIES
+ MACOSX_BUNDLE_BUNDLE_NAME "${target}")
+ endif()
+ endif()
+endfunction()
+
+function(_qt_internal_set_xcode_bitcode_enablement target)
+ if(CMAKE_XCODE_ATTRIBUTE_ENABLE_BITCODE
+ OR QT_NO_SET_XCODE_ENABLE_BITCODE)
+ return()
+ endif()
+
+ get_target_property(existing_bitcode_enablement
+ "${target}" XCODE_ATTRIBUTE_ENABLE_BITCODE)
+ if(NOT existing_bitcode_enablement MATCHES "-NOTFOUND")
+ return()
+ endif()
+
+ # Disable bitcode to match Xcode 14's new default
+ set_target_properties("${target}"
+ PROPERTIES
+ XCODE_ATTRIBUTE_ENABLE_BITCODE
+ "NO")
+endfunction()
+
+function(_qt_internal_copy_info_plist target)
+ # If the project already specifies a custom file, we don't override it.
+ get_target_property(info_plist_in "${target}" MACOSX_BUNDLE_INFO_PLIST)
+ if(NOT info_plist_in)
+ set(info_plist_in "${__qt_internal_cmake_apple_support_files_path}/Info.plist.app.in")
+ endif()
+
+ string(MAKE_C_IDENTIFIER "${target}" target_identifier)
+ set(info_plist_out_dir
+ "${CMAKE_CURRENT_BINARY_DIR}/.qt/info_plist/${target_identifier}")
+ set(info_plist_out "${info_plist_out_dir}/Info.plist")
+
+ # Check if we need to specify a custom launch screen storyboard entry.
+ get_target_property(launch_screen_base_name "${target}" _qt_ios_launch_screen_base_name)
+ if(launch_screen_base_name)
+ set(qt_ios_launch_screen_plist_entry "${launch_screen_base_name}")
+ endif()
+
+ # Call configure_file to substitute Qt-specific @FOO@ values, not ${FOO} values.
+ #
+ # The output file will be another template file to be fed to CMake via the
+ # MACOSX_BUNDLE_INFO_PLIST property. CMake will then call configure_file on it to provide
+ # content for regular entries like CFBundleName, etc.
+ #
+ # We require this extra configure_file call so we can create unique Info.plist files for each
+ # target in a project, while also providing a way to add Qt specific entries that CMake
+ # does not support out of the box (e.g. a launch screen name).
+ configure_file(
+ "${info_plist_in}"
+ "${info_plist_out}"
+ @ONLY
+ )
+
+ set_target_properties("${target}" PROPERTIES MACOSX_BUNDLE_INFO_PLIST "${info_plist_out}")
+endfunction()
+
+function(_qt_internal_plist_buddy plist_file)
+ cmake_parse_arguments(PARSE_ARGV 1 arg
+ "" "OUTPUT_VARIABLE;ERROR_VARIABLE" "COMMANDS")
+ foreach(command ${arg_COMMANDS})
+ execute_process(COMMAND "/usr/libexec/PlistBuddy"
+ -c "${command}" "${plist_file}"
+ OUTPUT_VARIABLE plist_buddy_output
+ ERROR_VARIABLE plist_buddy_error)
+ string(STRIP "${plist_buddy_output}" plist_buddy_output)
+ if(arg_OUTPUT_VARIABLE)
+ list(APPEND ${arg_OUTPUT_VARIABLE} ${plist_buddy_output})
+ set(${arg_OUTPUT_VARIABLE} ${${arg_OUTPUT_VARIABLE}} PARENT_SCOPE)
+ endif()
+ if(arg_ERROR_VARIABLE)
+ list(APPEND ${arg_ERROR_VARIABLE} ${plist_buddy_error})
+ set(${arg_ERROR_VARIABLE} ${${arg_ERROR_VARIABLE}} PARENT_SCOPE)
+ endif()
+ if(plist_buddy_error)
+ return()
+ endif()
+ endforeach()
+endfunction()
+
+function(_qt_internal_set_apple_localizations target)
+ if(QT_NO_SET_PLIST_LOCALIZATIONS)
+ return()
+ endif()
+
+ set(supported_languages "${QT_I18N_TRANSLATED_LANGUAGES}")
+ if("${QT_I18N_TRANSLATED_LANGUAGES}" STREQUAL "")
+ get_target_property(supported_languages "${target}" _qt_apple_supported_languages)
+ if("${supported_languages}" STREQUAL "supported_languages-NOTFOUND")
+ return()
+ endif()
+ endif()
+ get_target_property(plist_file "${target}" MACOSX_BUNDLE_INFO_PLIST)
+ if (NOT plist_file)
+ return()
+ endif()
+
+ _qt_internal_plist_buddy("${plist_file}"
+ COMMANDS "print CFBundleLocalizations"
+ OUTPUT_VARIABLE existing_localizations
+ )
+ if(existing_localizations)
+ return()
+ endif()
+
+ list(TRANSFORM supported_languages PREPEND
+ "Add CFBundleLocalizations: string ")
+
+ _qt_internal_plist_buddy("${plist_file}"
+ COMMANDS
+ "Add CFBundleLocalizations array"
+ ${supported_languages}
+ "Delete CFBundleAllowMixedLocalizations"
+ )
+endfunction()
+
+function(_qt_internal_set_ios_simulator_arch target)
+ if(CMAKE_XCODE_ATTRIBUTE_ARCHS
+ OR QT_NO_SET_XCODE_ARCHS)
+ return()
+ endif()
+
+ get_target_property(existing_archs
+ "${target}" XCODE_ATTRIBUTE_ARCHS)
+ if(NOT existing_archs MATCHES "-NOTFOUND")
+ return()
+ endif()
+
+ if(NOT x86_64 IN_LIST QT_OSX_ARCHITECTURES)
+ return()
+ endif()
+
+ if(CMAKE_OSX_ARCHITECTURES AND NOT x86_64 IN_LIST CMAKE_OSX_ARCHITECTURES)
+ return()
+ endif()
+
+ set_target_properties("${target}"
+ PROPERTIES
+ "XCODE_ATTRIBUTE_ARCHS[sdk=iphonesimulator*]"
+ "x86_64")
+endfunction()
+
+# Export Apple platform sdk and xcode version requirements to Qt6ConfigExtras.cmake.
+function(_qt_internal_export_apple_sdk_and_xcode_version_requirements out_var)
+ if(NOT APPLE)
+ return()
+ endif()
+
+ if(IOS)
+ set(vars_to_assign
+ QT_SUPPORTED_MIN_IOS_SDK_VERSION
+ QT_SUPPORTED_MAX_IOS_SDK_VERSION
+ QT_SUPPORTED_MIN_IOS_XCODE_VERSION
+ )
+ elseif(VISIONOS)
+ set(vars_to_assign
+ QT_SUPPORTED_MIN_VISIONOS_SDK_VERSION
+ QT_SUPPORTED_MAX_VISIONOS_SDK_VERSION
+ QT_SUPPORTED_MIN_VISIONOS_XCODE_VERSION
+ )
+ else()
+ set(vars_to_assign
+ QT_SUPPORTED_MIN_MACOS_SDK_VERSION
+ QT_SUPPORTED_MAX_MACOS_SDK_VERSION
+ QT_SUPPORTED_MIN_MACOS_XCODE_VERSION
+ )
+ endif()
+
+ set(assignments "")
+ foreach(var IN LISTS vars_to_assign)
+ set(value "${${var}}")
+ list(APPEND assignments
+ "
+if(NOT ${var})
+ set(${var} \"${value}\")
+endif()")
+ endforeach()
+
+ list(JOIN assignments "\n" assignments)
+ set(${out_var} "${assignments}" PARENT_SCOPE)
+endfunction()
+
+function(_qt_internal_get_apple_sdk_version out_var)
+ if(APPLE)
+ if(CMAKE_SYSTEM_NAME STREQUAL iOS)
+ set(sdk_name "iphoneos")
+ elseif(CMAKE_SYSTEM_NAME STREQUAL visionOS)
+ set(sdk_name "xros")
+ else()
+ # Default to macOS
+ set(sdk_name "macosx")
+ endif()
+ set(xcrun_version_arg "--show-sdk-version")
+ execute_process(COMMAND /usr/bin/xcrun --sdk ${sdk_name} ${xcrun_version_arg}
+ OUTPUT_VARIABLE sdk_version
+ ERROR_VARIABLE xcrun_error)
+ if(NOT sdk_version)
+ message(FATAL_ERROR
+ "Can't determine darwin ${sdk_name} SDK version. Error: ${xcrun_error}")
+ endif()
+ string(STRIP "${sdk_version}" sdk_version)
+ set(${out_var} "${sdk_version}" PARENT_SCOPE)
+ endif()
+endfunction()
+
+function(_qt_internal_get_xcode_version_raw out_var)
+ if(APPLE)
+ execute_process(COMMAND /usr/bin/xcrun xcodebuild -version
+ OUTPUT_VARIABLE xcode_version
+ ERROR_VARIABLE xcrun_error)
+ string(REPLACE "\n" " " xcode_version "${xcode_version}")
+ string(STRIP "${xcode_version}" xcode_version)
+ set(${out_var} "${xcode_version}" PARENT_SCOPE)
+ endif()
+endfunction()
+
+function(_qt_internal_get_xcode_version out_var)
+ if(APPLE)
+ _qt_internal_get_xcode_version_raw(xcode_version_raw)
+
+ # The raw output is something like after the newlines are replaced with spaces:
+ # Xcode 14.3 Build version 14E222b
+ # We want only the '14.3' part. We could be more specific with the regex to match only
+ # digits separated by dots, but you never know how Apple might change the format.
+ string(REGEX REPLACE "Xcode (([^ ])+)" "\\2" xcode_version "${xcode_version_raw}")
+ if(xcode_version_raw MATCHES "Xcode ([^ ]+)")
+ set(xcode_version "${CMAKE_MATCH_1}")
+ else()
+ message(DEBUG "Failed to extract Xcode version from '${xcode_version_raw}'")
+ set(xcode_version "${xcode_version_raw}")
+ endif()
+
+ set(${out_var} "${xcode_version}" PARENT_SCOPE)
+ endif()
+endfunction()
+
+function(_qt_internal_get_cached_apple_sdk_version out_var)
+ if(QT_INTERNAL_APPLE_SDK_VERSION)
+ set(sdk_version "${QT_INTERNAL_APPLE_SDK_VERSION}")
+ else()
+ _qt_internal_get_apple_sdk_version(sdk_version)
+ set(QT_INTERNAL_APPLE_SDK_VERSION "${sdk_version}" CACHE STRING "Apple SDK version")
+ endif()
+
+ set(${out_var} "${sdk_version}" PARENT_SCOPE)
+endfunction()
+
+function(_qt_internal_get_cached_xcode_version out_var)
+ if(QT_INTERNAL_XCODE_VERSION)
+ set(xcode_version "${QT_INTERNAL_XCODE_VERSION}")
+ else()
+ _qt_internal_get_xcode_version(xcode_version)
+ set(QT_INTERNAL_XCODE_VERSION "${xcode_version}" CACHE STRING "Xcode version")
+ endif()
+
+ set(${out_var} "${xcode_version}" PARENT_SCOPE)
+endfunction()
+
+# Warn when the platform SDK or Xcode version are not supported.
+#
+# The warnings are currently only shown when building Qt, not when building user projects
+# with CMake.
+# The warnings ARE shown for qmake user projects.
+#
+# The qmake equivalent for user projects is in mkspecs/features/mac/default_post.prf.
+function(_qt_internal_check_apple_sdk_and_xcode_versions)
+ if(NOT APPLE)
+ return()
+ endif()
+
+ if(QT_NO_APPLE_SDK_AND_XCODE_CHECK)
+ return()
+ endif()
+
+ # Only run the check once in a top-level build.
+ get_property(check_done GLOBAL PROPERTY _qt_internal_apple_sdk_and_xcode_check_done)
+ if(check_done)
+ return()
+ endif()
+ set_property(GLOBAL PROPERTY _qt_internal_apple_sdk_and_xcode_check_done "TRUE")
+
+ if(IOS)
+ set(min_sdk_version "${QT_SUPPORTED_MIN_IOS_SDK_VERSION}")
+ set(max_sdk_version "${QT_SUPPORTED_MAX_IOS_SDK_VERSION}")
+ set(min_xcode_version "${QT_SUPPORTED_MIN_IOS_XCODE_VERSION}")
+ elseif(VISIONOS)
+ set(min_sdk_version "${QT_SUPPORTED_MIN_VISIONOS_SDK_VERSION}")
+ set(max_sdk_version "${QT_SUPPORTED_MAX_VISIONOS_SDK_VERSION}")
+ set(min_xcode_version "${QT_SUPPORTED_MIN_VISIONOS_XCODE_VERSION}")
+ else()
+ set(min_sdk_version "${QT_SUPPORTED_MIN_MACOS_SDK_VERSION}")
+ set(max_sdk_version "${QT_SUPPORTED_MAX_MACOS_SDK_VERSION}")
+ set(min_xcode_version "${QT_SUPPORTED_MIN_MACOS_XCODE_VERSION}")
+ endif()
+
+ _qt_internal_get_cached_apple_sdk_version(sdk_version)
+ _qt_internal_get_cached_xcode_version(xcode_version)
+
+ if(NOT max_sdk_version MATCHES "^[0-9]+$")
+ message(FATAL_ERROR
+ "Invalid max SDK version: ${max_sdk_version} "
+ "It should be a major version number, without minor or patch version components.")
+ endif()
+
+ # The default differs in different branches.
+ set(failed_check_should_error FALSE)
+
+ if(failed_check_should_error)
+ # Allow downgrading the error into a warning.
+ if(QT_FORCE_WARN_APPLE_SDK_AND_XCODE_CHECK)
+ set(message_type WARNING)
+ set(extra_message " Due to QT_FORCE_WARN_APPLE_SDK_AND_XCODE_CHECK being ON "
+ "the build will continue, but it will likely fail. Use at your own risk.")
+ else()
+ set(message_type FATAL_ERROR)
+ set(extra_message " You can turn this error into a warning by configuring with "
+ "-DQT_FORCE_WARN_APPLE_SDK_AND_XCODE_CHECK=ON, but the build will likely fail. "
+ "Use at your own risk.")
+ endif()
+ else()
+ # Allow upgrading the warning into an error.
+ if(QT_FORCE_FATAL_APPLE_SDK_AND_XCODE_CHECK)
+ set(message_type FATAL_ERROR)
+ set(extra_message " Erroring out due to QT_FORCE_FATAL_APPLE_SDK_AND_XCODE_CHECK "
+ "being ON.")
+ else()
+ set(message_type WARNING)
+ set(extra_message " You can turn this warning into an error by configuring with "
+ "-DQT_FORCE_FATAL_APPLE_SDK_AND_XCODE_CHECK=ON. ")
+ endif()
+ endif()
+
+ if(sdk_version VERSION_LESS min_sdk_version AND NOT QT_NO_APPLE_SDK_MIN_VERSION_CHECK)
+ message(${message_type}
+ "Qt requires at least version ${min_sdk_version} of the platform SDK, "
+ "you're building against version ${sdk_version}. Please upgrade."
+ ${extra_message}
+ )
+ endif()
+
+ if(xcode_version VERSION_LESS min_xcode_version AND NOT QT_NO_XCODE_MIN_VERSION_CHECK)
+ message(${message_type}
+ "Qt requires at least version ${min_xcode_version} of Xcode, "
+ "you're building against version ${xcode_version}. Please upgrade."
+ ${extra_message}
+ )
+ endif()
+
+ if(QT_NO_APPLE_SDK_MAX_VERSION_CHECK)
+ return()
+ endif()
+
+ # Make sure we warn only when the current version is greater than the max supported version.
+ math(EXPR next_after_max_sdk_version "${max_sdk_version} + 1")
+ if(sdk_version VERSION_GREATER_EQUAL next_after_max_sdk_version)
+ message(WARNING
+ "Qt has only been tested with version ${max_sdk_version} "
+ "of the platform SDK, you're using ${sdk_version}. "
+ "This is an unsupported configuration. You may experience build issues, "
+ "and by using "
+ "the ${sdk_version} SDK you are opting in to new features "
+ "that Qt has not been prepared for. "
+ "Please downgrade the SDK you use to build your app to version "
+ "${max_sdk_version}, or configure "
+ "with -DQT_NO_APPLE_SDK_MAX_VERSION_CHECK=ON to silence this warning."
+ )
+ endif()
+endfunction()
+
+function(_qt_internal_finalize_apple_app target)
+ # Shared between macOS and UIKit apps
+
+ _qt_internal_copy_info_plist("${target}")
+ _qt_internal_set_apple_localizations("${target}")
+
+ # Only set the various properties if targeting the Xcode generator, otherwise the various
+ # Xcode tokens are embedded as-is instead of being dynamically evaluated.
+ # This affects things like the version number or application name as reported by Qt API.
+ if(CMAKE_GENERATOR STREQUAL "Xcode")
+ _qt_internal_set_xcode_development_team_id("${target}")
+ _qt_internal_set_xcode_code_sign_style("${target}")
+ _qt_internal_set_xcode_bundle_display_name("${target}")
+ _qt_internal_set_xcode_install_path("${target}")
+ endif()
+
+ _qt_internal_set_xcode_bundle_name("${target}")
+ _qt_internal_set_apple_bundle_identifier("${target}")
+ _qt_internal_set_placeholder_apple_bundle_version("${target}")
+endfunction()
+
+function(_qt_internal_finalize_uikit_app target)
+ if(CMAKE_SYSTEM_NAME STREQUAL iOS)
+ _qt_internal_finalize_ios_app("${target}")
+ else()
+ _qt_internal_finalize_apple_app("${target}")
+ endif()
+endfunction()
+
+function(_qt_internal_finalize_ios_app target)
+ # Must be called before we generate the Info.plist
+ _qt_internal_handle_ios_launch_screen("${target}")
+
+ _qt_internal_finalize_apple_app("${target}")
+ _qt_internal_set_xcode_targeted_device_family("${target}")
+ _qt_internal_set_xcode_bitcode_enablement("${target}")
+ _qt_internal_set_ios_simulator_arch("${target}")
+endfunction()
+
+function(_qt_internal_finalize_macos_app target)
+ get_target_property(is_bundle ${target} MACOSX_BUNDLE)
+ if(NOT is_bundle)
+ return()
+ endif()
+
+ _qt_internal_finalize_apple_app("${target}")
+
+ # Make sure the install rpath has at least the minimum needed if the app
+ # has any non-static frameworks. We can't rigorously know if the app will
+ # have any, even with a static Qt, so always add this. If there are no
+ # frameworks, it won't do any harm.
+ get_property(install_rpath TARGET ${target} PROPERTY INSTALL_RPATH)
+ list(APPEND install_rpath "@executable_path/../Frameworks")
+ list(REMOVE_DUPLICATES install_rpath)
+ set_property(TARGET ${target} PROPERTY INSTALL_RPATH "${install_rpath}")
+endfunction()
diff --git a/cmake/QtPublicCMakeHelpers.cmake b/cmake/QtPublicCMakeHelpers.cmake
new file mode 100644
index 0000000000..ca091fcf9a
--- /dev/null
+++ b/cmake/QtPublicCMakeHelpers.cmake
@@ -0,0 +1,510 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+# copy_if_different works incorrect in Windows if file size if bigger than 2GB.
+# See https://gitlab.kitware.com/cmake/cmake/-/issues/23052 and QTBUG-99491 for details.
+function(_qt_internal_copy_file_if_different_command out_var src_file dst_file)
+ # The CMake version higher than 3.23 doesn't contain the issue
+ if(CMAKE_HOST_WIN32 AND CMAKE_VERSION VERSION_LESS 3.23)
+ set(${out_var} "${CMAKE_COMMAND}"
+ "-DSRC_FILE_PATH=${src_file}"
+ "-DDST_FILE_PATH=${dst_file}"
+ -P "${_qt_6_config_cmake_dir}/QtCopyFileIfDifferent.cmake"
+ PARENT_SCOPE
+ )
+ else()
+ set(${out_var} "${CMAKE_COMMAND}"
+ -E copy_if_different
+ "${src_file}"
+ "${dst_file}"
+ PARENT_SCOPE
+ )
+ endif()
+endfunction()
+
+# The function checks if add_custom_command has the support of the DEPFILE argument.
+function(_qt_internal_check_depfile_support out_var)
+ if(CMAKE_GENERATOR MATCHES "Ninja" OR
+ (CMAKE_VERSION VERSION_GREATER_EQUAL 3.20 AND CMAKE_GENERATOR MATCHES "Makefiles")
+ OR (CMAKE_VERSION VERSION_GREATER_EQUAL 3.21
+ AND (CMAKE_GENERATOR MATCHES "Xcode"
+ OR (CMAKE_GENERATOR MATCHES "Visual Studio ([0-9]+)" AND CMAKE_MATCH_1 GREATER_EQUAL 12)
+ )
+ )
+ )
+ set(${out_var} TRUE)
+ else()
+ set(${out_var} FALSE)
+ endif()
+ set(${out_var} "${${out_var}}" PARENT_SCOPE)
+endfunction()
+
+# Checks if the path points to the cmake directory, like lib/cmake.
+function(__qt_internal_check_path_points_to_cmake_dir result path)
+ string(TOUPPER "${QT_CMAKE_EXPORT_NAMESPACE}" export_namespace_upper)
+ if((INSTALL_LIBDIR AND path MATCHES "/${INSTALL_LIBDIR}/cmake$") OR
+ (${export_namespace_upper}_INSTALL_LIBS AND
+ path MATCHES "/${${export_namespace_upper}_INSTALL_LIBS}/cmake$") OR
+ path MATCHES "/lib/cmake$"
+ )
+ set(${result} TRUE PARENT_SCOPE)
+ else()
+ set(${result} FALSE PARENT_SCOPE)
+ endif()
+endfunction()
+
+# Creates a reverse path to prefix from possible cmake directories. Returns the unchanged path
+# if it doesn't point to cmake directory.
+function(__qt_internal_reverse_prefix_path_from_cmake_dir result cmake_path)
+ string(TOUPPER "${QT_CMAKE_EXPORT_NAMESPACE}" export_namespace_upper)
+ if(INSTALL_LIBDIR AND cmake_path MATCHES "(.+)/${INSTALL_LIBDIR}/cmake$")
+ if(CMAKE_MATCH_1)
+ set(${result} "${CMAKE_MATCH_1}" PARENT_SCOPE)
+ endif()
+ elseif(${export_namespace_upper}_INSTALL_LIBS AND
+ cmake_path MATCHES "(.+)/${${export_namespace_upper}_INSTALL_LIBS}/cmake$")
+ if(CMAKE_MATCH_1)
+ set(${result} "${CMAKE_MATCH_1}" PARENT_SCOPE)
+ endif()
+ elseif(result MATCHES "(.+)/lib/cmake$")
+ if(CMAKE_MATCH_1)
+ set(${result} "${CMAKE_MATCH_1}" PARENT_SCOPE)
+ endif()
+ else()
+ set(${result} "${cmake_path}" PARENT_SCOPE)
+ endif()
+endfunction()
+
+# Returns the possible cmake directories based on prefix_path.
+function(__qt_internal_get_possible_cmake_dirs out_paths prefix_path)
+ set(${out_paths} "")
+
+ if(EXISTS "${prefix_path}/lib/cmake")
+ list(APPEND ${out_paths} "${prefix_path}/lib/cmake")
+ endif()
+
+ string(TOUPPER "${QT_CMAKE_EXPORT_NAMESPACE}" export_namespace_upper)
+ set(next_path "${prefix_path}/${${export_namespace_upper}_INSTALL_LIBS}/cmake")
+ if(${export_namespace_upper}_INSTALL_LIBS AND EXISTS "${next_path}")
+ list(APPEND ${out_paths} "${next_path}")
+ endif()
+
+ set(next_path "${prefix_path}/${INSTALL_LIBDIR}/cmake")
+ if(INSTALL_LIBDIR AND EXISTS "${next_path}")
+ list(APPEND ${out_paths} "${next_path}")
+ endif()
+
+ list(REMOVE_DUPLICATES ${out_paths})
+ set(${out_paths} "${${out_paths}}" PARENT_SCOPE)
+endfunction()
+
+# Collect additional package prefix paths to look for Qt packages, both from command line and the
+# env variable ${prefixes_var}. The result is stored in ${out_var} and is a list of paths ending
+# with "/lib/cmake".
+function(__qt_internal_collect_additional_prefix_paths out_var prefixes_var)
+ if(DEFINED "${out_var}")
+ return()
+ endif()
+
+ set(additional_packages_prefix_paths "")
+
+ set(additional_packages_prefixes "")
+ if(${prefixes_var})
+ list(APPEND additional_packages_prefixes ${${prefixes_var}})
+ endif()
+ if(DEFINED ENV{${prefixes_var}}
+ AND NOT "$ENV{${prefixes_var}}" STREQUAL "")
+ set(prefixes_from_env "$ENV{${prefixes_var}}")
+ if(NOT CMAKE_HOST_WIN32)
+ string(REPLACE ":" ";" prefixes_from_env "${prefixes_from_env}")
+ endif()
+ list(APPEND additional_packages_prefixes ${prefixes_from_env})
+ endif()
+
+ foreach(additional_path IN LISTS additional_packages_prefixes)
+ file(TO_CMAKE_PATH "${additional_path}" additional_path)
+
+ # The prefix paths need to end with lib/cmake to ensure the packages are found when
+ # cross compiling. Search for REROOT_PATH_ISSUE_MARKER in the qt.toolchain.cmake file for
+ # details.
+ # We must pass the values via the PATHS options because the main find_package call uses
+ # NO_DEFAULT_PATH, and thus CMAKE_PREFIX_PATH values are discarded.
+ # CMAKE_FIND_ROOT_PATH values are not discarded and togegher with the PATHS option, it
+ # ensures packages from additional prefixes are found.
+ __qt_internal_check_path_points_to_cmake_dir(is_path_to_cmake "${additional_path}")
+ if(is_path_to_cmake)
+ list(APPEND additional_packages_prefix_paths "${additional_path}")
+ else()
+ __qt_internal_get_possible_cmake_dirs(additional_cmake_dirs "${additional_path}")
+ list(APPEND additional_packages_prefix_paths ${additional_cmake_dirs})
+ endif()
+ endforeach()
+
+ set("${out_var}" "${additional_packages_prefix_paths}" PARENT_SCOPE)
+endfunction()
+
+# Collects CMAKE_MODULE_PATH from QT_ADDITIONAL_PACKAGES_PREFIX_PATH
+function(__qt_internal_collect_additional_module_paths)
+ if(__qt_additional_module_paths_set)
+ return()
+ endif()
+ foreach(prefix_path IN LISTS QT_ADDITIONAL_PACKAGES_PREFIX_PATH)
+ __qt_internal_check_path_points_to_cmake_dir(is_path_to_cmake "${prefix_path}")
+ if(is_path_to_cmake)
+ list(APPEND CMAKE_MODULE_PATH "${prefix_path}/${QT_CMAKE_EXPORT_NAMESPACE}")
+ else()
+ __qt_internal_get_possible_cmake_dirs(additional_cmake_dirs "${additional_path}")
+ list(TRANSFORM additional_cmake_dirs APPEND "/${QT_CMAKE_EXPORT_NAMESPACE}")
+ list(APPEND CMAKE_MODULE_PATH ${additional_cmake_dirs})
+ endif()
+ endforeach()
+ list(REMOVE_DUPLICATES CMAKE_MODULE_PATH)
+ set(CMAKE_MODULE_PATH "${CMAKE_MODULE_PATH}" PARENT_SCOPE)
+ set(__qt_additional_module_paths_set TRUE PARENT_SCOPE)
+endfunction()
+
+# Take a list of prefix paths ending with "/lib/cmake", and return a list of absolute paths with
+# "/lib/cmake" removed.
+function(__qt_internal_prefix_paths_to_roots out_var prefix_paths)
+ set(result "")
+ foreach(path IN LISTS prefix_paths)
+ __qt_internal_reverse_prefix_path_from_cmake_dir(path "${path}")
+ list(APPEND result "${path}")
+ endforeach()
+ set("${out_var}" "${result}" PARENT_SCOPE)
+endfunction()
+
+# This function gets all targets below this directory
+#
+# Multi-value Arguments:
+# EXCLUDE list of target types that should be filtered from resulting list.
+#
+# INCLUDE list of target types that should be filtered from resulting list.
+# EXCLUDE has higher priority than INCLUDE.
+function(_qt_internal_collect_buildsystem_targets result dir)
+ cmake_parse_arguments(arg "" "" "EXCLUDE;INCLUDE" ${ARGN})
+
+ if(NOT _qt_internal_collect_buildsystem_targets_inner)
+ set(${result} "")
+ set(_qt_internal_collect_buildsystem_targets_inner TRUE)
+ endif()
+
+ set(forward_args "")
+ if(arg_EXCLUDE)
+ set(forward_args APPEND EXCLUDE ${arg_EXCLUDE})
+ endif()
+
+ if(arg_INCLUDE)
+ set(forward_args APPEND INCLUDE ${arg_INCLUDE})
+ endif()
+
+ get_property(subdirs DIRECTORY "${dir}" PROPERTY SUBDIRECTORIES)
+
+ # Make sure that we don't hit endless recursion when running qt-cmake-standalone-test on a
+ # in-source test dir, where the currently processed directory lists itself in its SUBDIRECTORIES
+ # property.
+ # See https://bugreports.qt.io/browse/QTBUG-119998
+ # and https://gitlab.kitware.com/cmake/cmake/-/issues/25489
+ # Do it only when QT_INTERNAL_IS_STANDALONE_TEST is set, to avoid the possible slowdown when
+ # processing many subdirectores when configuring all standalone tests rather than just one.
+ if(QT_INTERNAL_IS_STANDALONE_TEST)
+ list(REMOVE_ITEM subdirs "${dir}")
+ endif()
+
+ foreach(subdir IN LISTS subdirs)
+ _qt_internal_collect_buildsystem_targets(${result} "${subdir}" ${forward_args})
+ endforeach()
+ get_property(sub_targets DIRECTORY "${dir}" PROPERTY BUILDSYSTEM_TARGETS)
+ set(real_targets "")
+ if(sub_targets)
+ foreach(target IN LISTS sub_targets)
+ get_target_property(target_type ${target} TYPE)
+ if((NOT arg_INCLUDE OR target_type IN_LIST arg_INCLUDE) AND
+ (NOT arg_EXCLUDE OR (NOT target_type IN_LIST arg_EXCLUDE)))
+ list(APPEND real_targets ${target})
+ endif()
+ endforeach()
+ endif()
+ set(${result} ${${result}} ${real_targets} PARENT_SCOPE)
+endfunction()
+
+# Add a custom target ${target} that is *not* added to the default build target in a safe way.
+# Dependencies must then be added with _qt_internal_add_phony_target_dependencies.
+#
+# What's "safe" in this context? For the Visual Studio generators, we cannot use add_dependencies,
+# because this would enable the dependencies in the default build of the solution. See QTBUG-115166
+# and upstream CMake issue #16668 for details. Instead, we record the dependencies (added with
+# _qt_internal_add_phony_target_dependencies) and create the target at the end of the top-level
+# directory scope.
+#
+# This only works if at least CMake 3.19 is used. Older CMake versions will trigger a warning that
+# can be turned off with the variable ${WARNING_VARIABLE}.
+#
+# For other generators, this is just a call to add_custom_target, unless the target already exists,
+# followed by add_dependencies.
+#
+# Use this function for targets that are not part of the default build, i.e. that should be
+# triggered by the user.
+#
+# TARGET_CREATED_HOOK is the name of a function that is called after the target has been created.
+# It takes the target's name as first and only argument.
+#
+# Example:
+# _qt_internal_add_phony_target(update_translations
+# WARNING_VARIABLE QT_NO_GLOBAL_LUPDATE_TARGET_CREATED_WARNING
+# )
+# _qt_internal_add_phony_target_dependencies(update_translations
+# narf_lupdate_zort_lupdate
+# )
+#
+function(_qt_internal_add_phony_target target)
+ set(no_value_options "")
+ set(single_value_options
+ TARGET_CREATED_HOOK
+ WARNING_VARIABLE
+ )
+ set(multi_value_options "")
+ cmake_parse_arguments(PARSE_ARGV 0 arg
+ "${no_value_options}" "${single_value_options}" "${multi_value_options}"
+ )
+ if("${arg_WARNING_VARIABLE}" STREQUAL "")
+ message(FATAL_ERROR "WARNING_VARIABLE must be provided.")
+ endif()
+ if(CMAKE_GENERATOR MATCHES "^Visual Studio ")
+ if(${CMAKE_VERSION} VERSION_LESS "3.19.0")
+ if(NOT ${${arg_WARNING_VARIABLE}})
+ message(WARNING
+ "Cannot create target ${target} with this CMake version. "
+ "Please upgrade to CMake 3.19.0 or newer. "
+ "Set ${WARNING_VARIABLE} to ON to disable this warning."
+ )
+ endif()
+ return()
+ endif()
+
+ get_property(already_deferred GLOBAL PROPERTY _qt_target_${target}_creation_deferred)
+ if(NOT already_deferred)
+ cmake_language(EVAL CODE
+ "cmake_language(DEFER DIRECTORY \"${CMAKE_SOURCE_DIR}\" CALL _qt_internal_add_phony_target_deferred \"${target}\")"
+ )
+ if(DEFINED arg_TARGET_CREATED_HOOK)
+ set_property(GLOBAL
+ PROPERTY _qt_target_${target}_creation_hook ${arg_TARGET_CREATED_HOOK}
+ )
+ endif()
+ endif()
+ set_property(GLOBAL APPEND PROPERTY _qt_target_${target}_creation_deferred ON)
+ else()
+ if(NOT TARGET ${target})
+ add_custom_target(${target})
+ if(DEFINED arg_TARGET_CREATED_HOOK)
+ if(CMAKE_VERSION VERSION_LESS "3.19")
+ set(incfile
+ "${CMAKE_CURRENT_BINARY_DIR}/.qt_internal_add_phony_target.cmake"
+ )
+ file(WRITE "${incfile}" "${arg_TARGET_CREATED_HOOK}(${target})")
+ include("${incfile}")
+ file(REMOVE "${incfile}")
+ else()
+ cmake_language(CALL "${arg_TARGET_CREATED_HOOK}" "${target}")
+ endif()
+ endif()
+ endif()
+ endif()
+endfunction()
+
+# Adds dependencies to a custom target that has been created with
+# _qt_internal_add_phony_target. See the docstring at _qt_internal_add_phony_target for
+# more details.
+function(_qt_internal_add_phony_target_dependencies target)
+ set(dependencies ${ARGN})
+ if(CMAKE_GENERATOR MATCHES "^Visual Studio ")
+ set_property(GLOBAL APPEND PROPERTY _qt_target_${target}_dependencies ${dependencies})
+
+ # Exclude the dependencies from the solution's default build to avoid them being enabled
+ # accidentally should the user add another dependency to them.
+ set_target_properties(${dependencies} PROPERTIES EXCLUDE_FROM_DEFAULT_BUILD ON)
+ else()
+ add_dependencies(${target} ${dependencies})
+ endif()
+endfunction()
+
+# Hack for the Visual Studio generator. Create the custom target named ${target} and work
+# around the lack of a working add_dependencies by calling 'cmake --build' for every dependency.
+function(_qt_internal_add_phony_target_deferred target)
+ get_property(target_dependencies GLOBAL PROPERTY _qt_target_${target}_dependencies)
+ set(target_commands "")
+ foreach(dependency IN LISTS target_dependencies)
+ list(APPEND target_commands
+ COMMAND "${CMAKE_COMMAND}" --build "${CMAKE_BINARY_DIR}" -t ${dependency}
+ )
+ endforeach()
+ add_custom_target(${target} ${target_commands})
+ get_property(creation_hook GLOBAL PROPERTY _qt_target_${target}_creation_hook)
+ if(creation_hook)
+ cmake_language(CALL ${creation_hook} ${target})
+ endif()
+endfunction()
+
+# The helper function that checks if module was included multiple times, and has the inconsistent
+# set of targets that belong to the module. It's expected that either all 'targets' or none of them
+# will be written to the 'targets_not_defined' variable, if the module was not or was
+# searched before accordingly.
+function(_qt_internal_check_multiple_inclusion targets_not_defined targets)
+ set(targets_defined "")
+ set(${targets_not_defined} "")
+ set(expected_targets "")
+ foreach(expected_target ${targets})
+ list(APPEND expected_targets ${expected_target})
+ if(NOT TARGET Qt::${expected_target})
+ list(APPEND ${targets_not_defined} ${expected_target})
+ endif()
+ if(TARGET Qt::${expected_target})
+ list(APPEND targets_defined ${expected_target})
+ endif()
+ endforeach()
+ if("${targets_defined}" STREQUAL "${expected_targets}")
+ set(${targets_not_defined} "" PARENT_SCOPE)
+ return()
+ endif()
+ if(NOT "${targets_defined}" STREQUAL "")
+ message(FATAL_ERROR "Some (but not all) targets in this export set were already defined."
+ "\nTargets Defined: ${targets_defined}\nTargets not yet defined: "
+ "${${targets_not_defined}}\n"
+ )
+ endif()
+ set(${targets_not_defined} "${${targets_not_defined}}" PARENT_SCOPE)
+endfunction()
+
+# The function is used when creating version less targets using ALIASes.
+function(_qt_internal_create_versionless_alias_targets targets install_namespace)
+ foreach(target IN LISTS targets)
+ add_library(Qt::${target} ALIAS ${install_namespace}::${target})
+ endforeach()
+endfunction()
+
+# The function is used when creating version less targets from scratch but not using ALIASes.
+# It assigns the known properties from the versioned targets to the versionless created in this
+# function. This allows versionless targets mimic the versioned.
+function(_qt_internal_create_versionless_targets targets install_namespace)
+ set(known_interface_properties
+ QT_MAJOR_VERSION
+ AUTOMOC_MACRO_NAMES
+ AUTOUIC_OPTIONS
+ COMPILE_DEFINITIONS
+ COMPILE_FEATURES
+ COMPILE_OPTIONS
+ CXX_MODULE_SETS
+ HEADER_SETS
+ HEADER_SETS_TO_VERIFY
+ INCLUDE_DIRECTORIES
+ LINK_DEPENDS
+ LINK_DIRECTORIES
+ LINK_LIBRARIES
+ LINK_LIBRARIES_DIRECT
+ LINK_LIBRARIES_DIRECT_EXCLUDE
+ LINK_OPTIONS
+ POSITION_INDEPENDENT_CODE
+ PRECOMPILE_HEADERS
+ SOURCES
+ SYSTEM_INCLUDE_DIRECTORIES
+ )
+
+ set(known_qt_exported_properties
+ MODULE_PLUGIN_TYPES
+ QT_DISABLED_PRIVATE_FEATURES
+ QT_DISABLED_PUBLIC_FEATURES
+ QT_ENABLED_PRIVATE_FEATURES
+ QT_ENABLED_PUBLIC_FEATURES
+ QT_QMAKE_PRIVATE_CONFIG
+ QT_QMAKE_PUBLIC_CONFIG
+ QT_QMAKE_PUBLIC_QT_CONFIG
+ )
+
+ set(known_qt_exported_properties_interface_allowed
+ _qt_config_module_name
+ _qt_is_public_module
+ _qt_module_has_headers
+ _qt_module_has_private_headers
+ _qt_module_has_public_headers
+ _qt_module_has_qpa_headers
+ _qt_module_has_rhi_headers
+ _qt_module_include_name
+ _qt_module_interface_name
+ _qt_package_name
+ _qt_package_version
+ _qt_private_module_target_name
+ )
+
+ set(supported_target_types STATIC_LIBRARY MODULE_LIBRARY SHARED_LIBRARY OBJECT_LIBRARY
+ INTERFACE_LIBRARY)
+
+ foreach(target IN LISTS targets)
+ if(NOT TARGET ${install_namespace}::${target})
+ message(FATAL_ERROR "${install_namespace}::${target} is not a target, can not extend"
+ " an alias target")
+ endif()
+
+ get_target_property(type ${install_namespace}::${target} TYPE)
+ if(NOT type)
+ message(FATAL_ERROR "Cannot get the ${install_namespace}::${target} target type.")
+ endif()
+
+ if(NOT "${type}" IN_LIST supported_target_types)
+ message(AUTHOR_WARNING "${install_namespace}::${target} requires the versionless"
+ " target creation, but it has incompatible type ${type}.")
+ continue()
+ endif()
+
+ string(REPLACE "_LIBRARY" "" creation_type "${type}")
+ add_library(Qt::${target} ${creation_type} IMPORTED)
+
+ if(NOT "${type}" STREQUAL "INTERFACE_LIBRARY")
+ foreach(config "" _RELEASE _DEBUG _RELWITHDEBINFO _MINSIZEREL)
+ get_target_property(target_imported_location
+ ${install_namespace}::${target} IMPORTED_LOCATION${config})
+ if(NOT target_imported_location)
+ if("${config}" STREQUAL "")
+ message(FATAL_ERROR "Cannot create versionless target for"
+ " ${install_namespace}::${target}. IMPORTED_LOCATION property is "
+ "missing."
+ )
+ else()
+ continue()
+ endif()
+ endif()
+ set_property(TARGET Qt::${target} PROPERTY
+ IMPORTED_LOCATION${config} "${target_imported_location}")
+ endforeach()
+
+ foreach(property IN LISTS known_qt_exported_properties)
+ get_target_property(exported_property_value
+ ${install_namespace}::${target} ${property})
+ if(exported_property_value)
+ set_property(TARGET Qt::${target} APPEND PROPERTY
+ ${property} "${exported_property_value}")
+ endif()
+ endforeach()
+ endif()
+
+ foreach(property IN LISTS known_interface_properties)
+ get_target_property(interface_property_value
+ ${install_namespace}::${target} INTERFACE_${property})
+ if(interface_property_value)
+ set_property(TARGET Qt::${target} APPEND PROPERTY
+ INTERFACE_${property} "${interface_property_value}")
+ endif()
+ endforeach()
+
+ foreach(property IN LISTS known_qt_exported_properties_interface_allowed)
+ get_target_property(exported_property_value
+ ${install_namespace}::${target} ${property})
+ if(exported_property_value)
+ set_property(TARGET Qt::${target} APPEND PROPERTY
+ ${property} "${exported_property_value}")
+ endif()
+ endforeach()
+
+ set_property(TARGET Qt::${target} PROPERTY _qt_is_versionless_target TRUE)
+ endforeach()
+endfunction()
diff --git a/cmake/QtPublicCMakeVersionHelpers.cmake b/cmake/QtPublicCMakeVersionHelpers.cmake
new file mode 100644
index 0000000000..de896d9d2f
--- /dev/null
+++ b/cmake/QtPublicCMakeVersionHelpers.cmake
@@ -0,0 +1,72 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+function(__qt_internal_get_supported_min_cmake_version_for_using_qt out_var)
+ # This is recorded in Qt6ConfigExtras.cmake
+ set(supported_version "${QT_SUPPORTED_MIN_CMAKE_VERSION_FOR_USING_QT}")
+ set(${out_var} "${supported_version}" PARENT_SCOPE)
+endfunction()
+
+function(__qt_internal_get_computed_min_cmake_version_for_using_qt out_var)
+ # Allow override when configuring user project.
+ if(QT_FORCE_MIN_CMAKE_VERSION_FOR_USING_QT)
+ set(computed_min_version "${QT_FORCE_MIN_CMAKE_VERSION_FOR_USING_QT}")
+
+ # Set in QtConfigExtras.cmake.
+ elseif(QT_COMPUTED_MIN_CMAKE_VERSION_FOR_USING_QT)
+ set(computed_min_version "${QT_COMPUTED_MIN_CMAKE_VERSION_FOR_USING_QT}")
+ else()
+ message(FATAL_ERROR
+ "Qt Developer error: Can't compute the minimum CMake version required to use this Qt.")
+ endif()
+
+ set(${out_var} "${computed_min_version}" PARENT_SCOPE)
+endfunction()
+
+function(__qt_internal_warn_if_min_cmake_version_not_met)
+ __qt_internal_get_supported_min_cmake_version_for_using_qt(min_supported_version)
+ __qt_internal_get_computed_min_cmake_version_for_using_qt(computed_min_version)
+
+ if(NOT min_supported_version STREQUAL computed_min_version
+ AND computed_min_version VERSION_LESS min_supported_version)
+ message(WARNING
+ "The minimum required CMake version to use Qt is: '${min_supported_version}'. "
+ "You have explicitly chosen to require a lower minimum CMake version: '${computed_min_version}'. "
+ "Using Qt with this CMake version is not officially supported. Use at your own risk."
+ )
+ endif()
+endfunction()
+
+function(__qt_internal_require_suitable_cmake_version_for_using_qt)
+ # Skip the public project check if we're building a Qt repo because it's too early to do
+ # it at find_package(Qt6) time.
+ # Instead, a separate check is done in qt_build_repo_begin.
+ # We detect a Qt repo by the presence of the QT_REPO_MODULE_VERSION variable set in .cmake.conf
+ # of each repo.
+ if(QT_REPO_MODULE_VERSION)
+ return()
+ endif()
+
+ # Only do the setup once per directory scope, because Qt6 is a dependency for many packages,
+ # and a recursive call will show the warning multiple times.
+ if(__qt_internal_set_up_cmake_minimum_required_version_already_done)
+ return()
+ endif()
+ set(__qt_internal_set_up_cmake_minimum_required_version_already_done TRUE PARENT_SCOPE)
+
+ # Check the overall minimum required CMake version when consuming any Qt CMake package.
+ __qt_internal_warn_if_min_cmake_version_not_met()
+ __qt_internal_get_computed_min_cmake_version_for_using_qt(computed_min_version)
+
+ if(CMAKE_VERSION VERSION_LESS computed_min_version)
+ set(major_minor "${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}")
+ message(FATAL_ERROR
+ "CMake ${computed_min_version} or higher is required to use Qt. "
+ "You are running version ${CMAKE_VERSION} "
+ "Qt requires newer CMake features to work correctly. You can lower the minimum "
+ "required version by passing "
+ "-DQT_FORCE_MIN_CMAKE_VERSION_FOR_USING_QT=${major_minor} when configuring the "
+ "project. Using Qt with this CMake version is not officially supported. "
+ "Use at your own risk.")
+ endif()
+endfunction()
diff --git a/cmake/QtPublicDependencyHelpers.cmake b/cmake/QtPublicDependencyHelpers.cmake
new file mode 100644
index 0000000000..bd8b4a55c4
--- /dev/null
+++ b/cmake/QtPublicDependencyHelpers.cmake
@@ -0,0 +1,294 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+# Note that target_dep_list does not accept a list of values, but a var name that contains the
+# list of dependencies. See foreach block for reference.
+macro(_qt_internal_find_third_party_dependencies target target_dep_list)
+ foreach(__qt_${target}_target_dep IN LISTS ${target_dep_list})
+ list(GET __qt_${target}_target_dep 0 __qt_${target}_pkg)
+ list(GET __qt_${target}_target_dep 1 __qt_${target}_is_optional)
+ list(GET __qt_${target}_target_dep 2 __qt_${target}_version)
+ list(GET __qt_${target}_target_dep 3 __qt_${target}_components)
+ list(GET __qt_${target}_target_dep 4 __qt_${target}_optional_components)
+ set(__qt_${target}_find_package_args "${__qt_${target}_pkg}")
+ if(__qt_${target}_version)
+ list(APPEND __qt_${target}_find_package_args "${__qt_${target}_version}")
+ endif()
+ if(__qt_${target}_components)
+ string(REPLACE " " ";" __qt_${target}_components "${__qt_${target}_components}")
+ list(APPEND __qt_${target}_find_package_args COMPONENTS ${__qt_${target}_components})
+ endif()
+ if(__qt_${target}_optional_components)
+ string(REPLACE " " ";"
+ __qt_${target}_optional_components "${__qt_${target}_optional_components}")
+ list(APPEND __qt_${target}_find_package_args
+ OPTIONAL_COMPONENTS ${__qt_${target}_optional_components})
+ endif()
+
+ _qt_internal_save_find_package_context_for_debugging(${target})
+
+ if(__qt_${target}_is_optional)
+ if(${CMAKE_FIND_PACKAGE_NAME}_FIND_QUIETLY)
+ list(APPEND __qt_${target}_find_package_args QUIET)
+ endif()
+ find_package(${__qt_${target}_find_package_args})
+ else()
+ find_dependency(${__qt_${target}_find_package_args})
+ endif()
+ endforeach()
+endmacro()
+
+# Note that target_dep_list does not accept a list of values, but a var name that contains the
+# list of dependencies. See foreach block for reference.
+macro(_qt_internal_find_tool_dependencies target target_dep_list)
+ if(NOT "${${target_dep_list}}" STREQUAL "" AND NOT "${QT_HOST_PATH}" STREQUAL "")
+ # Make sure that the tools find the host tools first
+ set(BACKUP_${target}_CMAKE_PREFIX_PATH ${CMAKE_PREFIX_PATH})
+ set(BACKUP_${target}_CMAKE_FIND_ROOT_PATH ${CMAKE_FIND_ROOT_PATH})
+ list(PREPEND CMAKE_PREFIX_PATH "${QT_HOST_PATH_CMAKE_DIR}"
+ "${_qt_additional_host_packages_prefix_paths}")
+ list(PREPEND CMAKE_FIND_ROOT_PATH "${QT_HOST_PATH}"
+ "${_qt_additional_host_packages_root_paths}")
+ endif()
+
+ foreach(__qt_${target}_target_dep IN LISTS ${target_dep_list})
+ list(GET __qt_${target}_target_dep 0 __qt_${target}_pkg)
+ list(GET __qt_${target}_target_dep 1 __qt_${target}_version)
+
+ unset(__qt_${target}_find_package_args)
+ if(${CMAKE_FIND_PACKAGE_NAME}_FIND_QUIETLY)
+ list(APPEND __qt_${target}_find_package_args QUIET)
+ endif()
+
+ _qt_internal_save_find_package_context_for_debugging(${target})
+
+ find_package(${__qt_${target}_pkg}
+ ${__qt_${target}_version}
+ ${__qt_${target}_find_package_args}
+ PATHS
+ "${CMAKE_CURRENT_LIST_DIR}/.."
+ "${_qt_cmake_dir}"
+ ${_qt_additional_packages_prefix_paths}
+ )
+ if (NOT ${__qt_${target}_pkg}_FOUND AND NOT QT_ALLOW_MISSING_TOOLS_PACKAGES)
+ set(${CMAKE_FIND_PACKAGE_NAME}_FOUND FALSE)
+ set(${CMAKE_FIND_PACKAGE_NAME}_NOT_FOUND_MESSAGE
+"${CMAKE_FIND_PACKAGE_NAME} could not be found because dependency \
+${__qt_${target}_pkg} could not be found.")
+ if(NOT "${QT_HOST_PATH}" STREQUAL "")
+ set(CMAKE_PREFIX_PATH ${BACKUP_${target}_CMAKE_PREFIX_PATH})
+ set(CMAKE_FIND_ROOT_PATH ${BACKUP_${target}_CMAKE_FIND_ROOT_PATH})
+ endif()
+ return()
+ endif()
+ endforeach()
+ if(NOT "${${target_dep_list}}" STREQUAL "" AND NOT "${QT_HOST_PATH}" STREQUAL "")
+ set(CMAKE_PREFIX_PATH ${BACKUP_${target}_CMAKE_PREFIX_PATH})
+ set(CMAKE_FIND_ROOT_PATH ${BACKUP_${target}_CMAKE_FIND_ROOT_PATH})
+ endif()
+endmacro()
+
+# Please note the target_dep_list accepts not the actual list values but the list names that
+# contain preformed dependencies. See foreach block for reference.
+# The same applies for find_dependency_path_list.
+macro(_qt_internal_find_qt_dependencies target target_dep_list find_dependency_path_list)
+ foreach(__qt_${target}_target_dep IN LISTS ${target_dep_list})
+ list(GET __qt_${target}_target_dep 0 __qt_${target}_pkg)
+ list(GET __qt_${target}_target_dep 1 __qt_${target}_version)
+
+ if (NOT ${__qt_${target}_pkg}_FOUND)
+
+ # TODO: Remove Private handling once sufficient time has passed, aka all developers
+ # updated their builds not to contain stale FooDependencies.cmake files without the
+ # _qt_package_name property.
+ set(__qt_${target}_pkg_names ${__qt_${target}_pkg})
+ if(__qt_${target}_pkg MATCHES "(.*)Private$")
+ set(__qt_${target}_pkg_names "${CMAKE_MATCH_1};${__qt_${target}_pkg}")
+ endif()
+
+ _qt_internal_save_find_package_context_for_debugging(${target})
+
+ find_dependency(${__qt_${target}_pkg} ${__qt_${target}_version}
+ NAMES
+ ${__qt_${target}_pkg_names}
+ PATHS
+ ${QT_BUILD_CMAKE_PREFIX_PATH}
+ ${${find_dependency_path_list}}
+ ${_qt_additional_packages_prefix_paths}
+ ${__qt_use_no_default_path_for_qt_packages}
+ )
+ endif()
+ endforeach()
+endmacro()
+
+
+# TODO: Remove once a dependency update completes and most developers have the Dependencies.cmake
+# files updated in their builds.
+# The name is too generic, it doesn't look for any kind of dependencies but only Qt package
+# dependencies.
+macro(_qt_internal_find_dependencies target_dep_list find_dependency_path_list)
+ _qt_internal_find_qt_dependencies("none" "${target_dep_list}" "${find_dependency_path_list}")
+endmacro()
+
+# If a dependency package was not found, provide some hints in the error message on how to debug
+# the issue.
+#
+# pkg_name_var should be the variable name that contains the package that was not found.
+# e.g. __qt_Core_pkg
+#
+# message_out_var should contain the variable name of the original "not found" message, and it
+# will have the hints appended to it as a string. e.g. ${CMAKE_FIND_PACKAGE_NAME}_NOT_FOUND_MESSAGE
+#
+# infix is used as a unique prefix to retrieve the find_package paths context for the last package
+# that was not found, for debugging purposes.
+#
+# The function should not be called in Dependencies.cmake files directly, because find_dependency
+# returns out of the included file.
+macro(_qt_internal_suggest_dependency_debugging infix pkg_name_var message_out_var)
+ if(${pkg_name_var}
+ AND NOT ${CMAKE_FIND_PACKAGE_NAME}_FOUND
+ AND ${message_out_var})
+ if(CMAKE_VERSION VERSION_GREATER_EQUAL "3.23")
+ string(APPEND ${message_out_var}
+ "\nConfiguring with --debug-find-pkg=${${pkg_name_var}} might reveal \
+details why the package was not found.")
+ elseif(CMAKE_VERSION VERSION_GREATER_EQUAL "3.17")
+ string(APPEND ${message_out_var}
+ "\nConfiguring with -DCMAKE_FIND_DEBUG_MODE=TRUE might reveal \
+details why the package was not found.")
+ endif()
+
+ if(NOT QT_DEBUG_FIND_PACKAGE)
+ string(APPEND ${message_out_var}
+ "\nConfiguring with -DQT_DEBUG_FIND_PACKAGE=ON will print the values of some of \
+the path variables that find_package uses to try and find the package.")
+ else()
+ string(APPEND ${message_out_var}
+ "\n find_package search path values and other context for the last package that was not found:"
+ "\n CMAKE_MODULE_PATH: ${_qt_${infix}_CMAKE_MODULE_PATH}"
+ "\n CMAKE_PREFIX_PATH: ${_qt_${infix}_CMAKE_PREFIX_PATH}"
+ "\n \$ENV{CMAKE_PREFIX_PATH}: $ENV{CMAKE_PREFIX_PATH}"
+ "\n CMAKE_FIND_ROOT_PATH: ${_qt_${infix}_CMAKE_FIND_ROOT_PATH}"
+ "\n _qt_additional_packages_prefix_paths: ${_qt_${infix}_qt_additional_packages_prefix_paths}"
+ "\n _qt_additional_host_packages_prefix_paths: ${_qt_${infix}_qt_additional_host_packages_prefix_paths}"
+ "\n _qt_cmake_dir: ${_qt_${infix}_qt_cmake_dir}"
+ "\n QT_HOST_PATH: ${QT_HOST_PATH}"
+ "\n Qt6HostInfo_DIR: ${Qt6HostInfo_DIR}"
+ "\n Qt6_DIR: ${Qt6_DIR}"
+ "\n CMAKE_TOOLCHAIN_FILE: ${CMAKE_TOOLCHAIN_FILE}"
+ "\n CMAKE_FIND_ROOT_PATH_MODE_PACKAGE: ${CMAKE_FIND_ROOT_PATH_MODE_PACKAGE}"
+ "\n CMAKE_SYSROOT: ${CMAKE_SYSROOT}"
+ "\n \$ENV{PATH}: $ENV{PATH}"
+ )
+ endif()
+ endif()
+endmacro()
+
+# Save find_package search paths context just before a find_package call, to be shown with a
+# package not found message.
+macro(_qt_internal_save_find_package_context_for_debugging infix)
+ if(QT_DEBUG_FIND_PACKAGE)
+ set(_qt_${infix}_CMAKE_MODULE_PATH "${CMAKE_MODULE_PATH}")
+ set(_qt_${infix}_CMAKE_PREFIX_PATH "${CMAKE_PREFIX_PATH}")
+ set(_qt_${infix}_CMAKE_FIND_ROOT_PATH "${CMAKE_FIND_ROOT_PATH}")
+ set(_qt_${infix}_qt_additional_packages_prefix_paths
+ "${_qt_additional_packages_prefix_paths}")
+ set(_qt_${infix}_qt_additional_host_packages_prefix_paths
+ "${_qt_additional_host_packages_prefix_paths}")
+ set(_qt_${infix}_qt_cmake_dir "${_qt_cmake_dir}")
+ endif()
+endmacro()
+
+function(_qt_internal_determine_if_host_info_package_needed out_var)
+ set(needed FALSE)
+
+ # If a QT_HOST_PATH is provided when configuring qtbase, we assume it's a cross build
+ # and thus we require the QT_HOST_PATH to be provided also when using the cross-built Qt.
+ # This tells the QtConfigDependencies file to do appropriate requirement checks.
+ if(NOT "${QT_HOST_PATH}" STREQUAL "" AND NOT QT_NO_REQUIRE_HOST_PATH_CHECK)
+ set(needed TRUE)
+ endif()
+ set(${out_var} "${needed}" PARENT_SCOPE)
+endfunction()
+
+macro(_qt_internal_find_host_info_package platform_requires_host_info)
+ if(${platform_requires_host_info})
+ find_package(Qt6HostInfo
+ CONFIG
+ REQUIRED
+ PATHS "${QT_HOST_PATH}"
+ "${QT_HOST_PATH_CMAKE_DIR}"
+ NO_CMAKE_FIND_ROOT_PATH
+ NO_DEFAULT_PATH)
+ endif()
+endmacro()
+
+macro(_qt_internal_setup_qt_host_path
+ host_path_required
+ initial_qt_host_path
+ initial_qt_host_path_cmake_dir
+ )
+ # Set up QT_HOST_PATH and do sanity checks.
+ # A host path is required when cross-compiling but optional when doing a native build.
+ # Requiredness can be overridden via variable.
+ if(DEFINED QT_REQUIRE_HOST_PATH_CHECK)
+ set(_qt_platform_host_path_required "${QT_REQUIRE_HOST_PATH_CHECK}")
+ else()
+ set(_qt_platform_host_path_required "${host_path_required}")
+ endif()
+
+ if(_qt_platform_host_path_required)
+ # QT_HOST_PATH precedence:
+ # - cache variable / command line option
+ # - environment variable
+ # - initial QT_HOST_PATH when qtbase was configured (and the directory exists)
+ if(NOT DEFINED QT_HOST_PATH)
+ if(DEFINED ENV{QT_HOST_PATH})
+ set(QT_HOST_PATH "$ENV{QT_HOST_PATH}" CACHE PATH "")
+ elseif(NOT "${initial_qt_host_path}" STREQUAL "" AND EXISTS "${initial_qt_host_path}")
+ set(QT_HOST_PATH "${initial_qt_host_path}" CACHE PATH "")
+ endif()
+ endif()
+
+ if(NOT QT_HOST_PATH STREQUAL "")
+ get_filename_component(_qt_platform_host_path_absolute "${QT_HOST_PATH}" ABSOLUTE)
+ endif()
+
+ if("${QT_HOST_PATH}" STREQUAL "" OR NOT EXISTS "${_qt_platform_host_path_absolute}")
+ message(FATAL_ERROR
+ "To use a cross-compiled Qt, please set the QT_HOST_PATH cache variable to the "
+ "location of your host Qt installation.")
+ endif()
+
+ # QT_HOST_PATH_CMAKE_DIR is needed to work around the rerooting issue when looking for host
+ # tools. See REROOT_PATH_ISSUE_MARKER.
+ # Prefer initially configured path if none was explicitly set.
+ if(NOT DEFINED QT_HOST_PATH_CMAKE_DIR)
+ if(NOT "${initial_qt_host_path_cmake_dir}" STREQUAL ""
+ AND EXISTS "${initial_qt_host_path_cmake_dir}")
+ set(QT_HOST_PATH_CMAKE_DIR "${initial_qt_host_path_cmake_dir}" CACHE PATH "")
+ else()
+ # First try to auto-compute the location instead of requiring to set
+ # QT_HOST_PATH_CMAKE_DIR explicitly.
+ set(__qt_candidate_host_path_cmake_dir "${QT_HOST_PATH}/lib/cmake")
+ if(__qt_candidate_host_path_cmake_dir
+ AND EXISTS "${__qt_candidate_host_path_cmake_dir}")
+ set(QT_HOST_PATH_CMAKE_DIR
+ "${__qt_candidate_host_path_cmake_dir}" CACHE PATH "")
+ endif()
+ endif()
+ endif()
+
+ if(NOT QT_HOST_PATH_CMAKE_DIR STREQUAL "")
+ get_filename_component(_qt_platform_host_path_cmake_dir_absolute
+ "${QT_HOST_PATH_CMAKE_DIR}" ABSOLUTE)
+ endif()
+
+ if("${QT_HOST_PATH_CMAKE_DIR}" STREQUAL ""
+ OR NOT EXISTS "${_qt_platform_host_path_cmake_dir_absolute}")
+ message(FATAL_ERROR
+ "To use a cross-compiled Qt, please set the QT_HOST_PATH_CMAKE_DIR cache variable "
+ "to the location of your host Qt installation lib/cmake directory.")
+ endif()
+ endif()
+endmacro()
diff --git a/cmake/QtPublicExternalProjectHelpers.cmake b/cmake/QtPublicExternalProjectHelpers.cmake
new file mode 100644
index 0000000000..07096523d0
--- /dev/null
+++ b/cmake/QtPublicExternalProjectHelpers.cmake
@@ -0,0 +1,86 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+include_guard()
+
+# Get CMake variables that are needed to build external projects such as examples or CMake test
+# projects.
+#
+# CMAKE_DIR_VAR: Variable name to store the path to the Qt6 CMake config module.
+#
+# PREFIXES_VAR: Variable name to store the prefixes that can be passed as CMAKE_PREFIX_PATH.
+#
+# ADDITIONAL_PACKAGES_PREFIXES_VAR: Variable name to store the prefixes that can be appended to
+# QT_ADDITIONAL_PACKAGES_PREFIX_PATH.
+function(_qt_internal_get_build_vars_for_external_projects)
+ set(no_value_options "")
+ set(single_value_options
+ CMAKE_DIR_VAR
+ PREFIXES_VAR
+ ADDITIONAL_PACKAGES_PREFIXES_VAR
+ )
+ set(multi_value_options "")
+ cmake_parse_arguments(PARSE_ARGV 0 arg
+ "${no_value_options}" "${single_value_options}" "${multi_value_options}"
+ )
+
+ # Standalone tests and examples have QT_BUILD_DIR pointing to the fake standalone prefix.
+ # Use instead the relocatable prefix, because qt must have been built / installed by this point.
+ if(QT_INTERNAL_BUILD_STANDALONE_PARTS)
+ qt_path_join(qt_cmake_dir
+ "${QT_BUILD_INTERNALS_RELOCATABLE_INSTALL_PREFIX}"
+ "${INSTALL_LIBDIR}/cmake/${QT_CMAKE_EXPORT_NAMESPACE}"
+ )
+
+ set(qt_prefixes "${QT_BUILD_INTERNALS_RELOCATABLE_INSTALL_PREFIX}")
+ set(qt_additional_packages_prefixes "${qt_prefixes}")
+
+ if(QT_WILL_INSTALL)
+ list(APPEND qt_prefixes "${QT6_INSTALL_PREFIX}")
+ endif()
+ # TODO: Fix example/test builds when using Conan / install prefixes are different for each repo.
+ elseif(QT_SUPERBUILD OR QtBase_BINARY_DIR)
+ # When doing a top-level build or when building qtbase,
+ # always use the Config file from the current build directory, even for prefix builds.
+ # We strive to allow building examples without installing Qt first, which means we can't
+ # use the install or staging Config files.
+ set(qt_prefixes "${QT_BUILD_DIR}")
+ set(qt_cmake_dir "${QT_CONFIG_BUILD_DIR}/${QT_CMAKE_EXPORT_NAMESPACE}")
+ set(qt_additional_packages_prefixes "")
+ else()
+ # This is a per-repo build that isn't the qtbase repo, so we know that
+ # qtbase was found via find_package() and Qt6_DIR must be set
+ set(qt_cmake_dir "${${QT_CMAKE_EXPORT_NAMESPACE}_DIR}")
+
+ # In a prefix build of a non-qtbase repo, we want to pick up the installed Config files
+ # for all repos except the one that is currently built. For the repo that is currently
+ # built, we pick up the Config files from the current repo build dir instead.
+ # For non-prefix builds, there's only one prefix, the main build dir.
+ # Both are handled by this assignment.
+ set(qt_prefixes "${QT_BUILD_DIR}")
+
+ # Appending to QT_ADDITIONAL_PACKAGES_PREFIX_PATH helps find Qt6 components in
+ # non-qtbase prefix builds because we use NO_DEFAULT_PATH in find_package calls.
+ # It also handles the cross-compiling scenario where we need to adjust both the root path
+ # and prefixes, with the prefixes containing lib/cmake. This leverages the infrastructure
+ # previously added for Conan.
+ set(qt_additional_packages_prefixes "${qt_prefixes}")
+
+ # In a prefix build, look up all repo Config files in the install prefix,
+ # except for the current repo, which will look in the build dir (handled above).
+ if(QT_WILL_INSTALL)
+ list(APPEND qt_prefixes "${QT6_INSTALL_PREFIX}")
+ endif()
+ endif()
+
+ if(arg_CMAKE_DIR_VAR)
+ set("${arg_CMAKE_DIR_VAR}" "${qt_cmake_dir}" PARENT_SCOPE)
+ endif()
+ if(arg_PREFIXES_VAR)
+ set("${arg_PREFIXES_VAR}" "${qt_prefixes}" PARENT_SCOPE)
+ endif()
+ if(arg_ADDITIONAL_PACKAGES_PREFIXES_VAR)
+ set("${arg_ADDITIONAL_PACKAGES_PREFIXES_VAR}" "${qt_additional_packages_prefixes}"
+ PARENT_SCOPE)
+ endif()
+endfunction()
diff --git a/cmake/QtPublicFinalizerHelpers.cmake b/cmake/QtPublicFinalizerHelpers.cmake
new file mode 100644
index 0000000000..96b5c6c740
--- /dev/null
+++ b/cmake/QtPublicFinalizerHelpers.cmake
@@ -0,0 +1,35 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+# Helper to check if the finalizer mode should be used.
+# If true, use finalizer mode.
+# If false, use regular mode (usage requirement propagation via associated Qt module)
+# Arguments:
+# DEFAULT_VALUE specifies the default value of the finalizer mode flag if it is not set.
+function(__qt_internal_check_finalizer_mode target out_var finalizer)
+ set(option_args "")
+ set(single_args DEFAULT_VALUE)
+ set(multi_args "")
+ cmake_parse_arguments(arg "${option_args}" "${single_args}" "${multi_args}" ${ARGN})
+
+ if(NOT DEFINED arg_DEFAULT_VALUE OR arg_DEFAULT_VALUE)
+ set(arg_DEFAULT_VALUE TRUE)
+ else()
+ set(arg_DEFAULT_VALUE FALSE)
+ endif()
+ get_target_property(value ${target} _qt_${finalizer}_finalizer_mode)
+ if("${value}" STREQUAL "value-NOTFOUND")
+ __qt_internal_enable_finalizer_mode(${target} ${finalizer} "${arg_DEFAULT_VALUE}")
+ set(value "${arg_DEFAULT_VALUE}")
+ endif()
+ set(${out_var} "${value}" PARENT_SCOPE)
+endfunction()
+
+function(__qt_internal_enable_finalizer_mode target finalizer enabled)
+ if(enabled)
+ set(enabled "TRUE")
+ else()
+ set(enabled "FALSE")
+ endif()
+ set_property(TARGET "${target}" PROPERTY _qt_${finalizer}_finalizer_mode "${enabled}")
+endfunction()
diff --git a/cmake/QtPublicFindPackageHelpers.cmake b/cmake/QtPublicFindPackageHelpers.cmake
new file mode 100644
index 0000000000..69f4f69e40
--- /dev/null
+++ b/cmake/QtPublicFindPackageHelpers.cmake
@@ -0,0 +1,6 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+function(qt_internal_disable_find_package_global_promotion target)
+ set_target_properties("${target}" PROPERTIES _qt_no_promote_global TRUE)
+endfunction()
diff --git a/cmake/QtPublicPluginHelpers.cmake b/cmake/QtPublicPluginHelpers.cmake
new file mode 100644
index 0000000000..7087c31234
--- /dev/null
+++ b/cmake/QtPublicPluginHelpers.cmake
@@ -0,0 +1,562 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+# Gets the qt plugin type of the given plugin into out_var_plugin_type.
+# Also sets out_var_has_plugin_type to TRUE or FALSE depending on whether the plugin type was found.
+function(__qt_internal_plugin_get_plugin_type
+ plugin_target
+ out_var_has_plugin_type
+ out_var_plugin_type)
+ set(has_plugin_type TRUE)
+
+ set(plugin_target_versioned "${QT_CMAKE_EXPORT_NAMESPACE}::${plugin_target}")
+
+ get_target_property(_plugin_type "${plugin_target_versioned}" QT_PLUGIN_TYPE)
+ if(NOT _plugin_type)
+ message("Warning: plugin ${plugin_target_versioned} has no plugin type set, skipping.")
+ set(has_plugin_type FALSE)
+ else()
+ set(${out_var_plugin_type} "${_plugin_type}" PARENT_SCOPE)
+ endif()
+
+ set(${out_var_has_plugin_type} "${has_plugin_type}" PARENT_SCOPE)
+endfunction()
+
+# Gets the qt plugin class name of the given target into out_var.
+function(__qt_internal_plugin_has_class_name plugin_target out_var)
+ set(plugin_target_versioned "${QT_CMAKE_EXPORT_NAMESPACE}::${plugin_target}")
+
+ get_target_property(classname "${plugin_target_versioned}" QT_PLUGIN_CLASS_NAME)
+ if(NOT classname)
+ message("Warning: plugin ${plugin_target_versioned} has no class name, skipping.")
+ endif()
+
+ # If unset, it will be -NOTFOUND and still evaluate to false.
+ set(${out_var} "${classname}" PARENT_SCOPE)
+endfunction()
+
+# Constructs a generator expression which decides whether a plugin will be used.
+#
+# The conditions are based on the various properties set in qt_import_plugins.
+
+# All the TARGET_PROPERTY genexes are evaluated in the context of the currently linked target,
+# unless the TARGET argument is given.
+#
+# The genex is saved into out_var.
+function(__qt_internal_get_static_plugin_condition_genex
+ plugin_target_unprefixed
+ out_var)
+ set(options)
+ set(oneValueArgs TARGET)
+ set(multiValueArgs)
+ cmake_parse_arguments(arg "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
+
+ set(plugin_target "${QT_CMAKE_EXPORT_NAMESPACE}::${plugin_target_unprefixed}")
+ set(plugin_target_versionless "Qt::${plugin_target_unprefixed}")
+
+ get_target_property(_plugin_type "${plugin_target}" QT_PLUGIN_TYPE)
+
+ set(target_infix "")
+ if(arg_TARGET)
+ set(target_infix "${arg_TARGET},")
+ endif()
+
+ set(_default_plugins_are_enabled
+ "$<NOT:$<STREQUAL:$<GENEX_EVAL:$<TARGET_PROPERTY:${target_infix}QT_DEFAULT_PLUGINS>>,0>>")
+ set(_manual_plugins_genex "$<GENEX_EVAL:$<TARGET_PROPERTY:${target_infix}QT_PLUGINS>>")
+ set(_no_plugins_genex "$<GENEX_EVAL:$<TARGET_PROPERTY:${target_infix}QT_NO_PLUGINS>>")
+
+ # Plugin genex marker for prl processing.
+ set(_is_plugin_marker_genex "$<BOOL:QT_IS_PLUGIN_GENEX>")
+
+ set(_plugin_is_default "$<TARGET_PROPERTY:${plugin_target},QT_DEFAULT_PLUGIN>")
+
+ # The code in here uses the properties defined in qt_import_plugins (Qt6CoreMacros.cmake)
+
+ # INCLUDE
+ set(_plugin_is_whitelisted "$<IN_LIST:${plugin_target},${_manual_plugins_genex}>")
+ set(_plugin_versionless_is_whitelisted
+ "$<IN_LIST:${plugin_target_versionless},${_manual_plugins_genex}>")
+
+ # Note: qt_import_plugins sets the QT_PLUGINS_${_plugin_type} to "-"
+ # when excluding it with EXCLUDE_BY_TYPE,
+ # which ensures that no plug-in will be supported unless explicitly re-added afterwards.
+ string(CONCAT _plugin_is_not_blacklisted
+ "$<AND:"
+ "$<NOT:" # EXCLUDE
+ "$<IN_LIST:${plugin_target},${_no_plugins_genex}>"
+ ">,"
+ "$<NOT:"
+ "$<IN_LIST:${plugin_target_versionless},${_no_plugins_genex}>"
+ ">,"
+ # Excludes both plugins targeted by EXCLUDE_BY_TYPE and not included in
+ # INCLUDE_BY_TYPE.
+ "$<STREQUAL:,$<GENEX_EVAL:$<TARGET_PROPERTY:${target_infix}QT_PLUGINS_${_plugin_type}>>>"
+ ">"
+ )
+
+ # Support INCLUDE_BY_TYPE
+ string(CONCAT _plugin_is_in_type_whitelist
+ "$<IN_LIST:"
+ "${plugin_target},"
+ "$<GENEX_EVAL:"
+ "$<TARGET_PROPERTY:${target_infix}QT_PLUGINS_${_plugin_type}>"
+ ">"
+ ">"
+ )
+ string(CONCAT _plugin_versionless_is_in_type_whitelist
+ "$<IN_LIST:"
+ "${plugin_target_versionless},"
+ "$<GENEX_EVAL:"
+ "$<TARGET_PROPERTY:${target_infix}QT_PLUGINS_${_plugin_type}>"
+ ">"
+ ">"
+ )
+
+ # No point in linking the plugin initialization source file into static libraries. The
+ # initialization symbol will be discarded by the linker when the static lib is linked into an
+ # executable or shared library, because nothing is referencing the global static symbol.
+ set(type_genex "$<TARGET_PROPERTY:${target_infix}TYPE>")
+ set(no_static_genex "$<NOT:$<STREQUAL:${type_genex},STATIC_LIBRARY>>")
+
+ # Complete condition that defines whether a static plugin is linked
+ string(CONCAT _plugin_condition
+ "$<BOOL:$<AND:"
+ "${_is_plugin_marker_genex},"
+ "${no_static_genex},"
+ "$<OR:"
+ "${_plugin_is_whitelisted},"
+ "${_plugin_versionless_is_whitelisted},"
+ "${_plugin_is_in_type_whitelist},"
+ "${_plugin_versionless_is_in_type_whitelist},"
+ "$<AND:"
+ "${_default_plugins_are_enabled},"
+ "${_plugin_is_default},"
+ "${_plugin_is_not_blacklisted}"
+ ">"
+ ">"
+ ">>"
+ )
+
+ set(${out_var} "${_plugin_condition}" PARENT_SCOPE)
+endfunction()
+
+# Wraps the genex condition to evaluate to true only when using the regular plugin importing mode
+# (not finalizer mode).
+function(__qt_internal_get_plugin_condition_regular_mode plugin_condition out_var)
+ set(not_finalizer_mode "$<NOT:$<BOOL:$<TARGET_PROPERTY:_qt_static_plugins_finalizer_mode>>>")
+ set(full_plugin_condition "$<AND:${plugin_condition},${not_finalizer_mode}>")
+ set(${out_var} "${full_plugin_condition}" PARENT_SCOPE)
+endfunction()
+
+# Link plugin via usage requirements of associated Qt module.
+function(__qt_internal_add_static_plugin_linkage plugin_target qt_module_target)
+ __qt_internal_get_static_plugin_condition_genex("${plugin_target}" plugin_condition)
+ __qt_internal_get_plugin_condition_regular_mode("${plugin_condition}" full_plugin_condition)
+
+ set(plugin_target "${QT_CMAKE_EXPORT_NAMESPACE}::${plugin_target}")
+
+ # If this condition is true, we link against the plug-in
+ set(plugin_genex "$<${full_plugin_condition}:${plugin_target}>")
+ target_link_libraries(${qt_module_target} INTERFACE "${plugin_genex}")
+endfunction()
+
+# Generates C++ import macro source code for given plugin
+function(__qt_internal_get_plugin_import_macro plugin_target out_var)
+ set(plugin_target_prefixed "${QT_CMAKE_EXPORT_NAMESPACE}::${plugin_target}")
+
+ # Query the class name of plugin targets prefixed with a Qt namespace and without, this is
+ # needed to support plugin object initializers created by user projects.
+ set(class_name"")
+ set(class_name_prefixed "")
+
+ if(TARGET ${plugin_target})
+ get_target_property(class_name "${plugin_target}" QT_PLUGIN_CLASS_NAME)
+ endif()
+
+ if(TARGET ${plugin_target_prefixed})
+ get_target_property(class_name_prefixed "${plugin_target_prefixed}" QT_PLUGIN_CLASS_NAME)
+ endif()
+
+ if(NOT class_name AND NOT class_name_prefixed)
+ message(FATAL_ERROR "No QT_PLUGIN_CLASS_NAME value on target: '${plugin_target}'")
+ endif()
+
+ # Qt prefixed target takes priority.
+ if(class_name_prefixed)
+ set(class_name "${class_name_prefixed}")
+ endif()
+
+ set(${out_var} "Q_IMPORT_PLUGIN(${class_name})\n" PARENT_SCOPE)
+endfunction()
+
+function(__qt_internal_get_plugin_include_prelude out_var)
+ set(${out_var} "#include <QtPlugin>\n" PARENT_SCOPE)
+endfunction()
+
+# Set up plugin initialization via usage requirements of associated Qt module.
+#
+# Adds the plugin init object library as an INTERFACE source of the plugin target.
+# This is similar to how it was done before, except instead of generating a C++ file and compiling
+# it as part of the user project, we just specify the pre-compiled object file as an INTERFACE
+# source so that user projects don't have to compile it. User project builds will thus be shorter.
+function(__qt_internal_add_static_plugin_import_macro
+ plugin_target
+ qt_module_target
+ qt_module_unprefixed)
+
+ __qt_internal_get_static_plugin_init_target_name("${plugin_target}" plugin_init_target)
+ set(plugin_init_target_namespaced "${QT_CMAKE_EXPORT_NAMESPACE}::${plugin_init_target}")
+
+ __qt_internal_propagate_object_library(
+ "${QT_CMAKE_EXPORT_NAMESPACE}::${plugin_target}"
+ "${plugin_init_target_namespaced}"
+ EXTRA_CONDITIONS
+ "$<NOT:$<BOOL:$<TARGET_PROPERTY:_qt_static_plugins_finalizer_mode>>>"
+ )
+endfunction()
+
+# Get target name of object library which is used to initialize a qt plugin.
+function(__qt_internal_get_static_plugin_init_target_name plugin_target out_var)
+ # Keep the target name short, so we don't hit long path issues on Windows.
+ set(plugin_init_target "${plugin_target}_init")
+
+ set(${out_var} "${plugin_init_target}" PARENT_SCOPE)
+endfunction()
+
+# Create an object library that initializes a static qt plugin.
+#
+# The object library contains a single generated C++ file that calls Q_IMPORT_PLUGIN(plugin_class).
+# The object library is exported as part of the Qt build and consumed by user applications
+# that link to qt plugins.
+#
+# The created target name is assigned to 'out_var_plugin_init_target'.
+function(__qt_internal_add_static_plugin_init_object_library
+ plugin_target
+ out_var_plugin_init_target)
+
+ __qt_internal_get_plugin_import_macro(${plugin_target} import_macro)
+ __qt_internal_get_plugin_include_prelude(include_prelude)
+ set(import_content "${include_prelude}${import_macro}")
+
+ string(MAKE_C_IDENTIFIER "${plugin_target}" plugin_target_identifier)
+ set(generated_qt_plugin_file_name
+ "${CMAKE_CURRENT_BINARY_DIR}/${plugin_target_identifier}_init.cpp")
+
+ file(GENERATE
+ OUTPUT "${generated_qt_plugin_file_name}"
+ CONTENT "${import_content}"
+ )
+
+ # CMake versions earlier than 3.18.0 can't find the generated file for some reason,
+ # failing at generation phase.
+ # Explicitly marking the file as GENERATED fixes the issue.
+ set_source_files_properties("${generated_qt_plugin_file_name}" PROPERTIES GENERATED TRUE)
+
+ __qt_internal_get_static_plugin_init_target_name("${plugin_target}" plugin_init_target)
+
+ qt6_add_library("${plugin_init_target}" OBJECT "${generated_qt_plugin_file_name}")
+ target_link_libraries(${plugin_init_target}
+ PRIVATE
+
+ # Core provides the symbols needed by Q_IMPORT_PLUGIN.
+ ${QT_CMAKE_EXPORT_NAMESPACE}::Core
+ )
+
+ set_property(TARGET ${plugin_init_target} PROPERTY _is_qt_plugin_init_target TRUE)
+ set_property(TARGET ${plugin_init_target} APPEND PROPERTY
+ EXPORT_PROPERTIES _is_qt_plugin_init_target
+ )
+
+ set(${out_var_plugin_init_target} "${plugin_init_target}" PARENT_SCOPE)
+endfunction()
+
+# Collect a list of genexes to link plugin libraries.
+function(__qt_internal_collect_plugin_libraries plugin_targets out_var)
+ set(plugins_to_link "")
+
+ foreach(plugin_target ${plugin_targets})
+ set(plugin_target_versioned "${QT_CMAKE_EXPORT_NAMESPACE}::${plugin_target}")
+ get_target_property(type "${plugin_target_versioned}" TYPE)
+ if(NOT type STREQUAL STATIC_LIBRARY)
+ continue()
+ endif()
+
+ __qt_internal_get_static_plugin_condition_genex(
+ "${plugin_target}"
+ plugin_condition)
+
+ list(APPEND plugins_to_link "$<${plugin_condition}:${plugin_target_versioned}>")
+ endforeach()
+
+ set("${out_var}" "${plugins_to_link}" PARENT_SCOPE)
+endfunction()
+
+# Collect a list of genexes to link plugin initializer object libraries.
+#
+# The object libraries are only linked if the associated plugins are linked.
+function(__qt_internal_collect_plugin_init_libraries plugin_targets out_var)
+ set(plugin_inits_to_link "")
+
+ foreach(plugin_target ${plugin_targets})
+ set(plugin_target_versioned "${QT_CMAKE_EXPORT_NAMESPACE}::${plugin_target}")
+ get_target_property(type "${plugin_target_versioned}" TYPE)
+ if(NOT type STREQUAL STATIC_LIBRARY)
+ continue()
+ endif()
+
+ __qt_internal_get_static_plugin_condition_genex(
+ "${plugin_target}"
+ plugin_condition)
+
+ __qt_internal_get_static_plugin_init_target_name("${plugin_target}" plugin_init_target)
+ set(plugin_init_target_versioned "${QT_CMAKE_EXPORT_NAMESPACE}::${plugin_init_target}")
+
+ list(APPEND plugin_inits_to_link "$<${plugin_condition}:${plugin_init_target_versioned}>")
+ endforeach()
+
+ set("${out_var}" "${plugin_inits_to_link}" PARENT_SCOPE)
+endfunction()
+
+# Collect a list of genexes to deploy plugin libraries.
+function(__qt_internal_collect_plugin_library_files target plugin_targets out_var)
+ set(library_files "")
+
+ foreach(plugin_target ${plugin_targets})
+ set(plugin_target_versioned "${QT_CMAKE_EXPORT_NAMESPACE}::${plugin_target}")
+ __qt_internal_get_static_plugin_condition_genex(
+ "${plugin_target}"
+ plugin_condition
+ TARGET ${target}
+ )
+
+ set(target_genex "$<${plugin_condition}:${plugin_target_versioned}>")
+ list(APPEND library_files "$<$<BOOL:${target_genex}>:$<TARGET_FILE:${target_genex}>>")
+ endforeach()
+
+ set("${out_var}" "${library_files}" PARENT_SCOPE)
+endfunction()
+
+# Collects all plugin targets discovered by walking the dependencies of ${target}.
+#
+# Walks immediate dependencies and their transitive dependencies.
+# Plugins are collected by inspecting the _qt_plugins property found on any dependency Qt target.
+function(__qt_internal_collect_plugin_targets_from_dependencies target out_var)
+ set(dep_targets "")
+
+ __qt_internal_collect_all_target_dependencies("${target}" dep_targets)
+
+ set(plugin_targets "")
+ foreach(dep_target ${dep_targets})
+ get_target_property(plugins ${dep_target} _qt_plugins)
+ if(plugins)
+ list(APPEND plugin_targets ${plugins})
+ endif()
+ endforeach()
+
+ # Plugins that are specified via qt_import_plugin's INCLUDE or INCLUDE_BY_TYPE can have
+ # dependencies on Qt modules. These modules in turn might bring in more default plugins to link
+ # So it's recursive. Do only one pass for now. Try to extract the included static plugins, walk
+ # their public and private dependencies, check if any of them are Qt modules that provide more
+ # plugins and extract the target names of those plugins.
+ __qt_internal_collect_plugin_targets_from_dependencies_of_plugins(
+ "${target}" recursive_plugin_targets)
+ if(recursive_plugin_targets)
+ list(APPEND plugin_targets ${recursive_plugin_targets})
+ endif()
+ list(REMOVE_DUPLICATES plugin_targets)
+
+ set("${out_var}" "${plugin_targets}" PARENT_SCOPE)
+endfunction()
+
+# Helper to collect plugin targets from encountered module dependencies as a result of walking
+# dependencies. These module dependencies might expose additional plugins.
+function(__qt_internal_collect_plugin_targets_from_dependencies_of_plugins target out_var)
+ set(assigned_plugins_overall "")
+
+ get_target_property(assigned_qt_plugins "${target}" QT_PLUGINS)
+
+ if(assigned_qt_plugins)
+ foreach(assigned_qt_plugin ${assigned_qt_plugins})
+ if(TARGET "${assigned_qt_plugin}")
+ list(APPEND assigned_plugins_overall "${assigned_qt_plugin}")
+ endif()
+ endforeach()
+ endif()
+
+ get_target_property(assigned_qt_plugins_by_type "${target}" _qt_plugins_by_type)
+
+ if(assigned_qt_plugins_by_type)
+ foreach(assigned_qt_plugin ${assigned_qt_plugins_by_type})
+ if(TARGET "${assigned_qt_plugin}")
+ list(APPEND assigned_plugins_overall "${assigned_qt_plugin}")
+ endif()
+ endforeach()
+ endif()
+
+ set(plugin_targets "")
+ foreach(target ${assigned_plugins_overall})
+ __qt_internal_walk_libs(
+ "${target}"
+ dep_targets
+ _discarded_out_var
+ "qt_private_link_library_targets"
+ "collect_targets")
+
+ foreach(dep_target ${dep_targets})
+ get_target_property(plugins ${dep_target} _qt_plugins)
+ if(plugins)
+ list(APPEND plugin_targets ${plugins})
+ endif()
+ endforeach()
+ endforeach()
+
+ list(REMOVE_DUPLICATES plugin_targets)
+
+ set("${out_var}" "${plugin_targets}" PARENT_SCOPE)
+endfunction()
+
+# Generate plugin information files for deployment
+#
+# Arguments:
+# OUT_PLUGIN_TARGETS - Variable name to store the plugin targets that were collected with
+# __qt_internal_collect_plugin_targets_from_dependencies.
+function(__qt_internal_generate_plugin_deployment_info target)
+ set(no_value_options "")
+ set(single_value_options "OUT_PLUGIN_TARGETS")
+ set(multi_value_options "")
+ cmake_parse_arguments(PARSE_ARGV 0 arg
+ "${no_value_options}" "${single_value_options}" "${multi_value_options}"
+ )
+
+ __qt_internal_collect_plugin_targets_from_dependencies("${target}" plugin_targets)
+ if(NOT "${arg_OUT_PLUGIN_TARGETS}" STREQUAL "")
+ set("${arg_OUT_PLUGIN_TARGETS}" "${plugin_targets}" PARENT_SCOPE)
+ endif()
+
+ get_target_property(marked_for_deployment ${target} _qt_marked_for_deployment)
+ if(NOT marked_for_deployment)
+ return()
+ endif()
+
+ __qt_internal_collect_plugin_library_files(${target} "${plugin_targets}" plugins_files)
+ set(plugins_files "$<FILTER:${plugins_files},EXCLUDE,^$>")
+
+ _qt_internal_get_deploy_impl_dir(deploy_impl_dir)
+ set(file_path "${deploy_impl_dir}/${target}-plugins")
+ get_cmake_property(is_multi_config GENERATOR_IS_MULTI_CONFIG)
+ if(is_multi_config)
+ string(APPEND file_path "-$<CONFIG>")
+ endif()
+ string(APPEND file_path ".cmake")
+
+ file(GENERATE
+ OUTPUT ${file_path}
+ CONTENT "set(__QT_DEPLOY_PLUGINS ${plugins_files})"
+ )
+endfunction()
+
+# Main logic of finalizer mode.
+function(__qt_internal_apply_plugin_imports_finalizer_mode target)
+ # Process a target only once.
+ get_target_property(processed ${target} _qt_plugin_finalizer_imports_processed)
+ if(processed)
+ return()
+ endif()
+
+ __qt_internal_generate_plugin_deployment_info(${target}
+ OUT_PLUGIN_TARGETS plugin_targets)
+
+ # By default if the project hasn't explicitly opted in or out, use finalizer mode.
+ # The precondition for this is that qt_finalize_target was called (either explicitly by the user
+ # or auto-deferred by CMake 3.19+).
+ __qt_internal_check_finalizer_mode("${target}"
+ use_finalizer_mode
+ static_plugins
+ DEFAULT_VALUE "TRUE"
+ )
+
+ if(NOT use_finalizer_mode)
+ return()
+ endif()
+
+ __qt_internal_collect_plugin_init_libraries("${plugin_targets}" init_libraries)
+ __qt_internal_collect_plugin_libraries("${plugin_targets}" plugin_libraries)
+
+ target_link_libraries(${target} PRIVATE "${plugin_libraries}" "${init_libraries}")
+
+ set_target_properties(${target} PROPERTIES _qt_plugin_finalizer_imports_processed TRUE)
+endfunction()
+
+# Include CMake plugin packages that belong to the Qt module ${target} and initialize automatic
+# linkage of the plugins in static builds.
+# The variables inside the macro have to be named unique to the module because an included Plugin
+# file might look up another module dependency that calls the same macro before the first one
+# has finished processing, which can silently override the values if the variables are not unique.
+macro(__qt_internal_include_plugin_packages target)
+ set(__qt_${target}_plugin_module_target "${QT_CMAKE_EXPORT_NAMESPACE}::${target}")
+ set(__qt_${target}_plugins "")
+
+ # Properties can't be set on aliased targets, so make sure to unalias the target. This is needed
+ # when Qt examples are built as part of the Qt build itself.
+ get_target_property(_aliased_target ${__qt_${target}_plugin_module_target} ALIASED_TARGET)
+ if(_aliased_target)
+ set(__qt_${target}_plugin_module_target ${_aliased_target})
+ endif()
+
+ # Include all PluginConfig.cmake files and update the _qt_plugins and QT_PLUGINS property of
+ # the module. The underscored version is the one we will use going forward to have compatibility
+ # with INTERFACE libraries. QT_PLUGINS is now deprecated and only kept so that we don't break
+ # existing projects using it (like CMake itself).
+ file(GLOB __qt_${target}_plugin_config_files
+ "${CMAKE_CURRENT_LIST_DIR}/${QT_CMAKE_EXPORT_NAMESPACE}*PluginConfig.cmake")
+ foreach(__qt_${target}_plugin_config_file ${__qt_${target}_plugin_config_files})
+ string(REGEX REPLACE
+ "^.*/${QT_CMAKE_EXPORT_NAMESPACE}(.*Plugin)Config.cmake$"
+ "\\1"
+ __qt_${target}_qt_plugin "${__qt_${target}_plugin_config_file}")
+ include("${__qt_${target}_plugin_config_file}")
+ if(TARGET "${QT_CMAKE_EXPORT_NAMESPACE}::${__qt_${target}_qt_plugin}")
+ list(APPEND __qt_${target}_plugins ${__qt_${target}_qt_plugin})
+ endif()
+ endforeach()
+ set_property(TARGET ${__qt_${target}_plugin_module_target}
+ PROPERTY _qt_plugins ${__qt_${target}_plugins})
+
+ # TODO: Deprecated. Remove in Qt 7.
+ set_property(TARGET ${__qt_${target}_plugin_module_target}
+ PROPERTY QT_PLUGINS ${__qt_${target}_plugins})
+
+ get_target_property(__qt_${target}_have_added_plugins_already
+ ${__qt_${target}_plugin_module_target} __qt_internal_plugins_added)
+ if(__qt_${target}_have_added_plugins_already)
+ return()
+ endif()
+
+ foreach(plugin_target ${__qt_${target}_plugins})
+ __qt_internal_plugin_get_plugin_type("${plugin_target}" __has_plugin_type __plugin_type)
+ if(NOT __has_plugin_type)
+ continue()
+ endif()
+
+ __qt_internal_plugin_has_class_name("${plugin_target}" __has_class_name)
+ if(NOT __has_class_name)
+ continue()
+ endif()
+
+ list(APPEND "QT_ALL_PLUGINS_FOUND_BY_FIND_PACKAGE_${__plugin_type}" "${plugin_target}")
+
+ # Auto-linkage should be set up only for static plugins.
+ set(plugin_target_versioned "${QT_CMAKE_EXPORT_NAMESPACE}::${plugin_target}")
+ get_target_property(type "${plugin_target_versioned}" TYPE)
+ if(type STREQUAL STATIC_LIBRARY)
+ __qt_internal_add_static_plugin_linkage(
+ "${plugin_target}" "${__qt_${target}_plugin_module_target}")
+ __qt_internal_add_static_plugin_import_macro(
+ "${plugin_target}" ${__qt_${target}_plugin_module_target} "${target}")
+ endif()
+ endforeach()
+
+ set_target_properties(
+ ${__qt_${target}_plugin_module_target} PROPERTIES __qt_internal_plugins_added TRUE)
+endmacro()
diff --git a/cmake/QtPublicTargetHelpers.cmake b/cmake/QtPublicTargetHelpers.cmake
new file mode 100644
index 0000000000..02d5546560
--- /dev/null
+++ b/cmake/QtPublicTargetHelpers.cmake
@@ -0,0 +1,337 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+function(__qt_internal_strip_target_directory_scope_token target out_var)
+ # In CMake versions earlier than CMake 3.18, a subdirectory scope id is appended to the
+ # target name if the target is referenced in a target_link_libraries command from a
+ # different directory scope than where the target was created.
+ # Strip it.
+ #
+ # For informational purposes, in CMake 3.18, the target name looks as follows:
+ # ::@(0x5604cb3f6b50);Threads::Threads;::@
+ # This case doesn't have to be stripped (at least for now), because when we iterate over
+ # link libraries, the tokens appear as separate target names.
+ #
+ # Example: Threads::Threads::@<0x5604cb3f6b50>
+ # Output: Threads::Threads
+ string(REGEX REPLACE "::@<.+>$" "" target "${target}")
+ set("${out_var}" "${target}" PARENT_SCOPE)
+endfunction()
+
+# Tests if linker could resolve circular dependencies between object files and static libraries.
+function(__qt_internal_static_link_order_public_test result)
+ # We could trust iOS linker
+ if(IOS)
+ set(QT_HAVE_LINK_ORDER_MATTERS "FALSE" CACHE INTERNAL "Link order matters")
+ endif()
+
+ if(DEFINED QT_HAVE_LINK_ORDER_MATTERS)
+ set(${result} "${QT_HAVE_LINK_ORDER_MATTERS}" PARENT_SCOPE)
+ return()
+ endif()
+
+ if(EXISTS "${QT_CMAKE_DIR}")
+ set(test_source_basedir "${QT_CMAKE_DIR}/..")
+ else()
+ set(test_source_basedir "${_qt_cmake_dir}/${QT_CMAKE_EXPORT_NAMESPACE}")
+ endif()
+
+ try_compile(${result}
+ "${CMAKE_CURRENT_BINARY_DIR}/config.tests/static_link_order"
+ "${test_source_basedir}/config.tests/static_link_order"
+ static_link_order_test
+ static_link_order_test
+ )
+ message(STATUS "Check if linker can resolve circular dependencies - ${${result}}")
+
+ # Invert the result
+ if(${result})
+ set(${result} FALSE)
+ else()
+ set(${result} TRUE)
+ endif()
+
+ set(QT_HAVE_LINK_ORDER_MATTERS "${${result}}" CACHE INTERNAL "Link order matters")
+
+ set(${result} "${${result}}" PARENT_SCOPE)
+endfunction()
+
+# Sets _qt_link_order_matters flag for the target.
+function(__qt_internal_set_link_order_matters target link_order_matters)
+ if(NOT TARGET ${target})
+ message(FATAL_ERROR "Unable to set _qt_link_order_matters flag. ${target} is not a target.")
+ endif()
+
+ get_target_property(aliased_target ${target} ALIASED_TARGET)
+ if(aliased_target)
+ set(target "${aliased_target}")
+ endif()
+
+ if(link_order_matters)
+ set(link_order_matters TRUE)
+ else()
+ set(link_order_matters FALSE)
+ endif()
+ set_target_properties(${target} PROPERTIES _qt_link_order_matters "${link_order_matters}")
+endfunction()
+
+# Function combines __qt_internal_static_link_order_public_test and
+# __qt_internal_set_link_order_matters calls on Qt::Platform target.
+function(__qt_internal_check_link_order_matters)
+ __qt_internal_static_link_order_public_test(
+ link_order_matters
+ )
+ __qt_internal_set_link_order_matters(
+ ${QT_CMAKE_EXPORT_NAMESPACE}::Platform "${link_order_matters}"
+ )
+
+ if("${ARGC}" GREATER "0" AND NOT ARGV0 STREQUAL "")
+ set(${ARGV0} ${link_order_matters} PARENT_SCOPE)
+ endif()
+endfunction()
+
+# Constructs a TARGET_POLICY genex expression if the policy is available.
+function(__qt_internal_get_cmp0099_genex_check result)
+ if(POLICY CMP0099)
+ set(${result} "$<BOOL:$<TARGET_POLICY:CMP0099>>" PARENT_SCOPE)
+ else()
+ set(${result} "$<BOOL:FALSE>" PARENT_SCOPE)
+ endif()
+endfunction()
+
+function(__qt_internal_check_cmp0099_available)
+ set(platform_target ${QT_CMAKE_EXPORT_NAMESPACE}::Platform)
+ get_target_property(aliased_target ${platform_target} ALIASED_TARGET)
+ if(aliased_target)
+ set(platform_target "${aliased_target}")
+ endif()
+
+ __qt_internal_get_cmp0099_genex_check(cmp0099_check)
+ set_target_properties(${platform_target} PROPERTIES
+ _qt_cmp0099_policy_check "${cmp0099_check}"
+ )
+
+ set(result TRUE)
+ if(NOT POLICY CMP0099)
+ set(result FALSE)
+ endif()
+
+ if("${ARGC}" GREATER "0" AND NOT ARGV0 STREQUAL "")
+ set(${ARGV0} ${result} PARENT_SCOPE)
+ endif()
+endfunction()
+
+function(__qt_internal_process_dependency_object_libraries target)
+ # The CMake versions greater than 3.21 take care about the order of object files in a
+ # linker line, it's expected that all object files are located at the beginning of the linker
+ # line.
+ # So circular dependencies between static libraries and object files are resolved and no need
+ # to call the finalizer code.
+ if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.21)
+ return()
+ endif()
+ get_target_property(processed ${target} _qt_object_libraries_finalizer_processed)
+ if(processed)
+ return()
+ endif()
+ set_target_properties(${target} PROPERTIES _qt_object_libraries_finalizer_processed TRUE)
+
+ get_target_property(qt_link_order_matters
+ ${QT_CMAKE_EXPORT_NAMESPACE}::Platform _qt_link_order_matters
+ )
+ __qt_internal_check_finalizer_mode(${target}
+ use_finalizer_mode
+ object_libraries
+ DEFAULT_VALUE "${qt_link_order_matters}"
+ )
+
+ if(NOT use_finalizer_mode)
+ return()
+ endif()
+
+ __qt_internal_collect_dependency_object_libraries(${target} objects)
+ target_sources(${target} PRIVATE "${objects}")
+endfunction()
+
+function(__qt_internal_collect_dependency_object_libraries target out_var)
+ set_property(GLOBAL PROPERTY _qt_processed_object_libraries "")
+
+ __qt_internal_collect_object_libraries_recursively(object_libraries ${target} ${target})
+
+ # Collect object libraries of plugins and plugin dependencies.
+ __qt_internal_collect_plugin_targets_from_dependencies(${target} plugin_targets)
+ __qt_internal_collect_dependency_plugin_object_libraries(${target}
+ "${plugin_targets}"
+ plugin_objects
+ )
+
+ set_property(GLOBAL PROPERTY _qt_processed_object_libraries "")
+ __qt_internal_get_cmp0099_genex_check(cmp0099_check)
+
+ list(REMOVE_DUPLICATES object_libraries)
+ set(objects "")
+ foreach(dep IN LISTS object_libraries)
+ list(PREPEND objects "$<$<NOT:${cmp0099_check}>:$<TARGET_OBJECTS:${dep}>>")
+ endforeach()
+
+ set(${out_var} "${plugin_objects};${objects}" PARENT_SCOPE)
+endfunction()
+
+function(__qt_internal_collect_dependency_plugin_object_libraries target plugin_targets out_var)
+ __qt_internal_get_cmp0099_genex_check(cmp0099_check)
+ set(plugin_objects "")
+ foreach(plugin_target IN LISTS plugin_targets)
+ __qt_internal_collect_object_libraries_recursively(plugin_object_libraries
+ "${QT_CMAKE_EXPORT_NAMESPACE}::${plugin_target}"
+ ${target}
+ )
+ __qt_internal_get_static_plugin_condition_genex("${plugin_target}" plugin_condition)
+
+ foreach(plugin_object_library IN LISTS plugin_object_libraries)
+ string(JOIN "" plugin_objects_genex
+ "$<"
+ "$<AND:"
+ "$<NOT:${cmp0099_check}>,"
+ "${plugin_condition}"
+ ">"
+ ":$<TARGET_OBJECTS:${plugin_object_library}>"
+ ">"
+ )
+ list(APPEND plugin_objects "${plugin_objects_genex}")
+ endforeach()
+ endforeach()
+ set(${out_var} "${plugin_objects}" PARENT_SCOPE)
+endfunction()
+
+function(__qt_internal_collect_object_libraries_recursively out_var target initial_target)
+ get_property(processed_object_libraries GLOBAL PROPERTY _qt_processed_object_libraries)
+
+ set(interface_libs "")
+ set(libs "")
+ if(NOT "${target}" STREQUAL "${initial_target}")
+ get_target_property(interface_libs ${target} INTERFACE_LINK_LIBRARIES)
+ endif()
+ get_target_property(type ${target} TYPE)
+ if(NOT type STREQUAL "INTERFACE_LIBRARY")
+ get_target_property(libs ${target} LINK_LIBRARIES)
+ endif()
+
+ set(object_libraries "")
+ foreach(lib IN LISTS libs interface_libs)
+ # Extract possible target from exported LINK_ONLY dependencies.
+ # This is super important for traversing backing library dependencies of qml plugins.
+ if(lib MATCHES "^\\$<LINK_ONLY:(.*)>$")
+ set(lib "${CMAKE_MATCH_1}")
+ endif()
+ if(TARGET ${lib})
+ get_target_property(aliased_target ${lib} ALIASED_TARGET)
+ if(aliased_target)
+ set(lib ${aliased_target})
+ endif()
+
+ if(${lib} IN_LIST processed_object_libraries)
+ continue()
+ else()
+ list(APPEND processed_object_libraries ${lib})
+ set_property(GLOBAL APPEND PROPERTY _qt_processed_object_libraries ${lib})
+ endif()
+
+ get_target_property(is_qt_propagated_object_library ${lib}
+ _is_qt_propagated_object_library
+ )
+ if(is_qt_propagated_object_library)
+ list(APPEND object_libraries ${lib})
+ else()
+ __qt_internal_collect_object_libraries_recursively(next_level_object_libraries
+ ${lib}
+ ${initial_target}
+ )
+ list(APPEND object_libraries ${next_level_object_libraries})
+ endif()
+ endif()
+ endforeach()
+ set(${out_var} "${object_libraries}" PARENT_SCOPE)
+endfunction()
+
+function(__qt_internal_promote_target_to_global target)
+ get_property(is_global TARGET ${target} PROPERTY IMPORTED_GLOBAL)
+ if(NOT is_global)
+ message(DEBUG "Promoting target to global: '${target}'")
+ set_property(TARGET ${target} PROPERTY IMPORTED_GLOBAL TRUE)
+ endif()
+endfunction()
+
+function(__qt_internal_promote_target_to_global_checked target)
+ # With CMake version 3.21 we use a different mechanism that allows us to promote all targets
+ # within a scope.
+ if(QT_PROMOTE_TO_GLOBAL_TARGETS AND CMAKE_VERSION VERSION_LESS 3.21)
+ __qt_internal_promote_target_to_global(${target})
+ endif()
+endfunction()
+
+function(__qt_internal_promote_targets_in_dir_scope_to_global)
+ # IMPORTED_TARGETS got added in 3.21.
+ if(CMAKE_VERSION VERSION_LESS 3.21)
+ return()
+ endif()
+
+ get_directory_property(targets IMPORTED_TARGETS)
+ foreach(target IN LISTS targets)
+ __qt_internal_promote_target_to_global(${target})
+ endforeach()
+endfunction()
+
+function(__qt_internal_promote_targets_in_dir_scope_to_global_checked)
+ if(QT_PROMOTE_TO_GLOBAL_TARGETS)
+ __qt_internal_promote_targets_in_dir_scope_to_global()
+ endif()
+endfunction()
+
+# This function ends up being called multiple times as part of a find_package(Qt6Foo) call,
+# due sub-packages depending on the Qt6 package. Ensure the finalizer is ran only once per
+# directory scope.
+function(__qt_internal_defer_promote_targets_in_dir_scope_to_global)
+ get_directory_property(is_deferred _qt_promote_targets_is_deferred)
+ if(NOT is_deferred)
+ set_property(DIRECTORY PROPERTY _qt_promote_targets_is_deferred TRUE)
+
+ if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.19)
+ cmake_language(DEFER CALL __qt_internal_promote_targets_in_dir_scope_to_global_checked)
+ endif()
+ endif()
+endfunction()
+
+function(_qt_internal_set_up_static_runtime_library target)
+ if(QT_FEATURE_static_runtime)
+ if(MSVC)
+ set_property(TARGET ${target} PROPERTY
+ MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")
+ elseif(MINGW)
+ get_target_property(target_type ${target} TYPE)
+ if(target_type STREQUAL "EXECUTABLE")
+ set(link_option PRIVATE)
+ else()
+ set(link_option INTERFACE)
+ endif()
+ if(CLANG)
+ target_link_options(${target} ${link_option} "LINKER:-Bstatic")
+ else()
+ target_link_options(${target} ${link_option} "-static")
+ endif()
+ endif()
+ endif()
+endfunction()
+
+function(_qt_internal_warn_about_example_add_subdirectory)
+ # This is set by qt_build_repo_impl_examples() in QtBuildRepoHelpers.cmake, only for developer
+ # builds, to catch examples that are added via add_subdirectory instead of via
+ # qt_internal_add_example.
+ if(QT_WARN_ABOUT_EXAMPLE_ADD_SUBDIRECTORY)
+ get_filename_component(dir_name "${PROJECT_SOURCE_DIR}" NAME)
+ message(AUTHOR_WARNING
+ "It looks like this example project was added via add_subdirectory instead of via "
+ "qt_internal_add_example. This causes issues in certain build configurations. Please "
+ "change the code to use\n qt_internal_add_example(${dir_name})\ninstead."
+ )
+ endif()
+endfunction()
diff --git a/cmake/QtPublicTestHelpers.cmake b/cmake/QtPublicTestHelpers.cmake
new file mode 100644
index 0000000000..771911c5d5
--- /dev/null
+++ b/cmake/QtPublicTestHelpers.cmake
@@ -0,0 +1,108 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+# This function wraps COMMAND with cmake script, that makes possible standalone run with external
+# arguments.
+#
+# Generated wrapper will be written to OUTPUT_FILE.
+# If WORKING_DIRECTORY is not set COMMAND will be executed in CMAKE_CURRENT_BINARY_DIR.
+# Variables from ENVIRONMENT will be set before COMMAND execution.
+# PRE_RUN and POST_RUN arguments may contain extra cmake code that supposed to be executed before
+# and after COMMAND, respectively. Both arguments accept a list of cmake script language
+# constructions. Each item of the list will be concantinated into single string with '\n' separator.
+# COMMAND_ECHO option takes a value like it does for execute_process, and passes that value to
+# execute_process.
+function(_qt_internal_create_command_script)
+ #This style of parsing keeps ';' in ENVIRONMENT variables
+ cmake_parse_arguments(PARSE_ARGV 0 arg
+ ""
+ "OUTPUT_FILE;WORKING_DIRECTORY;COMMAND_ECHO"
+ "COMMAND;ENVIRONMENT;PRE_RUN;POST_RUN"
+ )
+
+ if(NOT arg_COMMAND)
+ message(FATAL_ERROR "qt_internal_create_command_script: COMMAND is not specified")
+ endif()
+
+ if(NOT arg_OUTPUT_FILE)
+ message(FATAL_ERROR "qt_internal_create_command_script: Wrapper OUTPUT_FILE\
+is not specified")
+ endif()
+
+ if(NOT arg_WORKING_DIRECTORY AND NOT QNX)
+ set(arg_WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}")
+ endif()
+
+ set(environment_extras)
+ set(skipNext false)
+ if(arg_ENVIRONMENT)
+ list(LENGTH arg_ENVIRONMENT length)
+ math(EXPR length "${length} - 1")
+ foreach(envIdx RANGE ${length})
+ if(skipNext)
+ set(skipNext FALSE)
+ continue()
+ endif()
+
+ set(envVariable "")
+ set(envValue "")
+
+ list(GET arg_ENVIRONMENT ${envIdx} envVariable)
+ math(EXPR envIdx "${envIdx} + 1")
+ if (envIdx LESS_EQUAL ${length})
+ list(GET arg_ENVIRONMENT ${envIdx} envValue)
+ endif()
+
+ if(NOT "${envVariable}" STREQUAL "")
+ set(environment_extras "${environment_extras}\nset(ENV{${envVariable}} \
+\"${envValue}\")")
+ endif()
+ set(skipNext TRUE)
+ endforeach()
+ endif()
+
+ #Escaping environment variables before expand them by file GENERATE
+ string(REPLACE "\\" "\\\\" environment_extras "${environment_extras}")
+
+ if(CMAKE_HOST_WIN32)
+ # It's necessary to call actual test inside 'cmd.exe', because 'execute_process' uses
+ # SW_HIDE to avoid showing a console window, it affects other GUI as well.
+ # See https://gitlab.kitware.com/cmake/cmake/-/issues/17690 for details.
+ set(extra_runner "cmd /c")
+ endif()
+
+ if(arg_PRE_RUN)
+ string(JOIN "\n" pre_run ${arg_PRE_RUN})
+ endif()
+
+ if(arg_POST_RUN)
+ string(JOIN "\n" post_run ${arg_POST_RUN})
+ endif()
+
+ set(command_echo "")
+ if(arg_COMMAND_ECHO)
+ set(command_echo "COMMAND_ECHO ${arg_COMMAND_ECHO}")
+ endif()
+
+ file(GENERATE OUTPUT "${arg_OUTPUT_FILE}" CONTENT
+"#!${CMAKE_COMMAND} -P
+# Qt generated command wrapper
+
+${environment_extras}
+${pre_run}
+execute_process(COMMAND ${extra_runner} ${arg_COMMAND}
+ WORKING_DIRECTORY \"${arg_WORKING_DIRECTORY}\"
+ ${command_echo}
+ RESULT_VARIABLE result
+)
+${post_run}
+if(NOT result EQUAL 0)
+ string(JOIN \" \" full_command ${extra_runner} ${arg_COMMAND})
+ message(FATAL_ERROR \"\${full_command} execution failed with exit code \${result}.\")
+endif()"
+ )
+endfunction()
+
+function(_qt_internal_test_batch_target_name out)
+ set(${out} "test_batch" PARENT_SCOPE)
+endfunction()
diff --git a/cmake/QtPublicToolHelpers.cmake b/cmake/QtPublicToolHelpers.cmake
new file mode 100644
index 0000000000..031f0a3317
--- /dev/null
+++ b/cmake/QtPublicToolHelpers.cmake
@@ -0,0 +1,116 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+# The function returns location of the imported 'tool', returns an empty string if tool is not
+# imported.
+function(__qt_internal_get_tool_imported_location out_var tool)
+ unset(${out_var})
+ if("${tool}" MATCHES "^Qt[0-9]?::.+$")
+ # The tool target has namespace already
+ set(target ${tool})
+ else()
+ set(target ${QT_CMAKE_EXPORT_NAMESPACE}::${tool})
+ endif()
+
+ if(NOT TARGET ${target})
+ message(FATAL_ERROR "${target} is not a target.")
+ endif()
+
+ get_target_property(is_imported ${target} IMPORTED)
+ if(NOT is_imported)
+ set(${out_var} "" PARENT_SCOPE)
+ return()
+ endif()
+
+ get_target_property(configs ${target} IMPORTED_CONFIGURATIONS)
+ list(TRANSFORM configs PREPEND _)
+ # Well-known configuration types
+ list(APPEND configs
+ _RELWITHDEBINFO
+ _RELEASE
+ _MINSIZEREL
+ _DEBUG
+ )
+ list(REMOVE_DUPLICATES configs)
+ # Look for the default empty configuration type at the first place.
+ list(PREPEND configs "")
+
+ foreach(config ${configs})
+ get_target_property(${out_var} ${target} "IMPORTED_LOCATION${config}")
+ if(${out_var})
+ break()
+ endif()
+ endforeach()
+
+ set(${out_var} "${${out_var}}" PARENT_SCOPE)
+endfunction()
+
+function(_qt_internal_generate_tool_command_wrapper)
+ get_property(is_called GLOBAL PROPERTY _qt_internal_generate_tool_command_wrapper_called)
+ if(NOT CMAKE_HOST_WIN32 OR is_called)
+ return()
+ endif()
+
+ set(prefixes "")
+
+ # In a prefix build, the just-built tools should pick up libraries from the current repo build
+ # dir.
+ if(QT_BUILD_DIR)
+ list(APPEND prefixes "${QT_BUILD_DIR}")
+ endif()
+
+ # Pick up libraries from the main location where Qt was installed during a Qt build.
+ if(QT_BUILD_INTERNALS_RELOCATABLE_INSTALL_PREFIX)
+ list(APPEND prefixes "${QT_BUILD_INTERNALS_RELOCATABLE_INSTALL_PREFIX}")
+ endif()
+
+ # Needed for ExternalProjects examples, where the Qt build dir is passed via this variable
+ # to the example project.
+ if(QT_ADDITIONAL_PACKAGES_PREFIX_PATH)
+ __qt_internal_prefix_paths_to_roots(additional_roots
+ "${QT_ADDITIONAL_PACKAGES_PREFIX_PATH}")
+ list(APPEND prefixes ${QT_ADDITIONAL_PACKAGES_PREFIX_PATH})
+ endif()
+
+ # Fallback to wherever Qt6 package is.
+ if(QT6_INSTALL_PREFIX)
+ list(APPEND prefixes "${QT6_INSTALL_PREFIX}")
+ endif()
+
+ # When building qtbase, QT6_INSTALL_BINS is not set yet.
+ if(INSTALL_BINDIR)
+ set(bin_suffix "${INSTALL_BINDIR}")
+ else()
+ set(bin_suffix "${QT6_INSTALL_BINS}")
+ endif()
+
+ set(path_dirs "")
+ foreach(prefix IN LISTS prefixes)
+ set(bin_dir "${prefix}/${bin_suffix}")
+ if(EXISTS "${bin_dir}")
+ file(TO_NATIVE_PATH "${bin_dir}" path_dir)
+ list(APPEND path_dirs "${path_dir}")
+ endif()
+ endforeach()
+
+ set(tool_command_wrapper_dir "${CMAKE_BINARY_DIR}/.qt/bin")
+ file(MAKE_DIRECTORY "${tool_command_wrapper_dir}")
+ set(tool_command_wrapper_path "${tool_command_wrapper_dir}/qt_setup_tool_path.bat")
+
+ file(WRITE "${tool_command_wrapper_path}" "@echo off
+set PATH=${path_dirs};%PATH%
+%*")
+
+ set(QT_TOOL_COMMAND_WRAPPER_PATH "${tool_command_wrapper_path}"
+ CACHE INTERNAL "Path to the wrapper of the tool commands")
+
+ set_property(GLOBAL PROPERTY _qt_internal_generate_tool_command_wrapper_called TRUE)
+endfunction()
+
+# Gets the path to tool wrapper shell script.
+function(_qt_internal_get_tool_wrapper_script_path out_variable)
+ # Ensure the script wrapper exists.
+ _qt_internal_generate_tool_command_wrapper()
+
+ set(${out_variable} "${QT_TOOL_COMMAND_WRAPPER_PATH}" PARENT_SCOPE)
+endfunction()
diff --git a/cmake/QtPublicWalkLibsHelpers.cmake b/cmake/QtPublicWalkLibsHelpers.cmake
new file mode 100644
index 0000000000..f79b70c710
--- /dev/null
+++ b/cmake/QtPublicWalkLibsHelpers.cmake
@@ -0,0 +1,334 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+# Add libraries to variable ${out_libs_var} in a way that duplicates
+# are added at the end. This ensures the library order needed for the
+# linker.
+function(__qt_internal_merge_libs out_libs_var)
+ foreach(dep ${ARGN})
+ list(REMOVE_ITEM ${out_libs_var} ${dep})
+ list(APPEND ${out_libs_var} ${dep})
+ endforeach()
+ set(${out_libs_var} ${${out_libs_var}} PARENT_SCOPE)
+endfunction()
+
+
+# Extracts value from per-target dict key and assigns it to out_var.
+# Assumes dict_name to be an existing INTERFACE target.
+function(__qt_internal_get_dict_key_values out_var target_infix dict_name dict_key)
+ get_target_property(values "${dict_name}" "INTERFACE_${target_infix}_${dict_key}")
+ set(${out_var} "${values}" PARENT_SCOPE)
+endfunction()
+
+
+# Assigns 'values' to per-target dict key, including for aliases of the target.
+# Assumes dict_name to be an existing INTERFACE target.
+function(__qt_internal_memoize_values_in_dict target dict_name dict_key values)
+ # Memoize the computed values for the target as well as its aliases.
+ #
+ # Aka assigns the contents of ${values} to INTERFACE_Core, INTERFACE_Qt::Core,
+ # INTERFACE_Qt6::Core.
+ #
+ # Yes, i know it's crazy that target names are legal property names.
+ #
+ # Assigning for library aliases is needed to avoid multiple recomputation of values.
+ # Scenario in the context of __qt_internal_walk_libs:
+ # 'values' are computed for Core target and memoized to INTERFACE_Core.
+ # When processing Gui, it depends on Qt::Core, but there are no values for INTERFACE_Qt::Core.
+ set_target_properties(${dict_name} PROPERTIES INTERFACE_${target}_${dict_key} "${values}")
+
+ get_target_property(versionless_alias "${target}" "_qt_versionless_alias")
+ if(versionless_alias)
+ __qt_internal_get_dict_key_values(
+ versionless_values "${versionless_alias}" "${dict_name}" "${dict_key}")
+ if(versionless_values MATCHES "-NOTFOUND$")
+ set_target_properties(${dict_name}
+ PROPERTIES INTERFACE_${versionless_alias}_${dict_key} "${values}")
+ endif()
+ endif()
+
+ get_target_property(versionfull_alias "${target}" "_qt_versionfull_alias")
+ if(versionfull_alias)
+ __qt_internal_get_dict_key_values(
+ versionfull_values "${versionfull_alias}" "${dict_name}" "${dict_key}")
+ if(versionfull_values MATCHES "-NOTFOUND$")
+ set_target_properties(${dict_name}
+ PROPERTIES INTERFACE_${versionfull_alias}_${dict_key} "${values}")
+ endif()
+ endif()
+endfunction()
+
+
+# Walks a target's public link libraries recursively, and performs some actions (poor man's
+# polypmorphism)
+#
+# Walks INTERFACE_LINK_LIBRARIES for all target types, as well as LINK_LIBRARIES for static
+# library targets.
+#
+# out_var: the name of the variable where the result will be assigned. The result is a list of
+# libraries, mostly in generator expression form.
+# rcc_objects_out_var: the name of the variable where the collected rcc object files will be
+# assigned (for the initial target and its dependencies)
+# dict_name: used for caching the results, and preventing the same target from being processed
+# twice
+# operation: a string to tell the function what additional behaviors to execute.
+# 'collect_libs' (default) operation is to collect linker file paths and flags.
+# Used for prl file generation.
+# 'promote_global' promotes walked imported targets to global scope.
+# 'collect_targets' collects all target names (discards framework or link flags)
+# 'direct_targets' collects only the direct target names (discards framework or link
+# flags)
+#
+#
+function(__qt_internal_walk_libs
+ target out_var rcc_objects_out_var dict_name operation)
+ set(collected ${ARGN})
+ if(target IN_LIST collected)
+ return()
+ endif()
+ list(APPEND collected ${target})
+
+ if(operation MATCHES "^direct")
+ set(direct TRUE)
+ else()
+ set(direct FALSE)
+ endif()
+
+ if(target STREQUAL "${QT_CMAKE_EXPORT_NAMESPACE}::EntryPointPrivate")
+ # We can't (and don't need to) process EntryPointPrivate because it brings in
+ # $<TARGET_PROPERTY:prop> genexes which get replaced with
+ # $<TARGET_PROPERTY:EntryPointPrivate,prop> genexes in the code below and that causes
+ # 'INTERFACE_LIBRARY targets may only have whitelisted properties.' errors with CMake
+ # versions equal to or lower than 3.18. These errors are super unintuitive to debug
+ # because there's no mention that it's happening during a file(GENERATE) call.
+ return()
+ endif()
+
+ if(NOT TARGET ${dict_name})
+ add_library(${dict_name} INTERFACE IMPORTED GLOBAL)
+ endif()
+ __qt_internal_get_dict_key_values(libs "${target}" "${dict_name}" "libs")
+ __qt_internal_get_dict_key_values(rcc_objects "${target}" "${dict_name}" "rcc_objects")
+
+ if(libs MATCHES "-NOTFOUND$")
+ unset(libs)
+ unset(rcc_objects)
+ get_target_property(target_libs ${target} INTERFACE_LINK_LIBRARIES)
+ if(NOT target_libs)
+ unset(target_libs)
+ endif()
+ get_target_property(target_type ${target} TYPE)
+ if(target_type STREQUAL "STATIC_LIBRARY")
+ get_target_property(link_libs ${target} LINK_LIBRARIES)
+ if(link_libs)
+ list(APPEND target_libs ${link_libs})
+ endif()
+ endif()
+
+ # Need to record the rcc object file info not only for dependencies, but also for
+ # the current target too. Otherwise the saved information is incomplete for prl static
+ # build purposes.
+ get_target_property(main_target_rcc_objects ${target} _qt_rcc_objects)
+ if(main_target_rcc_objects)
+ __qt_internal_merge_libs(rcc_objects ${main_target_rcc_objects})
+ endif()
+
+ foreach(lib ${target_libs})
+ # Cannot use $<TARGET_POLICY:...> in add_custom_command.
+ # Check the policy now, and replace the generator expression with the value.
+ while(lib MATCHES "\\$<TARGET_POLICY:([^>]+)>")
+ cmake_policy(GET ${CMAKE_MATCH_1} value)
+ if(value STREQUAL "NEW")
+ set(value "TRUE")
+ else()
+ set(value "FALSE")
+ endif()
+ string(REPLACE "${CMAKE_MATCH_0}" "${value}" lib "${lib}")
+ endwhile()
+
+ # Fix up $<TARGET_PROPERTY:FOO> expressions that refer to the "current" target.
+ # Those cannot be used with add_custom_command.
+ while(lib MATCHES "\\$<TARGET_PROPERTY:([^,>]+)>")
+ string(REPLACE "${CMAKE_MATCH_0}" "$<TARGET_PROPERTY:${target},${CMAKE_MATCH_1}>"
+ lib "${lib}")
+ endwhile()
+
+ # Skip static plugins.
+ set(_is_plugin_marker_genex "\\$<BOOL:QT_IS_PLUGIN_GENEX>")
+ if(lib MATCHES "${_is_plugin_marker_genex}")
+ continue()
+ endif()
+
+ # Skip optional dependencies for now. They are likely to be handled manually for prl
+ # file purposes (like nolink handling). And for one of the other operations, we don't
+ # have a use case yet. This might be revisited.
+ if(lib MATCHES "^\\$<TARGET_NAME_IF_EXISTS:")
+ continue()
+ endif()
+
+ # Strip any directory scope tokens.
+ __qt_internal_strip_target_directory_scope_token("${lib}" lib)
+
+ if(lib MATCHES "^\\$<TARGET_OBJECTS:")
+ # Skip object files.
+ continue()
+ elseif(lib MATCHES "^\\$<LINK_ONLY:(.*)>$")
+ set(lib_target ${CMAKE_MATCH_1})
+ else()
+ set(lib_target ${lib})
+ endif()
+
+ # Skip CMAKE_DIRECTORY_ID_SEP. If a target_link_libraries is applied to a target
+ # that was defined in a different scope, CMake appends and prepends a special directory
+ # id separator. Filter those out.
+ if(lib_target MATCHES "^::@")
+ continue()
+ elseif(TARGET ${lib_target})
+ if ("${lib_target}" MATCHES "^Qt::(.*)")
+ # If both, Qt::Foo and Foo targets exist, prefer the target name without
+ # namespace. Which one is preferred doesn't really matter. This code exists to
+ # avoid ending up with both, Qt::Foo and Foo in our dependencies.
+ set(namespaceless_lib_target "${CMAKE_MATCH_1}")
+ if(TARGET "${namespaceless_lib_target}")
+ set(lib_target ${namespaceless_lib_target})
+ endif()
+ endif()
+ get_target_property(lib_target_type ${lib_target} TYPE)
+ if(lib_target_type STREQUAL "INTERFACE_LIBRARY")
+ if(NOT ${direct})
+ __qt_internal_walk_libs(
+ ${lib_target}
+ lib_libs_${target}
+ lib_rcc_objects_${target}
+ "${dict_name}" "${operation}" ${collected})
+ if(lib_libs_${target})
+ __qt_internal_merge_libs(libs ${lib_libs_${target}})
+ set(is_module 0)
+ endif()
+ if(lib_rcc_objects_${target})
+ __qt_internal_merge_libs(rcc_objects ${lib_rcc_objects_${target}})
+ endif()
+ else()
+ __qt_internal_merge_libs(libs ${lib})
+ endif()
+ elseif(NOT lib_target_type STREQUAL "OBJECT_LIBRARY")
+
+ if(operation MATCHES "^(collect|direct)_targets$")
+ __qt_internal_merge_libs(libs ${lib_target})
+ else()
+ __qt_internal_merge_libs(libs "$<TARGET_LINKER_FILE:${lib_target}>")
+ endif()
+
+ get_target_property(target_rcc_objects "${lib_target}" _qt_rcc_objects)
+ if(target_rcc_objects)
+ __qt_internal_merge_libs(rcc_objects ${target_rcc_objects})
+ endif()
+
+ if(NOT ${direct})
+ __qt_internal_walk_libs(
+ ${lib_target}
+ lib_libs_${target}
+ lib_rcc_objects_${target}
+ "${dict_name}" "${operation}" ${collected})
+ endif()
+ if(lib_libs_${target})
+ __qt_internal_merge_libs(libs ${lib_libs_${target}})
+ endif()
+ if(lib_rcc_objects_${target})
+ __qt_internal_merge_libs(rcc_objects ${lib_rcc_objects_${target}})
+ endif()
+ endif()
+ if(operation STREQUAL "promote_global")
+ set(lib_target_unaliased "${lib_target}")
+ get_target_property(aliased_target ${lib_target} ALIASED_TARGET)
+ if(aliased_target)
+ set(lib_target_unaliased ${aliased_target})
+ endif()
+
+ get_property(is_imported TARGET ${lib_target_unaliased} PROPERTY IMPORTED)
+
+ # Allow opting out of promotion. This is useful in certain corner cases
+ # like with WrapLibClang and Threads in qttools.
+ qt_internal_should_not_promote_package_target_to_global(
+ "${lib_target_unaliased}" should_not_promote)
+ if(is_imported AND NOT should_not_promote)
+ __qt_internal_promote_target_to_global(${lib_target_unaliased})
+ endif()
+ endif()
+ elseif("${lib_target}" MATCHES "^Qt::(.*)")
+ message(FATAL_ERROR "The ${CMAKE_MATCH_1} target is mentioned as a dependency for \
+${target}, but not declared.")
+ else()
+ if(NOT operation MATCHES "^(collect|direct)_targets$")
+ set(final_lib_name_to_merge "${lib_target}")
+ if(lib_target MATCHES "/([^/]+).framework$")
+ set(final_lib_name_to_merge "-framework ${CMAKE_MATCH_1}")
+ endif()
+ __qt_internal_merge_libs(libs "${final_lib_name_to_merge}")
+ endif()
+ endif()
+ endforeach()
+ __qt_internal_memoize_values_in_dict("${target}" "${dict_name}" "libs" "${libs}")
+ __qt_internal_memoize_values_in_dict("${target}" "${dict_name}"
+ "rcc_objects" "${rcc_objects}")
+
+ endif()
+ set(${out_var} ${libs} PARENT_SCOPE)
+ set(${rcc_objects_out_var} ${rcc_objects} PARENT_SCOPE)
+endfunction()
+
+function(__qt_internal_print_missing_dependency_target_warning target dep)
+ if(QT_SILENCE_MISSING_DEPENDENCY_TARGET_WARNING)
+ return()
+ endif()
+ message(WARNING
+ "When trying to collect dependencies of target '${target}', "
+ "the non-existent target '${dep}' was encountered. "
+ "This can likely be fixed by moving the find_package call that pulls in "
+ "'${dep}' to the scope of directory '${CMAKE_CURRENT_LIST_DIR}' or higher. "
+ "This warning can be silenced by setting QT_SILENCE_MISSING_DEPENDENCY_TARGET_WARNING to "
+ "ON.")
+endfunction()
+
+# Given ${target}, collect all its private dependencies that are CMake targets.
+#
+# Discards non-CMake-target dependencies like linker flags or file paths.
+# Does nothing when given an interface library.
+#
+# To be used to extract the full list of target dependencies of a library or executable.
+function(__qt_internal_collect_all_target_dependencies target out_var)
+ set(dep_targets "")
+
+ get_target_property(target_type ${target} TYPE)
+
+ if(NOT target_type STREQUAL "INTERFACE_LIBRARY")
+ get_target_property(link_libs ${target} LINK_LIBRARIES)
+ if(link_libs)
+ foreach(lib ${link_libs})
+ if(TARGET "${lib}")
+ list(APPEND dep_targets "${lib}")
+
+ __qt_internal_walk_libs(
+ "${lib}"
+ lib_walked_targets
+ _discarded_out_var
+ "qt_private_link_library_targets"
+ "collect_targets")
+
+ foreach(lib_target IN LISTS lib_walked_targets)
+ if(NOT TARGET "${lib_target}")
+ __qt_internal_print_missing_dependency_target_warning(${target}
+ ${lib_target})
+ continue()
+ endif()
+ list(APPEND dep_targets ${lib_target})
+ endforeach()
+ endif()
+ endforeach()
+ endif()
+ endif()
+
+ list(REMOVE_DUPLICATES dep_targets)
+
+ set(${out_var} "${dep_targets}" PARENT_SCOPE)
+endfunction()
diff --git a/cmake/QtPublicWasmToolchainHelpers.cmake b/cmake/QtPublicWasmToolchainHelpers.cmake
new file mode 100644
index 0000000000..31f6b5aca5
--- /dev/null
+++ b/cmake/QtPublicWasmToolchainHelpers.cmake
@@ -0,0 +1,108 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+# Assuming EMSDK == /path/emsdk
+#
+# Then we expect /path/emsdk/.emscripten file to contain the following line
+# EMSCRIPTEN_ROOT = emsdk_path + '/upstream/emscripten'
+#
+# then we set out_var to '/upstream/emscripten', so it's not a full path
+function(__qt_internal_get_emroot_path_suffix_from_emsdk_env out_var)
+ # Query EMSCRIPTEN_ROOT path.
+ file(READ "$ENV{EMSDK}/.emscripten" ver)
+ string(REGEX MATCH "EMSCRIPTEN_ROOT.*$" EMROOT "${ver}")
+ string(REGEX MATCH "'([^' ]*)'" EMROOT2 "${EMROOT}")
+ string(REPLACE "'" "" EMROOT_PATH "${EMROOT2}")
+
+ set(${out_var} "${EMROOT_PATH}" PARENT_SCOPE)
+endfunction()
+
+function(__qt_internal_get_emscripten_cmake_toolchain_file_path_from_emsdk_env emroot_path out_var)
+ set(wasm_toolchain_file "$ENV{EMSDK}/${emroot_path}/cmake/Modules/Platform/Emscripten.cmake")
+ set(${out_var} "${wasm_toolchain_file}" PARENT_SCOPE)
+endfunction()
+
+function(__qt_internal_query_emsdk_version emroot_path is_fatal out_var)
+ # get emscripten version
+ if(CMAKE_HOST_SYSTEM_NAME STREQUAL "Windows")
+ set(EXECUTE_COMMANDPATH "$ENV{EMSDK}/${emroot_path}/emcc.bat")
+ else()
+ set(EXECUTE_COMMANDPATH "$ENV{EMSDK}/${emroot_path}/emcc")
+ endif()
+
+ file(TO_CMAKE_PATH "${EXECUTE_COMMANDPATH}" EXECUTE_COMMAND)
+ execute_process(COMMAND ${EXECUTE_COMMAND} --version
+ OUTPUT_VARIABLE emOutput
+ OUTPUT_STRIP_TRAILING_WHITESPACE
+ ERROR_VARIABLE emrun_error
+ RESULT_VARIABLE result)
+ message(DEBUG "emcc --version output: ${emOutput}")
+
+ if(NOT emOutput)
+ if(is_fatal)
+ message(FATAL_ERROR
+ "Couldn't determine Emscripten version from running ${EXECUTE_COMMAND} --version. "
+ "Error: ${emrun_error}")
+ endif()
+ set(${out_var} "" PARENT_SCOPE)
+ else()
+ string(REGEX MATCH "[0-9]+\\.[0-9]+\\.[0-9]+" CMAKE_EMSDK_REGEX_VERSION "${emOutput}")
+ set(${out_var} "${CMAKE_EMSDK_REGEX_VERSION}" PARENT_SCOPE)
+ endif()
+endfunction()
+
+function(__qt_internal_get_emcc_recommended_version out_var)
+ # This version of Qt needs this version of emscripten.
+ set(QT_EMCC_RECOMMENDED_VERSION "3.1.50")
+ set(${out_var} "${QT_EMCC_RECOMMENDED_VERSION}" PARENT_SCOPE)
+endfunction()
+
+function(__qt_internal_show_error_no_emscripten_toolchain_file_found_when_building_qt)
+ message(FATAL_ERROR
+ "Cannot find the toolchain file Emscripten.cmake. "
+ "Please specify the toolchain file with -DCMAKE_TOOLCHAIN_FILE=<file> "
+ "or provide a path to a valid emscripten installation via the EMSDK "
+ "environment variable.")
+endfunction()
+
+function(__qt_internal_show_error_no_emscripten_toolchain_file_found_when_using_qt)
+ message(FATAL_ERROR
+ "Cannot find the toolchain file Emscripten.cmake. "
+ "Please specify the toolchain file with -DQT_CHAINLOAD_TOOLCHAIN_FILE=<file> "
+ "or provide a path to a valid emscripten installation via the EMSDK "
+ "environment variable.")
+endfunction()
+
+function(__qt_internal_get_qt_build_emsdk_version out_var)
+ if(QT6_INSTALL_PREFIX)
+ set(WASM_BUILD_DIR "${QT6_INSTALL_PREFIX}")
+ elseif(QT_BUILD_DIR)
+ set(WASM_BUILD_DIR "${QT_BUILD_DIR}")
+ endif()
+ if(EXISTS "${WASM_BUILD_DIR}/src/corelib/global/qconfig.h")
+ file(READ "${WASM_BUILD_DIR}/src/corelib/global/qconfig.h" ver)
+ elseif(EXISTS "${WASM_BUILD_DIR}/include/QtCore/qconfig.h")
+ file(READ "${WASM_BUILD_DIR}/include/QtCore/qconfig.h" ver)
+ else()
+ message("qconfig.h not found, unable to determine Qt build Emscripten version")
+ endif()
+ if (ver)
+ string(REGEX MATCH "#define QT_EMCC_VERSION.\"[0-9]+\\.[0-9]+\\.[0-9]+\"" emOutput ${ver})
+ string(REGEX MATCH "[0-9]+\\.[0-9]+\\.[0-9]+" build_emcc_version "${emOutput}")
+ set(${out_var} "${build_emcc_version}" PARENT_SCOPE)
+ endif()
+endfunction()
+
+function(_qt_test_emscripten_version)
+ __qt_internal_get_emcc_recommended_version(_recommended_emver)
+ __qt_internal_get_emroot_path_suffix_from_emsdk_env(emroot_path)
+ __qt_internal_query_emsdk_version("${emroot_path}" TRUE current_emsdk_ver)
+ __qt_internal_get_qt_build_emsdk_version(qt_build_emcc_version)
+
+ if(NOT "${qt_build_emcc_version}" STREQUAL "${current_emsdk_ver}")
+ message("Qt Wasm built with Emscripten version: ${qt_build_emcc_version}")
+ message("You are using Emscripten version: ${current_emsdk_ver}")
+ message("The recommended version of Emscripten for this Qt is: ${_recommended_emver}")
+ message("This may not work correctly")
+ endif()
+endfunction()
diff --git a/cmake/QtQmakeHelpers.cmake b/cmake/QtQmakeHelpers.cmake
new file mode 100644
index 0000000000..c618fa0510
--- /dev/null
+++ b/cmake/QtQmakeHelpers.cmake
@@ -0,0 +1,251 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+# Create a QMake list (values space-separated) containing paths.
+# Entries that contain whitespace characters are quoted.
+function(qt_to_qmake_path_list out_var)
+ set(quoted_paths "")
+ foreach(path ${ARGN})
+ if(path MATCHES "[ \t]")
+ list(APPEND quoted_paths "\"${path}\"")
+ else()
+ list(APPEND quoted_paths "${path}")
+ endif()
+ endforeach()
+ list(JOIN quoted_paths " " result)
+ set("${out_var}" "${result}" PARENT_SCOPE)
+endfunction()
+
+
+function(qt_generate_qconfig_cpp in_file out_file)
+ set(QT_CONFIG_STRS "")
+
+ string(APPEND QT_CONFIG_STRS " R\"qconfig(${INSTALL_DOCDIR})qconfig\",\n")
+ string(APPEND QT_CONFIG_STRS " R\"qconfig(${INSTALL_INCLUDEDIR})qconfig\",\n")
+ string(APPEND QT_CONFIG_STRS " R\"qconfig(${INSTALL_LIBDIR})qconfig\",\n")
+ string(APPEND QT_CONFIG_STRS " R\"qconfig(${INSTALL_LIBEXECDIR})qconfig\",\n")
+ string(APPEND QT_CONFIG_STRS " R\"qconfig(${INSTALL_BINDIR})qconfig\",\n")
+ string(APPEND QT_CONFIG_STRS " R\"qconfig(${INSTALL_PLUGINSDIR})qconfig\",\n")
+ string(APPEND QT_CONFIG_STRS " R\"qconfig(${INSTALL_QMLDIR})qconfig\",\n")
+ string(APPEND QT_CONFIG_STRS " R\"qconfig(${INSTALL_ARCHDATADIR})qconfig\",\n")
+ string(APPEND QT_CONFIG_STRS " R\"qconfig(${INSTALL_DATADIR})qconfig\",\n")
+ string(APPEND QT_CONFIG_STRS " R\"qconfig(${INSTALL_TRANSLATIONSDIR})qconfig\",\n")
+ string(APPEND QT_CONFIG_STRS " R\"qconfig(${INSTALL_EXAMPLESDIR})qconfig\",\n")
+ string(APPEND QT_CONFIG_STRS " R\"qconfig(${INSTALL_TESTSDIR})qconfig\"")
+
+ # Settings path / sysconf dir.
+ set(QT_SYS_CONF_DIR "${INSTALL_SYSCONFDIR}")
+
+ # Compute and set relocation prefixes.
+ if(WIN32)
+ set(lib_location_absolute_path
+ "${QT_BUILD_INTERNALS_RELOCATABLE_INSTALL_PREFIX}/${INSTALL_BINDIR}")
+ else()
+ set(lib_location_absolute_path
+ "${QT_BUILD_INTERNALS_RELOCATABLE_INSTALL_PREFIX}/${INSTALL_LIBDIR}")
+ endif()
+ file(RELATIVE_PATH from_lib_location_to_prefix
+ "${lib_location_absolute_path}" "${QT_BUILD_INTERNALS_RELOCATABLE_INSTALL_PREFIX}")
+ set(QT_CONFIGURE_LIBLOCATION_TO_PREFIX_PATH "${from_lib_location_to_prefix}")
+
+ # Ensure Windows drive letter is prepended to the install prefix hardcoded
+ # into qconfig.cpp, otherwise qmake can't find Qt modules in a static Qt
+ # build if there's no qt.conf. Mostly relevant for CI.
+ # Given input like
+ # \work/qt/install
+ # or
+ # \work\qt\install
+ # Expected output is something like
+ # C:/work/qt/install
+ # so it includes a drive letter and forward slashes.
+ if(QT_FEATURE_relocatable)
+ # A relocatable Qt does not need a hardcoded prefix path.
+ # This makes reproducible builds a closer reality, because we don't embed a CI path
+ # into the binaries.
+ set(QT_CONFIGURE_PREFIX_PATH_STR "")
+ else()
+ set(QT_CONFIGURE_PREFIX_PATH_STR "${QT_BUILD_INTERNALS_RELOCATABLE_INSTALL_PREFIX}")
+ if(CMAKE_HOST_WIN32)
+ get_filename_component(
+ QT_CONFIGURE_PREFIX_PATH_STR
+ "${QT_CONFIGURE_PREFIX_PATH_STR}" REALPATH)
+ endif()
+ endif()
+
+ configure_file(${in_file} ${out_file} @ONLY)
+endfunction()
+
+# In the cross-compiling case, creates a wrapper around the host Qt's
+# qmake and qtpaths executables. Also creates a qmake configuration file that sets
+# up the host qmake's properties for cross-compiling with this Qt
+# build.
+function(qt_generate_qmake_and_qtpaths_wrapper_for_target)
+ if(NOT CMAKE_CROSSCOMPILING OR QT_NO_GENERATE_QMAKE_WRAPPER_FOR_TARGET)
+ return()
+ endif()
+
+ # Call the configuration file something else but qt.conf to avoid
+ # being picked up by the qmake executable that's created if
+ # QT_FORCE_BUILD_TOOLS is enabled.
+ qt_path_join(qt_conf_path "${INSTALL_BINDIR}" "target_qt.conf")
+
+ set(prefix "${CMAKE_INSTALL_PREFIX}")
+ set(ext_prefix "${QT_STAGING_PREFIX}")
+ set(host_prefix "${QT_HOST_PATH}")
+ file(RELATIVE_PATH host_prefix_relative_to_conf_file "${ext_prefix}/${INSTALL_BINDIR}"
+ "${host_prefix}")
+ file(RELATIVE_PATH ext_prefix_relative_to_conf_file "${ext_prefix}/${INSTALL_BINDIR}"
+ "${ext_prefix}")
+ file(RELATIVE_PATH ext_datadir_relative_to_host_prefix "${host_prefix}"
+ "${ext_prefix}/${INSTALL_MKSPECSDIR}/..")
+
+ set(content "")
+
+ # On Android CMAKE_SYSROOT is set, but from qmake's point of view it should not be set, because
+ # then qmake generates incorrect Qt module include flags (among other things). Do the same for
+ # darwin uikit cross-compilation.
+ set(sysroot "")
+ if(CMAKE_SYSROOT AND NOT ANDROID AND NOT UIKIT)
+ set(sysroot "${CMAKE_SYSROOT}")
+ endif()
+
+ # Detect if automatic sysrootification should happen. All of the following must be true:
+ # sysroot is set (CMAKE_SYSRROT)
+ # prefix is set (CMAKE_INSTALL_PREFIX)
+ # extprefix is explicitly NOT set (CMAKE_STAGING_PREFIX, not QT_STAGING_PREFIX because that
+ # always ends up having a value)
+ if(NOT CMAKE_STAGING_PREFIX AND sysroot)
+ set(sysrootify_prefix true)
+ else()
+ set(sysrootify_prefix false)
+ if(NOT ext_prefix STREQUAL prefix)
+ string(APPEND content "[DevicePaths]
+Prefix=${prefix}
+")
+ endif()
+ endif()
+
+ string(APPEND content
+ "[Paths]
+Prefix=${ext_prefix_relative_to_conf_file}
+Documentation=${INSTALL_DOCDIR}
+Headers=${INSTALL_INCLUDEDIR}
+Libraries=${INSTALL_LIBDIR}
+LibraryExecutables=${INSTALL_LIBEXECDIR}
+Binaries=${INSTALL_BINDIR}
+Plugins=${INSTALL_PLUGINSDIR}
+QmlImports=${INSTALL_QMLDIR}
+ArchData=${INSTALL_ARCHDATADIR}
+Data=${INSTALL_DATADIR}
+Translations=${INSTALL_TRANSLATIONSDIR}
+Examples=${INSTALL_EXAMPLESDIR}
+Tests=${INSTALL_TESTSDIR}
+Settings=${INSTALL_SYSCONFDIR}
+HostPrefix=${host_prefix_relative_to_conf_file}
+HostBinaries=${QT${PROJECT_VERSION_MAJOR}_HOST_INFO_BINDIR}
+HostLibraries=${QT${PROJECT_VERSION_MAJOR}_HOST_INFO_LIBDIR}
+HostLibraryExecutables=${QT${PROJECT_VERSION_MAJOR}_HOST_INFO_LIBEXECDIR}
+HostData=${ext_datadir_relative_to_host_prefix}
+Sysroot=${sysroot}
+SysrootifyPrefix=${sysrootify_prefix}
+TargetSpec=${QT_QMAKE_TARGET_MKSPEC}
+HostSpec=${QT_QMAKE_HOST_MKSPEC}
+")
+ file(GENERATE OUTPUT "${qt_conf_path}" CONTENT "${content}")
+ qt_install(FILES "${CMAKE_CURRENT_BINARY_DIR}/${qt_conf_path}"
+ DESTINATION "${INSTALL_BINDIR}")
+
+ if(QT_GENERATE_WRAPPER_SCRIPTS_FOR_ALL_HOSTS)
+ set(hosts "unix" "non-unix")
+ elseif(CMAKE_HOST_UNIX)
+ set(hosts "unix")
+ else()
+ set(hosts "non-unix")
+ endif()
+
+ set(wrapper_prefix)
+ if(QT_FORCE_BUILD_TOOLS)
+ # Avoid collisions with the cross-compiled qmake/qtpaths binaries.
+ set(wrapper_prefix "host-")
+ endif()
+
+ set(host_qt_bindir "${host_prefix}/${QT${PROJECT_VERSION_MAJOR}_HOST_INFO_BINDIR}")
+ file(TO_NATIVE_PATH "${host_qt_bindir}" host_qt_bindir)
+
+ if(QT_CREATE_VERSIONED_HARD_LINK AND QT_WILL_INSTALL)
+ set(tool_version "${PROJECT_VERSION_MAJOR}")
+ endif()
+
+ foreach(host_type ${hosts})
+ foreach(tool_name qmake qtpaths)
+ set(wrapper_extension)
+ set(newline_style LF)
+
+ if(host_type STREQUAL "non-unix")
+ set(wrapper_extension ".bat")
+ set(newline_style CRLF)
+ endif()
+
+ set(wrapper_in_file
+ "${CMAKE_CURRENT_SOURCE_DIR}/bin/qmake-and-qtpaths-wrapper${wrapper_extension}.in")
+
+ set(wrapper "preliminary/${wrapper_prefix}${tool_name}${wrapper_extension}")
+ configure_file("${wrapper_in_file}" "${wrapper}" @ONLY NEWLINE_STYLE ${newline_style})
+ qt_copy_or_install(PROGRAMS "${CMAKE_CURRENT_BINARY_DIR}/${wrapper}"
+ DESTINATION "${INSTALL_BINDIR}")
+
+ # Configuring a new wrapper file, this type setting the tool_version
+ if(QT_CREATE_VERSIONED_HARD_LINK AND QT_WILL_INSTALL)
+ set(versioned_wrapper "preliminary/${wrapper_prefix}${tool_name}${tool_version}${wrapper_extension}")
+ configure_file("${wrapper_in_file}" "${versioned_wrapper}" @ONLY NEWLINE_STYLE ${newline_style})
+ qt_copy_or_install(PROGRAMS "${CMAKE_CURRENT_BINARY_DIR}/${versioned_wrapper}"
+ DESTINATION "${INSTALL_BINDIR}")
+ endif()
+ endforeach()
+ endforeach()
+endfunction()
+
+# Transforms a CMake Qt module name to a qmake Qt module name.
+# Example: Qt6FooPrivate becomes foo_private
+function(qt_get_qmake_module_name result module)
+ string(REGEX REPLACE "^Qt6" "" module "${module}")
+ string(REGEX REPLACE "Private$" "_private" module "${module}")
+ string(REGEX REPLACE "Qpa$" "_qpa_lib_private" module "${module}")
+ string(REGEX REPLACE "Rhi$" "_rhi_lib_private" module "${module}")
+ string(REGEX REPLACE "Ssg$" "_ssg_lib_private" module "${module}")
+ string(TOLOWER "${module}" module)
+ set(${result} ${module} PARENT_SCOPE)
+endfunction()
+
+function(qt_cmake_build_type_to_qmake_build_config out_var build_type)
+ if(build_type STREQUAL "Debug")
+ set(cfg debug)
+ else()
+ set(cfg release)
+ endif()
+ set(${out_var} ${cfg} PARENT_SCOPE)
+endfunction()
+
+function(qt_guess_qmake_build_config out_var)
+ if(QT_GENERATOR_IS_MULTI_CONFIG)
+ unset(cfg)
+ foreach(config_type ${CMAKE_CONFIGURATION_TYPES})
+ qt_cmake_build_type_to_qmake_build_config(tmp ${config_type})
+ list(APPEND cfg ${tmp})
+ endforeach()
+ if(cfg)
+ list(REMOVE_DUPLICATES cfg)
+ else()
+ set(cfg debug)
+ endif()
+ else()
+ qt_cmake_build_type_to_qmake_build_config(cfg ${CMAKE_BUILD_TYPE})
+ endif()
+ set(${out_var} ${cfg} PARENT_SCOPE)
+endfunction()
+
+macro(qt_add_qmake_lib_dependency lib dep)
+ string(REPLACE "-" "_" dep ${dep})
+ string(TOUPPER "${dep}" ucdep)
+ list(APPEND QT_QMAKE_LIB_DEPS_${lib} ${ucdep})
+endmacro()
diff --git a/cmake/QtResourceHelpers.cmake b/cmake/QtResourceHelpers.cmake
new file mode 100644
index 0000000000..2df1fed50f
--- /dev/null
+++ b/cmake/QtResourceHelpers.cmake
@@ -0,0 +1,133 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+function(qt_internal_add_resource target resourceName)
+ if(NOT TARGET "${target}")
+ message(FATAL_ERROR "${target} is not a target.")
+ endif()
+ qt_internal_is_skipped_test(skipped ${target})
+ if(skipped)
+ return()
+ endif()
+ qt_internal_is_in_test_batch(in_batch ${target})
+ if(in_batch)
+ _qt_internal_test_batch_target_name(target)
+ endif()
+
+ # Don't try to add resources when cross compiling, and the target is actually a host target
+ # (like a tool).
+ qt_is_imported_target("${target}" is_imported)
+ if(is_imported)
+ return()
+ endif()
+
+ cmake_parse_arguments(PARSE_ARGV 2 arg
+ ""
+ "PREFIX;LANG;BASE;OUTPUT_TARGETS"
+ "FILES")
+ _qt_internal_validate_all_args_are_parsed(arg)
+
+ _qt_internal_process_resource(${target} ${resourceName}
+ PREFIX "${arg_PREFIX}"
+ LANG "${arg_LANG}"
+ BASE "${arg_BASE}"
+ FILES ${arg_FILES}
+ OUTPUT_TARGETS out_targets
+ )
+
+ if (out_targets)
+ qt_install(TARGETS ${out_targets}
+ EXPORT "${INSTALL_CMAKE_NAMESPACE}${target}Targets"
+ DESTINATION "${INSTALL_LIBDIR}"
+ )
+ qt_internal_add_targets_to_additional_targets_export_file(
+ TARGETS ${out_targets}
+ EXPORT_NAME_PREFIX "${INSTALL_CMAKE_NAMESPACE}${target}"
+ )
+
+ qt_internal_install_resource_pdb_files("${out_targets}")
+ qt_internal_record_rcc_object_files("${target}" "${out_targets}"
+ INSTALL_DIRECTORY "${INSTALL_LIBDIR}")
+ endif()
+
+ if (arg_OUTPUT_TARGETS)
+ set(${arg_OUTPUT_TARGETS} "${out_targets}" PARENT_SCOPE)
+ endif()
+endfunction()
+
+function(qt_internal_record_rcc_object_files target resource_targets)
+ set(args_optional "")
+ set(args_single INSTALL_DIRECTORY)
+ set(args_multi "")
+
+ cmake_parse_arguments(arg
+ "${args_optional}"
+ "${args_single}"
+ "${args_multi}"
+ ${ARGN}
+ )
+
+ foreach(out_target ${resource_targets})
+ get_target_property(resource_name ${out_target} _qt_resource_name)
+ if(NOT resource_name)
+ continue()
+ endif()
+ if(QT_WILL_INSTALL)
+ # Compute the install location of a resource object file in a prefix build.
+ # It's comprised of thee following path parts:
+ #
+ # part (1) INSTALL_DIRECTORY.
+ # A usual value is '${INSTALL_LIBDIR}/' for libraries
+ # and '${INSTALL_QMLDIR}/foo/bar/' for qml plugin resources.
+ #
+ # part (2) the value computed by CMake's computeInstallObjectDir comprised of an
+ # objects-<CONFIG> dir and the target name of the object library.
+ # Example: objects-$<CONFIG>/Gui_resources_qpdf
+ #
+ # part (3) path to the object file, relative to it's build directory.
+ # Example: .rcc/qrc_qpdf.cpp.o
+ #
+ # The final path is relative to CMAKE_INSTALL_PREFIX aka $qt_install_prefix.
+ #
+ # The relative path will be transformed into an absolute path when generating .prl
+ # files, by prepending $$[QT_INSTALL_PREFIX]/.
+ get_target_property(generated_cpp_file_relative_path
+ ${out_target}
+ _qt_resource_generated_cpp_relative_path)
+
+ set(object_file_name "${generated_cpp_file_relative_path}${CMAKE_CXX_OUTPUT_EXTENSION}")
+ qt_path_join(rcc_object_file_path
+ "objects-$<CONFIG>" ${out_target} "${object_file_name}")
+ if(arg_INSTALL_DIRECTORY)
+ qt_path_join(rcc_object_file_path
+ "${arg_INSTALL_DIRECTORY}" "${rcc_object_file_path}")
+ else()
+ message(FATAL_ERROR "No install location given for object files to be installed"
+ " for the following resource target: '${out_target}'")
+ endif()
+ else()
+ # In a non-prefix build we use the object file paths right away.
+ set(rcc_object_file_path $<TARGET_OBJECTS:$<TARGET_NAME:${out_target}>>)
+ endif()
+ set_property(TARGET ${target} APPEND PROPERTY _qt_rcc_objects "${rcc_object_file_path}")
+
+ qt_internal_link_internal_platform_for_object_library("${out_target}")
+ endforeach()
+endfunction()
+
+function(qt_internal_install_resource_pdb_files objlib_targets)
+ if(NOT MSVC OR NOT QT_WILL_INSTALL)
+ return()
+ endif()
+
+ foreach(target IN LISTS objlib_targets)
+ qt_internal_set_compile_pdb_names(${target})
+
+ get_target_property(generated_cpp_file_relative_path
+ ${target}
+ _qt_resource_generated_cpp_relative_path)
+ get_filename_component(rel_obj_file_dir "${generated_cpp_file_relative_path}" DIRECTORY)
+ qt_internal_install_pdb_files(${target}
+ "${INSTALL_LIBDIR}/objects-$<CONFIG>/${target}/${rel_obj_file_dir}")
+ endforeach()
+endfunction()
diff --git a/cmake/QtRpathHelpers.cmake b/cmake/QtRpathHelpers.cmake
new file mode 100644
index 0000000000..da6c8715a8
--- /dev/null
+++ b/cmake/QtRpathHelpers.cmake
@@ -0,0 +1,289 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+# Returns the platform-specific relative rpath base token, if it's supported.
+# If it's not supported, returns the string NO_KNOWN_RPATH_REL_BASE.
+function(qt_internal_get_relative_rpath_base_token out_var)
+ if(APPLE)
+ set(rpath_rel_base "@loader_path")
+ elseif(LINUX OR SOLARIS OR FREEBSD OR HURD OR OPENBSD)
+ set(rpath_rel_base "$ORIGIN")
+ else()
+ set(rpath_rel_base "NO_KNOWN_RPATH_REL_BASE")
+ endif()
+ set(${out_var} "${rpath_rel_base}" PARENT_SCOPE)
+endfunction()
+
+# Computes a relative rpath between ${rpath} and ${install_location} using tokens
+# like $ORIGIN / @loader_path
+# Not all platforms support such tokens though, in which case the returned rpath will be invalid.
+#
+# install_location: a directory relative to CMAKE_INSTALL_PREFIX, where the binary will be installed
+# rpath: an rpath to embed, can be either an absolute path or a path relative to
+# ${CMAKE_INSTALL_PREFIX}/${INSTALL_LIBDIR}.
+function(qt_compute_relative_rpath_base rpath install_location out_var)
+ set(install_lib_dir_absolute "${CMAKE_INSTALL_PREFIX}/${INSTALL_LIBDIR}")
+ get_filename_component(rpath_absolute "${rpath}"
+ ABSOLUTE BASE_DIR "${install_lib_dir_absolute}")
+
+ set(install_location_absolute "${install_location}")
+ if(NOT IS_ABSOLUTE "${install_location_absolute}")
+ set(install_location_absolute "${CMAKE_INSTALL_PREFIX}/${install_location}")
+ endif()
+ # Compute relative rpath from where the target will be installed, to the place where libraries
+ # will be placed (INSTALL_LIBDIR).
+ file(RELATIVE_PATH rpath_relative "${install_location_absolute}" "${rpath_absolute}")
+
+ if("${rpath_relative}" STREQUAL "")
+ # file(RELATIVE_PATH) returns an empty string if the given absolute paths are equal
+ set(rpath_relative ".")
+ endif()
+
+ # Prepend $ORIGIN / @loader_path style tokens (qmake's QMAKE_REL_RPATH_BASE), to make the
+ # relative rpaths work. qmake does this automatically when generating a project, so it wasn't
+ # needed in the .prf files, but for CMake we need to prepend them ourselves.
+ qt_internal_get_relative_rpath_base_token(rpath_rel_base)
+ if(rpath_rel_base STREQUAL "NO_KNOWN_RPATH_REL_BASE")
+ message(WARNING "No known RPATH_REL_BASE for target platform.")
+ endif()
+
+ if(rpath_relative STREQUAL ".")
+ set(rpath_relative "${rpath_rel_base}")
+ else()
+ set(rpath_relative "${rpath_rel_base}/${rpath_relative}")
+ endif()
+
+ set("${out_var}" "${rpath_relative}" PARENT_SCOPE)
+endfunction()
+
+# Applies necessary rpaths to a target upon target installation.
+# No-op when targeting Windows, Android.
+#
+# Since abf72395411b135054b5820f64f93dfbcda430b8 rpaths are also applied in non-prefix builds,
+# to address -rpath-link issues when cross-compiling, although this might not be needed anymore
+# due to 606124c5cceba0dd4a406a9278588b58bb9f9800.
+# See QTBUG-86533 for the whole saga.
+#
+# If no RELATIVE_RPATH option is given, embeds an absolute path rpath to
+# ${CMAKE_INSTALL_PREFIX}/${INSTALL_LIBDIR} into the target.
+
+# If RELATIVE_RPATH is given, the INSTALL_PATH value is used to compute the relative path from
+# ${CMAKE_INSTALL_PREFIX}/${INSTALL_LIBDIR} to wherever the target will be installed
+# (the value of INSTALL_PATH).
+# INSTALL_PATH is expected to be a relative directory where the binary / library will be installed.
+
+# RELATIVE_RPATH is the equivalent of qmake's relative_qt_rpath.
+# INSTALL_PATH is used to implement the equivalent of qmake's $$qtRelativeRPathBase().
+#
+# QT_DISABLE_RPATH can be set to disable embedding any Qt specific rpaths.
+function(qt_apply_rpaths)
+ # No rpath support for win32 and android.
+ if(WIN32 OR ANDROID)
+ return()
+ endif()
+
+ # Rpaths explicitly disabled (like for uikit), equivalent to qmake's no_qt_rpath.
+ # Or feature was turned OFF.
+ if(QT_DISABLE_RPATH OR NOT QT_FEATURE_rpath)
+ return()
+ endif()
+
+ cmake_parse_arguments(PARSE_ARGV 0 arg
+ "RELATIVE_RPATH"
+ "TARGET;INSTALL_PATH"
+ "")
+ _qt_internal_validate_all_args_are_parsed(arg)
+
+ if(NOT arg_TARGET)
+ message(FATAL_ERROR "No target given to qt_apply_rpaths.")
+ else()
+ set(target "${arg_TARGET}")
+ endif()
+
+ # If a target is not built (which can happen for tools when crosscompiling, we shouldn't try
+ # to apply properties.
+ if(NOT TARGET "${target}")
+ return()
+ endif()
+
+ # Protect against interface libraries.
+ get_target_property(target_type "${target}" TYPE)
+ if (target_type STREQUAL "INTERFACE_LIBRARY")
+ return()
+ endif()
+
+ if(NOT arg_INSTALL_PATH)
+ message(FATAL_ERROR "No INSTALL_PATH given to qt_apply_rpaths.")
+ endif()
+
+ set(rpaths "")
+
+ # Modify the install path to contain the nested structure of a framework.
+ get_target_property(is_framework "${target}" FRAMEWORK)
+ if(is_framework)
+ qt_internal_get_framework_info(fw ${target})
+ if(UIKIT)
+ # Shallow framework
+ string(APPEND arg_INSTALL_PATH "/${fw_dir}")
+ else()
+ # Full framework
+ string(APPEND arg_INSTALL_PATH "/${fw_dir}/Versions/Current")
+ endif()
+ endif()
+
+ # Same but for an app bundle.
+ get_target_property(is_bundle "${target}" MACOSX_BUNDLE)
+ if(is_bundle AND NOT is_framework)
+ if(UIKIT)
+ # Shallow bundle
+ string(APPEND arg_INSTALL_PATH "/${target}.app")
+ else()
+ # Full bundle
+ string(APPEND arg_INSTALL_PATH "/${target}.app/Contents/MacOS")
+ endif()
+ endif()
+
+ qt_internal_get_relative_rpath_base_token(rpath_base_token)
+ if(rpath_base_token STREQUAL "NO_KNOWN_RPATH_REL_BASE")
+ set(relative_rpath_supported FALSE)
+ else()
+ set(relative_rpath_supported TRUE)
+ endif()
+
+ # Somewhat similar to mkspecs/features/qt.prf
+ # Embed either an absolute path to the installed Qt lib dir, or a relative one, based on
+ # where ${target} is installed.
+ # Don't embed relative rpaths if the platform does not support it.
+ if(arg_RELATIVE_RPATH AND relative_rpath_supported)
+ qt_compute_relative_rpath_base(
+ "${_default_install_rpath}" "${arg_INSTALL_PATH}" relative_rpath)
+ list(APPEND rpaths "${relative_rpath}")
+ else()
+ list(APPEND rpaths "${_default_install_rpath}")
+ endif()
+
+ # Somewhat similar to mkspecs/features/qt_build_extra.prf.
+ foreach(rpath ${QT_EXTRA_RPATHS})
+ if(IS_ABSOLUTE "${rpath}")
+ list(APPEND rpaths "${rpath}")
+ else()
+ if(relative_rpath_supported)
+ qt_compute_relative_rpath_base("${rpath}" "${arg_INSTALL_PATH}" relative_rpath)
+ list(APPEND rpaths "${relative_rpath}")
+ else()
+ # Any extra relative rpaths on a platform that does not support relative rpaths,
+ # need to be transformed into absolute ones.
+ set(install_lib_dir_absolute "${CMAKE_INSTALL_PREFIX}/${INSTALL_LIBDIR}")
+ get_filename_component(rpath_absolute "${rpath}"
+ ABSOLUTE BASE_DIR "${install_lib_dir_absolute}")
+ list(APPEND rpaths "${rpath_absolute}")
+ endif()
+ endif()
+ endforeach()
+
+ if(rpaths)
+ list(REMOVE_DUPLICATES rpaths)
+ if(QT_WILL_INSTALL)
+ set(prop_name "INSTALL_RPATH")
+ else()
+ set(prop_name "BUILD_RPATH")
+ endif()
+ set_property(TARGET "${target}" APPEND PROPERTY "${prop_name}" ${rpaths})
+ endif()
+endfunction()
+
+macro(qt_internal_set_default_rpath_settings)
+ # the default RPATH to be used when installing, but only if it's not a system directory
+ list(FIND CMAKE_PLATFORM_IMPLICIT_LINK_DIRECTORIES
+ "${CMAKE_INSTALL_PREFIX}/${INSTALL_LIBDIR}" isSystemDir)
+ if("${isSystemDir}" STREQUAL "-1")
+ set(_default_install_rpath "${CMAKE_INSTALL_PREFIX}/${INSTALL_LIBDIR}")
+ endif("${isSystemDir}" STREQUAL "-1")
+
+ # The default rpath settings for installed targets is empty.
+ # The rpaths will instead be computed for each target separately using qt_apply_rpaths().
+ # Additional rpaths can be passed via QT_EXTRA_RPATHS.
+ # By default this will include $ORIGIN / @loader_path, so the installation is relocatable.
+ # Bottom line: No need to pass anything to CMAKE_INSTALL_RPATH.
+ set(CMAKE_INSTALL_RPATH "" CACHE STRING "RPATH for installed binaries")
+
+ # By default, don't embed auto-determined RPATHs pointing to directories
+ # outside of the build tree, into the installed binaries.
+ # This ended up adding rpaths like ${CMAKE_INSTALL_PREFIX}/lib (or /Users/qt/work/install/lib
+ # into the official libraries created by the CI) into the non-qtbase libraries, plugins, etc.
+ #
+ # It should not be necessary, given that qt_apply_rpaths() already adds the necessary rpaths,
+ # either relocatable ones or absolute ones, depending on what the platform supports.
+ if(NOT QT_NO_DISABLE_CMAKE_INSTALL_RPATH_USE_LINK_PATH)
+ set(CMAKE_INSTALL_RPATH_USE_LINK_PATH FALSE)
+ endif()
+
+ # If Qt is built without rpath support, we should not add "user-project default rpaths" to
+ # qt qml plugins. Do this by setting QT_NO_QML_PLUGIN_RPATH to TRUE, which is
+ # then read by qt6_add_qml_plugin.
+ # We do this as part of the internal API, because we still want to allow user project qml
+ # plugins to have sensible default rpaths, even if Qt qml plugins were built without support
+ # for rpaths.
+ #
+ # Note that feature evaluation is not done yet in qtbase at this point, so we check both
+ # feature variable variants. In practice it doesn't really matter, because the variable is only
+ # read during qtdeclarative configuration time when the feature is already evaluated.
+ #
+ # We also make sure not to set it as a cache var just in case somebody wants to override it
+ # per directory scope.
+ if(NOT DEFINED QT_NO_QML_PLUGIN_RPATH
+ AND (QT_DISABLE_RPATH OR (NOT FEATURE_rpath) OR (NOT QT_FEATURE_rpath)))
+ set(QT_NO_QML_PLUGIN_RPATH "TRUE")
+ endif()
+endmacro()
+
+# Overrides the CMAKE_STAGING_PREFIX in a subdirectory scope, to stop CMake from rewriting build
+# rpaths to point into the original staging prefix, and thus breaking running executables from
+# the build directory.
+# See details at https://bugreports.qt.io/browse/QTBUG-102592
+# and https://gitlab.kitware.com/cmake/cmake/-/issues/23421
+#
+# This macro is only meant to be called in functions like
+# qt_internal_add_module / qt_internal_add_tool to ensure the variable is set in the
+# subdirectory scope of the calling function, and not in the actual function scope (where the
+# variable assignment would have no effect).
+#
+# This is the best workaround we can currently do, but it comes with the disadvantage that calling
+# subdirectory-scoped install targets does not work anymore.
+# e.g. calling ninja src/gui/install will try to install to the fake prefix and fail.
+# A regular ninja install call works fine.
+#
+# Usage of this macro assumes there are no binaries or libraries added in the root CMakeLists.txt
+# of the project because that would mean the macro is called at root level scope, which would
+# break installation.
+#
+# The implementation has to be a macro, so we can propagate the variable into the calling
+# subdirectory scope. The implementation can't use return().
+macro(qt_internal_apply_staging_prefix_build_rpath_workaround)
+ set(__qt_internal_should_apply_staging_prefix_build_rpath_workaround TRUE)
+ # Allow an opt out.
+ if(QT_NO_STAGING_PREFIX_BUILD_RPATH_WORKAROUND)
+ set(__qt_internal_should_apply_staging_prefix_build_rpath_workaround FALSE)
+ endif()
+
+ # No need for workaround if CMAKE_STAGING_PREFIX is not set.
+ if(NOT CMAKE_STAGING_PREFIX)
+ set(__qt_internal_should_apply_staging_prefix_build_rpath_workaround FALSE)
+ endif()
+
+ # No rpath support for win32, android, ios, so nothing to do.
+ if(WIN32 OR ANDROID OR UIKIT)
+ set(__qt_internal_should_apply_staging_prefix_build_rpath_workaround FALSE)
+ endif()
+
+ # Set the staging prefix to a non-existent directory, which is unlikely to have permissions
+ # for installation.
+ # The verbose directory name is chosen to attract the user's attention in case if they end up
+ # calling a subdirectory-scope install file.
+ if(__qt_internal_should_apply_staging_prefix_build_rpath_workaround)
+ set_property(GLOBAL PROPERTY _qt_internal_staging_prefix_build_rpath_workaround TRUE)
+ set(CMAKE_STAGING_PREFIX
+ "/qt_fake_staging_prefix/check_qt_internal_apply_staging_prefix_build_rpath_workaround"
+ PARENT_SCOPE)
+ endif()
+endmacro()
diff --git a/cmake/QtSanitizerHelpers.cmake b/cmake/QtSanitizerHelpers.cmake
new file mode 100644
index 0000000000..2a933b2222
--- /dev/null
+++ b/cmake/QtSanitizerHelpers.cmake
@@ -0,0 +1,60 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+# Computes which sanitizer options should be set based on features evaluated in qtbase.
+# Sets ECM_ENABLE_SANITIZERS with those options in the function calling scope.
+function(qt_internal_set_up_sanitizer_options)
+ set(ECM_ENABLE_SANITIZERS "" CACHE STRING "Enable sanitizers")
+ set_property(CACHE ECM_ENABLE_SANITIZERS PROPERTY STRINGS
+ "address;memory;thread;undefined;fuzzer;fuzzer-no-link")
+
+ # If QT_FEATURE_sanitize_foo was enabled, make sure to set the appropriate
+ # ECM_ENABLE_SANITIZERS value.
+ set(enabled_sanitizer_features "")
+ foreach(sanitizer_type address memory thread undefined)
+ if(QT_FEATURE_sanitize_${sanitizer_type})
+ list(APPEND enabled_sanitizer_features "${sanitizer_type}")
+ endif()
+ endforeach()
+
+ # There's a mismatch between fuzzer-no-link ECM option and fuzzer_no_link Qt feature.
+ if(QT_FEATURE_sanitize_fuzzer_no_link)
+ list(APPEND enabled_sanitizer_features "fuzzer-no-link")
+ endif()
+
+ if(enabled_sanitizer_features)
+ set(ECM_ENABLE_SANITIZERS "${enabled_sanitizer_features}" PARENT_SCOPE)
+ endif()
+endfunction()
+
+# This function clears the previously set sanitizer flags from CMAKE_<C|CXX>_FLAGS
+function(qt_internal_skip_sanitizer)
+ if(CMAKE_CXX_COMPILER_ID MATCHES "GNU" OR
+ CMAKE_CXX_COMPILER_ID MATCHES "Clang" OR
+ CMAKE_CXX_COMPILER_ID MATCHES "MSVC")
+ foreach(sanitizer ${ECM_ENABLE_SANITIZERS})
+ string(TOLOWER "${sanitizer}" sanitizer)
+ enable_sanitizer_flags("${sanitizer}")
+ qt_internal_remove_compiler_flags(${XSAN_COMPILE_FLAGS})
+ endforeach()
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}" PARENT_SCOPE)
+ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS}" PARENT_SCOPE)
+ endif()
+endfunction()
+
+# This function disables the sanitizer library linking to all targets created in a subdirectory
+# where the function is called. Note that the function should be called after all involved targets
+# are created, to make sure they are collected by the function.
+function(qt_internal_skip_linking_sanitizer)
+ _qt_internal_collect_buildsystem_targets(all_targets "${CMAKE_CURRENT_SOURCE_DIR}"
+ INCLUDE
+ STATIC_LIBRARY
+ MODULE_LIBRARY
+ SHARED_LIBRARY
+ OBJECT_LIBRARY
+ EXECUTABLE
+ )
+ foreach(t IN LISTS all_targets)
+ set_property(TARGET ${t} PROPERTY SKIP_SANITIZER TRUE)
+ endforeach()
+endfunction()
diff --git a/cmake/QtScopeFinalizerHelpers.cmake b/cmake/QtScopeFinalizerHelpers.cmake
new file mode 100644
index 0000000000..9e13bec26d
--- /dev/null
+++ b/cmake/QtScopeFinalizerHelpers.cmake
@@ -0,0 +1,104 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+# Add a finalizer function for the current CMake list file.
+# It will be processed just before leaving the current source directory scope.
+#
+# When using CMake 3.18 or lower:
+# You may add up to nine arguments that are passed to the finalizer.
+# A finalizer that is registered with qt_add_list_file_finalizer(foo bar baz)
+# will be called with nine arguments: foo(bar baz IGNORE IGNORE IGNORE...),
+# because CMake's handling of empty list elements is a cruel joke.
+# For CMake < 3.18 the function qt_watch_current_list_dir must know about the finalizer.
+#
+# When using CMake 3.19 or higher, no more IGNORE parameters are passed. Instead we
+# use cmake_language(DEFER CALL) and pass arguments as usual.
+# qt_watch_current_list_dir also doesn't need to know about the finalizer
+function(qt_add_list_file_finalizer func)
+ set(use_cmake_defer_call TRUE)
+ if(CMAKE_VERSION VERSION_LESS "3.19.0")
+ set(use_cmake_defer_call FALSE)
+ endif()
+
+ if(use_cmake_defer_call)
+ cmake_language(EVAL CODE "cmake_language(DEFER CALL \"${func}\" ${ARGN}) ")
+ else()
+ set_property(GLOBAL APPEND
+ PROPERTY QT_LIST_FILE_FINALIZER_FILES "${CMAKE_CURRENT_LIST_FILE}")
+ set_property(GLOBAL APPEND
+ PROPERTY QT_LIST_FILE_FINALIZER_FUNCS ${func})
+ foreach(i RANGE 1 9)
+ set(arg "${ARGV${i}}")
+ if(i GREATER_EQUAL ARGC OR "${arg}" STREQUAL "")
+ set(arg "IGNORE")
+ endif()
+ set_property(GLOBAL APPEND
+ PROPERTY QT_LIST_FILE_FINALIZER_ARGV${i} "${arg}")
+ endforeach()
+ endif()
+endfunction()
+
+# Watcher function for the variable CMAKE_CURRENT_LIST_DIR.
+# This is the driver of the finalizer facility.
+function(qt_watch_current_list_dir variable access value current_list_file stack)
+ if(NOT access STREQUAL "MODIFIED_ACCESS")
+ # We are only interested in modifications of CMAKE_CURRENT_LIST_DIR.
+ return()
+ endif()
+ list(GET stack -1 stack_top)
+ if(stack_top STREQUAL current_list_file)
+ # If the top of the stack equals the current list file then
+ # we're entering a file. We're not interested in this case.
+ return()
+ endif()
+ get_property(files GLOBAL PROPERTY QT_LIST_FILE_FINALIZER_FILES)
+ if(NOT files)
+ return()
+ endif()
+ get_property(funcs GLOBAL PROPERTY QT_LIST_FILE_FINALIZER_FUNCS)
+ foreach(i RANGE 1 9)
+ get_property(args${i} GLOBAL PROPERTY QT_LIST_FILE_FINALIZER_ARGV${i})
+ endforeach()
+ list(LENGTH files n)
+ set(i 0)
+ while(i LESS n)
+ list(GET files ${i} file)
+ if(file STREQUAL stack_top)
+ list(GET funcs ${i} func)
+ foreach(k RANGE 1 9)
+ list(GET args${k} ${i} a${k})
+ endforeach()
+ # We've found a file we're looking for. Call the finalizer.
+ if(${CMAKE_VERSION} VERSION_LESS "3.18.0")
+ # Make finalizer known functions here:
+ if(func STREQUAL "qt_finalize_module")
+ qt_finalize_module(${a1} ${a2} ${a3} ${a4} ${a5} ${a6} ${a7} ${a8} ${a9})
+ elseif(func STREQUAL "qt_finalize_plugin")
+ qt_finalize_plugin(${a1} ${a2} ${a3} ${a4} ${a5} ${a6} ${a7} ${a8} ${a9})
+ elseif(func STREQUAL "qt_internal_finalize_app")
+ qt_internal_finalize_app(${a1} ${a2} ${a3} ${a4} ${a5} ${a6} ${a7} ${a8} ${a9})
+ elseif(func STREQUAL "qt_internal_export_additional_targets_file_finalizer")
+ qt_internal_export_additional_targets_file_finalizer(
+ ${a1} ${a2} ${a3} ${a4} ${a5} ${a6} ${a7} ${a8} ${a9})
+ else()
+ message(FATAL_ERROR "qt_watch_current_list_dir doesn't know about ${func}. Consider adding it.")
+ endif()
+ else()
+ cmake_language(CALL ${func} ${a1} ${a2} ${a3} ${a4} ${a5} ${a6} ${a7} ${a8} ${a9})
+ endif()
+ list(REMOVE_AT files ${i})
+ list(REMOVE_AT funcs ${i})
+ foreach(k RANGE 1 9)
+ list(REMOVE_AT args${k} ${i})
+ endforeach()
+ math(EXPR n "${n} - 1")
+ else()
+ math(EXPR i "${i} + 1")
+ endif()
+ endwhile()
+ set_property(GLOBAL PROPERTY QT_LIST_FILE_FINALIZER_FILES ${files})
+ set_property(GLOBAL PROPERTY QT_LIST_FILE_FINALIZER_FUNCS ${funcs})
+ foreach(i RANGE 1 9)
+ set_property(GLOBAL PROPERTY QT_LIST_FILE_FINALIZER_ARGV${i} "${args${i}}")
+ endforeach()
+endfunction()
diff --git a/cmake/QtSeparateDebugInfo.Info.plist.in b/cmake/QtSeparateDebugInfo.Info.plist.in
index d3e8dfbe7f..27489e29bb 100644
--- a/cmake/QtSeparateDebugInfo.Info.plist.in
+++ b/cmake/QtSeparateDebugInfo.Info.plist.in
@@ -1,3 +1,8 @@
+<!--
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: BSD-3-Clause
+-->
+
<?xml version=\"1.0\" encoding=\"UTF-8\"?>
<!DOCTYPE plist PUBLIC \"-//Apple Computer//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">
<plist version=\"1.0\">
diff --git a/cmake/QtSeparateDebugInfo.cmake b/cmake/QtSeparateDebugInfo.cmake
index d2c976f164..61f62207fa 100644
--- a/cmake/QtSeparateDebugInfo.cmake
+++ b/cmake/QtSeparateDebugInfo.cmake
@@ -1,11 +1,230 @@
-include(CMakeFindBinUtils)
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
if(CMAKE_VERSION VERSION_LESS 3.17.0)
set(CMAKE_CURRENT_FUNCTION_LIST_DIR ${CMAKE_CURRENT_LIST_DIR})
endif()
+# Builds a shared library which will have strip run on it.
+function(qt_internal_try_compile_binary_for_strip binary_out_var)
+ # Need to find the config.tests files depending whether the qtbase sources are available.
+ # This mirrors the logic in qt_set_up_build_internals_paths.
+ # TODO: Clean this up, together with qt_set_up_build_internals_paths to only use the
+ # the qtbase sources when building qtbase. And perhaps also when doing a non-prefix
+ # developer-build.
+
+ set(config_test_dir "config.tests/binary_for_strip")
+ set(qtbase_config_test_dir "${QT_SOURCE_TREE}/${config_test_dir}")
+ set(installed_config_test_dir
+ "${_qt_cmake_dir}/${QT_CMAKE_EXPORT_NAMESPACE}/${config_test_dir}")
+
+ # qtbase sources available, always use them, regardless of prefix or non-prefix builds.
+ if(EXISTS "${qtbase_config_test_dir}")
+ set(src_dir "${qtbase_config_test_dir}")
+
+ # qtbase sources unavailable, use installed files.
+ elseif(EXISTS "${installed_config_test_dir}")
+ set(src_dir "${installed_config_test_dir}")
+ else()
+ message(FATAL_ERROR "Can't find binary_for_strip config test project.")
+ endif()
+
+ # Make sure the built project files are not installed when doing an in-source build (like it
+ # happens in Qt's CI) by choosing a build dir that does not coincide with the installed
+ # source dir. Otherwise the config test binaries will be packaged up, which we don't want.
+ set(binary_dir "${CMAKE_CURRENT_BINARY_DIR}/${config_test_dir}_built")
+
+ set(flags "")
+ qt_get_platform_try_compile_vars(platform_try_compile_vars)
+ list(APPEND flags ${platform_try_compile_vars})
+
+ # CI passes the project dir of the Qt repository as absolute path without drive letter:
+ # \Users\qt\work\qt\qtbase
+ # Ensure that arg_PROJECT_PATH is an absolute path with drive letter:
+ # C:/Users/qt/work/qt/qtbase
+ # This works around CMake upstream issue #22534.
+ if(CMAKE_HOST_WIN32)
+ get_filename_component(src_dir "${src_dir}" REALPATH)
+ endif()
+
+ # Build a real binary that strip can be run on.
+ try_compile(QT_INTERNAL_BUILT_BINARY_FOR_STRIP
+ "${binary_dir}"
+ "${src_dir}"
+ binary_for_strip # project name
+ OUTPUT_VARIABLE build_output
+ CMAKE_FLAGS ${flags}
+ )
+
+ # Retrieve the binary path from the build output.
+ string(REGEX REPLACE ".+###(.+)###.+" "\\1" output_binary_path "${build_output}")
+
+ if(NOT EXISTS "${output_binary_path}")
+ message(FATAL_ERROR "Extracted binary path for strip does not exist: ${output_binary_path}")
+ endif()
+
+ set(${binary_out_var} "${output_binary_path}" PARENT_SCOPE)
+endfunction()
+
+# When using the MinGW 11.2.0 toolchain, cmake --install --strip as used by
+# qt-cmake-private-install.cmake, removes the .gnu_debuglink section in binaries and thus
+# breaks the separate debug info feature.
+#
+# Generate a wrapper shell script that passes an option to keep the debug section.
+# The wrapper is used when targeting Linux or MinGW with a shared Qt build.
+# The check to see if the option is supported by 'strip', is done once for every repo configured,
+# because different machines might have different strip versions installed, without support for
+# the option we need.
+#
+# Once CMake supports custom strip arguments, we can remove the part that creates a shell wrapper.
+# https://gitlab.kitware.com/cmake/cmake/-/issues/23346
+function(qt_internal_generate_binary_strip_wrapper)
+ # Return early if check was done already, if explicitly skipped, or when building a static Qt.
+ if(DEFINED CACHE{QT_INTERNAL_STRIP_SUPPORTS_KEEP_SECTION}
+ OR QT_NO_STRIP_WRAPPER
+ OR (NOT QT_BUILD_SHARED_LIBS)
+ )
+ return()
+ endif()
+
+ # Backup the original strip path on very first configuration call.
+ # The value might have been determined by CMake via CMakeDetermineCXXCompiler ->
+ # CMakeFindBinUtils -> find_program(), or it might have been set by a toolchain file.
+ if(NOT QT_INTERNAL_ORIGINAL_CMAKE_STRIP AND CMAKE_STRIP)
+ set(QT_INTERNAL_ORIGINAL_CMAKE_STRIP "${CMAKE_STRIP}" CACHE INTERNAL
+ "Original strip binary")
+ endif()
+
+ message(STATUS "CMAKE_STRIP (original): ${QT_INTERNAL_ORIGINAL_CMAKE_STRIP}")
+
+ # Target Linux and MinGW.
+ if((UNIX OR MINGW)
+ AND NOT APPLE
+ AND NOT ANDROID
+ AND CMAKE_STRIP)
+
+ # To make reconfiguration more robust when QT_INTERNAL_STRIP_SUPPORTS_KEEP_SECTION is
+ # manually removed, make sure to always restore the original strip first, by
+ # re-assigning the original value.
+ set(CMAKE_STRIP "${QT_INTERNAL_ORIGINAL_CMAKE_STRIP}" CACHE STRING "")
+
+ # Getting path to a binary we can run strip on.
+ qt_internal_try_compile_binary_for_strip(valid_binary_path)
+
+ # The strip arguments are used both for the execute_process test and also as content
+ # in the file created by configure_file.
+ set(strip_arguments "--keep-section=.gnu_debuglink")
+
+ # Check if the option is supported.
+ message(STATUS "Performing Test strip --keep-section")
+ execute_process(
+ COMMAND
+ "${CMAKE_STRIP}" ${strip_arguments} "${valid_binary_path}"
+ OUTPUT_VARIABLE strip_probe_output
+ ERROR_VARIABLE strip_probe_output
+ RESULT_VARIABLE strip_result_var
+ )
+
+ # A successful strip of a binary should have a '0' exit code.
+ if(NOT strip_result_var STREQUAL "0")
+ set(keep_section_supported FALSE)
+ else()
+ set(keep_section_supported TRUE)
+ endif()
+
+ # Cache the result.
+ set(QT_INTERNAL_STRIP_SUPPORTS_KEEP_SECTION "${keep_section_supported}" CACHE BOOL
+ "strip supports --keep-section")
+
+ message(DEBUG
+ "qt_internal_generate_binary_strip_wrapper:\n"
+ "original strip: ${QT_INTERNAL_ORIGINAL_CMAKE_STRIP}\n"
+ "strip probe output: ${strip_probe_output}\n"
+ "strip result: ${strip_result_var}\n"
+ "keep section supported: ${keep_section_supported}\n"
+ )
+ message(STATUS "Performing Test strip --keep-section - ${keep_section_supported}")
+
+ # If the option is not supported, don't generate a wrapper and just use the stock binary.
+ if(NOT keep_section_supported)
+ return()
+ endif()
+
+ set(wrapper_extension "")
+
+ if(NOT CMAKE_HOST_UNIX)
+ set(wrapper_extension ".bat")
+ endif()
+
+ set(script_name "qt-internal-strip")
+
+ # the libexec literal is used on purpose for the source, so the file is found
+ # on Windows hosts.
+ set(wrapper_rel_path "libexec/${script_name}${wrapper_extension}.in")
+
+ # Need to find the libexec input file depending whether the qtbase sources are available.
+ # This mirrors the logic in qt_set_up_build_internals_paths.
+ # TODO: Clean this up, together with qt_set_up_build_internals_paths to only use the
+ # the qtbase sources when building qtbase. And perhaps also when doing a non-prefix
+ # developer-build.
+ set(qtbase_wrapper_in_path "${QT_SOURCE_TREE}/${wrapper_rel_path}")
+ set(installed_wrapper_in_path
+ "${_qt_cmake_dir}/${QT_CMAKE_EXPORT_NAMESPACE}/${wrapper_rel_path}")
+
+ # qtbase sources available, always use them, regardless of prefix or non-prefix builds.
+ if(EXISTS "${qtbase_wrapper_in_path}")
+ set(wrapper_in "${qtbase_wrapper_in_path}")
+
+ # qtbase sources unavailable, use installed files.
+ elseif(EXISTS "${installed_wrapper_in_path}")
+ set(wrapper_in "${installed_wrapper_in_path}")
+ else()
+ message(FATAL_ERROR "Can't find ${script_name}${wrapper_extension}.in file.")
+ endif()
+
+ set(wrapper_out "${QT_BUILD_DIR}/${INSTALL_LIBEXECDIR}/${script_name}${wrapper_extension}")
+
+ # Used in the template file.
+ set(original_strip "${QT_INTERNAL_ORIGINAL_CMAKE_STRIP}")
+
+ configure_file("${wrapper_in}" "${wrapper_out}" @ONLY)
+
+ # Override the strip binary to be used by CMake install target.
+ set(CMAKE_STRIP "${wrapper_out}" CACHE INTERNAL "Custom Qt strip wrapper")
+
+ message(STATUS "CMAKE_STRIP (used by Qt): ${CMAKE_STRIP}")
+ endif()
+endfunction()
+
# Enable separate debug information for the given target
function(qt_enable_separate_debug_info target installDestination)
+ set(flags QT_EXECUTABLE)
+ if(APPLE)
+ set(options DSYM_OUTPUT_DIR)
+ else()
+ set(options)
+ endif()
+ set(multiopts ADDITIONAL_INSTALL_ARGS)
+ cmake_parse_arguments(arg "${flags}" "${options}" "${multiopts}" ${ARGN})
+
+ if (NOT QT_FEATURE_separate_debug_info)
+ return()
+ endif()
+ if (NOT UNIX AND NOT MINGW)
+ return()
+ endif()
+ get_target_property(target_type ${target} TYPE)
+ if (NOT target_type STREQUAL "MODULE_LIBRARY" AND
+ NOT target_type STREQUAL "SHARED_LIBRARY" AND
+ NOT target_type STREQUAL "EXECUTABLE")
+ return()
+ endif()
+ get_property(target_source_dir TARGET ${target} PROPERTY SOURCE_DIR)
+ get_property(skip_separate_debug_info DIRECTORY "${target_source_dir}" PROPERTY _qt_skip_separate_debug_info)
+ if (skip_separate_debug_info)
+ return()
+ endif()
+
unset(commands)
if(APPLE)
find_program(DSYMUTIL_PROGRAM dsymutil)
@@ -30,12 +249,21 @@ function(qt_enable_separate_debug_info target installDestination)
if(APPLE)
get_target_property(is_framework ${target} FRAMEWORK)
if(is_framework)
- set(debug_info_bundle_dir "$<TARGET_BUNDLE_DIR:${target}>.${debug_info_suffix}")
- set(BUNDLE_ID Qt${target})
+ qt_internal_get_framework_info(fw ${target})
+ set(BUNDLE_ID ${fw_name})
else()
- set(debug_info_bundle_dir "$<TARGET_FILE:${target}>.${debug_info_suffix}")
set(BUNDLE_ID ${target})
endif()
+
+ if (NOT "x${arg_DSYM_OUTPUT_DIR}" STREQUAL "x")
+ set(debug_info_bundle_dir "${arg_DSYM_OUTPUT_DIR}/${target}")
+ elseif(is_framework)
+ set(debug_info_bundle_dir "$<TARGET_BUNDLE_DIR:${target}>")
+ else()
+ set(debug_info_bundle_dir "$<TARGET_FILE:${target}>")
+ endif()
+ set(debug_info_bundle_dir "${debug_info_bundle_dir}.${debug_info_suffix}")
+
set(debug_info_contents_dir "${debug_info_bundle_dir}/Contents")
set(debug_info_target_dir "${debug_info_contents_dir}/Resources/DWARF")
configure_file(
@@ -47,7 +275,27 @@ function(qt_enable_separate_debug_info target installDestination)
COMMAND ${CMAKE_COMMAND} -E copy "Info.dSYM.plist" "${debug_info_contents_dir}/Info.plist"
)
set(debug_info_target "${debug_info_target_dir}/$<TARGET_FILE_BASE_NAME:${target}>")
- qt_install(DIRECTORY ${debug_info_bundle_dir} DESTINATION ${installDestination})
+
+ if(arg_QT_EXECUTABLE AND QT_FEATURE_debug_and_release)
+ qt_get_cmake_configurations(cmake_configs)
+ foreach(cmake_config ${cmake_configs})
+ # Make installation optional for targets that are not built by default in this config
+ if(NOT (cmake_config STREQUAL QT_MULTI_CONFIG_FIRST_CONFIG))
+ set(install_optional_arg OPTIONAL)
+ else()
+ unset(install_optional_arg)
+ endif()
+ qt_install(DIRECTORY ${debug_info_bundle_dir}
+ ${arg_ADDITIONAL_INSTALL_ARGS}
+ ${install_optional_arg}
+ CONFIGURATIONS ${cmake_config}
+ DESTINATION ${installDestination})
+ endforeach()
+ else()
+ qt_install(DIRECTORY ${debug_info_bundle_dir}
+ ${arg_ADDITIONAL_INSTALL_ARGS}
+ DESTINATION ${installDestination})
+ endif()
else()
set(debug_info_target "$<TARGET_FILE_DIR:${target}>/$<TARGET_FILE_BASE_NAME:${target}>.${debug_info_suffix}")
qt_install(FILES ${debug_info_target} DESTINATION ${installDestination})
@@ -71,5 +319,5 @@ function(qt_enable_separate_debug_info target installDestination)
TARGET ${target}
POST_BUILD
${commands}
- )
+ VERBATIM)
endfunction()
diff --git a/cmake/QtSetup.cmake b/cmake/QtSetup.cmake
index a3584190ab..a420495756 100644
--- a/cmake/QtSetup.cmake
+++ b/cmake/QtSetup.cmake
@@ -1,212 +1,6 @@
-## Set a default build type if none was specified
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
-# Set the QT_IS_BUILDING_QT variable so we can verify whether we are building
-# Qt from source
-set(QT_BUILDING_QT TRUE CACHE
- TYPE STRING "When this is present and set to true, it signals that we are building Qt from source.")
-
-set(_default_build_type "Release")
-if(EXISTS "${CMAKE_SOURCE_DIR}/.git")
- set(_default_build_type "Debug")
-endif()
-
-# Reset content of extra build internal vars for each inclusion of QtSetup.
-unset(QT_EXTRA_BUILD_INTERNALS_VARS)
-
-# Save the global property in a variable to make it available to feature conditions.
-get_property(QT_GENERATOR_IS_MULTI_CONFIG GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
-
-if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
- message(STATUS "Setting build type to '${_default_build_type}' as none was specified.")
- set(CMAKE_BUILD_TYPE "${_default_build_type}" CACHE STRING "Choose the type of build." FORCE)
- set_property(CACHE CMAKE_BUILD_TYPE
- PROPERTY STRINGS
- "Debug" "Release" "MinSizeRel" "RelWithDebInfo") # Set the possible values for cmake-gui.
-elseif(CMAKE_CONFIGURATION_TYPES)
- message(STATUS "Building for multiple configurations: ${CMAKE_CONFIGURATION_TYPES}.")
- message(STATUS "Main configuration is: ${QT_MULTI_CONFIG_FIRST_CONFIG}.")
- if(CMAKE_NINJA_MULTI_DEFAULT_BUILD_TYPE)
- message(STATUS
- "Default build configuration set to '${CMAKE_NINJA_MULTI_DEFAULT_BUILD_TYPE}'.")
- endif()
-endif()
-
-# Appends a 'debug postfix' to library targets (not executables)
-# e.g. lib/libQt6DBus_debug.5.12.0.dylib
-if(WIN32)
- if(MINGW)
- # On MinGW we don't have "d" suffix for debug libraries like on Linux,
- # unless we're building debug and release libraries in one go.
- if(FEATURE_debug_and_release)
- set(CMAKE_DEBUG_POSTFIX "d")
- endif()
- else()
- set(CMAKE_DEBUG_POSTFIX "d")
- endif()
-elseif(APPLE)
- set(CMAKE_DEBUG_POSTFIX "_debug")
- set(CMAKE_FRAMEWORK_MULTI_CONFIG_POSTFIX_DEBUG "_debug")
-endif()
-
-## Position independent code:
-set(CMAKE_POSITION_INDEPENDENT_CODE ON)
-
-# Do not relink dependent libraries when no header has changed:
-set(CMAKE_LINK_DEPENDS_NO_SHARED ON)
-
-# Default to hidden visibility for symbols:
-set(CMAKE_C_VISIBILITY_PRESET hidden)
-set(CMAKE_CXX_VISIBILITY_PRESET hidden)
-set(CMAKE_OBJC_VISIBILITY_PRESET hidden)
-set(CMAKE_OBJCXX_VISIBILITY_PRESET hidden)
-set(CMAKE_VISIBILITY_INLINES_HIDDEN 1)
-
-# Detect non-prefix builds: either when the qtbase install prefix is set to the binary dir
-# or when a developer build is explicitly enabled and no install prefix is specified.
-# This detection only happens when building qtbase, and later is propagated via the generated
-# QtBuildInternalsExtra.cmake file.
-if (PROJECT_NAME STREQUAL "QtBase" AND NOT QT_BUILD_STANDALONE_TESTS)
- if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT AND FEATURE_developer_build)
- # Handle non-prefix builds by setting the CMake install prefix to point to qtbase's build
- # dir.
- # While building another repo (like qtsvg) the CMAKE_PREFIX_PATH
- # should be set on the command line to point to the qtbase build dir.
- set(CMAKE_INSTALL_PREFIX ${QtBase_BINARY_DIR} CACHE PATH
- "Install path prefix, prepended onto install directories." FORCE)
- endif()
- if(CMAKE_CROSSCOMPILING)
- set(__qt_prefix "${CMAKE_STAGING_PREFIX}")
- else()
- set(__qt_prefix "")
- endif()
- if(__qt_prefix STREQUAL "")
- set(__qt_prefix "${CMAKE_INSTALL_PREFIX}")
- endif()
- if(__qt_prefix STREQUAL QtBase_BINARY_DIR)
- set(__qt_will_install_value OFF)
- else()
- set(__qt_will_install_value ON)
- endif()
- set(QT_WILL_INSTALL ${__qt_will_install_value} CACHE BOOL
- "Boolean indicating if doing a Qt prefix build (vs non-prefix build)." FORCE)
- unset(__qt_prefix)
- unset(__qt_will_install_value)
-endif()
-
-# Specify the QT_SOURCE_TREE only when building qtbase. Needed by some tests when the tests are
-# built as part of the project, and not standalone. For standalone tests, the value is set in
-# QtBuildInternalsExtra.cmake.
-if(PROJECT_NAME STREQUAL "QtBase")
- set(QT_SOURCE_TREE "${QtBase_SOURCE_DIR}" CACHE PATH
- "A path to the source tree of the previously configured QtBase project." FORCE)
-endif()
-
-if(FEATURE_developer_build)
- if(DEFINED QT_CMAKE_EXPORT_COMPILE_COMMANDS)
- set(CMAKE_EXPORT_COMPILE_COMMANDS ${QT_CMAKE_EXPORT_COMPILE_COMMANDS})
- else()
- set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
- endif()
- set(QT_BUILD_TESTING ON)
- set(__build_benchmarks ON)
-
- # Tests are not built by default with qmake for iOS and friends, and thus the overall build
- # tends to fail. Disable them by default when targeting uikit.
- if(UIKIT OR ANDROID)
- set(QT_BUILD_TESTING OFF)
- endif()
-
- # Disable benchmarks for single configuration generators which do not build
- # with release configuration.
- if (CMAKE_BUILD_TYPE AND NOT CMAKE_BUILD_TYPE STREQUAL Release)
- set(__build_benchmarks OFF)
- endif()
-else()
- set(QT_BUILD_TESTING OFF)
- set(__build_benchmarks OFF)
-endif()
-
-## Set up testing
-option(BUILD_TESTING "Build the testing tree." ${QT_BUILD_TESTING})
-if(QT_BUILD_STANDALONE_TESTS)
- set(QT_BUILD_TESTING ON)
-
- # BuildInternals might have set it to OFF on initial configuration. So force it to ON when
- # building standalone tests.
- set(BUILD_TESTING ON CACHE BOOL "Build the testing tree." FORCE)
-
- # Also force the tests to be built as part of the default build target.
- set(QT_NO_MAKE_TESTS OFF CACHE BOOL
- "Should examples be built as part of the default 'all' target." FORCE)
-endif()
-option(QT_NO_MAKE_TESTS "Should tests be built as part of the default 'all' target." OFF)
-
-# When cross-building, we don't build tools by default. Sometimes this also covers Qt apps as well.
-# Like in qttools/assistant/assistant.pro, load(qt_app), which is guarded by a qtNomakeTools() call.
-
-set(qt_no_make_tools_default OFF)
-if(CMAKE_CROSSCOMPILING AND NOT QT_BUILD_TOOLS_WHEN_CROSSCOMPILING)
- set(qt_no_make_tools_default ON)
-endif()
-option(QT_NO_MAKE_TOOLS "Should tools be built as part of the default 'all' target."
- "${qt_no_make_tools_default}")
-unset(qt_no_make_tools_default)
-
-include(CTest)
-enable_testing()
-
-option(BUILD_EXAMPLES "Build Qt examples" OFF)
-option(QT_NO_MAKE_EXAMPLES "Should examples be built as part of the default 'all' target." OFF)
-
-# Build Benchmarks
-option(QT_BUILD_BENCHMARKS "Build Qt Benchmarks" ${__build_benchmarks})
-
-## Find host tools (if non native):
-set(QT_HOST_PATH "" CACHE PATH "Installed Qt host directory path, used for cross compiling.")
-
-if (CMAKE_CROSSCOMPILING)
- if(NOT IS_DIRECTORY "${QT_HOST_PATH}")
- message(FATAL_ERROR "You need to set QT_HOST_PATH to cross compile Qt.")
- endif()
- find_package(Qt${PROJECT_VERSION_MAJOR}HostInfo
- CONFIG
- REQUIRED
- PATHS "${QT_HOST_PATH}" "${QT_HOST_PATH}/lib/cmake"
- NO_CMAKE_FIND_ROOT_PATH
- NO_DEFAULT_PATH)
-endif()
-
-## Android platform settings
-if(ANDROID)
- include(QtPlatformAndroid)
-endif()
-
-## qt_add_module and co.:
+# Any new code should go into QtBuildHelpers.cmake or other appropriate files and then called in
+# qt_internal_setup_build_and_global_variables().
include(QtBuild)
-
-## Qt Feature support:
-include(QtBuildInformation)
-include(QtFeature)
-
-## Compiler optimization flags:
-include(QtCompilerOptimization)
-
-## Compiler flags:
-include(QtCompilerFlags)
-
-## Set up non-prefix build:
-qt_set_up_nonprefix_build()
-
-qt_set_language_standards()
-
-## Enable support for sanitizers:
-qt_internal_set_up_sanitizer_features()
-include(${CMAKE_CURRENT_LIST_DIR}/3rdparty/extra-cmake-modules/modules/ECMEnableSanitizers.cmake)
-
-option(QT_USE_CCACHE "Enable the use of ccache")
-if(QT_USE_CCACHE)
- find_program(CCACHE_PROGRAM ccache)
- set(CMAKE_C_COMPILER_LAUNCHER "${CCACHE_PROGRAM}")
- set(CMAKE_CXX_COMPILER_LAUNCHER "${CCACHE_PROGRAM}")
- set(CMAKE_OBJC_COMPILER_LAUNCHER "${CCACHE_PROGRAM}")
-endif()
diff --git a/cmake/QtSimdHelpers.cmake b/cmake/QtSimdHelpers.cmake
new file mode 100644
index 0000000000..1e77bf449f
--- /dev/null
+++ b/cmake/QtSimdHelpers.cmake
@@ -0,0 +1,110 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+# Handle files that need special SIMD-related flags.
+#
+# This function adds the passed source files to the given target only if the SIMD specific condition
+# evaluates to true. It also adds the SIMD architecture specific flags as compile options to those
+# source files.
+#
+# Arguments
+# NAME: is deprecated, don't use it.
+# SIMD: name of the simd architecture, e.g. sse2, avx, neon. A Qt feature named QT_FEATURE_foo
+# should exist, as well as QT_CFLAGS_foo assignment in QtCompilerOptimization.cmake.
+# COMPILE_FLAGS: extra compile flags to set for the passed source files
+# EXCLUDE_OSX_ARCHITECTURES: On apple platforms, specifies which architectures should not get the
+# SIMD compiler flags. This is mostly relevant for fat / universal builds
+#
+function(qt_internal_add_simd_part target)
+ cmake_parse_arguments(PARSE_ARGV 1 arg
+ ""
+ "NAME;SIMD"
+ "${__default_private_args};COMPILE_FLAGS;EXCLUDE_OSX_ARCHITECTURES")
+ _qt_internal_validate_all_args_are_parsed(arg)
+
+ if ("x${arg_SIMD}" STREQUAL x)
+ message(FATAL_ERROR "qt_add_simd_part needs a SIMD type to be set.")
+ endif()
+
+ set(condition "QT_FEATURE_${arg_SIMD}")
+ string(TOUPPER "QT_CFLAGS_${arg_SIMD}" simd_flags_var_name)
+ set(simd_flags_expanded "")
+
+ # As per mkspecs/features/simd.prf, the arch_haswell SIMD compiler is enabled when
+ # qmake's CONFIG contains "avx2", which maps to CMake's QT_FEATURE_avx2.
+ # The list of dependencies 'avx2 bmi bmi2 f16c fma lzcnt popcnt' only influences whether
+ # the 'arch_haswell' SIMD flags need to be added explicitly to the compiler invocation.
+ # If the compiler adds them implicitly, they must be present in qmake's QT_CPU_FEATURES as
+ # detected by the architecture test, and thus they are present in TEST_subarch_result.
+ if("${arg_SIMD}" STREQUAL arch_haswell)
+ set(condition "QT_FEATURE_avx2")
+
+ # Use avx2 flags as per simd.prf, if there are no specific arch_haswell flags specified in
+ # QtCompilerOptimization.cmake.
+ if("${simd_flags_var_name}" STREQUAL "")
+ set(simd_flags_var_name "QT_CFLAGS_AVX2")
+ endif()
+
+ # The avx512 profiles dependencies DO influence if the SIMD compiler will be executed,
+ # so each of the profile dependencies have to be in qmake's CONFIG for the compiler to be
+ # enabled, which means the CMake features have to evaluate to true.
+ # Also the profile flags to be used are a combination of arch_haswell, avx512f and each of the
+ # dependencies.
+ elseif("${arg_SIMD}" STREQUAL avx512common)
+ set(condition "QT_FEATURE_avx512cd")
+ list(APPEND simd_flags_expanded "${QT_CFLAGS_ARCH_HASWELL}")
+ list(APPEND simd_flags_expanded "${QT_CFLAGS_AVX512F}")
+ list(APPEND simd_flags_expanded "${QT_CFLAGS_AVX512CD}")
+ list(REMOVE_DUPLICATES simd_flags_expanded)
+ elseif("${arg_SIMD}" STREQUAL avx512core)
+ set(condition "QT_FEATURE_avx512cd AND QT_FEATURE_avx512bw AND QT_FEATURE_avx512dq AND QT_FEATURE_avx512vl")
+ list(APPEND simd_flags_expanded "${QT_CFLAGS_ARCH_HASWELL}")
+ list(APPEND simd_flags_expanded "${QT_CFLAGS_AVX512F}")
+ list(APPEND simd_flags_expanded "${QT_CFLAGS_AVX512CD}")
+ list(APPEND simd_flags_expanded "${QT_CFLAGS_AVX512BW}")
+ list(APPEND simd_flags_expanded "${QT_CFLAGS_AVX512DQ}")
+ list(APPEND simd_flags_expanded "${QT_CFLAGS_AVX512VL}")
+ list(REMOVE_DUPLICATES simd_flags_expanded)
+ endif()
+
+ qt_evaluate_config_expression(result ${condition})
+ if(${result})
+ if(QT_CMAKE_DEBUG_EXTEND_TARGET)
+ message("qt_add_simd_part(${target} SIMD ${arg_SIMD} ...): Evaluated")
+ endif()
+
+ if(NOT simd_flags_expanded)
+ set(simd_flags_expanded "${${simd_flags_var_name}}")
+ endif()
+
+ # If requested, don't pass the simd specific flags to excluded arches on apple platforms.
+ # Mostly important for universal / fat builds.
+ get_target_property(osx_architectures ${target} OSX_ARCHITECTURES)
+ if(simd_flags_expanded AND osx_architectures AND arg_EXCLUDE_OSX_ARCHITECTURES)
+ list(REMOVE_ITEM osx_architectures ${arg_EXCLUDE_OSX_ARCHITECTURES})
+
+ # Assumes that simd_flags_expanded contains only one item on apple platforms.
+ list(TRANSFORM osx_architectures
+ REPLACE "^(.+)$" "-Xarch_\\1;${simd_flags_expanded}"
+ OUTPUT_VARIABLE simd_flags_expanded)
+ endif()
+
+ # The manual loop is done on purpose. Check Gerrit comments for
+ # 1b7008a3d784f3f266368f824cb43d473a301ba1.
+ foreach(source IN LISTS arg_SOURCES)
+ set_property(SOURCE "${source}" APPEND
+ PROPERTY COMPILE_OPTIONS
+ ${simd_flags_expanded}
+ ${arg_COMPILE_FLAGS}
+ )
+ endforeach()
+ set_source_files_properties(${arg_SOURCES} PROPERTIES
+ SKIP_PRECOMPILE_HEADERS TRUE
+ SKIP_UNITY_BUILD_INCLUSION TRUE)
+ target_sources(${target} PRIVATE ${arg_SOURCES})
+ else()
+ if(QT_CMAKE_DEBUG_EXTEND_TARGET)
+ message("qt_add_simd_part(${target} SIMD ${arg_SIMD} ...): Skipped")
+ endif()
+ endif()
+endfunction()
diff --git a/cmake/QtSingleRepoTargetSetBuildHelpers.cmake b/cmake/QtSingleRepoTargetSetBuildHelpers.cmake
new file mode 100644
index 0000000000..9a003c62c5
--- /dev/null
+++ b/cmake/QtSingleRepoTargetSetBuildHelpers.cmake
@@ -0,0 +1,14 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+# Macro that checks for a single repo target set build, and returns from the current file, directory
+# or function. Use this at the top of project files to whitelist the file for the given package.
+macro(qt_internal_include_in_repo_target_set _repo_target_set_name)
+ if(DEFINED QT_BUILD_SINGLE_REPO_TARGET_SET)
+ if(NOT "${_repo_target_set_name}" STREQUAL QT_BUILD_SINGLE_REPO_TARGET_SET)
+ message(STATUS "Not part of repo target set ${QT_BUILD_SINGLE_REPO_TARGET_SET}: "
+ "${CMAKE_CURRENT_LIST_DIR}")
+ return()
+ endif()
+ endif()
+endmacro()
diff --git a/cmake/QtStandaloneTestsConfig.cmake.in b/cmake/QtStandaloneTestsConfig.cmake.in
index 3d08ae0c12..39200167a5 100644
--- a/cmake/QtStandaloneTestsConfig.cmake.in
+++ b/cmake/QtStandaloneTestsConfig.cmake.in
@@ -1,2 +1,8 @@
-find_package(@INSTALL_CMAKE_NAMESPACE@ @PROJECT_VERSION@
- REQUIRED COMPONENTS @QT_REPO_KNOWN_MODULES_STRING@)
+# Copyright (C) 2024 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+# TODO: Ideally this should look for each Qt module separately, with each module's specific version,
+# bypassing the Qt6 Config file, aka find_package(Qt6SpecificFoo) repated x times. But it's not
+# critical.
+find_package(@INSTALL_CMAKE_NAMESPACE@ @main_qt_package_version@
+ COMPONENTS @QT_REPO_KNOWN_MODULES_STRING@)
diff --git a/cmake/QtSyncQtHelpers.cmake b/cmake/QtSyncQtHelpers.cmake
new file mode 100644
index 0000000000..0188b87c6a
--- /dev/null
+++ b/cmake/QtSyncQtHelpers.cmake
@@ -0,0 +1,324 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+# The function generates the Qt module header structure in build directory and creates install
+# rules. Apart the lists of header files the function takes into account
+# QT_REPO_PUBLIC_NAMESPACE_REGEX cache variable, that can be set by repository in .cmake.conf file.
+# The variable tells the syncqt program, what namespaces are treated as public. Symbols in public
+# namespaces are considered when generating CaMeL case header files.
+function(qt_internal_target_sync_headers target module_headers module_headers_generated)
+ if(NOT TARGET ${QT_CMAKE_EXPORT_NAMESPACE}::syncqt)
+ message(FATAL_ERROR "${QT_CMAKE_EXPORT_NAMESPACE}::syncqt is not a target.")
+ endif()
+ get_target_property(has_headers ${target} _qt_module_has_headers)
+ if(NOT has_headers)
+ return()
+ endif()
+
+ qt_internal_module_info(module "${target}")
+
+ get_target_property(sync_source_directory ${target} _qt_sync_source_directory)
+ set(syncqt_timestamp "${CMAKE_CURRENT_BINARY_DIR}/${target}_syncqt_timestamp")
+ set(syncqt_outputs "${syncqt_timestamp}")
+
+ set(is_interface_lib FALSE)
+ get_target_property(type ${target} TYPE)
+ if(type STREQUAL "INTERFACE_LIBRARY")
+ set(is_interface_lib TRUE)
+ endif()
+
+ set(version_script_private_content_file "")
+ if(NOT is_interface_lib)
+ list(APPEND syncqt_outputs
+ "${module_build_interface_include_dir}/${module}Version"
+ "${module_build_interface_include_dir}/qt${module_lower}version.h")
+ if(TEST_ld_version_script)
+ set(version_script_private_content_file
+ "${CMAKE_CURRENT_BINARY_DIR}/${target}.version.private_content")
+ set(version_script_args
+ "-versionScript" "${version_script_private_content_file}")
+ list(APPEND syncqt_outputs "${version_script_private_content_file}")
+ qt_internal_add_linker_version_script(${target}
+ PRIVATE_CONTENT_FILE "${version_script_private_content_file}")
+ endif()
+ endif()
+
+ # Check for _qt_module_is_3rdparty_header_library flag to detect non-Qt modules and
+ # indicate this to syncqt.
+ get_target_property(is_3rd_party_library ${target} _qt_module_is_3rdparty_header_library)
+ set(non_qt_module_argument "")
+ if(is_3rd_party_library)
+ set(non_qt_module_argument "-nonQt")
+ else()
+ list(APPEND syncqt_outputs "${module_build_interface_include_dir}/${module}")
+ get_target_property(no_headersclean_check ${target} _qt_no_headersclean_check)
+ if(NOT no_headersclean_check)
+ list(APPEND syncqt_outputs
+ "${CMAKE_CURRENT_BINARY_DIR}/${module}_header_check_exceptions")
+ endif()
+ endif()
+
+ set(is_framework FALSE)
+ if(NOT is_interface_lib)
+ get_target_property(is_framework ${target} FRAMEWORK)
+ endif()
+
+ qt_internal_get_qt_all_known_modules(known_modules)
+
+ get_target_property(is_internal_module ${target} _qt_is_internal_module)
+ set(internal_module_argument "")
+ if(is_internal_module)
+ set(internal_module_argument "-internal")
+ endif()
+
+ get_target_property(qpa_filter_regex ${target} _qt_module_qpa_headers_filter_regex)
+ get_target_property(rhi_filter_regex ${target} _qt_module_rhi_headers_filter_regex)
+ get_target_property(ssg_filter_regex ${target} _qt_module_ssg_headers_filter_regex)
+ get_target_property(private_filter_regex ${target} _qt_module_private_headers_filter_regex)
+
+ # We need to use the real paths since otherwise it may lead to the invalid work of the
+ # std::filesystem API
+ get_filename_component(source_dir_real "${sync_source_directory}" REALPATH)
+ get_filename_component(binary_dir_real "${CMAKE_CURRENT_BINARY_DIR}" REALPATH)
+
+ if(QT_REPO_PUBLIC_NAMESPACE_REGEX)
+ set(public_namespaces_filter -publicNamespaceFilter "${QT_REPO_PUBLIC_NAMESPACE_REGEX}")
+ endif()
+
+ if(qpa_filter_regex)
+ set(qpa_filter_argument
+ -qpaHeadersFilter "${qpa_filter_regex}"
+ )
+ endif()
+
+ if(rhi_filter_regex)
+ set(rhi_filter_argument
+ -rhiHeadersFilter "${rhi_filter_regex}"
+ )
+ endif()
+
+ if(ssg_filter_regex)
+ set(ssg_filter_argument
+ -ssgHeadersFilter "${ssg_filter_regex}"
+ )
+ endif()
+
+ set(common_syncqt_arguments
+ -module "${module}"
+ -sourceDir "${source_dir_real}"
+ -binaryDir "${binary_dir_real}"
+ -privateHeadersFilter "${private_filter_regex}"
+ -includeDir "${module_build_interface_include_dir}"
+ -privateIncludeDir "${module_build_interface_private_include_dir}"
+ -qpaIncludeDir "${module_build_interface_qpa_include_dir}"
+ -rhiIncludeDir "${module_build_interface_rhi_include_dir}"
+ -ssgIncludeDir "${module_build_interface_ssg_include_dir}"
+ -generatedHeaders ${module_headers_generated}
+ ${qpa_filter_argument}
+ ${rhi_filter_argument}
+ ${ssg_filter_argument}
+ ${public_namespaces_filter}
+ ${non_qt_module_argument}
+ ${internal_module_argument}
+ )
+
+ if(QT_INTERNAL_ENABLE_SYNCQT_DEBUG_OUTPUT)
+ list(APPEND common_syncqt_arguments -debug)
+ endif()
+
+ set(build_time_syncqt_arguments "")
+ if(WARNINGS_ARE_ERRORS)
+ if(is_interface_lib)
+ set(warnings_are_errors_enabled_genex 1)
+ else()
+ set(warnings_are_errors_enabled_genex
+ "$<NOT:$<BOOL:$<TARGET_PROPERTY:${target},QT_SKIP_WARNINGS_ARE_ERRORS>>>")
+ endif()
+ list(APPEND build_time_syncqt_arguments
+ "$<${warnings_are_errors_enabled_genex}:-warningsAreErrors>")
+ endif()
+
+ if(is_framework)
+ list(REMOVE_ITEM module_headers "${CMAKE_CURRENT_BINARY_DIR}/${target}_fake_header.h")
+ endif()
+
+ # Filter the generated ui_ header files and header files located in the 'doc/' subdirectory.
+ list(FILTER module_headers EXCLUDE REGEX
+ "(.+/(ui_)[^/]+\\.h|${CMAKE_CURRENT_SOURCE_DIR}(/.+)?/doc/+\\.h)")
+
+ set(syncqt_staging_dir "${module_build_interface_include_dir}/.syncqt_staging")
+
+ set(syncqt_args "${common_syncqt_arguments}")
+ list(APPEND syncqt_args
+ -headers ${module_headers}
+ -stagingDir "${syncqt_staging_dir}"
+ -knownModules ${known_modules}
+ ${version_script_args}
+ )
+ list(JOIN syncqt_args "\n" syncqt_args_string)
+ set(syncqt_args_rsp "${binary_dir_real}/${target}_syncqt_args")
+ qt_configure_file(OUTPUT "${syncqt_args_rsp}" CONTENT "${syncqt_args_string}")
+
+ get_target_property(external_headers_dir ${target} _qt_external_headers_dir)
+ if(external_headers_dir)
+ if(NOT IS_ABSOLUTE "${external_headers_dir}")
+ get_filename_component(external_headers_dir "${external_headers_dir}" ABSOLUTE)
+ endif()
+ if(EXISTS "${external_headers_dir}")
+ set(external_headers_dir_copy_cmd
+ COMMAND
+ ${CMAKE_COMMAND}
+ -E copy_directory
+ "${external_headers_dir}"
+ "${module_build_interface_include_dir}"
+ )
+ endif()
+ endif()
+ add_custom_command(
+ OUTPUT
+ ${syncqt_outputs}
+ COMMAND
+ ${QT_CMAKE_EXPORT_NAMESPACE}::syncqt
+ "@${syncqt_args_rsp}"
+ ${build_time_syncqt_arguments}
+ ${external_headers_dir_copy_cmd}
+ COMMAND
+ ${CMAKE_COMMAND} -E touch "${syncqt_timestamp}"
+ DEPENDS
+ ${syncqt_args_rsp}
+ ${module_headers}
+ ${QT_CMAKE_EXPORT_NAMESPACE}::syncqt
+ "$<GENEX_EVAL:$<TARGET_PROPERTY:${target},_qt_internal_sync_headers_deps>>"
+ COMMENT
+ "Running syncqt.cpp for module: ${module}"
+ VERBATIM
+ )
+
+ set(add_sync_headers_to_all "")
+ if(is_interface_lib)
+ set(add_sync_headers_to_all ALL)
+ endif()
+
+ add_custom_target(${target}_sync_headers
+ ${add_sync_headers_to_all}
+ DEPENDS
+ ${syncqt_outputs}
+ )
+ add_dependencies(sync_headers ${target}_sync_headers)
+ set_target_properties(${target}
+ PROPERTIES _qt_internal_sync_headers_target ${target}_sync_headers)
+
+ if(is_3rd_party_library)
+ add_dependencies(thirdparty_sync_headers ${target}_sync_headers)
+ endif()
+ # This target is required when building docs, to make all header files and their aliases
+ # available for qdoc.
+ # ${target}_sync_headers is added as dependency to make sure that
+ # ${target}_sync_all_public_headers is running after ${target}_sync_headers, when building docs.
+ set(syncqt_all_args "${common_syncqt_arguments};-all")
+ list(JOIN syncqt_all_args "\n" syncqt_all_args_string)
+ set(syncqt_all_args_rsp "${binary_dir_real}/${target}_syncqt_all_args")
+ qt_configure_file(OUTPUT "${syncqt_all_args_rsp}" CONTENT "${syncqt_all_args_string}")
+ add_custom_target(${target}_sync_all_public_headers
+ COMMAND
+ ${QT_CMAKE_EXPORT_NAMESPACE}::syncqt
+ "@${syncqt_all_args_rsp}"
+ ${external_headers_dir_copy_cmd}
+ DEPENDS
+ ${module_headers}
+ ${syncqt_all_args_rsp}
+ ${QT_CMAKE_EXPORT_NAMESPACE}::syncqt
+ ${target}_sync_headers
+ VERBATIM
+ )
+
+ if(NOT TARGET sync_all_public_headers)
+ add_custom_target(sync_all_public_headers)
+ endif()
+ add_dependencies(sync_all_public_headers ${target}_sync_all_public_headers)
+
+ if(NOT is_3rd_party_library AND NOT is_framework AND module_headers)
+ # Install all the CaMeL style aliases of header files from the staging directory in one rule
+ qt_install(DIRECTORY "${syncqt_staging_dir}/"
+ DESTINATION "${module_install_interface_include_dir}"
+ )
+ endif()
+
+ if(NOT is_interface_lib)
+ set_property(TARGET ${target}
+ APPEND PROPERTY AUTOGEN_TARGET_DEPENDS "${target}_sync_headers")
+ endif()
+ add_dependencies(${target} "${target}_sync_headers")
+
+
+ get_target_property(private_module_target ${target} _qt_private_module_target_name)
+ if(private_module_target)
+ add_dependencies(${private_module_target} "${target}_sync_headers")
+ endif()
+
+ # Run sync Qt first time at configure step to make all header files available for the code model
+ # of IDEs.
+ get_property(synced_modules GLOBAL PROPERTY _qt_synced_modules)
+ if(NOT "${module}" IN_LIST synced_modules AND QT_SYNC_HEADERS_AT_CONFIGURE_TIME)
+ message(STATUS "Running syncqt.cpp for module: ${module}")
+ get_target_property(syncqt_location ${QT_CMAKE_EXPORT_NAMESPACE}::syncqt LOCATION)
+ execute_process(
+ COMMAND
+ ${syncqt_location}
+ "@${syncqt_args_rsp}"
+ RESULT_VARIABLE syncqt_result
+ OUTPUT_VARIABLE syncqt_output
+ ERROR_VARIABLE syncqt_output
+ )
+ if(NOT syncqt_result EQUAL 0)
+ if(syncqt_output STREQUAL "")
+ string(JOIN "" syncqt_output "The syncqt process exited with code ${syncqt_result}"
+ " and without any useful output. This can happen if syncqt crashes due to the"
+ " incompatibilities with the standard C++ library located by either PATH or"
+ " LD_LIBRARY_PATH environment variables. Please make sure that PATH or"
+ " LD_LIBRARY_PATH don't point to the standard libraries different from the one you"
+ " use for building Qt.")
+ endif()
+ message(FATAL_ERROR
+ "syncqt.cpp failed for module ${module}:\n${syncqt_output}")
+ endif()
+ if(syncqt_output)
+ message(WARNING "${syncqt_output}")
+ endif()
+ set_property(GLOBAL APPEND PROPERTY _qt_synced_modules ${module})
+ endif()
+endfunction()
+
+function(qt_internal_collect_sync_header_dependencies out_var skip_non_existing)
+ list(LENGTH ARGN sync_headers_target_count)
+ if(sync_headers_target_count EQUAL 0)
+ message(FATAL_ERROR "Invalid use of qt_internal_collect_sync_header_dependencies,"
+ " dependencies are not specified")
+ endif()
+
+ set(${out_var} "")
+ foreach(sync_headers_target IN LISTS ARGN)
+ set(sync_headers_target "${sync_headers_target}_sync_headers")
+ if(NOT skip_non_existing OR TARGET ${sync_headers_target})
+ list(APPEND ${out_var} ${sync_headers_target})
+ endif()
+ endforeach()
+ list(REMOVE_DUPLICATES ${out_var})
+
+ set(${out_var} "${${out_var}}" PARENT_SCOPE)
+endfunction()
+
+function(qt_internal_add_sync_header_dependencies target)
+ qt_internal_collect_sync_header_dependencies(sync_headers_targets FALSE ${ARGN})
+ if(sync_headers_targets)
+ add_dependencies(${target} ${sync_headers_targets})
+ endif()
+endfunction()
+
+function(qt_internal_add_autogen_sync_header_dependencies target)
+ qt_internal_collect_sync_header_dependencies(sync_headers_targets TRUE ${ARGN})
+ foreach(sync_headers_target IN LISTS sync_headers_targets)
+ set_property(TARGET ${target} APPEND PROPERTY AUTOGEN_TARGET_DEPENDS
+ "${sync_headers_target}")
+ endforeach()
+endfunction()
diff --git a/cmake/QtTargetHelpers.cmake b/cmake/QtTargetHelpers.cmake
new file mode 100644
index 0000000000..e669047ff1
--- /dev/null
+++ b/cmake/QtTargetHelpers.cmake
@@ -0,0 +1,1671 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+# This function can be used to add sources/libraries/etc. to the specified CMake target
+# if the provided CONDITION evaluates to true.
+# One-value Arguments:
+# PRECOMPILED_HEADER
+# Name of the precompiled header that is used for the target.
+# Multi-value Arguments:
+# CONDITION
+# The condition under which the target will be extended.
+# CONDITION_INDEPENDENT_SOURCES
+# Source files that should be added to the target unconditionally. Note that if target is Qt
+# module, these files will raise a warning at configure time if the condition is not met.
+# COMPILE_FLAGS
+# Custom compilation flags.
+# EXTRA_LINKER_SCRIPT_CONTENT
+# Extra content that should be appended to a target linker script. Applicable for ld only.
+# EXTRA_LINKER_SCRIPT_EXPORTS
+# Extra content that should be added to export section of the linker script.
+# NO_PCH_SOURCES
+# Exclude the specified source files from PRECOMPILE_HEADERS and UNITY_BUILD builds.
+function(qt_internal_extend_target target)
+ if(NOT TARGET "${target}")
+ message(FATAL_ERROR "${target} is not a target.")
+ endif()
+ qt_internal_is_skipped_test(skipped ${target})
+ if(skipped)
+ return()
+ endif()
+ qt_internal_is_in_test_batch(in_batch ${target})
+ if(in_batch)
+ _qt_internal_test_batch_target_name(target)
+ endif()
+
+ # Don't try to extend_target when cross compiling an imported host target (like a tool).
+ qt_is_imported_target("${target}" is_imported)
+ if(is_imported)
+ return()
+ endif()
+
+ set(option_args
+ NO_UNITY_BUILD
+ )
+ set(single_args
+ PRECOMPILED_HEADER
+ EXTRA_LINKER_SCRIPT_CONTENT
+ )
+ set(multi_args
+ ${__default_public_args}
+ ${__default_private_args}
+ ${__default_private_module_args}
+ CONDITION
+ CONDITION_INDEPENDENT_SOURCES
+ COMPILE_FLAGS
+ EXTRA_LINKER_SCRIPT_EXPORTS
+ )
+
+ cmake_parse_arguments(PARSE_ARGV 1 arg
+ "${option_args}"
+ "${single_args}"
+ "${multi_args}"
+ )
+ _qt_internal_validate_all_args_are_parsed(arg)
+
+ if("x${arg_CONDITION}" STREQUAL "x")
+ set(arg_CONDITION ON)
+ endif()
+
+ qt_evaluate_config_expression(result ${arg_CONDITION})
+ if(${result})
+ if(QT_CMAKE_DEBUG_EXTEND_TARGET)
+ message("qt_extend_target(${target} CONDITION ${arg_CONDITION} ...): Evaluated")
+ endif()
+ set(dbus_sources "")
+ foreach(adaptor ${arg_DBUS_ADAPTOR_SOURCES})
+ qt_create_qdbusxml2cpp_command("${target}" "${adaptor}"
+ ADAPTOR
+ BASENAME "${arg_DBUS_ADAPTOR_BASENAME}"
+ FLAGS ${arg_DBUS_ADAPTOR_FLAGS}
+ )
+ list(APPEND dbus_sources "${adaptor}")
+ endforeach()
+
+ foreach(interface ${arg_DBUS_INTERFACE_SOURCES})
+ qt_create_qdbusxml2cpp_command("${target}" "${interface}"
+ INTERFACE
+ BASENAME "${arg_DBUS_INTERFACE_BASENAME}"
+ FLAGS ${arg_DBUS_INTERFACE_FLAGS}
+ )
+ list(APPEND dbus_sources "${interface}")
+ endforeach()
+
+ set(all_sources
+ ${arg_SOURCES}
+ ${dbus_sources}
+ )
+
+ get_target_property(target_type ${target} TYPE)
+ set(is_library FALSE)
+ set(is_interface_lib FALSE)
+ if(${target_type} STREQUAL "STATIC_LIBRARY" OR ${target_type} STREQUAL "SHARED_LIBRARY")
+ set(is_library TRUE)
+ elseif(target_type STREQUAL "INTERFACE_LIBRARY")
+ set(is_interface_lib TRUE)
+ endif()
+
+ foreach(lib ${arg_PUBLIC_LIBRARIES} ${arg_LIBRARIES})
+ # Automatically generate PCH for 'target' using public dependencies.
+ # But only if 'target' is a library/module that does not specify its own PCH file.
+ if(NOT arg_PRECOMPILED_HEADER AND ${is_library})
+ qt_update_precompiled_header_with_library("${target}" "${lib}")
+ endif()
+
+ string(REGEX REPLACE "_nolink$" "" base_lib "${lib}")
+ if(NOT base_lib STREQUAL lib)
+ qt_create_nolink_target("${base_lib}" ${target})
+ endif()
+
+ # Collect _sync_headers targets from libraries that the target depends on. This is
+ # heuristic way of building the dependency tree between the _sync_headers targets of
+ # different Qt modules.
+ if(TARGET "${lib}")
+ get_target_property(is_imported ${lib} IMPORTED)
+ if(NOT is_imported)
+ get_target_property(is_private ${lib} _qt_is_private_module)
+ if(is_private)
+ get_target_property(lib ${lib} _qt_public_module_target_name)
+ endif()
+ set(out_genex "$<TARGET_PROPERTY:${lib},_qt_internal_sync_headers_target>")
+ set_property(TARGET ${target}
+ APPEND PROPERTY _qt_internal_sync_headers_deps "${out_genex}")
+ endif()
+ endif()
+ endforeach()
+
+ list(TRANSFORM arg_PUBLIC_LIBRARIES REPLACE "^Qt::" "${QT_CMAKE_EXPORT_NAMESPACE}::")
+ list(TRANSFORM arg_LIBRARIES REPLACE "^Qt::" "${QT_CMAKE_EXPORT_NAMESPACE}::")
+
+ # Set-up the target
+
+ # CMake versions less than 3.19 don't support adding the source files to the PRIVATE scope
+ # of the INTERFACE libraries. These PRIVATE sources are only needed by IDEs to display
+ # them in a project tree, so to avoid build issues and appearing the sources in
+ # INTERFACE_SOURCES property of INTERFACE_LIBRARY. Collect them inside the
+ # _qt_internal_target_sources property, since they can be useful in the source processing
+ # functions. The property itself is not exported and should only be used in the Qt internal
+ # build tree.
+ if(NOT is_interface_lib OR CMAKE_VERSION VERSION_GREATER_EQUAL "3.19")
+ target_sources("${target}" PRIVATE ${all_sources})
+ if(arg_COMPILE_FLAGS)
+ set_source_files_properties(${all_sources} PROPERTIES
+ COMPILE_FLAGS "${arg_COMPILE_FLAGS}")
+ endif()
+ else()
+ set_property(TARGET ${target} APPEND PROPERTY
+ _qt_internal_target_sources ${all_sources})
+ endif()
+
+ set(public_visibility_option "PUBLIC")
+ set(private_visibility_option "PRIVATE")
+ if(is_interface_lib)
+ set(public_visibility_option "INTERFACE")
+ set(private_visibility_option "INTERFACE")
+ endif()
+ target_include_directories("${target}"
+ ${public_visibility_option} ${arg_PUBLIC_INCLUDE_DIRECTORIES}
+ ${private_visibility_option} ${arg_INCLUDE_DIRECTORIES})
+ target_include_directories("${target}" SYSTEM
+ ${private_visibility_option} ${arg_SYSTEM_INCLUDE_DIRECTORIES})
+ target_compile_definitions("${target}"
+ ${public_visibility_option} ${arg_PUBLIC_DEFINES}
+ ${private_visibility_option} ${arg_DEFINES})
+ target_link_libraries("${target}"
+ ${public_visibility_option} ${arg_PUBLIC_LIBRARIES}
+ ${private_visibility_option} ${arg_LIBRARIES})
+ target_compile_options("${target}"
+ ${public_visibility_option} ${arg_PUBLIC_COMPILE_OPTIONS}
+ ${private_visibility_option} ${arg_COMPILE_OPTIONS})
+ target_link_options("${target}"
+ ${public_visibility_option} ${arg_PUBLIC_LINK_OPTIONS}
+ ${private_visibility_option} ${arg_LINK_OPTIONS})
+
+ if(NOT is_interface_lib)
+ set_property(TARGET "${target}" APPEND PROPERTY
+ AUTOMOC_MOC_OPTIONS "${arg_MOC_OPTIONS}"
+ )
+ # Plugin types associated to a module
+ if(NOT "x${arg_PLUGIN_TYPES}" STREQUAL "x")
+ qt_internal_add_plugin_types("${target}" "${arg_PLUGIN_TYPES}")
+ endif()
+ endif()
+
+ # When computing the private library dependencies, we need to check not only the known
+ # modules added by this repo's qt_build_repo(), but also all module dependencies that
+ # were found via find_package().
+ qt_internal_get_qt_all_known_modules(known_modules)
+
+ # When a public module depends on a private module (Gui on CorePrivate)
+ # make its private module depend on the other private module (GuiPrivate will depend on
+ # CorePrivate).
+ set(qt_libs_private "")
+ foreach(it ${known_modules})
+ list(FIND arg_LIBRARIES "Qt::${it}Private" pos)
+ if(pos GREATER -1)
+ list(APPEND qt_libs_private "Qt::${it}Private")
+ endif()
+ endforeach()
+
+ set(target_private "${target}Private")
+ get_target_property(is_internal_module ${target} _qt_is_internal_module)
+ # Internal modules don't have Private targets but we still need to
+ # propagate their private dependencies.
+ if(is_internal_module)
+ set(target_private "${target}")
+ endif()
+ if(TARGET "${target_private}")
+ target_link_libraries("${target_private}"
+ INTERFACE ${arg_PRIVATE_MODULE_INTERFACE})
+ elseif(arg_PRIVATE_MODULE_INTERFACE)
+ set(warning_message "")
+ string(APPEND warning_message
+ "The PRIVATE_MODULE_INTERFACE option was provided the values:"
+ "'${arg_PRIVATE_MODULE_INTERFACE}' "
+ "but there is no ${target}Private target to assign them to."
+ "Ensure the target exists or remove the option.")
+ message(AUTHOR_WARNING "${warning_message}")
+ endif()
+ qt_register_target_dependencies("${target}"
+ "${arg_PUBLIC_LIBRARIES};${arg_PRIVATE_MODULE_INTERFACE}"
+ "${qt_libs_private};${arg_LIBRARIES}")
+
+
+ qt_autogen_tools(${target}
+ ENABLE_AUTOGEN_TOOLS ${arg_ENABLE_AUTOGEN_TOOLS}
+ DISABLE_AUTOGEN_TOOLS ${arg_DISABLE_AUTOGEN_TOOLS})
+
+ qt_update_precompiled_header("${target}" "${arg_PRECOMPILED_HEADER}")
+ ## Also exclude them from unity build
+ qt_update_ignore_pch_source("${target}" "${arg_NO_PCH_SOURCES}")
+ ## Ignore objective-c files for PCH (not supported atm)
+ qt_ignore_pch_obj_c_sources("${target}" "${arg_SOURCES}")
+
+ if(arg_NO_UNITY_BUILD)
+ set_target_properties("${target}" PROPERTIES UNITY_BUILD OFF)
+ qt_update_ignore_unity_build_sources("${target}" "${arg_SOURCES}")
+ endif()
+ if(arg_NO_UNITY_BUILD_SOURCES)
+ qt_update_ignore_unity_build_sources("${target}" "${arg_NO_UNITY_BUILD_SOURCES}")
+ endif()
+ else()
+ if(QT_CMAKE_DEBUG_EXTEND_TARGET)
+ message("qt_extend_target(${target} CONDITION ${arg_CONDITION} ...): Skipped")
+ endif()
+ endif()
+
+ if(arg_CONDITION_INDEPENDENT_SOURCES)
+ set_source_files_properties(${arg_CONDITION_INDEPENDENT_SOURCES} PROPERTIES
+ _qt_extend_target_condition "${arg_CONDITION}"
+ SKIP_AUTOGEN TRUE
+ )
+
+ qt_internal_get_target_sources_property(sources_property)
+ set_property(TARGET ${target} APPEND PROPERTY
+ ${sources_property} "${arg_CONDITION_INDEPENDENT_SOURCES}")
+ endif()
+
+ if(arg_EXTRA_LINKER_SCRIPT_CONTENT)
+ set_target_properties(${target} PROPERTIES
+ _qt_extra_linker_script_content "${arg_EXTRA_LINKER_SCRIPT_CONTENT}")
+ endif()
+ if(arg_EXTRA_LINKER_SCRIPT_EXPORTS)
+ set_target_properties(${target} PROPERTIES
+ _qt_extra_linker_script_exports "${arg_EXTRA_LINKER_SCRIPT_EXPORTS}")
+ endif()
+endfunction()
+
+# Given CMAKE_CONFIG and ALL_CMAKE_CONFIGS, determines if a directory suffix needs to be appended
+# to each destination, and sets the computed install target destination arguments in OUT_VAR.
+# Defaults used for each of the destination types, and can be configured per destination type.
+function(qt_get_install_target_default_args)
+ cmake_parse_arguments(PARSE_ARGV 0 arg
+ ""
+ "OUT_VAR;CMAKE_CONFIG;RUNTIME;LIBRARY;ARCHIVE;INCLUDES;BUNDLE"
+ "ALL_CMAKE_CONFIGS")
+ _qt_internal_validate_all_args_are_parsed(arg)
+
+ if(NOT arg_CMAKE_CONFIG)
+ message(FATAL_ERROR "No value given for CMAKE_CONFIG.")
+ endif()
+ if(NOT arg_ALL_CMAKE_CONFIGS)
+ message(FATAL_ERROR "No value given for ALL_CMAKE_CONFIGS.")
+ endif()
+ list(LENGTH arg_ALL_CMAKE_CONFIGS all_configs_count)
+ list(GET arg_ALL_CMAKE_CONFIGS 0 first_config)
+
+ set(suffix "")
+ if(all_configs_count GREATER 1 AND NOT arg_CMAKE_CONFIG STREQUAL first_config)
+ set(suffix "/${arg_CMAKE_CONFIG}")
+ endif()
+
+ set(runtime "${INSTALL_BINDIR}")
+ if(arg_RUNTIME)
+ set(runtime "${arg_RUNTIME}")
+ endif()
+
+ set(library "${INSTALL_LIBDIR}")
+ if(arg_LIBRARY)
+ set(library "${arg_LIBRARY}")
+ endif()
+
+ set(archive "${INSTALL_LIBDIR}")
+ if(arg_ARCHIVE)
+ set(archive "${arg_ARCHIVE}")
+ endif()
+
+ set(includes "${INSTALL_INCLUDEDIR}")
+ if(arg_INCLUDES)
+ set(includes "${arg_INCLUDES}")
+ endif()
+
+ set(bundle "${INSTALL_BINDIR}")
+ if(arg_BUNDLE)
+ set(bundle "${arg_BUNDLE}")
+ endif()
+
+ set(args
+ RUNTIME DESTINATION "${runtime}${suffix}"
+ LIBRARY DESTINATION "${library}${suffix}"
+ ARCHIVE DESTINATION "${archive}${suffix}" COMPONENT Devel
+ BUNDLE DESTINATION "${bundle}${suffix}"
+ INCLUDES DESTINATION "${includes}${suffix}")
+ set(${arg_OUT_VAR} "${args}" PARENT_SCOPE)
+endfunction()
+
+macro(qt_internal_setup_default_target_function_options)
+ set(__default_private_args
+ SOURCES
+ LIBRARIES
+ INCLUDE_DIRECTORIES
+ SYSTEM_INCLUDE_DIRECTORIES
+ DEFINES
+ DBUS_ADAPTOR_BASENAME
+ DBUS_ADAPTOR_FLAGS
+ DBUS_ADAPTOR_SOURCES
+ DBUS_INTERFACE_BASENAME
+ DBUS_INTERFACE_FLAGS
+ DBUS_INTERFACE_SOURCES
+ FEATURE_DEPENDENCIES
+ COMPILE_OPTIONS
+ LINK_OPTIONS
+ MOC_OPTIONS
+ DISABLE_AUTOGEN_TOOLS
+ ENABLE_AUTOGEN_TOOLS
+ PLUGIN_TYPES
+ NO_PCH_SOURCES
+ NO_UNITY_BUILD_SOURCES
+ )
+ set(__default_public_args
+ PUBLIC_LIBRARIES
+ PUBLIC_INCLUDE_DIRECTORIES
+ PUBLIC_DEFINES
+ PUBLIC_COMPILE_OPTIONS
+ PUBLIC_LINK_OPTIONS
+ )
+ set(__default_private_module_args
+ PRIVATE_MODULE_INTERFACE
+ )
+ set(__default_target_info_args
+ TARGET_VERSION
+ TARGET_PRODUCT
+ TARGET_DESCRIPTION
+ TARGET_COMPANY
+ TARGET_COPYRIGHT
+ )
+
+ # Collection of arguments so they can be shared across qt_internal_add_executable
+ # and qt_internal_add_test_helper.
+ set(__qt_internal_add_executable_optional_args
+ GUI
+ NO_INSTALL
+ EXCEPTIONS
+ DELAY_RC
+ DELAY_TARGET_INFO
+ QT_APP
+ NO_UNITY_BUILD
+ )
+ set(__qt_internal_add_executable_single_args
+ CORE_LIBRARY
+ OUTPUT_DIRECTORY
+ INSTALL_DIRECTORY
+ VERSION
+ ${__default_target_info_args}
+ )
+ set(__qt_internal_add_executable_multi_args
+ ${__default_private_args}
+ ${__default_public_args}
+ )
+endmacro()
+
+# Append a config-specific postfix to library names to ensure distinct names
+# in a multi-config build.
+# e.g. lib/libQt6DBus_relwithdebinfo.6.3.0.dylib
+# Don't apply the postfix to the first encountered release-like config, so we have at least one
+# config without a postifx.
+# If postfixes are set by user warn about potential issues.
+function(qt_internal_setup_cmake_config_postfix)
+ # Collect configuration that require postfix in Qt library names.
+ if(QT_GENERATOR_IS_MULTI_CONFIG)
+ set(postfix_configurations ${CMAKE_CONFIGURATION_TYPES})
+ else()
+ set(postfix_configurations ${CMAKE_BUILD_TYPE})
+
+ # Set the default postfix to empty by default for single-config builds.
+ string(TOLOWER "${CMAKE_BUILD_TYPE}" build_type_lower)
+ set(default_cmake_${build_type_lower}_postfix "")
+ endif()
+
+ # Override the generic debug postfixes above with custom debug postfixes (even in a single
+ # config build) to follow the conventions we had since Qt 5.
+ # e.g. lib/libQt6DBus_debug.6.3.0.dylib
+ if(WIN32)
+ if(MINGW)
+ # On MinGW we don't have "d" suffix for debug libraries like on Linux,
+ # unless we're building debug and release libraries in one go.
+ if(QT_GENERATOR_IS_MULTI_CONFIG)
+ set(default_cmake_debug_postfix "d")
+ endif()
+ else()
+ set(default_cmake_debug_postfix "d")
+ endif()
+ elseif(APPLE)
+ set(default_cmake_debug_postfix "_debug")
+ endif()
+
+ set(custom_postfix_vars "")
+ set(release_configs Release RelWithDebInfo MinSizeRel)
+ set(found_first_release_config FALSE)
+ foreach(config_type IN LISTS postfix_configurations)
+ string(TOLOWER "${config_type}" config_type_lower)
+ string(TOUPPER "${config_type}" config_type_upper)
+ set(postfix_var CMAKE_${config_type_upper}_POSTFIX)
+
+ # Skip assigning postfix for the first release-like config.
+ if(NOT found_first_release_config
+ AND config_type IN_LIST release_configs)
+ set(found_first_release_config TRUE)
+ if(NOT "${${postfix_var}}" STREQUAL "")
+ list(APPEND custom_postfix_vars ${postfix_var})
+ endif()
+ continue()
+ endif()
+
+ # Check if the default postfix is set, use '_<config_type_lower>' otherwise.
+ set(default_postfix_var
+ default_cmake_${config_type_lower}_postfix)
+ if(NOT DEFINED ${default_postfix_var})
+ set(${default_postfix_var}
+ "_${config_type_lower}")
+ endif()
+
+ # If postfix is set by user avoid changing it, but save postfix variable that has
+ # a non-default value for further warning.
+ if("${${postfix_var}}" STREQUAL "")
+ set(${postfix_var} "${${default_postfix_var}}" PARENT_SCOPE)
+ elseif(NOT "${${postfix_var}}" STREQUAL "${${default_postfix_var}}")
+ list(APPEND custom_postfix_vars ${postfix_var})
+ endif()
+
+ # Adjust framework postfixes accordingly
+ if(APPLE)
+ set(CMAKE_FRAMEWORK_MULTI_CONFIG_POSTFIX_${config_type_upper}
+ "${${postfix_var}}" PARENT_SCOPE)
+ endif()
+ endforeach()
+ if(custom_postfix_vars)
+ list(REMOVE_DUPLICATES custom_postfix_vars)
+ list(JOIN custom_postfix_vars ", " postfix_vars_string)
+
+ message(WARNING "You are using custom library postfixes: '${postfix_vars_string}' which are"
+ " considered experimental and are not officially supported by Qt."
+ " Expect unforeseen issues and user projects built with qmake to be broken."
+ )
+ endif()
+endfunction()
+
+function(qt_is_imported_target target out_var)
+ if(NOT TARGET "${target}")
+ set(target "${QT_CMAKE_EXPORT_NAMESPACE}::${target}")
+ endif()
+ if(NOT TARGET "${target}")
+ message(FATAL_ERROR "Invalid target given to qt_is_imported_target: ${target}")
+ endif()
+ get_target_property(is_imported "${target}" IMPORTED)
+ set(${out_var} "${is_imported}" PARENT_SCOPE)
+endfunction()
+
+# Add Qt::target and Qt6::target as aliases for the target
+function(qt_internal_add_target_aliases target)
+ set(versionless_alias "Qt::${target}")
+ set(versionfull_alias "Qt${PROJECT_VERSION_MAJOR}::${target}")
+ set_target_properties("${target}" PROPERTIES _qt_versionless_alias "${versionless_alias}")
+ set_target_properties("${target}" PROPERTIES _qt_versionfull_alias "${versionfull_alias}")
+
+ get_target_property(type "${target}" TYPE)
+ if (type STREQUAL EXECUTABLE)
+ add_executable("${versionless_alias}" ALIAS "${target}")
+ add_executable("${versionfull_alias}" ALIAS "${target}")
+ else()
+ add_library("${versionless_alias}" ALIAS "${target}")
+ add_library("${versionfull_alias}" ALIAS "${target}")
+ endif()
+endfunction()
+
+function(qt_get_cmake_configurations out_var)
+ set(possible_configs "${CMAKE_BUILD_TYPE}")
+ if(CMAKE_CONFIGURATION_TYPES)
+ set(possible_configs "${CMAKE_CONFIGURATION_TYPES}")
+ endif()
+ set(${out_var} "${possible_configs}" PARENT_SCOPE)
+endfunction()
+
+function(qt_clone_property_for_configs target property configs)
+ get_target_property(value "${target}" "${property}")
+ foreach(config ${configs})
+ string(TOUPPER "${config}" upper_config)
+ set_property(TARGET "${target}" PROPERTY "${property}_${upper_config}" "${value}")
+ endforeach()
+endfunction()
+
+function(qt_handle_multi_config_output_dirs target)
+ qt_get_cmake_configurations(possible_configs)
+ qt_clone_property_for_configs(${target} LIBRARY_OUTPUT_DIRECTORY "${possible_configs}")
+ qt_clone_property_for_configs(${target} RUNTIME_OUTPUT_DIRECTORY "${possible_configs}")
+ qt_clone_property_for_configs(${target} ARCHIVE_OUTPUT_DIRECTORY "${possible_configs}")
+endfunction()
+
+# Set target properties that are the same for all modules, plugins, executables
+# and 3rdparty libraries.
+function(qt_set_common_target_properties target)
+ if(QT_FEATURE_reduce_exports)
+ set_target_properties(${target} PROPERTIES
+ C_VISIBILITY_PRESET hidden
+ CXX_VISIBILITY_PRESET hidden
+ OBJC_VISIBILITY_PRESET hidden
+ OBJCXX_VISIBILITY_PRESET hidden
+ VISIBILITY_INLINES_HIDDEN 1)
+ endif()
+ qt_internal_set_compile_pdb_names("${target}")
+endfunction()
+
+# Set common, informational target properties.
+#
+# On Windows, these properties are used to generate the version information resource.
+function(qt_set_target_info_properties target)
+ cmake_parse_arguments(arg "" "${__default_target_info_args}" "" ${ARGN})
+ if(NOT arg_TARGET_VERSION)
+ set(arg_TARGET_VERSION "${PROJECT_VERSION}.0")
+ endif()
+ if(NOT arg_TARGET_PRODUCT)
+ set(arg_TARGET_PRODUCT "Qt6")
+ endif()
+ if(NOT arg_TARGET_DESCRIPTION)
+ set(arg_TARGET_DESCRIPTION "C++ Application Development Framework")
+ endif()
+ if(NOT arg_TARGET_COMPANY)
+ set(arg_TARGET_COMPANY "The Qt Company Ltd.")
+ endif()
+ if(NOT arg_TARGET_COPYRIGHT)
+ set(arg_TARGET_COPYRIGHT "${QT_COPYRIGHT}")
+ endif()
+ set_target_properties(${target} PROPERTIES
+ QT_TARGET_VERSION "${arg_TARGET_VERSION}"
+ QT_TARGET_COMPANY_NAME "${arg_TARGET_COMPANY}"
+ QT_TARGET_DESCRIPTION "${arg_TARGET_DESCRIPTION}"
+ QT_TARGET_COPYRIGHT "${arg_TARGET_COPYRIGHT}"
+ QT_TARGET_PRODUCT_NAME "${arg_TARGET_PRODUCT}")
+endfunction()
+
+# Uses the QT_DELAYED_TARGET_* property values to set the final QT_TARGET_* properties.
+# Needed when doing executable finalization at the end of a subdirectory scope
+# (aka scope finalization).
+function(qt_internal_set_target_info_properties_from_delayed_properties target)
+ set(args "")
+ foreach(prop ${__default_target_info_args})
+ get_target_property(prop_value "${target}" "QT_DELAYED_${prop}")
+ list(APPEND args "${prop}" "${prop_value}")
+ endforeach()
+ qt_set_target_info_properties(${target} ${args})
+endfunction()
+
+# Updates the QT_DELAYED_ properties with values from the QT_ variants, in case if they were
+# set in-between a qt_add_* call and before scope finalization.
+function(qt_internal_update_delayed_target_info_properties target)
+ foreach(prop ${__default_target_info_args})
+ get_target_property(prop_value "${target}" "QT_${prop}")
+ get_target_property(delayed_prop_value ${target} "QT_DELAYED_${prop}")
+ set(final_value "${delayed_prop_value}")
+ if(prop_value)
+ set(final_value "${prop_value}")
+ endif()
+ set_target_properties(${target} PROPERTIES "QT_DELAYED_${prop}" "${final_value}")
+ endforeach()
+endfunction()
+
+function(qt_internal_check_directory_or_type name dir type default result_var)
+ if ("x${dir}" STREQUAL x)
+ if("x${type}" STREQUAL x)
+ message(FATAL_ERROR
+ "qt_internal_add_plugin called without setting either PLUGIN_TYPE or ${name}.")
+ endif()
+ set(${result_var} "${default}" PARENT_SCOPE)
+ else()
+ set(${result_var} "${dir}" PARENT_SCOPE)
+ endif()
+endfunction()
+
+macro(qt_internal_get_export_additional_targets_keywords option_args single_args multi_args)
+ set(${option_args}
+ )
+ set(${single_args}
+ EXPORT_NAME_PREFIX
+ )
+ set(${multi_args}
+ TARGETS
+ TARGET_EXPORT_NAMES
+ )
+endmacro()
+
+# Create a Qt*AdditionalTargetInfo.cmake file that is included by Qt*Config.cmake
+# and sets IMPORTED_*_<CONFIG> properties on the exported targets.
+#
+# The file also makes the targets global if the QT_PROMOTE_TO_GLOBAL_TARGETS property is set in the
+# consuming project.
+# When using a CMake version lower than 3.21, only the specified TARGETS are made global.
+# E.g. transitive non-Qt 3rd party targets of the specified targets are not made global.
+#
+# EXPORT_NAME_PREFIX:
+# The portion of the file name before AdditionalTargetInfo.cmake
+# CONFIG_INSTALL_DIR:
+# Installation location for the target info file
+# TARGETS:
+# The internal target names. Those must be actual targets.
+# TARGET_EXPORT_NAMES:
+# The target names how they appear in the QtXXXTargets.cmake files.
+# The names get prefixed by ${QT_CMAKE_EXPORT_NAMESPACE}:: unless they already are.
+# This argument may be empty, then the target export names are the same as the internal ones.
+#
+# TARGETS and TARGET_EXPORT_NAMES must contain exactly the same number of elements.
+# Example: TARGETS = qmljs_native
+# TARGET_EXPORT_NAMES = Qt6::qmljs
+#
+function(qt_internal_export_additional_targets_file)
+ qt_internal_get_export_additional_targets_keywords(option_args single_args multi_args)
+ cmake_parse_arguments(arg
+ "${option_args}"
+ "${single_args};CONFIG_INSTALL_DIR"
+ "${multi_args}"
+ ${ARGN})
+
+ qt_internal_append_export_additional_targets()
+
+ set_property(GLOBAL APPEND PROPERTY _qt_export_additional_targets_ids "${id}")
+ set_property(GLOBAL APPEND
+ PROPERTY _qt_export_additional_targets_export_name_prefix_${id} "${arg_EXPORT_NAME_PREFIX}")
+ set_property(GLOBAL APPEND
+ PROPERTY _qt_export_additional_targets_config_install_dir_${id} "${arg_CONFIG_INSTALL_DIR}")
+
+ qt_add_list_file_finalizer(qt_internal_export_additional_targets_file_finalizer)
+endfunction()
+
+function(qt_internal_get_export_additional_targets_id export_name out_var)
+ string(MAKE_C_IDENTIFIER "${export_name}" id)
+ set(${out_var} "${id}" PARENT_SCOPE)
+endfunction()
+
+# Uses outer-scope variables to keep the implementation less verbose.
+macro(qt_internal_append_export_additional_targets)
+ qt_internal_validate_export_additional_targets(
+ EXPORT_NAME_PREFIX "${arg_EXPORT_NAME_PREFIX}"
+ TARGETS ${arg_TARGETS}
+ TARGET_EXPORT_NAMES ${arg_TARGET_EXPORT_NAMES})
+
+ qt_internal_get_export_additional_targets_id("${arg_EXPORT_NAME_PREFIX}" id)
+
+ set_property(GLOBAL APPEND
+ PROPERTY _qt_export_additional_targets_${id} "${arg_TARGETS}")
+ set_property(GLOBAL APPEND
+ PROPERTY _qt_export_additional_target_export_names_${id} "${arg_TARGET_EXPORT_NAMES}")
+endmacro()
+
+# Can be called to add additional targets to the file after the initial setup call.
+# Used for resources.
+function(qt_internal_add_targets_to_additional_targets_export_file)
+ qt_internal_get_export_additional_targets_keywords(option_args single_args multi_args)
+ cmake_parse_arguments(arg
+ "${option_args}"
+ "${single_args}"
+ "${multi_args}"
+ ${ARGN})
+
+ qt_internal_append_export_additional_targets()
+endfunction()
+
+function(qt_internal_validate_export_additional_targets)
+ qt_internal_get_export_additional_targets_keywords(option_args single_args multi_args)
+ cmake_parse_arguments(arg
+ "${option_args}"
+ "${single_args}"
+ "${multi_args}"
+ ${ARGN})
+
+ if(NOT arg_EXPORT_NAME_PREFIX)
+ message(FATAL_ERROR "qt_internal_validate_export_additional_targets: "
+ "Missing EXPORT_NAME_PREFIX argument.")
+ endif()
+
+ list(LENGTH arg_TARGETS num_TARGETS)
+ list(LENGTH arg_TARGET_EXPORT_NAMES num_TARGET_EXPORT_NAMES)
+ if(num_TARGET_EXPORT_NAMES GREATER 0)
+ if(NOT num_TARGETS EQUAL num_TARGET_EXPORT_NAMES)
+ message(FATAL_ERROR "qt_internal_validate_export_additional_targets: "
+ "TARGET_EXPORT_NAMES is set but has ${num_TARGET_EXPORT_NAMES} elements while "
+ "TARGETS has ${num_TARGETS} elements. "
+ "They must contain the same number of elements.")
+ endif()
+ else()
+ set(arg_TARGET_EXPORT_NAMES ${arg_TARGETS})
+ endif()
+
+ set(arg_TARGETS "${arg_TARGETS}" PARENT_SCOPE)
+ set(arg_TARGET_EXPORT_NAMES "${arg_TARGET_EXPORT_NAMES}" PARENT_SCOPE)
+endfunction()
+
+# The finalizer might be called multiple times in the same scope, but only the first one will
+# process all the ids.
+function(qt_internal_export_additional_targets_file_finalizer)
+ get_property(ids GLOBAL PROPERTY _qt_export_additional_targets_ids)
+
+ foreach(id ${ids})
+ qt_internal_export_additional_targets_file_handler("${id}")
+ endforeach()
+
+ set_property(GLOBAL PROPERTY _qt_export_additional_targets_ids "")
+endfunction()
+
+function(qt_internal_export_additional_targets_file_handler id)
+ get_property(arg_EXPORT_NAME_PREFIX GLOBAL PROPERTY
+ _qt_export_additional_targets_export_name_prefix_${id})
+ get_property(arg_CONFIG_INSTALL_DIR GLOBAL PROPERTY
+ _qt_export_additional_targets_config_install_dir_${id})
+ get_property(arg_TARGETS GLOBAL PROPERTY
+ _qt_export_additional_targets_${id})
+ get_property(arg_TARGET_EXPORT_NAMES GLOBAL PROPERTY
+ _qt_export_additional_target_export_names_${id})
+
+ list(LENGTH arg_TARGETS num_TARGETS)
+
+ # Determine the release configurations we're currently building
+ if(QT_GENERATOR_IS_MULTI_CONFIG)
+ set(active_configurations ${CMAKE_CONFIGURATION_TYPES})
+ else()
+ set(active_configurations ${CMAKE_BUILD_TYPE})
+ endif()
+ unset(active_release_configurations)
+ foreach(config ${active_configurations})
+ string(TOUPPER ${config} ucconfig)
+ if(NOT ucconfig STREQUAL "DEBUG")
+ list(APPEND active_release_configurations ${config})
+ endif()
+ endforeach()
+
+ if(active_release_configurations)
+ # Use the first active release configuration as *the* release config for imported targets
+ # and for QT_DEFAULT_IMPORT_CONFIGURATION.
+ list(GET active_release_configurations 0 release_cfg)
+ string(TOUPPER ${release_cfg} uc_release_cfg)
+ set(uc_default_cfg ${uc_release_cfg})
+
+ # Determine the release configurations we do *not* build currently
+ set(configurations_to_export Release;RelWithDebInfo;MinSizeRel)
+ list(REMOVE_ITEM configurations_to_export ${active_configurations})
+ else()
+ # There are no active release configurations.
+ # Use the first active configuration for QT_DEFAULT_IMPORT_CONFIGURATION.
+ unset(uc_release_cfg)
+ list(GET active_configurations 0 default_cfg)
+ string(TOUPPER ${default_cfg} uc_default_cfg)
+ unset(configurations_to_export)
+ endif()
+
+ set(content "# Additional target information for ${arg_EXPORT_NAME_PREFIX}
+if(NOT DEFINED QT_DEFAULT_IMPORT_CONFIGURATION)
+ set(QT_DEFAULT_IMPORT_CONFIGURATION ${uc_default_cfg})
+endif()
+")
+
+ math(EXPR n "${num_TARGETS} - 1")
+ foreach(i RANGE ${n})
+ list(GET arg_TARGETS ${i} target)
+ list(GET arg_TARGET_EXPORT_NAMES ${i} target_export_name)
+
+ set(full_target ${target_export_name})
+ if(NOT full_target MATCHES "^${QT_CMAKE_EXPORT_NAMESPACE}::")
+ string(PREPEND full_target "${QT_CMAKE_EXPORT_NAMESPACE}::")
+ endif()
+
+ # Tools are already made global unconditionally in QtFooToolsConfig.cmake.
+ # And the
+ get_target_property(target_type ${target} TYPE)
+ if(NOT target_type STREQUAL "EXECUTABLE")
+ string(APPEND content
+ "__qt_internal_promote_target_to_global_checked(${full_target})\n")
+ endif()
+
+ # INTERFACE libraries don't have IMPORTED_LOCATION-like properties.
+ # Skip the rest of the processing for those.
+ if(target_type STREQUAL "INTERFACE_LIBRARY")
+ continue()
+ endif()
+
+ set(properties_retrieved TRUE)
+
+ get_target_property(is_configure_time_target ${target} _qt_internal_configure_time_target)
+ if(is_configure_time_target)
+ # For Multi-config developer builds we should simply reuse IMPORTED_LOCATION of the
+ # target.
+ if(NOT QT_WILL_INSTALL AND QT_FEATURE_debug_and_release)
+ set(configure_time_target_build_location "")
+ get_target_property(configure_time_target_install_location ${target}
+ IMPORTED_LOCATION)
+ else()
+ if(IS_ABSOLUTE "${arg_CONFIG_INSTALL_DIR}")
+ file(RELATIVE_PATH reverse_relative_prefix_path
+ "${arg_CONFIG_INSTALL_DIR}" "${CMAKE_INSTALL_PREFIX}")
+ else()
+ file(RELATIVE_PATH reverse_relative_prefix_path
+ "${CMAKE_INSTALL_PREFIX}/${arg_CONFIG_INSTALL_DIR}"
+ "${CMAKE_INSTALL_PREFIX}")
+ endif()
+
+ get_target_property(configure_time_target_build_location ${target}
+ _qt_internal_configure_time_target_build_location)
+ string(TOUPPER "${QT_CMAKE_EXPORT_NAMESPACE}_INSTALL_PREFIX" install_prefix_var)
+ string(JOIN "" configure_time_target_build_location
+ "$\{CMAKE_CURRENT_LIST_DIR}/"
+ "${reverse_relative_prefix_path}"
+ "${configure_time_target_build_location}")
+
+ get_target_property(configure_time_target_install_location ${target}
+ _qt_internal_configure_time_target_install_location)
+
+ string(JOIN "" configure_time_target_install_location
+ "$\{CMAKE_CURRENT_LIST_DIR}/"
+ "${reverse_relative_prefix_path}"
+ "${configure_time_target_install_location}")
+ endif()
+ if(configure_time_target_install_location)
+ string(APPEND content "
+# Import configure-time executable ${full_target}
+if(NOT TARGET ${full_target})
+ set(_qt_imported_build_location \"${configure_time_target_build_location}\")
+ set(_qt_imported_install_location \"${configure_time_target_install_location}\")
+ set(_qt_imported_location \"\${_qt_imported_install_location}\")
+ if(NOT EXISTS \"$\{_qt_imported_location}\"
+ AND NOT \"$\{_qt_imported_build_location}\" STREQUAL \"\")
+ set(_qt_imported_location \"\${_qt_imported_build_location}\")
+ endif()
+ if(NOT EXISTS \"$\{_qt_imported_location}\")
+ message(FATAL_ERROR \"Unable to add configure time executable ${full_target}\"
+ \" $\{_qt_imported_location} doesn't exists\")
+ endif()
+ add_executable(${full_target} IMPORTED)
+ set_property(TARGET ${full_target} APPEND PROPERTY IMPORTED_CONFIGURATIONS ${default_cfg})
+ set_target_properties(${full_target} PROPERTIES IMPORTED_LOCATION_${uc_default_cfg}
+ \"$\{_qt_imported_location}\")
+ set_property(TARGET ${full_target} PROPERTY IMPORTED_GLOBAL TRUE)
+ unset(_qt_imported_location)
+ unset(_qt_imported_build_location)
+ unset(_qt_imported_install_location)
+endif()
+\n")
+ endif()
+ endif()
+
+ # Non-prefix debug-and-release builds: add check for the existence of the debug binary of
+ # the target. It is not built by default.
+ if(NOT QT_WILL_INSTALL AND QT_FEATURE_debug_and_release)
+ get_target_property(excluded_genex ${target} EXCLUDE_FROM_ALL)
+ if(excluded_genex)
+ string(APPEND content "
+# ${full_target} is not built by default in the Debug configuration. Check existence.
+get_target_property(_qt_imported_location ${full_target} IMPORTED_LOCATION_DEBUG)
+if(NOT EXISTS \"$\{_qt_imported_location}\")
+ get_target_property(_qt_imported_configs ${full_target} IMPORTED_CONFIGURATIONS)
+ list(REMOVE_ITEM _qt_imported_configs DEBUG)
+ set_property(TARGET ${full_target} PROPERTY IMPORTED_CONFIGURATIONS $\{_qt_imported_configs})
+ set_property(TARGET ${full_target} PROPERTY IMPORTED_LOCATION_DEBUG)
+endif()\n")
+ endif()
+ endif()
+
+ set(write_implib FALSE)
+ set(write_soname FALSE)
+ set(write_objects FALSE)
+ set(write_location TRUE)
+
+ if(target_type STREQUAL "SHARED_LIBRARY")
+ if(WIN32)
+ set(write_implib TRUE)
+ elseif(WASM)
+ # Keep write_soname at FALSE
+ else()
+ set(write_soname TRUE)
+ endif()
+ elseif(target_type STREQUAL "OBJECT_LIBRARY")
+ set(write_objects TRUE)
+ set(write_location FALSE)
+ endif()
+
+ if(NOT "${uc_release_cfg}" STREQUAL "")
+ if(write_location)
+ string(APPEND content "get_target_property(_qt_imported_location ${full_target} IMPORTED_LOCATION_${uc_release_cfg})\n")
+ endif()
+ if(write_implib)
+ string(APPEND content "get_target_property(_qt_imported_implib ${full_target} IMPORTED_IMPLIB_${uc_release_cfg})\n")
+ endif()
+ if(write_soname)
+ string(APPEND content "get_target_property(_qt_imported_soname ${full_target} IMPORTED_SONAME_${uc_release_cfg})\n")
+ endif()
+ if(write_objects)
+ string(APPEND content "get_target_property(_qt_imported_objects ${full_target} IMPORTED_OBJECTS_${uc_release_cfg})\n")
+ # We generate CLR props as well, because that's what CMake generates for object
+ # libraries with CMake 3.27. They are usually empty strings though, aka "".
+ string(APPEND content "get_target_property(_qt_imported_clr ${full_target} IMPORTED_COMMON_LANGUAGE_RUNTIME_${uc_release_cfg})\n")
+ endif()
+ endif()
+ if(write_location)
+ string(APPEND content "get_target_property(_qt_imported_location_default ${full_target} IMPORTED_LOCATION_$\{QT_DEFAULT_IMPORT_CONFIGURATION})\n")
+ endif()
+ if(write_implib)
+ string(APPEND content "get_target_property(_qt_imported_implib_default ${full_target} IMPORTED_IMPLIB_$\{QT_DEFAULT_IMPORT_CONFIGURATION})\n")
+ endif()
+ if(write_soname)
+ string(APPEND content "get_target_property(_qt_imported_soname_default ${full_target} IMPORTED_SONAME_$\{QT_DEFAULT_IMPORT_CONFIGURATION})\n")
+ endif()
+ if(write_objects)
+ string(APPEND content "get_target_property(_qt_imported_objects_default ${full_target} IMPORTED_OBJECTS_$\{QT_DEFAULT_IMPORT_CONFIGURATION})\n")
+ string(APPEND content "get_target_property(_qt_imported_clr_default ${full_target} IMPORTED_COMMON_LANGUAGE_RUNTIME_$\{QT_DEFAULT_IMPORT_CONFIGURATION})\n")
+ endif()
+ foreach(config ${configurations_to_export} "")
+ string(TOUPPER "${config}" ucconfig)
+ if("${config}" STREQUAL "")
+ set(property_suffix "")
+ set(var_suffix "_default")
+ string(APPEND content "\n# Default configuration")
+ else()
+ set(property_suffix "_${ucconfig}")
+ set(var_suffix "")
+ string(APPEND content "
+# Import target \"${full_target}\" for configuration \"${config}\"
+set_property(TARGET ${full_target} APPEND PROPERTY IMPORTED_CONFIGURATIONS ${ucconfig})
+")
+ endif()
+ if(write_location)
+ string(APPEND content "
+if(_qt_imported_location${var_suffix})
+ set_property(TARGET ${full_target} PROPERTY IMPORTED_LOCATION${property_suffix} \"$\{_qt_imported_location${var_suffix}}\")
+endif()")
+ endif()
+ if(write_implib)
+ string(APPEND content "
+if(_qt_imported_implib${var_suffix})
+ set_property(TARGET ${full_target} PROPERTY IMPORTED_IMPLIB${property_suffix} \"$\{_qt_imported_implib${var_suffix}}\")
+endif()")
+ endif()
+ if(write_soname)
+ string(APPEND content "
+if(_qt_imported_soname${var_suffix})
+ set_property(TARGET ${full_target} PROPERTY IMPORTED_SONAME${property_suffix} \"$\{_qt_imported_soname${var_suffix}}\")
+endif()")
+ endif()
+ if(write_objects)
+ string(APPEND content "
+if(_qt_imported_objects${var_suffix})
+ set_property(TARGET ${full_target} PROPERTY IMPORTED_OBJECTS${property_suffix} \"$\{_qt_imported_objects${var_suffix}}\")
+endif()")
+ string(APPEND content "
+if(_qt_imported_clr${var_suffix})
+ set_property(TARGET ${full_target} PROPERTY IMPORTED_COMMON_LANGUAGE_RUNTIME${property_suffix} \"$\{_qt_imported_clr${var_suffix}}\")
+endif()")
+ endif()
+ string(APPEND content "\n")
+ endforeach()
+ endforeach()
+
+ if(properties_retrieved)
+ string(APPEND content "
+unset(_qt_imported_location)
+unset(_qt_imported_location_default)
+unset(_qt_imported_soname)
+unset(_qt_imported_soname_default)
+unset(_qt_imported_objects)
+unset(_qt_imported_objects_default)
+unset(_qt_imported_clr)
+unset(_qt_imported_clr_default)
+unset(_qt_imported_configs)")
+ endif()
+
+ qt_path_join(output_file "${arg_CONFIG_INSTALL_DIR}"
+ "${arg_EXPORT_NAME_PREFIX}AdditionalTargetInfo.cmake")
+ if(NOT IS_ABSOLUTE "${output_file}")
+ qt_path_join(output_file "${QT_BUILD_DIR}" "${output_file}")
+ endif()
+ qt_configure_file(OUTPUT "${output_file}" CONTENT "${content}")
+ qt_install(FILES "${output_file}" DESTINATION "${arg_CONFIG_INSTALL_DIR}")
+endfunction()
+
+function(qt_internal_export_modern_cmake_config_targets_file)
+ cmake_parse_arguments(arg
+ ""
+ "EXPORT_NAME_PREFIX;CONFIG_BUILD_DIR;CONFIG_INSTALL_DIR"
+ "TARGETS"
+ ${ARGN}
+ )
+
+ if("${arg_TARGETS}" STREQUAL "")
+ message(FATAL_ERROR "Target list is empty")
+ endif()
+
+ if("${arg_CONFIG_BUILD_DIR}" STREQUAL "")
+ message(FATAL_ERROR "CONFIG_BUILD_DIR is not specified")
+ endif()
+
+ if("${arg_CONFIG_INSTALL_DIR}" STREQUAL "")
+ message(FATAL_ERROR "CONFIG_INSTALL_DIR is not specified")
+ endif()
+
+ if("${arg_EXPORT_NAME_PREFIX}" STREQUAL "")
+ message(FATAL_ERROR "EXPORT_NAME_PREFIX is not specified")
+ endif()
+
+ set(versionless_targets ${arg_TARGETS})
+
+ # CMake versions < 3.18 compatibility code. Creates the mimics of the versioned libraries.
+ set(versionless_targets_export "${arg_CONFIG_BUILD_DIR}/${arg_EXPORT_NAME_PREFIX}VersionlessTargets.cmake")
+ configure_file("${QT_CMAKE_DIR}/QtVersionlessTargets.cmake.in"
+ "${versionless_targets_export}"
+ @ONLY
+ )
+
+ # CMake versions >= 3.18 code. Create the versionless ALIAS targets.
+ set(alias_export "${arg_CONFIG_BUILD_DIR}/${arg_EXPORT_NAME_PREFIX}VersionlessAliasTargets.cmake")
+ configure_file("${QT_CMAKE_DIR}/QtVersionlessAliasTargets.cmake.in"
+ "${alias_export}"
+ @ONLY
+ )
+
+ qt_install(FILES
+ "${alias_export}"
+ "${versionless_targets_export}"
+ DESTINATION "${arg_CONFIG_INSTALL_DIR}"
+ COMPONENT Devel
+ )
+endfunction()
+
+function(qt_internal_create_tracepoints name tracepoints_file)
+ string(TOLOWER "${name}" provider_name)
+ string(PREPEND provider_name "qt")
+ set(header_filename "${provider_name}_tracepoints_p.h")
+ set(header_path "${CMAKE_CURRENT_BINARY_DIR}/${header_filename}")
+
+ if(QT_FEATURE_lttng OR QT_FEATURE_etw OR QT_FEATURE_ctf)
+ set(source_path "${CMAKE_CURRENT_BINARY_DIR}/${provider_name}_tracepoints.cpp")
+ qt_configure_file(OUTPUT "${source_path}"
+ CONTENT "#define TRACEPOINT_CREATE_PROBES
+#define TRACEPOINT_DEFINE
+#include \"${header_filename}\"")
+ target_sources(${name} PRIVATE "${source_path}")
+ target_compile_definitions(${name} PUBLIC Q_TRACEPOINT)
+
+ if(QT_FEATURE_lttng)
+ set(tracegen_arg "lttng")
+ target_link_libraries(${name} PRIVATE LTTng::UST)
+ elseif(QT_FEATURE_etw)
+ set(tracegen_arg "etw")
+ elseif(QT_FEATURE_ctf)
+ set(tracegen_arg "ctf")
+ endif()
+
+ if(NOT "${QT_HOST_PATH}" STREQUAL "")
+ qt_path_join(tracegen
+ "${QT_HOST_PATH}"
+ "${QT${PROJECT_VERSION_MAJOR}_HOST_INFO_LIBEXECDIR}"
+ "tracegen")
+ else()
+ set(tracegen "${QT_CMAKE_EXPORT_NAMESPACE}::tracegen")
+ endif()
+
+ get_filename_component(tracepoints_filepath "${tracepoints_file}" ABSOLUTE)
+ add_custom_command(OUTPUT "${header_path}"
+ COMMAND ${tracegen} ${tracegen_arg} "${tracepoints_filepath}" "${header_path}"
+ VERBATIM)
+ add_custom_target(${name}_tracepoints_header DEPENDS "${header_path}")
+ add_dependencies(${name} ${name}_tracepoints_header)
+ else()
+ qt_configure_file(OUTPUT "${header_path}" CONTENT "#include <private/qtrace_p.h>\n")
+ endif()
+endfunction()
+
+function(qt_internal_generate_tracepoints name provider)
+ cmake_parse_arguments(arg "" "" "SOURCES" ${ARGN} )
+ set(provider_name ${provider})
+ string(PREPEND provider_name "qt")
+ set(tracepoint_filename "${provider_name}.tracepoints")
+ set(tracepoints_path "${CMAKE_CURRENT_BINARY_DIR}/${tracepoint_filename}")
+ set(header_filename "${provider_name}_tracepoints_p.h")
+ set(header_path "${CMAKE_CURRENT_BINARY_DIR}/${header_filename}")
+
+ if(QT_FEATURE_lttng OR QT_FEATURE_etw OR QT_FEATURE_ctf)
+
+ set(absolute_file_paths "")
+ foreach(file IN LISTS arg_SOURCES)
+ get_filename_component(absolute_file ${file} ABSOLUTE)
+ list(APPEND absolute_file_paths ${absolute_file})
+ endforeach()
+
+ if(NOT "${QT_HOST_PATH}" STREQUAL "")
+ qt_path_join(tracepointgen
+ "${QT_HOST_PATH}"
+ "${QT${PROJECT_VERSION_MAJOR}_HOST_INFO_LIBEXECDIR}"
+ "tracepointgen")
+ else()
+ set(tracepointgen "${QT_CMAKE_EXPORT_NAMESPACE}::tracepointgen")
+ endif()
+
+ add_custom_command(OUTPUT "${tracepoints_path}"
+ COMMAND ${tracepointgen} ${provider_name} "${tracepoints_path}" "I$<JOIN:$<TARGET_PROPERTY:${name},INCLUDE_DIRECTORIES>,;>" ${absolute_file_paths}
+ DEPENDS ${absolute_file_paths}
+ VERBATIM)
+ add_custom_target(${name}_${provider_name}_tracepoints_file DEPENDS "${tracepoints_path}")
+ add_dependencies(${name} ${name}_${provider_name}_tracepoints_file)
+
+ set(source_path "${CMAKE_CURRENT_BINARY_DIR}/${provider_name}_tracepoints.cpp")
+ qt_configure_file(OUTPUT "${source_path}"
+ CONTENT "#define TRACEPOINT_CREATE_PROBES
+ #define TRACEPOINT_DEFINE
+ #include \"${header_filename}\"")
+ target_sources(${name} PRIVATE "${source_path}")
+ target_compile_definitions(${name} PUBLIC Q_TRACEPOINT)
+
+ if(QT_FEATURE_lttng)
+ set(tracegen_arg "lttng")
+ target_link_libraries(${name} PRIVATE LTTng::UST)
+ elseif(QT_FEATURE_etw)
+ set(tracegen_arg "etw")
+ elseif(QT_FEATURE_ctf)
+ set(tracegen_arg "ctf")
+ endif()
+
+ if(NOT "${QT_HOST_PATH}" STREQUAL "")
+ qt_path_join(tracegen
+ "${QT_HOST_PATH}"
+ "${QT${PROJECT_VERSION_MAJOR}_HOST_INFO_LIBEXECDIR}"
+ "tracegen")
+ else()
+ set(tracegen "${QT_CMAKE_EXPORT_NAMESPACE}::tracegen")
+ endif()
+
+ get_filename_component(tracepoints_filepath "${tracepoints_path}" ABSOLUTE)
+ add_custom_command(OUTPUT "${header_path}"
+ COMMAND ${tracegen} ${tracegen_arg} "${tracepoints_filepath}" "${header_path}"
+ DEPENDS "${tracepoints_path}"
+ VERBATIM)
+ add_custom_target(${name}_${provider_name}_tracepoints_header DEPENDS "${header_path}")
+ add_dependencies(${name} ${name}_${provider_name}_tracepoints_header)
+ else()
+ qt_configure_file(OUTPUT "${header_path}" CONTENT "#include <private/qtrace_p.h>\n")
+ endif()
+endfunction()
+
+function(qt_internal_set_compile_pdb_names target)
+ if(MSVC)
+ get_target_property(target_type ${target} TYPE)
+ if(target_type STREQUAL "STATIC_LIBRARY" OR target_type STREQUAL "OBJECT_LIBRARY")
+ get_target_property(output_name ${target} OUTPUT_NAME)
+ if(NOT output_name)
+ set(output_name "${INSTALL_CMAKE_NAMESPACE}${target}")
+ endif()
+ set_target_properties(${target} PROPERTIES COMPILE_PDB_NAME "${output_name}")
+ set_target_properties(${target} PROPERTIES COMPILE_PDB_NAME_DEBUG "${output_name}d")
+ endif()
+ endif()
+endfunction()
+
+# Installs pdb files for given target into the specified install dir.
+#
+# MSVC generates 2 types of pdb files:
+# - compile-time generated pdb files (compile flag /Zi + /Fd<pdb_name>)
+# - link-time generated pdb files (link flag /debug + /PDB:<pdb_name>)
+#
+# CMake allows changing the names of each of those pdb file types by setting
+# the COMPILE_PDB_NAME_<CONFIG> and PDB_NAME_<CONFIG> properties. If they are
+# left empty, CMake will compute the default names itself (or rather in certain cases
+# leave it up to the compiler), without actually setting the property values.
+#
+# For installation purposes, CMake only provides a generator expression to the
+# link time pdb file path, not the compile path one, which means we have to compute the
+# path to the compile path pdb files ourselves.
+# See https://gitlab.kitware.com/cmake/cmake/-/issues/18393 for details.
+#
+# For shared libraries and executables, we install the linker provided pdb file via the
+# TARGET_PDB_FILE generator expression.
+#
+# For static libraries there is no linker invocation, so we need to install the compile
+# time pdb file. We query the ARCHIVE_OUTPUT_DIRECTORY property of the target to get the
+# path to the pdb file, and reconstruct the file name. We use a generator expression
+# to append a possible debug suffix, in order to allow installation of all Release and
+# Debug pdb files when using Ninja Multi-Config.
+function(qt_internal_install_pdb_files target install_dir_path)
+ if(MSVC)
+ get_target_property(target_type ${target} TYPE)
+
+ if(target_type STREQUAL "EXECUTABLE")
+ qt_get_cmake_configurations(cmake_configs)
+ list(LENGTH cmake_configs all_configs_count)
+ list(GET cmake_configs 0 first_config)
+ foreach(cmake_config ${cmake_configs})
+ set(suffix "")
+ if(all_configs_count GREATER 1 AND NOT cmake_config STREQUAL first_config)
+ set(suffix "/${cmake_config}")
+ endif()
+ qt_install(FILES "$<TARGET_PDB_FILE:${target}>"
+ CONFIGURATIONS ${cmake_config}
+ DESTINATION "${install_dir_path}${suffix}"
+ OPTIONAL)
+ endforeach()
+
+ elseif(target_type STREQUAL "SHARED_LIBRARY"
+ OR target_type STREQUAL "MODULE_LIBRARY")
+ qt_install(FILES "$<TARGET_PDB_FILE:${target}>"
+ DESTINATION "${install_dir_path}"
+ OPTIONAL)
+
+ elseif(target_type STREQUAL "STATIC_LIBRARY")
+ get_target_property(lib_dir "${target}" ARCHIVE_OUTPUT_DIRECTORY)
+ if(NOT lib_dir)
+ message(FATAL_ERROR
+ "Can't install pdb file for static library ${target}. "
+ "The ARCHIVE_OUTPUT_DIRECTORY path is not known.")
+ endif()
+ get_target_property(pdb_name "${target}" COMPILE_PDB_NAME)
+ qt_path_join(compile_time_pdb_file_path
+ "${lib_dir}" "${pdb_name}$<$<CONFIG:Debug>:d>.pdb")
+
+ qt_install(FILES "${compile_time_pdb_file_path}"
+ DESTINATION "${install_dir_path}" OPTIONAL)
+ elseif(target_type STREQUAL "OBJECT_LIBRARY")
+ get_target_property(pdb_dir "${target}" COMPILE_PDB_OUTPUT_DIRECTORY)
+ if(NOT pdb_dir)
+ get_target_property(pdb_dir "${target}" BINARY_DIR)
+ if(QT_GENERATOR_IS_MULTI_CONFIG)
+ qt_path_join(pdb_dir "${pdb_dir}" "$<CONFIG>")
+ endif()
+ endif()
+ get_target_property(pdb_name "${target}" COMPILE_PDB_NAME)
+ qt_path_join(compile_time_pdb_file_path
+ "${pdb_dir}" "${pdb_name}$<$<CONFIG:Debug>:d>.pdb")
+
+ qt_install(FILES "${compile_time_pdb_file_path}"
+ DESTINATION "${install_dir_path}" OPTIONAL)
+ endif()
+ endif()
+endfunction()
+
+# Certain targets might have dependencies on libraries that don't have an Apple Silicon arm64
+# slice. When doing a universal macOS build, force those targets to be built only for the
+# Intel x86_64 arch.
+# This behavior can be disabled for all targets by setting the QT_FORCE_MACOS_ALL_ARCHES cache
+# variable to TRUE or by setting the target specific cache variable
+# QT_FORCE_MACOS_ALL_ARCHES_${target} to TRUE.
+#
+# TODO: Ideally we'd use something like _apple_resolve_supported_archs_for_sdk_from_system_lib
+# from CMake's codebase to parse which architectures are available in a library, but it's
+# not straightforward to extract the library absolute file path from a CMake target. Furthermore
+# Apple started using a built-in dynamic linker cache of all system-provided libraries as per
+# https://gitlab.kitware.com/cmake/cmake/-/issues/20863
+# so if the target is a library in the dynamic cache, that might further complicate how to get
+# the list of arches in it.
+function(qt_internal_force_macos_intel_arch target)
+ if(MACOS AND QT_IS_MACOS_UNIVERSAL AND NOT QT_FORCE_MACOS_ALL_ARCHES
+ AND NOT QT_FORCE_MACOS_ALL_ARCHES_${target})
+ set(arches "x86_64")
+ set_target_properties(${target} PROPERTIES OSX_ARCHITECTURES "${arches}")
+ endif()
+endfunction()
+
+function(qt_disable_apple_app_extension_api_only target)
+ set_target_properties("${target}" PROPERTIES QT_NO_APP_EXTENSION_ONLY_API TRUE)
+endfunction()
+
+# Common function to add Qt prefixes to the target name
+function(qt_internal_qtfy_target out_var target)
+ set(${out_var} "Qt${target}" PARENT_SCOPE)
+ set(${out_var}_versioned "Qt${PROJECT_VERSION_MAJOR}${target}" PARENT_SCOPE)
+endfunction()
+
+function(qt_internal_get_main_cmake_configuration out_var)
+ if(CMAKE_BUILD_TYPE)
+ set(config "${CMAKE_BUILD_TYPE}")
+ elseif(QT_MULTI_CONFIG_FIRST_CONFIG)
+ set(config "${QT_MULTI_CONFIG_FIRST_CONFIG}")
+ endif()
+ set("${out_var}" "${config}" PARENT_SCOPE)
+endfunction()
+
+function(qt_internal_get_upper_case_main_cmake_configuration out_var)
+ qt_internal_get_main_cmake_configuration("${out_var}")
+ string(TOUPPER "${${out_var}}" upper_config)
+ set("${out_var}" "${upper_config}" PARENT_SCOPE)
+endfunction()
+
+function(qt_internal_adjust_main_config_runtime_output_dir target output_dir)
+ # When building Qt with multiple configurations, place the main configuration executable
+ # directly in ${output_dir}, rather than a ${output_dir}/<CONFIG> subdirectory.
+ qt_internal_get_upper_case_main_cmake_configuration(main_cmake_configuration)
+ set_target_properties("${target}" PROPERTIES
+ RUNTIME_OUTPUT_DIRECTORY_${main_cmake_configuration} "${output_dir}"
+ )
+endfunction()
+
+# Marks a target with a property that it is a library (shared or static) which was built using the
+# internal Qt API (qt_internal_add_module, qt_internal_add_plugin, etc) as opposed to it being
+# a user project library (qt_add_library, qt_add_plugin, etc).
+#
+# Needed to allow selectively applying certain flags via PlatformXInternal targets.
+function(qt_internal_mark_as_internal_library target)
+ set_target_properties(${target} PROPERTIES _qt_is_internal_library TRUE)
+ qt_internal_mark_as_internal_target(${target})
+endfunction()
+
+# Marks a target with a property that it was built using the internal Qt API (qt_internal_*) as
+# opposed to it being a user project library or executable(qt_add_*, etc).
+#
+# Needed to allow selectively applying certain flags via PlatformXInternal targets.
+function(qt_internal_mark_as_internal_target target)
+ set_target_properties(${target} PROPERTIES _qt_is_internal_target TRUE)
+endfunction()
+
+# Marks a target with a property to skip it adding it as a dependency when building examples as
+# ExternalProjects.
+# Needed to create a ${repo}_src global target that examples can depend on in multi-config builds
+# due to a bug in AUTOUIC.
+#
+# See QTBUG-110369.
+function(qt_internal_skip_dependency_for_examples target)
+ set_target_properties(${target} PROPERTIES _qt_skip_dependency_for_examples TRUE)
+endfunction()
+
+function(qt_internal_is_target_skipped_for_examples target out_var)
+ get_property(is_skipped TARGET ${target} PROPERTY _qt_skip_dependency_for_examples)
+ if(NOT is_skipped)
+ set(is_skipped FALSE)
+ endif()
+ set(${out_var} "${is_skipped}" PARENT_SCOPE)
+endfunction()
+
+function(qt_internal_link_internal_platform_for_object_library target)
+ # We need to apply iOS bitcode flags to object libraries that are associated with internal
+ # modules or plugins (e.g. object libraries added by qt_internal_add_resource,
+ # qt_internal_add_plugin, etc.)
+ # The flags are needed when building iOS apps because Xcode expects bitcode to be
+ # present by default.
+ # Achieve this by compiling the cpp files with the PlatformModuleInternal compile flags.
+ target_link_libraries("${target}" PRIVATE Qt::PlatformModuleInternal)
+endfunction()
+
+# Use ${dep_target}'s include dirs when building ${target}.
+#
+# Assumes ${dep_target} is an INTERFACE_LIBRARY that only propagates include dirs and ${target}
+# is a Qt module / plugin.
+#
+# Building ${target} requires ${dep_target}'s include dirs.
+# Using ${target} does not require ${dep_target}'s include dirs.
+#
+# The main use case is adding the private header-only dependency PkgConfig::ATSPI2.
+function(qt_internal_add_target_include_dirs target dep_target)
+ if(NOT TARGET "${target}")
+ message(FATAL_ERROR "${target} is not a valid target.")
+ endif()
+ if(NOT TARGET "${dep_target}")
+ message(FATAL_ERROR "${dep_target} is not a valid target.")
+ endif()
+
+ target_include_directories("${target}" PRIVATE
+ "$<TARGET_PROPERTY:${dep_target},INTERFACE_INCLUDE_DIRECTORIES>")
+endfunction()
+
+# Use ${dep_target}'s include dirs when building ${target} and optionally propagate the include
+# dirs to consumers of ${target}.
+
+# Assumes ${dep_target} is an INTERFACE_LIBRARY that only propagates include dirs and ${target}
+# is a Qt module / plugin.
+#
+# Building ${target} requires ${dep_target}'s include dirs.
+#
+# User projects that don't have ${dep_target}'s headers installed in their system should still
+# configure successfully.
+#
+# To achieve that, consumers of ${target} will only get the include directories of ${dep_target}
+# if the latter package and target exists.
+#
+# A find_package(dep_target) dependency is added to ${target}'s *Dependencies.cmake file.
+#
+# We use target_include_directories(PRIVATE) instead of target_link_libraries(PRIVATE) because the
+# latter would propagate a mandatory LINK_ONLY dependency on the ${dep_target} in a static Qt build.
+#
+# The main use case is for propagating WrapVulkanHeaders::WrapVulkanHeaders.
+function(qt_internal_add_target_include_dirs_and_optionally_propagate target dep_target)
+ qt_internal_add_target_include_dirs(${target} ${dep_target})
+
+ target_link_libraries("${target}" INTERFACE "$<TARGET_NAME_IF_EXISTS:${dep_target}>")
+
+ qt_record_extra_third_party_dependency("${target}" "${dep_target}")
+endfunction()
+
+# The function disables one or multiple internal global definitions that are defined by the
+# qt_internal_add_global_definition function for a specific 'target'.
+function(qt_internal_undefine_global_definition target)
+ if(NOT TARGET "${target}")
+ message(FATAL_ERROR "${target} is not a target.")
+ endif()
+ qt_internal_is_skipped_test(skipped ${target})
+ if(skipped)
+ return()
+ endif()
+ qt_internal_is_in_test_batch(in_batch ${target})
+ if(in_batch)
+ _qt_internal_test_batch_target_name(target)
+ endif()
+
+ if("${ARGN}" STREQUAL "")
+ message(FATAL_ERROR "The function expects at least one definition as an argument.")
+ endif()
+
+ foreach(definition IN LISTS ARGN)
+ set(undef_property_name "QT_INTERNAL_UNDEF_${definition}")
+ set_target_properties(${target} PROPERTIES "${undef_property_name}" TRUE)
+ endforeach()
+endfunction()
+
+# This function adds any defines which are local to the current repository (e.g. qtbase,
+# qtmultimedia). Those can be defined in the corresponding .cmake.conf file via
+# QT_EXTRA_INTERNAL_TARGET_DEFINES. QT_EXTRA_INTERNAL_TARGET_DEFINES accepts a list of definitions.
+# The definitions are passed to target_compile_definitions, which means that values can be provided
+# via the FOO=Bar syntax
+# This does nothing for interface targets
+function(qt_internal_add_repo_local_defines target)
+ get_target_property(type "${target}" TYPE)
+ if (${type} STREQUAL "INTERFACE_LIBRARY")
+ return()
+ endif()
+ if(DEFINED QT_EXTRA_INTERNAL_TARGET_DEFINES)
+ target_compile_definitions("${target}" PRIVATE ${QT_EXTRA_INTERNAL_TARGET_DEFINES})
+ endif()
+endfunction()
+
+# The function returns the value of the target's SOURCES property. The function takes into account
+# the limitation of the CMake version less than 3.19, that restricts to add non-interface sources
+# to an interface target.
+# Note: The function works correctly only if qt_internal_extend_target is used when adding source
+# files.
+function(qt_internal_get_target_sources out_var target)
+ qt_internal_get_target_sources_property(sources_property)
+ get_target_property(${out_var} ${target} ${sources_property})
+ set(${out_var} "${${out_var}}" PARENT_SCOPE)
+endfunction()
+
+# The function distinguishes what property supposed to store target sources, based on target TYPE
+# and the CMake version.
+function(qt_internal_get_target_sources_property out_var)
+ set(${out_var} "SOURCES")
+ get_target_property(target_type ${target} TYPE)
+ if(CMAKE_VERSION VERSION_LESS "3.19" AND target_type STREQUAL "INTERFACE_LIBRARY")
+ set(${out_var} "_qt_internal_target_sources")
+ endif()
+ set(${out_var} "${${out_var}}" PARENT_SCOPE)
+endfunction()
+
+# This function collects target properties that contain generator expressions and needs to be
+# exported. This function is needed since the CMake EXPORT_PROPERTIES property doesn't support
+# properties that contain generator expressions.
+# Usage: qt_internal_add_genex_properties_export(target properties...)
+function(qt_internal_add_genex_properties_export target)
+ get_cmake_property(is_multi_config GENERATOR_IS_MULTI_CONFIG)
+
+ set(config_check_begin "")
+ set(config_check_end "")
+ if(is_multi_config)
+ list(GET CMAKE_CONFIGURATION_TYPES 0 first_config_type)
+
+ # The genex snippet is evaluated to '$<NOT:$<BOOL:$<CONFIG>>>' in the generated cmake file.
+ # The check is only applicable to the 'main' configuration. If user project doesn't use
+ # multi-config generator, then the check supposed to return true and the value from the
+ # 'main' configuration supposed to be used.
+ string(JOIN "" check_if_config_empty
+ "$<1:$><NOT:"
+ "$<1:$><BOOL:"
+ "$<1:$><CONFIG$<ANGLE-R>"
+ "$<ANGLE-R>"
+ "$<ANGLE-R>"
+ )
+
+ # The genex snippet is evaluated to '$<CONFIG:'Qt config type'>' in the generated cmake
+ # file and checks if the config that user uses matches the generated cmake file config.
+ string(JOIN "" check_user_config
+ "$<1:$><CONFIG:$<CONFIG>$<ANGLE-R>"
+ )
+
+ # The genex snippet is evaluated to '$<$<OR:$<CONFIG:'Qt config type'>>:'Property content'>
+ # for non-main Qt configs and to
+ # $<$<OR:$<CONFIG:'Qt config type'>,$<NOT:$<BOOL:$<CONFIG>>>>:'Property content'> for the
+ # main Qt config. This guard is required to choose the correct value of the property for the
+ # user project according to the user config type.
+ # All genexes need to be escaped properly to protect them from evaluation by the
+ # file(GENERATE call in the qt_internal_export_genex_properties function.
+ string(JOIN "" config_check_begin
+ "$<1:$><"
+ "$<1:$><OR:"
+ "${check_user_config}"
+ "$<$<CONFIG:${first_config_type}>:$<COMMA>${check_if_config_empty}>"
+ "$<ANGLE-R>:"
+ )
+ set(config_check_end "$<ANGLE-R>")
+ endif()
+ set(target_name "${QT_CMAKE_EXPORT_NAMESPACE}::${target}")
+ foreach(property IN LISTS ARGN)
+ set(target_property_genex "$<TARGET_PROPERTY:${target_name},${property}>")
+ # All properties that contain lists need to be protected of processing by JOIN genex calls.
+ # So this escapes the semicolons for these list.
+ set(target_property_list_escape
+ "$<JOIN:$<GENEX_EVAL:${target_property_genex}>,\;>")
+ set(property_value
+ "\"${config_check_begin}${target_property_list_escape}${config_check_end}\"")
+ set_property(TARGET ${target} APPEND PROPERTY _qt_export_genex_properties_content
+ "${property} ${property_value}")
+ endforeach()
+endfunction()
+
+# This function executes generator expressions for the properties that are added by the
+# qt_internal_add_genex_properties_export function and sets the calculated values to the
+# corresponding properties in the generated ExtraProperties.cmake file. The file then needs to be
+# included after the target creation routines in Config.cmake files. It also supports Multi-Config
+# builds.
+# Arguments:
+# EXPORT_NAME_PREFIX:
+# The portion of the file name before ExtraProperties.cmake
+# CONFIG_INSTALL_DIR:
+# Installation location for the file.
+# TARGETS:
+# The internal target names.
+function(qt_internal_export_genex_properties)
+ set(option_args "")
+ set(single_args
+ EXPORT_NAME_PREFIX
+ CONFIG_INSTALL_DIR
+ )
+ set(multi_args TARGETS)
+ cmake_parse_arguments(arg "${option_args}" "${single_args}" "${multi_args}" ${ARGN})
+
+ if(NOT arg_EXPORT_NAME_PREFIX)
+ message(FATAL_ERROR "qt_internal_export_genex_properties: "
+ "Missing EXPORT_NAME_PREFIX argument.")
+ endif()
+
+ if(NOT arg_TARGETS)
+ message(FATAL_ERROR "qt_internal_export_genex_properties: "
+ "TARGETS argument must contain at least one target")
+ endif()
+
+ foreach(target IN LISTS arg_TARGETS)
+ get_cmake_property(is_multi_config GENERATOR_IS_MULTI_CONFIG)
+
+ set(output_file_base_name "${arg_EXPORT_NAME_PREFIX}ExtraProperties")
+ set(should_append "")
+ set(config_suffix "")
+ if(is_multi_config)
+ list(GET CMAKE_CONFIGURATION_TYPES 0 first_config_type)
+ set(config_suffix "$<$<NOT:$<CONFIG:${first_config_type}>>:-$<CONFIG>>")
+ # If the generated file belongs to the 'main' config type, we should set property
+ # but not append it.
+ string(JOIN "" should_append
+ "$<$<NOT:$<CONFIG:${first_config_type}>>: APPEND>")
+ endif()
+ set(file_name "${output_file_base_name}${config_suffix}.cmake")
+
+ qt_path_join(output_file "${arg_CONFIG_INSTALL_DIR}"
+ "${file_name}")
+
+ if(NOT IS_ABSOLUTE "${output_file}")
+ qt_path_join(output_file "${QT_BUILD_DIR}" "${output_file}")
+ endif()
+
+ set(target_name "${QT_CMAKE_EXPORT_NAMESPACE}::${target}")
+
+ string(JOIN "" set_property_begin "set_property(TARGET "
+ "${target_name}${should_append} PROPERTY "
+ )
+ set(set_property_end ")")
+ set(set_property_glue "${set_property_end}\n${set_property_begin}")
+ set(property_list
+ "$<GENEX_EVAL:$<TARGET_PROPERTY:${target},_qt_export_genex_properties_content>>")
+ string(JOIN "" set_property_content "${set_property_begin}"
+ "$<JOIN:${property_list},${set_property_glue}>"
+ "${set_property_end}")
+
+ if(is_multi_config)
+ set(config_includes "")
+ foreach(config IN LISTS CMAKE_CONFIGURATION_TYPES)
+ if(NOT first_config_type STREQUAL config)
+ set(include_file_name
+ "${output_file_base_name}-${config}.cmake")
+ list(APPEND config_includes
+ "include(\"\${CMAKE_CURRENT_LIST_DIR}/${include_file_name}\")")
+ endif()
+ endforeach()
+ list(JOIN config_includes "\n" config_includes_string)
+ set(config_includes_string
+ "\n$<$<CONFIG:${first_config_type}>:${config_includes_string}>")
+ endif()
+
+ file(GENERATE OUTPUT "${output_file}"
+ CONTENT "$<$<BOOL:${property_list}>:${set_property_content}${config_includes_string}>"
+ CONDITION "$<BOOL:${property_list}>"
+ )
+ endforeach()
+
+ qt_install(FILES "$<$<BOOL:${property_list}>:${output_file}>"
+ DESTINATION "${arg_CONFIG_INSTALL_DIR}"
+ COMPONENT Devel
+ )
+endfunction()
+
+# The macro promotes the Qt platform targets and their dependencies to global. The macro shouldn't
+# be called explicitly in regular cases. It's called right after the first find_package(Qt ...)
+# call in the qt_internal_project_setup macro.
+# This allows using the qt_find_package(Wrap<3rdparty> PROVIDED_TARGETS ...) function,
+# without the risk of having duplicated global promotion of Qt internals. This is especially
+# sensitive for the bundled 3rdparty libraries.
+macro(qt_internal_promote_platform_targets_to_global)
+ if(TARGET Qt6::Platform)
+ get_target_property(is_imported Qt6::Platform IMPORTED)
+ if(is_imported)
+ set(known_platform_targets
+ Platform
+ PlatformCommonInternal
+ PlatformModuleInternal
+ PlatformPluginInternal
+ PlatformAppInternal
+ PlatformToolInternal
+ )
+ set(versionless_platform_targets ${known_platform_targets})
+
+ list(TRANSFORM known_platform_targets PREPEND Qt6::)
+ list(TRANSFORM versionless_platform_targets PREPEND Qt::)
+ qt_find_package(Qt6 PROVIDED_TARGETS
+ ${known_platform_targets}
+ ${versionless_platform_targets})
+ endif()
+ endif()
+endmacro()
diff --git a/cmake/QtTestHelpers.cmake b/cmake/QtTestHelpers.cmake
new file mode 100644
index 0000000000..705de2f739
--- /dev/null
+++ b/cmake/QtTestHelpers.cmake
@@ -0,0 +1,1091 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+# Simple wrapper around qt_internal_add_executable for benchmarks which insure that
+# the binary is built under ${CMAKE_CURRENT_BINARY_DIR} and never installed.
+# See qt_internal_add_executable() for more details.
+function(qt_internal_add_benchmark target)
+ if(QT_BUILD_TESTS_BATCHED)
+ message(WARNING "Benchmarks won't be batched - unsupported (yet)")
+ endif()
+
+ cmake_parse_arguments(PARSE_ARGV 1 arg
+ "${__qt_internal_add_executable_optional_args}"
+ "${__qt_internal_add_executable_single_args}"
+ "${__qt_internal_add_executable_multi_args}"
+ )
+ _qt_internal_validate_all_args_are_parsed(arg)
+ _qt_internal_validate_no_unity_build(arg)
+
+ qt_remove_args(exec_args
+ ARGS_TO_REMOVE
+ ${target}
+ OUTPUT_DIRECTORY
+ INSTALL_DIRECTORY
+ ALL_ARGS
+ "${__qt_internal_add_executable_optional_args}"
+ "${__qt_internal_add_executable_single_args}"
+ "${__qt_internal_add_executable_multi_args}"
+ ARGS
+ ${ARGV}
+ )
+
+ if(NOT arg_OUTPUT_DIRECTORY)
+ if(CMAKE_RUNTIME_OUTPUT_DIRECTORY)
+ set(arg_OUTPUT_DIRECTORY "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}")
+ else()
+ set(arg_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}")
+ endif()
+ endif()
+
+ qt_internal_library_deprecation_level(deprecation_define)
+
+ qt_internal_add_executable(${target}
+ NO_INSTALL # we don't install benchmarks
+ NO_UNITY_BUILD # excluded by default
+ OUTPUT_DIRECTORY "${arg_OUTPUT_DIRECTORY}" # avoid polluting bin directory
+ ${exec_args}
+ )
+ qt_internal_extend_target(${target}
+ DEFINES
+ ${deprecation_define}
+ )
+
+ # Benchmarks on iOS must be app bundles.
+ if(IOS)
+ set_target_properties(${target} PROPERTIES MACOSX_BUNDLE TRUE)
+ endif()
+
+ qt_internal_add_repo_local_defines(${target})
+
+ # Disable the QT_NO_NARROWING_CONVERSIONS_IN_CONNECT define for benchmarks
+ qt_internal_undefine_global_definition(${target} QT_NO_NARROWING_CONVERSIONS_IN_CONNECT)
+
+ qt_internal_collect_command_environment(benchmark_env_path benchmark_env_plugin_path)
+
+ # Add a ${target}_benchmark generator target, to run single benchmark more easily.
+ set(benchmark_wrapper_file "${arg_OUTPUT_DIRECTORY}/${target}Wrapper$<CONFIG>.cmake")
+ _qt_internal_create_command_script(COMMAND "$<TARGET_FILE:${target}>"
+ OUTPUT_FILE "${benchmark_wrapper_file}"
+ ENVIRONMENT "PATH" "${benchmark_env_path}"
+ "QT_PLUGIN_PATH" "${benchmark_env_plugin_path}"
+ )
+
+ add_custom_target("${target}_benchmark"
+ VERBATIM
+ COMMENT "Running benchmark ${target}"
+ COMMAND "${CMAKE_COMMAND}" "-P" "${benchmark_wrapper_file}"
+ )
+
+ add_dependencies("${target}_benchmark" "${target}")
+
+ # Add benchmark to meta target if it exists.
+ if (TARGET benchmark)
+ add_dependencies("benchmark" "${target}_benchmark")
+ endif()
+
+ qt_internal_add_test_finalizers("${target}")
+endfunction()
+
+function(qt_internal_add_test_dependencies target)
+ if(QT_BUILD_TESTS_BATCHED)
+ _qt_internal_test_batch_target_name(target)
+ endif()
+ add_dependencies(${target} ${ARGN})
+endfunction()
+
+# Simple wrapper around qt_internal_add_executable for manual tests which insure that
+# the binary is built under ${CMAKE_CURRENT_BINARY_DIR} and never installed.
+# See qt_internal_add_executable() for more details.
+function(qt_internal_add_manual_test target)
+ qt_internal_add_test(${ARGV} MANUAL)
+endfunction()
+
+# This function will configure the fixture for the network tests that require docker network services
+# qmake counterpart: qtbase/mkspecs/features/unsupported/testserver.prf
+function(qt_internal_setup_docker_test_fixture name)
+ # Only Linux is provisioned with docker at this time
+ if (NOT CMAKE_HOST_SYSTEM_NAME STREQUAL "Linux")
+ return()
+ endif()
+
+ option(QT_SKIP_DOCKER_COMPOSE "Skip setting up docker on Linux." OFF)
+ if(QT_SKIP_DOCKER_COMPOSE)
+ return()
+ endif()
+
+ set(QT_TEST_SERVER_LIST ${ARGN})
+ set(DNSDOMAIN test-net.qt.local)
+
+ find_program(QT_DOCKER_COMPOSE docker-compose)
+ if (NOT QT_DOCKER_COMPOSE)
+ message(WARNING "docker-compose was not found. Docker network tests will not be run.")
+ return()
+ endif()
+ if (NOT DEFINED QT_DOCKER_COMPOSE_VERSION)
+ execute_process(COMMAND "${QT_DOCKER_COMPOSE}" --version OUTPUT_VARIABLE QT_DOCKER_COMPOSE_VERSION)
+ string(REPLACE "\n" "" QT_DOCKER_COMPOSE_VERSION "${QT_DOCKER_COMPOSE_VERSION}")
+ set(QT_DOCKER_COMPOSE_VERSION "${QT_DOCKER_COMPOSE_VERSION}" CACHE STRING "docker compose version")
+ endif()
+
+ find_program(QT_DOCKER docker)
+ if (NOT QT_DOCKER)
+ message(WARNING "docker was not found. Docker network tests will not be run.")
+ return()
+ endif()
+ if (NOT DEFINED QT_DOCKER_TEST_SERVER)
+ execute_process(COMMAND "${QT_DOCKER}" images -aq "qt-test-server-*" OUTPUT_VARIABLE QT_DOCKER_TEST_SERVER)
+ if (NOT QT_DOCKER_TEST_SERVER)
+ message(WARNING
+ "Docker image qt-test-server-* not found.\n"
+ "Run the provisioning script (coin/provisioning/.../testserver/docker_testserver.sh) in advance\n"
+ "Docker network tests will not be run.")
+ return()
+ endif()
+ set(QT_DOCKER_TEST_SERVER "ON" CACHE BOOL "docker qt-test-server-* present")
+ endif()
+
+ target_compile_definitions("${name}"
+ PRIVATE
+ QT_TEST_SERVER QT_TEST_SERVER_NAME QT_TEST_SERVER_DOMAIN=\"${DNSDOMAIN}\"
+ )
+
+ if(DEFINED QT_TESTSERVER_COMPOSE_FILE)
+ set(TESTSERVER_COMPOSE_FILE ${QT_TESTSERVER_COMPOSE_FILE})
+ elseif(QNX)
+ set(TESTSERVER_COMPOSE_FILE "${QT_SOURCE_TREE}/tests/testserver/docker-compose-qemu-bridge-network.yml")
+ else()
+ set(TESTSERVER_COMPOSE_FILE "${QT_SOURCE_TREE}/tests/testserver/docker-compose-bridge-network.yml")
+ endif()
+
+ # Bring up test servers and make sure the services are ready.
+ add_test(NAME ${name}-setup COMMAND
+ "${QT_DOCKER_COMPOSE}" -f ${TESTSERVER_COMPOSE_FILE} up --build -d --force-recreate --timeout 1 ${QT_TEST_SERVER_LIST}
+ )
+ # Stop and remove test servers after testing.
+ add_test(NAME ${name}-cleanup COMMAND
+ "${QT_DOCKER_COMPOSE}" -f ${TESTSERVER_COMPOSE_FILE} down --timeout 1
+ )
+
+ set_tests_properties(${name}-setup PROPERTIES FIXTURES_SETUP ${name}-docker)
+ set_tests_properties(${name}-cleanup PROPERTIES FIXTURES_CLEANUP ${name}-docker)
+ set_tests_properties(${name} PROPERTIES FIXTURES_REQUIRED ${name}-docker)
+
+ foreach(test_name ${name} ${name}-setup ${name}-cleanup)
+ set_property(TEST "${test_name}" APPEND PROPERTY ENVIRONMENT "testserver=${QT_DOCKER_COMPOSE_VERSION}")
+ set_property(TEST "${test_name}" APPEND PROPERTY ENVIRONMENT TEST_DOMAIN=${DNSDOMAIN})
+ set_property(TEST "${test_name}" APPEND PROPERTY ENVIRONMENT "SHARED_DATA=${QT_MKSPECS_DIR}/features/data/testserver")
+ set_property(TEST "${test_name}" APPEND PROPERTY ENVIRONMENT SHARED_SERVICE=bridge-network)
+ endforeach()
+
+endfunction()
+
+function(qt_internal_get_test_batch out)
+ get_property(batched_list GLOBAL PROPERTY _qt_batched_test_list_property)
+ set(${out} ${batched_list} PARENT_SCOPE)
+endfunction()
+
+function(qt_internal_prepare_test_target_flags version_arg exceptions_text gui_text)
+ cmake_parse_arguments(arg "EXCEPTIONS;NO_EXCEPTIONS;GUI" "VERSION" "" ${ARGN})
+
+ if (arg_VERSION)
+ set(${version_arg} VERSION "${arg_VERSION}" PARENT_SCOPE)
+ endif()
+
+ # Qt modules get compiled without exceptions enabled by default.
+ # However, testcases should be still built with exceptions.
+ set(${exceptions_text} "EXCEPTIONS" PARENT_SCOPE)
+ if (${arg_NO_EXCEPTIONS} OR WASM)
+ set(${exceptions_text} "" PARENT_SCOPE)
+ endif()
+
+ if (${arg_GUI})
+ set(${gui_text} "GUI" PARENT_SCOPE)
+ endif()
+endfunction()
+
+function(qt_internal_get_test_arg_definitions optional_args single_value_args multi_value_args)
+ set(${optional_args}
+ RUN_SERIAL
+ EXCEPTIONS
+ NO_EXCEPTIONS
+ GUI
+ QMLTEST
+ CATCH
+ LOWDPI
+ NO_WRAPPER
+ BUILTIN_TESTDATA
+ MANUAL
+ NO_BATCH
+ NO_INSTALL
+ BUNDLE_ANDROID_OPENSSL_LIBS
+ PARENT_SCOPE
+ )
+ set(${single_value_args}
+ OUTPUT_DIRECTORY
+ WORKING_DIRECTORY
+ TIMEOUT
+ VERSION
+ PARENT_SCOPE
+ )
+ set(${multi_value_args}
+ QML_IMPORTPATH
+ TESTDATA
+ QT_TEST_SERVER_LIST
+ ${__default_private_args}
+ ${__default_public_args}
+ PARENT_SCOPE
+ )
+endfunction()
+
+function(qt_internal_add_test_to_batch batch_name name)
+ qt_internal_get_test_arg_definitions(optional_args single_value_args multi_value_args)
+
+ cmake_parse_arguments(
+ arg "${optional_args}" "${single_value_args}" "${multi_value_args}" ${ARGN})
+ qt_internal_prepare_test_target_flags(version_arg exceptions_text gui_text ${ARGN})
+
+ _qt_internal_validate_no_unity_build(arg)
+
+ _qt_internal_test_batch_target_name(target)
+
+ # Lazy-init the test batch
+ if(NOT TARGET ${target})
+ qt_internal_library_deprecation_level(deprecation_define)
+ qt_internal_add_executable(${target}
+ ${exceptions_text}
+ ${gui_text}
+ ${version_arg}
+ NO_INSTALL
+ OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/build_dir"
+ SOURCES "${QT_CMAKE_DIR}/qbatchedtestrunner.in.cpp"
+ DEFINES QTEST_BATCH_TESTS ${deprecation_define}
+ INCLUDE_DIRECTORIES ${private_includes}
+ LIBRARIES ${QT_CMAKE_EXPORT_NAMESPACE}::Core
+ ${QT_CMAKE_EXPORT_NAMESPACE}::Test
+ ${QT_CMAKE_EXPORT_NAMESPACE}::TestPrivate
+ # Add GUI by default so that the plugins link properly with non-standalone
+ # build of tests. Plugin handling is currently only done in
+ # qt_internal_add_executable if Gui is present. This should be reevaluated with
+ # multiple batches.
+ ${QT_CMAKE_EXPORT_NAMESPACE}::Gui
+ )
+
+ set_property(TARGET ${target} PROPERTY _qt_has_exceptions ${arg_EXCEPTIONS})
+ set_property(TARGET ${target} PROPERTY _qt_has_gui ${arg_GUI})
+ set_property(TARGET ${target} PROPERTY _qt_has_lowdpi ${arg_LOWDPI})
+ set_property(TARGET ${target} PROPERTY _qt_version ${version_arg})
+ set_property(TARGET ${target} PROPERTY _qt_is_test_executable TRUE)
+ set_property(TARGET ${target} PROPERTY _qt_is_manual_test ${arg_MANUAL})
+ else()
+ # Check whether the args match with the batch. Some differences between
+ # flags cannot be reconciled - one should not combine these tests into
+ # a single binary.
+ qt_internal_get_target_property(
+ batch_has_exceptions ${target} _qt_has_exceptions)
+ if(NOT ${batch_has_exceptions} STREQUAL ${arg_EXCEPTIONS})
+ qt_internal_get_test_batch(test_batch_contents)
+ message(FATAL_ERROR "Conflicting exceptions declaration between test \
+ batch (${test_batch_contents}) and ${name}")
+ endif()
+ qt_internal_get_target_property(batch_has_gui ${target} _qt_has_gui)
+ if(NOT ${batch_has_gui} STREQUAL ${arg_GUI})
+ qt_internal_get_test_batch(test_batch_contents)
+ message(FATAL_ERROR "Conflicting gui declaration between test batch \
+ (${test_batch_contents}) and ${name}")
+ endif()
+ qt_internal_get_target_property(
+ batch_has_lowdpi ${target} _qt_has_lowdpi)
+ if(NOT ${batch_has_lowdpi} STREQUAL ${arg_LOWDPI})
+ qt_internal_get_test_batch(test_batch_contents)
+ message(FATAL_ERROR "Conflicting lowdpi declaration between test batch \
+ (${test_batch_contents}) and ${name}")
+ endif()
+ qt_internal_get_target_property(batch_version ${target} _qt_version)
+ if(NOT "${batch_version} " STREQUAL " " AND
+ NOT "${version_arg} " STREQUAL " " AND
+ NOT "${batch_version} " STREQUAL "${version_arg} ")
+ qt_internal_get_test_batch(test_batch_contents)
+ message(FATAL_ERROR "Conflicting version declaration between test \
+ batch ${test_batch_contents} (${batch_version}) and ${name} (${version_arg})")
+ endif()
+ endif()
+
+ get_property(batched_test_list GLOBAL PROPERTY _qt_batched_test_list_property)
+ if(NOT batched_test_list)
+ set_property(GLOBAL PROPERTY _qt_batched_test_list_property "")
+ set(batched_test_list "")
+ endif()
+ list(PREPEND batched_test_list ${name})
+ set_property(GLOBAL PROPERTY _qt_batched_test_list_property ${batched_test_list})
+
+ # Test batching produces single executable which can result in one source file being added
+ # multiple times (with different definitions) to one translation unit. This is not supported by
+ # CMake so instead we try to detect such situation and rename file every time it's added
+ # to the build more than once. This avoids filenames collisions in one translation unit.
+ get_property(batched_test_sources_list GLOBAL PROPERTY _qt_batched_test_sources_list_property)
+ if(NOT batched_test_sources_list)
+ set_property(GLOBAL PROPERTY _qt_batched_test_sources_list_property "")
+ set(batched_test_sources_list "")
+ endif()
+ foreach(source ${arg_SOURCES})
+ set(source_path ${source})
+ if(${source} IN_LIST batched_test_sources_list)
+ set(new_filename ${name}.cpp)
+ configure_file(${source} ${new_filename})
+ set(source_path ${CMAKE_CURRENT_BINARY_DIR}/${new_filename})
+ set(skip_automoc ON)
+ list(APPEND arg_SOURCES ${source_path})
+ else()
+ set(skip_automoc OFF)
+ list(APPEND batched_test_sources_list ${source})
+ endif()
+ set_source_files_properties(${source_path}
+ TARGET_DIRECTORY ${target} PROPERTIES
+ SKIP_AUTOMOC ${skip_automoc}
+ COMPILE_DEFINITIONS "BATCHED_TEST_NAME=\"${name}\";${arg_DEFINES}")
+ endforeach()
+ set_property(GLOBAL PROPERTY _qt_batched_test_sources_list_property ${batched_test_sources_list})
+
+ # Merge the current test with the rest of the batch
+ qt_internal_extend_target(${target}
+ INCLUDE_DIRECTORIES ${arg_INCLUDE_DIRECTORIES}
+ PUBLIC_LIBRARIES ${arg_PUBLIC_LIBRARIES}
+ LIBRARIES ${arg_LIBRARIES}
+ SOURCES ${arg_SOURCES}
+ COMPILE_OPTIONS ${arg_COMPILE_OPTIONS}
+ COMPILE_FLAGS ${arg_COMPILE_FLAGS}
+ LINK_OPTIONS ${arg_LINK_OPTIONS}
+ MOC_OPTIONS ${arg_MOC_OPTIONS}
+ ENABLE_AUTOGEN_TOOLS ${arg_ENABLE_AUTOGEN_TOOLS}
+ DISABLE_AUTOGEN_TOOLS ${arg_DISABLE_AUTOGEN_TOOLS}
+ NO_UNITY_BUILD # Tests should not be built using UNITY_BUILD
+ )
+
+ set(${batch_name} ${target} PARENT_SCOPE)
+
+ # Add a dummy target so that new tests don't have problems with a nonexistent
+ # target when calling cmake functions.
+ # The batch tests that include this target will compile, but may fail to work.
+ # Manual action is required then.
+ add_custom_target(${name})
+
+ # Add the dependency to the dummy target so that it is indirectly added to the test batch
+ # dependencies.
+ add_dependencies(${target} ${name})
+endfunction()
+
+# Checks whether the test 'name' is present in the test batch. See QT_BUILD_TESTS_BATCHED.
+# The result of the check is placed in the 'out' variable.
+function(qt_internal_is_in_test_batch out name)
+ set(${out} FALSE PARENT_SCOPE)
+ if(QT_BUILD_TESTS_BATCHED)
+ get_property(batched_test_list GLOBAL PROPERTY _qt_batched_test_list_property)
+ if("${name}" IN_LIST batched_test_list)
+ set(${out} TRUE PARENT_SCOPE)
+ endif()
+ endif()
+endfunction()
+
+function(qt_internal_is_skipped_test out name)
+ get_target_property(is_skipped_test ${name} _qt_is_skipped_test)
+ set(${out} ${is_skipped_test} PARENT_SCOPE)
+endfunction()
+
+function(qt_internal_set_skipped_test name)
+ set_target_properties(${name} PROPERTIES _qt_is_skipped_test TRUE)
+endfunction()
+
+function(qt_internal_is_qtbase_test out)
+ get_filename_component(dir "${CMAKE_CURRENT_BINARY_DIR}" ABSOLUTE)
+ set(${out} FALSE PARENT_SCOPE)
+
+ while(TRUE)
+ get_filename_component(filename "${dir}" NAME)
+ if("${filename}" STREQUAL "qtbase")
+ set(${out} TRUE PARENT_SCOPE)
+ break()
+ endif()
+
+ set(prev_dir "${dir}")
+ get_filename_component(dir "${dir}" DIRECTORY)
+ if("${dir}" STREQUAL "${prev_dir}")
+ break()
+ endif()
+ endwhile()
+endfunction()
+
+function(qt_internal_get_batched_test_arguments out testname)
+ if(WASM)
+ # Add a query string to the runner document, so that the script therein
+ # knows which test to run in response to launching the testcase by ctest.
+ list(APPEND args "qbatchedtest")
+ if(CMAKE_BUILD_TYPE STREQUAL "Debug")
+ list(APPEND args "qvisualoutput")
+ endif()
+ else()
+ # Simply add the test name in case of standard executables.
+ list(APPEND args "${testname}")
+ endif()
+ set(${out} ${args} PARENT_SCOPE)
+endfunction()
+
+# This function creates a CMake test target with the specified name for use with CTest.
+#
+# All tests are wrapped with cmake script that supports TESTARGS and TESTRUNNER environment
+# variables handling. Endpoint wrapper may be used standalone as cmake script to run tests e.g.:
+# TESTARGS="-o result.xml,junitxml" TESTRUNNER="testrunner --arg" ./tst_simpleTestWrapper.cmake
+# On non-UNIX machine you may need to use 'cmake -P' explicitly to execute wrapper.
+# You may avoid test wrapping by either passing NO_WRAPPER option or switching QT_NO_TEST_WRAPPERS
+# to ON. This is helpful if you want to use internal CMake tools within tests, like memory or
+# sanitizer checks. See https://cmake.org/cmake/help/v3.19/manual/ctest.1.html#ctest-memcheck-step
+# Arguments:
+# BUILTIN_TESTDATA
+# The option forces adding the provided TESTDATA to resources.
+# MANUAL
+# The option indicates that the test is a manual test.
+function(qt_internal_add_test name)
+ qt_internal_get_test_arg_definitions(optional_args single_value_args multi_value_args)
+
+ cmake_parse_arguments(PARSE_ARGV 1 arg
+ "${optional_args}"
+ "${single_value_args}"
+ "${multi_value_args}"
+ )
+ _qt_internal_validate_all_args_are_parsed(arg)
+ _qt_internal_validate_no_unity_build(arg)
+
+ set(batch_current_test FALSE)
+ if(QT_BUILD_TESTS_BATCHED AND NOT arg_NO_BATCH AND NOT arg_QMLTEST AND NOT arg_MANUAL
+ AND ("${QT_STANDALONE_TEST_PATH}" STREQUAL ""
+ OR DEFINED ENV{QT_BATCH_STANDALONE_TESTS}))
+ set(batch_current_test TRUE)
+ endif()
+
+ if(batch_current_test OR (QT_BUILD_TESTS_BATCHED AND arg_QMLTEST))
+ if (QT_SUPERBUILD OR DEFINED ENV{TESTED_MODULE_COIN})
+ set(is_qtbase_test FALSE)
+ if(QT_SUPERBUILD)
+ qt_internal_is_qtbase_test(is_qtbase_test)
+ elseif($ENV{TESTED_MODULE_COIN} STREQUAL "qtbase")
+ set(is_qtbase_test TRUE)
+ endif()
+ if(NOT is_qtbase_test)
+ file(GENERATE OUTPUT "dummy${name}.cpp" CONTENT "int main() { return 0; }")
+ # Add a dummy target to tackle some potential problems
+ qt_internal_add_executable(${name} SOURCES "dummy${name}.cpp")
+ # Batched tests outside of qtbase are unsupported and skipped
+ qt_internal_set_skipped_test(${name})
+ return()
+ endif()
+ endif()
+ endif()
+
+ if(NOT arg_OUTPUT_DIRECTORY)
+ if(CMAKE_RUNTIME_OUTPUT_DIRECTORY)
+ set(arg_OUTPUT_DIRECTORY "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}")
+ else()
+ set(arg_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}")
+ endif()
+ endif()
+
+ set(private_includes
+ "${CMAKE_CURRENT_SOURCE_DIR}"
+ "${CMAKE_CURRENT_BINARY_DIR}"
+ "$<BUILD_INTERFACE:${QT_BUILD_DIR}/include>"
+ )
+
+ set(testname "${name}")
+
+ if(arg_PUBLIC_LIBRARIES)
+ message(WARNING
+ "qt_internal_add_test's PUBLIC_LIBRARIES option is deprecated, and will be "
+ "removed in a future Qt version. Use the LIBRARIES option instead.")
+ endif()
+
+ if(batch_current_test)
+ qt_internal_add_test_to_batch(name ${name} ${ARGN})
+ elseif(arg_SOURCES)
+ if(QT_BUILD_TESTS_BATCHED AND arg_QMLTEST)
+ message(WARNING "QML tests won't be batched - unsupported (yet)")
+ endif()
+ # Handle cases where we have a qml test without source files
+ list(APPEND private_includes ${arg_INCLUDE_DIRECTORIES})
+
+ qt_internal_prepare_test_target_flags(version_arg exceptions_text gui_text ${ARGN})
+ qt_internal_library_deprecation_level(deprecation_define)
+
+ qt_internal_add_executable("${name}"
+ ${exceptions_text}
+ ${gui_text}
+ ${version_arg}
+ NO_INSTALL
+ OUTPUT_DIRECTORY "${arg_OUTPUT_DIRECTORY}"
+ SOURCES "${arg_SOURCES}"
+ INCLUDE_DIRECTORIES
+ ${private_includes}
+ DEFINES
+ ${arg_DEFINES}
+ ${deprecation_define}
+ LIBRARIES
+ ${arg_LIBRARIES}
+ ${arg_PUBLIC_LIBRARIES}
+ ${QT_CMAKE_EXPORT_NAMESPACE}::Core
+ ${QT_CMAKE_EXPORT_NAMESPACE}::Test
+ COMPILE_OPTIONS ${arg_COMPILE_OPTIONS}
+ LINK_OPTIONS ${arg_LINK_OPTIONS}
+ MOC_OPTIONS ${arg_MOC_OPTIONS}
+ ENABLE_AUTOGEN_TOOLS ${arg_ENABLE_AUTOGEN_TOOLS}
+ DISABLE_AUTOGEN_TOOLS ${arg_DISABLE_AUTOGEN_TOOLS}
+ NO_UNITY_BUILD # Tests should not be built using UNITY_BUILD
+ )
+
+ qt_internal_add_repo_local_defines(${name})
+
+ # Disable the QT_NO_NARROWING_CONVERSIONS_IN_CONNECT define for tests
+ qt_internal_undefine_global_definition(${name} QT_NO_NARROWING_CONVERSIONS_IN_CONNECT)
+
+ # Manual tests can be bundle apps
+ if(NOT arg_MANUAL)
+ # Tests should not be bundles on macOS even if arg_GUI is true, because some tests make
+ # assumptions about the location of helper processes, and those paths would be different
+ # if a test is built as a bundle.
+ set_property(TARGET "${name}" PROPERTY MACOSX_BUNDLE FALSE)
+ # The same goes for WIN32_EXECUTABLE, but because it will detach from the console window
+ # and not print anything.
+ set_property(TARGET "${name}" PROPERTY WIN32_EXECUTABLE FALSE)
+ endif()
+
+ # Tests on iOS must be app bundles.
+ if(IOS)
+ set_target_properties(${name} PROPERTIES MACOSX_BUNDLE TRUE)
+ endif()
+
+ # QMLTest specifics
+ qt_internal_extend_target("${name}" CONDITION arg_QMLTEST
+ LIBRARIES ${QT_CMAKE_EXPORT_NAMESPACE}::QuickTest
+ )
+
+ qt_internal_extend_target("${name}" CONDITION arg_QMLTEST AND NOT ANDROID
+ DEFINES
+ QUICK_TEST_SOURCE_DIR="${CMAKE_CURRENT_SOURCE_DIR}"
+ )
+
+ qt_internal_extend_target("${name}" CONDITION arg_QMLTEST AND ANDROID
+ DEFINES
+ QUICK_TEST_SOURCE_DIR=":/"
+ )
+
+ # Android requires Qt::Gui so add it by default for tests
+ qt_internal_extend_target("${name}" CONDITION ANDROID
+ LIBRARIES ${QT_CMAKE_EXPORT_NAMESPACE}::Gui
+ )
+ set_target_properties(${name} PROPERTIES _qt_is_test_executable TRUE)
+ set_target_properties(${name} PROPERTIES _qt_is_manual_test ${arg_MANUAL})
+
+ set(blacklist_file "${CMAKE_CURRENT_SOURCE_DIR}/BLACKLIST")
+ if(EXISTS ${blacklist_file})
+ _qt_internal_expose_source_file_to_ide("${name}" ${blacklist_file})
+ endif()
+ endif()
+
+ foreach(path IN LISTS arg_QML_IMPORTPATH)
+ list(APPEND extra_test_args "-import" "${path}")
+ endforeach()
+
+ # Generate a label in the form tests/auto/foo/bar/tst_baz
+ # and use it also for XML output
+ set(label_base_directory "${PROJECT_SOURCE_DIR}")
+ if (QT_SUPERBUILD)
+ # Prepend repository name for qt5 builds, so that tests can be run for
+ # individual repositories.
+ set(label_base_directory "${label_base_directory}/..")
+ endif()
+ file(RELATIVE_PATH label "${label_base_directory}" "${CMAKE_CURRENT_SOURCE_DIR}/${name}")
+
+ if (arg_LOWDPI)
+ target_compile_definitions("${name}" PUBLIC TESTCASE_LOWDPI)
+ if (MACOS)
+ set_property(TARGET "${name}" PROPERTY MACOSX_BUNDLE_INFO_PLIST "${QT_MKSPECS_DIR}/macx-clang/Info.plist.disable_highdpi")
+ set_property(TARGET "${name}" PROPERTY PROPERTY MACOSX_BUNDLE TRUE)
+ endif()
+ endif()
+
+ if (ANDROID)
+ # Pass 95% of the timeout to allow the test runner time to do any cleanup
+ # before being killed.
+ set(percentage "95")
+ qt_internal_get_android_test_timeout("${arg_TIMEOUT}" "${percentage}" android_timeout)
+
+ if(arg_BUNDLE_ANDROID_OPENSSL_LIBS)
+ if(EXISTS "${OPENSSL_ROOT_DIR}/${CMAKE_ANDROID_ARCH_ABI}/libcrypto_3.so")
+ message(STATUS "Looking for OpenSSL in ${OPENSSL_ROOT_DIR}")
+ set_property(TARGET ${name} APPEND PROPERTY QT_ANDROID_EXTRA_LIBS
+ "${OPENSSL_ROOT_DIR}/${CMAKE_ANDROID_ARCH_ABI}/libcrypto_3.so"
+ "${OPENSSL_ROOT_DIR}/${CMAKE_ANDROID_ARCH_ABI}/libssl_3.so")
+ elseif(QT_USE_VCPKG AND DEFINED ENV{VCPKG_ROOT})
+ message(STATUS "Looking for OpenSSL in $ENV{VCPKG_ROOT}")
+ if (CMAKE_ANDROID_ARCH_ABI MATCHES "arm64-v8a")
+ set(coin_vcpkg_target_triplet "arm64-android-dynamic")
+ elseif(CMAKE_ANDROID_ARCH_ABI MATCHES "armeabi-v7a")
+ set(coin_vcpkg_target_triplet "arm-neon-android-dynamic")
+ elseif(CMAKE_ANDROID_ARCH_ABI MATCHES "x86_64")
+ set(coin_vcpkg_target_triplet "x64-android-dynamic")
+ elseif(CMAKE_ANDROID_ARCH_ABI MATCHES "x86")
+ set(coin_vcpkg_target_triplet "x86-android-dynamic")
+ endif()
+ if(EXISTS "$ENV{VCPKG_ROOT}/installed/${coin_vcpkg_target_triplet}/lib/libcrypto.so")
+ message(STATUS "Found OpenSSL in $ENV{VCPKG_ROOT}/installed/${coin_vcpkg_target_triplet}/lib")
+ set_property(TARGET ${name} APPEND PROPERTY QT_ANDROID_EXTRA_LIBS
+ "$ENV{VCPKG_ROOT}/installed/${coin_vcpkg_target_triplet}/lib/libcrypto.so"
+ "$ENV{VCPKG_ROOT}/installed/${coin_vcpkg_target_triplet}/lib/libssl.so")
+ endif()
+ else()
+ message(STATUS "The argument BUNDLE_ANDROID_OPENSSL_LIBS is set "
+ "but OPENSSL_ROOT_DIR parameter is not set. "
+ "Test should bundle OpenSSL libraries but they are not found. "
+ "This is fine if OpenSSL was built statically.")
+ endif()
+ endif()
+ qt_internal_android_test_arguments(
+ "${name}" "${android_timeout}" test_executable extra_test_args)
+ set(test_working_dir "${CMAKE_CURRENT_BINARY_DIR}")
+ elseif(QNX)
+ set(test_working_dir "")
+ set(test_executable "${name}")
+ elseif(WASM)
+ # The test script expects an html file. In case of batched tests, the
+ # version specialized for running batches has to be supplied.
+ if(batch_current_test)
+ get_target_property(batch_output_dir ${name} RUNTIME_OUTPUT_DIRECTORY)
+ set(test_executable "${batch_output_dir}/${name}.html")
+ else()
+ set(test_executable "${name}.html")
+ endif()
+
+ list(APPEND extra_test_args "quseemrun")
+ list(APPEND extra_test_args "qtestname=${testname}")
+ list(APPEND extra_test_args "--silence_timeout=60")
+ # TODO: Add functionality to specify browser
+ list(APPEND extra_test_args "--browser=chrome")
+ list(APPEND extra_test_args "--browser_args=\"--password-store=basic\"")
+ list(APPEND extra_test_args "--kill_exit")
+
+ # Tests may require asyncify if they use exec(). Enable asyncify for
+ # batched tests since this is the configuration used on the CI system.
+ # Optimize for size (-Os), since asyncify tends to make the resulting
+ # binary very large
+ if(batch_current_test)
+ target_link_options("${name}" PRIVATE "SHELL:-s ASYNCIFY" "-Os")
+ endif()
+
+ # This tells cmake to run the tests with this script, since wasm files can't be
+ # executed directly
+ if (CMAKE_HOST_WIN32)
+ set_property(TARGET "${name}" PROPERTY CROSSCOMPILING_EMULATOR "emrun.bat")
+ else()
+ set_property(TARGET "${name}" PROPERTY CROSSCOMPILING_EMULATOR "emrun")
+ endif()
+ else()
+ if(arg_QMLTEST AND NOT arg_SOURCES)
+ set(test_working_dir "${CMAKE_CURRENT_SOURCE_DIR}")
+ set(test_executable ${QT_CMAKE_EXPORT_NAMESPACE}::qmltestrunner)
+ else()
+ if (arg_WORKING_DIRECTORY)
+ set(test_working_dir "${arg_WORKING_DIRECTORY}")
+ elseif(arg_OUTPUT_DIRECTORY)
+ set(test_working_dir "${arg_OUTPUT_DIRECTORY}")
+ else()
+ set(test_working_dir "${CMAKE_CURRENT_BINARY_DIR}")
+ endif()
+ set(test_executable "${name}")
+ endif()
+ endif()
+
+ if(NOT arg_MANUAL)
+ if(batch_current_test)
+ qt_internal_get_batched_test_arguments(batched_test_args ${testname})
+ list(PREPEND extra_test_args ${batched_test_args})
+ elseif(WASM AND CMAKE_BUILD_TYPE STREQUAL "Debug")
+ list(PREPEND extra_test_args "qvisualoutput")
+ endif()
+
+ qt_internal_collect_command_environment(test_env_path test_env_plugin_path)
+
+ if(arg_NO_WRAPPER OR QT_NO_TEST_WRAPPERS)
+ if(QT_BUILD_TESTS_BATCHED)
+ message(FATAL_ERROR "Wrapperless tests are unspupported with test batching")
+ endif()
+
+ add_test(NAME "${testname}" COMMAND ${test_executable} ${extra_test_args}
+ WORKING_DIRECTORY "${test_working_dir}")
+ set_property(TEST "${testname}" APPEND PROPERTY
+ ENVIRONMENT "PATH=${test_env_path}"
+ "QT_TEST_RUNNING_IN_CTEST=1"
+ "QT_PLUGIN_PATH=${test_env_plugin_path}"
+ )
+ else()
+ set(test_wrapper_file "${CMAKE_CURRENT_BINARY_DIR}/${testname}Wrapper$<CONFIG>.cmake")
+ qt_internal_create_test_script(NAME "${testname}"
+ COMMAND "${test_executable}"
+ ARGS "${extra_test_args}"
+ WORKING_DIRECTORY "${test_working_dir}"
+ OUTPUT_FILE "${test_wrapper_file}"
+ ENVIRONMENT "QT_TEST_RUNNING_IN_CTEST" 1
+ "PATH" "${test_env_path}"
+ "QT_PLUGIN_PATH" "${test_env_plugin_path}"
+ )
+ endif()
+
+ if(arg_QT_TEST_SERVER_LIST AND NOT ANDROID)
+ qt_internal_setup_docker_test_fixture(${testname} ${arg_QT_TEST_SERVER_LIST})
+ endif()
+
+ set_tests_properties("${testname}" PROPERTIES RUN_SERIAL "${arg_RUN_SERIAL}" LABELS "${label}")
+ if(arg_TIMEOUT)
+ set_tests_properties(${testname} PROPERTIES TIMEOUT ${arg_TIMEOUT})
+ endif()
+
+ if(ANDROID AND NOT CMAKE_HOST_SYSTEM_NAME STREQUAL "Windows")
+ # Set timeout signal and some time for androidtestrunner to do cleanup
+ set_tests_properties(${testname} PROPERTIES
+ TIMEOUT_SIGNAL_NAME "SIGINT"
+ TIMEOUT_SIGNAL_GRACE_PERIOD 10.0
+ )
+ endif()
+
+ # Add a ${target}/check makefile target, to more easily test one test.
+
+ set(test_config_options "")
+ get_cmake_property(is_multi_config GENERATOR_IS_MULTI_CONFIG)
+ if(is_multi_config)
+ set(test_config_options -C $<CONFIG>)
+ endif()
+ add_custom_target("${testname}_check"
+ VERBATIM
+ COMMENT "Running ${CMAKE_CTEST_COMMAND} -V -R \"^${name}$\" ${test_config_options}"
+ COMMAND "${CMAKE_CTEST_COMMAND}" -V -R "^${name}$" ${test_config_options}
+ )
+ if(TARGET "${name}")
+ add_dependencies("${testname}_check" "${name}")
+ if(ANDROID)
+ add_dependencies("${testname}_check" "${name}_make_apk")
+ endif()
+ endif()
+ endif()
+
+ if(ANDROID OR IOS OR WASM OR INTEGRITY OR arg_BUILTIN_TESTDATA)
+ set(builtin_testdata TRUE)
+ endif()
+
+ if(builtin_testdata)
+ # Safe guard against qml only tests, no source files == no target
+ if (TARGET "${name}")
+ target_compile_definitions("${name}" PRIVATE BUILTIN_TESTDATA)
+
+ foreach(testdata IN LISTS arg_TESTDATA)
+ list(APPEND builtin_files ${testdata})
+ endforeach()
+ foreach(file IN LISTS builtin_files)
+ set_source_files_properties(${file}
+ PROPERTIES QT_SKIP_QUICKCOMPILER TRUE
+ )
+ endforeach()
+
+ if(batch_current_test)
+ set(blacklist_path "BLACKLIST")
+ if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/${blacklist_path}")
+ get_target_property(blacklist_files ${name} _qt_blacklist_files)
+ if(NOT blacklist_files)
+ set_target_properties(${name} PROPERTIES _qt_blacklist_files "")
+ set(blacklist_files "")
+ cmake_language(EVAL CODE "cmake_language(DEFER DIRECTORY \"${CMAKE_SOURCE_DIR}\" CALL \"_qt_internal_finalize_batch\" \"${name}\") ")
+ endif()
+ list(PREPEND blacklist_files "${CMAKE_CURRENT_SOURCE_DIR}/${blacklist_path}")
+ set_target_properties(${name} PROPERTIES _qt_blacklist_files "${blacklist_files}")
+ endif()
+ else()
+ set(blacklist_path "BLACKLIST")
+ if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/${blacklist_path}")
+ list(APPEND builtin_files ${blacklist_path})
+ endif()
+ endif()
+
+ list(REMOVE_DUPLICATES builtin_files)
+
+ # Skip Qt quick compiler when embedding test resources
+ foreach(file IN LISTS builtin_files)
+ set_source_files_properties(${file}
+ PROPERTIES QT_SKIP_QUICKCOMPILER TRUE
+ )
+ endforeach()
+
+ if(builtin_files)
+ qt_internal_add_resource(${name} "${testname}_testdata_builtin"
+ PREFIX "/"
+ FILES ${builtin_files}
+ BASE ${CMAKE_CURRENT_SOURCE_DIR})
+ endif()
+ endif()
+ else()
+ # Install test data, when tests are built in-tree or as standalone tests, but not as a
+ # single standalone test, which is checked by the existence of the QT_TOP_LEVEL_SOURCE_DIR
+ # variable.
+ # TODO: Shouldn't we also handle the single standalone test case?
+ # TODO: Does installing even makes sense, given where QFINDTESTDATA looks for installed
+ # test data, and where we end up installing it? See QTBUG-117098.
+ if(QT_TOP_LEVEL_SOURCE_DIR)
+ foreach(testdata IN LISTS arg_TESTDATA)
+ set(testdata "${CMAKE_CURRENT_SOURCE_DIR}/${testdata}")
+
+ # Get the relative source dir for each test data entry, because it might contain a
+ # subdirectory.
+ file(RELATIVE_PATH relative_path_to_test_project
+ "${QT_TOP_LEVEL_SOURCE_DIR}"
+ "${testdata}")
+ get_filename_component(relative_path_to_test_project
+ "${relative_path_to_test_project}" DIRECTORY)
+
+ qt_path_join(testdata_install_dir ${QT_INSTALL_DIR}
+ "${relative_path_to_test_project}")
+
+ if (IS_DIRECTORY "${testdata}")
+ qt_install(
+ DIRECTORY "${testdata}"
+ DESTINATION "${testdata_install_dir}")
+ else()
+ qt_install(
+ FILES "${testdata}"
+ DESTINATION "${testdata_install_dir}")
+ endif()
+ endforeach()
+ endif()
+ endif()
+
+ qt_internal_add_test_finalizers("${name}")
+endfunction()
+
+# Given an optional test timeout value (specified via qt_internal_add_test's TIMEOUT option)
+# returns a percentage of the final timeout to be passed to the androidtestrunner executable.
+#
+# When the optional timeout is empty, default to cmake's defaults for getting the timeout.
+function(qt_internal_get_android_test_timeout input_timeout percentage output_timeout_var)
+ set(actual_timeout "${input_timeout}")
+ if(NOT actual_timeout)
+ # we have coin ci timeout set use that to avoid having the emulator killed
+ # so we can at least get some logs from the android test runner.
+ set(coin_timeout $ENV{COIN_COMMAND_OUTPUT_TIMEOUT})
+ if(coin_timeout)
+ set(actual_timeout "${coin_timeout}")
+ elseif(DART_TESTING_TIMEOUT)
+ # Related: https://gitlab.kitware.com/cmake/cmake/-/issues/20450
+ set(actual_timeout "${DART_TESTING_TIMEOUT}")
+ elseif(CTEST_TEST_TIMEOUT)
+ set(actual_timeout "${CTEST_TEST_TIMEOUT}")
+ else()
+ # Default DART_TESTING_TIMEOUT is 25 minutes, specified in seconds
+ # https://github.com/Kitware/CMake/blob/master/Modules/CTest.cmake#L167C16-L167C16
+ set(actual_timeout "1500")
+ endif()
+ endif()
+
+ math(EXPR calculated_timeout "${actual_timeout} * ${percentage} / 100")
+
+ set(${output_timeout_var} "${calculated_timeout}" PARENT_SCOPE)
+endfunction()
+
+# This function adds test with specified NAME and wraps given test COMMAND with standalone cmake
+# script.
+#
+# NAME must be compatible with add_test function, since it's propagated as is.
+# COMMAND might be either target or path to executable. When test is called either by ctest or
+# directly by 'cmake -P path/to/scriptWrapper.cmake', COMMAND will be executed in specified
+# WORKING_DIRECTORY with arguments specified in ARGS.
+#
+# See also _qt_internal_create_command_script for details.
+function(qt_internal_create_test_script)
+ #This style of parsing keeps ';' in ENVIRONMENT variables
+ cmake_parse_arguments(PARSE_ARGV 0 arg
+ ""
+ "NAME;COMMAND;OUTPUT_FILE;WORKING_DIRECTORY"
+ "ARGS;ENVIRONMENT;PRE_RUN;POST_RUN"
+ )
+
+ if(NOT arg_COMMAND)
+ message(FATAL_ERROR "qt_internal_create_test_script: Test COMMAND is not specified")
+ endif()
+
+ if(NOT arg_NAME)
+ message(FATAL_ERROR "qt_internal_create_test_script: Test NAME is not specified")
+ endif()
+
+ if(NOT arg_OUTPUT_FILE)
+ message(FATAL_ERROR "qt_internal_create_test_script: Test Wrapper OUTPUT_FILE\
+is not specified")
+ endif()
+
+ if(arg_PRE_RUN)
+ message(WARNING "qt_internal_create_test_script: PRE_RUN is not acceptable argument\
+for this function. Will be ignored")
+ endif()
+
+ if(arg_POST_RUN)
+ message(WARNING "qt_internal_create_test_script: POST_RUN is not acceptable argument\
+for this function. Will be ignored")
+ endif()
+
+ if(arg_ARGS)
+ set(command_args ${arg_ARGS})# Avoid "${arg_ARGS}" usage and let cmake expand string to
+ # semicolon-separated list
+ qt_internal_wrap_command_arguments(command_args)
+ endif()
+
+ if(TARGET ${arg_COMMAND})
+ set(executable_file "$<TARGET_FILE:${arg_COMMAND}>")
+ else()
+ set(executable_file "${arg_COMMAND}")
+ endif()
+
+ set(executable_name ${arg_NAME})
+ qt_internal_is_in_test_batch(is_in_batch ${executable_name})
+ if(is_in_batch)
+ _qt_internal_test_batch_target_name(executable_name)
+ endif()
+ add_test(NAME "${arg_NAME}" COMMAND "${CMAKE_COMMAND}" "-P" "${arg_OUTPUT_FILE}"
+ WORKING_DIRECTORY "${arg_WORKING_DIRECTORY}")
+
+ # If crosscompiling is enabled, we should avoid run cmake in emulator environment.
+ # Prepend emulator to test command in generated cmake script instead. Keep in mind that
+ # CROSSCOMPILING_EMULATOR don't check if actual cross compilation is configured,
+ # emulator is prepended independently.
+ set(crosscompiling_emulator "")
+ if(CMAKE_CROSSCOMPILING AND TARGET ${executable_name})
+ get_target_property(crosscompiling_emulator ${executable_name} CROSSCOMPILING_EMULATOR)
+ if(NOT crosscompiling_emulator)
+ set(crosscompiling_emulator "")
+ else()
+ qt_internal_wrap_command_arguments(crosscompiling_emulator)
+ endif()
+ endif()
+
+ _qt_internal_create_command_script(COMMAND "${crosscompiling_emulator} \${env_test_runner} \
+\"${executable_file}\" \${env_test_args} ${command_args}"
+ OUTPUT_FILE "${arg_OUTPUT_FILE}"
+ WORKING_DIRECTORY "${arg_WORKING_DIRECTORY}"
+ ENVIRONMENT ${arg_ENVIRONMENT}
+ PRE_RUN "separate_arguments(env_test_args NATIVE_COMMAND \
+\"\$ENV{TESTARGS}\")"
+ "separate_arguments(env_test_runner NATIVE_COMMAND \
+\"\$ENV{TESTRUNNER}\")"
+ )
+endfunction()
+
+
+
+# This function creates an executable for use as a helper program with tests. Some
+# tests launch separate programs to test certain input/output behavior.
+# Specify OVERRIDE_OUTPUT_DIRECTORY if you don't want to place the helper in the parent directory,
+# in which case you should specify OUTPUT_DIRECTORY "/foo/bar" manually.
+function(qt_internal_add_test_helper name)
+
+ set(qt_add_test_helper_optional_args
+ "OVERRIDE_OUTPUT_DIRECTORY"
+ )
+
+ cmake_parse_arguments(PARSE_ARGV 1 arg
+ "${qt_add_test_helper_optional_args};${__qt_internal_add_executable_optional_args}"
+ "${__qt_internal_add_executable_single_args}"
+ "${__qt_internal_add_executable_multi_args}"
+ )
+ _qt_internal_validate_all_args_are_parsed(arg)
+
+ qt_remove_args(forward_args
+ ARGS_TO_REMOVE
+ "${name}"
+ ${qt_add_test_helper_optional_args}
+ ALL_ARGS
+ ${qt_add_test_helper_optional_args}
+ ${__qt_internal_add_executable_optional_args}
+ ${__qt_internal_add_executable_single_args}
+ ${__qt_internal_add_executable_multi_args}
+ ARGS
+ ${ARGV}
+ )
+
+ set(extra_args_to_pass)
+ if(NOT arg_OVERRIDE_OUTPUT_DIRECTORY)
+ _qt_internal_test_batch_target_name(test_batch_target_name)
+ if(QT_BUILD_TESTS_BATCHED AND TARGET ${test_batch_target_name})
+ get_target_property(
+ test_batch_output_dir ${test_batch_target_name} RUNTIME_OUTPUT_DIRECTORY)
+ set(extra_args_to_pass OUTPUT_DIRECTORY "${test_batch_output_dir}")
+ else()
+ set(extra_args_to_pass OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/..")
+ endif()
+ endif()
+
+ qt_internal_add_executable("${name}" NO_INSTALL
+ NO_UNITY_BUILD # excluded by default
+ ${extra_args_to_pass} ${forward_args})
+
+ # Disable the QT_NO_NARROWING_CONVERSIONS_IN_CONNECT define for test helpers
+ qt_internal_undefine_global_definition(${name} QT_NO_NARROWING_CONVERSIONS_IN_CONNECT)
+
+endfunction()
+
+function(qt_internal_wrap_command_arguments argument_list)
+ list(TRANSFORM ${argument_list} REPLACE "^(.+)$" "[=[\\1]=]")
+ list(JOIN ${argument_list} " " ${argument_list})
+ set(${argument_list} "${${argument_list}}" PARENT_SCOPE)
+endfunction()
+
+function(qt_internal_collect_command_environment out_path out_plugin_path)
+ # Get path to <qt_relocatable_install_prefix>/bin, as well as CMAKE_INSTALL_PREFIX/bin, and
+ # combine them with the PATH environment variable.
+ # It's needed on Windows to find the shared libraries and plugins.
+ # qt_relocatable_install_prefix is dynamically computed from the location of where the Qt CMake
+ # package is found.
+ # The regular CMAKE_INSTALL_PREFIX can be different for example when building standalone tests.
+ # Any given CMAKE_INSTALL_PREFIX takes priority over qt_relocatable_install_prefix for the
+ # PATH environment variable.
+ set(install_prefixes "${CMAKE_INSTALL_PREFIX}")
+ if(QT_BUILD_INTERNALS_RELOCATABLE_INSTALL_PREFIX)
+ list(APPEND install_prefixes "${QT_BUILD_INTERNALS_RELOCATABLE_INSTALL_PREFIX}")
+ endif()
+
+ file(TO_NATIVE_PATH "${CMAKE_CURRENT_BINARY_DIR}" test_env_path)
+ foreach(install_prefix ${install_prefixes})
+ file(TO_NATIVE_PATH "${install_prefix}/${INSTALL_BINDIR}" install_prefix)
+ set(test_env_path "${test_env_path}${QT_PATH_SEPARATOR}${install_prefix}")
+ endforeach()
+ set(test_env_path "${test_env_path}${QT_PATH_SEPARATOR}$ENV{PATH}")
+ string(REPLACE ";" "\;" test_env_path "${test_env_path}")
+ set(${out_path} "${test_env_path}" PARENT_SCOPE)
+
+ # Add the install prefix to list of plugin paths when doing a prefix build
+ if(NOT QT_INSTALL_DIR)
+ foreach(install_prefix ${install_prefixes})
+ file(TO_NATIVE_PATH "${install_prefix}/${INSTALL_BINDIR}" install_prefix)
+ list(APPEND plugin_paths "${install_prefix}")
+ endforeach()
+ endif()
+
+ #TODO: Collect all paths from known repositories when performing a super
+ # build.
+ file(TO_NATIVE_PATH "${PROJECT_BINARY_DIR}/${INSTALL_PLUGINSDIR}" install_pluginsdir)
+ list(APPEND plugin_paths "${install_pluginsdir}")
+ list(JOIN plugin_paths "${QT_PATH_SEPARATOR}" plugin_paths_joined)
+ string(REPLACE ";" "\;" plugin_paths_joined "${plugin_paths_joined}")
+ set(${out_plugin_path} "${plugin_paths_joined}" PARENT_SCOPE)
+endfunction()
+
+function(qt_internal_add_test_finalizers target)
+ # It might not be safe to run all the finalizers of _qt_internal_finalize_executable
+ # within the context of a Qt build (not a user project) when targeting a host build.
+ # At least one issue is missing qmlimportscanner at configure time.
+ # For now, we limit it to iOS, where it was tested to work, an we know that host tools
+ # should already be built and available.
+ if(IOS)
+ qt_add_list_file_finalizer(_qt_internal_finalize_executable "${target}")
+ endif()
+endfunction()
diff --git a/cmake/QtToolHelpers.cmake b/cmake/QtToolHelpers.cmake
new file mode 100644
index 0000000000..7dd507c0ee
--- /dev/null
+++ b/cmake/QtToolHelpers.cmake
@@ -0,0 +1,769 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+# This function is used to define a "Qt tool", such as moc, uic or rcc.
+#
+# USER_FACING can be passed to mark the tool as a program that is supposed to be
+# started directly by users.
+#
+# We must pass this function a target name obtained from
+# qt_get_tool_target_name like this:
+# qt_get_tool_target_name(target_name my_tool)
+# qt_internal_add_tool(${target_name})
+#
+# Option Arguments:
+# INSTALL_VERSIONED_LINK
+# Prefix build only. On installation, create a versioned hard-link of the installed file.
+# E.g. create a link of "bin/qmake6" to "bin/qmake".
+# TRY_RUN
+# On Windows, it creates a helper batch script that tests whether the tool can be executed
+# successfully or not. If not, build halts and an error will be show, with tips on what
+# might be cause, and how to fix it. TRY_RUN is disabled when cross-compiling.
+# TRY_RUN_FLAGS
+# Command line flags that are going to be passed to the tool for testing its correctness.
+# If no flags were given, we default to `-v`.
+#
+# One-value Arguments:
+# EXTRA_CMAKE_FILES
+# List of additional CMake files that will be installed alongside the tool's exported CMake
+# files.
+# EXTRA_CMAKE_INCLUDES
+# List of files that will be included in the Qt6${module}Tools.cmake file.
+# Also see TOOLS_TARGET.
+# INSTALL_DIR
+# Takes a path, relative to the install prefix, like INSTALL_LIBEXECDIR.
+# If this argument is omitted, the default is INSTALL_BINDIR.
+# TOOLS_TARGET
+# Specifies the module this tool belongs to. The module's Qt6${module}Tools.cmake file
+# will then contain targets for this tool.
+# CORE_LIBRARY
+# The argument accepts 'Bootstrap' or 'None' values. If the argument value is set to
+# 'Bootstrap' the Qt::Bootstrap library is linked to the executable instead of Qt::Core.
+# The 'None' value points that core library is not necessary and avoids linking neither
+# Qt::Core or Qt::Bootstrap libraries. Otherwise the Qt::Core library will be publicly
+# linked to the executable target by default.
+function(qt_internal_add_tool target_name)
+ qt_tool_target_to_name(name ${target_name})
+ set(option_keywords
+ NO_INSTALL
+ USER_FACING
+ INSTALL_VERSIONED_LINK
+ EXCEPTIONS
+ NO_UNITY_BUILD
+ TRY_RUN)
+ set(one_value_keywords
+ TOOLS_TARGET
+ INSTALL_DIR
+ CORE_LIBRARY
+ TRY_RUN_FLAGS
+ ${__default_target_info_args})
+ set(multi_value_keywords
+ EXTRA_CMAKE_FILES
+ EXTRA_CMAKE_INCLUDES
+ PUBLIC_LIBRARIES
+ ${__default_private_args})
+
+ cmake_parse_arguments(PARSE_ARGV 1 arg
+ "${option_keywords}"
+ "${one_value_keywords}"
+ "${multi_value_keywords}")
+ _qt_internal_validate_all_args_are_parsed(arg)
+
+ qt_internal_find_tool(will_build_tools ${target_name} "${arg_TOOLS_TARGET}")
+
+ if(NOT will_build_tools)
+ return()
+ endif()
+
+ set(disable_autogen_tools "${arg_DISABLE_AUTOGEN_TOOLS}")
+ set(corelib "")
+ if(arg_CORE_LIBRARY STREQUAL "Bootstrap" OR arg_CORE_LIBRARY STREQUAL "None")
+ set(corelib CORE_LIBRARY ${arg_CORE_LIBRARY})
+ list(APPEND disable_autogen_tools "uic" "moc" "rcc")
+ endif()
+
+ set(exceptions "")
+ if(arg_EXCEPTIONS)
+ set(exceptions EXCEPTIONS)
+ endif()
+
+ set(install_dir "${INSTALL_BINDIR}")
+ if(arg_INSTALL_DIR)
+ set(install_dir "${arg_INSTALL_DIR}")
+ endif()
+
+ set(output_dir "${QT_BUILD_DIR}/${install_dir}")
+
+ if(arg_PUBLIC_LIBRARIES)
+ message(WARNING
+ "qt_internal_add_tool's PUBLIC_LIBRARIES option is deprecated, and will be "
+ "removed in a future Qt version. Use the LIBRARIES option instead.")
+ endif()
+
+ qt_internal_library_deprecation_level(deprecation_define)
+
+ if(arg_NO_UNITY_BUILD)
+ set(arg_NO_UNITY_BUILD "NO_UNITY_BUILD")
+ else()
+ set(arg_NO_UNITY_BUILD "")
+ endif()
+
+ qt_internal_add_executable("${target_name}"
+ OUTPUT_DIRECTORY "${output_dir}"
+ ${exceptions}
+ NO_INSTALL
+ ${arg_NO_UNITY_BUILD}
+ SOURCES ${arg_SOURCES}
+ NO_PCH_SOURCES ${arg_NO_PCH_SOURCES}
+ NO_UNITY_BUILD_SOURCES ${arg_NO_UNITY_BUILD_SOURCES}
+ INCLUDE_DIRECTORIES
+ ${arg_INCLUDE_DIRECTORIES}
+ DEFINES
+ ${arg_DEFINES}
+ ${deprecation_define}
+ ${corelib}
+ LIBRARIES
+ ${arg_LIBRARIES}
+ ${arg_PUBLIC_LIBRARIES}
+ Qt::PlatformToolInternal
+ COMPILE_OPTIONS ${arg_COMPILE_OPTIONS}
+ LINK_OPTIONS ${arg_LINK_OPTIONS}
+ MOC_OPTIONS ${arg_MOC_OPTIONS}
+ DISABLE_AUTOGEN_TOOLS ${disable_autogen_tools}
+ TARGET_VERSION ${arg_TARGET_VERSION}
+ TARGET_PRODUCT ${arg_TARGET_PRODUCT}
+ TARGET_DESCRIPTION ${arg_TARGET_DESCRIPTION}
+ TARGET_COMPANY ${arg_TARGET_COMPANY}
+ TARGET_COPYRIGHT ${arg_TARGET_COPYRIGHT}
+ # If you are putting anything after these, make sure that
+ # qt_set_target_info_properties knows how to process them
+ )
+ qt_internal_add_target_aliases("${target_name}")
+ _qt_internal_apply_strict_cpp("${target_name}")
+ qt_internal_adjust_main_config_runtime_output_dir("${target_name}" "${output_dir}")
+
+ if (WIN32)
+ _qt_internal_generate_longpath_win32_rc_file_and_manifest("${target_name}")
+ endif()
+
+ set_target_properties(${target_name} PROPERTIES
+ _qt_package_version "${PROJECT_VERSION}"
+ )
+ set_property(TARGET ${target_name}
+ APPEND PROPERTY
+ EXPORT_PROPERTIES "_qt_package_version")
+
+ if(CMAKE_VERSION VERSION_GREATER_EQUAL "3.19.0" AND QT_FEATURE_debug_and_release)
+ set_property(TARGET "${target_name}"
+ PROPERTY EXCLUDE_FROM_ALL "$<NOT:$<CONFIG:${QT_MULTI_CONFIG_FIRST_CONFIG}>>")
+ endif()
+
+ if (NOT target_name STREQUAL name)
+ set_target_properties(${target_name} PROPERTIES
+ OUTPUT_NAME ${name}
+ EXPORT_NAME ${name}
+ )
+ endif()
+
+ if(TARGET host_tools)
+ add_dependencies(host_tools "${target_name}")
+ if(arg_CORE_LIBRARY STREQUAL "Bootstrap")
+ add_dependencies(bootstrap_tools "${target_name}")
+ endif()
+ endif()
+
+ if(arg_EXTRA_CMAKE_FILES)
+ set_target_properties(${target_name} PROPERTIES
+ EXTRA_CMAKE_FILES "${arg_EXTRA_CMAKE_FILES}"
+ )
+ endif()
+
+ if(arg_EXTRA_CMAKE_INCLUDES)
+ set_target_properties(${target_name} PROPERTIES
+ EXTRA_CMAKE_INCLUDES "${arg_EXTRA_CMAKE_INCLUDES}"
+ )
+ endif()
+
+ if(arg_USER_FACING)
+ set_property(GLOBAL APPEND PROPERTY QT_USER_FACING_TOOL_TARGETS ${target_name})
+ endif()
+
+
+ if(NOT arg_NO_INSTALL AND arg_TOOLS_TARGET)
+ # Assign a tool to an export set, and mark the module to which the tool belongs.
+ qt_internal_append_known_modules_with_tools("${arg_TOOLS_TARGET}")
+
+ # Also append the tool to the module list.
+ qt_internal_append_known_module_tool("${arg_TOOLS_TARGET}" "${target_name}")
+
+ qt_get_cmake_configurations(cmake_configs)
+
+ set(install_initial_call_args
+ EXPORT "${INSTALL_CMAKE_NAMESPACE}${arg_TOOLS_TARGET}ToolsTargets")
+
+ foreach(cmake_config ${cmake_configs})
+ qt_get_install_target_default_args(
+ OUT_VAR install_targets_default_args
+ RUNTIME "${install_dir}"
+ CMAKE_CONFIG "${cmake_config}"
+ ALL_CMAKE_CONFIGS "${cmake_configs}")
+
+ # Make installation optional for targets that are not built by default in this config
+ if(QT_FEATURE_debug_and_release
+ AND NOT (cmake_config STREQUAL QT_MULTI_CONFIG_FIRST_CONFIG))
+ set(install_optional_arg OPTIONAL)
+ else()
+ unset(install_optional_arg)
+ endif()
+
+ qt_install(TARGETS "${target_name}"
+ ${install_initial_call_args}
+ ${install_optional_arg}
+ CONFIGURATIONS ${cmake_config}
+ ${install_targets_default_args})
+ unset(install_initial_call_args)
+ endforeach()
+
+ if(arg_INSTALL_VERSIONED_LINK)
+ qt_internal_install_versioned_link(WORKING_DIRECTORY "${install_dir}"
+ TARGETS "${target_name}")
+ endif()
+
+ qt_apply_rpaths(TARGET "${target_name}" INSTALL_PATH "${install_dir}" RELATIVE_RPATH)
+ qt_internal_apply_staging_prefix_build_rpath_workaround()
+ endif()
+
+ if(arg_TRY_RUN AND WIN32 AND NOT CMAKE_CROSSCOMPILING)
+ if(NOT arg_TRY_RUN_FLAGS)
+ set(arg_TRY_RUN_FLAGS "-v")
+ endif()
+ _qt_internal_add_try_run_post_build("${target_name}" "${arg_TRY_RUN_FLAGS}")
+ endif()
+
+ qt_enable_separate_debug_info(${target_name} "${install_dir}" QT_EXECUTABLE)
+ qt_internal_install_pdb_files(${target_name} "${install_dir}")
+endfunction()
+
+function(_qt_internal_add_try_run_post_build target try_run_flags)
+ qt_internal_get_upper_case_main_cmake_configuration(main_cmake_configuration)
+ get_target_property(target_out_dir ${target}
+ RUNTIME_OUTPUT_DIRECTORY_${main_cmake_configuration})
+ get_target_property(target_bin_dir ${target}
+ BINARY_DIR)
+
+ set(try_run_scripts_path "${target_bin_dir}/${target}_try_run.bat")
+ # The only reason -h is passed is because some of the tools, e.g., moc
+ # wait for an input without any arguments.
+
+ qt_configure_file(OUTPUT "${try_run_scripts_path}"
+ CONTENT "@echo off
+
+${target_out_dir}/${target}.exe ${try_run_flags} > nul 2>&1
+
+if \"%errorlevel%\" == \"-1073741515\" (
+echo
+echo '${target}' is built successfully, but some of the libraries
+echo necessary for running it are missing. If you are building Qt with
+echo 3rdparty libraries, make sure that you add their directory to the
+echo PATH environment variable.
+echo
+exit /b %errorlevel%
+)
+echo. > ${target_bin_dir}/${target}_try_run_passed"
+ )
+
+ add_custom_command(
+ OUTPUT
+ ${target_bin_dir}/${target}_try_run_passed
+ DEPENDS
+ ${target}
+ COMMAND
+ ${CMAKE_COMMAND} -E env QT_COMMAND_LINE_PARSER_NO_GUI_MESSAGE_BOXES=1
+ ${try_run_scripts_path}
+ COMMENT
+ "Testing ${target} by trying to run it."
+ VERBATIM
+ )
+
+ add_custom_target(${target}_try_run ALL
+ DEPENDS ${target_bin_dir}/${target}_try_run_passed)
+endfunction()
+
+function(qt_export_tools module_name)
+ # Bail out when not building tools.
+ if(NOT QT_WILL_BUILD_TOOLS)
+ return()
+ endif()
+
+ # If no tools were defined belonging to this module, don't create a config and targets file.
+ if(NOT "${module_name}" IN_LIST QT_KNOWN_MODULES_WITH_TOOLS)
+ return()
+ endif()
+
+ # The tools target name. For example: CoreTools
+ set(target "${module_name}Tools")
+
+ set(path_suffix "${INSTALL_CMAKE_NAMESPACE}${target}")
+ qt_path_join(config_build_dir ${QT_CONFIG_BUILD_DIR} ${path_suffix})
+ qt_path_join(config_install_dir ${QT_CONFIG_INSTALL_DIR} ${path_suffix})
+
+ # Add the extra cmake statements to make the tool targets global, so it doesn't matter where
+ # find_package is called.
+ # Also assemble a list of tool targets to expose in the config file for informational purposes.
+ set(extra_cmake_statements "")
+ set(tool_targets "")
+ set(tool_targets_non_prefixed "")
+
+ # List of package dependencies that need be find_package'd when using the Tools package.
+ set(package_deps "")
+
+ # Additional cmake files to install
+ set(extra_cmake_files "")
+ set(extra_cmake_includes "")
+
+ set(first_tool_package_version "")
+
+ foreach(tool_name ${QT_KNOWN_MODULE_${module_name}_TOOLS})
+ # Specific tools can have package dependencies.
+ # e.g. qtwaylandscanner depends on WaylandScanner (non-qt package).
+ get_target_property(extra_packages "${tool_name}" QT_EXTRA_PACKAGE_DEPENDENCIES)
+ if(extra_packages)
+ list(APPEND package_deps "${extra_packages}")
+ endif()
+
+ get_target_property(_extra_cmake_files "${tool_name}" EXTRA_CMAKE_FILES)
+ if (_extra_cmake_files)
+ foreach(cmake_file ${_extra_cmake_files})
+ file(COPY "${cmake_file}" DESTINATION "${config_build_dir}")
+ list(APPEND extra_cmake_files "${cmake_file}")
+ endforeach()
+ endif()
+
+ get_target_property(_extra_cmake_includes "${tool_name}" EXTRA_CMAKE_INCLUDES)
+ if(_extra_cmake_includes)
+ list(APPEND extra_cmake_includes "${_extra_cmake_includes}")
+ endif()
+
+ if (QT_WILL_RENAME_TOOL_TARGETS)
+ string(REGEX REPLACE "_native$" "" tool_name ${tool_name})
+ endif()
+ set(extra_cmake_statements "${extra_cmake_statements}
+if(NOT QT_NO_CREATE_TARGETS AND ${INSTALL_CMAKE_NAMESPACE}${target}_FOUND)
+ __qt_internal_promote_target_to_global(${INSTALL_CMAKE_NAMESPACE}::${tool_name})
+endif()
+")
+ list(APPEND tool_targets "${QT_CMAKE_EXPORT_NAMESPACE}::${tool_name}")
+ list(APPEND tool_targets_non_prefixed "${tool_name}")
+
+ if(NOT first_tool_package_version)
+ qt_internal_get_package_version_of_target("${tool_name}" tool_package_version)
+ if(tool_package_version)
+ set(first_tool_package_version "${tool_package_version}")
+ endif()
+ endif()
+ endforeach()
+
+ string(APPEND extra_cmake_statements
+"set(${QT_CMAKE_EXPORT_NAMESPACE}${module_name}Tools_TARGETS \"${tool_targets}\")")
+
+ # Extract package dependencies that were determined in QtPostProcess, but only if ${module_name}
+ # is an actual target.
+ # module_name can be a non-existent target, if the tool doesn't have an existing associated
+ # module, e.g. qtwaylandscanner.
+ if(TARGET "${module_name}")
+ get_target_property(module_package_deps "${module_name}" _qt_tools_package_deps)
+ if(module_package_deps)
+ list(APPEND package_deps "${module_package_deps}")
+ endif()
+ endif()
+
+ # Configure and install dependencies file for the ${module_name}Tools package.
+ configure_file(
+ "${QT_CMAKE_DIR}/QtModuleToolsDependencies.cmake.in"
+ "${config_build_dir}/${INSTALL_CMAKE_NAMESPACE}${target}Dependencies.cmake"
+ @ONLY
+ )
+
+ qt_install(FILES
+ "${config_build_dir}/${INSTALL_CMAKE_NAMESPACE}${target}Dependencies.cmake"
+ DESTINATION "${config_install_dir}"
+ COMPONENT Devel
+ )
+
+ if(extra_cmake_files)
+ qt_install(FILES
+ ${extra_cmake_files}
+ DESTINATION "${config_install_dir}"
+ COMPONENT Devel
+ )
+ endif()
+
+ # Configure and install the ${module_name}Tools package Config file.
+ qt_internal_get_min_new_policy_cmake_version(min_new_policy_version)
+ qt_internal_get_max_new_policy_cmake_version(max_new_policy_version)
+ configure_package_config_file(
+ "${QT_CMAKE_DIR}/QtModuleToolsConfig.cmake.in"
+ "${config_build_dir}/${INSTALL_CMAKE_NAMESPACE}${target}Config.cmake"
+ INSTALL_DESTINATION "${config_install_dir}"
+ )
+
+ # There might be Tools packages which don't have a corresponding real module_name target, like
+ # WaylandScannerTools.
+ # In that case we'll use the package version of the first tool that belongs to that package.
+ if(TARGET "${module_name}")
+ qt_internal_get_package_version_of_target("${module_name}" tools_package_version)
+ elseif(first_tool_package_version)
+ set(tools_package_version "${first_tool_package_version}")
+ else()
+ # This should never happen, because tools_package_version should always have at least some
+ # value. Issue an assertion message just in case the pre-condition ever changes.
+ set(tools_package_version "${PROJECT_VERSION}")
+ if(FEATURE_developer_build)
+ message(WARNING
+ "Could not determine package version of tools package ${module_name}. "
+ "Defaulting to project version ${PROJECT_VERSION}.")
+ endif()
+ endif()
+ message(TRACE
+ "Exporting tools package ${module_name}Tools with package version ${tools_package_version}"
+ "\n included targets: ${tool_targets_non_prefixed}")
+ write_basic_package_version_file(
+ "${config_build_dir}/${INSTALL_CMAKE_NAMESPACE}${target}ConfigVersionImpl.cmake"
+ VERSION "${tools_package_version}"
+ COMPATIBILITY AnyNewerVersion
+ ARCH_INDEPENDENT
+ )
+ qt_internal_write_qt_package_version_file(
+ "${INSTALL_CMAKE_NAMESPACE}${target}"
+ "${config_build_dir}/${INSTALL_CMAKE_NAMESPACE}${target}ConfigVersion.cmake"
+ )
+
+ qt_install(FILES
+ "${config_build_dir}/${INSTALL_CMAKE_NAMESPACE}${target}Config.cmake"
+ "${config_build_dir}/${INSTALL_CMAKE_NAMESPACE}${target}ConfigVersion.cmake"
+ "${config_build_dir}/${INSTALL_CMAKE_NAMESPACE}${target}ConfigVersionImpl.cmake"
+ DESTINATION "${config_install_dir}"
+ COMPONENT Devel
+ )
+
+ set(export_name "${INSTALL_CMAKE_NAMESPACE}${target}Targets")
+ qt_install(EXPORT "${export_name}"
+ NAMESPACE "${QT_CMAKE_EXPORT_NAMESPACE}::"
+ DESTINATION "${config_install_dir}")
+
+ qt_internal_export_additional_targets_file(
+ TARGETS ${QT_KNOWN_MODULE_${module_name}_TOOLS}
+ TARGET_EXPORT_NAMES ${tool_targets}
+ EXPORT_NAME_PREFIX ${INSTALL_CMAKE_NAMESPACE}${target}
+ CONFIG_INSTALL_DIR "${config_install_dir}")
+
+ # Create versionless targets file.
+ configure_file(
+ "${QT_CMAKE_DIR}/QtModuleToolsVersionlessTargets.cmake.in"
+ "${config_build_dir}/${INSTALL_CMAKE_NAMESPACE}${target}VersionlessTargets.cmake"
+ @ONLY
+ )
+
+ qt_install(FILES
+ "${config_build_dir}/${INSTALL_CMAKE_NAMESPACE}${target}VersionlessTargets.cmake"
+ DESTINATION "${config_install_dir}"
+ COMPONENT Devel
+ )
+endfunction()
+
+# Returns the target name for the tool with the given name.
+#
+# In most cases, the target name is the same as the tool name.
+# If the user specifies to build tools when cross-compiling, then the
+# suffix "_native" is appended.
+function(qt_get_tool_target_name out_var name)
+ if (QT_WILL_RENAME_TOOL_TARGETS)
+ set(${out_var} ${name}_native PARENT_SCOPE)
+ else()
+ set(${out_var} ${name} PARENT_SCOPE)
+ endif()
+endfunction()
+
+# Returns the tool name for a given tool target.
+# This is the inverse of qt_get_tool_target_name.
+function(qt_tool_target_to_name out_var target)
+ set(name ${target})
+ if (QT_WILL_RENAME_TOOL_TARGETS)
+ string(REGEX REPLACE "_native$" "" name ${target})
+ endif()
+ set(${out_var} ${name} PARENT_SCOPE)
+endfunction()
+
+# Sets QT_WILL_BUILD_TOOLS if tools will be built and QT_WILL_RENAME_TOOL_TARGETS
+# if those tools have replaced naming.
+function(qt_check_if_tools_will_be_built)
+ # By default, we build our own tools unless we're cross-building or QT_HOST_PATH is set.
+ set(need_target_rename FALSE)
+ set(require_find_tools FALSE)
+ if(CMAKE_CROSSCOMPILING)
+ set(will_build_tools FALSE)
+ if(QT_FORCE_BUILD_TOOLS)
+ set(will_build_tools TRUE)
+ set(need_target_rename TRUE)
+ endif()
+ set(require_find_tools TRUE)
+ else()
+ if(QT_HOST_PATH)
+ set(will_build_tools FALSE)
+ else()
+ set(will_build_tools TRUE)
+ endif()
+ if(QT_FORCE_FIND_TOOLS)
+ set(will_build_tools FALSE)
+ set(require_find_tools TRUE)
+ endif()
+ if(QT_FORCE_BUILD_TOOLS)
+ set(will_build_tools TRUE)
+ set(need_target_rename TRUE)
+ endif()
+ endif()
+
+ set_property(GLOBAL PROPERTY qt_require_find_tools "${require_find_tools}")
+
+ set(QT_WILL_BUILD_TOOLS ${will_build_tools} CACHE INTERNAL "Are tools going to be built" FORCE)
+ set(QT_WILL_RENAME_TOOL_TARGETS ${need_target_rename} CACHE INTERNAL
+ "Do tool targets need to be renamed" FORCE)
+endfunction()
+
+# Use this macro to exit a file or function scope unless we're building tools. This is supposed to
+# be called after qt_internal_add_tools() to avoid special-casing operations on imported targets.
+macro(qt_internal_return_unless_building_tools)
+ if(NOT QT_WILL_BUILD_TOOLS)
+ return()
+ endif()
+endmacro()
+
+# Equivalent of qmake's qtNomakeTools(directory1 directory2).
+# If QT_BUILD_TOOLS_BY_DEFAULT is true, then targets within the given directories will be excluded
+# from the default 'all' target, as well as from install phase. The private variable is checked by
+# qt_internal_add_executable.
+function(qt_exclude_tool_directories_from_default_target)
+ if(NOT QT_BUILD_TOOLS_BY_DEFAULT)
+ set(absolute_path_directories "")
+ foreach(directory ${ARGV})
+ list(APPEND absolute_path_directories "${CMAKE_CURRENT_SOURCE_DIR}/${directory}")
+ endforeach()
+ set(__qt_exclude_tool_directories "${absolute_path_directories}" PARENT_SCOPE)
+ endif()
+endfunction()
+
+function(qt_internal_find_tool out_var target_name tools_target)
+ qt_tool_target_to_name(name ${target_name})
+
+ # Handle case when a tool does not belong to a module and it can't be built either (like
+ # during a cross-compile).
+ if(NOT tools_target AND NOT QT_WILL_BUILD_TOOLS)
+ message(FATAL_ERROR "The tool \"${name}\" has not been assigned to a module via"
+ " TOOLS_TARGET (so it can't be found) and it can't be built"
+ " (QT_WILL_BUILD_TOOLS is ${QT_WILL_BUILD_TOOLS}).")
+ endif()
+
+ if(NOT CMAKE_CROSSCOMPILING)
+ if(QT_INTERNAL_FORCE_FIND_HOST_TOOLS_MODULE_LIST AND
+ NOT "${tools_target}" IN_LIST QT_INTERNAL_FORCE_FIND_HOST_TOOLS_MODULE_LIST)
+ message(STATUS "Tool '${full_name}' will be built from source.")
+ set(${out_var} "TRUE" PARENT_SCOPE)
+ return()
+ endif()
+ endif()
+
+ if(QT_WILL_RENAME_TOOL_TARGETS AND (name STREQUAL target_name))
+ message(FATAL_ERROR
+ "qt_internal_add_tool must be passed a target obtained from qt_get_tool_target_name.")
+ endif()
+
+ set(full_name "${QT_CMAKE_EXPORT_NAMESPACE}::${name}")
+ set(imported_tool_target_already_found FALSE)
+
+ # This condition can only be TRUE if a previous find_package(Qt6${tools_target}Tools)
+ # was already done. That can happen if QT_FORCE_FIND_TOOLS was ON or we're cross-compiling.
+ # In such a case, we need to exit early if we're not going to also build the tools.
+ if(TARGET ${full_name})
+ get_property(path TARGET ${full_name} PROPERTY LOCATION)
+ message(STATUS "Tool '${full_name}' was found at ${path}.")
+ set(imported_tool_target_already_found TRUE)
+ if(NOT QT_WILL_BUILD_TOOLS)
+ set(${out_var} "FALSE" PARENT_SCOPE)
+ return()
+ endif()
+ endif()
+
+ # We need to search for the host Tools package when doing a cross-build
+ # or when QT_FORCE_FIND_TOOLS is ON.
+ # As an optimiziation, we don't search for the package one more time if the target
+ # was already brought into scope from a previous find_package.
+ set(search_for_host_package FALSE)
+ if(NOT QT_WILL_BUILD_TOOLS OR QT_WILL_RENAME_TOOL_TARGETS)
+ set(search_for_host_package TRUE)
+ endif()
+ if(search_for_host_package AND NOT imported_tool_target_already_found)
+ set(tools_package_name "${INSTALL_CMAKE_NAMESPACE}${tools_target}Tools")
+ message(STATUS "Searching for tool '${full_name}' in package ${tools_package_name}.")
+
+ # Create the tool targets, even if QT_NO_CREATE_TARGETS is set.
+ # Otherwise targets like Qt6::moc are not available in a top-level cross-build.
+ set(BACKUP_QT_NO_CREATE_TARGETS ${QT_NO_CREATE_TARGETS})
+ set(QT_NO_CREATE_TARGETS OFF)
+
+ # When cross-compiling, we want to search for Tools packages in QT_HOST_PATH.
+ # To do that, we override CMAKE_PREFIX_PATH and CMAKE_FIND_ROOT_PATH.
+ #
+ # We don't use find_package + PATHS option because any recursive find_dependency call
+ # inside a Tools package would not inherit the initial PATHS value given.
+ # TODO: Potentially we could set a global __qt_cmake_host_dir var like we currently
+ # do with _qt_cmake_dir in Qt6Config and change all our host tool find_package calls
+ # everywhere to specify that var in PATHS.
+ #
+ # Note though that due to path rerooting issue in
+ # https://gitlab.kitware.com/cmake/cmake/-/issues/21937
+ # we have to append a lib/cmake suffix to CMAKE_PREFIX_PATH so the value does not get
+ # rerooted on top of CMAKE_FIND_ROOT_PATH.
+ # Use QT_HOST_PATH_CMAKE_DIR for the suffix when available (it would be set by
+ # the qt.toolchain.cmake file when building other repos or given by the user when
+ # configuring qtbase) or derive it from from the Qt6HostInfo package which is
+ # found in QtSetup.
+ set(${tools_package_name}_BACKUP_CMAKE_PREFIX_PATH ${CMAKE_PREFIX_PATH})
+ set(${tools_package_name}_BACKUP_CMAKE_FIND_ROOT_PATH "${CMAKE_FIND_ROOT_PATH}")
+ if(QT_HOST_PATH_CMAKE_DIR)
+ set(qt_host_path_cmake_dir_absolute "${QT_HOST_PATH_CMAKE_DIR}")
+ elseif(Qt${PROJECT_VERSION_MAJOR}HostInfo_DIR)
+ get_filename_component(qt_host_path_cmake_dir_absolute
+ "${Qt${PROJECT_VERSION_MAJOR}HostInfo_DIR}/.." ABSOLUTE)
+ else()
+ # This should never happen, serves as an assert.
+ message(FATAL_ERROR
+ "Neither QT_HOST_PATH_CMAKE_DIR nor "
+ "Qt${PROJECT_VERSION_MAJOR}HostInfo_DIR available.")
+ endif()
+ set(CMAKE_PREFIX_PATH "${qt_host_path_cmake_dir_absolute}")
+
+ # Look for tools in additional host Qt installations. This is done for conan support where
+ # we have separate installation prefixes per package. For simplicity, we assume here that
+ # all host Qt installations use the same value of INSTALL_LIBDIR.
+ if(DEFINED QT_ADDITIONAL_HOST_PACKAGES_PREFIX_PATH)
+ file(RELATIVE_PATH rel_host_cmake_dir "${QT_HOST_PATH}"
+ "${qt_host_path_cmake_dir_absolute}")
+ foreach(host_path IN LISTS QT_ADDITIONAL_HOST_PACKAGES_PREFIX_PATH)
+ set(host_cmake_dir "${host_path}/${rel_host_cmake_dir}")
+ list(PREPEND CMAKE_PREFIX_PATH "${host_cmake_dir}")
+ endforeach()
+
+ list(PREPEND CMAKE_FIND_ROOT_PATH "${QT_ADDITIONAL_HOST_PACKAGES_PREFIX_PATH}")
+ endif()
+ list(PREPEND CMAKE_FIND_ROOT_PATH "${QT_HOST_PATH}")
+
+ find_package(
+ ${tools_package_name}
+ ${PROJECT_VERSION}
+ NO_PACKAGE_ROOT_PATH
+ NO_CMAKE_ENVIRONMENT_PATH
+ NO_SYSTEM_ENVIRONMENT_PATH
+ NO_CMAKE_PACKAGE_REGISTRY
+ NO_CMAKE_SYSTEM_PATH
+ NO_CMAKE_SYSTEM_PACKAGE_REGISTRY)
+
+ # Restore backups.
+ set(CMAKE_FIND_ROOT_PATH "${${tools_package_name}_BACKUP_CMAKE_FIND_ROOT_PATH}")
+ set(CMAKE_PREFIX_PATH "${${tools_package_name}_BACKUP_CMAKE_PREFIX_PATH}")
+ set(QT_NO_CREATE_TARGETS ${BACKUP_QT_NO_CREATE_TARGETS})
+
+ if(${${tools_package_name}_FOUND} AND TARGET ${full_name})
+ # Even if the tool is already visible, make sure that our modules remain associated
+ # with the tools.
+ qt_internal_append_known_modules_with_tools("${tools_target}")
+ get_property(path TARGET ${full_name} PROPERTY LOCATION)
+ message(STATUS "${full_name} was found at ${path} using package ${tools_package_name}.")
+ if (NOT QT_FORCE_BUILD_TOOLS)
+ set(${out_var} "FALSE" PARENT_SCOPE)
+ return()
+ endif()
+ endif()
+ endif()
+
+ get_property(require_find_tools GLOBAL PROPERTY qt_require_find_tools)
+ if(require_find_tools AND NOT TARGET ${full_name})
+ if(${${tools_package_name}_FOUND})
+ set(pkg_found_msg "")
+ string(APPEND pkg_found_msg
+ "the ${tools_package_name} package, but the package did not contain the tool. "
+ "Make sure that the host module ${tools_target} was built with all features "
+ "enabled (no explicitly disabled tools).")
+ else()
+ set(pkg_found_msg "")
+ string(APPEND pkg_found_msg
+ "the ${tools_package_name} package, but the package could not be found. "
+ "Make sure you have built and installed the host ${tools_target} module, "
+ "which will ensure the creation of the ${tools_package_name} package.")
+ endif()
+ message(FATAL_ERROR
+ "Failed to find the host tool \"${full_name}\". It is part of "
+ ${pkg_found_msg})
+ endif()
+
+ if(QT_WILL_BUILD_TOOLS)
+ message(STATUS "Tool '${full_name}' will be built from source.")
+ endif()
+ set(${out_var} "TRUE" PARENT_SCOPE)
+endfunction()
+
+# This function adds an internal tool that should be compiled at configure time.
+# TOOLS_TARGET
+# Specifies the module this tool belongs to. The Qt6${TOOLS_TARGET}Tools module
+# will then expose targets for this tool. Ignored if NO_INSTALL is set.
+function(qt_internal_add_configure_time_tool target_name)
+ set(one_value_args INSTALL_DIRECTORY TOOLS_TARGET CONFIG)
+ set(multi_value_args)
+ set(option_args NO_INSTALL)
+ cmake_parse_arguments(PARSE_ARGV 1 arg
+ "${option_args}" "${one_value_args}" "${multi_value_args}")
+
+ qt_internal_find_tool(will_build_tools ${target_name} "${arg_TOOLS_TARGET}")
+ if(NOT will_build_tools)
+ return()
+ endif()
+
+ qt_tool_target_to_name(name ${target_name})
+ set(extra_args "")
+ if(arg_NO_INSTALL OR NOT arg_TOOLS_TARGET)
+ list(APPEND extra_args "NO_INSTALL")
+ else()
+ set(install_dir "${INSTALL_BINDIR}")
+ if(arg_INSTALL_DIRECTORY)
+ set(install_dir "${arg_INSTALL_DIRECTORY}")
+ endif()
+ set(extra_args "INSTALL_DIRECTORY" "${install_dir}")
+ endif()
+
+ if(arg_CONFIG)
+ set(tool_config "${arg_CONFIG}")
+ elseif(QT_MULTI_CONFIG_FIRST_CONFIG)
+ set(tool_config "${arg_QT_MULTI_CONFIG_FIRST_CONFIG}")
+ else()
+ set(tool_config "${CMAKE_BUILD_TYPE}")
+ endif()
+
+ string(REPLACE "\\\;" "\\\\\\\;" unparsed_arguments "${arg_UNPARSED_ARGUMENTS}")
+ qt_internal_add_configure_time_executable(${target_name}
+ OUTPUT_NAME ${name}
+ CONFIG ${tool_config}
+ ${extra_args}
+ ${unparsed_arguments}
+ )
+
+ if(TARGET host_tools)
+ add_dependencies(host_tools "${target_name}_build")
+ endif()
+
+ if(NOT arg_NO_INSTALL AND arg_TOOLS_TARGET)
+ qt_internal_add_targets_to_additional_targets_export_file(
+ TARGETS ${target_name}
+ TARGET_EXPORT_NAMES ${QT_CMAKE_EXPORT_NAMESPACE}::${name}
+ EXPORT_NAME_PREFIX ${INSTALL_CMAKE_NAMESPACE}${arg_TOOLS_TARGET}Tools
+ )
+ endif()
+endfunction()
diff --git a/cmake/QtToolchainHelpers.cmake b/cmake/QtToolchainHelpers.cmake
new file mode 100644
index 0000000000..26b44bb10c
--- /dev/null
+++ b/cmake/QtToolchainHelpers.cmake
@@ -0,0 +1,310 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+# Create a CMake toolchain file for convenient configuration of both internal Qt builds
+# as well as CMake application projects.
+# Expects various global variables to be set.
+function(qt_internal_create_toolchain_file)
+ if(CMAKE_TOOLCHAIN_FILE)
+ file(TO_CMAKE_PATH "${CMAKE_TOOLCHAIN_FILE}" __qt_chainload_toolchain_file)
+ set(init_original_toolchain_file
+ "
+set(__qt_initially_configured_toolchain_file \"${__qt_chainload_toolchain_file}\")
+set(__qt_chainload_toolchain_file \"\${__qt_initially_configured_toolchain_file}\")
+")
+ endif()
+
+ if(VCPKG_CHAINLOAD_TOOLCHAIN_FILE)
+ file(TO_CMAKE_PATH "${VCPKG_CHAINLOAD_TOOLCHAIN_FILE}" VCPKG_CHAINLOAD_TOOLCHAIN_FILE)
+ list(APPEND init_vcpkg
+ "set(VCPKG_CHAINLOAD_TOOLCHAIN_FILE \"${VCPKG_CHAINLOAD_TOOLCHAIN_FILE}\")")
+ endif()
+
+ if(VCPKG_TARGET_TRIPLET)
+ list(APPEND init_vcpkg
+ "set(VCPKG_TARGET_TRIPLET \"${VCPKG_TARGET_TRIPLET}\" CACHE STRING \"\")")
+ endif()
+
+ if(CMAKE_SYSTEM_NAME STREQUAL "Windows" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "arm64" AND CMAKE_SYSTEM_VERSION STREQUAL "10")
+ list(APPEND init_platform "set(CMAKE_SYSTEM_NAME Windows CACHE STRING \"\")")
+ list(APPEND init_platform "set(CMAKE_SYSTEM_VERSION 10 CACHE STRING \"\")")
+ list(APPEND init_platform "set(CMAKE_SYSTEM_PROCESSOR arm64 CACHE STRING \"\")")
+ endif()
+
+ if(QT_QMAKE_TARGET_MKSPEC)
+ list(APPEND init_platform
+ "if(NOT QT_QMAKE_TARGET_MKSPEC)"
+ " set(QT_QMAKE_TARGET_MKSPEC ${QT_QMAKE_TARGET_MKSPEC} CACHE STRING \"\")"
+ "endif()"
+ )
+ endif()
+
+ if("${QT_QMAKE_TARGET_MKSPEC}" STREQUAL "linux-g++-32" AND NOT QT_NO_AUTO_DETECT_LINUX_X86)
+ set(__qt_toolchain_common_flags_init "-m32")
+
+ if(NOT QT_NO_OVERRIDE_LANG_FLAGS_INIT)
+ list(APPEND init_platform
+ "if(NOT QT_NO_OVERRIDE_LANG_FLAGS_INIT)")
+
+ list(APPEND init_platform
+ " set(__qt_toolchain_common_flags_init \"-m32\")")
+ list(APPEND init_platform
+ " set(CMAKE_C_FLAGS_INIT \"\${__qt_toolchain_common_flags_init}\")")
+ list(APPEND init_platform
+ " set(CMAKE_CXX_FLAGS_INIT \"\${__qt_toolchain_common_flags_init}\")")
+ list(APPEND init_platform
+ " set(CMAKE_ASM_FLAGS_INIT \"\${__qt_toolchain_common_flags_init}\")")
+
+ list(APPEND init_platform "endif()")
+ endif()
+
+ # Ubuntu-specific paths are used below.
+ # See comments of qt_auto_detect_linux_x86() for details.
+ if(NOT QT_NO_OVERRIDE_CMAKE_IGNORE_PATH)
+ list(APPEND init_platform
+ "if(NOT QT_NO_OVERRIDE_CMAKE_IGNORE_PATH)")
+
+ get_property(linux_x86_ignore_path GLOBAL PROPERTY _qt_internal_linux_x86_ignore_path)
+
+ string(REPLACE ";" "LITERAL_SEMICOLON"
+ linux_x86_ignore_path "${linux_x86_ignore_path}")
+
+ list(APPEND init_platform
+ " set(CMAKE_IGNORE_PATH \"${linux_x86_ignore_path}\")")
+
+ list(APPEND init_platform "endif()")
+ endif()
+
+ if(NOT QT_NO_OVERRIDE_PKG_CONFIG_LIBDIR)
+ list(APPEND init_platform
+ "if(NOT QT_NO_OVERRIDE_PKG_CONFIG_LIBDIR)")
+
+ get_property(pc_config_libdir GLOBAL PROPERTY _qt_internal_linux_x86_pc_config_libdir)
+
+ list(APPEND init_platform
+ " set(ENV{PKG_CONFIG_LIBDIR} \"${pc_config_libdir}\")")
+ list(APPEND init_platform
+ " set(ENV{PKG_CONFIG_DIR} \"\")")
+
+ list(APPEND init_platform "endif()")
+ endif()
+ endif()
+
+ # By default we don't want to allow mixing compilers for building different repositories, so we
+ # embed the initially chosen compilers into the toolchain.
+ # This is because on Windows compilers aren't easily mixed.
+ # We want to avoid that qtbase is built using cl.exe for example, and then for another repo
+ # gcc is picked up from %PATH%.
+ # The same goes when using a custom compiler on other platforms, such as ICC.
+ #
+ # There are a few exceptions though.
+ #
+ # When crosscompiling using Boot2Qt, the environment setup shell script sets up the CXX env var,
+ # which is used by CMake to determine the initial compiler that should be used.
+ # Unfortunately, the CXX env var contains not only the compiler name, but also a few required
+ # arch-specific compiler flags. This means that when building qtsvg, if the Qt created toolchain
+ # file sets the CMAKE_CXX_COMPILER variable, the CXX env var is ignored and thus the extra
+ # arch specific compiler flags are not picked up anymore, leading to a configuration failure.
+ #
+ # To avoid this issue, disable automatic embedding of the compilers into the qt toolchain when
+ # cross compiling. This is merely a heuristic, becacuse we don't have enough data to decide
+ # when to do it or not.
+ # For example on Linux one might want to allow mixing of clang and gcc (maybe).
+ #
+ # To allow such use cases when the default is wrong, one can provide a flag to explicitly opt-in
+ # or opt-out of the compiler embedding into the Qt toolchain.
+ #
+ # Passing -DQT_EMBED_TOOLCHAIN_COMPILER=ON will force embedding of the compilers.
+ # Passing -DQT_EMBED_TOOLCHAIN_COMPILER=OFF will disable embedding of the compilers.
+ set(__qt_embed_toolchain_compilers TRUE)
+ if(CMAKE_CROSSCOMPILING)
+ set(__qt_embed_toolchain_compilers FALSE)
+ endif()
+ if(DEFINED QT_EMBED_TOOLCHAIN_COMPILER)
+ if(QT_EMBED_TOOLCHAIN_COMPILER)
+ set(__qt_embed_toolchain_compilers TRUE)
+ else()
+ set(__qt_embed_toolchain_compilers FALSE)
+ endif()
+ endif()
+ if(__qt_embed_toolchain_compilers)
+ list(APPEND init_platform "
+set(__qt_initial_c_compiler \"${CMAKE_C_COMPILER}\")
+set(__qt_initial_cxx_compiler \"${CMAKE_CXX_COMPILER}\")
+if(QT_USE_ORIGINAL_COMPILER AND NOT DEFINED CMAKE_C_COMPILER
+ AND EXISTS \"\${__qt_initial_c_compiler}\")
+ set(CMAKE_C_COMPILER \"\${__qt_initial_c_compiler}\" CACHE STRING \"\")
+endif()
+if(QT_USE_ORIGINAL_COMPILER AND NOT DEFINED CMAKE_CXX_COMPILER
+ AND EXISTS \"\${__qt_initial_cxx_compiler}\")
+ set(CMAKE_CXX_COMPILER \"\${__qt_initial_cxx_compiler}\" CACHE STRING \"\")
+endif()")
+ endif()
+
+ unset(init_additional_used_variables)
+ if(APPLE)
+
+ # For an iOS simulator_and_device build, we should not explicitly set the sysroot,
+ # but let CMake do it's universal build magic to use one sysroot / sdk per-arch.
+ # For a single arch / sysroot build, try to use the initially configured sysroot
+ # by name.
+ #
+ # Also allow to opt out just in case.
+ #
+ # TODO: Figure out if the same should apply to universal macOS builds.
+
+ # We want to preserve the sysroot as an SDK name, instead of the path
+ # that CMake transforms it into in Darwin-initialize.cmake, so we pick
+ # it out from the cache, where it hasn't been touched by CMake.
+ set(cmake_sysroot_name "$CACHE{CMAKE_OSX_SYSROOT}")
+
+ list(LENGTH CMAKE_OSX_ARCHITECTURES _qt_osx_architectures_count)
+ if(cmake_sysroot_name AND NOT _qt_osx_architectures_count GREATER 1 AND UIKIT)
+ list(APPEND init_platform "
+if(NOT DEFINED CMAKE_OSX_SYSROOT)
+ set(CMAKE_OSX_SYSROOT \"${cmake_sysroot_name}\" CACHE STRING \"\")
+endif()")
+ endif()
+
+ if(CMAKE_OSX_DEPLOYMENT_TARGET)
+ list(APPEND init_platform
+ "set(CMAKE_OSX_DEPLOYMENT_TARGET \"${CMAKE_OSX_DEPLOYMENT_TARGET}\" CACHE STRING \"\")")
+ endif()
+
+ # Save list of initial architectures Qt was configured with.
+ set(_qt_osx_architectures_escaped "${CMAKE_OSX_ARCHITECTURES}")
+ string(REPLACE ";" "LITERAL_SEMICOLON"
+ _qt_osx_architectures_escaped "${_qt_osx_architectures_escaped}")
+ set(docstring "List of architectures Qt was built with")
+ list(APPEND init_platform
+ "set(QT_OSX_ARCHITECTURES \"${_qt_osx_architectures_escaped}\" CACHE STRING \"${docstring}\")")
+ list(APPEND init_platform "")
+
+ # When building another qt repo, ensure the same list of architectures is used by default.
+ # Detection of a qt repo is done by checking for QT_REPO_MODULE_VERSION which is set in
+ # the repo's .cmake.conf file.
+ # Most standalone tests will also be built with multiple architectures.
+ # Certain tests will be built with a single arch only (like tests/auto/cmake) to avoid
+ # issues in the CI when trying to build them on VMs that do not have a universal macOS
+ # SDK.
+ list(APPEND init_platform
+ "# Only build multiple architectures when building Qt itself. Can be explicitly enabled or disabled.")
+ list(APPEND init_platform "if((QT_REPO_MODULE_VERSION AND NOT QT_FORCE_SINGLE_QT_OSX_ARCHITECTURE) OR QT_FORCE_ALL_QT_OSX_ARCHITECTURES)")
+ list(APPEND init_platform " set(__qt_toolchain_building_qt_repo TRUE)")
+ list(APPEND init_platform " set(CMAKE_OSX_ARCHITECTURES \"\${QT_OSX_ARCHITECTURES}\" CACHE STRING \"\")")
+ list(APPEND init_platform "endif()")
+ list(APPEND init_platform "")
+
+ # For macOS user projects, default to not specifying any architecture. This means CMake will
+ # not pass an -arch flag to the compiler and the compiler will choose the default
+ # architecture to build for.
+ # On Apple Silicon, CMake will introspect whether it's running under Rosetta and will
+ # pass the detected architecture (x86_64 under Rosetta or arm64 natively) to the compiler.
+ # This is line with default CMake behavior for user projects.
+ #
+ # For iOS, we provide a bit more convenience.
+ # When the user project is built using the Xcode generator, we only specify the architecture
+ # if this is a single architecture Qt for iOS build. If we wouldn't, invoking just
+ # xcodebuild from the command line would try to build with the wrong architecture. Also
+ # provide an opt-out option just in case.
+ #
+ # For a multi-architecture build (so simulator_and_device) we set an explicit
+ # architecture for simulator only, via _qt_internal_set_ios_simulator_arch.
+ #
+ # When using the Ninja generator, specify the first architecture from QT_OSX_ARCHITECTURES
+ # (even with a simulator_and_device Qt build). This ensures that the default configuration
+ # at least tries to build something.
+ if(UIKIT)
+ qt_internal_get_first_osx_arch(osx_first_arch)
+ list(APPEND init_platform
+"if((NOT CMAKE_GENERATOR STREQUAL \"Xcode\" AND NOT __qt_toolchain_building_qt_repo)
+ OR (CMAKE_GENERATOR STREQUAL \"Xcode\" AND __qt_apple_sdk AND NOT QT_NO_SET_OSX_ARCHITECTURES))")
+ list(APPEND init_platform
+ " set(CMAKE_OSX_ARCHITECTURES \"${osx_first_arch}\" CACHE STRING \"\")")
+ list(APPEND init_platform "endif()")
+ list(APPEND init_platform "")
+ endif()
+
+ if(UIKIT)
+ list(APPEND init_platform
+ "set(CMAKE_SYSTEM_NAME \"${CMAKE_SYSTEM_NAME}\" CACHE STRING \"\")")
+ endif()
+ elseif(ANDROID)
+ list(APPEND init_platform
+"# Detect Android SDK/NDK from environment before loading the Android platform toolchain file."
+"if(\"$\{ANDROID_SDK_ROOT}\" STREQUAL \"\" AND NOT \"\$ENV{ANDROID_SDK_ROOT}\" STREQUAL \"\")"
+" set(ANDROID_SDK_ROOT \"\$ENV{ANDROID_SDK_ROOT}\" CACHE STRING \"Path to the Android SDK\")"
+"endif()"
+"if(\"$\{ANDROID_NDK_ROOT}\" STREQUAL \"\" AND NOT \"\$ENV{ANDROID_NDK_ROOT}\" STREQUAL \"\")"
+" set(ANDROID_NDK_ROOT \"\$ENV{ANDROID_NDK_ROOT}\" CACHE STRING \"Path to the Android NDK\")"
+"endif()"
+ )
+
+ foreach(var ANDROID_PLATFORM ANDROID_NATIVE_API_LEVEL ANDROID_STL
+ ANDROID_ABI ANDROID_SDK_ROOT ANDROID_NDK_ROOT)
+ list(APPEND init_additional_used_variables
+ "list(APPEND __qt_toolchain_used_variables ${var})")
+ endforeach()
+
+ list(APPEND init_platform
+ "if(NOT DEFINED ANDROID_PLATFORM AND NOT DEFINED ANDROID_NATIVE_API_LEVEL)")
+ list(APPEND init_platform
+ " set(ANDROID_PLATFORM \"${ANDROID_PLATFORM}\" CACHE STRING \"\")")
+ list(APPEND init_platform "endif()")
+ list(APPEND init_platform "set(ANDROID_STL \"${ANDROID_STL}\" CACHE STRING \"\")")
+ list(APPEND init_platform "set(ANDROID_ABI \"${ANDROID_ABI}\" CACHE STRING \"\")")
+ list(APPEND init_platform "if (NOT DEFINED ANDROID_SDK_ROOT)")
+ file(TO_CMAKE_PATH "${ANDROID_SDK_ROOT}" __qt_android_sdk_root)
+ list(APPEND init_platform
+ " set(ANDROID_SDK_ROOT \"${__qt_android_sdk_root}\" CACHE STRING \"\")")
+ list(APPEND init_platform "endif()")
+
+ list(APPEND init_platform "if(NOT \"$\{ANDROID_NDK_ROOT\}\" STREQUAL \"\")")
+ list(APPEND init_platform
+ " set(__qt_toolchain_file_candidate \"$\{ANDROID_NDK_ROOT\}/build/cmake/android.toolchain.cmake\")")
+ list(APPEND init_platform " if(EXISTS \"$\{__qt_toolchain_file_candidate\}\")")
+ list(APPEND init_platform
+ " message(STATUS \"Android toolchain file within NDK detected: $\{__qt_toolchain_file_candidate\}\")")
+ list(APPEND init_platform " set(__qt_chainload_toolchain_file \"$\{__qt_toolchain_file_candidate\}\")")
+ list(APPEND init_platform " else()")
+ list(APPEND init_platform
+ " message(FATAL_ERROR \"Cannot find the toolchain file '$\{__qt_toolchain_file_candidate\}'. \"")
+ list(APPEND init_platform
+ " \"Please specify the toolchain file with -DQT_CHAINLOAD_TOOLCHAIN_FILE=<file>.\")")
+ list(APPEND init_platform " endif()")
+ list(APPEND init_platform "endif()")
+ elseif(EMSCRIPTEN)
+ list(APPEND init_platform
+"include(\${CMAKE_CURRENT_LIST_DIR}/QtPublicWasmToolchainHelpers.cmake)
+if(DEFINED ENV{EMSDK} AND NOT \"\$ENV{EMSDK}\" STREQUAL \"\")
+ __qt_internal_get_emroot_path_suffix_from_emsdk_env(__qt_toolchain_emroot_path)
+ __qt_internal_get_emscripten_cmake_toolchain_file_path_from_emsdk_env(
+ \"\${__qt_toolchain_emroot_path}\" _qt_candidate_emscripten_toolchain_path)
+ set(__qt_chainload_toolchain_file \"\${_qt_candidate_emscripten_toolchain_path}\")
+endif()
+")
+ list(APPEND init_post_chainload_toolchain "
+if(NOT __qt_chainload_toolchain_file_included)
+ __qt_internal_show_error_no_emscripten_toolchain_file_found_when_using_qt()
+endif()
+")
+ endif()
+
+ string(REPLACE ";" "\n" init_additional_used_variables
+ "${init_additional_used_variables}")
+ string(REPLACE ";" "\n" init_vcpkg "${init_vcpkg}")
+
+ string(REPLACE ";" "\n" init_platform "${init_platform}")
+ string(REPLACE "LITERAL_SEMICOLON" ";" init_platform "${init_platform}")
+
+ string(REPLACE ";" "\n" init_post_chainload_toolchain "${init_post_chainload_toolchain}")
+ string(REPLACE "LITERAL_SEMICOLON" ";" init_post_chainload_toolchain
+ "${init_post_chainload_toolchain}")
+
+ qt_compute_relative_path_from_cmake_config_dir_to_prefix()
+ configure_file(
+ "${CMAKE_CURRENT_SOURCE_DIR}/cmake/qt.toolchain.cmake.in"
+ "${__GlobalConfig_build_dir}/qt.toolchain.cmake" @ONLY)
+ qt_install(FILES "${__GlobalConfig_build_dir}/qt.toolchain.cmake"
+ DESTINATION "${__GlobalConfig_install_dir}" COMPONENT Devel)
+endfunction()
diff --git a/cmake/QtUnityBuildHelpers.cmake b/cmake/QtUnityBuildHelpers.cmake
new file mode 100644
index 0000000000..e804396f59
--- /dev/null
+++ b/cmake/QtUnityBuildHelpers.cmake
@@ -0,0 +1,24 @@
+# Copyright (C) 2023 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+# Check whether no unity build is requested where it is disabled by default.
+function(_qt_internal_validate_no_unity_build prefix)
+ if(${prefix}_NO_UNITY_BUILD OR ${prefix}_NO_UNITY_BUILD_SOURCES)
+ message(WARNING
+ "Unity build is disabled by default for this target, and its sources. "
+ "You may remove the NO_UNITY_BUILD and/or NO_UNITY_BUILD_SOURCES arguments.")
+ endif()
+endfunction()
+
+function(qt_update_ignore_unity_build_sources target sources)
+ if(sources)
+ # We need to add the TARGET_DIRECTORY scope for targets that have qt_internal_extend_target
+ # calls in different subdirectories, like in qtgraphs.
+ set(scope_args)
+ if(CMAKE_VERSION VERSION_GREATER_EQUAL "3.18")
+ set(scope_args TARGET_DIRECTORY ${target})
+ endif()
+ set_source_files_properties(${sources} ${scope_args}
+ PROPERTIES SKIP_UNITY_BUILD_INCLUSION ON)
+ endif()
+endfunction()
diff --git a/cmake/QtVersionlessAliasTargets.cmake.in b/cmake/QtVersionlessAliasTargets.cmake.in
new file mode 100644
index 0000000000..fcf182941c
--- /dev/null
+++ b/cmake/QtVersionlessAliasTargets.cmake.in
@@ -0,0 +1,7 @@
+# Protect against multiple inclusion, which would fail when already imported targets are
+# added once more.
+_qt_internal_check_multiple_inclusion(_targets_not_defined "@versionless_targets@")
+
+_qt_internal_create_versionless_alias_targets("${_targets_not_defined}" @INSTALL_CMAKE_NAMESPACE@)
+
+unset(_targets_not_defined)
diff --git a/cmake/QtVersionlessTargets.cmake.in b/cmake/QtVersionlessTargets.cmake.in
new file mode 100644
index 0000000000..c809915e65
--- /dev/null
+++ b/cmake/QtVersionlessTargets.cmake.in
@@ -0,0 +1,7 @@
+# Protect against multiple inclusion, which would fail when already imported targets are
+# added once more.
+_qt_internal_check_multiple_inclusion(_targets_not_defined "@versionless_targets@")
+
+_qt_internal_create_versionless_targets("${_targets_not_defined}" @INSTALL_CMAKE_NAMESPACE@)
+
+unset(_targets_not_defined)
diff --git a/cmake/QtWasmHelpers.cmake b/cmake/QtWasmHelpers.cmake
new file mode 100644
index 0000000000..41ef5cb0ba
--- /dev/null
+++ b/cmake/QtWasmHelpers.cmake
@@ -0,0 +1,127 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+
+# WARNING must keep in sync with wasm-emscripten/qmake.conf!
+function (qt_internal_setup_wasm_target_properties wasmTarget)
+
+ target_link_options("${wasmTarget}" INTERFACE
+ "SHELL:-s MAX_WEBGL_VERSION=2"
+ "SHELL:-s FETCH=1"
+ "SHELL:-s WASM_BIGINT=1"
+ "SHELL:-s STACK_SIZE=5MB")
+
+ target_link_libraries("${wasmTarget}" INTERFACE embind)
+
+ ## wasm64
+ if (WASM64)
+ target_compile_options("${wasmTarget}" INTERFACE "SHELL:-s MEMORY64=1" )
+ target_link_options("${wasmTarget}" INTERFACE "SHELL:-s MEMORY64=1" -mwasm64)
+ endif()
+ # Enable MODULARIZE so that we are able to set EXPORT_NAME later and instantiate on demand (with
+ # MODULARIZE=0, emscripten creates a global app instance object at Javascript eval time)
+ target_link_options("${wasmTarget}" INTERFACE "SHELL:-s MODULARIZE=1")
+
+ #simd
+ if (QT_FEATURE_wasm_simd128)
+ target_compile_options("${wasmTarget}" INTERFACE -msimd128)
+ endif()
+ if (QT_FEATURE_sse2)
+ target_compile_options("${wasmTarget}" INTERFACE -O2 -msimd128 -msse -msse2)
+ endif()
+
+ # wasm exceptions
+ if (QT_FEATURE_wasm_exceptions)
+ target_compile_options("${wasmTarget}" INTERFACE -fwasm-exceptions)
+ target_link_options("${wasmTarget}" INTERFACE -fwasm-exceptions)
+ endif()
+
+ if (QT_FEATURE_thread)
+ target_compile_options("${wasmTarget}" INTERFACE "SHELL:-pthread")
+ target_link_options("${wasmTarget}" INTERFACE "SHELL:-pthread")
+ endif()
+
+ target_link_options("${wasmTarget}" INTERFACE "SHELL:-s ALLOW_MEMORY_GROWTH")
+
+ # debug add_compile_options
+ if ("QT_WASM_SOURCE_MAP=1" IN_LIST QT_QMAKE_DEVICE_OPTIONS)
+ set(WASM_SOURCE_MAP_BASE "http://localhost:8000/")
+
+ if(DEFINED QT_WASM_SOURCE_MAP_BASE)
+ set(WASM_SOURCE_MAP_BASE "${QT_WASM_SOURCE_MAP_BASE}")
+ endif()
+
+ # Pass --source-map-base on the linker line. This informs the
+ # browser where to find the source files when debugging.
+ # -g4 to make source maps for debugging
+ target_link_options("${wasmTarget}" INTERFACE "-gsource-map" "--source-map-base" "${WASM_SOURCE_MAP_BASE}")
+
+ endif()
+
+ # a few good defaults to make console more verbose while debugging
+ target_link_options("${wasmTarget}" INTERFACE $<$<CONFIG:Debug>:
+ "SHELL:-s DEMANGLE_SUPPORT=1"
+ --profiling-funcs>)
+
+ # target_link_options("${wasmTarget}" INTERFACE "SHELL:-s LIBRARY_DEBUG=1") # print out library calls, verbose
+ # target_link_options("${wasmTarget}" INTERFACE "SHELL:-s SYSCALL_DEBUG=1") # print out sys calls, verbose
+ # target_link_options("${wasmTarget}" INTERFACE "SHELL:-s FS_LOG=1") # print out filesystem ops, verbose
+ # target_link_options("${wasmTarget}" INTERFACE "SHELL:-s SOCKET_DEBUG") # print out socket,network data transfer
+
+ if ("QT_EMSCRIPTEN_ASYNCIFY=1" IN_LIST QT_QMAKE_DEVICE_OPTIONS)
+ # Emscripten recommends building with optimizations when using asyncify
+ # in order to reduce wasm file size, and may also generate broken wasm
+ # (with "wasm validation error: too many locals" type errors) if optimizations
+ # are omitted. Enable optimizations also for debug builds.
+ set(QT_CFLAGS_OPTIMIZE_DEBUG "-Os" CACHE STRING INTERNAL FORCE)
+ set(QT_FEATURE_optimize_debug ON CACHE BOOL INTERNAL FORCE)
+
+ target_link_options("${wasmTarget}" INTERFACE "SHELL:-s ASYNCIFY" "-Os")
+ target_compile_definitions("${wasmTarget}" INTERFACE QT_HAVE_EMSCRIPTEN_ASYNCIFY)
+ endif()
+
+ # Set ASYNCIFY_IMPORTS unconditionally in order to support enabling asyncify at link time.
+ target_link_options("${wasmTarget}" INTERFACE "SHELL:-sASYNCIFY_IMPORTS=qt_asyncify_suspend_js,qt_asyncify_resume_js")
+
+ if(QT_FEATURE_shared)
+
+ set_property(GLOBAL PROPERTY TARGET_SUPPORTS_SHARED_LIBS TRUE)
+
+ set(side_modules
+ MODULE_LIBRARY SHARED_LIBRARY)
+ set(enable_side_module_if_needed
+ "$<$<IN_LIST:$<TARGET_PROPERTY:TYPE>,${side_modules}>:SHELL:-s SIDE_MODULE=1>")
+ set(enable_main_module_if_needed
+ "$<$<IN_LIST:$<TARGET_PROPERTY:TYPE>,EXECUTABLE>:SHELL:-s MAIN_MODULE=1>")
+ set(set_shared_module_type_if_needed
+ "${enable_side_module_if_needed}"
+ "${enable_main_module_if_needed}"
+ )
+
+ # Add Qt libdir to linker library paths
+ set(qt_lib_location
+ "${QT_BUILD_INTERNALS_RELOCATABLE_INSTALL_PREFIX}/${INSTALL_LIBDIR}")
+ target_link_options("${wasmTarget}" INTERFACE
+ "$<$<STREQUAL:$<TARGET_PROPERTY:TYPE>,EXECUTABLE>:SHELL:" -L${qt_lib_location}/>)
+
+ target_compile_options("${wasmTarget}" INTERFACE "${set_shared_module_type_if_needed}")
+ target_link_options("${wasmTarget}" INTERFACE "${set_shared_module_type_if_needed}")
+
+ else()
+ target_link_options("${wasmTarget}" INTERFACE "SHELL:-s ERROR_ON_UNDEFINED_SYMBOLS=1")
+ endif()
+
+ # Suppress warnings for known issues for developer builds
+ if(FEATURE_developer_build)
+ target_link_options("${wasmTarget}" INTERFACE "SHELL:-Wno-pthreads-mem-growth")
+ endif()
+
+endfunction()
+
+function(qt_internal_wasm_add_finalizers target)
+ qt_add_list_file_finalizer(_qt_internal_set_wasm_export_name ${target})
+ qt_add_list_file_finalizer(_qt_internal_add_wasm_extra_exported_methods ${target})
+ qt_add_list_file_finalizer(_qt_internal_wasm_add_target_helpers ${target})
+endfunction()
+
+
diff --git a/cmake/QtWrapperScriptHelpers.cmake b/cmake/QtWrapperScriptHelpers.cmake
new file mode 100644
index 0000000000..8eb4416e6d
--- /dev/null
+++ b/cmake/QtWrapperScriptHelpers.cmake
@@ -0,0 +1,333 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+# Creates and installs the following wrapper CMake scripts:
+# qt-make
+# qt-cmake-private
+# qt-configure-module
+# qt-cmake-private-install
+# And other helper scripts.
+function(qt_internal_create_wrapper_scripts)
+ # Provide a convenience cmake wrapper.
+
+ if(QT_GENERATE_WRAPPER_SCRIPTS_FOR_ALL_HOSTS)
+ set(generate_unix TRUE)
+ set(generate_non_unix TRUE)
+ elseif(CMAKE_HOST_UNIX)
+ set(generate_unix TRUE)
+ else()
+ set(generate_non_unix TRUE)
+ endif()
+
+ set(extra_qt_cmake_code "")
+ if(generate_unix)
+
+ if(UIKIT)
+ set(extra_qt_cmake_code [=[
+# Specify Xcode as the default generator by assigning it to the CMAKE_GENERATOR env var.
+# An explicit -G or -D CMAKE_GENERATOR given on the command line will still take precedence.
+export CMAKE_GENERATOR=Xcode
+]=])
+ endif()
+
+ configure_file("${CMAKE_CURRENT_SOURCE_DIR}/bin/qt-cmake.in"
+ "${QT_BUILD_DIR}/${INSTALL_BINDIR}/qt-cmake" @ONLY
+ NEWLINE_STYLE LF)
+ qt_install(PROGRAMS "${QT_BUILD_DIR}/${INSTALL_BINDIR}/qt-cmake"
+ DESTINATION "${INSTALL_BINDIR}")
+ endif()
+ if(generate_non_unix)
+ configure_file("${CMAKE_CURRENT_SOURCE_DIR}/bin/qt-cmake.bat.in"
+ "${QT_BUILD_DIR}/${INSTALL_BINDIR}/qt-cmake.bat" @ONLY
+ NEWLINE_STYLE CRLF)
+ qt_install(PROGRAMS "${QT_BUILD_DIR}/${INSTALL_BINDIR}/qt-cmake.bat"
+ DESTINATION "${INSTALL_BINDIR}")
+ endif()
+
+ if(generate_unix)
+ configure_file("${CMAKE_CURRENT_SOURCE_DIR}/bin/qt-cmake-create.in"
+ "${QT_BUILD_DIR}/${INSTALL_BINDIR}/qt-cmake-create" @ONLY
+ NEWLINE_STYLE LF)
+ qt_install(PROGRAMS "${QT_BUILD_DIR}/${INSTALL_BINDIR}/qt-cmake-create"
+ DESTINATION "${INSTALL_BINDIR}")
+ endif()
+ if(generate_non_unix)
+ configure_file("${CMAKE_CURRENT_SOURCE_DIR}/bin/qt-cmake-create.bat.in"
+ "${QT_BUILD_DIR}/${INSTALL_BINDIR}/qt-cmake-create.bat" @ONLY
+ NEWLINE_STYLE CRLF)
+ qt_install(PROGRAMS "${QT_BUILD_DIR}/${INSTALL_BINDIR}/qt-cmake-create.bat"
+ DESTINATION "${INSTALL_BINDIR}")
+ endif()
+
+ # Reset the contents for the next script.
+ set(extra_qt_cmake_code "")
+
+ # Provide a private convenience wrapper with options that should not be propagated via the
+ # public qt-cmake wrapper e.g. CMAKE_GENERATOR.
+ # These options can not be set in a toolchain file, but only on the command line.
+ # These options should not be in the public wrapper, because a consumer of Qt might want to
+ # build their CMake app with the Unix Makefiles generator, while Qt should be built with the
+ # Ninja generator. In a similar vein, we do want to use the same compiler for all Qt modules,
+ # but not for user applications.
+ # The private wrapper is more convenient for building Qt itself, because a developer doesn't
+ # need to specify the same options for each qt module built.
+ set(__qt_cmake_extra "-G\"${CMAKE_GENERATOR}\" -DQT_USE_ORIGINAL_COMPILER=ON")
+ if(generate_unix)
+ configure_file("${CMAKE_CURRENT_SOURCE_DIR}/bin/qt-cmake.in"
+ "${QT_BUILD_DIR}/${INSTALL_LIBEXECDIR}/qt-cmake-private" @ONLY
+ NEWLINE_STYLE LF)
+ qt_install(PROGRAMS "${QT_BUILD_DIR}/${INSTALL_LIBEXECDIR}/qt-cmake-private"
+ DESTINATION "${INSTALL_LIBEXECDIR}")
+ endif()
+ if(generate_non_unix)
+ configure_file("${CMAKE_CURRENT_SOURCE_DIR}/bin/qt-cmake.bat.in"
+ "${QT_BUILD_DIR}/${INSTALL_BINDIR}/qt-cmake-private.bat" @ONLY
+ NEWLINE_STYLE CRLF)
+ qt_install(PROGRAMS "${QT_BUILD_DIR}/${INSTALL_BINDIR}/qt-cmake-private.bat"
+ DESTINATION "${INSTALL_BINDIR}")
+ endif()
+ unset(__qt_cmake_extra)
+
+ # Provide a script to configure Qt modules.
+ if(QT_WILL_INSTALL)
+ set(__relative_path_to_cmake_scripts_dir
+ "${__GlobalConfig_relative_path_from_bin_dir_to_cmake_config_dir}")
+ else()
+ file(RELATIVE_PATH __relative_path_to_cmake_scripts_dir
+ "${__qt_bin_dir_absolute}" "${CMAKE_CURRENT_LIST_DIR}")
+ endif()
+ file(TO_NATIVE_PATH "${__relative_path_to_cmake_scripts_dir}"
+ __relative_path_to_cmake_scripts_dir)
+ if(generate_unix)
+ configure_file("${CMAKE_CURRENT_SOURCE_DIR}/bin/qt-configure-module.in"
+ "${QT_BUILD_DIR}/${INSTALL_BINDIR}/qt-configure-module" @ONLY
+ NEWLINE_STYLE LF)
+ qt_install(PROGRAMS "${QT_BUILD_DIR}/${INSTALL_BINDIR}/qt-configure-module"
+ DESTINATION "${INSTALL_BINDIR}")
+ endif()
+ if(generate_non_unix)
+ configure_file("${CMAKE_CURRENT_SOURCE_DIR}/bin/qt-configure-module.bat.in"
+ "${QT_BUILD_DIR}/${INSTALL_BINDIR}/qt-configure-module.bat" @ONLY
+ NEWLINE_STYLE CRLF)
+ qt_install(PROGRAMS "${QT_BUILD_DIR}/${INSTALL_BINDIR}/qt-configure-module.bat"
+ DESTINATION "${INSTALL_BINDIR}")
+ endif()
+ unset(__relative_path_to_cmake_scripts_dir)
+
+ # Provide a private convenience wrapper to configure and build one or more standalone tests.
+ # Calling CMake directly on a Qt test project won't work because the project does not call
+ # find_package(Qt...) to get all dependencies like examples do.
+ # Instead a template CMakeLists.txt project is used which sets up all the necessary private bits
+ # and then calls add_subdirectory on the provided project path.
+ set(__qt_cmake_standalone_test_name "qt-cmake-standalone-test")
+ if(generate_unix)
+ set(__qt_cmake_standalone_test_libexec_path
+ "${INSTALL_LIBEXECDIR}/${__qt_cmake_standalone_test_name}")
+ endif()
+ if(generate_non_unix)
+ set(__qt_cmake_standalone_test_bin_path
+ "${INSTALL_BINDIR}/${__qt_cmake_standalone_test_name}")
+ endif()
+
+ # Configuring a standalone test on iOS should use the Xcode generator, but qt-cmake-private uses
+ # the generator that was used to build Qt itself (e.g. Ninja).
+ # Use qt-cmake instead, which does use the Xcode generator since Qt 6.2.5, 6.3.1, 6.4.
+ if(IOS)
+ set(__qt_cmake_private_path
+ "${QT_STAGING_PREFIX}/${INSTALL_BINDIR}/qt-cmake")
+ else()
+ if(generate_unix)
+ set(__qt_cmake_private_path
+ "${QT_STAGING_PREFIX}/${INSTALL_LIBEXECDIR}/qt-cmake-private")
+ endif()
+ if(generate_non_unix)
+ set(__qt_cmake_private_path
+ "${QT_STAGING_PREFIX}/${INSTALL_BINDIR}/qt-cmake-private")
+ endif()
+ endif()
+
+ set(__qt_cmake_standalone_test_path
+ "${__build_internals_install_dir}/${__build_internals_standalone_test_template_dir}")
+
+ if(QT_WILL_INSTALL)
+ # Need to prepend the staging prefix when doing prefix builds, because the build internals
+ # install dir is relative in that case..
+ qt_path_join(__qt_cmake_standalone_test_path
+ "${QT_STAGING_PREFIX}"
+ "${__qt_cmake_standalone_test_path}")
+ endif()
+
+ if(generate_unix)
+ get_filename_component(rel_base_path
+ "${QT_STAGING_PREFIX}/${__qt_cmake_standalone_test_libexec_path}"
+ DIRECTORY)
+
+ file(RELATIVE_PATH __qt_cmake_private_relpath "${rel_base_path}"
+ "${__qt_cmake_private_path}")
+ file(RELATIVE_PATH __qt_cmake_standalone_test_relpath "${rel_base_path}"
+ "${__qt_cmake_standalone_test_path}")
+
+ set(__qt_cmake_standalone_test_os_prelude "#!/bin/sh")
+ set(__qt_cmake_standalone_test_script_relpath "SCRIPT_DIR=`dirname $0`")
+ string(PREPEND __qt_cmake_private_relpath "exec $SCRIPT_DIR/")
+ string(PREPEND __qt_cmake_standalone_test_relpath "$SCRIPT_DIR/")
+ set(__qt_cmake_standalone_passed_args "\"$@\" -DPWD=\"$PWD\"")
+
+ configure_file("${CMAKE_CURRENT_SOURCE_DIR}/bin/qt-cmake-standalone-test.in"
+ "${QT_BUILD_DIR}/${__qt_cmake_standalone_test_libexec_path}"
+ NEWLINE_STYLE LF)
+ qt_install(PROGRAMS "${QT_BUILD_DIR}/${__qt_cmake_standalone_test_libexec_path}"
+ DESTINATION "${INSTALL_LIBEXECDIR}")
+ endif()
+ if(generate_non_unix)
+ get_filename_component(rel_base_path
+ "${QT_STAGING_PREFIX}/${__qt_cmake_standalone_test_bin_path}"
+ DIRECTORY)
+
+ file(RELATIVE_PATH __qt_cmake_private_relpath "${rel_base_path}"
+ "${__qt_cmake_private_path}")
+ file(RELATIVE_PATH __qt_cmake_standalone_test_relpath "${rel_base_path}"
+ "${__qt_cmake_standalone_test_path}")
+
+ set(__qt_cmake_standalone_test_os_prelude "@echo off")
+ set(__qt_cmake_standalone_test_script_relpath "set SCRIPT_DIR=%~dp0")
+ string(APPEND __qt_cmake_standalone_test_bin_path ".bat")
+ string(APPEND __qt_cmake_private_relpath ".bat")
+ string(PREPEND __qt_cmake_private_relpath "%SCRIPT_DIR%")
+ string(PREPEND __qt_cmake_standalone_test_relpath "%SCRIPT_DIR%")
+ set(__qt_cmake_standalone_passed_args "%* -DPWD=\"%CD%\"")
+
+ configure_file("${CMAKE_CURRENT_SOURCE_DIR}/bin/qt-cmake-standalone-test.in"
+ "${QT_BUILD_DIR}/${__qt_cmake_standalone_test_bin_path}"
+ NEWLINE_STYLE CRLF)
+ qt_install(PROGRAMS "${QT_BUILD_DIR}/${__qt_cmake_standalone_test_bin_path}"
+ DESTINATION "${INSTALL_BINDIR}")
+ endif()
+
+ # Create an installation script that the CI can use to handle installation for both
+ # single and multiple configurations.
+ set(__qt_cmake_install_script_name "qt-cmake-private-install.cmake")
+ if(CMAKE_CONFIGURATION_TYPES)
+ set(__qt_configured_configs "${CMAKE_CONFIGURATION_TYPES}")
+ elseif(CMAKE_BUILD_TYPE)
+ set(__qt_configured_configs "${CMAKE_BUILD_TYPE}")
+ endif()
+
+ if(
+ # Skip stripping pure debug builds so it's easier to debug issues in CI VMs.
+ (NOT QT_FEATURE_debug_and_release
+ AND QT_FEATURE_debug
+ AND NOT QT_FEATURE_separate_debug_info)
+
+ # Skip stripping on MSVC because ${CMAKE_STRIP} might contain a MinGW strip binary
+ # and the breaks the linker version flag embedded in the binary and causes Qt Creator
+ # to mis-identify the Kit ABI.
+ OR MSVC
+ )
+ set(__qt_skip_strip_installed_artifacts TRUE)
+ else()
+ set(__qt_skip_strip_installed_artifacts FALSE)
+ endif()
+ configure_file("${CMAKE_CURRENT_SOURCE_DIR}/bin/${__qt_cmake_install_script_name}.in"
+ "${QT_BUILD_DIR}/${INSTALL_LIBEXECDIR}/${__qt_cmake_install_script_name}" @ONLY)
+ qt_install(FILES "${QT_BUILD_DIR}/${INSTALL_LIBEXECDIR}/${__qt_cmake_install_script_name}"
+ DESTINATION "${INSTALL_LIBEXECDIR}")
+
+ qt_internal_create_qt_configure_part_wrapper_script("STANDALONE_TESTS")
+ qt_internal_create_qt_configure_part_wrapper_script("STANDALONE_EXAMPLES")
+ qt_internal_create_qt_configure_redo_script()
+endfunction()
+
+function(qt_internal_create_qt_configure_part_wrapper_script component)
+ if(QT_GENERATE_WRAPPER_SCRIPTS_FOR_ALL_HOSTS)
+ set(generate_unix TRUE)
+ set(generate_non_unix TRUE)
+ elseif(CMAKE_HOST_UNIX)
+ set(generate_unix TRUE)
+ else()
+ set(generate_non_unix TRUE)
+ endif()
+
+ # Create a private wrapper script to configure and build all standalone tests / examples.
+ #
+ # The script uses qt-cmake instead of qt-cmake-private on purpose. That's to ensure we build
+ # only one configuration of tests (e.g RelWithDebInfo only) when Qt is configured with more
+ # than one configuration (RelWithDebInfo;Debug).
+ # Meant to be used by our CI instructions.
+ #
+ # The script takes a path to the repo for which the standalone tests / examples will be
+ # configured.
+
+ if(component STREQUAL "STANDALONE_TESTS")
+ set(script_name "qt-internal-configure-tests")
+ set(script_passed_args "-DQT_BUILD_STANDALONE_TESTS=ON -DQT_BUILD_EXAMPLES=OFF")
+ elseif(component STREQUAL "STANDALONE_EXAMPLES")
+ set(script_name "qt-internal-configure-examples")
+ set(script_passed_args "-DQT_BUILD_STANDALONE_EXAMPLES=ON -DQT_BUILD_TESTS=OFF")
+ else()
+ message(FATAL_ERROR "Invalid component type: ${component}")
+ endif()
+
+ string(APPEND script_passed_args " -DQT_USE_ORIGINAL_COMPILER=ON")
+
+ file(RELATIVE_PATH relative_path_from_libexec_dir_to_bin_dir
+ ${__qt_libexec_dir_absolute}
+ ${__qt_bin_dir_absolute})
+ file(TO_NATIVE_PATH "${relative_path_from_libexec_dir_to_bin_dir}"
+ relative_path_from_libexec_dir_to_bin_dir)
+
+ if(generate_unix)
+ configure_file("${CMAKE_CURRENT_SOURCE_DIR}/libexec/${script_name}.in"
+ "${QT_BUILD_DIR}/${INSTALL_LIBEXECDIR}/${script_name}" @ONLY
+ NEWLINE_STYLE LF)
+
+ qt_install(PROGRAMS "${QT_BUILD_DIR}/${INSTALL_LIBEXECDIR}/${script_name}"
+ DESTINATION "${INSTALL_LIBEXECDIR}")
+ endif()
+ if(generate_non_unix)
+ configure_file("${CMAKE_CURRENT_SOURCE_DIR}/libexec/${script_name}.bat.in"
+ "${QT_BUILD_DIR}/${INSTALL_BINDIR}/${script_name}.bat" @ONLY
+ NEWLINE_STYLE CRLF)
+
+ qt_install(PROGRAMS "${QT_BUILD_DIR}/${INSTALL_BINDIR}/${script_name}.bat"
+ DESTINATION "${INSTALL_BINDIR}")
+ endif()
+endfunction()
+
+# Create a shell wrapper script to reconfigure Qt with the original configure arguments and
+# any additional ones passed.
+#
+# Removes CMakeCache.txt and friends, either manually, or using CMake's --fresh.
+#
+# The script is created in the root of the build dir and is called config.redo
+# It has the same contents as the 'config.status' script we created in qt 5.
+function(qt_internal_create_qt_configure_redo_script)
+ set(input_script_name "qt-internal-config.redo")
+ set(input_script_path "${CMAKE_CURRENT_SOURCE_DIR}/libexec/${input_script_name}")
+
+ # We don't use QT_BUILD_DIR because we want the file in the root of the build dir in a top-level
+ # build.
+ set(output_script_name "config.redo")
+ set(output_path "${CMAKE_BINARY_DIR}/${output_script_name}")
+
+ if(QT_SUPERBUILD)
+ set(configure_script_path "${Qt_SOURCE_DIR}")
+ else()
+ set(configure_script_path "${QtBase_SOURCE_DIR}")
+ endif()
+ string(APPEND configure_script_path "/configure")
+
+ # Used in the file contents.
+ file(TO_NATIVE_PATH "${configure_script_path}" configure_path)
+
+ if(CMAKE_HOST_UNIX)
+ string(APPEND input_script_path ".in")
+ set(newline_style "LF")
+ else()
+ string(APPEND input_script_path ".bat.in")
+ string(APPEND output_path ".bat")
+ set(newline_style "CRLF")
+ endif()
+
+ configure_file("${input_script_path}" "${output_path}" @ONLY NEWLINE_STYLE ${newline_style})
+endfunction()
diff --git a/cmake/QtWriteArgsFile.cmake b/cmake/QtWriteArgsFile.cmake
new file mode 100644
index 0000000000..77a9eb2463
--- /dev/null
+++ b/cmake/QtWriteArgsFile.cmake
@@ -0,0 +1,92 @@
+# Copyright (C) 2022 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 config.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}")
diff --git a/cmake/README.md b/cmake/README.md
index 65be11666d..9d0743566d 100644
--- a/cmake/README.md
+++ b/cmake/README.md
@@ -1,23 +1,37 @@
-# Status
+# Overview
-Port is still on-going.
-Most of qtbase and qtsvg is ported.
-Other repositories are ported, but not under CI control yet.
-Some libraries, tests and examples are still missing.
+This document gives an overview of the Qt 6 build system. For a hands-on guide on how
+to build Qt 6, see https://doc.qt.io/qt-6/build-sources.html and
+https://wiki.qt.io/Building_Qt_6_from_Git
-Note:
-You need CMake 3.16.0 or later for most platforms (due to new AUTOMOC json feature).
-You need CMake 3.17.0 to build Qt for iOS with the simulator_and_device feature.
-You need CMake 3.17.0 + Ninja to build Qt in debug_and_release mode on Windows / Linux.
-You need CMake 3.18.0 + Ninja to build Qt on macOS in debug_and_release mode when using frameworks.
+# Contributing
-# Intro
+See qtbase/cmake/CODESTYLE.md for the code style you should follow when contributing
+to Qt's cmake files.
-The CMake update offers an opportunity to revisit some topics that came up during the last few
-years.
+# CMake Versions
-* The Qt build system does not support building host tools during a cross-compilation run. You need
- to build a Qt for your host machine first and then use the platform tools from that version. The
+* You need CMake 3.16.0 or later for most platforms (due to new AUTOMOC json feature).
+* You need CMake 3.17.0 to build Qt for iOS with the simulator_and_device feature.
+* You need CMake 3.17.0 + Ninja to build Qt in debug_and_release mode on Windows / Linux.
+* You need CMake 3.18.0 + Ninja to build Qt on macOS in debug_and_release mode when using
+ frameworks.
+* You need CMake 3.18.0 in user projects that use a static Qt together with QML
+ (cmake_language EVAL is required for running the qmlimportscanner deferred finalizer)
+* You need CMake 3.19.0 in user projects to use automatic deferred finalizers
+ (automatic calling of qt_finalize_target)
+* You need CMake 3.21.0 in user projects that create user libraries that link against a static Qt
+ with a linker that is not capable to resolve circular dependencies between libraries
+ (GNU ld, MinGW ld)
+
+# Changes to Qt 5
+
+The build system of Qt 5 was done on top of qmake. Qt 6 is built with CMake.
+
+This offered an opportunity to revisit other areas of the build system, too:
+
+* The Qt 5 build system allowed to build host tools during a cross-compilation run. Qt 6 requires
+ you to build a Qt for your host machine first and then use the platform tools from that version. The
decision to do this was reached independent of cmake: This does save resources on build machines
as the host tools will only get built once.
@@ -27,23 +41,21 @@ years.
* There is less need for bootstrapping. Only moc and rcc (plus the lesser known tracegen and
qfloat16-tables) are linking against the bootstrap Qt library. Everything else can link against
- the full QtCore. This will include qmake.
- Qmake is supported as a build system for applications *using* Qt going forward and will
+ the full QtCore. This does include qmake.
+ qmake is supported as a build system for applications *using* Qt going forward and will
not go away anytime soon.
-* We keep the qmake-based Qt build system working so that we do not interfere too much with ongoing
- development.
-
-
# Building against homebrew on macOS
You may use brew to install dependencies needed to build QtBase.
* Install homebrew:
- ```/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"```
+ `/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"`
* Build Qt dependencies: ``brew install pcre2 harfbuzz freetype``
* Install cmake: ``brew install cmake``
- * When running cmake in qtbase, pass ``-DCMAKE_PREFIX_PATH=/usr/local``
+ * When running cmake in qtbase, pass ``-DFEATURE_pkg_config=ON`` together with
+ ``-DCMAKE_PREFIX_PATH=/usr/local``, or ``-DCMAKE_PREFIX_PATH=/opt/homebrew`` if you have a Mac
+ with Apple Silicon.
# Building
@@ -110,7 +122,8 @@ the source directory next to them using the helper script
``path_to_qtbase_source/util/cmake/configurejson2cmake.py``. They are checked into the repository.
If the feature in configure.json has the name "dlopen", you can specify whether to enable or disable that
feature in CMake with a -D flag on the CMake command line. So for example -DFEATURE_dlopen=ON or
--DFEATURE_sql_mysql=OFF. At the moment, if you change a FEATURE flag's value, you have to remove the
+-DFEATURE_sql_mysql=OFF. Remember to convert all '-' to '_' in the feature name.
+At the moment, if you change a FEATURE flag's value, you have to remove the
CMakeCache.txt file and reconfigure with CMake. And even then you might stumble on some issues when
reusing an existing build, because of an automoc bug in upstream CMake.
@@ -126,11 +139,11 @@ Compiling for a target architecture that's different than the host requires one
host. This "host build" is needed because the process of building Qt involves the compilation of
intermediate code generator tools, that in turn are called to produce source code that needs to be
compiled into the final libraries. These tools are built using Qt itself and they need to run on the
-machine you're building on, regardless of the architecure you are targeting.
+machine you're building on, regardless of the architecture you are targeting.
Build Qt regularly for your host system and install it into a directory of your choice using the
``CMAKE_INSTALL_PREFIX`` variable. You are free to disable the build of tests and examples by
-passing ``-DBUILD_EXAMPLES=OFF`` and ``-DBUILD_TESTING=OFF``.
+passing ``-DQT_BUILD_EXAMPLES=OFF`` and ``-DQT_BUILD_TESTS=OFF``.
With this installation of Qt in place, which contains all tools needed, we can proceed to create a
new build of Qt that is cross-compiled to the target architecture of choice. You may proceed by
@@ -156,22 +169,29 @@ The specified path needs to point to a directory that contains an installed host
In order to cross-compile Qt to Android, you need a host build (see instructions above) and an
Android build. In addition, it is necessary to install the Android NDK.
-The environment for Android can be set up using the following steps:
+The following CMake variables are required for an Android build:
+ * `ANDROID_SDK_ROOT` must point to where the Android SDK is installed
+ * `CMAKE_TOOLCHAIN_FILE` must point to the toolchain file that comes with the NDK
+ * `QT_HOST_PATH` must point to a host installation of Qt
- * Set the ``ANDROID_NDK_HOME`` environment variable to the path where you have installed the Android NDK.
- * Set the ``ANDROID_SDK_HOME`` environment variable to the path where you have installed the Android SDK.
+Call CMake with the following arguments:
+`-DCMAKE_TOOLCHAIN_FILE=<path/to/ndk>/build/cmake/android.toolchain.cmake -DQT_HOST_PATH=/path/to/your/host/build -DANDROID_SDK_ROOT=<path/to/sdk> -DCMAKE_INSTALL_PREFIX=$INSTALL_PATH`
-When running cmake in qtbase, pass
-``-DCMAKE_TOOLCHAIN_FILE=$ANDROID_NDK_HOME/build/cmake/android.toolchain.cmake -DQT_HOST_PATH=/path/to/your/host/build -DANDROID_SDK_ROOT=$ANDROID_SDK_HOME -DCMAKE_INSTALL_PREFIX=$INSTALL_PATH``
+The toolchain file is usually located below the NDK's root at "build/cmake/android.toolchain.cmake".
+Instead of specifying the toolchain file you may specify `ANDROID_NDK_ROOT` instead.
+This variable is exclusively used for auto-detecting the toolchain file.
+
+In a recent SDK installation, the NDK is located in a subdirectory "ndk_bundle" below the SDK's root
+directory. In that situation you may omit `ANDROID_NDK_ROOT` and `CMAKE_TOOLCHAIN_FILE`.
If you don't supply the configuration argument ``-DANDROID_ABI=...``, it will default to
``armeabi-v7a``. To target other architectures, use one of the following values:
- * arm64: ``-DANDROID_ABI=arm64-v8``
+ * arm64: ``-DANDROID_ABI=arm64-v8a``
* x86: ``-DANDROID_ABI=x86``
* x86_64: ``-DANDROID_ABI=x86_64``
-By default we set the android API level to 21. Should you need to change this supply the following
-configuration argument to the above CMake call: ``-DANDROID_NATIVE_API_LEVEL=${API_LEVEL}``
+By default we set the android API level to 23. Should you need to change this supply the following
+configuration argument to the above CMake call: ``-DANDROID_PLATFORM=android-${API_LEVEL}``.
### Cross compiling for iOS
@@ -180,13 +200,13 @@ In order to cross-compile Qt to iOS, you need a host macOS build.
When running cmake in qtbase, pass
``-DCMAKE_SYSTEM_NAME=iOS -DQT_HOST_PATH=/path/to/your/host/build -DCMAKE_INSTALL_PREFIX=$INSTALL_PATH``
-If you don't supply the configuration argument ``-DQT_UIKIT_SDK=...``, it will default to
-``iphonesimulator``. To target another SDK / device type, use one of the following values:
- * iphonesimulator: ``-DQT_UIKIT_SDK=iphonesimulator``
- * iphoneos: ``-DQT_UIKIT_SDK=iphoneos``
- * simulator_and_device: ``-DQT_FORCE_SIMULATOR_AND_DEVICE=ON -DQT_UIKIT_SDK=``
+If you don't supply the configuration argument ``-DQT_APPLE_SDK=...``, CMake will build a
+multi-arch simulator_and_device iOS build.
+To target another SDK / device type, use one of the following values:
+ * iphonesimulator: ``-DQT_APPLE_SDK=iphonesimulator``
+ * iphoneos: ``-DQT_APPLE_SDK=iphoneos``
-Depending on what value you pass to ``-DQT_UIKIT_SDK=`` a list of target architectures is chosen
+Depending on what value you pass to ``-DQT_APPLE_SDK=`` a list of target architectures is chosen
by default:
* iphonesimulator: ``x86_64``
* iphoneos: ``arm64``
@@ -197,9 +217,6 @@ You can try choosing a different list of architectures by passing
Note that if you choose different architectures compared to the default ones, the build might fail.
Only do it if you know what you are doing.
-#### simulator_and_device special considerations
-To do a simulator_and_device build, an unreleased version of CMake is required (3.17.0).
-
# Debugging CMake files
CMake allows specifying the ``--trace`` and ``--trace-expand`` options, which work like
@@ -254,3 +271,63 @@ While the supporting code for building with vcpkg is still there, it is not test
| ``qtHaveModule(foo)`` | ``if(TARGET Qt::foo)`` |
| ``qtConfig(foo)`` | ``if (QT_FEATURE_foo)`` |
+
+# Convenience Scripts
+
+A Qt installation's bin directory contains a number of convenience scripts.
+
+## qt-cmake
+
+This is a wrapper around the CMake executable which passes a Qt-internal `CMAKE_TOOLCHAIN_FILE`. Use
+this to build projects against the installed Qt.
+
+To use a custom toolchain file, use `-DQT_CHAINLOAD_TOOLCHAIN_FILE=<file path>`.
+
+## qt-cmake-private
+
+The same as `qt-cmake`, but in addition, sets the CMake generator to Ninja.
+
+Example:
+
+```
+$ cd some/empty/directory
+$ ~/Qt/6.0.0/bin/qt-cmake-private ~/source/of/qtdeclarative -DFEATURE_qml_network=OFF
+$ cmake --build . && cmake --install .
+```
+
+## qt-configure-module
+
+Call the configure script for a single Qt module, doing a CMake build.
+
+Example:
+
+```
+$ cd some/empty/directory
+$ ~/Qt/6.0.0/bin/qt-configure-module ~/source/of/qtdeclarative -no-feature-qml-network
+$ cmake --build . && cmake --install .
+```
+
+## qt-cmake-standalone-test
+
+Build a single standalone test outside the Qt build.
+
+Example:
+
+```
+$ cd some/empty/directory
+$ ~/Qt/6.0.0/bin/qt-cmake-standalone-test ~/source/of/qtbase/test/auto/corelib/io/qprocess
+$ cmake --build .
+```
+
+## qt-cmake-create
+
+Generates a simple CMakeLists.txt based on source files in specified project directory.
+
+Example:
+
+```
+$ cd some/source/directory/
+$ qt-cmake-create
+$ qt-cmake -S . -B /build/directory
+$ cmake --build /build/directory
+```
diff --git a/cmake/configure-cmake-mapping.md b/cmake/configure-cmake-mapping.md
index 41ddec2960..d504bd8d4b 100644
--- a/cmake/configure-cmake-mapping.md
+++ b/cmake/configure-cmake-mapping.md
@@ -1,161 +1,173 @@
The following table describes the mapping of configure options to CMake arguments.
-Note that not everything is implemented in configure/configure.bat yet.
-The effort of this is tracked in QTBUG-85373 and QTBUG-85349.
| configure | cmake | Notes |
|---------------------------------------|---------------------------------------------------|-----------------------------------------------------------------|
| -prefix /opt/qt6 | -DCMAKE_INSTALL_PREFIX=/opt/qta6 | |
+| -no-prefix (only available in Qt6) | -DCMAKE_INSTALL_PREFIX=$PWD (with bash) | In Qt5 this was done by specifying -prefix $PWD |
+| or -DFEATURE_no_prefix=ON | |
| -extprefix /opt/qt6 | -DCMAKE_STAGING_PREFIX=/opt/qt6 | |
-| -hostprefix /where/ever | n/a | When cross-building Qt, we do not build for host system anymore |
-| -external-hostbindir /path/to/host/qt | -DQT_HOST_PATH=/path/to/host/qt | |
| -bindir <dir> | -DINSTALL_BINDIR=<dir> | similar for -headerdir -libdir and so on |
-| -host*dir <dir> | n/a | |
-| -help | | |
-| -verbose | | |
+| -hostdatadir <dir> | -DINSTALL_MKSPECSDIR=<dir> | |
+| -qt-host-path <dir> | -DQT_HOST_PATH=<dir> | |
+| -help | n/a | Handled by configure[.bat]. |
+| -verbose | --log-level=STATUS | Sets the CMake log level to STATUS. The default one is NOTICE. |
| -continue | | |
-| -redo | | |
+| -redo | n/a | Handled by configure[.bat]. |
| -recheck [test,...] | | |
| -feature-foo | -DFEATURE_foo=ON | |
| -no-feature-foo | -DFEATURE_foo=OFF | |
| -list-features | | At the moment: configure with cmake once, |
| | | then use ccmake or cmake-gui to inspect the features. |
-| -list-libraries | | |
-| -opensource | | |
-| -commercial | | |
-| -confirm-license | | |
-| -release | | |
-| -debug | | |
-| -debug-and-release | | |
-| -optimize-debug | | |
-| -optimize-size | | |
-| -optimized-tools | | |
-| -force-debug-info | | |
-| -separate-debug-info . | | |
-| -gdb-index | | |
-| -strip | | |
-| -gc-binaries | | |
-| -force-asserts | | |
-| -developer-build | | |
-| -shared | | |
-| -static | | |
-| -framework | | |
-| -platform <target> | | |
-| -xplatform <target> | -DQT_QMAKE_TARGET_MKSPEC=<target> | Only used for generating qmake-compatibility files. |
+| -opensource | n/a | |
+| -commercial | n/a | |
+| -confirm-license | n/a | |
+| -release | -DCMAKE_BUILD_TYPE=Release | |
+| -debug | -DCMAKE_BUILD_TYPE=Debug | |
+| -debug-and-release | -G "Ninja Multi-Config" | |
+| | -DCMAKE_CONFIGURATION_TYPES=Release;Debug | |
+| -optimize-debug | -DFEATURE_optimize_debug=ON | |
+| -optimize-size | -DFEATURE_optimize_size=ON | |
+| -optimized-tools | n/a | This affects only host tools. |
+| -force-debug-info | Use the RelWithDebInfo build config. | |
+| -separate-debug-info | -DFEATURE_separate_debug_info=ON | |
+| -gdb-index | -DFEATURE_enable_gdb_index=ON | |
+| -strip | cmake --install . --strip | This affects the install targets generated by qmake. |
+| -gc-binaries | -DFEATURE_gc_binaries=ON | |
+| -force-asserts | -DFEATURE_force_asserts=ON | |
+| -developer-build | -DFEATURE_developer_build=ON | |
+| -shared | -DBUILD_SHARED_LIBS=ON | |
+| -static | -DBUILD_SHARED_LIBS=OFF | |
+| -framework | -DFEATURE_framework=ON | |
+| -platform <target> | -DQT_QMAKE_TARGET_MKSPEC=<mkspec> | |
+| -xplatform <target> | -DQT_QMAKE_TARGET_MKSPEC=<mkspec> | Used for generating qmake-compatibility files. |
+| | | If passed 'macx-ios-clang', will configure an iOS build. |
| -device <name> | equivalent to -xplatform devices/<name> | |
| -device-option <key=value> | -DQT_QMAKE_DEVICE_OPTIONS=key1=value1;key2=value2 | Only used for generation qmake-compatibility files. |
| | | The device options are written into mkspecs/qdevice.pri. |
-| -appstore-compliant | | |
-| -qtnamespace <name> | | |
-| -qtlibinfix <infix> | | |
-| -qtlibinfix-plugins | | |
-| -testcocoon | | |
-| -gcov | | |
-| -trace [backend] | | |
-| -sanitize {address | | |
-| -coverage {trace-pc-gu | | |
-| -c++std <edition> | | |
-| -sse2 | | |
-| -sse3/-ssse3/-sse4.1/- | | |
-| -mips_dsp/-mips_dspr2 | | |
-| -qreal <type> | | |
-| -R <string> | | |
-| -rpath | | |
-| -reduce-exports | | |
-| -reduce-relocations | | |
+| -appstore-compliant | -DFEATURE_appstore_compliant=ON | |
+| -qtinlinenamespace | -DQT_INLINE_NAMESPACE=ON | Make the namespace specified by -qtnamespace an inline one. |
+| -qtnamespace <name> | -DQT_NAMESPACE=<name> | |
+| -qtlibinfix <infix> | -DQT_LIBINFIX=<infix> | |
+| -coverage <tool> | -DINPUT_coverage=<tool> | Enables code coverage using the specified tool. |
+| -gcov | -DINPUT_coverage=gcov | Enables code coverage using the gcov tool. |
+| -trace [backend] | -DINPUT_trace=yes or -DINPUT_trace=<backend> | |
+| | or -DFEATURE_<backend> | |
+| -sanitize address -sanitize undefined | -DFEATURE_sanitize_address=ON | Directly setting -DECM_ENABLE_SANITIZERS=foo is not supported |
+| | -DFEATURE_sanitize_undefined=ON | |
+| -c++std c++20 | -DFEATURE_cxx20=ON | |
+| -sse2/-sse3/-ssse3/-sse4.1 | -DFEATURE_sse4=ON | |
+| -mips_dsp/-mips_dspr2 | -DFEATURE_mips_dsp=ON | |
+| -qreal <type> | -DQT_COORD_TYPE=<type> | |
+| -R <string> | -DQT_EXTRA_RPATHS=path1;path2 | |
+| -rpath | negative CMAKE_SKIP_BUILD_RPATH | |
+| | negative CMAKE_SKIP_INSTALL_RPATH | |
+| | negative CMAKE_MACOSX_RPATH | |
+| -reduce-exports | -DFEATURE_reduce_exports=ON | |
+| -reduce-relocations | -DFEATURE_reduce_relocations=ON | |
| -plugin-manifests | | |
-| -static-runtime | | |
-| -pch | | |
-| -ltcg | | |
-| -linker [bfd,gold,lld] | | |
-| -incredibuild-xge | | |
+| -static-runtime | -DFEATURE_static_runtime=ON | |
+| -pch | -DBUILD_WITH_PCH=ON | |
+| -ltcg | -DCMAKE_INTERPROCEDURAL_OPTIMIZATION=ON or | |
+| | -DCMAKE_INTERPROCEDURAL_OPTIMIZATION_<CONFIG>=ON | |
+| -linker [bfd,gold,lld,mold] | -DINPUT_linker=<name> or | |
+| | -DFEATURE_use_<name>_linker=ON | |
+| -incredibuild-xge | n/a | This option enables remote distribution of Visual Studio |
+| | | custom build steps for moc, uic, and rcc. |
+| | | This lacks support in CMake. |
| -ccache | -DQT_USE_CCACHE=ON | |
-| -make-tool <tool> | n/a | |
-| -mp | n/a | |
+| -unity-build | -DQT_UNITY_BUILD=ON | |
+| -unity-build-batch-size <int> | -DQT_UNITY_BUILD_BATCH_SIZE=<int> | |
| -warnings-are-errors | -DWARNINGS_ARE_ERRORS=ON | |
-| -silent | | |
-| -sysroot <dir> | -DCMAKE_SYSROOT=<dir> | Should be provided by a toolchain file that's |
-| | | passed via -DCMAKE_TOOLCHAIN_FILE=<filename> |
-| -gcc-sysroot | | |
-| -pkg-config | | |
-| -D <string> | | |
-| -I <string> | | |
-| -L <string> | | |
-| -F <string> | | |
-| -sdk <sdk> | | |
-| -android-sdk path | | |
-| -android-ndk path | | |
-| -android-ndk-platform | | |
-| -android-ndk-host | | |
-| -android-abis | | |
-| -android-style-assets | | |
-| mponent selection: | | |
-| -skip <repo> | | |
-| -make <part> | | |
-| -nomake <part> | | |
-| -compile-examples | | |
-| -gui | | |
-| -widgets | | |
-| -no-dbus | | |
-| -dbus-linked | | |
-| -dbus-runtime | | |
-| -accessibility | | |
-| -skip <repo> | | |
-| -make <part> | | |
-| -nomake <part> | | |
-| -compile-examples | | |
-| -gui | | |
-| -widgets | | |
-| -no-dbus | | |
-| -dbus-linked | | |
-| -dbus-runtime | | |
-| -accessibility | | |
-| -doubleconversion | | |
-| -glib | | |
-| -eventfd | | |
-| -inotify | | |
-| -icu | | |
-| -pcre | | |
-| -pps | | |
-| -zlib | | |
-| -ssl | | |
-| -no-openssl | | |
-| -openssl-linked | | |
-| -openssl-runtime | | |
-| -schannel | | |
-| -securetransport | | |
-| -sctp | | |
-| -libproxy | | |
-| -system-proxies | | |
-| -cups | | |
-| -fontconfig | | |
-| -freetype | | |
-| -harfbuzz | | |
-| -gtk | | |
-| -lgmon | | |
-| -no-opengl | | |
-| -opengl <api> | | |
-| -opengles3 | | |
-| -egl | | |
-| -qpa <name> | | |
-| -xcb-xlib | | |
-| -direct2d | | |
-| -directfb | | |
-| -eglfs | | |
-| -gbm | | |
-| -kms | | |
-| -linuxfb | | |
-| -xcb | | |
-| -libudev | | |
-| -evdev | | |
-| -imf | | |
-| -libinput | | |
-| -mtdev | | |
-| -tslib | | |
-| -bundled-xcb-xinput | | |
-| -xkbcommon | | |
-| -gif | | |
-| -ico | | |
-| -libpng | | |
-| -libjpeg | | |
-| -sql-<driver> | | |
-| -sqlite | | |
+| -no-pkg-config | -DFEATURE_pkg_config=OFF | |
+| -vcpkg | -DQT_USE_VCPKG=ON | |
+| -D <string> | -DQT_EXTRA_DEFINES=<string1>;<string2> | |
+| -I <string> | -DQT_EXTRA_INCLUDEPATHS=<string1>;<string2> | |
+| -L <string> | -DQT_EXTRA_LIBDIRS=<string1>;<string2> | |
+| -F <string> | -DQT_EXTRA_FRAMEWORKPATHS=<string1>;<string2> | |
+| -sdk <sdk> | -DQT_APPLE_SDK=<value> | Should be provided a value like 'iphoneos' or 'iphonesimulator' |
+| | | If no value is provided, a simulator_and_device build is |
+| | | assumed. |
+| -android-sdk <path> | -DANDROID_SDK_ROOT=<path> | |
+| -android-ndk <path> | -DCMAKE_TOOLCHAIN_FILE=<toolchain file in NDK> | |
+| -android-ndk-platform android-23 | -DANDROID_PLATFORM=android-23 | |
+| -android-abis <abi_1>,...,<abi_n> | -DANDROID_ABI=<abi_1> | only one ABI can be specified |
+| -android-style-assets | -DFEATURE_android_style_assets=ON | |
+| -android-javac-source | -DQT_ANDROID_JAVAC_SOURCE=7 | Set the javac build source version. |
+| -android-javac-target | -DQT_ANDROID_JAVAC_TARGET=7 | Set the javac build target version. |
+| -skip <repo>,...,<repo_n> | -DBUILD_<repo>=OFF | |
+| -skip-tests <repo>,...,<repo_n> | -DQT_BUILD_TESTS_PROJECT_<repo>=OFF | |
+| -skip-examples <repo>,...,<repo_n> | -DQT_BUILD_EXAMPLES_PROJECT_<repo>=OFF | |
+| -submodules <repo>,...,<repo_n> | -DQT_BUILD_SUBMODULES=<repo>;...;<repo> | |
+| -make <part> | -DQT_BUILD_TESTS=ON | A way to turn on tools explicitly is missing. If tests/examples |
+| | -DQT_BUILD_EXAMPLES=ON | are enabled, you can disable their building as part of the |
+| | | 'all' target by also passing -DQT_BUILD_TESTS_BY_DEFAULT=OFF or |
+| | | -DQT_BUILD_EXAMPLES_BY_DEFAULT=OFF. Note that if you entirely |
+| | | disable tests/examples at configure time (by using |
+| | | -DQT_BUILD_TESTS=OFF or -DQT_BUILD_EXAMPLES=OFF) you can't then |
+| | | build them separately, after configuration. |
+| -nomake <part> | -DQT_BUILD_TESTS=OFF | A way to turn off tools explicitly is missing. |
+| | -DQT_BUILD_EXAMPLES=OFF | |
+| -install-examples-sources | -DQT_INSTALL_EXAMPLES_SOURCES=ON | |
+| -no-gui | -DFEATURE_gui=OFF | |
+| -no-widgets | -DFEATURE_widgets=OFF | |
+| -no-dbus | -DFEATURE_dbus=OFF | |
+| -dbus [linked/runtime] | -DINPUT_dbus=[linked/runtime] | |
+| -dbus-linked | -DINPUT_dbus=linked | |
+| -dbus-runtime | -DINPUT_dbus=runtime | |
+| -accessibility | -DFEATURE_accessibility=ON | |
+| -doubleconversion | -DFEATURE_doubleconversion=ON | |
+| | -DFEATURE_system_doubleconversion=ON/OFF | |
+| -glib | -DFEATURE_glib=ON | |
+| -inotify | -DFEATURE_inotify=ON | |
+| -icu | -DFEATURE_icu=ON | |
+| -pcre | -DFEATURE_pcre2=ON | |
+| -pcre [system/qt] | -DFEATURE_system_pcre2=ON/OFF | |
+| -pps | n/a | QNX feature. Not available for 6.0. |
+| -zlib [system/qt] | -DFEATURE_system_zlib=ON/OFF | |
+| -ssl | -DFEATURE_ssl=ON | |
+| -openssl [no/yes/linked/runtime] | -DINPUT_openssl=no/yes/linked/runtime | |
+| -openssl-linked | -DINPUT_openssl=linked | |
+| -openssl-runtime | -DINPUT_openssl=runtime | |
+| -schannel | -DFEATURE_schannel=ON | |
+| -securetransport | -DFEATURE_securetransport=ON | |
+| -sctp | -DFEATURE_sctp=ON | |
+| -libproxy | -DFEATURE_libproxy=ON | |
+| -system-proxies | -DFEATURE_system_proxies=ON | |
+| -cups | -DFEATURE_cups=ON | |
+| -fontconfig | -DFEATURE_fontconfig=ON | |
+| -freetype [no/qt/system] | -DFEATURE_freetype=ON/OFF | |
+| | -DFEATURE_system_freetype=ON/OFF | |
+| -harfbuzz [no/qt/system] | -DFEATURE_harfbuzz=ON | |
+| | -DFEATURE_system_harfbuzz=ON/OFF | |
+| -gtk | -DFEATURE_gtk3=ON | |
+| -lgmon | n/a | QNX-specific |
+| -no-opengl | -DINPUT_opengl=no | |
+| -opengl <api> | -DINPUT_opengl=<api> | |
+| -opengles3 | -DFEATURE_opengles3=ON | |
+| -egl | -DFEATURE_egl=ON | |
+| -qpa <name> | -DQT_QPA_DEFAULT_PLATFORM=<name> | |
+| -xcb-xlib | -DFEATURE_xcb_xlib=ON | |
+| -direct2d | -DFEATURE_direct2d=ON | |
+| -directfb | -DFEATURE_directfb=ON | |
+| -eglfs | -DFEATURE_eglfs=ON | |
+| -gbm | -DFEATURE_gbm=ON | |
+| -kms | -DFEATURE_kms=ON | |
+| -linuxfb | -DFEATURE_linuxfb=ON | |
+| -xcb | -DFEATURE_xcb=ON | |
+| -libudev | -DFEATURE_libudev=ON | |
+| -evdev | -DFEATURE_evdev=ON | |
+| -imf | n/a | QNX-specific |
+| -libinput | -DFEATURE_libinput=ON | |
+| -mtdev | -DFEATURE_mtdev=ON | |
+| -tslib | -DFEATURE_tslib=ON | |
+| -bundled-xcb-xinput | -DFEATURE_system_xcb_xinput=OFF | |
+| -xkbcommon | -DFEATURE_xkbcommon=ON | |
+| -gif | -DFEATURE_gif=ON | |
+| -ico | -DFEATURE_ico=ON | |
+| -libpng | -DFEATURE_png=ON | |
+| -libjpeg | -DFEATURE_jpeg=ON | |
+| -sql-<driver> | -DFEATURE_sql_<driver>=ON | |
+| -sqlite [qt/system] | -DFEATURE_system_sqlite=OFF/ON | |
+| -disable-deprecated-up-to <hex_version> | -DQT_DISABLE_DEPRECATED_UP_TO=<hex_version> | |
+| -mimetype-database-compression <type> | -DINPUT_mimetype_database_compression=<type> | Sets the compression type for mime type database. Supported |
+| | | types: gzip, zstd, none. |
diff --git a/cmake/ios/Info.plist.app.in b/cmake/ios/Info.plist.app.in
new file mode 100644
index 0000000000..2f13828213
--- /dev/null
+++ b/cmake/ios/Info.plist.app.in
@@ -0,0 +1,54 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>CFBundleInfoDictionaryVersion</key>
+ <string>6.0</string>
+
+ <key>CFBundlePackageType</key>
+ <string>APPL</string>
+
+ <key>CFBundleName</key>
+ <string>${MACOSX_BUNDLE_BUNDLE_NAME}</string>
+
+ <key>CFBundleDisplayName</key>
+ <string>${QT_INTERNAL_DOLLAR_VAR}{PRODUCT_NAME}</string>
+
+ <key>CFBundleIdentifier</key>
+ <string>${MACOSX_BUNDLE_GUI_IDENTIFIER}</string>
+
+ <key>CFBundleExecutable</key>
+ <string>${MACOSX_BUNDLE_EXECUTABLE_NAME}</string>
+
+ <key>CFBundleVersion</key>
+ <string>${MACOSX_BUNDLE_BUNDLE_VERSION}</string>
+
+ <key>CFBundleShortVersionString</key>
+ <string>${MACOSX_BUNDLE_SHORT_VERSION_STRING}</string>
+
+ <key>CFBundleIconFile</key>
+ <string>${MACOSX_BUNDLE_ICON_FILE}</string>
+
+ <key>CFBundleDevelopmentRegion</key>
+ <string>$(DEVELOPMENT_LANGUAGE)</string>
+ <key>CFBundleAllowMixedLocalizations</key>
+ <true/>
+
+ <key>LSRequiresIPhoneOS</key>
+ <true/>
+
+ <key>NOTE</key>
+ <string>This file was generated by Qt's default CMake support.</string>
+
+ <key>UILaunchStoryboardName</key>
+ <string>@qt_ios_launch_screen_plist_entry@</string>
+
+ <key>UISupportedInterfaceOrientations</key>
+ <array>
+ <string>UIInterfaceOrientationPortrait</string>
+ <string>UIInterfaceOrientationPortraitUpsideDown</string>
+ <string>UIInterfaceOrientationLandscapeLeft</string>
+ <string>UIInterfaceOrientationLandscapeRight</string>
+ </array>
+</dict>
+</plist>
diff --git a/cmake/ios/LaunchScreen.storyboard b/cmake/ios/LaunchScreen.storyboard
new file mode 100644
index 0000000000..83df24b618
--- /dev/null
+++ b/cmake/ios/LaunchScreen.storyboard
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="13142" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="01J-lp-oVM">
+ <dependencies>
+ <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="12042"/>
+ <capability name="Constraints with non-1.0 multipliers" minToolsVersion="5.1"/>
+ <capability name="Safe area layout guides" minToolsVersion="9.0"/>
+ <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
+ </dependencies>
+ <scenes>
+ <!--View Controller-->
+ <scene sceneID="EHf-IW-A2E">
+ <objects>
+ <viewController id="01J-lp-oVM" sceneMemberID="viewController">
+ <view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3">
+ <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
+ <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+ <color key="backgroundColor" systemColor="systemBackgroundColor"/>
+ <viewLayoutGuide key="safeArea" id="Bcu-3y-fUS"/>
+ </view>
+ </viewController>
+ <placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/>
+ </objects>
+ <point key="canvasLocation" x="53" y="375"/>
+ </scene>
+ </scenes>
+ <resources>
+ <systemColor name="systemBackgroundColor">
+ <color white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
+ </systemColor>
+ </resources>
+</document>
diff --git a/cmake/ios/PrivacyInfo.xcprivacy b/cmake/ios/PrivacyInfo.xcprivacy
new file mode 100644
index 0000000000..d75908da05
--- /dev/null
+++ b/cmake/ios/PrivacyInfo.xcprivacy
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>NSPrivacyTracking</key>
+ <false/>
+ <key>NSPrivacyCollectedDataTypes</key>
+ <array/>
+ <key>NSPrivacyTrackingDomains</key>
+ <array/>
+ <key>NSPrivacyAccessedAPITypes</key>
+ <array/>
+</dict>
+</plist>
diff --git a/cmake/macos/MacOSXBundleInfo.plist.in b/cmake/macos/Info.plist.app.in
index 99c314f428..c791521655 100644
--- a/cmake/macos/MacOSXBundleInfo.plist.in
+++ b/cmake/macos/Info.plist.app.in
@@ -18,14 +18,10 @@
<string>${MACOSX_BUNDLE_BUNDLE_VERSION}</string>
<key>CFBundleShortVersionString</key>
<string>${MACOSX_BUNDLE_SHORT_VERSION_STRING}</string>
- <key>CFBundleLongVersionString</key>
- <string>${MACOSX_BUNDLE_LONG_VERSION_STRING}</string>
<key>LSMinimumSystemVersion</key>
<string>${CMAKE_OSX_DEPLOYMENT_TARGET}</string>
- <key>CFBundleGetInfoString</key>
- <string>${MACOSX_BUNDLE_INFO_STRING}</string>
<key>NSHumanReadableCopyright</key>
<string>${MACOSX_BUNDLE_COPYRIGHT}</string>
@@ -33,7 +29,9 @@
<string>${MACOSX_BUNDLE_ICON_FILE}</string>
<key>CFBundleDevelopmentRegion</key>
- <string>English</string>
+ <string>en</string>
+ <key>CFBundleAllowMixedLocalizations</key>
+ <true/>
<key>NSPrincipalClass</key>
<string>NSApplication</string>
diff --git a/cmake/macos/PrivacyInfo.xcprivacy b/cmake/macos/PrivacyInfo.xcprivacy
new file mode 100644
index 0000000000..96aff954ea
--- /dev/null
+++ b/cmake/macos/PrivacyInfo.xcprivacy
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>NSPrivacyTracking</key>
+ <false/>
+ <key>NSPrivacyCollectedDataTypes</key>
+ <array/>
+ <key>NSPrivacyTrackingDomains</key>
+ <array/>
+</dict>
+</plist>
diff --git a/cmake/modulecppexports.h.in b/cmake/modulecppexports.h.in
new file mode 100644
index 0000000000..4d41a3a2a2
--- /dev/null
+++ b/cmake/modulecppexports.h.in
@@ -0,0 +1,50 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef @header_base_name_upper@_H
+#define @header_base_name_upper@_H
+
+#include <QtCore/qcompilerdetection.h>
+#include <QtCore/qtconfigmacros.h> // Q_@module_define_infix@_EXPORT
+#include <QtCore/qtdeprecationmarkers.h> // QT_IF_DEPRECATED_SINCE
+
+#if defined(QT_SHARED) || !defined(QT_STATIC)
+# if defined(QT_BUILD_@module_define_infix@_LIB)
+# define Q_@module_define_infix@_EXPORT Q_DECL_EXPORT
+# else
+# define Q_@module_define_infix@_EXPORT Q_DECL_IMPORT
+# endif
+#else
+# define Q_@module_define_infix@_EXPORT
+#endif
+
+#if !defined(QT_BUILD_@module_define_infix@_LIB) && !defined(QT_STATIC)
+/* outside library -> inline decl + defi */
+/* static builds treat everything as part of the library, so they never inline */
+# define QT_@module_define_infix@_INLINE_SINCE(major, minor) inline
+# define QT_@module_define_infix@_INLINE_IMPL_SINCE(major, minor) 1
+#elif defined(QT_@module_define_infix@_BUILD_REMOVED_API)
+/* inside library, inside removed_api.cpp:
+ * keep deprecated API -> non-inline decl;
+ * remove deprecated API -> inline decl;
+ * definition is always available */
+# define QT_@module_define_infix@_INLINE_SINCE(major, minor) \
+ QT_IF_DEPRECATED_SINCE(major, minor, inline, /* not inline */)
+# define QT_@module_define_infix@_INLINE_IMPL_SINCE(major, minor) 1
+#else
+/* inside library, outside removed_api.cpp:
+ * keep deprecated API -> non-inline decl, no defi;
+ * remove deprecated API -> inline decl, defi */
+# define QT_@module_define_infix@_INLINE_SINCE(major, minor) \
+ QT_IF_DEPRECATED_SINCE(major, minor, inline, /* not inline */)
+# define QT_@module_define_infix@_INLINE_IMPL_SINCE(major, minor) \
+ QT_IF_DEPRECATED_SINCE(major, minor, 1, 0)
+#endif
+
+#ifdef QT_@module_define_infix@_BUILD_REMOVED_API
+# define QT_@module_define_infix@_REMOVED_SINCE(major, minor) QT_DEPRECATED_SINCE(major, minor)
+#else
+# define QT_@module_define_infix@_REMOVED_SINCE(major, minor) 0
+#endif
+
+#endif // @header_base_name_upper@_H
diff --git a/cmake/platforms/FindIntegrityPlatformGraphics.cmake b/cmake/platforms/FindIntegrityPlatformGraphics.cmake
new file mode 100644
index 0000000000..7b03d7ae89
--- /dev/null
+++ b/cmake/platforms/FindIntegrityPlatformGraphics.cmake
@@ -0,0 +1,29 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+#.rst:
+# IntegrityPlatformGraphics
+# ---------
+find_package_handle_standard_args(IntegrityPlatformGraphics
+ FOUND_VAR
+ IntegrityPlatformGraphics_FOUND
+ REQUIRED_VARS
+ IntegrityPlatformGraphics_LIBRARY
+ IntegrityPlatformGraphics_INCLUDE_DIR
+)
+
+if(IntegrityPlatformGraphics_FOUND
+ AND NOT TARGET IntegrityPlatformGraphics::IntegrityPlatformGraphics)
+ add_library(IntegrityPlatformGraphics::IntegrityPlatformGraphics STATIC IMPORTED)
+ set_target_properties(IntegrityPlatformGraphics::IntegrityPlatformGraphics PROPERTIES
+ IMPORTED_LOCATION "${IntegrityPlatformGraphics_LIBRARY}"
+ INTERFACE_INCLUDE_DIRECTORIES "${IntegrityPlatformGraphics_INCLUDE_DIR}"
+ )
+ target_link_libraries(IntegrityPlatformGraphics::IntegrityPlatformGraphics
+ INTERFACE ${IntegrityPlatformGraphics_LIBRARIES_PACK})
+endif()
+
+mark_as_advanced(IntegrityPlatformGraphics_LIBRARY)
+
+# compatibility variables
+set(IntegrityPlatformGraphics_LIBRARIES ${IntegrityPlatformGraphics_LIBRARY})
diff --git a/cmake/platforms/Platform/Integrity.cmake b/cmake/platforms/Platform/Integrity.cmake
new file mode 100644
index 0000000000..0ad7fd1099
--- /dev/null
+++ b/cmake/platforms/Platform/Integrity.cmake
@@ -0,0 +1,11 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+# Custom platform module file for INTEGRITY.
+#
+# UNIX must be set here, because this variable is cleared after the toolchain file is loaded.
+#
+# Once the lowest CMake version we support ships an Integrity platform module,
+# we can remove this file.
+
+set(UNIX 1)
diff --git a/cmake/qbatchedtestrunner.in.cpp b/cmake/qbatchedtestrunner.in.cpp
new file mode 100644
index 0000000000..cc49b77e0a
--- /dev/null
+++ b/cmake/qbatchedtestrunner.in.cpp
@@ -0,0 +1,18 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include <QList>
+#include <QString>
+#include <QtTest/private/qtestcase_p.h>
+
+int main(int argc, char **argv)
+{
+ if (argc == 1) {
+ printf("%s\n", QTest::qGetTestCaseNames().join(
+ QStringLiteral(" ")).toStdString().c_str());
+ return 0;
+ }
+
+ const auto entryFunction = QTest::qGetTestCaseEntryFunction(QString::fromUtf8(argv[1]));
+ return entryFunction ? entryFunction(argc - 1, argv + 1) : -1;
+}
diff --git a/cmake/qt.toolchain.cmake.in b/cmake/qt.toolchain.cmake.in
index c4884e9dfa..15cf7a432e 100644
--- a/cmake/qt.toolchain.cmake.in
+++ b/cmake/qt.toolchain.cmake.in
@@ -1,27 +1,55 @@
-@init_platform@
+set(__qt_toolchain_used_variables
+ QT_CHAINLOAD_TOOLCHAIN_FILE
+ QT_TOOLCHAIN_INCLUDE_FILE
+ QT_TOOLCHAIN_RELOCATABLE_CMAKE_DIR
+ QT_TOOLCHAIN_RELOCATABLE_PREFIX
+ QT_ADDITIONAL_PACKAGES_PREFIX_PATH
+)
+@init_additional_used_variables@
-@init_qt_host_path@
-@init_qt_host_path_cmake_dir@
+# Make cache variables used by this toolchain file available to the
+# try_compile command that operates on sources files.
+list(APPEND CMAKE_TRY_COMPILE_PLATFORM_VARIABLES ${__qt_toolchain_used_variables})
+list(REMOVE_DUPLICATES CMAKE_TRY_COMPILE_PLATFORM_VARIABLES)
-@init_original_toolchain_file@
+# Turn the environment variables that are created at the end of this
+# file into proper variables. This is needed for try_compile calls
+# that operate on whole projects.
+if($ENV{_QT_TOOLCHAIN_VARS_INITIALIZED})
+ foreach(var ${__qt_toolchain_used_variables})
+ set(${var} "$ENV{_QT_TOOLCHAIN_${var}}")
+ endforeach()
+endif()
+@init_original_toolchain_file@
@init_vcpkg@
+@init_platform@
+
+if(NOT "${QT_CHAINLOAD_TOOLCHAIN_FILE}" STREQUAL "")
+ set(__qt_chainload_toolchain_file "${QT_CHAINLOAD_TOOLCHAIN_FILE}")
+endif()
if(__qt_chainload_toolchain_file)
get_filename_component(__qt_chainload_toolchain_file_real_path
"${__qt_chainload_toolchain_file}" REALPATH)
if(__qt_chainload_toolchain_file_real_path STREQUAL CMAKE_CURRENT_LIST_FILE)
message(FATAL_ERROR
- "Woah, the Qt toolchain file tried to include itself recusively! '${__qt_chainload_toolchain_file}' "
+ "Woah, the Qt toolchain file tried to include itself recursively! '${__qt_chainload_toolchain_file}' "
"Make sure to remove qtbase/CMakeCache.txt and reconfigure qtbase with 'cmake' "
"rather than 'qt-cmake', and then you can reconfigure your own project."
)
+ elseif(NOT EXISTS "${__qt_chainload_toolchain_file_real_path}")
+ message(WARNING "The toolchain file to be chainloaded "
+ "'${__qt_chainload_toolchain_file}' does not exist.")
else()
include("${__qt_chainload_toolchain_file}")
+ set(__qt_chainload_toolchain_file_included TRUE)
endif()
unset(__qt_chainload_toolchain_file)
endif()
+@init_post_chainload_toolchain@
+
# Compute dynamically the Qt installation prefix from the location of this file. This allows
# the usage of the toolchain file when the Qt installation is relocated.
get_filename_component(QT_TOOLCHAIN_RELOCATABLE_INSTALL_PREFIX
@@ -33,6 +61,7 @@ get_filename_component(QT_TOOLCHAIN_RELOCATABLE_INSTALL_PREFIX
# one level higher is what we're looking for.
get_filename_component(QT_TOOLCHAIN_RELOCATABLE_CMAKE_DIR "${CMAKE_CURRENT_LIST_DIR}/.." ABSOLUTE)
+# REROOT_PATH_ISSUE_MARKER
# There's a subdirectory check in cmake's cmFindCommon::RerootPaths() function, that doesn't handle
# the case of CMAKE_PREFIX_PATH == CMAKE_FIND_ROOT_PATH for a particular pair of entries.
# Instead of collapsing the search prefix (which is the case when one is a subdir of the other),
@@ -41,3 +70,98 @@ get_filename_component(QT_TOOLCHAIN_RELOCATABLE_CMAKE_DIR "${CMAKE_CURRENT_LIST_
list(PREPEND CMAKE_PREFIX_PATH "${QT_TOOLCHAIN_RELOCATABLE_CMAKE_DIR}")
list(PREPEND CMAKE_FIND_ROOT_PATH "${QT_TOOLCHAIN_RELOCATABLE_INSTALL_PREFIX}")
+# Let CMake load our custom platform modules.
+# CMake-provided platform modules take precedence.
+if(NOT QT_AVOID_CUSTOM_PLATFORM_MODULES)
+ list(PREPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/platforms")
+endif()
+
+# Handle packages located in QT_ADDITIONAL_PACKAGES_PREFIX_PATH when cross-compiling. Needed for
+# Conan.
+# We prepend to CMAKE_PREFIX_PATH so that a find_package(Qt6Foo) call works, without having to go
+# through the Qt6 umbrella package. The paths must end in lib/cmake to ensure the package is found.
+# See REROOT_PATH_ISSUE_MARKER.
+# We prepend to CMAKE_FIND_ROOT_PATH, due to the bug mentioned at REROOT_PATH_ISSUE_MARKER.
+#
+# Note that we don't handle QT_ADDITIONAL_HOST_PACKAGES_PREFIX_PATH here, because we would thwart
+# our efforts to not accidentally pick up host packages. For now, we say that
+# find_package(Qt6FooTools) is not supported, and people must use find_package(Qt6 COMPONENTS
+# FooTools) instead.
+set(__qt_toolchain_additional_packages_prefixes "")
+if(QT_ADDITIONAL_PACKAGES_PREFIX_PATH)
+ list(APPEND __qt_toolchain_additional_packages_prefixes
+ ${QT_ADDITIONAL_PACKAGES_PREFIX_PATH})
+endif()
+if(DEFINED ENV{QT_ADDITIONAL_PACKAGES_PREFIX_PATH}
+ AND NOT "$ENV{QT_ADDITIONAL_PACKAGES_PREFIX_PATH}" STREQUAL "")
+ set(__qt_env_additional_packages_prefixes $ENV{QT_ADDITIONAL_PACKAGES_PREFIX_PATH})
+ if(NOT CMAKE_HOST_WIN32)
+ string(REPLACE ":" ";" __qt_env_additional_packages_prefixes
+ "${__qt_env_additional_packages_prefixes}")
+ endif()
+ list(APPEND __qt_toolchain_additional_packages_prefixes
+ ${__qt_env_additional_packages_prefixes})
+ unset(__qt_env_additional_packages_prefixes)
+endif()
+
+if(__qt_toolchain_additional_packages_prefixes)
+ set(__qt_toolchain_additional_packages_root_paths "")
+ set(__qt_toolchain_additional_packages_prefix_paths "")
+
+ foreach(__qt_additional_path IN LISTS __qt_toolchain_additional_packages_prefixes)
+ file(TO_CMAKE_PATH "${__qt_additional_path}" __qt_additional_path)
+ get_filename_component(__qt_additional_path "${__qt_additional_path}" ABSOLUTE)
+ set(__qt_additional_path_lib_cmake "${__qt_additional_path}")
+ if(NOT __qt_additional_path_lib_cmake MATCHES "/lib/cmake$")
+ string(APPEND __qt_additional_path_lib_cmake "/lib/cmake")
+ endif()
+
+ list(APPEND __qt_toolchain_additional_packages_root_paths
+ "${__qt_additional_path}")
+ list(APPEND __qt_toolchain_additional_packages_prefix_paths
+ "${__qt_additional_path_lib_cmake}")
+ endforeach()
+ list(PREPEND CMAKE_PREFIX_PATH ${__qt_toolchain_additional_packages_prefix_paths})
+ list(PREPEND CMAKE_FIND_ROOT_PATH ${__qt_toolchain_additional_packages_root_paths})
+
+ unset(__qt_additional_path)
+ unset(__qt_additional_path_lib_cmake)
+ unset(__qt_toolchain_additional_packages_root_paths)
+ unset(__qt_toolchain_additional_packages_prefix_paths)
+endif()
+unset(__qt_toolchain_additional_packages_prefixes)
+
+# Allow customization of the toolchain file by placing an additional file next to it.
+set(__qt_toolchain_extra_file "${CMAKE_CURRENT_LIST_DIR}/qt.toolchain.extra.cmake")
+if(EXISTS "${__qt_toolchain_extra_file}")
+ include("${__qt_toolchain_extra_file}")
+endif()
+
+# Allow customization of the toolchain file by passing a path to an additional CMake file to be
+# included.
+if(QT_TOOLCHAIN_INCLUDE_FILE)
+ get_filename_component(__qt_toolchain_include_file_real_path
+ "${QT_TOOLCHAIN_INCLUDE_FILE}" REALPATH)
+ if(EXISTS "${__qt_toolchain_include_file_real_path}")
+ include("${__qt_toolchain_include_file_real_path}")
+ else()
+ message(WARNING "The passed extra toolchain file to be included does not exist: "
+ "${__qt_toolchain_include_file_real_path}")
+ endif()
+endif()
+
+# Store initial build type (if any is specified) to be read by QtBuildInternals.cmake when building
+# a Qt repo, standalone tests or a single test.
+if(DEFINED CACHE{CMAKE_BUILD_TYPE})
+ set(__qt_toolchain_cmake_build_type_before_project_call "${CMAKE_BUILD_TYPE}")
+endif()
+
+# Compile tests only see a restricted set of variables.
+# All cache variables, this toolchain file uses, must be made available to project-based
+# try_compile tests because this toolchain file will be included there too.
+if(NOT "$ENV{_QT_TOOLCHAIN_VARS_INITIALIZED}")
+ set(ENV{_QT_TOOLCHAIN_VARS_INITIALIZED} ON)
+ foreach(var ${__qt_toolchain_used_variables})
+ set(ENV{_QT_TOOLCHAIN_${var}} "${${var}}")
+ endforeach()
+endif()
diff --git a/cmake/tests/CMakeLists.txt b/cmake/tests/CMakeLists.txt
index 6b53c9703d..45523c2195 100644
--- a/cmake/tests/CMakeLists.txt
+++ b/cmake/tests/CMakeLists.txt
@@ -1,3 +1,6 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# These macros are inspired by ECM:
# a macro for tests that have a simple format where the name matches the
diff --git a/cmake/tests/features/CMakeLists.txt b/cmake/tests/features/CMakeLists.txt
index 0fff2b8be9..415accb04e 100644
--- a/cmake/tests/features/CMakeLists.txt
+++ b/cmake/tests/features/CMakeLists.txt
@@ -1,4 +1,7 @@
-cmake_minimum_required(VERSION 3.12.0)
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+cmake_minimum_required(VERSION 3.16)
project(FeaturesTest
VERSION 1.0.0
diff --git a/cmake/tests/features/configure.cmake b/cmake/tests/features/configure.cmake
index ace2b62450..fa68d8596e 100644
--- a/cmake/tests/features/configure.cmake
+++ b/cmake/tests/features/configure.cmake
@@ -1,3 +1,6 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
#### Features
# This belongs into gui, but the license check needs it here already.
diff --git a/cmake/tests/features/src/CMakeLists.txt b/cmake/tests/features/src/CMakeLists.txt
index bfb02be07d..a02fb1f581 100644
--- a/cmake/tests/features/src/CMakeLists.txt
+++ b/cmake/tests/features/src/CMakeLists.txt
@@ -1,3 +1,6 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
## Features from parent scope were inherited:
assert(QT_FEATURE_top_a STREQUAL "ON")
assert(QT_FEATURE_top_b STREQUAL "OFF")
diff --git a/cmake/tests/qt_make_output_file/CMakeLists.txt b/cmake/tests/qt_make_output_file/CMakeLists.txt
index 3620909494..5beecc6ec3 100644
--- a/cmake/tests/qt_make_output_file/CMakeLists.txt
+++ b/cmake/tests/qt_make_output_file/CMakeLists.txt
@@ -1,4 +1,7 @@
-cmake_minimum_required(VERSION 3.12.0)
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+cmake_minimum_required(VERSION 3.16)
project(QtMakeOutputFileTest
VERSION 1.0.0
diff --git a/cmake/tests/test.cmake b/cmake/tests/test.cmake
index 099f490c94..db55cc8842 100644
--- a/cmake/tests/test.cmake
+++ b/cmake/tests/test.cmake
@@ -1,3 +1,6 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# FAKE moc-ing:
set(QT_MOCSCANNER /usr/bin/true)
diff --git a/cmake/visionos/Info.plist.app.in b/cmake/visionos/Info.plist.app.in
new file mode 100644
index 0000000000..7aa4698649
--- /dev/null
+++ b/cmake/visionos/Info.plist.app.in
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>CFBundleInfoDictionaryVersion</key>
+ <string>6.0</string>
+
+ <key>CFBundlePackageType</key>
+ <string>APPL</string>
+
+ <key>CFBundleName</key>
+ <string>${MACOSX_BUNDLE_BUNDLE_NAME}</string>
+
+ <key>CFBundleDisplayName</key>
+ <string>${QT_INTERNAL_DOLLAR_VAR}{PRODUCT_NAME}</string>
+
+ <key>CFBundleIdentifier</key>
+ <string>${MACOSX_BUNDLE_GUI_IDENTIFIER}</string>
+
+ <key>CFBundleExecutable</key>
+ <string>${MACOSX_BUNDLE_EXECUTABLE_NAME}</string>
+
+ <key>CFBundleVersion</key>
+ <string>${MACOSX_BUNDLE_BUNDLE_VERSION}</string>
+
+ <key>CFBundleShortVersionString</key>
+ <string>${MACOSX_BUNDLE_SHORT_VERSION_STRING}</string>
+
+ <key>CFBundleIconFile</key>
+ <string>${MACOSX_BUNDLE_ICON_FILE}</string>
+
+ <key>CFBundleDevelopmentRegion</key>
+ <string>$(DEVELOPMENT_LANGUAGE)</string>
+ <key>CFBundleAllowMixedLocalizations</key>
+ <true/>
+
+ <key>CFBundleSupportedPlatforms</key>
+ <array>
+ <string>XROS</string>
+ </array>
+</dict>
+</plist>
diff --git a/cmake/visionos/PrivacyInfo.xcprivacy b/cmake/visionos/PrivacyInfo.xcprivacy
new file mode 100644
index 0000000000..d75908da05
--- /dev/null
+++ b/cmake/visionos/PrivacyInfo.xcprivacy
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>NSPrivacyTracking</key>
+ <false/>
+ <key>NSPrivacyCollectedDataTypes</key>
+ <array/>
+ <key>NSPrivacyTrackingDomains</key>
+ <array/>
+ <key>NSPrivacyAccessedAPITypes</key>
+ <array/>
+</dict>
+</plist>