summaryrefslogtreecommitdiffstats
path: root/cmake
diff options
context:
space:
mode:
Diffstat (limited to 'cmake')
-rw-r--r--cmake/3rdparty/extra-cmake-modules/find-modules/FindEGL.cmake3
-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.cmake10
-rw-r--r--cmake/3rdparty/extra-cmake-modules/modules/ECMFindModuleHelpers.cmake4
-rw-r--r--cmake/3rdparty/extra-cmake-modules/qt_attribution.json2
-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.cmake3
-rw-r--r--cmake/FindDirectFB.cmake5
-rw-r--r--cmake/FindGLESv2.cmake3
-rw-r--r--cmake/FindGSSAPI.cmake27
-rw-r--r--cmake/FindGTK3.cmake5
-rw-r--r--cmake/FindInterbase.cmake4
-rw-r--r--cmake/FindLibb2.cmake5
-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.cmake57
-rw-r--r--cmake/FindOracle.cmake3
-rw-r--r--cmake/FindPPS.cmake11
-rw-r--r--cmake/FindPostgreSQL.cmake8
-rw-r--r--cmake/FindRenderDoc.cmake20
-rw-r--r--cmake/FindSlog2.cmake3
-rw-r--r--cmake/FindTslib.cmake5
-rw-r--r--cmake/FindWrapAtomic.cmake3
-rw-r--r--cmake/FindWrapBacktrace.cmake3
-rw-r--r--cmake/FindWrapBrotli.cmake9
-rw-r--r--cmake/FindWrapDBus1.cmake3
-rw-r--r--cmake/FindWrapDoubleConversion.cmake22
-rw-r--r--cmake/FindWrapFreetype.cmake3
-rw-r--r--cmake/FindWrapHarfbuzz.cmake3
-rw-r--r--cmake/FindWrapJpeg.cmake3
-rw-r--r--cmake/FindWrapOpenGL.cmake21
-rw-r--r--cmake/FindWrapOpenSSL.cmake3
-rw-r--r--cmake/FindWrapOpenSSLHeaders.cmake3
-rw-r--r--cmake/FindWrapPCRE2.cmake3
-rw-r--r--cmake/FindWrapPNG.cmake3
-rw-r--r--cmake/FindWrapResolv.cmake53
-rw-r--r--cmake/FindWrapRt.cmake27
-rw-r--r--cmake/FindWrapSystemDoubleConversion.cmake85
-rw-r--r--cmake/FindWrapSystemFreetype.cmake3
-rw-r--r--cmake/FindWrapSystemHarfbuzz.cmake43
-rw-r--r--cmake/FindWrapSystemJpeg.cmake3
-rw-r--r--cmake/FindWrapSystemMd4c.cmake45
-rw-r--r--cmake/FindWrapSystemPCRE2.cmake9
-rw-r--r--cmake/FindWrapSystemPNG.cmake3
-rw-r--r--cmake/FindWrapSystemZLIB.cmake3
-rw-r--r--cmake/FindWrapVulkan.cmake3
-rw-r--r--cmake/FindWrapVulkanHeaders.cmake23
-rw-r--r--cmake/FindWrapZLIB.cmake3
-rw-r--r--cmake/FindWrapZSTD.cmake16
-rw-r--r--cmake/FindXKB_COMMON_X11.cmake5
-rw-r--r--cmake/FindXRender.cmake5
-rw-r--r--cmake/Finddouble-conversion.cmake32
-rw-r--r--cmake/ModuleDescription.json.in10
-rw-r--r--cmake/PkgConfigLibrary.pc.in1
-rw-r--r--cmake/Qt3rdPartyLibraryConfig.cmake.in9
-rw-r--r--cmake/Qt3rdPartyLibraryHelpers.cmake52
-rw-r--r--cmake/QtAndroidHelpers.cmake201
-rw-r--r--cmake/QtAppHelpers.cmake61
-rw-r--r--cmake/QtAutoDetect.cmake541
-rw-r--r--cmake/QtAutoDetectHelpers.cmake487
-rw-r--r--cmake/QtAutogenHelpers.cmake54
-rw-r--r--cmake/QtBaseCMakeTesting.cmake3
-rw-r--r--cmake/QtBaseConfigureTests.cmake77
-rw-r--r--cmake/QtBaseGlobalTargets.cmake249
-rw-r--r--cmake/QtBaseHelpers.cmake222
-rw-r--r--cmake/QtBaseTopLevelHelpers.cmake96
-rw-r--r--cmake/QtBuild.cmake598
-rw-r--r--cmake/QtBuildHelpers.cmake458
-rw-r--r--cmake/QtBuildInformation.cmake146
-rw-r--r--cmake/QtBuildInternals/QtBuildInternalsConfig.cmake1261
-rw-r--r--cmake/QtBuildInternals/QtStandaloneTestTemplateProject/CMakeLists.txt29
-rw-r--r--cmake/QtBuildInternals/QtStandaloneTestTemplateProject/Main.cmake17
-rw-r--r--cmake/QtBuildInternalsExtra.cmake.in95
-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.cmake53
-rw-r--r--cmake/QtCMakePackageVersionFile.cmake.in15
-rw-r--r--cmake/QtCMakeVersionHelpers.cmake26
-rw-r--r--cmake/QtCompilerFlags.cmake18
-rw-r--r--cmake/QtCompilerOptimization.cmake82
-rw-r--r--cmake/QtConfig.cmake.in175
-rw-r--r--cmake/QtConfigDependencies.cmake.in66
-rw-r--r--cmake/QtConfigExtras.cmake.in5
-rw-r--r--cmake/QtConfigureTimeExecutableCMakeLists.txt.in26
-rw-r--r--cmake/QtCopyFileIfDifferent.cmake3
-rw-r--r--cmake/QtDbusHelpers.cmake11
-rw-r--r--cmake/QtDeferredDependenciesHelpers.cmake3
-rw-r--r--cmake/QtDocsHelpers.cmake47
-rw-r--r--cmake/QtExecutableHelpers.cmake420
-rw-r--r--cmake/QtFeature.cmake350
-rw-r--r--cmake/QtFeatureCommon.cmake3
-rw-r--r--cmake/QtFindPackageHelpers.cmake210
-rw-r--r--cmake/QtFindWrapConfigExtra.cmake.in3
-rw-r--r--cmake/QtFindWrapHelper.cmake3
-rw-r--r--cmake/QtFinishPkgConfigFile.cmake3
-rw-r--r--cmake/QtFinishPrlFile.cmake32
-rw-r--r--cmake/QtFlagHandlingHelpers.cmake366
-rw-r--r--cmake/QtFrameworkHelpers.cmake139
-rw-r--r--cmake/QtGenerateExtPri.cmake3
-rw-r--r--cmake/QtGenerateLibHelpers.cmake3
-rw-r--r--cmake/QtGenerateLibPri.cmake3
-rw-r--r--cmake/QtGenerateVersionScript.cmake15
-rw-r--r--cmake/QtGlobalStateHelpers.cmake23
-rw-r--r--cmake/QtHeadersClean.cmake250
-rw-r--r--cmake/QtHostInfoConfig.cmake.in3
-rw-r--r--cmake/QtInitProject.cmake214
-rw-r--r--cmake/QtInstallHelpers.cmake122
-rw-r--r--cmake/QtInstallPaths.cmake.in16
-rw-r--r--cmake/QtInternalTargets.cmake168
-rw-r--r--cmake/QtJavaHelpers.cmake14
-rw-r--r--cmake/QtLalrHelpers.cmake19
-rw-r--r--cmake/QtMkspecHelpers.cmake146
-rw-r--r--cmake/QtModuleConfig.cmake.in42
-rw-r--r--cmake/QtModuleDependencies.cmake.in99
-rw-r--r--cmake/QtModuleHeadersCheck.cmake34
-rw-r--r--cmake/QtModuleHelpers.cmake784
-rw-r--r--cmake/QtModuleToolsConfig.cmake.in19
-rw-r--r--cmake/QtModuleToolsDependencies.cmake.in3
-rw-r--r--cmake/QtModuleToolsVersionlessTargets.cmake.in3
-rw-r--r--cmake/QtNoLinkTargetHelpers.cmake5
-rw-r--r--cmake/QtPkgConfigHelpers.cmake17
-rw-r--r--cmake/QtPlatformAndroid.cmake18
-rw-r--r--cmake/QtPlatformSupport.cmake8
-rw-r--r--cmake/QtPlatformTargetHelpers.cmake24
-rw-r--r--cmake/QtPluginConfig.cmake.in5
-rw-r--r--cmake/QtPluginDependencies.cmake.in36
-rw-r--r--cmake/QtPluginHelpers.cmake275
-rw-r--r--cmake/QtPlugins.cmake.in71
-rw-r--r--cmake/QtPostProcess.cmake5
-rw-r--r--cmake/QtPostProcessHelpers.cmake194
-rw-r--r--cmake/QtPrecompiledHeadersHelpers.cmake7
-rw-r--r--cmake/QtPriHelpers.cmake112
-rw-r--r--cmake/QtPrlHelpers.cmake18
-rw-r--r--cmake/QtProcessConfigureArgs.cmake213
-rw-r--r--cmake/QtProperties.cmake13
-rw-r--r--cmake/QtPublicAppleHelpers.cmake954
-rw-r--r--cmake/QtPublicCMakeHelpers.cmake482
-rw-r--r--cmake/QtPublicCMakeVersionHelpers.cmake3
-rw-r--r--cmake/QtPublicDependencyHelpers.cmake293
-rw-r--r--cmake/QtPublicExternalProjectHelpers.cmake86
-rw-r--r--cmake/QtPublicFinalizerHelpers.cmake3
-rw-r--r--cmake/QtPublicFindPackageHelpers.cmake3
-rw-r--r--cmake/QtPublicPluginHelpers.cmake184
-rw-r--r--cmake/QtPublicTargetHelpers.cmake29
-rw-r--r--cmake/QtPublicTestHelpers.cmake108
-rw-r--r--cmake/QtPublicToolHelpers.cmake75
-rw-r--r--cmake/QtPublicWalkLibsHelpers.cmake28
-rw-r--r--cmake/QtPublicWasmToolchainHelpers.cmake41
-rw-r--r--cmake/QtQmakeHelpers.cmake43
-rw-r--r--cmake/QtResourceHelpers.cmake21
-rw-r--r--cmake/QtRpathHelpers.cmake57
-rw-r--r--cmake/QtSanitizerHelpers.cmake35
-rw-r--r--cmake/QtScopeFinalizerHelpers.cmake5
-rw-r--r--cmake/QtSeparateDebugInfo.Info.plist.in5
-rw-r--r--cmake/QtSeparateDebugInfo.cmake21
-rw-r--r--cmake/QtSetup.cmake330
-rw-r--r--cmake/QtSimdHelpers.cmake15
-rw-r--r--cmake/QtSingleRepoTargetSetBuildHelpers.cmake3
-rw-r--r--cmake/QtStandaloneTestsConfig.cmake.in10
-rw-r--r--cmake/QtSyncQtHelpers.cmake471
-rw-r--r--cmake/QtTargetHelpers.cmake897
-rw-r--r--cmake/QtTestHelpers.cmake862
-rw-r--r--cmake/QtToolHelpers.cmake529
-rw-r--r--cmake/QtToolchainHelpers.cmake90
-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.cmake103
-rw-r--r--cmake/QtWrapperScriptHelpers.cmake210
-rw-r--r--cmake/QtWriteArgsFile.cmake62
-rw-r--r--cmake/README.md32
-rw-r--r--cmake/configure-cmake-mapping.md34
-rw-r--r--cmake/ios/Info.plist.app.in54
-rw-r--r--cmake/ios/LaunchScreen.storyboard29
-rw-r--r--cmake/ios/MacOSXBundleInfo.plist.in55
-rw-r--r--cmake/ios/PrivacyInfo.xcprivacy14
-rw-r--r--cmake/macos/Info.plist.app.in (renamed from cmake/macos/MacOSXBundleInfo.plist.in)4
-rw-r--r--cmake/macos/PrivacyInfo.xcprivacy12
-rw-r--r--cmake/modulecppexports.h.in33
-rw-r--r--cmake/modulecppexports_p.h.in22
-rw-r--r--cmake/platforms/FindIntegrityPlatformGraphics.cmake3
-rw-r--r--cmake/platforms/Platform/Integrity.cmake3
-rw-r--r--cmake/qbatchedtestrunner.in.cpp18
-rw-r--r--cmake/qt.toolchain.cmake.in73
-rw-r--r--cmake/tests/CMakeLists.txt3
-rw-r--r--cmake/tests/features/CMakeLists.txt3
-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.txt3
-rw-r--r--cmake/tests/test.cmake3
-rw-r--r--cmake/visionos/Info.plist.app.in42
-rw-r--r--cmake/visionos/PrivacyInfo.xcprivacy14
201 files changed, 14040 insertions, 5665 deletions
diff --git a/cmake/3rdparty/extra-cmake-modules/find-modules/FindEGL.cmake b/cmake/3rdparty/extra-cmake-modules/find-modules/FindEGL.cmake
index 0733f1f702..9ac8e2fa0c 100644
--- a/cmake/3rdparty/extra-cmake-modules/find-modules/FindEGL.cmake
+++ b/cmake/3rdparty/extra-cmake-modules/find-modules/FindEGL.cmake
@@ -128,7 +128,8 @@ check_cxx_source_compiles("
#include <EGL/egl.h>
int main(int, char **) {
- EGLint x = 0; EGLDisplay dpy = 0; EGLContext ctx = 0;
+ [[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/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 dcdb8621d3..15610587bd 100644
--- a/cmake/3rdparty/extra-cmake-modules/modules/ECMEnableSanitizers.cmake
+++ b/cmake/3rdparty/extra-cmake-modules/modules/ECMEnableSanitizers.cmake
@@ -158,7 +158,15 @@ 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 MATCHES "Clang")
string(REPLACE "-Wl,--no-undefined" "" CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS}")
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 941fb9ea11..1839af3690 100644
--- a/cmake/3rdparty/extra-cmake-modules/qt_attribution.json
+++ b/cmake/3rdparty/extra-cmake-modules/qt_attribution.json
@@ -9,7 +9,7 @@
"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/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 e5b81cc9a5..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
# ---------
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 6d7147f563..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
diff --git a/cmake/FindGSSAPI.cmake b/cmake/FindGSSAPI.cmake
index 6ea36a08ff..44594941e3 100644
--- a/cmake/FindGSSAPI.cmake
+++ b/cmake/FindGSSAPI.cmake
@@ -1,7 +1,10 @@
+# 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)
+ pkg_check_modules(PC_GSSAPI QUIET "mit-krb5-gssapi")
endif()
find_path(GSSAPI_INCLUDE_DIRS
@@ -9,11 +12,24 @@ find_path(GSSAPI_INCLUDE_DIRS
HINTS ${PC_GSSAPI_INCLUDEDIR}
)
+# 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
- gss # solaris
- gssapi_krb5
+ ${gssapi_library_names}
HINTS ${PC_GSSAPI_LIBDIR}
)
@@ -40,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 6f5bd98675..221d5a34d1 100644
--- a/cmake/FindGTK3.cmake
+++ b/cmake/FindGTK3.cmake
@@ -1,10 +1,13 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
find_package(PkgConfig QUIET)
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 "gtk+-3.0${__gtk3_required_version}" IMPORTED_TARGET)
+pkg_check_modules(GTK3 IMPORTED_TARGET "gtk+-3.0${__gtk3_required_version}")
if (NOT TARGET PkgConfig::GTK3)
set(GTK3_FOUND 0)
diff --git a/cmake/FindInterbase.cmake b/cmake/FindInterbase.cmake
index 22f866d826..95b735e56a 100644
--- a/cmake/FindInterbase.cmake
+++ b/cmake/FindInterbase.cmake
@@ -1,3 +1,6 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
#.rst:
# FindInterbase
# ---------
@@ -21,6 +24,7 @@
find_path(Interbase_INCLUDE_DIR
NAMES ibase.h
HINTS ${Interbase_INCLUDEDIR}
+ PATH_SUFFIXES firebird
)
find_library(Interbase_LIBRARY
diff --git a/cmake/FindLibb2.cmake b/cmake/FindLibb2.cmake
index 0e4a7f2a95..bf51c37aed 100644
--- a/cmake/FindLibb2.cmake
+++ b/cmake/FindLibb2.cmake
@@ -1,3 +1,6 @@
+# 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.
@@ -10,7 +13,7 @@ endif()
find_package(PkgConfig QUIET)
if(PkgConfig_FOUND)
- pkg_check_modules(Libb2 libb2 IMPORTED_TARGET)
+ pkg_check_modules(Libb2 IMPORTED_TARGET "libb2")
if (TARGET PkgConfig::Libb2)
add_library(Libb2::Libb2 INTERFACE IMPORTED)
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 a069a5eb12..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,17 +39,39 @@
# ``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_DIR
NAMES mysql.h
- HINTS ${PC_MySQL_INCLUDEDIR}
+ HINTS "${MySQL_include_dir_hints}"
PATH_SUFFIXES mysql mariadb)
find_library(MySQL_LIBRARY
+ NO_PACKAGE_ROOT_PATH
NAMES libmysql mysql mysqlclient libmariadb mariadb
- HINTS ${PC_MySQL_LIBDIR})
+ 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_LIBRARY MySQL_INCLUDE_DIR)
@@ -41,6 +84,10 @@ if(MySQL_FOUND)
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()
diff --git a/cmake/FindOracle.cmake b/cmake/FindOracle.cmake
index 38860abb8c..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
# ---------
diff --git a/cmake/FindPPS.cmake b/cmake/FindPPS.cmake
index fdcc87fa37..099019243c 100644
--- a/cmake/FindPPS.cmake
+++ b/cmake/FindPPS.cmake
@@ -1,3 +1,6 @@
+# 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.
@@ -15,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
index 6e27f5d8f5..a61bec9337 100644
--- a/cmake/FindPostgreSQL.cmake
+++ b/cmake/FindPostgreSQL.cmake
@@ -1,5 +1,6 @@
-# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
-# file Copyright.txt or https://cmake.org/licensing for details.
+# Copyright (C) 2000-2022 Kitware, Inc. and Contributors.
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
#[=======================================================================[.rst:
FindPostgreSQL
@@ -98,6 +99,9 @@ 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}")
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 1e3e264816..18c10773f9 100644
--- a/cmake/FindSlog2.cmake
+++ b/cmake/FindSlog2.cmake
@@ -1,3 +1,6 @@
+# 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.
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 006be0ed8f..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)
diff --git a/cmake/FindWrapBacktrace.cmake b/cmake/FindWrapBacktrace.cmake
index 6a6264099a..3cc5748dd1 100644
--- a/cmake/FindWrapBacktrace.cmake
+++ b/cmake/FindWrapBacktrace.cmake
@@ -1,3 +1,6 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
if(TARGET WrapBacktrace::WrapBacktrace)
set(WrapBacktrace_FOUND ON)
return()
diff --git a/cmake/FindWrapBrotli.cmake b/cmake/FindWrapBrotli.cmake
index bc8e058f99..e2d7b564f6 100644
--- a/cmake/FindWrapBrotli.cmake
+++ b/cmake/FindWrapBrotli.cmake
@@ -1,3 +1,6 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
if(TARGET WrapBrotli::WrapBrotliDec)
set(WrapBrotli_FOUND ON)
return()
@@ -19,21 +22,21 @@ if (unofficial-brotli_FOUND)
else()
find_package(PkgConfig QUIET)
if (PKG_CONFIG_FOUND)
- pkg_check_modules(libbrotlidec QUIET libbrotlidec IMPORTED_TARGET)
+ 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 libbrotlienc IMPORTED_TARGET)
+ 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 libbrotlicommon IMPORTED_TARGET)
+ 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)
diff --git a/cmake/FindWrapDBus1.cmake b/cmake/FindWrapDBus1.cmake
index e227d224e0..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
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
index 194296e3a6..5714c1dc34 100644
--- a/cmake/FindWrapJpeg.cmake
+++ b/cmake/FindWrapJpeg.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_jpeg
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 7b6dccb1d2..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)
diff --git a/cmake/FindWrapOpenSSLHeaders.cmake b/cmake/FindWrapOpenSSLHeaders.cmake
index afaf77ac48..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)
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 95be415b50..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)
@@ -18,17 +21,31 @@ if(LIBRT)
endif()
check_cxx_source_compiles("
-#include <unistd.h>
#include <time.h>
+#include <unistd.h>
int main(int, char **) {
- timespec ts; clock_gettime(CLOCK_REALTIME, &ts);
-}" HAVE_GETTIME)
+ 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)
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 2cf6caca19..d0c27a9f0f 100644
--- a/cmake/FindWrapSystemFreetype.cmake
+++ b/cmake/FindWrapSystemFreetype.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 WrapSystemFreetype::WrapSystemFreetype)
diff --git a/cmake/FindWrapSystemHarfbuzz.cmake b/cmake/FindWrapSystemHarfbuzz.cmake
index 3cb44aa766..07b3405bc0 100644
--- a/cmake/FindWrapSystemHarfbuzz.cmake
+++ b/cmake/FindWrapSystemHarfbuzz.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 WrapSystemHarfbuzz::WrapSystemHarfbuzz)
@@ -28,22 +31,38 @@ if(harfbuzz_FOUND AND TARGET "${__harfbuzz_target_name}")
endif()
if(__harfbuzz_broken_config_file OR NOT __harfbuzz_found)
- list(PREPEND WrapSystemHarfbuzz_REQUIRED_VARS HARFBUZZ_LIBRARIES HARFBUZZ_INCLUDE_DIRS)
-
find_package(PkgConfig QUIET)
- pkg_check_modules(PC_HARFBUZZ harfbuzz IMPORTED_TARGET)
+ 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()
find_path(HARFBUZZ_INCLUDE_DIRS
- NAMES harfbuzz/hb.h
- HINTS ${PC_HARFBUZZ_INCLUDEDIR})
+ NAMES harfbuzz/hb.h
+ ${__harfbuzz_find_include_dirs_hints})
find_library(HARFBUZZ_LIBRARIES
- NAMES harfbuzz
- HINTS ${PC_HARFBUZZ_LIBDIR})
+ NAMES harfbuzz
+ ${__harfbuzz_find_library_hints})
- set(__harfbuzz_target_name "PkgConfig::PC_HARFBUZZ")
- set(__harfbuzz_found TRUE)
- if(PC_HARFBUZZ_VERSION)
- set(WrapSystemHarfbuzz_VERSION "${PC_HARFBUZZ_VERSION}")
+ 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()
@@ -57,6 +76,8 @@ if(WrapSystemHarfbuzz_FOUND)
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)
diff --git a/cmake/FindWrapSystemJpeg.cmake b/cmake/FindWrapSystemJpeg.cmake
index 2853654ea1..16a9e5ab23 100644
--- a/cmake/FindWrapSystemJpeg.cmake
+++ b/cmake/FindWrapSystemJpeg.cmake
@@ -1,3 +1,6 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
if(TARGET WrapSystemJpeg::WrapSystemJpeg)
set(WrapSystemJpeg_FOUND TRUE)
return()
diff --git a/cmake/FindWrapSystemMd4c.cmake b/cmake/FindWrapSystemMd4c.cmake
index ea691a4590..5ac3ded975 100644
--- a/cmake/FindWrapSystemMd4c.cmake
+++ b/cmake/FindWrapSystemMd4c.cmake
@@ -1,24 +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)
-find_package(md4c CONFIG)
+ # 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()
-# 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::md4c)
- add_library(md4c::md4c INTERFACE IMPORTED)
- target_link_libraries(md4c::md4c INTERFACE md4c)
+ if(md4c_VERSION)
+ set(WrapSystemMd4c_VERSION "${md4c_VERSION}")
+ endif()
endif()
-if(TARGET md4c::md4c)
+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::md4c)
+ target_link_libraries(WrapSystemMd4c::WrapSystemMd4c
+ INTERFACE "${__md4c_target_name}")
endif()
-if(TARGET WrapSystemMd4c::WrapSystemMd4c)
- set(WrapSystemMd4c_FOUND TRUE)
-endif()
+unset(__md4c_found)
+unset(__md4c_target_name)
diff --git a/cmake/FindWrapSystemPCRE2.cmake b/cmake/FindWrapSystemPCRE2.cmake
index 92c6e2a167..61e0d2fb5b 100644
--- a/cmake/FindWrapSystemPCRE2.cmake
+++ b/cmake/FindWrapSystemPCRE2.cmake
@@ -1,12 +1,15 @@
+# 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 COMPONENTS 16BIT ${${CMAKE_FIND_PACKAGE_NAME}_FIND_VERSION} CONFIG QUIET)
+find_package(PCRE2 ${${CMAKE_FIND_PACKAGE_NAME}_FIND_VERSION} COMPONENTS 16BIT QUIET)
-set(__pcre2_target_name "PCRE2::pcre2-16")
+set(__pcre2_target_name "PCRE2::16BIT")
if(PCRE2_FOUND AND TARGET "${__pcre2_target_name}")
# Hunter case.
set(__pcre2_found TRUE)
@@ -19,7 +22,7 @@ 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)
+ pkg_check_modules(PC_PCRE2 QUIET "libpcre2-16")
find_path(PCRE2_INCLUDE_DIRS
NAMES pcre2.h
diff --git a/cmake/FindWrapSystemPNG.cmake b/cmake/FindWrapSystemPNG.cmake
index 372a064ff4..967ccc5c02 100644
--- a/cmake/FindWrapSystemPNG.cmake
+++ b/cmake/FindWrapSystemPNG.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 WrapSystemPNG::WrapSystemPNG)
diff --git a/cmake/FindWrapSystemZLIB.cmake b/cmake/FindWrapSystemZLIB.cmake
index c109a598be..5db43db626 100644
--- a/cmake/FindWrapSystemZLIB.cmake
+++ b/cmake/FindWrapSystemZLIB.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 WrapSystemZLIB::WrapSystemZLIB)
diff --git a/cmake/FindWrapVulkan.cmake b/cmake/FindWrapVulkan.cmake
index 38cf3ea417..843ca4c202 100644
--- a/cmake/FindWrapVulkan.cmake
+++ b/cmake/FindWrapVulkan.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 WrapVulkan::WrapVulkan)
diff --git a/cmake/FindWrapVulkanHeaders.cmake b/cmake/FindWrapVulkanHeaders.cmake
index ac2c912a56..92510ae000 100644
--- a/cmake/FindWrapVulkanHeaders.cmake
+++ b/cmake/FindWrapVulkanHeaders.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 WrapVulkanHeaders::WrapVulkanHeaders)
@@ -45,6 +48,26 @@ if(Vulkan_INCLUDE_DIR)
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()
diff --git a/cmake/FindWrapZLIB.cmake b/cmake/FindWrapZLIB.cmake
index ecb0070f81..6cf60fab9f 100644
--- a/cmake/FindWrapZLIB.cmake
+++ b/cmake/FindWrapZLIB.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_zlib
diff --git a/cmake/FindWrapZSTD.cmake b/cmake/FindWrapZSTD.cmake
index e619d78c86..fb424236b8 100644
--- a/cmake/FindWrapZSTD.cmake
+++ b/cmake/FindWrapZSTD.cmake
@@ -1,3 +1,6 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
#.rst:
# FindZstd
# ---------
@@ -25,10 +28,10 @@ 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_static)
- set(zstdtargetsuffix "_static")
- else()
+ if(TARGET zstd::libzstd_shared)
set(zstdtargetsuffix "_shared")
+ else()
+ set(zstdtargetsuffix "_static")
endif()
if(NOT TARGET WrapZSTD::WrapZSTD)
add_library(WrapZSTD::WrapZSTD INTERFACE IMPORTED)
@@ -37,7 +40,7 @@ if(TARGET zstd::libzstd_static OR TARGET zstd::libzstd_shared)
endif()
else()
find_package(PkgConfig QUIET)
- pkg_check_modules(PC_ZSTD QUIET libzstd)
+ pkg_check_modules(PC_ZSTD QUIET "libzstd")
find_path(ZSTD_INCLUDE_DIRS
NAMES zstd.h
@@ -56,9 +59,12 @@ else()
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 PC_ZSTD_VERSION)
+ VERSION_VAR WrapZSTD_VERSION)
if(WrapZSTD_FOUND AND NOT TARGET WrapZSTD::WrapZSTD)
add_library(WrapZSTD::WrapZSTD UNKNOWN IMPORTED)
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/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 6aae9a4a59..93f9a5ed25 100644
--- a/cmake/ModuleDescription.json.in
+++ b/cmake/ModuleDescription.json.in
@@ -1,11 +1,13 @@
{
- "module_name": "${target}",
- "version": "${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
index 609346cb39..9393cec0c5 100644
--- a/cmake/PkgConfigLibrary.pc.in
+++ b/cmake/PkgConfigLibrary.pc.in
@@ -1,6 +1,7 @@
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@>
diff --git a/cmake/Qt3rdPartyLibraryConfig.cmake.in b/cmake/Qt3rdPartyLibraryConfig.cmake.in
index 3f59d212d8..869c67443f 100644
--- a/cmake/Qt3rdPartyLibraryConfig.cmake.in
+++ b/cmake/Qt3rdPartyLibraryConfig.cmake.in
@@ -1,3 +1,6 @@
+# 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@)
@@ -20,7 +23,11 @@ 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
index 1db4683c69..924db182be 100644
--- a/cmake/Qt3rdPartyLibraryHelpers.cmake
+++ b/cmake/Qt3rdPartyLibraryHelpers.cmake
@@ -4,6 +4,7 @@ macro(qt_internal_get_add_library_option_args option_args)
STATIC
MODULE
INTERFACE
+ NO_UNITY_BUILD
)
endmacro()
@@ -14,12 +15,12 @@ endmacro()
# 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)
- qt_parse_all_arguments(arg "qt_internal_add_common_qt_library_helper"
+ cmake_parse_arguments(PARSE_ARGV 1 arg
"${option_args}"
""
""
- ${ARGN}
)
+ _qt_internal_validate_all_args_are_parsed(arg)
if(arg_SHARED)
set(arg_SHARED SHARED)
@@ -50,6 +51,11 @@ function(qt_internal_add_common_qt_library_helper target)
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()
@@ -67,12 +73,13 @@ function(qt_internal_add_cmake_library target)
${__default_public_args}
)
- qt_parse_all_arguments(arg "qt_add_cmake_library"
+ cmake_parse_arguments(PARSE_ARGV 1 arg
"${option_args}"
"${single_args}"
"${multi_args}"
- ${ARGN}
)
+ _qt_internal_validate_all_args_are_parsed(arg)
+ _qt_internal_validate_no_unity_build(arg)
qt_remove_args(library_helper_args
ARGS_TO_REMOVE
@@ -102,6 +109,8 @@ function(qt_internal_add_cmake_library 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
@@ -117,6 +126,7 @@ function(qt_internal_add_cmake_library target)
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()
@@ -139,12 +149,13 @@ function(qt_internal_add_3rdparty_library target)
${__default_public_args}
)
- qt_parse_all_arguments(arg "qt_internal_add_3rdparty_library"
+ cmake_parse_arguments(PARSE_ARGV 1 arg
"${library_option_args};${option_args}"
"${single_args}"
"${multi_args}"
- ${ARGN}
)
+ _qt_internal_validate_all_args_are_parsed(arg)
+ _qt_internal_validate_no_unity_build(arg)
qt_remove_args(library_helper_args
ARGS_TO_REMOVE
@@ -164,7 +175,22 @@ function(qt_internal_add_3rdparty_library target)
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})
@@ -177,7 +203,6 @@ function(qt_internal_add_3rdparty_library target)
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
)
set_property(TARGET "${target}"
@@ -224,6 +249,7 @@ function(qt_internal_add_3rdparty_library target)
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)
@@ -284,6 +310,7 @@ function(qt_internal_add_3rdparty_library target)
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}"
)
@@ -294,6 +321,12 @@ function(qt_internal_add_3rdparty_library target)
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)
@@ -327,12 +360,13 @@ function(qt_internal_add_3rdparty_header_module target)
set(multi_args
EXTERNAL_HEADERS
)
- qt_parse_all_arguments(arg "qt_internal_add_header_module"
+ cmake_parse_arguments(PARSE_ARGV 1 arg
"${option_args}"
"${single_args}"
"${multi_args}"
- ${ARGN}
)
+ _qt_internal_validate_all_args_are_parsed(arg)
+
qt_internal_add_module(${target}
INTERNAL_MODULE
HEADER_MODULE
diff --git a/cmake/QtAndroidHelpers.cmake b/cmake/QtAndroidHelpers.cmake
index 49c384f698..0743fe41a9 100644
--- a/cmake/QtAndroidHelpers.cmake
+++ b/cmake/QtAndroidHelpers.cmake
@@ -1,88 +1,92 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
#
# 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_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."
-)
+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)
@@ -127,8 +131,9 @@ function(qt_internal_android_dependencies_content target file_content_out)
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")
+ # 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()
@@ -139,8 +144,10 @@ function(qt_internal_android_dependencies_content target file_content_out)
if (init_class)
set(init_class "initClass=\"${init_class}\"")
endif()
- file(TO_NATIVE_PATH ${bundle_file} jar_bundle_native)
- string(APPEND file_contents "<jar bundling=\"1\" file=\"${jar_bundle_native}\" ${init_class} />\n")
+ # 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()
@@ -152,8 +159,9 @@ function(qt_internal_android_dependencies_content target file_content_out)
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")
+ # 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()
@@ -163,19 +171,23 @@ function(qt_internal_android_dependencies_content target file_content_out)
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}\"")
+ # 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()
- file(TO_NATIVE_PATH ${lib_file} lib_file_native)
- string(APPEND file_contents "<lib file=\"${lib_file_native}\" ${lib_replacement} />\n")
+ # 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)
- file(TO_NATIVE_PATH ${bundled_file} file_native)
- string(APPEND file_contents "<bundled file=\"${file_native}\" />\n")
+ # 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()
@@ -241,7 +253,8 @@ function(qt_internal_android_dependencies target)
# Module plugins
if(module_plugin_types)
foreach(plugin IN LISTS module_plugin_types)
- string(APPEND file_contents "<bundled file=\"plugins/${plugin}\" />\n")
+ string(APPEND file_contents
+ "<bundled file=\"${INSTALL_PLUGINSDIR}/${plugin}\" type=\"plugin_dir\"/>\n")
endforeach()
endif()
diff --git a/cmake/QtAppHelpers.cmake b/cmake/QtAppHelpers.cmake
index 719b9d4793..c0ad53ab9e 100644
--- a/cmake/QtAppHelpers.cmake
+++ b/cmake/QtAppHelpers.cmake
@@ -1,12 +1,20 @@
+# 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)
- qt_parse_all_arguments(arg
- "qt_internal_add_app"
- "NO_INSTALL;INSTALL_VERSIONED_LINK"
+ 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}"
- ${ARGN})
+ "${__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})
@@ -21,29 +29,53 @@ function(qt_internal_add_app target)
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}
- LIBRARIES ${arg_LIBRARIES} Qt::PlatformAppInternal
+ ${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}"
+ 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}")
@@ -53,7 +85,7 @@ function(qt_internal_add_app target)
# 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
+ # 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)
@@ -62,7 +94,8 @@ function(qt_internal_add_app target)
# Install versioned link if requested.
if(NOT arg_NO_INSTALL AND arg_INSTALL_VERSIONED_LINK)
- qt_internal_install_versioned_link("${arg_INSTALL_DIR}" ${target})
+ qt_internal_install_versioned_link(WORKING_DIRECTORY "${arg_INSTALL_DIR}"
+ TARGETS ${target})
endif()
qt_add_list_file_finalizer(qt_internal_finalize_app ${target})
@@ -75,7 +108,7 @@ function(qt_internal_get_title_case value out_var)
endif()
string(SUBSTRING "${value}" 0 1 first_char)
string(TOUPPER "${first_char}" first_char_upper)
- string(SUBSTRING "${target}" 1 -1 rest_of_value)
+ 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()
diff --git a/cmake/QtAutoDetect.cmake b/cmake/QtAutoDetect.cmake
index 3731707f88..464e8e900b 100644
--- a/cmake/QtAutoDetect.cmake
+++ b/cmake/QtAutoDetect.cmake
@@ -1,538 +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_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()
-
-include("${CMAKE_CURRENT_LIST_DIR}/QtPublicWasmToolchainHelpers.cmake")
-function(qt_auto_detect_wasm)
- if("${QT_QMAKE_TARGET_MKSPEC}" STREQUAL "wasm-emscripten")
- 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)
-
- # 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_ensure_static_qt_config()
-
- __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_cmake_generator)
- if(NOT CMAKE_GENERATOR MATCHES "Ninja" AND NOT QT_SILENCE_CMAKE_GENERATOR_WARNING)
- message(WARNING
- "The officially supported CMake generator for building Qt is Ninja. "
- "You are using: '${CMAKE_GENERATOR}' instead. "
- "Thus, you might encounter issues. Use at your own risk.")
- 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(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)
- 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(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 "")
-
- qt_internal_ensure_static_qt_config()
-
- # 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)
- 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 "13.0")
- elseif(CMAKE_SYSTEM_NAME STREQUAL watchOS)
- set(version "6.0")
- elseif(CMAKE_SYSTEM_NAME STREQUAL tvOS)
- set(version "13.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.")
-
- set(device_names "iOS" "watchOS" "tvOS")
- list(LENGTH CMAKE_OSX_ARCHITECTURES arch_count)
- if(NOT CMAKE_SYSTEM_NAME IN_LIST device_names AND 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()
- endif()
-endfunction()
-
-function(qt_auto_detect_macos_universal)
- set(device_names "iOS" "watchOS" "tvOS")
- if(APPLE AND NOT CMAKE_SYSTEM_NAME IN_LIST device_names)
- list(LENGTH CMAKE_OSX_ARCHITECTURES arch_count)
-
- 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_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()
-
-# 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_cmake_generator()
-qt_auto_detect_cyclic_toolchain()
-qt_auto_detect_cmake_config()
-qt_auto_detect_darwin()
-qt_auto_detect_macos_universal()
-qt_auto_detect_ios()
-qt_auto_detect_android()
-qt_auto_detect_vcpkg()
-qt_auto_detect_pch()
-qt_auto_detect_wasm()
-qt_auto_detect_win32_arm()
-qt_auto_detect_linux_x86()
-qt_auto_detect_integrity()
+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
index a583af568f..029a709e90 100644
--- a/cmake/QtAutogenHelpers.cmake
+++ b/cmake/QtAutogenHelpers.cmake
@@ -1,3 +1,6 @@
+# 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)
@@ -36,8 +39,7 @@ function(qt_enable_autogen_tool target tool enable)
# 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_GADGET_EXPORT;Q_NAMESPACE;Q_NAMESPACE_EXPORT;Q_ENUM_NS")
-
+ 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)
@@ -58,7 +60,8 @@ 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})
+ 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})
@@ -75,14 +78,23 @@ endfunction()
# Complete manual moc invocation with full control.
# Use AUTOMOC whenever possible.
-# 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.
+# 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"
+ "FLAGS;INCLUDE_DIRECTORIES;INCLUDE_DIRECTORY_TARGETS;DEFINITIONS;TARGETS"
${ARGN})
set(moc_files)
set(metatypes_json_list)
@@ -91,7 +103,7 @@ function(qt_manual_moc result)
"${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_file "${outfile}_parameters$<$<BOOL:$<CONFIG>>:_$<CONFIG>>")
set(moc_parameters ${arg_FLAGS} -o "${outfile}" "${infile}")
foreach(dir IN ITEMS ${arg_INCLUDE_DIRECTORIES})
@@ -99,7 +111,7 @@ function(qt_manual_moc result)
"-I\n${dir}")
endforeach()
- foreach(dep IN ITEMS ${arg_INCLUDE_DIRECTORY_TARGETS})
+ 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>>")
@@ -125,6 +137,30 @@ function(qt_manual_moc result)
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")
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 e337a43111..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,10 +12,14 @@ 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(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:\n${flags_indented}")
+ "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
@@ -55,8 +62,13 @@ function(qt_run_config_test_architecture)
endif()
message(STATUS "Extracting architecture info from ${_arch_file}.")
+ 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)
@@ -66,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}")
@@ -108,41 +120,38 @@ 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\"")
-
- # 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)
- set(CMAKE_REQUIRED_LINK_OPTIONS ${linker_flags})
- endif()
-
- 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)
- set(HAVE_LD_VERSION_SCRIPT OFF)
- endif()
# Also makes no sense with MSVC-style command-line
- if(MSVC)
+ 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)
@@ -191,7 +200,7 @@ 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}\"")
@@ -199,8 +208,8 @@ function(qt_internal_print_cmake_darwin_info)
if(DEFINED CACHE{QT_IS_MACOS_UNIVERSAL})
message(STATUS "QT_IS_MACOS_UNIVERSAL: \"${QT_IS_MACOS_UNIVERSAL}\"")
endif()
- if(QT_UIKIT_SDK)
- message(STATUS "QT_UIKIT_SDK: \"${QT_UIKIT_SDK}\"")
+ 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)
diff --git a/cmake/QtBaseGlobalTargets.cmake b/cmake/QtBaseGlobalTargets.cmake
index c20066204d..1e604559ed 100644
--- a/cmake/QtBaseGlobalTargets.cmake
+++ b/cmake/QtBaseGlobalTargets.cmake
@@ -1,3 +1,6 @@
+# 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})
@@ -60,12 +63,8 @@ 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")
-include(QtToolchainHelpers)
qt_internal_create_toolchain_file()
-include(QtWrapperScriptHelpers)
-qt_internal_create_wrapper_scripts()
-
## 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
@@ -87,17 +86,19 @@ include("${CMAKE_CURRENT_SOURCE_DIR}/configure.cmake")
qt_internal_get_first_osx_arch(__qt_osx_first_arch)
set(__qt_apple_silicon_arches "arm64;arm64e")
-if((UIKIT AND NOT QT_UIKIT_SDK)
- OR (MACOS AND QT_IS_MACOS_UNIVERSAL
- AND __qt_osx_first_arch IN_LIST __qt_apple_silicon_arches))
- set(QT_FORCE_FEATURE_sse2 ON CACHE INTERNAL "Force enable sse2 due to platform requirements.")
+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")
+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
@@ -117,6 +118,9 @@ qt_generate_global_module_pri_file()
qt_generate_global_device_pri_file()
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)
@@ -128,8 +132,8 @@ target_include_directories(GlobalConfigPrivate INTERFACE
$<INSTALL_INTERFACE:${INSTALL_INCLUDEDIR}/QtCore/${PROJECT_VERSION}/QtCore>
)
add_library(Qt::GlobalConfigPrivate ALIAS GlobalConfigPrivate)
+add_library(${QT_CMAKE_EXPORT_NAMESPACE}::GlobalConfigPrivate ALIAS GlobalConfigPrivate)
-include(QtPlatformTargetHelpers)
qt_internal_setup_public_platform_target()
# defines PlatformCommonInternal PlatformModuleInternal PlatformPluginInternal PlatformToolInternal
@@ -155,9 +159,10 @@ 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)
@@ -167,6 +172,11 @@ qt_internal_get_computed_min_cmake_version_for_using_qt(computed_min_version_for
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(
@@ -175,6 +185,8 @@ configure_package_config_file(
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"
@@ -191,96 +203,48 @@ qt_internal_write_qt_package_version_file(
"${__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/PkgConfigLibrary.pc.in
- cmake/Qt3rdPartyLibraryConfig.cmake.in
- cmake/Qt3rdPartyLibraryHelpers.cmake
- cmake/QtAndroidHelpers.cmake
- cmake/QtAppHelpers.cmake
- cmake/QtAutogenHelpers.cmake
- cmake/QtBuild.cmake
- cmake/QtBuildInformation.cmake
- cmake/QtCMakeHelpers.cmake
- cmake/QtCMakeVersionHelpers.cmake
- cmake/QtCMakePackageVersionFile.cmake.in
- cmake/QtCompilerFlags.cmake
- cmake/QtCompilerOptimization.cmake
- cmake/QtConfigDependencies.cmake.in
- cmake/QtDeferredDependenciesHelpers.cmake
- cmake/QtDbusHelpers.cmake
- cmake/QtDocsHelpers.cmake
- cmake/QtExecutableHelpers.cmake
- cmake/QtFileConfigure.txt.in
- cmake/QtFindPackageHelpers.cmake
- cmake/QtFindWrapConfigExtra.cmake.in
- cmake/QtFindWrapHelper.cmake
- cmake/QtFinishPkgConfigFile.cmake
- cmake/QtFinishPrlFile.cmake
- cmake/QtFlagHandlingHelpers.cmake
- cmake/QtFrameworkHelpers.cmake
- cmake/QtGenerateExtPri.cmake
- cmake/QtGenerateLibHelpers.cmake
- cmake/QtGenerateLibPri.cmake
- cmake/QtGlobalStateHelpers.cmake
- cmake/QtHeadersClean.cmake
- cmake/QtInstallHelpers.cmake
- cmake/QtJavaHelpers.cmake
- cmake/QtLalrHelpers.cmake
- cmake/QtModuleConfig.cmake.in
- cmake/QtModuleDependencies.cmake.in
- cmake/QtModuleHelpers.cmake
- cmake/QtModuleToolsConfig.cmake.in
- cmake/QtModuleToolsDependencies.cmake.in
- cmake/QtModuleToolsVersionlessTargets.cmake.in
- cmake/QtNoLinkTargetHelpers.cmake
- cmake/QtPkgConfigHelpers.cmake
- cmake/QtPlatformAndroid.cmake
- cmake/QtPlatformSupport.cmake
- cmake/QtPluginConfig.cmake.in
- cmake/QtPluginDependencies.cmake.in
- cmake/QtPluginHelpers.cmake
- cmake/QtPlugins.cmake.in
- cmake/QtPostProcess.cmake
- cmake/QtPostProcessHelpers.cmake
- cmake/QtPrecompiledHeadersHelpers.cmake
- cmake/QtPriHelpers.cmake
- cmake/QtPrlHelpers.cmake
- cmake/QtPlatformTargetHelpers.cmake
- cmake/QtProcessConfigureArgs.cmake
- cmake/QtQmakeHelpers.cmake
- cmake/QtResourceHelpers.cmake
- cmake/QtRpathHelpers.cmake
- cmake/QtSanitizerHelpers.cmake
- cmake/QtScopeFinalizerHelpers.cmake
- cmake/QtSeparateDebugInfo.Info.plist.in
- cmake/QtSeparateDebugInfo.cmake
- cmake/QtSetup.cmake
- cmake/QtSimdHelpers.cmake
- cmake/QtSingleRepoTargetSetBuildHelpers.cmake
- cmake/QtStandaloneTestsConfig.cmake.in
- cmake/QtSyncQtHelpers.cmake
- cmake/QtTargetHelpers.cmake
- cmake/QtTestHelpers.cmake
- cmake/QtToolchainHelpers.cmake
- cmake/QtToolHelpers.cmake
- cmake/QtWasmHelpers.cmake
- cmake/QtWrapperScriptHelpers.cmake
- cmake/QtWriteArgsFile.cmake
- cmake/modulecppexports.h.in
- cmake/modulecppexports_p.h.in
+ ${__private_files}
DESTINATION "${__GlobalConfig_install_dir}"
)
@@ -314,40 +278,32 @@ if(QT_WILL_INSTALL)
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_cmake_helpers
- cmake/QtCopyFileIfDifferent.cmake
- cmake/QtFeature.cmake
- cmake/QtFeatureCommon.cmake
- cmake/QtPublicCMakeHelpers.cmake
- cmake/QtPublicCMakeVersionHelpers.cmake
- cmake/QtPublicFinalizerHelpers.cmake
- cmake/QtPublicPluginHelpers.cmake
- cmake/QtPublicTargetHelpers.cmake
- cmake/QtPublicToolHelpers.cmake
- cmake/QtPublicWalkLibsHelpers.cmake
- cmake/QtPublicFindPackageHelpers.cmake
- cmake/QtPublicDependencyHelpers.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.
- cmake/QtPublicWasmToolchainHelpers.cmake
+set(__public_files
+ ${__qt_cmake_public_helpers}
+ ${__qt_public_files_to_install}
)
-qt_copy_or_install(FILES ${__public_cmake_helpers} DESTINATION "${__GlobalConfig_install_dir}")
+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_cmake_helper ${__public_cmake_helpers})
- file(COPY "${_public_cmake_helper}" DESTINATION "${__GlobalConfig_build_dir}")
+ foreach(_public_file ${__public_files})
+ file(COPY "${_public_file}" DESTINATION "${__GlobalConfig_build_dir}")
endforeach()
endif()
-# 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
@@ -363,6 +319,11 @@ 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
)
# In prefix builds we also need to copy the files into the build config directory, so that the
@@ -373,20 +334,56 @@ if(QT_WILL_INSTALL)
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(MACOS)
- qt_copy_or_install(FILES
- cmake/macos/MacOSXBundleInfo.plist.in
- DESTINATION "${__GlobalConfig_install_dir}/macos"
+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}"
)
-elseif(IOS)
- qt_copy_or_install(FILES
- cmake/ios/MacOSXBundleInfo.plist.in
- cmake/ios/LaunchScreen.storyboard
- DESTINATION "${__GlobalConfig_install_dir}/ios"
+ # 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.
@@ -394,6 +391,6 @@ 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/wasm/wasmtestrunner/qt-wasmtestrunner.py"
- DESTINATION "${__qt_libexec_install_dir}")
+ 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 1859981399..ee24ba188e 100644
--- a/cmake/QtBuild.cmake
+++ b/cmake/QtBuild.cmake
@@ -1,596 +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 "^\.\./")
- # 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()
-
-# 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()
-
-# 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"
- "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_DATADIR}/modules"
- "Module description files directory")
-
-if(NOT "${CMAKE_STAGING_PREFIX}" STREQUAL "")
- set(QT_STAGING_PREFIX "${CMAKE_STAGING_PREFIX}")
-else()
- set(QT_STAGING_PREFIX "${CMAKE_INSTALL_PREFIX}")
-endif()
-
-if(PROJECT_NAME STREQUAL "QtBase")
- set(QT_COORD_TYPE double CACHE STRING "Type of qreal")
-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)
-
-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")
-
-# 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()
-
-# 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}")
-
-function(qt_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_wrap_tool_command
- # instead.
-endfunction()
-qt_setup_tool_path_command()
-
-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(bindir "${QT_BUILD_INTERNALS_RELOCATABLE_INSTALL_PREFIX}/${INSTALL_BINDIR}")
- file(TO_NATIVE_PATH "${bindir}" bindir)
- set(tool_command_wrapper_path "${QT_BUILD_DIR}/${INSTALL_LIBEXECDIR}/qt_setup_tool_path.bat")
- file(WRITE "${tool_command_wrapper_path}" "@echo off
-set PATH=${bindir};%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()
-qt_internal_generate_tool_command_wrapper()
-
-# Platform define path, etc.
-if(WIN32)
- set(QT_DEFAULT_PLATFORM_DEFINITIONS WIN32 _ENABLE_EXTENDED_ALIGNED_STORAGE)
- if(CMAKE_SIZEOF_VOID_P EQUAL 8)
- list(APPEND QT_DEFAULT_PLATFORM_DEFINITIONS WIN64 _WIN64)
- endif()
- if(MSVC)
- if (CLANG)
- set(QT_DEFAULT_MKSPEC win32-clang-msvc)
- elseif(CMAKE_SYSTEM_PROCESSOR STREQUAL "arm64")
- set(QT_DEFAULT_MKSPEC win32-arm64-msvc)
- else()
- set(QT_DEFAULT_MKSPEC win32-msvc)
- endif()
- 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 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)
- set(QT_DEFAULT_MKSPEC wasm-emscripten)
-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 EXISTS "${QT_MKSPECS_DIR}/${QT_QMAKE_TARGET_MKSPEC}")
- file(GLOB known_platforms
- LIST_DIRECTORIES true
- RELATIVE "${QT_MKSPECS_DIR}"
- "${QT_MKSPECS_DIR}/*"
- )
- list(JOIN known_platforms "\n " known_platforms)
- message(FATAL_ERROR "Unknown platform ${QT_QMAKE_TARGET_MKSPEC}\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")
-
-set(QT_NAMESPACE "" CACHE STRING "Qt Namespace")
-
-include(QtGlobalStateHelpers)
-
-# 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)
-
-# 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:
-
-# Needed for qt_internal_add_link_flags_no_undefined.
-include(CheckCXXSourceCompiles)
-
-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
-)
-
-# 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
-)
-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}
-)
-
-option(QT_CMAKE_DEBUG_EXTEND_TARGET "Debug extend_target calls in Qt's build system" OFF)
-
-# Internal helpers available only while building Qt itself.
-include(Qt3rdPartyLibraryHelpers)
-include(QtAppHelpers)
-include(QtAutogenHelpers)
-include(QtCMakeHelpers)
-include(QtDeferredDependenciesHelpers)
-include(QtDbusHelpers)
-include(QtDocsHelpers)
-include(QtExecutableHelpers)
-include(QtFindPackageHelpers)
-include(QtFlagHandlingHelpers)
-include(QtFrameworkHelpers)
-include(QtInstallHelpers)
-include(QtLalrHelpers)
-include(QtModuleHelpers)
-include(QtNoLinkTargetHelpers)
-include(QtPluginHelpers)
-include(QtPrecompiledHeadersHelpers)
-include(QtPkgConfigHelpers)
-include(QtPriHelpers)
-include(QtPrlHelpers)
-include(QtQmakeHelpers)
-include(QtResourceHelpers)
-include(QtRpathHelpers)
-include(QtSanitizerHelpers)
-include(QtScopeFinalizerHelpers)
-include(QtSimdHelpers)
-include(QtSingleRepoTargetSetBuildHelpers)
-include(QtSyncQtHelpers)
-include(QtTargetHelpers)
-include(QtTestHelpers)
-include(QtToolHelpers)
-include(QtHeadersClean)
-include(QtJavaHelpers)
-
-if(ANDROID)
- include(QtAndroidHelpers)
-endif()
-
-# Helpers that are available in public projects and while building Qt itself.
-include(QtPublicCMakeHelpers)
-include(QtPublicPluginHelpers)
-include(QtPublicTargetHelpers)
-include(QtPublicWalkLibsHelpers)
-include(QtPublicFindPackageHelpers)
-include(QtPublicDependencyHelpers)
-include(QtPublicToolHelpers)
-
-# TODO: This block provides support for old variables. It should be removed once
-# we remove all references to these variables in other Qt module repos.
-# Prefer to use the provided commands to retrieve the relevant things instead.
-# We won't have the queried command when we get here for qtbase (it is
-# provided by the Core module), but we will for all other repos (which
-# is all we need).
-if(COMMAND _qt_internal_get_add_plugin_keywords)
- _qt_internal_get_add_plugin_keywords(
- __qt_public_add_plugin_option_args
- __qt_public_add_plugin_single_args
- __qt_public_add_plugin_multi_args
- )
- qt_internal_get_internal_add_plugin_keywords(
- __qt_internal_add_plugin_option_args
- __qt_internal_add_plugin_single_args
- __qt_internal_add_plugin_multi_args
- )
- set(__qt_add_plugin_optional_args
- ${__qt_public_add_plugin_option_args}
- ${__qt_internal_add_plugin_option_args}
- )
- set(__qt_add_plugin_single_args
- ${__qt_public_add_plugin_single_args}
- ${__qt_internal_add_plugin_single_args}
- )
- set(__qt_add_plugin_multi_args
- ${__qt_public_add_plugin_multi_args}
- ${__qt_internal_add_plugin_multi_args}
- )
- unset(__qt_public_add_plugin_option_args)
- unset(__qt_public_add_plugin_single_args)
- unset(__qt_public_add_plugin_multi_args)
- unset(__qt_internal_add_plugin_option_args)
- unset(__qt_internal_add_plugin_single_args)
- unset(__qt_internal_add_plugin_multi_args)
-endif()
-
-# 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()
+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 a55b9310e2..11fa9996b1 100644
--- a/cmake/QtBuildInformation.cmake
+++ b/cmake/QtBuildInformation.cmake
@@ -1,5 +1,32 @@
+# 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(INCLUDE_QUIET_PACKAGES
WHAT PACKAGES_FOUND
@@ -31,12 +58,20 @@ 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 .")
@@ -72,14 +107,47 @@ function(qt_print_build_instructions)
"\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 \n")
+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()
+ list(APPEND msg "\n")
+ endif()
+
list(JOIN msg "\n" msg)
if(NOT QT_INTERNAL_BUILD_INSTRUCTIONS_SHOWN)
- message(STATUS "${msg}")
+ 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()
+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)
@@ -88,24 +156,53 @@ function(qt_configure_print_summary)
set(summary_file "${CMAKE_BINARY_DIR}/config.summary")
file(WRITE "${summary_file}" "")
- # Show Qt-specific configure summary and any notes, wranings, etc.
+
+ get_property(features_possibly_changed GLOBAL PROPERTY _qt_dirty_build)
+
+ # Show Qt-specific configuration summary.
if(__qt_configure_reports)
- if(NOT QT_INTERNAL_SUMMARY_INSTRUCTIONS_SHOWN)
- message("")
+ # 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(
- "-- Configuration summary has been written to ${CMAKE_BINARY_DIR}/config.summary")
+ "\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 the output verbosity.")
+ "-- 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()
- # 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${__qt_configure_reports}")
- execute_process(COMMAND ${CMAKE_COMMAND} -E echo " ")
+ 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}")
@@ -242,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")
@@ -401,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)
@@ -434,9 +536,11 @@ function(qt_configure_add_report_error error)
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/QtBuildInternalsConfig.cmake b/cmake/QtBuildInternals/QtBuildInternalsConfig.cmake
index 5c30cc76dc..129f1ebb77 100644
--- a/cmake/QtBuildInternals/QtBuildInternalsConfig.cmake
+++ b/cmake/QtBuildInternals/QtBuildInternalsConfig.cmake
@@ -1,66 +1,28 @@
-# These values should be kept in sync with those in qtbase/.cmake.conf
-cmake_minimum_required(VERSION 3.16...3.20)
-
-###############################################
-#
-# Macros and functions for building Qt modules
-#
-###############################################
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
-# 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 qtimageformats:
-# qtbase;qtshadertools;qtsvg;qtdeclarative;qttools
-#
-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})
- list(APPEND dependencies ${subdeps} ${dependency})
- endif()
- endif()
- endforeach()
- list(REMOVE_DUPLICATES dependencies)
- endif()
- set(${out_var} "${dependencies}" PARENT_SCOPE)
-endfunction()
+# 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()
-# 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()
+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
@@ -92,1192 +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 (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()
-
- # Features won't have been evaluated yet if this is the first run, have to evaluate this here
- if(NOT "${FEATURE_pkg_config}" AND "${INPUT_pkg_config}"
- AND NOT "${INPUT_pkg_config}" STREQUAL "undefined")
- set(FEATURE_pkg_config ON)
- 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()
-
-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
- "/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()
-
-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)
- # Check for the minimum CMake version.
- include(QtCMakeVersionHelpers)
- qt_internal_require_suitable_cmake_version()
- qt_internal_upgrade_cmake_policies()
-
- # 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()
-
- # Decide whether tools will be built.
- qt_check_if_tools_will_be_built()
-endmacro()
-
-# find all targets defined in $subdir by recursing through all added subdirectories
-# populates $qt_repo_targets with a ;-list of non-UTILITY targets
-macro(qt_build_internals_get_repo_targets subdir)
- get_directory_property(_targets DIRECTORY "${subdir}" BUILDSYSTEM_TARGETS)
- if(_targets)
- foreach(_target IN LISTS _targets)
- get_target_property(_type ${_target} TYPE)
- if(NOT (${_type} STREQUAL "UTILITY" OR ${_type} STREQUAL "INTERFACE"))
- list(APPEND qt_repo_targets "${_target}")
- endif()
- endforeach()
- endif()
-
- get_directory_property(_directories DIRECTORY "${subdir}" SUBDIRECTORIES)
- if (_directories)
- foreach(_directory IN LISTS _directories)
- qt_build_internals_get_repo_targets("${_directory}")
- endforeach()
- endif()
-endmacro()
-
-# add toplevel targets for each subdirectory, e.g. qtbase_src
-function(qt_build_internals_add_toplevel_targets)
- 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_build_internals_get_repo_targets("${directory}")
- 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}"
- DEPENDS ${qt_repo_targets}
- COMMENT "Building everything in ${qt_repo_targets_name}/${qt_repo_target_basename}")
- list(APPEND qt_repo_target_all "${qt_repo_target_name}")
- endif()
- endforeach()
- if (qt_repo_target_all)
- add_custom_target("${qt_repo_targets_name}"
- DEPENDS ${qt_repo_target_all}
- COMMENT "Building everything in ${qt_repo_targets_name}")
- endif()
-endfunction()
-
-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()
-
- # 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.
- # 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()
-
-macro(qt_build_repo_begin)
- 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()
-
- # 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)
-
- 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()
-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})
- 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()
-
- if(NOT QT_SUPERBUILD)
- qt_print_build_instructions()
- endif()
-endmacro()
-
-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_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_BUILD_STANDALONE_TESTS)
- find_package(Qt6 ${PROJECT_VERSION} CONFIG REQUIRED COMPONENTS Test)
- endif()
-endmacro()
-
-macro(qt_build_repo_impl_src)
- if(NOT QT_BUILD_STANDALONE_TESTS)
- if (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/src/CMakeLists.txt")
- add_subdirectory(src)
- endif()
- endif()
-endmacro()
-
-macro(qt_build_repo_impl_tools)
- if(NOT QT_BUILD_STANDALONE_TESTS)
- 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 AND EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/tests/CMakeLists.txt")
- add_subdirectory(tests)
- if(NOT QT_BUILD_TESTS_BY_DEFAULT)
- set_property(DIRECTORY tests PROPERTY EXCLUDE_FROM_ALL TRUE)
- endif()
- endif()
-endmacro()
-
-macro(qt_build_repo_impl_examples)
- if(QT_BUILD_EXAMPLES
- AND EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/examples/CMakeLists.txt"
- AND NOT QT_BUILD_STANDALONE_TESTS)
- add_subdirectory(examples)
- 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_config_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)
- if(DEFINED CMAKE_STAGING_PREFIX)
- qt_path_join(path "${CMAKE_STAGING_PREFIX}" "${path}")
- else()
- qt_path_join(path "${CMAKE_INSTALL_PREFIX}" "${path}")
- endif()
- endif()
-
- set("${out_var}" "${path}" PARENT_SCOPE)
-endfunction()
-
-function(qt_internal_get_standalone_tests_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()
- string(APPEND tests_config_file_name "TestsConfig.cmake")
-
- set(${out_var} "${tests_config_file_name}" 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_config_files_path(_qt_build_tests_install_prefix)
-
- qt_internal_get_standalone_tests_config_file_name(_qt_tests_config_file_name)
- set(_qt_standalone_tests_config_file_path
- "${_qt_build_tests_install_prefix}/${_qt_tests_config_file_name}")
- include("${_qt_standalone_tests_config_file_path}"
- OPTIONAL
- RESULT_VARIABLE _qt_standalone_tests_included)
- if(NOT _qt_standalone_tests_included)
- message(DEBUG
- "Standalone tests config file not included because it does not exist: "
- "${_qt_standalone_tests_config_file_path}"
- )
- else()
- message(DEBUG
- "Standalone tests config file included successfully: "
- "${_qt_standalone_tests_config_file_path}"
- )
- endif()
-
- unset(_qt_standalone_tests_config_file_path)
- unset(_qt_standalone_tests_included)
- unset(_qt_tests_config_file_name)
-
- # 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()
- 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)
- 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)
- endif()
- 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(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_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)
-
- # 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()
-
-# 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)
-endmacro()
-
-macro(qt_examples_build_begin)
- set(options EXTERNAL_BUILD)
- set(singleOpts "")
- set(multiOpts DEPENDS)
-
- cmake_parse_arguments(arg "${options}" "${singleOpts}" "${multiOpts}" ${ARGN})
-
- # Use by qt_internal_add_example.
- set(QT_EXAMPLE_BASE_DIR "${CMAKE_CURRENT_SOURCE_DIR}")
-
- if(arg_EXTERNAL_BUILD AND QT_BUILD_EXAMPLES_AS_EXTERNAL)
- # Examples will be built using ExternalProject.
- # We always depend on all plugins so as 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_plugins ${arg_DEPENDS})
-
- if(TARGET ${qt_repo_targets_name}_src)
- list(APPEND QT_EXAMPLE_DEPENDENCIES ${qt_repo_targets_name}_src)
- 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.
- # 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.
- # Appending 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(APPEND CMAKE_FIND_ROOT_PATH "${QT_BUILD_DIR}")
- list(APPEND QT_EXAMPLES_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}")
- set(QT_DISABLE_QT_ADD_PLUGIN_COMPATIBILITY TRUE)
-
- 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).
-
- # This function gets all targets below this directory (excluding custom targets and aliases)
- 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(_real_targets "")
- if(_sub_targets)
- foreach(__target IN LISTS _sub_targets)
- get_target_property(target_type ${__target} TYPE)
- if(NOT target_type STREQUAL "UTILITY" AND NOT target_type STREQUAL "ALIAS")
- list(APPEND _real_targets ${__target})
- endif()
- endforeach()
- endif()
- set(${_result} ${${_result}} ${_real_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()
-
- install(CODE "
-# Restore backed up CMAKE_INSTALL_PREFIX.
-set(CMAKE_INSTALL_PREFIX \"\${_qt_internal_examples_cmake_install_prefix_backup}\")
-")
-endmacro()
-
-function(qt_internal_add_example subdir)
- if(NOT QT_IS_EXTERNAL_EXAMPLES_BUILD)
- qt_internal_add_example_in_tree(${ARGV})
- else()
- qt_internal_add_example_external_project(${ARGV})
- endif()
-endfunction()
-
-# Use old non-ExternalProject approach, aka build in-tree with the Qt build.
-function(qt_internal_add_example_in_tree subdir)
- file(RELATIVE_PATH example_rel_path
- "${QT_EXAMPLE_BASE_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}/${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.
-unset(CMAKE_INSTALL_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.
- # 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}")
- 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(CMAKE_INSTALL_PREFIX "${qt_example_install_prefix}/${example_rel_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} ${ARGN})
-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}")
-
- file(RELATIVE_PATH example_rel_path
- "${QT_EXAMPLE_BASE_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}/${subdir}")
-
- if(NOT arg_NAME)
- set(arg_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(arg_NAME MATCHES "/")
- string(REPLACE "/" ";" exploded_path "${arg_NAME}")
- list(POP_BACK exploded_path last_dir)
- if(NOT last_dir)
- message(FATAL_ERROR "Example subdirectory must have a name.")
- else()
- set(arg_NAME "${last_dir}")
- endif()
- endif()
- endif()
-
- # Likely a clash with an example subdir ExternalProject custom target of the same name.
- if(TARGET "${arg_NAME}")
- string(SHA1 rel_path_hash "${example_rel_path}")
- string(SUBSTRING "${rel_path_hash}" 0 4 short_hash)
- set(arg_NAME "${arg_NAME}-${short_hash}")
- endif()
-
- # TODO: Fix example builds when using Conan / install prefixes are different for each repo.
- if(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}")
- 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.
- list(APPEND QT_ADDITIONAL_PACKAGES_PREFIX_PATH ${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()
-
- 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()
-
- # 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()
-
- list(APPEND vars_to_pass_if_defined
- CMAKE_BUILD_TYPE:STRING
- CMAKE_CONFIGURATION_TYPES:STRING
- CMAKE_PREFIX_PATH:STRING
- QT_EXAMPLES_CMAKE_PREFIX_PATH:STRING
- QT_ADDITIONAL_PACKAGES_PREFIX_PATH:STRING
- CMAKE_FIND_ROOT_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:STRING
- CMAKE_C_COMPILER_LAUNCHER:STRING
- CMAKE_CXX_COMPILER:STRING
- CMAKE_CXX_COMPILER_LAUNCHER:STRING
- CMAKE_OBJC_COMPILER:STRING
- CMAKE_OBJC_COMPILER_LAUNCHER:STRING
- CMAKE_OBJCXX_COMPILER:STRING
- CMAKE_OBJCXX_COMPILER_LAUNCHER:STRING
- )
-
- foreach(var_with_type IN LISTS vars_to_pass_if_defined)
- 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.
-
- # 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}")
- 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(example_install_prefix "${qt_example_install_prefix}/${example_rel_path}")
-
- 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_prefix}"
- 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()
-
-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()
-
-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()
+include(QtBuildHelpers)
-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()
+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 564ed610c8..766e372666 100644
--- a/cmake/QtBuildInternals/QtStandaloneTestTemplateProject/CMakeLists.txt
+++ b/cmake/QtBuildInternals/QtStandaloneTestTemplateProject/CMakeLists.txt
@@ -1,9 +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)
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
-include(${CMAKE_CURRENT_LIST_DIR}/Main.cmake)
+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.
@@ -15,5 +13,26 @@ else()
set(absolute_project_path "${QT_STANDALONE_TEST_PATH}")
endif()
+# 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
index 3f8f8c3980..bd0984f314 100644
--- a/cmake/QtBuildInternals/QtStandaloneTestTemplateProject/Main.cmake
+++ b/cmake/QtBuildInternals/QtStandaloneTestTemplateProject/Main.cmake
@@ -1,18 +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_tests_config_files_path(standalone_tests_config_path)
+qt_get_standalone_parts_config_files_path(standalone_parts_config_path)
-file(GLOB config_files "${standalone_tests_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_tests_confg_files_path().
-qt_set_up_fake_standalone_tests_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 864e5badcc..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
@@ -25,32 +46,26 @@ if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT AND
NOT QT_BUILD_INTERNALS_NO_FORCE_SET_INSTALL_PREFIX
AND NOT QT_SUPERBUILD)
set(qtbi_orig_prefix "@CMAKE_INSTALL_PREFIX@")
- set(qtbi_new_prefix "${QT_BUILD_INTERNALS_RELOCATABLE_INSTALL_PREFIX}")
set(qtbi_orig_staging_prefix "@CMAKE_STAGING_PREFIX@")
- if(CMAKE_HOST_WIN32)
- # Make sure we use exactly the original prefix if it points to the same directory as the new
- # one. This is needed for the case where the original prefix is passed without drive letter
- # to support installing with DESTDIR set.
- get_filename_component(qtbi_real_orig_prefix "${qtbi_orig_prefix}" REALPATH)
- get_filename_component(qtbi_real_new_prefix "${qtbi_new_prefix}" REALPATH)
- if(qtbi_real_orig_prefix STREQUAL qtbi_real_new_prefix)
- set(qtbi_new_prefix "${qtbi_orig_prefix}")
- endif()
- endif()
+ 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)
- set(CMAKE_STAGING_PREFIX "${qtbi_new_prefix}" CACHE PATH
+ 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_real_orig_prefix)
unset(qtbi_new_prefix)
- unset(qtbi_real_new_prefix)
unset(qtbi_orig_staging_prefix)
+ unset(qtbi_new_staging_prefix)
endif()
# Propagate developer builds to other modules via BuildInternals package.
@@ -72,6 +87,11 @@ 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.")
@@ -86,6 +106,16 @@ set(QT_BUILD_EXAMPLES_AS_EXTERNAL "@QT_BUILD_EXAMPLES_AS_EXTERNAL@" CACHE BOOL
# 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")
@@ -105,42 +135,5 @@ if(NOT DEFINED QT_MAX_NEW_POLICY_CMAKE_VERSION)
set(QT_MAX_NEW_POLICY_CMAKE_VERSION "@max_new_policy_version@")
endif()
-get_property(__qt_internal_extras_is_multi_config GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
-
-# We want the same build type to be used when configuring all Qt repos or standalone
-# tests or single tests.
-# To do that, we need to force-set the CMAKE_BUILD_TYPE cache var because CMake itself
-# initializes it with the value of CMAKE_BUILD_TYPE_INIT at the start of project
-# configuration, so we need to override it.
-# Note the value of CMAKE_BUILD_TYPE_INIT is different based on the platform, most
-# Linux and macOS platforms will have it empty, but Windows platforms will have a value.
-#
-# We can't reliably differentiate between a value set on the command line by the user
-# and one set by CMake, so we use a few heuristics:
-# 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. 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) If a toolchain file is not used, we rely on the value of the CMake internal
-# CMAKE_BUILD_TYPE_INIT variable.
-# This won't work reliably on Windows where CMAKE_BUILD_TYPE_INIT is non-empty.
-#
-# Both cases won't handle an empty "" config set by the user, but we claim that's an
-# unsupported config when building Qt.
-#
-# Allow an opt out when QT_NO_FORCE_SET_CMAKE_BUILD_TYPE is set.
-# Finally, don't set the variable if a multi-config generator is used. This can happen
-# when qtbase is built with a single config, but a test is built with a multi-config generator.
-function(qt_internal_force_set_cmake_build_type_conditionally value)
- # STREQUAL check needs to be expanded variables because an undefined var is not equal to an
- # empty defined var.
- if("${CMAKE_BUILD_TYPE}" STREQUAL "${CMAKE_BUILD_TYPE_INIT}"
- AND NOT __qt_toolchain_cmake_build_type_before_project_call
- AND NOT QT_NO_FORCE_SET_CMAKE_BUILD_TYPE
- AND NOT __qt_internal_extras_is_multi_config)
- set(CMAKE_BUILD_TYPE "${value}" CACHE STRING "Choose the type of build." FORCE)
- endif()
-endfunction()
-
# 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
index d1d4fb9054..142a003cbc 100644
--- a/cmake/QtCMakeHelpers.cmake
+++ b/cmake/QtCMakeHelpers.cmake
@@ -1,18 +1,19 @@
-# 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})
+# 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()
- if(arg_CONTENT)
+ # 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).
@@ -30,10 +31,29 @@ function(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)
@@ -41,6 +61,14 @@ macro(qt_parse_all_arguments result type flags options multiopts)
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})
@@ -97,8 +125,7 @@ endfunction()
# 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
+# 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.
@@ -112,7 +139,7 @@ endfunction()
# bar(target BAR.... WWW...)
#
# function(foo target)
-# qt_parse_all_arguments(arg "" "" "BAR;ZZZ;WWW ${ARGV})
+# 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
diff --git a/cmake/QtCMakePackageVersionFile.cmake.in b/cmake/QtCMakePackageVersionFile.cmake.in
index f668e614c5..d4c30b33ac 100644
--- a/cmake/QtCMakePackageVersionFile.cmake.in
+++ b/cmake/QtCMakePackageVersionFile.cmake.in
@@ -1,3 +1,6 @@
+# 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")
@@ -8,7 +11,9 @@ 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)
@@ -17,9 +22,17 @@ else()
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)
+ 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 "
diff --git a/cmake/QtCMakeVersionHelpers.cmake b/cmake/QtCMakeVersionHelpers.cmake
index c594da99b4..322e58eed1 100644
--- a/cmake/QtCMakeVersionHelpers.cmake
+++ b/cmake/QtCMakeVersionHelpers.cmake
@@ -1,3 +1,6 @@
+# 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)
@@ -11,6 +14,8 @@ function(qt_internal_get_supported_min_cmake_version_for_building_qt out_var)
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()
@@ -27,7 +32,9 @@ function(qt_internal_get_supported_min_cmake_version_for_using_qt out_var)
"It should have been set by this point.")
endif()
- if(BUILD_SHARED_LIBS)
+ 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}")
@@ -189,18 +196,11 @@ function(qt_internal_warn_about_buggy_cmake_versions)
# https://gitlab.kitware.com/cmake/cmake/-/issues/16776
list(APPEND unsuitable_versions "3.21.0")
- # qt_ensure_perl fails to find perl in host PATH via find_program
- # due to Android Platform module setting CMAKE_FIND_USE_SYSTEM_ENVIRONMENT_PATH to OFF
- # Fixed in 3.20.6, 3.21.3. not a problem in CMake versions earlier than 3.20.0
- # https://gitlab.kitware.com/cmake/cmake/-/issues/22634
- # https://gitlab.kitware.com/cmake/cmake/-/merge_requests/5357
- # https://gitlab.kitware.com/cmake/cmake/-/merge_requests/6528
- if(ANDROID AND CMAKE_HOST_WIN32)
- list(APPEND unsuitable_versions
- "3.20.0" "3.20.1" "3.20.2" "3.20.3" "3.20.4" "3.20.5"
- "3.21.0" "3.21.1" "3.21.2"
- )
- endif()
+ # 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)
diff --git a/cmake/QtCompilerFlags.cmake b/cmake/QtCompilerFlags.cmake
index a34aaca20b..f58f36b7a2 100644
--- a/cmake/QtCompilerFlags.cmake
+++ b/cmake/QtCompilerFlags.cmake
@@ -1,3 +1,6 @@
+# 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)
@@ -5,18 +8,16 @@
# 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()
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()
- list(APPEND _qt_compiler_warning_flags_off -w)
endif()
set(_qt_compiler_warning_flags_condition
@@ -24,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 ea07330945..ac542e9451 100644
--- a/cmake/QtCompilerOptimization.cmake
+++ b/cmake/QtCompilerOptimization.cmake
@@ -1,3 +1,6 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
if (MSVC)
if (QT_64BIT)
# SSE2 is mandatory on 64-bit mode, so skip the option. It triggers:
@@ -13,7 +16,6 @@ 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")
@@ -33,35 +35,40 @@ if (MSVC)
endif()
if(GCC OR CLANG OR 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_F16C "-mf16c")
- set(QT_CFLAGS_RDRND "-mrdrnd")
- set(QT_CFLAGS_RDSEED "-mrdseed")
- set(QT_CFLAGS_AVX "-mavx")
- set(QT_CFLAGS_AVX2 "-mavx2")
- set(QT_CFLAGS_ARCH_HASWELL "-march=haswell")
- 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_AVX512VBMI2 "-mavx512vbmi2")
- set(QT_CFLAGS_AESNI "-maes")
- set(QT_CFLAGS_SHANI "-msha")
- set(QT_CFLAGS_VAES "-mvaes")
+ 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 "-mdsp")
- set(QT_CFLAGS_MIPS_DSPR2 "-mdspr2")
+ 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
@@ -71,7 +78,7 @@ endif()
# 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 AND NOT WASM)
+if(GCC OR CLANG)
set(QT_CFLAGS_OPTIMIZE "-O2")
set(QT_CFLAGS_OPTIMIZE_FULL "-O3")
set(QT_CFLAGS_OPTIMIZE_DEBUG "-Og")
@@ -91,9 +98,14 @@ 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" "/O0" "-O0")
+ set(QT_CFLAGS_OPTIMIZE_VALID_VALUES "/O2" "/O1" "/Od" "/Ob0" "/Ob1" "/Ob2" "/Ob3" "/O0" "-O0")
if(CLANG)
set(QT_CFLAGS_OPTIMIZE_FULL "/clang:-O3")
@@ -119,12 +131,8 @@ if (QCC)
set(QT_CFLAGS_OPTIMIZE_FULL "-O3")
endif()
+# Emscripten Clang
if(WASM)
- set(QT_CFLAGS_OPTIMIZE "-O2")
- set(QT_CFLAGS_OPTIMIZE_FULL "-O3")
- set(QT_CFLAGS_OPTIMIZE_SIZE "-Os")
- set(QT_CFLAGS_OPTIMIZE_DEBUG "-g2")
-
- set(QT_CFLAGS_SSE2 -O2 -msimd128 -msse -msse2)
-
+ 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 8ad4e45822..b5a21e391d 100644
--- a/cmake/QtConfig.cmake.in
+++ b/cmake/QtConfig.cmake.in
@@ -1,9 +1,15 @@
+# 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("${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)
@@ -12,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:
@@ -23,29 +33,32 @@ else()
QT_VERSION_PATCH @PROJECT_VERSION_PATCH@)
endif()
-if(NOT "${QT_HOST_PATH}" STREQUAL "")
- find_package(Qt@PROJECT_VERSION_MAJOR@HostInfo
- CONFIG
- REQUIRED
- PATHS "${QT_HOST_PATH}"
- "${QT_HOST_PATH_CMAKE_DIR}"
- NO_CMAKE_FIND_ROOT_PATH
- NO_DEFAULT_PATH)
-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")
-elseif(APPLE AND CMAKE_SYSTEM_NAME STREQUAL "iOS")
- # Add module directory to pick up custom Info.plist template for iOS
- set(__qt_internal_cmake_ios_support_files_path "${_qt_import_prefix}/ios")
- list(APPEND CMAKE_MODULE_PATH "${__qt_internal_cmake_ios_support_files_path}")
+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
@@ -53,84 +66,15 @@ set(QT_ADDITIONAL_PACKAGES_PREFIX_PATH "" CACHE STRING
set(QT_ADDITIONAL_HOST_PACKAGES_PREFIX_PATH "" CACHE STRING
"Additional directories where find(Qt6 ...) host Qt components are searched")
-# 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.
- if(NOT additional_path MATCHES "/lib/cmake$")
- string(APPEND additional_path "/lib/cmake")
- endif()
- list(APPEND additional_packages_prefix_paths "${additional_path}")
- endforeach()
-
- set("${out_var}" "${additional_packages_prefix_paths}" PARENT_SCOPE)
-endfunction()
-
__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)
-# 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)
- if(path MATCHES "/lib/cmake$")
- string(APPEND path "/../..")
- endif()
- get_filename_component(path "${path}" ABSOLUTE)
- list(APPEND result "${path}")
- endforeach()
- set("${out_var}" "${result}" PARENT_SCOPE)
-endfunction()
-
__qt_internal_prefix_paths_to_roots(_qt_additional_host_packages_root_paths
"${_qt_additional_host_packages_prefix_paths}")
-# Public helpers available to all Qt packages.
-include("${CMAKE_CURRENT_LIST_DIR}/QtFeature.cmake")
-include("${CMAKE_CURRENT_LIST_DIR}/QtPublicFinalizerHelpers.cmake")
-include("${CMAKE_CURRENT_LIST_DIR}/QtPublicPluginHelpers.cmake")
-include("${CMAKE_CURRENT_LIST_DIR}/QtPublicTargetHelpers.cmake")
-include("${CMAKE_CURRENT_LIST_DIR}/QtPublicWalkLibsHelpers.cmake")
-include("${CMAKE_CURRENT_LIST_DIR}/QtPublicFindPackageHelpers.cmake")
-include("${CMAKE_CURRENT_LIST_DIR}/QtPublicDependencyHelpers.cmake")
-include("${CMAKE_CURRENT_LIST_DIR}/QtPublicToolHelpers.cmake")
-include("${CMAKE_CURRENT_LIST_DIR}/QtPublicCMakeHelpers.cmake")
-
-if(NOT DEFINED QT_CMAKE_EXPORT_NAMESPACE)
- set(QT_CMAKE_EXPORT_NAMESPACE @QT_CMAKE_EXPORT_NAMESPACE@)
-endif()
+__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.
@@ -150,10 +94,14 @@ set(__qt_sanitizer_options_set TRUE)
include(CMakeFindDependencyMacro)
if(EXISTS "${CMAKE_CURRENT_LIST_DIR}/@INSTALL_CMAKE_NAMESPACE@Dependencies.cmake")
include("${CMAKE_CURRENT_LIST_DIR}/@INSTALL_CMAKE_NAMESPACE@Dependencies.cmake")
- if(NOT @INSTALL_CMAKE_NAMESPACE@_DEPENDENCIES_FOUND)
- set(@INSTALL_CMAKE_NAMESPACE@_FOUND FALSE)
- message(FATAL_ERROR "Failed to find Qt Platform dependency: "
- "${@INSTALL_CMAKE_NAMESPACE@_DEPENDENCY_NOT_FOUND_MESSAGE}")
+
+ _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()
@@ -187,17 +135,21 @@ foreach(module ${@INSTALL_CMAKE_NAMESPACE@_FIND_COMPONENTS})
${_qt_additional_host_packages_root_paths})
endif()
- find_package(@INSTALL_CMAKE_NAMESPACE@${module}
- ${@INSTALL_CMAKE_NAMESPACE@_FIND_VERSION}
- ${_@INSTALL_CMAKE_NAMESPACE@_FIND_PARTS_QUIET}
- PATHS
- ${_qt_cmake_dir}
- ${_qt_additional_packages_prefix_paths}
- ${QT_EXAMPLES_CMAKE_PREFIX_PATH}
- ${__qt_find_package_host_qt_path}
- ${_qt_additional_host_packages_prefix_paths}
- ${__qt_use_no_default_path_for_qt_packages}
- )
+ _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}")
@@ -234,11 +186,17 @@ foreach(module ${@INSTALL_CMAKE_NAMESPACE@_FIND_COMPONENTS})
endif()
if(@INSTALL_CMAKE_NAMESPACE@_FIND_REQUIRED_${module})
+ set(@INSTALL_CMAKE_NAMESPACE@_FOUND False)
set(_Qt_NOTFOUND_MESSAGE
- "${_Qt_NOTFOUND_MESSAGE}Failed to find Qt component \"${module}\". ${_qt_component_not_found_msg}")
+ "${_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}\". ${_qt_component_not_found_msg}")
+ "Failed to find optional Qt component \"${module}\". ${_qt_component_not_found_msg}")
endif()
unset(_qt_expected_component_config_path)
@@ -250,10 +208,15 @@ endforeach()
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()
diff --git a/cmake/QtConfigDependencies.cmake.in b/cmake/QtConfigDependencies.cmake.in
index b23b6681eb..9824f8525c 100644
--- a/cmake/QtConfigDependencies.cmake.in
+++ b/cmake/QtConfigDependencies.cmake.in
@@ -1,51 +1,27 @@
-set(@INSTALL_CMAKE_NAMESPACE@_DEPENDENCIES_FOUND FALSE)
+# 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@
-foreach(__qt_target_dep ${__qt_third_party_deps})
- list(GET __qt_target_dep 0 __qt_pkg)
- list(GET __qt_target_dep 1 __qt_is_optional)
- list(GET __qt_target_dep 2 __qt_version)
- list(GET __qt_target_dep 3 __qt_components)
- list(GET __qt_target_dep 4 __qt_optional_components)
- set(__qt_find_package_args "${__qt_pkg}")
- if(__qt_version)
- list(APPEND __qt_find_package_args "${__qt_version}")
- endif()
- if(__qt_components)
- string(REPLACE " " ";" __qt_components "${__qt_components}")
- list(APPEND __qt_find_package_args COMPONENTS ${__qt_components})
- endif()
- if(__qt_optional_components)
- string(REPLACE " " ";" __qt_optional_components "${__qt_optional_components}")
- list(APPEND __qt_find_package_args OPTIONAL_COMPONENTS ${__qt_optional_components})
- endif()
-
- # Already build an error message, because find_dependency calls return() on failure.
- set(__qt_message "\nPackage: ${__qt_pkg}")
- if(__qt_version)
- string(APPEND __qt_message "\nVersion: ${__qt_version}")
- endif()
- if(__qt_components)
- string(APPEND __qt_message "\nComponents: ${__qt_components}")
- endif()
- if(__qt_optional_components)
- string(APPEND __qt_message "\nComponents: ${__qt_optional_components}")
- endif()
- set(@INSTALL_CMAKE_NAMESPACE@_DEPENDENCY_NOT_FOUND_MESSAGE "${__qt_message}")
-
- if(__qt_is_optional)
- if(${CMAKE_FIND_PACKAGE_NAME}_FIND_QUIETLY)
- list(APPEND __qt_find_package_args QUIET)
- endif()
- find_package(${__qt_find_package_args})
- else()
- find_dependency(${__qt_find_package_args})
- endif()
-endforeach()
-
-set(@INSTALL_CMAKE_NAMESPACE@_DEPENDENCIES_FOUND TRUE)
-unset(@INSTALL_CMAKE_NAMESPACE@_DEPENDENCY_NOT_FOUND_MESSAGE)
+# 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
index bde3460cdc..06acd33c82 100644
--- a/cmake/QtConfigExtras.cmake.in
+++ b/cmake/QtConfigExtras.cmake.in
@@ -1,2 +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
index 4c64895b53..a27221ece8 100644
--- a/cmake/QtCopyFileIfDifferent.cmake
+++ b/cmake/QtCopyFileIfDifferent.cmake
@@ -1,3 +1,6 @@
+# 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.
diff --git a/cmake/QtDbusHelpers.cmake b/cmake/QtDbusHelpers.cmake
index 95f1f9aa13..26e98eff27 100644
--- a/cmake/QtDbusHelpers.cmake
+++ b/cmake/QtDbusHelpers.cmake
@@ -1,6 +1,14 @@
+# 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)
- qt_parse_all_arguments(arg "qt_create_qdbusxml2cpp_command" "ADAPTOR;INTERFACE" "BASENAME" "FLAGS" ${ARGN})
+ 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()
@@ -52,6 +60,7 @@ function(qt_create_qdbusxml2cpp_command target infile)
"${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
diff --git a/cmake/QtDeferredDependenciesHelpers.cmake b/cmake/QtDeferredDependenciesHelpers.cmake
index f4ae96ca92..b233865727 100644
--- a/cmake/QtDeferredDependenciesHelpers.cmake
+++ b/cmake/QtDeferredDependenciesHelpers.cmake
@@ -1,3 +1,6 @@
+# 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.
diff --git a/cmake/QtDocsHelpers.cmake b/cmake/QtDocsHelpers.cmake
index ae8034318e..8b631e88ca 100644
--- a/cmake/QtDocsHelpers.cmake
+++ b/cmake/QtDocsHelpers.cmake
@@ -1,3 +1,6 @@
+# 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'.
#
@@ -18,14 +21,39 @@ function(qt_internal_add_docs)
# 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).")
+ 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
+ # 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()
@@ -94,6 +122,7 @@ function(qt_internal_add_docs)
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"
)
@@ -110,13 +139,14 @@ function(qt_internal_add_docs)
if(NOT QT_BUILD_ONLINE_DOCS)
list(PREPEND prepare_qdoc_args
-installdir "${QT_INSTALL_DIR}/${INSTALL_DOCDIR}"
+ ${qdoc_extra_args}
)
endif()
- if(QT_SUPERBUILD)
+ 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}")
- elseif(QT_WILL_INSTALL)
- set(qt_install_docs_env "${CMAKE_INSTALL_PREFIX}/${INSTALL_DOCDIR}")
else()
set(qt_install_docs_env "${QT_BUILD_INTERNALS_RELOCATABLE_INSTALL_PREFIX}/${INSTALL_DOCDIR}")
endif()
@@ -136,6 +166,10 @@ function(qt_internal_add_docs)
)
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
@@ -148,6 +182,7 @@ function(qt_internal_add_docs)
if(NOT QT_BUILD_ONLINE_DOCS)
list(PREPEND generate_qdoc_args
-installdir "${QT_INSTALL_DIR}/${INSTALL_DOCDIR}"
+ ${qdoc_extra_args}
)
endif()
diff --git a/cmake/QtExecutableHelpers.cmake b/cmake/QtExecutableHelpers.cmake
index 80eb17e164..fb96ca4db2 100644
--- a/cmake/QtExecutableHelpers.cmake
+++ b/cmake/QtExecutableHelpers.cmake
@@ -1,3 +1,6 @@
+# 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.
@@ -6,14 +9,14 @@
# 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 publically
+# 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)
- qt_parse_all_arguments(arg "qt_internal_add_executable"
+ 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}"
- ${ARGN})
+ "${__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}")
@@ -27,6 +30,7 @@ function(qt_internal_add_executable name)
endif()
_qt_internal_create_executable(${name})
+ qt_internal_mark_as_internal_target(${name})
if(ANDROID)
_qt_internal_android_executable_finalizer(${name})
endif()
@@ -36,9 +40,6 @@ function(qt_internal_add_executable name)
PROPERTY EXCLUDE_FROM_ALL "$<NOT:$<CONFIG:${QT_MULTI_CONFIG_FIRST_CONFIG}>>")
endif()
- if(WASM)
- _qt_internal_wasm_add_target_helpers("${name}")
- endif()
if (arg_VERSION)
if(arg_VERSION MATCHES "[0-9]+\\.[0-9]+\\.[0-9]+\\.[0-9]+")
# nothing to do
@@ -64,12 +65,12 @@ function(qt_internal_add_executable name)
QT_DELAYED_TARGET_COPYRIGHT "${arg_TARGET_COPYRIGHT}"
)
else()
- if("${arg_TARGET_DESCRIPTION}" STREQUAL "")
+ 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}")
+ TARGET_DESCRIPTION ${arg_TARGET_DESCRIPTION}
+ TARGET_VERSION ${arg_VERSION})
endif()
if (WIN32 AND NOT arg_DELAY_RC)
@@ -104,16 +105,34 @@ function(qt_internal_add_executable name)
${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} 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}"
+ 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}
@@ -129,6 +148,10 @@ function(qt_internal_add_executable name)
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)
@@ -193,93 +216,322 @@ function(qt_internal_add_executable name)
add_dependencies("${name}" qpa_default_plugins)
endif()
- if(NOT BUILD_SHARED_LIBS)
- # For static builds, 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
- )
+ # 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()
+ 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()
+ # 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()
+ # 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(APPEND deduped_libs "${lib}")
+ endforeach()
- list(REMOVE_DUPLICATES deduped_libs)
+ 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)
+ 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 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>>")
+ # 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}")
+ # 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}")
+ set(out_file_path "${CMAKE_CURRENT_BINARY_DIR}/${out_file}")
- file(GENERATE OUTPUT "${out_file_path}" CONTENT
+ 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},>>"
- )
+ 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)
+ # 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>")
+ 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 b9af639503..96cb308b2c 100644
--- a/cmake/QtFeature.cmake
+++ b/cmake/QtFeature.cmake
@@ -1,10 +1,14 @@
-include(QtFeatureCommon)
+# 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}))
@@ -43,9 +47,11 @@ function(qt_feature 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)
@@ -74,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})
@@ -137,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
@@ -157,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().
@@ -167,18 +153,48 @@ 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_internal_dump_expression_values expression_dump expression)
- set(dump "")
- set(skipNext FALSE)
- set(isTargetExpression FALSE)
+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")
@@ -232,19 +248,44 @@ endfunction()
# ${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 computed label)
+function(qt_feature_check_and_save_user_provided_value
+ resultVar feature condition condition_expression computed label)
if (DEFINED "FEATURE_${feature}")
# Revisit new user provided value
set(user_value "${FEATURE_${feature}}")
- set(result "${user_value}")
+ string(TOUPPER "${user_value}" user_value_upper)
+ set(result "${user_value_upper}")
- # If the build is marked as dirty and the user_value doesn't meet the new condition,
- # reset it to the computed one.
+ # If ${feature} depends on another dirty feature, reset the ${feature} value to
+ # ${computed}.
get_property(dirty_build GLOBAL PROPERTY _qt_dirty_build)
- if(NOT condition AND result AND dirty_build)
- set(result "${computed}")
- message(WARNING "Reset FEATURE_${feature} value to ${result}, because it doesn't \
-meet its condition after reconfiguration.")
+ 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()
set(bool_values OFF NO FALSE N ON YES TRUE Y)
@@ -292,13 +333,21 @@ condition:\n ${conditionString}\nCondition values dump:\n ${conditionDump}
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, or derived from INPUT_foo (also set by the user).
+# 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.
@@ -327,9 +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}})
+ _qt_internal_parse_feature_definition("${feature}")
if("${arg_ENABLE}" STREQUAL "")
set(arg_ENABLE OFF)
@@ -367,17 +414,6 @@ function(qt_evaluate_feature feature)
qt_evaluate_config_expression(emit_if ${arg_EMIT_IF})
endif()
- # If FEATURE_ is not defined trying to use INPUT_ variable to enable/disable feature.
- if ((NOT DEFINED "FEATURE_${feature}") AND (DEFINED "INPUT_${feature}")
- AND (NOT "${INPUT_${feature}}" STREQUAL "undefined")
- AND (NOT "${INPUT_${feature}}" STREQUAL ""))
- if(INPUT_${feature})
- set(FEATURE_${feature} ON)
- else()
- set(FEATURE_${feature} OFF)
- endif()
- endif()
-
# 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 "")
@@ -394,7 +430,8 @@ function(qt_evaluate_feature feature)
# 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}" "${computed}" "${arg_LABEL}")
+ 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)
@@ -407,9 +444,67 @@ function(qt_evaluate_feature feature)
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}")
@@ -469,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}")
@@ -525,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")
@@ -659,22 +762,6 @@ 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")
@@ -783,6 +870,40 @@ 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()
@@ -905,8 +1026,11 @@ function(qt_config_compile_test name)
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})
+ 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")
@@ -921,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()
@@ -929,22 +1054,28 @@ 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 (INPUT_stdlib_libcpp OR QT_FEATURE_stdlib_libcpp)
+ if (QT_FEATURE_stdlib_libcpp)
list(APPEND CMAKE_REQUIRED_FLAGS "-stdlib=libc++")
endif()
@@ -965,16 +1096,31 @@ function(qt_config_compile_test name)
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()
@@ -995,6 +1141,7 @@ function(qt_get_platform_try_compile_vars out_var)
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)
@@ -1006,10 +1153,12 @@ 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 (INPUT_stdlib_libcpp OR QT_FEATURE_stdlib_libcpp)
+ if (QT_FEATURE_stdlib_libcpp)
if(CMAKE_CXX_FLAGS)
string(APPEND CMAKE_CXX_FLAGS " -stdlib=libc++")
else()
@@ -1043,8 +1192,8 @@ 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)
@@ -1210,7 +1359,16 @@ function(qt_config_linker_supports_flag_test name)
endif()
cmake_parse_arguments(arg "" "LABEL;FLAG" "" ${ARGN})
- set(flags "-Wl,${arg_FLAG}")
+ 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)
@@ -1246,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 to be \"${QT_FEATURE_${feature}}\" and should now be set to \"${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()
diff --git a/cmake/QtFeatureCommon.cmake b/cmake/QtFeatureCommon.cmake
index 5dfbeed2d5..9b49d4fcac 100644
--- a/cmake/QtFeatureCommon.cmake
+++ b/cmake/QtFeatureCommon.cmake
@@ -1,3 +1,6 @@
+# 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\\+\\+")
diff --git a/cmake/QtFindPackageHelpers.cmake b/cmake/QtFindPackageHelpers.cmake
index da96f3f176..dd10bde75a 100644
--- a/cmake/QtFindPackageHelpers.cmake
+++ b/cmake/QtFindPackageHelpers.cmake
@@ -1,3 +1,6 @@
+# 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.
#
@@ -13,6 +16,15 @@ function(qt_find_package_promote_targets_to_global_scope target)
"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)
@@ -25,12 +37,26 @@ macro(qt_find_package)
# 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
+ # 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})
@@ -138,6 +164,11 @@ macro(qt_find_package)
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()
@@ -197,6 +228,46 @@ macro(qt_find_package)
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)
@@ -284,6 +355,8 @@ endfunction()
# 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}")
@@ -307,13 +380,112 @@ function(qt_internal_is_lib_part_of_qt6_package lib out_var)
OR lib STREQUAL "GlobalConfigPrivate"
OR lib STREQUAL "PlatformModuleInternal"
OR lib STREQUAL "PlatformPluginInternal"
- OR lib STREQUAL "PlatformToolInternal")
+ 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)
@@ -343,14 +515,18 @@ function(qt_register_target_dependencies target public_libs private_libs)
endif()
foreach(lib IN LISTS lib_list)
- if ("${lib}" MATCHES "^Qt::(.*)")
+ if("${lib}" MATCHES "^Qt::(.*)")
set(lib "${CMAKE_MATCH_1}")
- qt_internal_is_lib_part_of_qt6_package("${lib}" is_part_of_qt6)
- if (is_part_of_qt6)
- list(APPEND target_deps "Qt6\;${PROJECT_VERSION}")
- else()
- list(APPEND target_deps "${INSTALL_CMAKE_NAMESPACE}${lib}\;${PROJECT_VERSION}")
- endif()
+ 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()
@@ -363,14 +539,24 @@ function(qt_register_target_dependencies target public_libs private_libs)
# INTERFACE libraries. INTERFACE libraries in most cases will be FooPrivate libraries.
if(target_is_shared AND private_libs)
foreach(lib IN LISTS private_libs)
- if ("${lib}" MATCHES "^Qt::(.*)")
- set(lib_namespaced "${lib}")
+ 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)
- list(APPEND target_deps "${INSTALL_CMAKE_NAMESPACE}${lib}\;${PROJECT_VERSION}")
+ 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()
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
index 63545df139..3799621400 100644
--- a/cmake/QtFinishPkgConfigFile.cmake
+++ b/cmake/QtFinishPkgConfigFile.cmake
@@ -1,3 +1,6 @@
+# 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.
diff --git a/cmake/QtFinishPrlFile.cmake b/cmake/QtFinishPrlFile.cmake
index 78c7d15770..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].
@@ -89,7 +92,34 @@ foreach(line ${lines})
# 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.
- list(APPEND libs_to_prepend "${target_library_path}")
+ 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()
diff --git a/cmake/QtFlagHandlingHelpers.cmake b/cmake/QtFlagHandlingHelpers.cmake
index c01b596b80..6a62b85c03 100644
--- a/cmake/QtFlagHandlingHelpers.cmake
+++ b/cmake/QtFlagHandlingHelpers.cmake
@@ -1,44 +1,127 @@
+# 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)
- qt_parse_all_arguments(arg "qt_internal_add_linker" "" "" "PRIVATE_HEADERS" ${ARGN})
+ 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)
- 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")
+ 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}")
- if (QT_NAMESPACE STREQUAL "")
- set(tag_symbol "qt_version_tag")
- else()
- set(tag_symbol "qt_version_tag_${QT_NAMESPACE}")
+ 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()
- 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()
-
- set(generator_command "${HOST_PERL}"
- "${QT_MKSPECS_DIR}/features/data/unix/findclasslist.pl"
- "<" "${infile}" ">" "${outfile}"
+ 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
- "${infile}"
- "${QT_MKSPECS_DIR}/features/data/unix/findclasslist.pl"
+ "${arg_PRIVATE_CONTENT_FILE}"
+ "${QT_CMAKE_DIR}/QtGenerateVersionScript.cmake"
)
add_custom_command(
@@ -56,7 +139,18 @@ function(qt_internal_add_linker_version_script target)
endfunction()
function(qt_internal_add_link_flags_no_undefined target)
- if (NOT QT_BUILD_SHARED_LIBS)
+ 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)
@@ -96,11 +190,20 @@ 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")
+ 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")
@@ -109,16 +212,26 @@ function(qt_internal_apply_gc_binaries target visibility)
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 "-ffunction-sections" "-fdata-sections")
+ 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})
+ target_compile_options("${target}" ${visibility} "${split_sections_flags}")
endif()
endfunction()
@@ -128,13 +241,17 @@ function(qt_internal_apply_intel_cet target visibility)
endif()
set(possible_visibilities PRIVATE INTERFACE PUBLIC)
- list(FIND possible_visibilities "${visibility}" known_visibility)
- if (known_visibility EQUAL "-1")
+ if(NOT visibility IN_LIST possible_visibilities)
message(FATAL_ERROR "Visibitily setting must be one of PRIVATE, INTERFACE or PUBLIC.")
endif()
if(GCC)
- set(flags "-mshstk")
+ 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}")
@@ -142,21 +259,25 @@ function(qt_internal_apply_intel_cet target visibility)
endfunction()
function(qt_internal_library_deprecation_level result)
- # QT_DISABLE_DEPPRECATED_BEFORE controls which version we use as a cut-off
+ # 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(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")
+ 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()
- # On other platforms, Qt's own compilation goes needs to compile the Qt 5.0 API
- list(APPEND deprecations "QT_DISABLE_DEPRECATED_BEFORE=0x050000")
+ list(APPEND deprecations "QT_DISABLE_DEPRECATED_UP_TO=${QT_DISABLE_DEPRECATED_UP_TO}")
endif()
- # QT_DEPRECATED_WARNINGS_SINCE controls the upper-bound of deprecation
- # warnings that are emitted. E.g. if it is set to 7.0 then all deprecations
- # during the 6.* lifetime will be warned about in Qt builds.
- list(APPEND deprecations "QT_DEPRECATED_WARNINGS_SINCE=0x070000")
+ # 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()
@@ -168,21 +289,21 @@ function(qt_internal_set_exceptions_flags target 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 ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
+ if(MSVC)
set(_flag "/EHs-c-" "/wd4530" "/wd4577")
- elseif ("${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU|AppleClang|InteLLLVM")
+ else()
set(_flag "-fno-exceptions")
- elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
- if (MSVC)
- set(_flag "/EHs-c-" "/wd4530" "/wd4577")
- else()
- set(_flag "-fno-exceptions")
- endif()
endif()
endif()
@@ -230,17 +351,17 @@ endfunction()
function(qt_set_language_standards)
## Use the latest standard the compiler supports (same as qt_common.prf)
- if (QT_FEATURE_cxx20)
+ 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)
- 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()
+ 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)
@@ -255,14 +376,15 @@ function(qt_set_msvc_cplusplus_options target visibility)
# 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} "$<$<COMPILE_LANGUAGE:CXX>:${flags}>")
+ 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 "-utf-8")
+ list(APPEND utf8_flags "$<$<CXX_COMPILER_ID:MSVC>:-utf-8>")
endif()
if(utf8_flags)
@@ -282,7 +404,7 @@ function(qt_internal_enable_unicode_defines)
set(no_unicode_condition
"$<NOT:$<BOOL:$<TARGET_PROPERTY:QT_NO_UNICODE_DEFINES>>>")
target_compile_definitions(Platform
- INTERFACE "$<${no_unicode_condition}:UNICODE;_UNICODE>")
+ INTERFACE "$<${no_unicode_condition}:UNICODE$<SEMICOLON>_UNICODE>")
endif()
endfunction()
@@ -494,13 +616,11 @@ endfunction()
# 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)
- qt_parse_all_arguments(
- arg
- "qt_internal_remove_known_optimization_flags"
+ cmake_parse_arguments(PARSE_ARGV 0 arg
"IN_CACHE"
""
- "CONFIGS;LANGUAGES"
- ${ARGN})
+ "CONFIGS;LANGUAGES")
+ _qt_internal_validate_all_args_are_parsed(arg)
if(NOT arg_CONFIGS)
message(FATAL_ERROR
@@ -527,20 +647,27 @@ endfunction()
# Removes specified flags from CMAKE_<LANGUAGES>_FLAGS[_CONFIGS] variables
#
-# IN_CACHE enables flags removal from CACHE
-# 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.
-# REGEX enables the flag processing as a regular expression.
+# 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)
- qt_parse_all_arguments(arg
- "qt_internal_remove_compiler_flags"
+ cmake_parse_arguments(PARSE_ARGV 1 arg
"IN_CACHE;REGEX"
""
"CONFIGS;LANGUAGES"
- ${ARGN}
)
+ _qt_internal_validate_all_args_are_parsed(arg)
if("${flags}" STREQUAL "")
message(WARNING "qt_internal_remove_compiler_flags was called without any flags specified.")
@@ -556,8 +683,7 @@ function(qt_internal_remove_compiler_flags flags)
if(arg_CONFIGS)
set(configs "${arg_CONFIGS}")
else()
- message(FATAL_ERROR
- "You must specify at least one configuration for which to remove the flags.")
+ qt_internal_get_configs_for_flag_manipulation(configs)
endif()
if(arg_REGEX)
@@ -595,13 +721,11 @@ endfunction()
# 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)
- qt_parse_all_arguments(
- arg
- "qt_internal_add_compiler_flags"
+ cmake_parse_arguments(PARSE_ARGV 0 arg
"IN_CACHE"
"FLAGS"
- "CONFIGS;LANGUAGES"
- ${ARGN})
+ "CONFIGS;LANGUAGES")
+ _qt_internal_validate_all_args_are_parsed(arg)
if(NOT arg_CONFIGS)
message(FATAL_ERROR
@@ -638,13 +762,11 @@ endfunction()
# 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)
- qt_parse_all_arguments(
- arg
- "qt_internal_add_compiler_flags_for_release_configs"
+ cmake_parse_arguments(PARSE_ARGV 0 arg
"IN_CACHE"
"FLAGS"
- "LANGUAGES"
- ${ARGN})
+ "LANGUAGES")
+ _qt_internal_validate_all_args_are_parsed(arg)
set(args "")
@@ -684,13 +806,11 @@ endfunction()
# 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)
- qt_parse_all_arguments(
- arg
- "qt_internal_add_optimize_full_flags"
+ cmake_parse_arguments(PARSE_ARGV 0 arg
"IN_CACHE"
""
- ""
- ${ARGN})
+ "")
+ _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)
@@ -746,13 +866,11 @@ endfunction()
# 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)
- qt_parse_all_arguments(
- arg
- "qt_internal_replace_compiler_flags"
+ cmake_parse_arguments(PARSE_ARGV 2 arg
"IN_CACHE"
""
- "CONFIGS;LANGUAGES"
- ${ARGN})
+ "CONFIGS;LANGUAGES")
+ _qt_internal_validate_all_args_are_parsed(arg)
if(NOT arg_CONFIGS)
message(FATAL_ERROR
@@ -787,13 +905,11 @@ endfunction()
# CMAKE_<LINKER_TYPE>_LINKER_FLAGS_<CONFIG> cache variable.
# e.g EXE, MODULE, SHARED, STATIC.
function(qt_internal_add_linker_flags)
- qt_parse_all_arguments(
- arg
- "qt_internal_add_linker_flags"
+ cmake_parse_arguments(PARSE_ARGV 0 arg
"IN_CACHE"
"FLAGS"
- "CONFIGS;TYPES"
- ${ARGN})
+ "CONFIGS;TYPES")
+ _qt_internal_validate_all_args_are_parsed(arg)
if(NOT arg_TYPES)
message(FATAL_ERROR
@@ -834,13 +950,11 @@ endfunction()
# CMAKE_<LINKER_TYPE>_LINKER_FLAGS_<CONFIG> cache variable.
# e.g EXE, MODULE, SHARED, STATIC.
function(qt_internal_replace_linker_flags match_string replace_string)
- qt_parse_all_arguments(
- arg
- "qt_internal_replace_compiler_flags"
+ cmake_parse_arguments(PARSE_ARGV 2 arg
"IN_CACHE"
""
- "CONFIGS;TYPES"
- ${ARGN})
+ "CONFIGS;TYPES")
+ _qt_internal_validate_all_args_are_parsed(arg)
if(NOT arg_TYPES)
message(FATAL_ERROR
@@ -975,14 +1089,42 @@ function(qt_internal_set_up_config_optimizations_like_in_qmake)
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(config ${configs})
- foreach(lang ${enabled_languages})
+ 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})
+ 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()
diff --git a/cmake/QtFrameworkHelpers.cmake b/cmake/QtFrameworkHelpers.cmake
index 86661ad4f7..750caf2cb8 100644
--- a/cmake/QtFrameworkHelpers.cmake
+++ b/cmake/QtFrameworkHelpers.cmake
@@ -1,7 +1,12 @@
+# 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)
@@ -28,6 +33,11 @@ macro(qt_find_apple_system_frameworks)
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()
@@ -50,7 +60,7 @@ function(qt_internal_find_apple_system_framework out_var framework_name)
endif()
endfunction()
-# Copy header files to QtXYZ.framework/Versions/A/Headers/
+# 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
@@ -61,42 +71,92 @@ function(qt_copy_framework_headers target)
return()
endif()
- set(options PUBLIC PRIVATE QPA)
+ set(options)
set(oneValueArgs)
- set(multiValueArgs)
- cmake_parse_arguments(ARG "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
+ set(multiValueArgs PUBLIC PRIVATE QPA RHI SSG)
+ cmake_parse_arguments(arg "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
qt_internal_get_framework_info(fw ${target})
- set(fw_output_header_dir "${fw_versioned_header_dir}")
- if(ARG_PRIVATE)
- set(fw_output_header_dir "${fw_private_module_header_dir}/private")
- elseif(ARG_QPA)
- set(fw_output_header_dir "${fw_private_module_header_dir}/qpa")
- endif()
-
get_target_property(output_dir ${target} LIBRARY_OUTPUT_DIRECTORY)
- set(fw_output_header_dir "${output_dir}/${fw_output_header_dir}")
+ 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")
- 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_output_header_dir}/${in_file_name}")
- add_custom_command(
- OUTPUT ${out_file_path}
- DEPENDS ${in_file_path}
- COMMAND ${CMAKE_COMMAND} -E make_directory "${fw_output_header_dir}"
- COMMAND ${CMAKE_COMMAND} -E copy "${in_file_path}" "${fw_output_header_dir}"
- VERBATIM)
- list(APPEND out_files ${out_file_path})
+ 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()
- get_target_property(fw_copied_headers ${target} QT_COPIED_FRAMEWORK_HEADERS)
- if(NOT fw_copied_headers)
- set(fw_copied_headers "")
+ 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()
- list(APPEND fw_copied_headers ${out_files})
- set_target_properties(${target} PROPERTIES QT_COPIED_FRAMEWORK_HEADERS "${fw_copied_headers}")
+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)
@@ -110,17 +170,7 @@ function(qt_finalize_framework_headers_copy target)
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_internal_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})
+ 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})
@@ -158,8 +208,13 @@ function(qt_internal_get_framework_info out_var target)
set(${out_var}_name "${module}")
set(${out_var}_dir "${${out_var}_name}.framework")
set(${out_var}_header_dir "${${out_var}_dir}/Headers")
- set(${out_var}_versioned_header_dir "${${out_var}_dir}/Versions/${${out_var}_version}/Headers")
- set(${out_var}_private_header_dir "${${out_var}_header_dir}/${${out_var}_bundle_version}")
+ 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)
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 e3f4bbf881..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.
diff --git a/cmake/QtGenerateLibPri.cmake b/cmake/QtGenerateLibPri.cmake
index 127d859189..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:
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
index bb5a289c85..2df89486c8 100644
--- a/cmake/QtGlobalStateHelpers.cmake
+++ b/cmake/QtGlobalStateHelpers.cmake
@@ -1,3 +1,6 @@
+# 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()
@@ -31,6 +34,26 @@ 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)
diff --git a/cmake/QtHeadersClean.cmake b/cmake/QtHeadersClean.cmake
index c8b43ddfe8..f47ac1754c 100644
--- a/cmake/QtHeadersClean.cmake
+++ b/cmake/QtHeadersClean.cmake
@@ -1,26 +1,25 @@
-# Add a custom ${module_include_name}_header_check target that builds each header in
+# 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_headers_clean_target
- module_target
- module_include_name
- module_headers)
- # module_headers is a list of strings of the form
- # <headerfile>[:feature]
+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(entry ${module_headers})
- string(REPLACE ":" ";" entry_list ${entry})
- list(LENGTH entry_list entry_list_length)
- list(GET entry_list 0 entry_path)
-
- if (${entry_list_length} EQUAL 2)
- list(GET entry_list 1 entry_feature)
- if (NOT QT_FEATURE_${entry_feature})
- message(STATUS "headersclean: Ignoring header ${entry_path} because of missing feature ${entry_feature}")
- continue()
- endif()
+ 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()
- list(APPEND hclean_headers ${entry_path})
endforeach()
# Make sure that the header compiles with our strict options
@@ -28,6 +27,7 @@ function(qt_internal_add_headers_clean_target
-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
@@ -39,7 +39,7 @@ function(qt_internal_add_headers_clean_target
endif()
set(prop_prefix "")
- get_target_property(target_type "${target}" TYPE)
+ get_target_property(target_type "${module_target}" TYPE)
if(target_type STREQUAL "INTERFACE_LIBRARY")
set(prop_prefix "INTERFACE_")
endif()
@@ -50,6 +50,12 @@ function(qt_internal_add_headers_clean_target
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
@@ -99,40 +105,32 @@ function(qt_internal_add_headers_clean_target
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU"
OR "${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang|IntelLLVM")
- # Turn on some extra warnings not found in -Wall -Wextra.
- set(hcleanFLAGS -Wall -Wextra -Werror -Woverloaded-virtual -Wshadow -Wundef -Wfloat-equal
- -Wnon-virtual-dtor -Wpointer-arith -Wformat-security -Wno-long-long -Wno-variadic-macros
- -pedantic-errors)
+ # 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()
- # options accepted by GCC and Clang
- list(APPEND hcleanFLAGS -Wchar-subscripts -Wold-style-cast)
-
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)
- if (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 4.5)
- list(APPEND hcleanFLAGS -Wdouble-promotion)
- endif()
- if (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 4.9)
- list(APPEND hcleanFLAGS -Wfloat-conversion)
-
- # GCC 9 has a lot of false positives relating to these
- list(APPEND hcleanFlags -Wno-deprecated-copy -Wno-redundant-move
- -Wno-format-overflow -Wno-init-list-lifetime)
- endif()
+ list(APPEND hcleanFLAGS -Wzero-as-null-pointer-constant
+ -Wdouble-promotion -Wfloat-conversion)
endif()
- # Use strict mode C++20, with no GNU extensions (see -pedantic-errors above).
- list(APPEND hcleanFLAGS -std=c++2a)
+ 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})
@@ -149,10 +147,7 @@ function(qt_internal_add_headers_clean_target
# If additional package prefixes are provided, we consider they can contain frameworks
# as well.
foreach(prefix IN LISTS _qt_additional_packages_prefix_paths)
- if(prefix MATCHES "/lib/cmake$") # Cut CMake files path
- string(APPEND prefix "/../..")
- endif()
- get_filename_component(prefix "${prefix}" ABSOLUTE)
+ __qt_internal_reverse_prefix_path_from_cmake_dir(path "${path}")
set(libdir "${prefix}/${INSTALL_LIBDIR}")
if(EXISTS "${libdir}")
@@ -162,73 +157,126 @@ function(qt_internal_add_headers_clean_target
endforeach()
endif()
- foreach(header ${hclean_headers})
- get_filename_component(input_path "${header}" ABSOLUTE)
- set(artifact_path "header_check/${header}.o")
- get_filename_component(artifact_directory "${artifact_path}" DIRECTORY)
- set(comment_header_path "${CMAKE_CURRENT_SOURCE_DIR}/${header}")
- file(RELATIVE_PATH comment_header_path "${PROJECT_SOURCE_DIR}" "${comment_header_path}")
-
- add_custom_command(
- OUTPUT "${artifact_path}"
- COMMENT "headersclean: Checking header ${comment_header_path}"
- COMMAND ${CMAKE_COMMAND} -E make_directory "${artifact_directory}"
- COMMAND
- ${compiler_to_run} -c ${cxx_flags}
- "${target_compile_flags_joined_genex}"
- "${target_defines_joined_genex}"
- ${hcleanFLAGS}
- "${target_includes_joined_genex}"
- ${framework_includes}
- ${hcleanDEFS}
- -xc++ "${input_path}"
- -o${artifact_path}
- IMPLICIT_DEPENDS CXX
- VERBATIM
- COMMAND_EXPAND_LISTS)
- list(APPEND hclean_artifacts "${artifact_path}")
- endforeach()
+ 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")
- # -Za would enable strict standards behavior, but we can't add it because
- # <windows.h> and <GL.h> violate the standards.
- set(hcleanFLAGS -std:c++latest -Zc:__cplusplus -WX -W3)
+ # 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)
- foreach(header ${hclean_headers})
- # We need realpath here to make sure path starts with drive letter
- get_filename_component(input_path "${header}" REALPATH)
- set(artifact_path "header_${header}.o")
- set(comment_header_path "${CMAKE_CURRENT_SOURCE_DIR}/${header}")
- file(RELATIVE_PATH comment_header_path "${PROJECT_SOURCE_DIR}" "${comment_header_path}")
-
- add_custom_command(
- OUTPUT "${artifact_path}"
- COMMENT "headersclean: Checking header ${comment_header_path}"
- COMMAND
- ${compiler_to_run} -nologo -c ${CMAKE_CXX_FLAGS}
- "${target_compile_flags_joined_genex}"
- "${target_defines_joined_genex}"
- ${hcleanFLAGS}
- "${target_includes_joined_genex}"
- ${hcleanDEFS}
- -FI "${input_path}"
- -Fo${artifact_path} "${source_path}"
- IMPLICIT_DEPENDS CXX
- VERBATIM
- COMMAND_EXPAND_LISTS)
- list(APPEND hclean_artifacts "${artifact_path}")
- endforeach()
+ 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(ERROR "CMAKE_CXX_COMPILER_ID \"${CMAKE_CXX_COMPILER_ID}\" is not supported for the headersclean check.")
+ message(FATAL_ERROR "CMAKE_CXX_COMPILER_ID \"${CMAKE_CXX_COMPILER_ID}\" is not supported"
+ " for the headersclean check.")
endif()
- add_custom_target(${module_include_name}_header_check
- COMMENT "headersclean: Checking headers in ${module_include_name}"
+ 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)
- add_dependencies(${module_target} ${module_include_name}_header_check)
+ 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 7933b8b500..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@")
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
index 97a2ecc164..deab48cda5 100644
--- a/cmake/QtInstallHelpers.cmake
+++ b/cmake/QtInstallHelpers.cmake
@@ -1,3 +1,6 @@
+# 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)
@@ -92,12 +95,27 @@ function(qt_copy_or_install)
qt_non_prefix_copy(COPY ${argv_copy} ${copy_arguments})
endfunction()
-# Create a versioned hard-link for the given target.
+# Create a versioned hard-link for the given target, or a program
# E.g. "bin/qmake6" -> "bin/qmake".
-# If no hard link can be created, make a copy instead.
+#
+# 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 install_dir target)
+function(qt_internal_install_versioned_link)
if(NOT QT_WILL_INSTALL)
return()
endif()
@@ -106,13 +124,41 @@ function(qt_internal_install_versioned_link install_dir target)
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}" "$<TARGET_FILE_BASE_NAME:${target}>")
- set(original "${install_base_file_path}$<TARGET_FILE_SUFFIX:${target}>")
- set(linkname "${install_base_file_path}${PROJECT_VERSION_MAJOR}$<TARGET_FILE_SUFFIX:${target}>")
+ "${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]:\")"
@@ -137,3 +183,67 @@ function(qt_internal_install_versioned_link install_dir target)
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 78c5ec898e..d7eadc1a73 100644
--- a/cmake/QtInternalTargets.cmake
+++ b/cmake/QtInternalTargets.cmake
@@ -1,3 +1,6 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
function(qt_internal_set_warnings_are_errors_flags target target_scope)
set(flags "")
@@ -8,6 +11,11 @@ function(qt_internal_set_warnings_are_errors_flags target target_scope)
# 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
@@ -40,6 +48,11 @@ function(qt_internal_set_warnings_are_errors_flags target target_scope)
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")
@@ -63,7 +76,7 @@ function(qt_internal_set_warnings_are_errors_flags target target_scope)
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>>")
@@ -89,7 +102,7 @@ function(qt_internal_add_global_definition definition)
set(optional_args)
set(single_value_args VALUE)
set(multi_value_args SCOPE)
- cmake_parse_arguments(args
+ cmake_parse_arguments(arg
"${optional_args}"
"${single_value_args}"
"${multi_value_args}"
@@ -123,27 +136,32 @@ function(qt_internal_add_global_definition definition)
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 INTERFACE)
@@ -154,6 +172,8 @@ 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
@@ -191,6 +211,14 @@ function(qt_internal_apply_bitcode_flags target)
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
@@ -201,6 +229,31 @@ elseif(UIKIT)
target_compile_definitions(PlatformCommonInternal INTERFACE GLES_SILENCE_DEPRECATION)
endif()
+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()
+
+ # 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"
@@ -208,25 +261,12 @@ if(MSVC)
)
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)
- endif()
- qt_internal_apply_bitcode_flags(PlatformCommonInternal)
-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
@@ -237,21 +277,20 @@ if (MSVC)
if (MSVC_VERSION GREATER_EQUAL 1899)
target_compile_options(PlatformCommonInternal INTERFACE
-Zc:strictStrings
+ -Zc:throwingNew
)
- if (NOT CLANG)
- target_compile_options(PlatformCommonInternal INTERFACE
- -Zc:throwingNew
- )
- endif()
endif()
- if (MSVC_VERSION GREATER_EQUAL 1909 AND NOT CLANG)
+ if (MSVC_VERSION GREATER_EQUAL 1909) # MSVC 2017
target_compile_options(PlatformCommonInternal INTERFACE
-Zc:referenceBinding
+ -Zc:ternary
)
endif()
- if (MSVC_VERSION GREATER_EQUAL 1919 AND NOT CLANG)
+ 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()
@@ -264,7 +303,7 @@ if (MSVC)
$<$<NOT:$<CONFIG:Debug>>:-guard:cf -Gw>
)
- target_link_options(PlatformCommonInternal INTERFACE
+ qt_internal_platform_link_options(PlatformCommonInternal INTERFACE
-DYNAMICBASE -NXCOMPAT -LARGEADDRESSAWARE
$<$<NOT:$<CONFIG:Debug>>:-OPT:REF -OPT:ICF -GUARD:CF>
)
@@ -278,21 +317,52 @@ 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)
- target_compile_options(PlatformCommonInternal INTERFACE
- -guard:ehcont
- )
- target_link_options(PlatformCommonInternal INTERFACE
- -guard:ehcont -CETCOMPAT
- )
+ qt_internal_platform_link_options(PlatformCommonInternal INTERFACE -CETCOMPAT)
else()
- target_compile_options(PlatformCommonInternal INTERFACE
- -fcf-protection
- )
+ 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()
@@ -312,30 +382,40 @@ 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})
- target_link_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)
- target_link_options(PlatformCommonInternal INTERFACE "${__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)
- target_link_options(PlatformCommonInternal INTERFACE "-Wl,--gdb-index")
+ qt_internal_platform_link_options(PlatformCommonInternal INTERFACE "-Wl,--gdb-index")
endif()
if(QT_FEATURE_enable_new_dtags)
- target_link_options(PlatformCommonInternal INTERFACE "-Wl,--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()
diff --git a/cmake/QtJavaHelpers.cmake b/cmake/QtJavaHelpers.cmake
index f362cb3863..ec9b611c5e 100644
--- a/cmake/QtJavaHelpers.cmake
+++ b/cmake/QtJavaHelpers.cmake
@@ -1,6 +1,13 @@
+# 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)
@@ -12,7 +19,12 @@ function(qt_internal_add_jar target)
set(javac_source_version "8")
endif()
- set(CMAKE_JAVA_COMPILE_FLAGS -source "${javac_source_version}" -target "${javac_target_version}" -Xlint:unchecked -bootclasspath "${QT_ANDROID_JAR}")
+ 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
index cdc24e5ac2..a63d8e9504 100644
--- a/cmake/QtLalrHelpers.cmake
+++ b/cmake/QtLalrHelpers.cmake
@@ -1,3 +1,6 @@
+# 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)
@@ -32,6 +35,15 @@ function(qt_process_qlalr consuming_target input_file_list flags)
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")
@@ -49,8 +61,8 @@ function(qt_process_qlalr consuming_target input_file_list flags)
"${absolute_input_file}")
set(cpp_file "${parser}.cpp")
- set(private_file "${parser}_p.h")
- set(decl_file "${decl}")
+ 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}
@@ -59,6 +71,7 @@ function(qt_process_qlalr consuming_target input_file_list flags)
MAIN_DEPENDENCY ${input_file}
VERBATIM
)
- target_sources(${consuming_target} PRIVATE ${cpp_file} ${impl_file})
+ 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 76c918a774..06a7daad71 100644
--- a/cmake/QtModuleConfig.cmake.in
+++ b/cmake/QtModuleConfig.cmake.in
@@ -1,3 +1,6 @@
+# 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@)
@@ -14,6 +17,8 @@ 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.
@@ -25,9 +30,8 @@ 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()
+ include("${CMAKE_CURRENT_LIST_DIR}/@INSTALL_CMAKE_NAMESPACE@@target@ExtraProperties.cmake"
+ OPTIONAL)
# DEPRECATED
# Provide old style variables for includes, compile definitions, etc.
@@ -70,15 +74,25 @@ if (NOT QT_NO_CREATE_TARGETS AND @INSTALL_CMAKE_NAMESPACE@@target@_FOUND)
${_@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)
@@ -87,12 +101,12 @@ if (NOT QT_NO_CREATE_TARGETS AND @INSTALL_CMAKE_NAMESPACE@@target@_FOUND)
endif()
if (TARGET @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()
- qt_make_features_available(@QT_CMAKE_EXPORT_NAMESPACE@::@target@)
-
if(EXISTS "${CMAKE_CURRENT_LIST_DIR}/@INSTALL_CMAKE_NAMESPACE@@target@Plugins.cmake")
include("${CMAKE_CURRENT_LIST_DIR}/@INSTALL_CMAKE_NAMESPACE@@target@Plugins.cmake")
endif()
@@ -114,12 +128,20 @@ if (TARGET @QT_CMAKE_EXPORT_NAMESPACE@::@target@)
EXISTS "${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. ${@INSTALL_CMAKE_NAMESPACE@@target@_extra_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
diff --git a/cmake/QtModuleDependencies.cmake.in b/cmake/QtModuleDependencies.cmake.in
index c7c986bfba..ba5922d1e2 100644
--- a/cmake/QtModuleDependencies.cmake.in
+++ b/cmake/QtModuleDependencies.cmake.in
@@ -1,3 +1,6 @@
+# Copyright (C) 2024 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Make sure @INSTALL_CMAKE_NAMESPACE@ is found before anything else.
set(@INSTALL_CMAKE_NAMESPACE@@target@_FOUND FALSE)
@@ -8,92 +11,36 @@ 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()
-find_dependency(@INSTALL_CMAKE_NAMESPACE@ @PROJECT_VERSION@
- PATHS
- "${CMAKE_CURRENT_LIST_DIR}/.."
- "${_qt_cmake_dir}"
- ${_qt_additional_packages_prefix_paths}
- ${QT_EXAMPLES_CMAKE_PREFIX_PATH}
- ${__qt_use_no_default_path_for_qt_packages}
-)
-
-# note: _third_party_deps example: "ICU\\;FALSE\\;1.0\\;i18n uc data;ZLIB\\;FALSE\\;\\;"
-set(__qt_@target@_third_party_deps "@third_party_deps@")
-
-foreach(__qt_@target@_target_dep ${__qt_@target@_third_party_deps})
- 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()
-
- 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()
-
-# Find Qt tool package.
-set(__qt_@target@_tool_deps "@main_module_tool_deps@")
-
-if(__qt_@target@_tool_deps 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 ${__qt_@target@_tool_deps})
- list(GET __qt_@target@_target_dep 0 __qt_@target@_pkg)
- list(GET __qt_@target@_target_dep 1 __qt_@target@_version)
+# 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)
- unset(__qt_@target@_find_package_args)
- if(${CMAKE_FIND_PACKAGE_NAME}_FIND_QUIETLY)
- list(APPEND __qt_@target@_find_package_args QUIET)
- endif()
- if(${CMAKE_FIND_PACKAGE_NAME}_FIND_REQUIRED)
- list(APPEND __qt_@target@_find_package_args REQUIRED)
- endif()
- find_package(${__qt_@target@_pkg} ${__qt_@target@_version} ${__qt_@target@_find_package_args}
+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}
)
- if (NOT ${__qt_@target@_pkg}_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(__qt_@target@_tool_deps 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()
+
+# 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)
+
+# 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(__qt_@target@_target_deps "@target_deps@")
set(__qt_@target@_find_dependency_paths "${CMAKE_CURRENT_LIST_DIR}/.." "${_qt_cmake_dir}")
-_qt_internal_find_dependencies(__qt_@target@_target_deps __qt_@target@_find_dependency_paths)
+_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
index 0d17d0b362..ba03173073 100644
--- a/cmake/QtModuleHelpers.cmake
+++ b/cmake/QtModuleHelpers.cmake
@@ -1,3 +1,6 @@
+# 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
@@ -12,9 +15,10 @@ macro(qt_internal_get_internal_add_module_keywords option_args single_args multi
NO_CONFIG_HEADER_FILE
NO_ADDITIONAL_TARGET_INFO
NO_GENERATE_METATYPES
- GENERATE_CPP_EXPORTS # TODO: Rename to NO_GENERATE_CPP_EXPORTS once migration is done
- GENERATE_METATYPES # TODO: Remove once it is not used anymore
- GENERATE_PRIVATE_CPP_EXPORTS
+ NO_HEADERSCLEAN_CHECK
+ GENERATE_CPP_EXPORTS # deprecated
+ NO_GENERATE_CPP_EXPORTS
+ NO_UNITY_BUILD
)
set(${single_args}
MODULE_INCLUDE_NAME
@@ -24,20 +28,43 @@ macro(qt_internal_get_internal_add_module_keywords option_args single_args multi
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
- NO_PCH_SOURCES
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.
@@ -80,7 +107,28 @@ endmacro()
# 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
@@ -88,14 +136,16 @@ function(qt_internal_add_module target)
module_multi_args
)
- qt_parse_all_arguments(arg "qt_internal_add_module"
+ cmake_parse_arguments(PARSE_ARGV 1 arg
"${module_option_args}"
"${module_single_args}"
"${module_multi_args}"
- ${ARGN}
)
+ _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
@@ -153,8 +203,32 @@ function(qt_internal_add_module target)
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"
)
- set_property(TARGET ${target} APPEND PROPERTY EXPORT_PROPERTIES _qt_module_interface_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}")
@@ -169,6 +243,13 @@ function(qt_internal_add_module target)
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)
@@ -201,7 +282,7 @@ function(qt_internal_add_module target)
qt_internal_get_framework_info(fw ${target})
endif()
- if(NOT QT_FEATURE_no_extern_direct_access AND QT_FEATURE_reduce_relocations AND
+ 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
@@ -238,9 +319,32 @@ function(qt_internal_add_module target)
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_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 _qt_config_module_name)
+ 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)
@@ -248,9 +352,8 @@ function(qt_internal_add_module target)
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}
- )
+ ${version_args}
+ )
qt_set_target_info_properties(${target} ${ARGN})
qt_handle_multi_config_output_dirs("${target}")
@@ -307,102 +410,90 @@ function(qt_internal_add_module target)
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}")
-
- # 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} RESULT_VARIABLE syncqt_ret)
- if(NOT syncqt_ret EQUAL 0)
- message(FATAL_ERROR "Failed to run syncqt, return code: ${syncqt_ret}")
- endif()
-
- set_target_properties("${target}" PROPERTIES
- _qt_module_has_headers ON)
-
- ### FIXME: Can we replace headers.pri?
- qt_read_headers_pri("${module_build_interface_include_dir}" "module_headers")
+ _qt_module_include_name "${module_include_name}"
+ _qt_module_has_headers ON
+ )
- if(arg_EXTERNAL_HEADERS)
- set(module_headers_public ${arg_EXTERNAL_HEADERS})
+ 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_property(TARGET ${target} APPEND PROPERTY
- _qt_module_timestamp_dependencies "${module_headers_public}")
-
+ 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(arg_GENERATE_CPP_EXPORTS AND NOT arg_STATIC)
+ 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()
- if(arg_GENERATE_PRIVATE_CPP_EXPORTS)
- set(generate_private_cpp_export "GENERATE_PRIVATE_CPP_EXPORTS")
- endif()
qt_internal_generate_cpp_global_exports(${target} ${module_define_infix}
"${cpp_export_header_base_name}"
- "${generate_private_cpp_export}"
)
endif()
set(module_depends_header
"${module_build_interface_include_dir}/${module_include_name}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_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_build_interface_include_dir}/${module_include_name}")
+ "${module_header}")
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 "${module_install_interface_qpa_include_dir}")
- 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")
- # 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}")
-
- # Export the plugin types.
- set_property(TARGET ${target} APPEND PROPERTY EXPORT_PROPERTIES MODULE_PLUGIN_TYPES)
+ qt_internal_add_plugin_types("${target}" "${arg_PLUGIN_TYPES}")
endif()
endif()
@@ -434,15 +525,15 @@ function(qt_internal_add_module target)
# 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.
+ # 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.
- if(module_headers_private)
- list(APPEND private_includes
- "$<BUILD_INTERFACE:${module_build_interface_versioned_include_dir}>"
- "$<BUILD_INTERFACE:${module_build_interface_versioned_inner_include_dir}>")
- endif()
+ 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
@@ -487,26 +578,12 @@ function(qt_internal_add_module target)
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 "$<TARGET_PROPERTY:${target},_qt_module_timestamp_dependencies>"
- 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_infix}_LIB ### FIXME: use QT_BUILD_ADDON for Add-ons or remove if we don't have add-ons anymore
@@ -517,11 +594,27 @@ function(qt_internal_add_module target)
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}"
- ${header_module}
- SOURCES ${arg_SOURCES}
+ ${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
@@ -574,39 +667,13 @@ function(qt_internal_add_module target)
include(${configureFile})
qt_feature_module_end("${target}")
- set_property(TARGET "${target}" APPEND PROPERTY
- PUBLIC_HEADER "${CMAKE_CURRENT_BINARY_DIR}/${module_config_header}"
- )
- set_property(TARGET "${target}" APPEND PROPERTY
- PRIVATE_HEADER "${CMAKE_CURRENT_BINARY_DIR}/${module_config_private_header}"
+ qt_internal_extend_target("${target}"
+ SOURCES
+ "${CMAKE_CURRENT_BINARY_DIR}/${module_config_header}"
+ "${CMAKE_CURRENT_BINARY_DIR}/${module_config_private_header}"
)
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})
@@ -618,8 +685,21 @@ function(qt_internal_add_module target)
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)
@@ -631,6 +711,11 @@ set(QT_VISIBILITY_AVAILABLE TRUE)")
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"
@@ -644,29 +729,40 @@ set(QT_LIBINFIX \"${QT_LIBINFIX}\")")
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 "")
- # Generate metatypes
- if(${arg_GENERATE_METATYPES})
- # No mention of NO_GENERATE_METATYPES. You should not use it.
- message(WARNING "GENERATE_METATYPES is on by default for Qt modules. Please remove the manual specification.")
+ 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()
- if (NOT ${arg_NO_GENERATE_METATYPES})
- if (NOT target_type STREQUAL "INTERFACE_LIBRARY")
- set(args "")
- if(QT_WILL_INSTALL)
- set(metatypes_install_dir "${INSTALL_LIBDIR}/metatypes")
- list(APPEND args
- __QT_INTERNAL_INSTALL __QT_INTERNAL_INSTALL_DIR "${metatypes_install_dir}")
- endif()
- qt6_extract_metatypes(${target} ${args})
- elseif(${arg_GENERATE_METATYPES})
- message(FATAL_ERROR "Meta types generation does not work on interface libraries")
+
+ # 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(
@@ -706,14 +802,6 @@ set(QT_LIBINFIX \"${QT_LIBINFIX}\")")
list(APPEND exported_targets ${target_private})
endif()
set(export_name "${INSTALL_CMAKE_NAMESPACE}${target}Targets")
- if(arg_EXTERNAL_HEADERS_DIR)
- qt_install(DIRECTORY "${arg_EXTERNAL_HEADERS_DIR}/"
- DESTINATION "${module_install_interface_include_dir}"
- )
- unset(public_header_destination)
- else()
- set(public_header_destination PUBLIC_HEADER DESTINATION "${module_install_interface_include_dir}")
- endif()
qt_install(TARGETS ${exported_targets}
EXPORT ${export_name}
@@ -721,9 +809,7 @@ set(QT_LIBINFIX \"${QT_LIBINFIX}\")")
LIBRARY DESTINATION ${INSTALL_LIBDIR}
ARCHIVE DESTINATION ${INSTALL_LIBDIR}
FRAMEWORK DESTINATION ${INSTALL_LIBDIR}
- PRIVATE_HEADER DESTINATION "${module_install_interface_private_include_dir}"
- ${public_header_destination}
- )
+ )
if(BUILD_SHARED_LIBS)
qt_apply_rpaths(TARGET "${target}" INSTALL_PATH "${INSTALL_LIBDIR}" RELATIVE_RPATH)
@@ -751,7 +837,14 @@ set(QT_LIBINFIX \"${QT_LIBINFIX}\")")
qt_internal_export_modern_cmake_config_targets_file(
TARGETS ${exported_targets}
EXPORT_NAME_PREFIX ${INSTALL_CMAKE_NAMESPACE}${target}
- CONFIG_INSTALL_DIR "${config_install_dir}")
+ 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.
@@ -763,39 +856,36 @@ set(QT_LIBINFIX \"${QT_LIBINFIX}\")")
# Handle cases like QmlDevToolsPrivate which do not have their own headers, but rather borrow them
# from another module.
- if(NOT arg_NO_SYNC_QT)
+ if(NOT arg_NO_SYNC_QT AND NOT arg_NO_MODULE_HEADERS)
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
+ # 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.
- if(NOT arg_NO_MODULE_HEADERS
- AND EXISTS "${module_build_interface_versioned_inner_include_dir}")
- list(APPEND interface_includes
- "$<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}")
- list(APPEND interface_includes
- "$<INSTALL_INTERFACE:${fw_install_private_header_dir}>"
- "$<INSTALL_INTERFACE:${fw_install_private_module_header_dir}>")
- else()
- list(APPEND interface_includes
- "$<INSTALL_INTERFACE:${module_install_interface_versioned_include_dir}>"
- "$<INSTALL_INTERFACE:${module_install_interface_versioned_inner_include_dir}>")
- endif()
- endif()
- endif()
+ 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(QT_FEATURE_headersclean AND NOT arg_NO_MODULE_HEADERS)
- qt_internal_add_headers_clean_target(
- ${target}
- "${module_include_name}"
- "${module_headers_clean}")
+ 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)
@@ -823,14 +913,49 @@ set(QT_LIBINFIX \"${QT_LIBINFIX}\")")
endif()
qt_describe_module(${target})
- qt_add_list_file_finalizer(qt_finalize_module ${target} ${arg_INTERNAL_MODULE} ${arg_NO_PRIVATE_MODULE} ${header_module})
+ 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.
@@ -857,6 +982,8 @@ endfunction()
# * 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.
#
@@ -879,6 +1006,12 @@ endfunction()
# * 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
@@ -913,6 +1046,10 @@ the different base name for the module info variables.")
"${${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")
@@ -926,8 +1063,12 @@ the different base name for the module info variables.")
"${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 direcotries
+ # 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}")
@@ -939,6 +1080,10 @@ the different base name for the module info variables.")
"${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)
@@ -952,6 +1097,8 @@ the different base name for the module info variables.")
"${${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
@@ -966,6 +1113,10 @@ the different base name for the module info variables.")
"${${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)
@@ -979,6 +1130,21 @@ the different base name for the module info variables.")
"${${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
@@ -989,10 +1155,41 @@ function(qt_describe_module target)
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}")
@@ -1000,7 +1197,7 @@ endfunction()
function(qt_internal_generate_cpp_global_exports target module_define_infix)
cmake_parse_arguments(arg
- "GENERATE_PRIVATE_CPP_EXPORTS"
+ ""
"CPP_EXPORT_HEADER_BASE_NAME"
"" ${ARGN}
)
@@ -1024,49 +1221,190 @@ function(qt_internal_generate_cpp_global_exports target module_define_infix)
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()
- if(arg_GENERATE_PRIVATE_CPP_EXPORTS)
- set(generated_private_header_path
- "${module_build_interface_private_include_dir}/${header_base_name}_p.h"
- )
+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})
- configure_file("${QT_CMAKE_DIR}/modulecppexports_p.h.in"
- "${generated_private_header_path}" @ONLY
- )
+ 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()
- set(${out_private_header} "${generated_private_header_path}" PARENT_SCOPE)
- target_sources(${target} PRIVATE "${generated_private_header_path}")
+
+ 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 "")
- get_target_property(is_framework ${target} FRAMEWORK)
+ qt_internal_get_target_sources(sources ${target})
get_target_property(target_type ${target} TYPE)
- set(is_interface_lib 0)
if(target_type STREQUAL "INTERFACE_LIBRARY")
- set(is_interface_lib 1)
+ 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()
- set_property(TARGET ${target} APPEND PROPERTY
- _qt_module_timestamp_dependencies "${generated_header_path}")
+ get_source_file_property(non_module_header ${file_path} _qt_non_module_header)
+ if(non_module_header)
+ continue()
+ endif()
- if(is_framework)
- if(NOT is_interface_lib)
- qt_copy_framework_headers(${target} PUBLIC "${generated_header_path}")
+ get_filename_component(file_path "${file_path}" ABSOLUTE)
- if(arg_GENERATE_PRIVATE_CPP_EXPORTS)
- qt_copy_framework_headers(${target} PRIVATE "${generated_private_header_path}")
- endif()
+ 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()
- else()
- set_property(TARGET ${target} APPEND PROPERTY PUBLIC_HEADER "${generated_header_path}")
- qt_install(FILES "${generated_header_path}"
- DESTINATION "${module_install_interface_include_dir}")
-
- if(arg_GENERATE_PRIVATE_CPP_EXPORTS)
- set_property(TARGET ${target} APPEND PROPERTY PRIVATE_HEADER
- "${generated_private_header_path}")
- qt_install(FILES "${generated_private_header_path}"
- DESTINATION "${module_install_interface_private_include_dir}")
+
+ 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 fdbc853646..ec447aa55b 100644
--- a/cmake/QtModuleToolsConfig.cmake.in
+++ b/cmake/QtModuleToolsConfig.cmake.in
@@ -1,15 +1,24 @@
+# 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)
diff --git a/cmake/QtModuleToolsDependencies.cmake.in b/cmake/QtModuleToolsDependencies.cmake.in
index 2eaaf74976..b2504a0943 100644
--- a/cmake/QtModuleToolsDependencies.cmake.in
+++ b/cmake/QtModuleToolsDependencies.cmake.in
@@ -1,3 +1,6 @@
+# Copyright (C) 2024 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Find "ModuleTools" dependencies, which are other ModuleTools packages.
set(@INSTALL_CMAKE_NAMESPACE@@target@_FOUND FALSE)
set(__qt_@target@_tool_deps "@package_deps@")
diff --git a/cmake/QtModuleToolsVersionlessTargets.cmake.in b/cmake/QtModuleToolsVersionlessTargets.cmake.in
index 0cf554c34a..bc861a77b6 100644
--- a/cmake/QtModuleToolsVersionlessTargets.cmake.in
+++ b/cmake/QtModuleToolsVersionlessTargets.cmake.in
@@ -1,3 +1,6 @@
+# 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 GLOBAL)
diff --git a/cmake/QtNoLinkTargetHelpers.cmake b/cmake/QtNoLinkTargetHelpers.cmake
index debf1eb3cd..59dc3ff5ac 100644
--- a/cmake/QtNoLinkTargetHelpers.cmake
+++ b/cmake/QtNoLinkTargetHelpers.cmake
@@ -1,3 +1,6 @@
+# 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.")
@@ -26,7 +29,7 @@ function(qt_create_nolink_target target dependee_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
+ # 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.
diff --git a/cmake/QtPkgConfigHelpers.cmake b/cmake/QtPkgConfigHelpers.cmake
index 21a09365f2..dbe736c438 100644
--- a/cmake/QtPkgConfigHelpers.cmake
+++ b/cmake/QtPkgConfigHelpers.cmake
@@ -1,3 +1,6 @@
+# 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")
@@ -19,7 +22,8 @@ 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")
+ 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)
@@ -47,6 +51,17 @@ function(qt_internal_generate_pkg_config_file module)
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)
diff --git a/cmake/QtPlatformAndroid.cmake b/cmake/QtPlatformAndroid.cmake
index a14c5626b3..e4253b75d7 100644
--- a/cmake/QtPlatformAndroid.cmake
+++ b/cmake/QtPlatformAndroid.cmake
@@ -1,3 +1,6 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
#
# Self contained Platform Settings for Android
#
@@ -33,7 +36,7 @@ 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-31")
+set(QT_ANDROID_API_VERSION "android-33")
function(qt_internal_sort_android_platforms out_var)
if(CMAKE_VERSION GREATER_EQUAL 3.18)
@@ -182,7 +185,7 @@ define_property(TARGET
)
# Returns test execution arguments for Android targets
-function(qt_internal_android_test_arguments target out_test_runner out_test_arguments)
+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")
@@ -192,14 +195,19 @@ function(qt_internal_android_test_arguments target out_test_runner out_test_argu
endif()
set(target_binary_dir "$<TARGET_PROPERTY:${target},BINARY_DIR>")
- set(apk_dir "${target_binary_dir}/android-build")
-
+ 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"
+ "--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
)
diff --git a/cmake/QtPlatformSupport.cmake b/cmake/QtPlatformSupport.cmake
index 22c6b9e056..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,7 +12,6 @@ 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?
@@ -17,6 +19,7 @@ qt_set01(OPENBSD CMAKE_SYSTEM_NAME STREQUAL "OpenBSD") # FIXME: How to identify
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" 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")
@@ -29,7 +32,8 @@ 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")
diff --git a/cmake/QtPlatformTargetHelpers.cmake b/cmake/QtPlatformTargetHelpers.cmake
index 4d5ad79374..f1976b9975 100644
--- a/cmake/QtPlatformTargetHelpers.cmake
+++ b/cmake/QtPlatformTargetHelpers.cmake
@@ -1,3 +1,6 @@
+# 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)
@@ -19,6 +22,13 @@ function(qt_internal_setup_public_platform_target)
)
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.
@@ -34,8 +44,18 @@ function(qt_internal_setup_public_platform_target)
endif()
target_link_options(Platform INTERFACE "${libc_link_option}")
endif()
- if (QT_FEATURE_no_extern_direct_access)
- target_compile_options(Platform INTERFACE "-mno-direct-extern-access")
+ 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)
diff --git a/cmake/QtPluginConfig.cmake.in b/cmake/QtPluginConfig.cmake.in
index 7bd9a1d579..1dc30b0338 100644
--- a/cmake/QtPluginConfig.cmake.in
+++ b/cmake/QtPluginConfig.cmake.in
@@ -1,6 +1,9 @@
+# Copyright (C) 2024 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
include_guard(DIRECTORY)
-if(DEFINED QT_REPO_DEPENDENCIES AND NOT QT_BUILD_STANDALONE_TESTS)
+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)
diff --git a/cmake/QtPluginDependencies.cmake.in b/cmake/QtPluginDependencies.cmake.in
index 81b66837f0..bcbb9bb5db 100644
--- a/cmake/QtPluginDependencies.cmake.in
+++ b/cmake/QtPluginDependencies.cmake.in
@@ -1,36 +1,11 @@
+# Copyright (C) 2024 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
set(@target@_FOUND FALSE)
# note: _third_party_deps example: "ICU\\;FALSE\\;1.0\\;i18n uc data;ZLIB\\;FALSE\\;\\;"
set(__qt_@target@_third_party_deps "@third_party_deps@")
-
-foreach(__qt_@target@_target_dep ${__qt_@target@_third_party_deps})
- 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()
-
- 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()
+_qt_internal_find_third_party_dependencies("@target@" __qt_@target@_third_party_deps)
set(__qt_use_no_default_path_for_qt_packages "NO_DEFAULT_PATH")
if(QT_DISABLE_NO_DEFAULT_PATH_IN_QT_PACKAGES)
@@ -40,6 +15,7 @@ endif()
# note: target_deps example: "Qt6Core\;5.12.0;Qt6Gui\;5.12.0"
set(__qt_@target@_target_deps "@target_deps@")
set(__qt_@target@_find_dependency_paths "@find_dependency_paths@")
-_qt_internal_find_dependencies(__qt_@target@_target_deps __qt_@target@_find_dependency_paths)
+_qt_internal_find_qt_dependencies("@target@" __qt_@target@_target_deps
+ __qt_@target@_find_dependency_paths)
set(@target@_FOUND TRUE)
diff --git a/cmake/QtPluginHelpers.cmake b/cmake/QtPluginHelpers.cmake
index 03ff7de1c9..9437d4236d 100644
--- a/cmake/QtPluginHelpers.cmake
+++ b/cmake/QtPluginHelpers.cmake
@@ -1,3 +1,6 @@
+# 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)
@@ -5,6 +8,7 @@ macro(qt_internal_get_internal_add_plugin_keywords option_args single_args multi
EXCEPTIONS
ALLOW_UNDEFINED_SYMBOLS
SKIP_INSTALL
+ NO_UNITY_BUILD
)
set(${single_args}
OUTPUT_DIRECTORY
@@ -40,12 +44,12 @@ function(qt_internal_add_plugin target)
set(single_args ${public_single_args} ${internal_single_args})
set(multi_args ${public_multi_args} ${internal_multi_args})
- qt_parse_all_arguments(arg "qt_internal_add_plugin"
+ cmake_parse_arguments(PARSE_ARGV 1 arg
"${option_args}"
"${single_args}"
"${multi_args}"
- "${ARGN}"
)
+ _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.
@@ -87,6 +91,11 @@ function(qt_internal_add_plugin 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.
@@ -117,7 +126,14 @@ function(qt_internal_add_plugin target)
endif()
endif()
- qt_set_target_info_properties(${target} ${ARGN} TARGET_VERSION "${arg_VERSION}")
+ 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.
@@ -196,70 +212,85 @@ function(qt_internal_add_plugin target)
endif()
get_target_property(is_imported_qt_module ${qt_module_target} IMPORTED)
- # 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)
# This QT_PLUGINS assignment is only used by QtPostProcessHelpers to decide if a
- # QtModulePlugins.cmake file should be generated (which only happens in static builds).
+ # 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()
- 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)
+ 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()
- # 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)
+ # 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
- _qt_initial_repo_plugins
- "${target}")
+ ${prop_prefix}_plugins "${target}")
set_property(TARGET ${qt_module_target} APPEND PROPERTY
- _qt_initial_repo_plugin_class_names
- "$<TARGET_PROPERTY:${target},QT_PLUGIN_CLASS_NAME>"
+ ${prop_prefix}_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()
+ 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.
@@ -277,6 +308,12 @@ function(qt_internal_add_plugin target)
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}")
@@ -302,10 +339,23 @@ function(qt_internal_add_plugin target)
${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
@@ -316,10 +366,10 @@ function(qt_internal_add_plugin target)
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}"
+ 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}
@@ -344,13 +394,8 @@ function(qt_internal_add_plugin target)
endforeach()
qt_register_target_dependencies("${target}" "${arg_PUBLIC_LIBRARIES}" "${qt_libs_private}")
- if (NOT BUILD_SHARED_LIBS)
-
- # There's no point in generating pri files for qml plugins. We didn't do it in Qt5 times.
- if(NOT plugin_type_escaped STREQUAL "qml_plugin")
- qt_generate_plugin_pri_file("${target}" pri_file)
- endif()
+ if(target_type STREQUAL STATIC_LIBRARY)
if(qt_module_target)
qt_internal_link_internal_platform_for_object_library("${plugin_init_target}")
endif()
@@ -400,9 +445,6 @@ function(qt_internal_add_plugin target)
DESTINATION "${config_install_dir}"
COMPONENT Devel
)
- if(pri_file)
- qt_install(FILES "${pri_file}" DESTINATION "${INSTALL_MKSPECSDIR}/modules")
- endif()
# 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.
@@ -451,11 +493,19 @@ function(qt_finalize_plugin target)
_qt_internal_generate_win32_rc_file("${target}")
endif()
- # Generate .prl files for plugins of static Qt builds.
- if(NOT BUILD_SHARED_LIBS)
+ # 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()
@@ -488,3 +538,88 @@ function(qt_internal_get_module_for_plugin target target_type out_var)
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 a96588cc5e..e668a4cbef 100644
--- a/cmake/QtPlugins.cmake.in
+++ b/cmake/QtPlugins.cmake.in
@@ -1,67 +1,14 @@
+# Copyright (C) 2024 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
include_guard(DIRECTORY)
@QT_MODULE_PLUGIN_INCLUDES@
-# Use a function to hide all the temporary variables we use so they don't leak
-# out into the consuming scope
-function(__qt_internal_add_static_plugins_once)
- set(_module_target "@INSTALL_CMAKE_NAMESPACE@::@QT_MODULE@")
- set(_qt_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 ${_module_target} ALIASED_TARGET)
- if(_aliased_target)
- set(_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_plugin_config_files "${CMAKE_CURRENT_LIST_DIR}/@INSTALL_CMAKE_NAMESPACE@*PluginConfig.cmake")
- foreach(_config_file ${_qt_plugin_config_files})
- string(REGEX REPLACE "^.*/@INSTALL_CMAKE_NAMESPACE@(.*Plugin)Config.cmake$" "\\1" _qt_plugin "${_config_file}")
- include("${_config_file}")
- if(TARGET "@INSTALL_CMAKE_NAMESPACE@::${_qt_plugin}")
- list(APPEND _qt_plugins ${_qt_plugin})
- endif()
- endforeach()
- set_property(TARGET ${_module_target} PROPERTY _qt_plugins ${_qt_plugins})
-
- # TODO: Deprecated. Remove in Qt 7.
- set_property(TARGET ${_module_target} PROPERTY QT_PLUGINS ${_qt_plugins})
-
- get_target_property(_have_added_plugins_already ${_module_target} __qt_internal_plugins_added)
- if(_have_added_plugins_already)
- return()
- endif()
-
- foreach(plugin_target ${_qt_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}")
-
- __qt_internal_add_static_plugin_linkage("${plugin_target}" "${_module_target}")
- __qt_internal_add_static_plugin_import_macro(
- "${plugin_target}" ${_module_target} "@QT_MODULE@")
- endforeach()
-
- set("QT_ALL_PLUGINS_FOUND_BY_FIND_PACKAGE_${__plugin_type}"
- "${QT_ALL_PLUGINS_FOUND_BY_FIND_PACKAGE_${__plugin_type}}"
- PARENT_SCOPE
- )
-
- set_target_properties(${_module_target} PROPERTIES __qt_internal_plugins_added TRUE)
-endfunction()
+# Distributions should probably change this default.
+if(NOT DEFINED QT_SKIP_AUTO_PLUGIN_INCLUSION)
+ set(QT_SKIP_AUTO_PLUGIN_INCLUSION OFF)
+endif()
-if(NOT @BUILD_SHARED_LIBS@ AND NOT QT_NO_CREATE_TARGETS)
- __qt_internal_add_static_plugins_once()
+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 0cb0edf1c6..f69448c14a 100644
--- a/cmake/QtPostProcess.cmake
+++ b/cmake/QtPostProcess.cmake
@@ -1,8 +1,9 @@
-include(QtPostProcessHelpers)
+# 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.
diff --git a/cmake/QtPostProcessHelpers.cmake b/cmake/QtPostProcessHelpers.cmake
index 5054bd44d4..0a207f6634 100644
--- a/cmake/QtPostProcessHelpers.cmake
+++ b/cmake/QtPostProcessHelpers.cmake
@@ -1,5 +1,9 @@
-function(qt_internal_write_depends_file target module_include_name)
- set(outfile "${QT_BUILD_DIR}/include/${module_include_name}/${module_include_name}Depends")
+# 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})
@@ -80,11 +84,6 @@ function(qt_internal_remove_qt_dependency_duplicates out_deps deps)
if(dep)
list(FIND ${out_deps} "${dep}" dep_seen)
- # If the library depends on the Private and non-Private targets,
- # we only need to 'find_dependency' for one of them.
- if(dep_seen EQUAL -1 AND "${dep}" MATCHES "(.+)Private\;(.+)")
- list(FIND ${out_deps} "${CMAKE_MATCH_1};${CMAKE_MATCH_2}" dep_seen)
- endif()
if(dep_seen EQUAL -1)
list(LENGTH dep len)
if(NOT (len EQUAL 2))
@@ -107,14 +106,13 @@ 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(arg_HEADER_MODULE ON)
- else()
- set(arg_HEADER_MODULE OFF)
+ set(is_interface_lib TRUE)
endif()
set(depends "")
- if(target_type STREQUAL "STATIC_LIBRARY" AND NOT arg_HEADER_MODULE)
+ if(target_type STREQUAL "STATIC_LIBRARY")
get_target_property(depends "${target}" LINK_LIBRARIES)
endif()
@@ -131,7 +129,7 @@ function(qt_internal_create_module_depends_file target)
set(target_deps_seen "")
set(qt_module_dependencies "")
- if(NOT arg_HEADER_MODULE)
+ if(NOT is_interface_lib)
get_target_property(extra_depends "${target}" QT_EXTRA_PACKAGE_DEPENDENCIES)
endif()
if(NOT extra_depends MATCHES "-NOTFOUND$")
@@ -163,7 +161,7 @@ function(qt_internal_create_module_depends_file target)
# Extra QtFooModuleTools packages to be added as dependencies to
# QtModuleDependencies.cmake. Needed for QtWaylandCompositor / QtWaylandClient.
- if(NOT arg_HEADER_MODULE)
+ if(NOT is_interface_lib)
get_target_property(extra_tools_package_dependencies "${target}"
QT_EXTRA_TOOLS_PACKAGE_DEPENDENCIES)
if(extra_tools_package_dependencies)
@@ -209,9 +207,10 @@ function(qt_internal_create_module_depends_file target)
# 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\;${PROJECT_VERSION}")
+ "${INSTALL_CMAKE_NAMESPACE}${dep}Tools\;${dep_package_version}")
endif()
endif()
endforeach()
@@ -220,14 +219,15 @@ function(qt_internal_create_module_depends_file 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\;${PROJECT_VERSION}")
+ "${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 cointains elements that are a pair of target name and version,
+ # 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:
@@ -250,8 +250,7 @@ function(qt_internal_create_module_depends_file target)
get_target_property(hasModuleHeaders "${target}" _qt_module_has_headers)
if (${hasModuleHeaders})
- get_target_property(module_include_name "${target}" _qt_module_include_name)
- qt_internal_write_depends_file(${target} ${module_include_name} ${qtdeps})
+ qt_internal_write_depends_file(${target} ${qtdeps})
endif()
if(third_party_deps OR main_module_tool_deps OR target_deps)
@@ -259,6 +258,10 @@ function(qt_internal_create_module_depends_file 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"
@@ -272,6 +275,9 @@ function(qt_internal_create_module_depends_file target)
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.
@@ -287,6 +293,13 @@ function(qt_internal_create_plugin_depends_file target)
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}")
@@ -323,6 +336,10 @@ function(qt_internal_create_plugin_depends_file target)
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()
@@ -349,7 +366,17 @@ function(qt_internal_create_qt6_dependencies_file)
endif()")
endif()
- if(third_party_deps)
+ _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}")
@@ -388,17 +415,14 @@ function(qt_internal_create_depends_files)
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()
+# 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)
- message("Generating Plugins files for ${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")
@@ -422,15 +446,41 @@ function(qt_internal_create_plugins_files)
# TODO: Find a better way to deal with this, perhaps by using find_package() instead of include
# for the Qml PluginConfig.cmake files.
-file(GLOB __qt_qml_plugins_config_file_list \"\${CMAKE_CURRENT_LIST_DIR}/QmlPlugins/${INSTALL_CMAKE_NAMESPACE}*Config.cmake\")
+# 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.
+ # Temporarily unset any failure markers and mark the Qml package as found.
unset(\${CMAKE_FIND_PACKAGE_NAME}_NOT_FOUND_MESSAGE)
- unset(\${CMAKE_FIND_PACKAGE_NAME}_FOUND)
+ set(\${CMAKE_FIND_PACKAGE_NAME}_FOUND TRUE)
endforeach()
# For the second round of inclusions, check and bail out early if there are errors.
@@ -448,8 +498,9 @@ if (__qt_qml_plugins_config_file_list AND NOT QT_SKIP_AUTO_QML_PLUGIN_INCLUSION)
endif()")
endif()
- get_target_property(qt_plugins "${QT_MODULE}" QT_PLUGINS)
- if(qt_plugins OR QT_MODULE_PLUGIN_INCLUDES)
+ 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"
@@ -462,6 +513,10 @@ endif()")
)
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)
@@ -522,9 +577,8 @@ function(qt_generate_build_internals_extra_cmake_code)
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}\")
-qt_internal_force_set_cmake_build_type_conditionally(
- \"\${__qt_internal_initial_qt_cmake_build_type}\")
")
endif()
if(CMAKE_CONFIGURATION_TYPES)
@@ -546,17 +600,6 @@ qt_internal_force_set_cmake_build_type_conditionally(
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 use CMake's default value.
- # In the case of Windows, we definitely don't it to default to Debug, because that causes
- # issues in the CI.
- if(multi_config_specific)
- string(APPEND QT_EXTRA_BUILD_INTERNALS_VARS "
-if(QT_BUILD_STANDALONE_TESTS)
- qt_internal_force_set_cmake_build_type_conditionally(
- \"\${QT_MULTI_CONFIG_FIRST_CONFIG}\")
-endif()\n")
- endif()
if(CMAKE_CROSS_CONFIGS)
string(APPEND ninja_multi_config_specific
@@ -587,9 +630,9 @@ endif()\n")
"set(QT_IS_MACOS_UNIVERSAL \"${QT_IS_MACOS_UNIVERSAL}\" CACHE BOOL \"\")\n")
endif()
- if(DEFINED QT_UIKIT_SDK)
+ if(DEFINED QT_APPLE_SDK)
string(APPEND QT_EXTRA_BUILD_INTERNALS_VARS
- "set(QT_UIKIT_SDK \"${QT_UIKIT_SDK}\" CACHE BOOL \"\")\n")
+ "set(QT_APPLE_SDK \"${QT_APPLE_SDK}\" CACHE BOOL \"\")\n")
endif()
if(QT_FORCE_FIND_TOOLS)
@@ -656,13 +699,18 @@ endif()\n")
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 STRING \"Using pkg-config\" FORCE)
+ 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
@@ -679,19 +727,6 @@ endif()\n")
string(APPEND QT_EXTRA_BUILD_INTERNALS_VARS "${install_prefix_content}")
- if(NOT BUILD_SHARED_LIBS)
- # The top-level check needs to happen inside QtBuildInternals, 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.
- string(APPEND QT_EXTRA_BUILD_INTERNALS_VARS
- "
-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()
-")
- endif()
-
if(DEFINED OpenGL_GL_PREFERENCE)
string(APPEND QT_EXTRA_BUILD_INTERNALS_VARS
"
@@ -700,6 +735,24 @@ 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"
@@ -764,9 +817,13 @@ function(qt_internal_create_config_file_for_standalone_tests)
return()
endif()
- # Ceate a Config file that calls find_package on the modules that were built as part
+ # 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_tests_config_file_name(tests_config_file_name)
+ 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}"
@@ -806,8 +863,15 @@ function(qt_internal_generate_user_facing_tools_info)
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}" "${filename}${PROJECT_VERSION_MAJOR}")
+ 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}")
diff --git a/cmake/QtPrecompiledHeadersHelpers.cmake b/cmake/QtPrecompiledHeadersHelpers.cmake
index b9735cd52a..fe38413407 100644
--- a/cmake/QtPrecompiledHeadersHelpers.cmake
+++ b/cmake/QtPrecompiledHeadersHelpers.cmake
@@ -1,3 +1,6 @@
+# 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}>")
@@ -16,7 +19,9 @@ endfunction()
function(qt_update_ignore_pch_source target sources)
if (sources)
- set_source_files_properties(${sources} PROPERTIES SKIP_PRECOMPILE_HEADERS ON)
+ set_source_files_properties(${sources} PROPERTIES
+ SKIP_PRECOMPILE_HEADERS ON
+ SKIP_UNITY_BUILD_INCLUSION ON)
endif()
endfunction()
diff --git a/cmake/QtPriHelpers.cmake b/cmake/QtPriHelpers.cmake
index 71164c6718..f410dc9b2a 100644
--- a/cmake/QtPriHelpers.cmake
+++ b/cmake/QtPriHelpers.cmake
@@ -1,3 +1,6 @@
+# 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}.
@@ -11,7 +14,7 @@ function(qt_generate_qmake_libraries_pri_content module_name output_root_dir out
set(implicit_include_dirs_regex "")
foreach(dir ${CMAKE_CXX_IMPLICIT_INCLUDE_DIRECTORIES})
qt_re_escape(regex "${dir}")
- list(APPEND implicit_include_dirs_regex ${regex})
+ list(APPEND implicit_include_dirs_regex "^${regex}$")
endforeach()
list(JOIN implicit_include_dirs_regex "|" implicit_include_dirs_regex)
@@ -23,9 +26,14 @@ function(qt_generate_qmake_libraries_pri_content module_name output_root_dir out
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)
@@ -136,13 +144,10 @@ function(qt_get_direct_module_dependencies target out_var)
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})
+ 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")
@@ -254,7 +259,7 @@ endfunction()
# Generates module .pri files for consumption by qmake
function(qt_generate_module_pri_file target)
- set(flags INTERNAL_MODULE HEADER_MODULE NO_PRIVATE_MODULE)
+ set(flags INTERNAL_MODULE NO_PRIVATE_MODULE)
set(options)
set(multiopts)
cmake_parse_arguments(arg "${flags}" "${options}" "${multiopts}" ${ARGN})
@@ -263,7 +268,13 @@ function(qt_generate_module_pri_file target)
set(pri_files)
set(property_prefix)
- if(arg_HEADER_MODULE)
+
+ 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()
@@ -314,13 +325,15 @@ function(qt_generate_module_pri_file target)
list(APPEND module_internal_config staticlib)
endif()
- # TODO: Add the value 'ltcg' to module_internal_config if LTCG is turned on.
+ 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 (arg_HEADER_MODULE)
+ if (is_interface_lib)
list(APPEND qmake_module_config "no_link")
endif()
if(qmake_module_config)
@@ -344,7 +357,7 @@ ${framework_base_path}/${fw_private_module_header_dir}")
$$QT_MODULE_INCLUDE_BASE/${module_versioned_inner_include_dir}")
endif()
- if(arg_HEADER_MODULE)
+ if(is_interface_lib)
set(module_name_in_pri "")
else()
get_target_property(module_name_in_pri ${target} OUTPUT_NAME)
@@ -368,7 +381,7 @@ $$QT_MODULE_INCLUDE_BASE/${module_versioned_inner_include_dir}")
qt_path_join(target_path ${QT_BUILD_DIR} ${INSTALL_MKSPECSDIR}/modules)
unset(private_module_frameworks)
- if(arg_HEADER_MODULE)
+ if(is_interface_lib)
set(module_plugin_types "")
else()
get_target_property(module_plugin_types ${target} QMAKE_MODULE_PLUGIN_TYPES)
@@ -452,7 +465,7 @@ ${module_pri_extra_content}
set(private_pri_file_name "qt_lib_${config_module_name}_private.pri")
set(private_module_dependencies "")
- if(NOT arg_HEADER_MODULE)
+ if(NOT is_interface_lib)
qt_get_direct_module_dependencies(${target}Private private_module_dependencies)
endif()
list(JOIN private_module_dependencies " " private_module_dependencies)
@@ -532,12 +545,15 @@ QT.${config_module_name}_private.disabled_features = ${disabled_private_features
"-DIMPLICIT_LINK_DIRECTORIES=${implicit_link_directories}"
-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)
+ # 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)
@@ -591,12 +607,21 @@ endfunction()
# - 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)
+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)
@@ -613,16 +638,28 @@ function(qt_generate_plugin_pri_file target pri_file_var)
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")
- qt_configure_file(OUTPUT "${pri_file}"
- CONTENT "QT_PLUGIN.${plugin_name}.TYPE = ${qmake_plugin_type}
+
+ 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}
-")
- set(${pri_file_var} "${pri_file}" PARENT_SCOPE)
+${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.
@@ -741,8 +778,23 @@ QT_PATCH_VERSION = ${PROJECT_VERSION_PATCH}
if(APPLE)
list(APPEND extra_statements "QT_MAC_SDK_VERSION = ${QT_MAC_SDK_VERSION}")
- list(APPEND extra_statements
- "QMAKE_MACOSX_DEPLOYMENT_TARGET = ${CMAKE_OSX_DEPLOYMENT_TARGET}")
+ 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}")
@@ -752,8 +804,6 @@ QT_PATCH_VERSION = ${PROJECT_VERSION_PATCH}
list(APPEND extra_statements "QT_ARCHS = ${architectures}")
endif()
- list(APPEND extra_statements "QT_EDITION = Open Source")
-
if(WASM)
list(APPEND extra_statements
"QT_EMCC_VERSION = ${EMCC_VERSION}")
@@ -812,8 +862,8 @@ function(qt_generate_global_device_pri_file)
endif()
endif()
- if(QT_UIKIT_SDK)
- string(APPEND content "QMAKE_MAC_SDK = ${QT_UIKIT_SDK}\n")
+ if(QT_APPLE_SDK)
+ string(APPEND content "QMAKE_MAC_SDK = ${QT_APPLE_SDK}\n")
endif()
set(gcc_machine_dump "")
diff --git a/cmake/QtPrlHelpers.cmake b/cmake/QtPrlHelpers.cmake
index c467e9a634..45bfaedcdf 100644
--- a/cmake/QtPrlHelpers.cmake
+++ b/cmake/QtPrlHelpers.cmake
@@ -1,3 +1,6 @@
+# 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.
@@ -105,7 +108,6 @@ function(qt_generate_prl_file target install_dir)
# 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_LINKER_FILE_NAME:${target}>
QMAKE_PRL_TARGET_PATH_FOR_CMAKE = $<TARGET_LINKER_FILE:${target}>
QMAKE_PRL_CONFIG = ${prl_config}
@@ -139,6 +141,18 @@ ${prl_step1_content_libs}
"${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
@@ -173,6 +187,8 @@ ${prl_step1_content_libs}
"-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
diff --git a/cmake/QtProcessConfigureArgs.cmake b/cmake/QtProcessConfigureArgs.cmake
index 493febe077..53235ee9d9 100644
--- a/cmake/QtProcessConfigureArgs.cmake
+++ b/cmake/QtProcessConfigureArgs.cmake
@@ -1,3 +1,6 @@
+# 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.
#
@@ -40,12 +43,22 @@ function(warn_in_per_repo_build arg)
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()
- file(TO_CMAKE_PATH "${MODULE_ROOT}" MODULE_ROOT)
+ # 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")
@@ -72,6 +85,7 @@ list(TRANSFORM configure_args STRIP)
unset(generator)
set(auto_detect_compiler TRUE)
set(auto_detect_generator ${qtbase_or_top_level_build})
+set(no_prefix_option FALSE)
unset(device_options)
unset(options_json_file)
set_property(GLOBAL PROPERTY UNHANDLED_ARGS "")
@@ -97,6 +111,20 @@ while(NOT "${configure_args}" STREQUAL "")
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)
@@ -114,14 +142,20 @@ while(NOT "${configure_args}" STREQUAL "")
push("-DINSTALL_MKSPECSDIR=${path}")
elseif(arg STREQUAL "-developer-build")
set(developer_build TRUE)
- # Treat this argument as "unhandled" to process it further.
- set_property(GLOBAL APPEND PROPERTY UNHANDLED_ARGS "${arg}")
+ 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.
list(APPEND cmake_args "${configure_args}")
@@ -131,6 +165,50 @@ while(NOT "${configure_args}" STREQUAL "")
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
@@ -197,16 +275,23 @@ macro(qt_commandline_custom handler)
endmacro()
function(qt_commandline_option name)
- set(options)
+ 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()
@@ -217,6 +302,11 @@ function(qt_commandline_option name)
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)
@@ -233,6 +323,8 @@ 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)
@@ -297,6 +389,23 @@ function(qtConfCommandlineAppendInput name val)
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)
@@ -313,7 +422,9 @@ function(qtConfValidateValue opt val out_var)
endforeach()
set(${out_var} FALSE PARENT_SCOPE)
- qtConfAddError("Invalid value '${val}' supplied to command line option '${opt}'.")
+ 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)
@@ -601,10 +712,20 @@ while(1)
if(arg MATCHES "^--?enable-(.*)")
set(opt "${CMAKE_MATCH_1}")
set(val "yes")
- # Handle -no-prefix so it's not interpreted as the negation of -prefix
- elseif(arg MATCHES "-(no-prefix)")
- set(opt "${CMAKE_MATCH_1}")
- set(val "")
+ # 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")
@@ -621,7 +742,6 @@ while(1)
if(NOT DEFINED commandline_option_${opt} AND opt MATCHES "(qt|system)-(.*)")
set(opt "${CMAKE_MATCH_2}")
set(val "${CMAKE_MATCH_1}")
- message("opt: ${opt} val: ${val}")
endif()
else()
qtConfAddError("Invalid command line parameter '${arg}'.")
@@ -642,15 +762,6 @@ while(1)
endforeach()
endif()
- # Handle builtin [-no]-feature-xxx
- if("${type}" STREQUAL "" AND opt MATCHES "^feature-(.*)")
- set(opt "${CMAKE_MATCH_1}")
- if(NOT opt IN_LIST commandline_known_features)
- qtConfAddError("Enabling/Disabling unknown feature '${opt}'.")
- endif()
- set(type boolean)
- endif()
-
if("${type}" STREQUAL "")
qtConfAddError("Unknown command line option '${arg}'.")
endif()
@@ -670,6 +781,9 @@ 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)
@@ -765,7 +879,7 @@ function(guess_compiler_from_mkspec)
push("-DCMAKE_CXX_COMPILER=${cxx_compiler}")
endif()
if(mkspec MATCHES "-libc\\+\\+$")
- push("-DINPUT_stdlib_libcpp=ON")
+ push("-DFEATURE_stdlib_libcpp=ON")
endif()
set(cmake_args "${cmake_args}" PARENT_SCOPE)
endfunction()
@@ -797,9 +911,13 @@ 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)
@@ -838,15 +956,11 @@ endif()
translate_string_input(android-javac-source QT_ANDROID_JAVAC_SOURCE)
translate_string_input(android-javac-target QT_ANDROID_JAVAC_TARGET)
-# FIXME: config_help.txt says -sdk should apply to macOS as well.
-translate_string_input(sdk QT_UIKIT_SDK)
-if(DEFINED INPUT_sdk OR (DEFINED INPUT_xplatform AND INPUT_xplatform STREQUAL "macx-ios-clang")
- OR (DEFINED INPUT_platform AND INPUT_platform STREQUAL "macx-ios-clang"))
- push("-DCMAKE_SYSTEM_NAME=iOS")
-endif()
+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)
@@ -867,10 +981,33 @@ 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}")
# We must not use the push macro here to avoid variable expansion.
@@ -901,12 +1038,20 @@ if(cmake_file_api OR (developer_build AND NOT DEFINED cmake_file_api))
endforeach()
endif()
+# 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)
- push("-DINPUT_${cmake_input}=${INPUT_${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(DEFINED INPUT_no-prefix AND DEFINED INPUT_prefix)
+if(no_prefix_option AND DEFINED INPUT_prefix)
qtConfAddError("Can't specify both -prefix and -no-prefix options at the same time.")
endif()
@@ -955,6 +1100,14 @@ 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 "\\[\\[;\\]\\]" "\\\\;")
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
index 35cd4fe1f3..ca091fcf9a 100644
--- a/cmake/QtPublicCMakeHelpers.cmake
+++ b/cmake/QtPublicCMakeHelpers.cmake
@@ -1,3 +1,6 @@
+# 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)
@@ -22,13 +25,486 @@ 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
+ (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))
+ 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
index 2b3c697f4c..de896d9d2f 100644
--- a/cmake/QtPublicCMakeVersionHelpers.cmake
+++ b/cmake/QtPublicCMakeVersionHelpers.cmake
@@ -1,3 +1,6 @@
+# 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}")
diff --git a/cmake/QtPublicDependencyHelpers.cmake b/cmake/QtPublicDependencyHelpers.cmake
index a1e422107a..bd8b4a55c4 100644
--- a/cmake/QtPublicDependencyHelpers.cmake
+++ b/cmake/QtPublicDependencyHelpers.cmake
@@ -1,25 +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_dependencies target_dep_list find_dependency_path_list)
- foreach(__qt_target_dep IN LISTS ${target_dep_list})
- list(GET __qt_target_dep 0 __qt_pkg)
- list(GET __qt_target_dep 1 __qt_version)
-
- if (NOT ${__qt_pkg}_FOUND)
- set(__qt_pkg_names ${__qt_pkg})
- if(__qt_pkg MATCHES "(.*)Private$")
- set(__qt_pkg_names "${CMAKE_MATCH_1};${__qt_pkg}")
+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()
- find_dependency(${__qt_pkg} ${__qt_version}
+
+ _qt_internal_save_find_package_context_for_debugging(${target})
+
+ find_dependency(${__qt_${target}_pkg} ${__qt_${target}_version}
NAMES
- ${__qt_pkg_names}
+ ${__qt_${target}_pkg_names}
PATHS
+ ${QT_BUILD_CMAKE_PREFIX_PATH}
${${find_dependency_path_list}}
${_qt_additional_packages_prefix_paths}
- ${QT_EXAMPLES_CMAKE_PREFIX_PATH}
${__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
index 1a4dcda902..96b5c6c740 100644
--- a/cmake/QtPublicFinalizerHelpers.cmake
+++ b/cmake/QtPublicFinalizerHelpers.cmake
@@ -1,3 +1,6 @@
+# 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)
diff --git a/cmake/QtPublicFindPackageHelpers.cmake b/cmake/QtPublicFindPackageHelpers.cmake
index df42241c56..69f4f69e40 100644
--- a/cmake/QtPublicFindPackageHelpers.cmake
+++ b/cmake/QtPublicFindPackageHelpers.cmake
@@ -1,3 +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
index a5b1125e4f..7087c31234 100644
--- a/cmake/QtPublicPluginHelpers.cmake
+++ b/cmake/QtPublicPluginHelpers.cmake
@@ -1,3 +1,6 @@
+# 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
@@ -36,22 +39,32 @@ endfunction()
#
# 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.
+# 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:QT_DEFAULT_PLUGINS>>,0>>")
- set(_manual_plugins_genex "$<GENEX_EVAL:$<TARGET_PROPERTY:QT_PLUGINS>>")
- set(_no_plugins_genex "$<GENEX_EVAL:$<TARGET_PROPERTY:QT_NO_PLUGINS>>")
+ "$<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>")
@@ -78,7 +91,7 @@ function(__qt_internal_get_static_plugin_condition_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}>>>"
+ "$<STREQUAL:,$<GENEX_EVAL:$<TARGET_PROPERTY:${target_infix}QT_PLUGINS_${_plugin_type}>>>"
">"
)
@@ -87,7 +100,7 @@ function(__qt_internal_get_static_plugin_condition_genex
"$<IN_LIST:"
"${plugin_target},"
"$<GENEX_EVAL:"
- "$<TARGET_PROPERTY:QT_PLUGINS_${_plugin_type}>"
+ "$<TARGET_PROPERTY:${target_infix}QT_PLUGINS_${_plugin_type}>"
">"
">"
)
@@ -95,7 +108,7 @@ function(__qt_internal_get_static_plugin_condition_genex
"$<IN_LIST:"
"${plugin_target_versionless},"
"$<GENEX_EVAL:"
- "$<TARGET_PROPERTY:QT_PLUGINS_${_plugin_type}>"
+ "$<TARGET_PROPERTY:${target_infix}QT_PLUGINS_${_plugin_type}>"
">"
">"
)
@@ -103,7 +116,7 @@ function(__qt_internal_get_static_plugin_condition_genex
# 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:TYPE>")
+ 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
@@ -174,7 +187,7 @@ function(__qt_internal_get_plugin_import_macro plugin_target out_var)
set(class_name "${class_name_prefixed}")
endif()
- set(${out_var} "Q_IMPORT_PLUGIN(${class_name})" PARENT_SCOPE)
+ set(${out_var} "Q_IMPORT_PLUGIN(${class_name})\n" PARENT_SCOPE)
endfunction()
function(__qt_internal_get_plugin_include_prelude out_var)
@@ -263,12 +276,16 @@ 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)
- set(plugin_target_versioned "${QT_CMAKE_EXPORT_NAMESPACE}::${plugin_target}")
-
list(APPEND plugins_to_link "$<${plugin_condition}:${plugin_target_versioned}>")
endforeach()
@@ -282,6 +299,12 @@ 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)
@@ -295,6 +318,25 @@ function(__qt_internal_collect_plugin_init_libraries plugin_targets out_var)
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.
@@ -374,19 +416,57 @@ function(__qt_internal_collect_plugin_targets_from_dependencies_of_plugins targe
set("${out_var}" "${plugin_targets}" PARENT_SCOPE)
endfunction()
-# Main logic of finalizer mode.
-function(__qt_internal_apply_plugin_imports_finalizer_mode target)
- # Nothing to do in a shared build.
- if(QT6_IS_SHARED_LIBS_BUILD)
+# 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+).
@@ -400,7 +480,6 @@ function(__qt_internal_apply_plugin_imports_finalizer_mode target)
return()
endif()
- __qt_internal_collect_plugin_targets_from_dependencies("${target}" plugin_targets)
__qt_internal_collect_plugin_init_libraries("${plugin_targets}" init_libraries)
__qt_internal_collect_plugin_libraries("${plugin_targets}" plugin_libraries)
@@ -408,3 +487,76 @@ function(__qt_internal_apply_plugin_imports_finalizer_mode target)
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
index 8f6c434c4e..02d5546560 100644
--- a/cmake/QtPublicTargetHelpers.cmake
+++ b/cmake/QtPublicTargetHelpers.cmake
@@ -1,3 +1,6 @@
+# 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
@@ -304,7 +307,31 @@ function(_qt_internal_set_up_static_runtime_library target)
set_property(TARGET ${target} PROPERTY
MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")
elseif(MINGW)
- target_link_options(${target} INTERFACE "LINKER:-Bstatic")
+ 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
index 8705a9e293..031f0a3317 100644
--- a/cmake/QtPublicToolHelpers.cmake
+++ b/cmake/QtPublicToolHelpers.cmake
@@ -1,3 +1,6 @@
+# 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)
@@ -22,7 +25,7 @@ function(__qt_internal_get_tool_imported_location out_var tool)
get_target_property(configs ${target} IMPORTED_CONFIGURATIONS)
list(TRANSFORM configs PREPEND _)
# Well-known configuration types
- list(APPEND
+ list(APPEND configs
_RELWITHDEBINFO
_RELEASE
_MINSIZEREL
@@ -41,3 +44,73 @@ function(__qt_internal_get_tool_imported_location out_var tool)
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
index 85f09b7679..f79b70c710 100644
--- a/cmake/QtPublicWalkLibsHelpers.cmake
+++ b/cmake/QtPublicWalkLibsHelpers.cmake
@@ -1,3 +1,6 @@
+# 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.
@@ -186,7 +189,7 @@ function(__qt_internal_walk_libs
# 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)
+ if(TARGET "${namespaceless_lib_target}")
set(lib_target ${namespaceless_lib_target})
endif()
endif()
@@ -274,6 +277,18 @@ ${target}, but not declared.")
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.
#
@@ -300,9 +315,14 @@ function(__qt_internal_collect_all_target_dependencies target out_var)
"qt_private_link_library_targets"
"collect_targets")
- if(lib_walked_targets)
- list(APPEND dep_targets ${lib_walked_targets})
- endif()
+ 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()
diff --git a/cmake/QtPublicWasmToolchainHelpers.cmake b/cmake/QtPublicWasmToolchainHelpers.cmake
index 0aa5d0145f..31f6b5aca5 100644
--- a/cmake/QtPublicWasmToolchainHelpers.cmake
+++ b/cmake/QtPublicWasmToolchainHelpers.cmake
@@ -1,3 +1,6 @@
+# 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
@@ -27,7 +30,7 @@ function(__qt_internal_query_emsdk_version emroot_path is_fatal out_var)
set(EXECUTE_COMMANDPATH "$ENV{EMSDK}/${emroot_path}/emcc")
endif()
- file(TO_NATIVE_PATH "${EXECUTE_COMMANDPATH}" EXECUTE_COMMAND)
+ file(TO_CMAKE_PATH "${EXECUTE_COMMANDPATH}" EXECUTE_COMMAND)
execute_process(COMMAND ${EXECUTE_COMMAND} --version
OUTPUT_VARIABLE emOutput
OUTPUT_STRIP_TRAILING_WHITESPACE
@@ -50,7 +53,7 @@ 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.0.0")
+ set(QT_EMCC_RECOMMENDED_VERSION "3.1.50")
set(${out_var} "${QT_EMCC_RECOMMENDED_VERSION}" PARENT_SCOPE)
endfunction()
@@ -69,3 +72,37 @@ function(__qt_internal_show_error_no_emscripten_toolchain_file_found_when_using_
"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
index 1ad05d7a80..c618fa0510 100644
--- a/cmake/QtQmakeHelpers.cmake
+++ b/cmake/QtQmakeHelpers.cmake
@@ -1,3 +1,6 @@
+# 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)
@@ -34,8 +37,6 @@ function(qt_generate_qconfig_cpp in_file out_file)
set(QT_SYS_CONF_DIR "${INSTALL_SYSCONFDIR}")
# 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}")
@@ -79,7 +80,7 @@ endfunction()
# 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)
+ if(NOT CMAKE_CROSSCOMPILING OR QT_NO_GENERATE_QMAKE_WRAPPER_FOR_TARGET)
return()
endif()
@@ -95,7 +96,8 @@ function(qt_generate_qmake_and_qtpaths_wrapper_for_target)
"${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}")
+ file(RELATIVE_PATH ext_datadir_relative_to_host_prefix "${host_prefix}"
+ "${ext_prefix}/${INSTALL_MKSPECSDIR}/..")
set(content "")
@@ -126,8 +128,24 @@ Prefix=${prefix}
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}
-HostData=${ext_prefix_relative_to_host_prefix}
+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}
@@ -152,6 +170,11 @@ HostSpec=${QT_QMAKE_HOST_MKSPEC}
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)
@@ -170,6 +193,14 @@ HostSpec=${QT_QMAKE_HOST_MKSPEC}
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()
@@ -180,6 +211,8 @@ 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()
diff --git a/cmake/QtResourceHelpers.cmake b/cmake/QtResourceHelpers.cmake
index aed5f6f2da..2df1fed50f 100644
--- a/cmake/QtResourceHelpers.cmake
+++ b/cmake/QtResourceHelpers.cmake
@@ -1,4 +1,19 @@
+# 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)
@@ -6,7 +21,11 @@ function(qt_internal_add_resource target resourceName)
return()
endif()
- qt_parse_all_arguments(arg "qt_add_resource" "" "PREFIX;LANG;BASE;OUTPUT_TARGETS" "FILES" ${ARGN})
+ 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}"
diff --git a/cmake/QtRpathHelpers.cmake b/cmake/QtRpathHelpers.cmake
index fc75b8f554..da6c8715a8 100644
--- a/cmake/QtRpathHelpers.cmake
+++ b/cmake/QtRpathHelpers.cmake
@@ -1,9 +1,12 @@
+# 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)
+ 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")
@@ -85,7 +88,12 @@ function(qt_apply_rpaths)
return()
endif()
- qt_parse_all_arguments(arg "qt_apply_rpaths" "RELATIVE_RPATH" "TARGET;INSTALL_PATH" "" ${ARGN})
+ 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()
@@ -184,6 +192,51 @@ function(qt_apply_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.
diff --git a/cmake/QtSanitizerHelpers.cmake b/cmake/QtSanitizerHelpers.cmake
index ff74792058..2a933b2222 100644
--- a/cmake/QtSanitizerHelpers.cmake
+++ b/cmake/QtSanitizerHelpers.cmake
@@ -1,3 +1,6 @@
+# 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)
@@ -23,3 +26,35 @@ function(qt_internal_set_up_sanitizer_options)
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
index 6dae635ba2..9e13bec26d 100644
--- a/cmake/QtScopeFinalizerHelpers.cmake
+++ b/cmake/QtScopeFinalizerHelpers.cmake
@@ -1,3 +1,6 @@
+# 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.
#
@@ -8,7 +11,7 @@
# 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 INGORE parameters are passed. Instead we
+# 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)
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 61fd29a8f1..61f62207fa 100644
--- a/cmake/QtSeparateDebugInfo.cmake
+++ b/cmake/QtSeparateDebugInfo.cmake
@@ -1,4 +1,5 @@
-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})
@@ -198,7 +199,11 @@ endfunction()
# Enable separate debug information for the given target
function(qt_enable_separate_debug_info target installDestination)
set(flags QT_EXECUTABLE)
- set(options)
+ if(APPLE)
+ set(options DSYM_OUTPUT_DIR)
+ else()
+ set(options)
+ endif()
set(multiopts ADDITIONAL_INSTALL_ARGS)
cmake_parse_arguments(arg "${flags}" "${options}" "${multiopts}" ${ARGN})
@@ -245,12 +250,20 @@ function(qt_enable_separate_debug_info target installDestination)
get_target_property(is_framework ${target} FRAMEWORK)
if(is_framework)
qt_internal_get_framework_info(fw ${target})
- set(debug_info_bundle_dir "$<TARGET_BUNDLE_DIR:${target}>.${debug_info_suffix}")
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(
diff --git a/cmake/QtSetup.cmake b/cmake/QtSetup.cmake
index a0674df0a9..a420495756 100644
--- a/cmake/QtSetup.cmake
+++ b/cmake/QtSetup.cmake
@@ -1,328 +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.")
-
-# Pre-calculate the developer_build feature if it's set by the user via INPUT_developer_build
-if(NOT FEATURE_developer_build AND INPUT_developer_build
- AND NOT "${INPUT_developer_build}" STREQUAL "undefined")
- set(FEATURE_developer_build ON)
-endif()
-
-# Pre-calculate the no_prefix feature if it's set by configure via INPUT_no_prefix.
-# This needs to be done before qtbase/configure.cmake is processed.
-if(NOT FEATURE_no_prefix AND INPUT_no_prefix
- AND NOT "${INPUT_no_prefix}" STREQUAL "undefined")
- set(FEATURE_no_prefix ON)
-endif()
-
-set(_default_build_type "Release")
-if(FEATURE_developer_build)
- set(_default_build_type "Debug")
-endif()
-
-# 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()
-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()
-else()
- message(STATUS "CMAKE_BUILD_TYPE was set to: '${CMAKE_BUILD_TYPE}'")
-endif()
-
-# 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(QT_GENERATOR_IS_MULTI_CONFIG AND CMAKE_CONFIGURATION_TYPES)
- set(__qt_setup_release_configs Release RelWithDebInfo MinSizeRel)
- set(__qt_setup_found_first_release_config FALSE)
- foreach(__qt_setup_config_type IN LISTS CMAKE_CONFIGURATION_TYPES)
- # Skip assigning postfix for the first release-like config.
- if(NOT __qt_setup_found_first_release_config
- AND __qt_setup_config_type IN_LIST __qt_setup_release_configs)
- set(__qt_setup_found_first_release_config TRUE)
- continue()
- endif()
-
- string(TOLOWER "${__qt_setup_config_type}" __qt_setup_config_type_lower)
- string(TOUPPER "${__qt_setup_config_type}" __qt_setup_config_type_upper)
- set(CMAKE_${__qt_setup_config_type_upper}_POSTFIX "_${__qt_setup_config_type_lower}")
- if(APPLE)
- set(CMAKE_FRAMEWORK_MULTI_CONFIG_POSTFIX_${__qt_setup_config_type_upper}
- "_${__qt_setup_config_type_lower}")
- endif()
- endforeach()
-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(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)
-
-# 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_BUILD_STANDALONE_TESTS)
- 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()
-
-# 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_tests_default 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_tests_default OFF)
- endif()
-
- # 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(_qt_build_tests_default OFF)
- set(__build_benchmarks OFF)
-endif()
-
-# Build Benchmarks
-option(QT_BUILD_BENCHMARKS "Build Qt Benchmarks" ${__build_benchmarks})
-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 "")
-
-# 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)
-
-include(CTest)
-enable_testing()
-
-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)
-
-# FIXME: Support prefix builds as well QTBUG-96232
-if(QT_WILL_INSTALL)
- 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)
-
-option(QT_BUILD_MANUAL_TESTS "Build Qt manual tests" OFF)
-option(QT_BUILD_MINIMAL_STATIC_TESTS "Build minimal subset of tests for static Qt builds" OFF)
-
-## Find host tools (if non native):
-set(QT_HOST_PATH "$ENV{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()
-endif()
-
-if(NOT "${QT_HOST_PATH}" STREQUAL "")
- find_package(${INSTALL_CMAKE_NAMESPACE}HostInfo
- CONFIG
- REQUIRED
- PATHS "${QT_HOST_PATH}"
- "${QT_HOST_PATH_CMAKE_DIR}"
- 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)
-
-qt_set_language_standards()
-
-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()
-
-# 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)
- message(STATUS "Check 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}' is changed from ${QT_FEATURE_${feature}} \
-to ${FEATURE_${feature}}")
- set(dirty_build TRUE)
- 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 "Re-configuring in existing build folder. \
-Some features will be re-evaluated automatically.")
- endif()
-endif()
diff --git a/cmake/QtSimdHelpers.cmake b/cmake/QtSimdHelpers.cmake
index 3e5fea11c8..1e77bf449f 100644
--- a/cmake/QtSimdHelpers.cmake
+++ b/cmake/QtSimdHelpers.cmake
@@ -1,3 +1,6 @@
+# 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
@@ -13,8 +16,12 @@
# SIMD compiler flags. This is mostly relevant for fat / universal builds
#
function(qt_internal_add_simd_part target)
- qt_parse_all_arguments(arg "qt_add_simd_part" "" "NAME;SIMD"
- "${__default_private_args};COMPILE_FLAGS;EXCLUDE_OSX_ARCHITECTURES" ${ARGN})
+ 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()
@@ -91,7 +98,9 @@ function(qt_internal_add_simd_part target)
${arg_COMPILE_FLAGS}
)
endforeach()
- set_source_files_properties(${arg_SOURCES} PROPERTIES SKIP_PRECOMPILE_HEADERS TRUE)
+ 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)
diff --git a/cmake/QtSingleRepoTargetSetBuildHelpers.cmake b/cmake/QtSingleRepoTargetSetBuildHelpers.cmake
index 789b23b6e6..9a003c62c5 100644
--- a/cmake/QtSingleRepoTargetSetBuildHelpers.cmake
+++ b/cmake/QtSingleRepoTargetSetBuildHelpers.cmake
@@ -1,3 +1,6 @@
+# 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)
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
index 84a8e93d80..0188b87c6a 100644
--- a/cmake/QtSyncQtHelpers.cmake
+++ b/cmake/QtSyncQtHelpers.cmake
@@ -1,203 +1,324 @@
-function(qt_ensure_perl)
- 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()
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
-function(qt_ensure_sync_qt)
- qt_ensure_perl()
- if(DEFINED QT_SYNCQT)
- return()
+# 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_property(QT_SYNCQT GLOBAL PROPERTY _qt_syncqt)
- if(NOT "${QT_SYNCQT}" STREQUAL "")
- set(QT_SYNCQT "${QT_SYNCQT}" PARENT_SCOPE)
+ get_target_property(has_headers ${target} _qt_module_has_headers)
+ if(NOT has_headers)
return()
endif()
- # When building qtbase, use the source syncqt, otherwise use the installed one.
- set(SYNCQT_FROM_SOURCE "${QtBase_SOURCE_DIR}/libexec/syncqt.pl")
- if(NOT ("${QtBase_SOURCE_DIR}" STREQUAL "") AND EXISTS "${SYNCQT_FROM_SOURCE}")
- set(syncqt_absolute_path "${SYNCQT_FROM_SOURCE}")
- message(STATUS "Using source syncqt found at: ${syncqt_absolute_path}")
-
- qt_path_join(syncqt_install_dir ${QT_INSTALL_DIR} ${INSTALL_LIBEXECDIR})
- qt_copy_or_install(PROGRAMS "${SYNCQT_FROM_SOURCE}"
- DESTINATION "${syncqt_install_dir}")
- elseif(NOT "${QT_HOST_PATH}" STREQUAL "")
- get_filename_component(syncqt_absolute_path
- "${QT_HOST_PATH}/${QT${PROJECT_VERSION_MAJOR}_HOST_INFO_LIBEXECDIR}/syncqt.pl"
- ABSOLUTE)
- message(STATUS "Using host syncqt found at: ${syncqt_absolute_path}")
- else()
- get_filename_component(syncqt_absolute_path
- "${QT_BUILD_INTERNALS_RELOCATABLE_INSTALL_PREFIX}/${INSTALL_LIBEXECDIR}/syncqt.pl"
- ABSOLUTE)
- message(STATUS "Using installed syncqt found at: ${syncqt_absolute_path}")
+ 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(QT_SYNCQT "${syncqt_absolute_path}" PARENT_SCOPE)
- set_property(GLOBAL PROPERTY _qt_syncqt "${syncqt_absolute_path}")
-endfunction()
+ 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()
-function(qt_install_injections target build_dir install_dir)
- set(injections ${ARGN})
- qt_internal_module_info(module ${target})
- get_target_property(target_type ${target} TYPE)
- if (target_type STREQUAL "INTERFACE_LIBRARY")
- set(is_framework FALSE)
+ # 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()
- # 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_include_name}/qtqml-config.h (part 1).
- #
- # Generate a lower case forwarding header (part 2) 'qtqml-config.h' at the following
- # location:
- # ${some_prefix}/include/${module_include_name}/qtqml-config.h.
- #
- # Inside this file, we #include the originally generated file,
- # ${qtdeclarative_build_dir}/src/{module_include_name}/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}/include/${module_include_name}")
- 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_internal_get_qt_all_known_modules(known_modules)
- qt_configure_file(OUTPUT "${lower_case_forwarding_header_path}/${original_file_name}"
- CONTENT "${main_contents}")
+ 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()
- 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})
+ 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()
- # 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_include_name} ${destinationdir})
- qt_install(FILES ${current_repo_build_dir}/${file}
- DESTINATION ${install_destination}
- RENAME ${destinationname} OPTIONAL)
+ 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()
- # Generate UpperCaseNamed forwarding headers (part 3).
- foreach(fwd_hdr ${fwd_hdrs})
- set(upper_case_forwarding_header_path "include/${module_include_name}")
- if(destinationdir)
- string(APPEND upper_case_forwarding_header_path "/${destinationdir}")
- 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)")
- # 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}" "${INSTALL_INCLUDEDIR}"
- ${module_include_name})
- qt_install(FILES "${build_dir}/${upper_case_forwarding_header_path}/${fwd_hdr}"
- DESTINATION ${install_destination} OPTIONAL)
+ 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()
- endforeach()
- endforeach()
+ 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_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)
+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()
- set(${resultVarPrefix}_public "${public_module_headers}" PARENT_SCOPE)
- set(${resultVarPrefix}_private "${private_module_headers}" PARENT_SCOPE)
- set(${resultVarPrefix}_injections "${injections}" PARENT_SCOPE)
-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)
+ list(REMOVE_DUPLICATES ${out_var})
- set(source_absolute_path "${CMAKE_CURRENT_BINARY_DIR}/${arg_SOURCE}")
- file(RELATIVE_PATH relpath "${PROJECT_BINARY_DIR}" "${source_absolute_path}")
+ set(${out_var} "${${out_var}}" PARENT_SCOPE)
+endfunction()
- if (arg_PRIVATE)
- set(fwd "${PROJECT_VERSION}/${module_include_name}/private/${file_name}")
- else()
- set(fwd "${file_name}")
+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()
- string(APPEND ${arg_OUT_VAR} " ${relpath}:${fwd}")
- set(${arg_OUT_VAR} ${${arg_OUT_VAR}} PARENT_SCOPE)
+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
index b425d1bfa2..e669047ff1 100644
--- a/cmake/QtTargetHelpers.cmake
+++ b/cmake/QtTargetHelpers.cmake
@@ -1,42 +1,110 @@
+# 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()
- 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(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(${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}")
+ 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}")
+ 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)
- if (${target_type} STREQUAL "STATIC_LIBRARY" OR ${target_type} STREQUAL "SHARED_LIBRARY")
+ 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.
@@ -48,32 +116,58 @@ function(qt_internal_extend_target target)
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 HEADER_MODULE let's simply exclude them for compatibility
- # with CMake versions less than 3.19.
- if(NOT arg_HEADER_MODULE OR CMAKE_VERSION VERSION_GREATER_EQUAL "3.19")
- target_sources("${target}" PRIVATE ${arg_SOURCES} ${dbus_sources})
- if (arg_COMPILE_FLAGS)
- set_source_files_properties(${arg_SOURCES} PROPERTIES
+ # 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(arg_HEADER_MODULE)
+ 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})
@@ -87,10 +181,14 @@ function(qt_internal_extend_target 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
+ 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
@@ -138,15 +236,252 @@ function(qt_internal_extend_target target)
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)
@@ -219,20 +554,20 @@ endfunction()
# 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 "")
+ if(NOT arg_TARGET_VERSION)
set(arg_TARGET_VERSION "${PROJECT_VERSION}.0")
endif()
- if("${arg_TARGET_PRODUCT}" STREQUAL "")
+ if(NOT arg_TARGET_PRODUCT)
set(arg_TARGET_PRODUCT "Qt6")
endif()
- if("${arg_TARGET_DESCRIPTION}" STREQUAL "")
+ if(NOT arg_TARGET_DESCRIPTION)
set(arg_TARGET_DESCRIPTION "C++ Application Development Framework")
endif()
- if("${arg_TARGET_COMPANY}" STREQUAL "")
+ if(NOT arg_TARGET_COMPANY)
set(arg_TARGET_COMPANY "The Qt Company Ltd.")
endif()
- if("${arg_TARGET_COPYRIGHT}" STREQUAL "")
- set(arg_TARGET_COPYRIGHT "Copyright (C) 2022 The Qt Company Ltd.")
+ if(NOT arg_TARGET_COPYRIGHT)
+ set(arg_TARGET_COPYRIGHT "${QT_COPYRIGHT}")
endif()
set_target_properties(${target} PROPERTIES
QT_TARGET_VERSION "${arg_TARGET_VERSION}"
@@ -479,56 +814,139 @@ endif()
endif()
# INTERFACE libraries don't have IMPORTED_LOCATION-like properties.
- # OBJECT libraries have properties like IMPORTED_OBJECTS instead.
- # Skip the rest of the procesing for those.
- if(target_type STREQUAL "INTERFACE_LIBRARY" OR target_type STREQUAL "OBJECT_LIBRARY")
+ # 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(NOT excluded_genex STREQUAL "")
+ 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}\")
+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_CONFIGURATIONS $\{_qt_imported_configs})
set_property(TARGET ${full_target} PROPERTY IMPORTED_LOCATION_DEBUG)
-endif()\n\n")
+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 "")
- string(APPEND content "get_target_property(_qt_imported_location ${full_target} IMPORTED_LOCATION_${uc_release_cfg})\n")
+ 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()
- string(APPEND content "get_target_property(_qt_imported_location_default ${full_target} IMPORTED_LOCATION_$\\{QT_DEFAULT_IMPORT_CONFIGURATION})\n")
if(write_implib)
- string(APPEND content "get_target_property(_qt_imported_implib_default ${full_target} IMPORTED_IMPLIB_$\\{QT_DEFAULT_IMPORT_CONFIGURATION})\n")
+ 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")
+ 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)
@@ -544,20 +962,32 @@ endif()\n\n")
set_property(TARGET ${full_target} APPEND PROPERTY IMPORTED_CONFIGURATIONS ${ucconfig})
")
endif()
- string(APPEND content "
+ 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}}\")
+ 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}}\")
+ 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}}\")
+ 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")
@@ -570,6 +1000,10 @@ 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()
@@ -583,25 +1017,51 @@ unset(_qt_imported_configs)")
endfunction()
function(qt_internal_export_modern_cmake_config_targets_file)
- cmake_parse_arguments(__arg "" "EXPORT_NAME_PREFIX;CONFIG_INSTALL_DIR" "TARGETS" ${ARGN})
+ cmake_parse_arguments(arg
+ ""
+ "EXPORT_NAME_PREFIX;CONFIG_BUILD_DIR;CONFIG_INSTALL_DIR"
+ "TARGETS"
+ ${ARGN}
+ )
- set(export_name "${__arg_EXPORT_NAME_PREFIX}VersionlessTargets")
- foreach(target ${__arg_TARGETS})
- if (TARGET "${target}Versionless")
- continue()
- endif()
+ if("${arg_TARGETS}" STREQUAL "")
+ message(FATAL_ERROR "Target list is empty")
+ 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)
+ if("${arg_CONFIG_BUILD_DIR}" STREQUAL "")
+ message(FATAL_ERROR "CONFIG_BUILD_DIR is not specified")
+ endif()
- qt_install(TARGETS "${target}Versionless" EXPORT ${export_name})
- endforeach()
- qt_install(EXPORT ${export_name} NAMESPACE Qt:: DESTINATION "${__arg_CONFIG_INSTALL_DIR}")
+ 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)
@@ -610,20 +1070,22 @@ function(qt_internal_create_tracepoints name tracepoints_file)
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)
+ 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} PRIVATE Q_TRACEPOINT)
+ 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 "")
@@ -646,6 +1108,77 @@ function(qt_internal_create_tracepoints name tracepoints_file)
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)
@@ -664,12 +1197,12 @@ endfunction()
#
# MSVC generates 2 types of pdb files:
# - compile-time generated pdb files (compile flag /Zi + /Fd<pdb_name>)
-# - link-time genereated pdb files (link flag /debug + /PDB:<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 te compiler), without actually setting the property values.
+# 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
@@ -803,6 +1336,33 @@ endfunction()
# 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)
@@ -850,7 +1410,7 @@ endfunction()
# 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 ModuleDependencies.cmake file.
+# 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.
@@ -867,9 +1427,17 @@ 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})
+ 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.")
@@ -896,3 +1464,208 @@ function(qt_internal_add_repo_local_defines target)
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
index c5b86bab6c..705de2f739 100644
--- a/cmake/QtTestHelpers.cmake
+++ b/cmake/QtTestHelpers.cmake
@@ -1,14 +1,21 @@
+# 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()
- qt_parse_all_arguments(arg "qt_add_benchmark"
+ 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}"
- ${ARGN}
)
+ _qt_internal_validate_all_args_are_parsed(arg)
+ _qt_internal_validate_no_unity_build(arg)
qt_remove_args(exec_args
ARGS_TO_REMOVE
@@ -24,15 +31,30 @@ function(qt_internal_add_benchmark target)
)
if(NOT arg_OUTPUT_DIRECTORY)
- set(arg_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}")
+ 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})
@@ -43,7 +65,7 @@ function(qt_internal_add_benchmark target)
# 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}>"
+ _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}"
@@ -61,46 +83,22 @@ function(qt_internal_add_benchmark target)
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_parse_all_arguments(arg "qt_add_manual_test"
- "${__qt_internal_add_executable_optional_args}"
- "${__qt_internal_add_executable_single_args}"
- "${__qt_internal_add_executable_multi_args}"
- ${ARGN}
- )
-
- 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)
- set(arg_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}")
- endif()
-
- qt_internal_add_executable(${target}
- NO_INSTALL # we don't install benchmarks
- OUTPUT_DIRECTORY "${arg_OUTPUT_DIRECTORY}" # avoid polluting bin directory
- ${exec_args}
- )
-
- # Disable the QT_NO_NARROWING_CONVERSIONS_IN_CONNECT define for manual tests
- qt_internal_undefine_global_definition(${target} QT_NO_NARROWING_CONVERSIONS_IN_CONNECT)
-
+ qt_internal_add_test(${ARGV} MANUAL)
endfunction()
# This function will configure the fixture for the network tests that require docker network services
@@ -111,6 +109,11 @@ function(qt_internal_setup_docker_test_fixture name)
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)
@@ -177,20 +180,32 @@ function(qt_internal_setup_docker_test_fixture name)
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 provded TESTDATA to resources.
-function(qt_internal_add_test name)
- # EXCEPTIONS is a noop as they are enabled by default.
- set(optional_args
+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
@@ -200,54 +215,305 @@ function(qt_internal_add_test name)
LOWDPI
NO_WRAPPER
BUILTIN_TESTDATA
+ MANUAL
+ NO_BATCH
+ NO_INSTALL
+ BUNDLE_ANDROID_OPENSSL_LIBS
+ PARENT_SCOPE
)
- set(single_value_args
+ set(${single_value_args}
OUTPUT_DIRECTORY
WORKING_DIRECTORY
TIMEOUT
VERSION
+ PARENT_SCOPE
)
- set(multi_value_args
+ set(${multi_value_args}
QML_IMPORTPATH
TESTDATA
QT_TEST_SERVER_LIST
${__default_private_args}
${__default_public_args}
+ PARENT_SCOPE
)
- qt_parse_all_arguments(arg "qt_add_test"
+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}"
- ${ARGN}
)
-
- if (NOT arg_OUTPUT_DIRECTORY)
- set(arg_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}")
+ _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()
- # Qt modules get compiled without exceptions enabled by default.
- # However, testcases should be still built with exceptions.
- set(exceptions_text "EXCEPTIONS")
- if (${arg_NO_EXCEPTIONS})
- set(exceptions_text "")
+ 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 (${arg_GUI})
- set(gui_text "GUI")
+ 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()
- if (arg_VERSION)
- set(version_arg VERSION "${arg_VERSION}")
+ 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()
- # 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}/include>"
- ${arg_INCLUDE_DIRECTORIES}
- )
+ 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}
@@ -260,13 +526,18 @@ function(qt_internal_add_test name)
${private_includes}
DEFINES
${arg_DEFINES}
- PUBLIC_LIBRARIES ${QT_CMAKE_EXPORT_NAMESPACE}::Core ${QT_CMAKE_EXPORT_NAMESPACE}::Test ${arg_PUBLIC_LIBRARIES}
- LIBRARIES ${arg_LIBRARIES}
+ ${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})
@@ -274,17 +545,25 @@ function(qt_internal_add_test name)
# Disable the QT_NO_NARROWING_CONVERSIONS_IN_CONNECT define for tests
qt_internal_undefine_global_definition(${name} QT_NO_NARROWING_CONVERSIONS_IN_CONNECT)
- # 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)
+ # 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
- PUBLIC_LIBRARIES ${QT_CMAKE_EXPORT_NAMESPACE}::QuickTest
+ LIBRARIES ${QT_CMAKE_EXPORT_NAMESPACE}::QuickTest
)
qt_internal_extend_target("${name}" CONDITION arg_QMLTEST AND NOT ANDROID
@@ -299,8 +578,15 @@ function(qt_internal_add_test name)
# Android requires Qt::Gui so add it by default for tests
qt_internal_extend_target("${name}" CONDITION ANDROID
- PUBLIC_LIBRARIES ${QT_CMAKE_EXPORT_NAMESPACE}::Gui
+ 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)
@@ -326,14 +612,80 @@ function(qt_internal_add_test name)
endif()
if (ANDROID)
- qt_internal_android_test_arguments("${name}" test_executable extra_test_args)
+ # 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)
- set(test_executable "${__qt_libexec_dir_absolute}/qt-wasmtestrunner.py")
- list(APPEND extra_test_args "${name}.html")
+ # 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}")
@@ -350,58 +702,79 @@ function(qt_internal_add_test name)
endif()
endif()
- qt_internal_collect_command_environment(test_env_path test_env_plugin_path)
+ 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()
- if(arg_NO_WRAPPER OR QT_NO_TEST_WRAPPERS)
- add_test(NAME "${name}" COMMAND ${test_executable} ${extra_test_args}
- WORKING_DIRECTORY "${test_working_dir}")
- set_property(TEST "${name}" 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}/${name}Wrapper$<CONFIG>.cmake")
- qt_internal_create_test_script(NAME "${name}"
- 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()
+ qt_internal_collect_command_environment(test_env_path test_env_plugin_path)
- if(arg_QT_TEST_SERVER_LIST AND NOT ANDROID)
- qt_internal_setup_docker_test_fixture(${name} ${arg_QT_TEST_SERVER_LIST})
- endif()
+ 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()
- 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_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()
- # Add a ${target}/check makefile target, to more easily test one test.
+ if(arg_QT_TEST_SERVER_LIST AND NOT ANDROID)
+ qt_internal_setup_docker_test_fixture(${testname} ${arg_QT_TEST_SERVER_LIST})
+ endif()
- 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("${name}_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("${name}_check" "${name}")
- if(ANDROID)
- add_dependencies("${name}_check" "${name}_make_apk")
+ 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 INTEGRITY OR arg_BUILTIN_TESTDATA)
+ if(ANDROID OR IOS OR WASM OR INTEGRITY OR arg_BUILTIN_TESTDATA)
set(builtin_testdata TRUE)
endif()
@@ -413,10 +786,29 @@ function(qt_internal_add_test name)
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()
- set(blacklist_path "BLACKLIST")
- if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/${blacklist_path}")
- list(APPEND builtin_files ${blacklist_path})
+ 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)
@@ -428,23 +820,35 @@ function(qt_internal_add_test name)
)
endforeach()
- if (builtin_files)
- qt_internal_add_resource(${name} "${name}_testdata_builtin"
+ 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
- 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}")
- if (testdata_install_dir)
+ # 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}"
@@ -458,6 +862,36 @@ function(qt_internal_add_test name)
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
@@ -468,7 +902,7 @@ endfunction()
# 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.
+# 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
@@ -512,6 +946,11 @@ for this function. Will be ignored")
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}")
@@ -520,8 +959,8 @@ for this function. Will be ignored")
# CROSSCOMPILING_EMULATOR don't check if actual cross compilation is configured,
# emulator is prepended independently.
set(crosscompiling_emulator "")
- if(CMAKE_CROSSCOMPILING AND TARGET ${arg_NAME})
- get_target_property(crosscompiling_emulator ${arg_NAME} 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()
@@ -529,7 +968,7 @@ for this function. Will be ignored")
endif()
endif()
- qt_internal_create_command_script(COMMAND "${crosscompiling_emulator} \${env_test_runner} \
+ _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}"
@@ -541,103 +980,11 @@ for this function. Will be ignored")
)
endfunction()
-# 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' sepatator.
-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;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(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()
-
- 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}\"
- RESULT_VARIABLE result
-)
-${post_run}
-if(NOT result EQUAL 0)
- string(JOIN \" \" full_command ${arg_COMMAND})
- message(FATAL_ERROR \"\${full_command} execution failed with exit code \${result}.\")
-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,
+# 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)
@@ -645,11 +992,12 @@ function(qt_internal_add_test_helper name)
"OVERRIDE_OUTPUT_DIRECTORY"
)
- qt_parse_all_arguments(arg "qt_add_test_helper"
+ 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}"
- ${ARGN})
+ )
+ _qt_internal_validate_all_args_are_parsed(arg)
qt_remove_args(forward_args
ARGS_TO_REMOVE
@@ -666,10 +1014,19 @@ function(qt_internal_add_test_helper name)
set(extra_args_to_pass)
if(NOT arg_OVERRIDE_OUTPUT_DIRECTORY)
- set(extra_args_to_pass OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/..")
+ _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 ${extra_args_to_pass} ${forward_args})
+ 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)
@@ -721,3 +1078,14 @@ function(qt_internal_collect_command_environment out_path out_plugin_path)
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
index dac074481a..7dd507c0ee 100644
--- a/cmake/QtToolHelpers.cmake
+++ b/cmake/QtToolHelpers.cmake
@@ -1,3 +1,6 @@
+# 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
@@ -12,6 +15,13 @@
# 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
@@ -30,149 +40,39 @@
# 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 publically
+# 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)
+ 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})
- qt_parse_all_arguments(arg "qt_internal_add_tool" "${option_keywords}"
- "${one_value_keywords}"
- "${multi_value_keywords}" ${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(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${arg_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)
- 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 "Qt6${arg_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)
+ cmake_parse_arguments(PARSE_ARGV 1 arg
+ "${option_keywords}"
+ "${one_value_keywords}"
+ "${multi_value_keywords}")
+ _qt_internal_validate_all_args_are_parsed(arg)
- # 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}")
+ qt_internal_find_tool(will_build_tools ${target_name} "${arg_TOOLS_TARGET}")
- # 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("${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_FORCE_BUILD_TOOLS)
- 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()
- message(STATUS "Tool '${full_name}' will be built from source.")
+ if(NOT will_build_tools)
+ return()
endif()
set(disable_autogen_tools "${arg_DISABLE_AUTOGEN_TOOLS}")
@@ -194,32 +94,65 @@ function(qt_internal_add_tool target_name)
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
- QT_USE_QSTRINGBUILDER
${arg_DEFINES}
+ ${deprecation_define}
${corelib}
- LIBRARIES ${arg_LIBRARIES} Qt::PlatformToolInternal
+ 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}"
+ 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}>>")
@@ -292,17 +225,70 @@ function(qt_internal_add_tool target_name)
endforeach()
if(arg_INSTALL_VERSIONED_LINK)
- qt_internal_install_versioned_link("${install_dir}" "${target_name}")
+ 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)
@@ -335,6 +321,8 @@ function(qt_export_tools module_name)
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).
@@ -360,12 +348,19 @@ function(qt_export_tools module_name)
string(REGEX REPLACE "_native$" "" tool_name ${tool_name})
endif()
set(extra_cmake_statements "${extra_cmake_statements}
-if (NOT QT_NO_CREATE_TARGETS)
+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
@@ -411,9 +406,30 @@ endif()
"${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 ${PROJECT_VERSION}
+ VERSION "${tools_package_version}"
COMPATIBILITY AnyNewerVersion
ARCH_INDEPENDENT
)
@@ -481,25 +497,34 @@ 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.
+ # 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()
- set(will_build_tools TRUE)
+ 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)
- if(QT_FORCE_BUILD_TOOLS)
- set(will_build_tools TRUE)
- set(need_target_rename TRUE)
- endif()
+ 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)
@@ -526,3 +551,219 @@ function(qt_exclude_tool_directories_from_default_target)
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
index 6a003d3e9b..26b44bb10c 100644
--- a/cmake/QtToolchainHelpers.cmake
+++ b/cmake/QtToolchainHelpers.cmake
@@ -1,22 +1,10 @@
+# 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)
- set(qt_host_path_required FALSE)
-
- if(NOT "${QT_HOST_PATH}" STREQUAL "")
- # 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 Qt toolchain file to do appropriate requirement checks.
- set(qt_host_path_required TRUE)
-
- # 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(CMAKE_TOOLCHAIN_FILE)
file(TO_CMAKE_PATH "${CMAKE_TOOLCHAIN_FILE}" __qt_chainload_toolchain_file)
set(init_original_toolchain_file
@@ -43,6 +31,14 @@ set(__qt_chainload_toolchain_file \"\${__qt_initially_configured_toolchain_file}
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")
@@ -133,39 +129,41 @@ set(__qt_chainload_toolchain_file \"\${__qt_initially_configured_toolchain_file}
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(NOT DEFINED CMAKE_C_COMPILER AND EXISTS \"\${__qt_initial_c_compiler}\")
- set(CMAKE_C_COMPILER \"\${__qt_initial_c_compiler}\" CACHE STRING \"\")
- endif()
- if(NOT DEFINED CMAKE_CXX_COMPILER AND EXISTS \"\${__qt_initial_cxx_compiler}\")
- set(CMAKE_CXX_COMPILER \"\${__qt_initial_cxx_compiler}\" CACHE STRING \"\")
- endif()")
+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 iOS build, try to use the initially configured sysroot
- # path if it exists, otherwise just set the name of the sdk to be used.
- # The latter "name" part is important for user projects so that running 'xcodebuild' from
- # the command line chooses the correct sdk.
+ # 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_OSX_SYSROOT AND NOT _qt_osx_architectures_count GREATER 1 AND UIKIT)
+ if(cmake_sysroot_name AND NOT _qt_osx_architectures_count GREATER 1 AND UIKIT)
list(APPEND init_platform "
- set(__qt_uikit_sdk \"${QT_UIKIT_SDK}\")
- set(__qt_initial_cmake_osx_sysroot \"${CMAKE_OSX_SYSROOT}\")
- if(NOT DEFINED CMAKE_OSX_SYSROOT AND EXISTS \"\${__qt_initial_cmake_osx_sysroot}\")
- set(CMAKE_OSX_SYSROOT \"\${__qt_initial_cmake_osx_sysroot}\" CACHE PATH \"\")
- elseif(NOT DEFINED CMAKE_OSX_SYSROOT AND NOT QT_NO_SET_OSX_SYSROOT)
- set(CMAKE_OSX_SYSROOT \"\${__qt_uikit_sdk}\" CACHE PATH \"\")
- endif()")
+if(NOT DEFINED CMAKE_OSX_SYSROOT)
+ set(CMAKE_OSX_SYSROOT \"${cmake_sysroot_name}\" CACHE STRING \"\")
+endif()")
endif()
if(CMAKE_OSX_DEPLOYMENT_TARGET)
@@ -210,8 +208,8 @@ set(__qt_chainload_toolchain_file \"\${__qt_initially_configured_toolchain_file}
# 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 don't set an explicit
- # architecture and let Xcode and the developer handle it.
+ # 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
@@ -220,7 +218,7 @@ set(__qt_chainload_toolchain_file \"\${__qt_initially_configured_toolchain_file}
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_uikit_sdk AND NOT QT_NO_SET_OSX_ARCHITECTURES))")
+ 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()")
@@ -234,15 +232,11 @@ set(__qt_chainload_toolchain_file \"\${__qt_initially_configured_toolchain_file}
elseif(ANDROID)
list(APPEND init_platform
"# Detect Android SDK/NDK from environment before loading the Android platform toolchain file."
-"if(NOT DEFINED ANDROID_SDK_ROOT)"
-" if(NOT \"\$ENV{ANDROID_SDK_ROOT}\" STREQUAL \"\")"
-" set(ANDROID_SDK_ROOT \"\$ENV{ANDROID_SDK_ROOT}\" CACHE STRING \"Path to the Android SDK\")"
-" endif()"
+"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(NOT DEFINED ANDROID_NDK_ROOT)"
-" if(NOT \"\$ENV{ANDROID_NDK_ROOT}\" STREQUAL \"\")"
-" set(ANDROID_NDK_ROOT \"\$ENV{ANDROID_NDK_ROOT}\" CACHE STRING \"Path to the Android NDK\")"
-" 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()"
)
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
index 5e09feac29..41ef5cb0ba 100644
--- a/cmake/QtWasmHelpers.cmake
+++ b/cmake/QtWasmHelpers.cmake
@@ -1,52 +1,48 @@
+# 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 ERROR_ON_UNDEFINED_SYMBOLS=1"
- "SHELL:-s EXPORTED_RUNTIME_METHODS=[UTF16ToString,stringToUTF16,specialHTMLTargets]"
- "SHELL:-s USE_WEBGL2=1"
- "--bind"
+ "SHELL:-s MAX_WEBGL_VERSION=2"
"SHELL:-s FETCH=1"
- "SHELL:-s WASM_BIGINT=1")
+ "SHELL:-s WASM_BIGINT=1"
+ "SHELL:-s STACK_SIZE=5MB")
- # Enable MODULARIZE and set EXPORT_NAME, which makes it possible to
- # create application instances using a global constructor function,
- # e.g. let app_instance = await createQtAppInstance().
- # (as opposed to MODULARIZE=0, where Emscripten creates a global app
- # instance object at Javascript eval time)
- target_link_options("${wasmTarget}" INTERFACE
- "SHELL:-s MODULARIZE=1"
- "SHELL:-s EXPORT_NAME=createQtAppInstance")
+ 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()
- if (QT_FEATURE_opengles3)
- target_link_options("${wasmTarget}" INTERFACE "SHELL:-s FULL_ES3=1")
-
- target_link_options("${wasmTarget}" INTERFACE "SHELL:-s FULL_ES3=1"
- "SHELL:-s MAX_WEBGL_VERSION=2"
- "SHELL:-s WEBGL2_BACKWARDS_COMPATIBILITY_EMULATION=1")
- else()
- target_link_options("${wasmTarget}" INTERFACE "SHELL:-s FULL_ES2=1")
- endif()
-
- set(disable_exceptions_catching 1)
- if (QT_FEATURE_exceptions)
- set(disable_exceptions_catching 0)
+ # wasm exceptions
+ if (QT_FEATURE_wasm_exceptions)
+ target_compile_options("${wasmTarget}" INTERFACE -fwasm-exceptions)
+ target_link_options("${wasmTarget}" INTERFACE -fwasm-exceptions)
endif()
- target_link_options("${wasmTarget}" INTERFACE "SHELL:-s DISABLE_EXCEPTION_CATCHING=${disable_exceptions_catching}")
if (QT_FEATURE_thread)
target_compile_options("${wasmTarget}" INTERFACE "SHELL:-pthread")
target_link_options("${wasmTarget}" INTERFACE "SHELL:-pthread")
- else()
- target_link_options("${wasmTarget}" INTERFACE "SHELL:-s ALLOW_MEMORY_GROWTH=1")
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/")
@@ -65,7 +61,6 @@ function (qt_internal_setup_wasm_target_properties wasmTarget)
# a few good defaults to make console more verbose while debugging
target_link_options("${wasmTarget}" INTERFACE $<$<CONFIG:Debug>:
"SHELL:-s DEMANGLE_SUPPORT=1"
- "SHELL:-s GL_DEBUG=1"
--profiling-funcs>)
# target_link_options("${wasmTarget}" INTERFACE "SHELL:-s LIBRARY_DEBUG=1") # print out library calls, verbose
@@ -74,7 +69,6 @@ function (qt_internal_setup_wasm_target_properties wasmTarget)
# 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
@@ -82,7 +76,52 @@ function (qt_internal_setup_wasm_target_properties wasmTarget)
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" "-s" "ASYNCIFY_IMPORTS=[qt_asyncify_suspend_js, qt_asyncify_resume_js]")
+ 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
index adb50bf25b..8eb4416e6d 100644
--- a/cmake/QtWrapperScriptHelpers.cmake
+++ b/cmake/QtWrapperScriptHelpers.cmake
@@ -1,3 +1,6 @@
+# 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
@@ -16,13 +19,18 @@ function(qt_internal_create_wrapper_scripts)
set(generate_non_unix TRUE)
endif()
+ set(extra_qt_cmake_code "")
if(generate_unix)
- if(IOS)
- set(infix ".ios")
- else()
- set(infix "")
+
+ 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${infix}.in"
+
+ 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"
@@ -36,21 +44,40 @@ function(qt_internal_create_wrapper_scripts)
DESTINATION "${INSTALL_BINDIR}")
endif()
- # Provide a private convenience wrapper with options which should not be propagated via the
+ 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.
- # 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}\"")
+ # 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_BINDIR}/qt-cmake-private" @ONLY
+ "${QT_BUILD_DIR}/${INSTALL_LIBEXECDIR}/qt-cmake-private" @ONLY
NEWLINE_STYLE LF)
- qt_install(PROGRAMS "${QT_BUILD_DIR}/${INSTALL_BINDIR}/qt-cmake-private"
- DESTINATION "${INSTALL_BINDIR}")
+ 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"
@@ -92,17 +119,36 @@ function(qt_internal_create_wrapper_scripts)
# 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_standalone_test_bin_path
- "${INSTALL_BINDIR}/${__qt_cmake_standalone_test_bin_name}")
- set(__qt_cmake_private_path
- "${QT_STAGING_PREFIX}/${INSTALL_BINDIR}/qt-cmake-private")
+ 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}")
- get_filename_component(rel_base_path
- "${QT_STAGING_PREFIX}/${__qt_cmake_standalone_test_bin_path}"
- DIRECTORY)
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..
@@ -111,12 +157,16 @@ function(qt_internal_create_wrapper_scripts)
"${__qt_cmake_standalone_test_path}")
endif()
- 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}")
-
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/")
@@ -124,12 +174,21 @@ function(qt_internal_create_wrapper_scripts)
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_bin_path}"
+ "${QT_BUILD_DIR}/${__qt_cmake_standalone_test_libexec_path}"
NEWLINE_STYLE LF)
- qt_install(PROGRAMS "${QT_BUILD_DIR}/${__qt_cmake_standalone_test_bin_path}"
- DESTINATION "${INSTALL_BINDIR}")
+ 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")
@@ -153,16 +212,33 @@ function(qt_internal_create_wrapper_scripts)
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_BINDIR}/${__qt_cmake_install_script_name}" @ONLY)
- qt_install(FILES "${QT_BUILD_DIR}/${INSTALL_BINDIR}/${__qt_cmake_install_script_name}"
- DESTINATION "${INSTALL_BINDIR}")
+ "${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_tests_wrapper_script()
- qt_internal_install_android_helper_scripts()
+ 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_tests_wrapper_script)
+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)
@@ -172,17 +248,27 @@ function(qt_internal_create_qt_configure_tests_wrapper_script)
set(generate_non_unix TRUE)
endif()
- # Create a private wrapper script to configure and build all standalone tests.
+ # 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 will be configured.
- set(script_name "qt-internal-configure-tests")
+ # 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()
- set(script_passed_args "-DQT_BUILD_STANDALONE_TESTS=ON")
+ 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}
@@ -200,16 +286,48 @@ function(qt_internal_create_qt_configure_tests_wrapper_script)
endif()
if(generate_non_unix)
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/libexec/${script_name}.bat.in"
- "${QT_BUILD_DIR}/${INSTALL_LIBEXECDIR}/${script_name}.bat" @ONLY
+ "${QT_BUILD_DIR}/${INSTALL_BINDIR}/${script_name}.bat" @ONLY
NEWLINE_STYLE CRLF)
- qt_install(PROGRAMS "${QT_BUILD_DIR}/${INSTALL_LIBEXECDIR}/${script_name}.bat"
- DESTINATION "${INSTALL_LIBEXECDIR}")
+ qt_install(PROGRAMS "${QT_BUILD_DIR}/${INSTALL_BINDIR}/${script_name}.bat"
+ DESTINATION "${INSTALL_BINDIR}")
endif()
endfunction()
-function(qt_internal_install_android_helper_scripts)
- qt_path_join(destination "${QT_INSTALL_DIR}" "${INSTALL_LIBEXECDIR}")
- qt_copy_or_install(PROGRAMS "${CMAKE_CURRENT_SOURCE_DIR}/util/android/android_emulator_launcher.sh"
- DESTINATION "${destination}")
+# 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
index 666806ffcc..77a9eb2463 100644
--- a/cmake/QtWriteArgsFile.cmake
+++ b/cmake/QtWriteArgsFile.cmake
@@ -1,19 +1,79 @@
+# 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.
+# 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})
diff --git a/cmake/README.md b/cmake/README.md
index 7bb778a7ce..9d0743566d 100644
--- a/cmake/README.md
+++ b/cmake/README.md
@@ -4,6 +4,11 @@ This document gives an overview of the Qt 6 build system. For a hands-on guide o
to build Qt 6, see https://doc.qt.io/qt-6/build-sources.html and
https://wiki.qt.io/Building_Qt_6_from_Git
+# Contributing
+
+See qtbase/cmake/CODESTYLE.md for the code style you should follow when contributing
+to Qt's cmake files.
+
# CMake Versions
* You need CMake 3.16.0 or later for most platforms (due to new AUTOMOC json feature).
@@ -48,7 +53,9 @@ You may use brew to install dependencies needed to build QtBase.
`/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
@@ -132,7 +139,7 @@ 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
@@ -193,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=...``, CMake will build a
+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_UIKIT_SDK=iphonesimulator``
- * iphoneos: ``-DQT_UIKIT_SDK=iphoneos``
+ * 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``
@@ -311,3 +318,16 @@ $ 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 1282c0d484..d504bd8d4b 100644
--- a/cmake/configure-cmake-mapping.md
+++ b/cmake/configure-cmake-mapping.md
@@ -8,6 +8,7 @@ The following table describes the mapping of configure options to CMake argument
| -extprefix /opt/qt6 | -DCMAKE_STAGING_PREFIX=/opt/qt6 | |
| -bindir <dir> | -DINSTALL_BINDIR=<dir> | similar for -headerdir -libdir and so on |
| -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 | | |
@@ -17,7 +18,6 @@ The following table describes the mapping of configure options to CMake argument
| -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 | n/a | |
| -commercial | n/a | |
| -confirm-license | n/a | |
@@ -45,10 +45,11 @@ The following table describes the mapping of configure options to CMake argument
| -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 | -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> | |
-| -testcocoon | | |
-| -gcov | | |
+| -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 |
@@ -60,6 +61,7 @@ The following table describes the mapping of configure options to CMake argument
| -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 | | |
@@ -73,21 +75,16 @@ The following table describes the mapping of configure options to CMake argument
| | | 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 | n/a | |
-| -sysroot <dir> | -DCMAKE_SYSROOT=<dir> | Should be provided by a toolchain file that's |
-| | | passed via -DCMAKE_TOOLCHAIN_FILE=<filename> |
-| -no-gcc-sysroot | n/a | The corresponding CMake variables are CMAKE_SYSROOT_LINK |
-| | | and CMAKE_SYSROOT_COMPILE. |
-| | | They are usually set in a toolchain file. |
| -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_UIKIT_SDK=<value> | Should be provided a value like 'iphoneos' or 'iphonesimulator' |
+| -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> | |
@@ -98,7 +95,9 @@ The following table describes the mapping of configure options to CMake argument
| -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 | |
-| -submodules <repo>,...,<repo_n> | -QT_BUILD_SUBMODULES=<repo>;...;<repo> | |
+| -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 |
@@ -108,6 +107,7 @@ The following table describes the mapping of configure options to CMake argument
| | | 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 | |
@@ -118,7 +118,6 @@ The following table describes the mapping of configure options to CMake argument
| -doubleconversion | -DFEATURE_doubleconversion=ON | |
| | -DFEATURE_system_doubleconversion=ON/OFF | |
| -glib | -DFEATURE_glib=ON | |
-| -eventfd | -DFEATURE_eventfd=ON | |
| -inotify | -DFEATURE_inotify=ON | |
| -icu | -DFEATURE_icu=ON | |
| -pcre | -DFEATURE_pcre2=ON | |
@@ -165,7 +164,10 @@ The following table describes the mapping of configure options to CMake argument
| -xkbcommon | -DFEATURE_xkbcommon=ON | |
| -gif | -DFEATURE_gif=ON | |
| -ico | -DFEATURE_ico=ON | |
-| -libpng | -DFEATURE_libpng=ON | |
-| -libjpeg | -DFEATURE_libjpeg=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
index cfe5d26eba..83df24b618 100644
--- a/cmake/ios/LaunchScreen.storyboard
+++ b/cmake/ios/LaunchScreen.storyboard
@@ -14,29 +14,7 @@
<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"/>
- <subviews>
- <label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumFontSize="9" translatesAutoresizingMaskIntoConstraints="NO" id="obG-Y5-kRd">
- <rect key="frame" x="0.0" y="626.5" width="375" height="20.5"/>
- <fontDescription key="fontDescription" type="system" pointSize="17"/>
- <color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
- <nil key="highlightedColor"/>
- </label>
- <label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="@QT_IOS_LAUNCH_SCREEN_TEXT@" textAlignment="center" lineBreakMode="middleTruncation" baselineAdjustment="alignBaselines" minimumFontSize="18" translatesAutoresizingMaskIntoConstraints="NO" id="GJd-Yh-RWb">
- <rect key="frame" x="0.0" y="202" width="375" height="43"/>
- <fontDescription key="fontDescription" type="boldSystem" pointSize="36"/>
- <color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
- <nil key="highlightedColor"/>
- </label>
- </subviews>
- <color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
- <constraints>
- <constraint firstItem="Bcu-3y-fUS" firstAttribute="centerX" secondItem="obG-Y5-kRd" secondAttribute="centerX" id="5cz-MP-9tL"/>
- <constraint firstItem="Bcu-3y-fUS" firstAttribute="centerX" secondItem="GJd-Yh-RWb" secondAttribute="centerX" id="Q3B-4B-g5h"/>
- <constraint firstItem="obG-Y5-kRd" firstAttribute="leading" secondItem="Bcu-3y-fUS" secondAttribute="leading" constant="20" symbolic="YES" id="SfN-ll-jLj"/>
- <constraint firstAttribute="bottom" secondItem="obG-Y5-kRd" secondAttribute="bottom" constant="20" id="Y44-ml-fuU"/>
- <constraint firstItem="GJd-Yh-RWb" firstAttribute="centerY" secondItem="Ze5-6b-2t3" secondAttribute="bottom" multiplier="1/3" constant="1" id="moa-c2-u7t"/>
- <constraint firstItem="GJd-Yh-RWb" firstAttribute="leading" secondItem="Bcu-3y-fUS" secondAttribute="leading" constant="20" symbolic="YES" id="x7j-FC-K8j"/>
- </constraints>
+ <color key="backgroundColor" systemColor="systemBackgroundColor"/>
<viewLayoutGuide key="safeArea" id="Bcu-3y-fUS"/>
</view>
</viewController>
@@ -45,4 +23,9 @@
<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/MacOSXBundleInfo.plist.in b/cmake/ios/MacOSXBundleInfo.plist.in
deleted file mode 100644
index 0cecf4ba99..0000000000
--- a/cmake/ios/MacOSXBundleInfo.plist.in
+++ /dev/null
@@ -1,55 +0,0 @@
-<?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>NSHumanReadableCopyright</key>
- <string>${MACOSX_BUNDLE_COPYRIGHT}</string>
-
- <key>CFBundleIconFile</key>
- <string>${MACOSX_BUNDLE_ICON_FILE}</string>
-
- <key>CFBundleDevelopmentRegion</key>
- <string>English</string>
-
- <key>LSRequiresIPhoneOS</key>
- <true/>
-
- <key>NOTE</key>
- <string>This file was generated by Qt's default CMake support.</string>
-
- <key>UILaunchStoryboardName</key>
- <string>${QT_INTERNAL_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/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 2ead02b7d5..c791521655 100644
--- a/cmake/macos/MacOSXBundleInfo.plist.in
+++ b/cmake/macos/Info.plist.app.in
@@ -29,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
index c39065c3fb..4d41a3a2a2 100644
--- a/cmake/modulecppexports.h.in
+++ b/cmake/modulecppexports.h.in
@@ -1,10 +1,12 @@
-// Copyright (C) 2021 The Qt Company Ltd.
+// 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/qglobal.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)
@@ -16,10 +18,33 @@
# 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)
+# 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
+# define QT_@module_define_infix@_REMOVED_SINCE(major, minor) 0
#endif
#endif // @header_base_name_upper@_H
diff --git a/cmake/modulecppexports_p.h.in b/cmake/modulecppexports_p.h.in
deleted file mode 100644
index 5f873e3c70..0000000000
--- a/cmake/modulecppexports_p.h.in
+++ /dev/null
@@ -1,22 +0,0 @@
-// Copyright (C) 2021 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@_P_H
-#define @header_base_name_upper@_P_H
-
-//
-// W A R N I N G
-// -------------
-//
-// This file is not part of the Qt API. It exists purely as an
-// implementation detail. This header file may change from version to
-// version without notice, or even be removed.
-//
-// We mean it.
-//
-
-#include <@module_include_name@/@header_base_name@.h>
-
-#define Q_@module_define_infix@_PRIVATE_EXPORT Q_@module_define_infix@_EXPORT
-
-#endif // @header_base_name_upper@_P_H
diff --git a/cmake/platforms/FindIntegrityPlatformGraphics.cmake b/cmake/platforms/FindIntegrityPlatformGraphics.cmake
index cfcd260740..7b03d7ae89 100644
--- a/cmake/platforms/FindIntegrityPlatformGraphics.cmake
+++ b/cmake/platforms/FindIntegrityPlatformGraphics.cmake
@@ -1,3 +1,6 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
#.rst:
# IntegrityPlatformGraphics
# ---------
diff --git a/cmake/platforms/Platform/Integrity.cmake b/cmake/platforms/Platform/Integrity.cmake
index 964a01fc2f..0ad7fd1099 100644
--- a/cmake/platforms/Platform/Integrity.cmake
+++ b/cmake/platforms/Platform/Integrity.cmake
@@ -1,3 +1,6 @@
+# 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.
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 6e37ae0281..15cf7a432e 100644
--- a/cmake/qt.toolchain.cmake.in
+++ b/cmake/qt.toolchain.cmake.in
@@ -3,11 +3,7 @@ set(__qt_toolchain_used_variables
QT_TOOLCHAIN_INCLUDE_FILE
QT_TOOLCHAIN_RELOCATABLE_CMAKE_DIR
QT_TOOLCHAIN_RELOCATABLE_PREFIX
- QT_HOST_PATH
- QT_HOST_PATH_CMAKE_DIR
- QT_REQUIRE_HOST_PATH_CHECK
QT_ADDITIONAL_PACKAGES_PREFIX_PATH
- QT_ADDITIONAL_HOST_PACKAGES_PREFIX_PATH
)
@init_additional_used_variables@
@@ -38,7 +34,7 @@ if(__qt_chainload_toolchain_file)
"${__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."
)
@@ -154,73 +150,6 @@ if(QT_TOOLCHAIN_INCLUDE_FILE)
endif()
endif()
-# 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_toolchain_host_path_required "${QT_REQUIRE_HOST_PATH_CHECK}")
-else()
- set(__qt_toolchain_host_path_required "@qt_host_path_required@")
-endif()
-set(__qt_toolchain_initial_qt_host_path
- "@qt_host_path_absolute@")
-set(__qt_toolchain_initial_qt_host_path_cmake_dir
- "@qt_host_path_cmake_dir_absolute@")
-
-# 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 "")
- else(__qt_toolchain_initial_qt_host_path AND EXISTS "${__qt_toolchain_initial_qt_host_path}")
- set(QT_HOST_PATH "${__qt_toolchain_initial_qt_host_path}" CACHE PATH "")
- endif()
-endif()
-
-if(NOT QT_HOST_PATH STREQUAL "")
- get_filename_component(__qt_toolchain_host_path_absolute "${QT_HOST_PATH}" ABSOLUTE)
-endif()
-
-if(__qt_toolchain_host_path_required AND
- ("${QT_HOST_PATH}" STREQUAL "" OR NOT EXISTS "${__qt_toolchain_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(__qt_toolchain_host_path_required AND NOT DEFINED QT_HOST_PATH_CMAKE_DIR)
- if(__qt_toolchain_initial_qt_host_path_cmake_dir
- AND EXISTS "${__qt_toolchain_initial_qt_host_path_cmake_dir}")
- set(QT_HOST_PATH_CMAKE_DIR "${__qt_toolchain_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_toolchain_host_path_cmake_dir_absolute
- "${QT_HOST_PATH_CMAKE_DIR}" ABSOLUTE)
-endif()
-
-if(__qt_toolchain_host_path_required AND
- ("${QT_HOST_PATH_CMAKE_DIR}" STREQUAL ""
- OR NOT EXISTS "${__qt_toolchain_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()
-
# 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})
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 8fe611b835..415accb04e 100644
--- a/cmake/tests/features/CMakeLists.txt
+++ b/cmake/tests/features/CMakeLists.txt
@@ -1,3 +1,6 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
cmake_minimum_required(VERSION 3.16)
project(FeaturesTest
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 ad1162e538..5beecc6ec3 100644
--- a/cmake/tests/qt_make_output_file/CMakeLists.txt
+++ b/cmake/tests/qt_make_output_file/CMakeLists.txt
@@ -1,3 +1,6 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
cmake_minimum_required(VERSION 3.16)
project(QtMakeOutputFileTest
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>