From ae64356a5b0283367db66de4bfc82af9ba5142e4 Mon Sep 17 00:00:00 2001 From: Joerg Bornemann Date: Thu, 17 Aug 2023 17:14:09 +0200 Subject: [PATCH] Fix running CMake test projects in prefix builds Consider the following situation: There are CMake tests in qttools/tests/auto/cmake that configure and build CMake test projects, essentially as external projects. One of those test projects does find_package(Qt6 COMPONENTS LinguistTools). This call fails in a prefix build, because Qt6LinguistToolsConfig.cmake is not installed yet. It merely exists in qttools-build/lib/cmake/Qt6LinguistTools. We must adjust CMAKE_PREFIX_PATH to be able to find Qt6LinguistTools. We also must adjust QT_ADDITIONAL_PACKAGES_PREFIX_PATH to be able to find the LinguistTools component of the Qt6 package. Use the prefixes setup from the support for building examples as external projects and use it for CMake test projects as well. Task-number: QTBUG-84884 Change-Id: I1bd5d5084cf931196bdb014cd75ca7578cd9decb Reviewed-by: Alexey Edelev Reviewed-by: Alexandru Croitor (cherry picked from commit ba9623860056cbb75e426e27905f9c29b687cefa) --- cmake/QtBaseGlobalTargets.cmake | 1 + cmake/QtBuild.cmake | 1 + .../QtBuildInternalsConfig.cmake | 38 ++-------- cmake/QtConfig.cmake.in | 1 + cmake/QtPublicExternalProjectHelpers.cmake | 72 +++++++++++++++++++ src/corelib/Qt6CTestMacros.cmake | 11 +-- 6 files changed, 87 insertions(+), 37 deletions(-) create mode 100644 cmake/QtPublicExternalProjectHelpers.cmake diff --git a/cmake/QtBaseGlobalTargets.cmake b/cmake/QtBaseGlobalTargets.cmake index cb5b67362b0..78d934d2686 100644 --- a/cmake/QtBaseGlobalTargets.cmake +++ b/cmake/QtBaseGlobalTargets.cmake @@ -335,6 +335,7 @@ set(__public_cmake_helpers cmake/QtPublicAppleHelpers.cmake cmake/QtPublicCMakeHelpers.cmake cmake/QtPublicCMakeVersionHelpers.cmake + cmake/QtPublicExternalProjectHelpers.cmake cmake/QtPublicFinalizerHelpers.cmake cmake/QtPublicPluginHelpers.cmake cmake/QtPublicTargetHelpers.cmake diff --git a/cmake/QtBuild.cmake b/cmake/QtBuild.cmake index 1dc576d27af..0b8b00015e0 100644 --- a/cmake/QtBuild.cmake +++ b/cmake/QtBuild.cmake @@ -560,6 +560,7 @@ endif() # Helpers that are available in public projects and while building Qt itself. include(QtPublicAppleHelpers) include(QtPublicCMakeHelpers) +include(QtPublicExternalProjectHelpers) include(QtPublicPluginHelpers) include(QtPublicTargetHelpers) include(QtPublicWalkLibsHelpers) diff --git a/cmake/QtBuildInternals/QtBuildInternalsConfig.cmake b/cmake/QtBuildInternals/QtBuildInternalsConfig.cmake index 20783d8934b..2b7219745e3 100644 --- a/cmake/QtBuildInternals/QtBuildInternalsConfig.cmake +++ b/cmake/QtBuildInternals/QtBuildInternalsConfig.cmake @@ -1101,39 +1101,13 @@ function(qt_internal_add_example_external_project subdir) cmake_parse_arguments(PARSE_ARGV 1 arg "${options}" "${singleOpts}" "${multiOpts}") - # 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}") + _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 + ) - # 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() + list(APPEND QT_ADDITIONAL_PACKAGES_PREFIX_PATH "${qt_additional_packages_prefixes}") set(vars_to_pass_if_defined) set(var_defs) diff --git a/cmake/QtConfig.cmake.in b/cmake/QtConfig.cmake.in index 2e498284724..66c10f3a57c 100644 --- a/cmake/QtConfig.cmake.in +++ b/cmake/QtConfig.cmake.in @@ -41,6 +41,7 @@ endif() # Public helpers available to all Qt packages. include("${CMAKE_CURRENT_LIST_DIR}/QtFeature.cmake") include("${CMAKE_CURRENT_LIST_DIR}/QtPublicAppleHelpers.cmake") +include("${CMAKE_CURRENT_LIST_DIR}/QtPublicExternalProjectHelpers.cmake") include("${CMAKE_CURRENT_LIST_DIR}/QtPublicFinalizerHelpers.cmake") include("${CMAKE_CURRENT_LIST_DIR}/QtPublicPluginHelpers.cmake") include("${CMAKE_CURRENT_LIST_DIR}/QtPublicTargetHelpers.cmake") diff --git a/cmake/QtPublicExternalProjectHelpers.cmake b/cmake/QtPublicExternalProjectHelpers.cmake new file mode 100644 index 00000000000..88bcce53a57 --- /dev/null +++ b/cmake/QtPublicExternalProjectHelpers.cmake @@ -0,0 +1,72 @@ +# 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}" + ) + + # TODO: Fix example/test 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}") + 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) + set("${arg_CMAKE_DIR}" "${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/src/corelib/Qt6CTestMacros.cmake b/src/corelib/Qt6CTestMacros.cmake index fb2ee6d3d0f..11101f7fa6f 100644 --- a/src/corelib/Qt6CTestMacros.cmake +++ b/src/corelib/Qt6CTestMacros.cmake @@ -142,17 +142,18 @@ function(_qt_internal_get_cmake_test_configure_options out_var) ) endforeach() - set(prefixes "") - foreach(prefix_path IN LISTS CMAKE_PREFIX_PATH) - file(TO_CMAKE_PATH "${prefix_path}" prefix_path) - list(APPEND prefixes "${prefix_path}") - endforeach() + _qt_internal_get_build_vars_for_external_projects( + PREFIXES_VAR prefixes + ADDITIONAL_PACKAGES_PREFIXES_VAR additional_prefixes + ) + if(arg_OUT_PREFIX_PATH) set(${arg_OUT_PREFIX_PATH} "${prefixes}" PARENT_SCOPE) endif() string(REPLACE ";" "\;" prefixes "${prefixes}") list(APPEND option_list "-DCMAKE_PREFIX_PATH=${prefixes}") + list(APPEND option_list "-DQT_ADDITIONAL_PACKAGES_PREFIX_PATH=${additional_prefixes}") set(${out_var} "${option_list}" PARENT_SCOPE) endfunction()