diff --git a/cmake/QtBaseHelpers.cmake b/cmake/QtBaseHelpers.cmake index 0157baf6495..a16f6987b46 100644 --- a/cmake/QtBaseHelpers.cmake +++ b/cmake/QtBaseHelpers.cmake @@ -52,17 +52,33 @@ function(qt_internal_check_if_path_has_symlinks path) 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) - # Run auto detection routines, but not when doing standalone tests. In that case, the detection + 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_BUILD_STANDALONE_TESTS AND NOT QT_SUPERBUILD) + 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_BUILD_STANDALONE_TESTS) + 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}) @@ -104,7 +120,7 @@ macro(qt_internal_qtbase_pre_project_setup) find_package(QtBuildInternals CMAKE_FIND_ROOT_PATH_BOTH) unset(QT_BUILD_INTERNALS_SKIP_CMAKE_MODULE_PATH_ADDITION) else() - # When building standalone tests, an istalled BuildInternals package already exists. + # When building standalone parts, an istalled BuildInternals package already exists. find_package(Qt6 REQUIRED COMPONENTS BuildInternals CMAKE_FIND_ROOT_PATH_BOTH) endif() endmacro() @@ -137,7 +153,7 @@ macro(qt_internal_qtbase_build_repo) qt_build_repo_begin() - if(NOT QT_BUILD_STANDALONE_TESTS) + 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}) @@ -188,7 +204,7 @@ macro(qt_internal_qtbase_build_repo) add_subdirectory(src) endif() - if(NOT QT_BUILD_STANDALONE_TESTS) + if(NOT QT_INTERNAL_BUILD_STANDALONE_PARTS) if(QT_WILL_BUILD_TOOLS AND QT_FEATURE_settings) add_subdirectory(qmake) endif() diff --git a/cmake/QtBaseTopLevelHelpers.cmake b/cmake/QtBaseTopLevelHelpers.cmake index 8de37a485a1..07893b6cece 100644 --- a/cmake/QtBaseTopLevelHelpers.cmake +++ b/cmake/QtBaseTopLevelHelpers.cmake @@ -1,14 +1,29 @@ # 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_BUILD_STANDALONE_TESTS) + 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}'") @@ -28,7 +43,7 @@ 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_BUILD_STANDALONE_TESTS) + 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}'") @@ -48,7 +63,7 @@ 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_BUILD_STANDALONE_TESTS) + if (NOT QT_INTERNAL_BUILD_STANDALONE_PARTS) set(QT_NO_CREATE_TARGETS TRUE) endif() endmacro() @@ -62,7 +77,7 @@ macro(qt_internal_top_level_end) endmacro() function(qt_internal_print_top_level_info) - if(NOT QT_BUILD_STANDALONE_TESTS) + if(NOT QT_INTERNAL_BUILD_STANDALONE_PARTS) # Display a summary of everything include(QtBuildInformation) include(QtPlatformSupport) @@ -73,7 +88,7 @@ endfunction() macro(qt_internal_top_level_after_add_subdirectory) if(module STREQUAL "qtbase") - if (NOT QT_BUILD_STANDALONE_TESTS) + 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() diff --git a/cmake/QtBuildInformation.cmake b/cmake/QtBuildInformation.cmake index 9de5705c1b1..11fa9996b1e 100644 --- a/cmake/QtBuildInformation.cmake +++ b/cmake/QtBuildInformation.cmake @@ -58,8 +58,7 @@ 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() diff --git a/cmake/QtBuildInternals/QtStandaloneTestTemplateProject/Main.cmake b/cmake/QtBuildInternals/QtStandaloneTestTemplateProject/Main.cmake index 3d5117d9232..bd0984f3145 100644 --- a/cmake/QtBuildInternals/QtStandaloneTestTemplateProject/Main.cmake +++ b/cmake/QtBuildInternals/QtStandaloneTestTemplateProject/Main.cmake @@ -10,9 +10,9 @@ qt_build_internals_set_up_private_api() # 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() @@ -23,5 +23,5 @@ 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/QtBuildOptionsHelpers.cmake b/cmake/QtBuildOptionsHelpers.cmake index 5fe3494bb9c..484fa6296e6 100644 --- a/cmake/QtBuildOptionsHelpers.cmake +++ b/cmake/QtBuildOptionsHelpers.cmake @@ -92,11 +92,12 @@ function(qt_internal_force_set_cmake_build_type_if_cmake_default_initialized val endfunction() function(qt_internal_set_cmake_build_type) - # When building standalone tests against a multi-config Qt, we want to configure the tests with + # 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_BUILD_STANDALONE_TESTS AND QT_MULTI_CONFIG_FIRST_CONFIG) + 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}") @@ -305,6 +306,16 @@ macro(qt_internal_setup_build_examples) option(QT_INSTALL_EXAMPLES_SOURCES_BY_DEFAULT "Install example sources as part of the default 'install' target" ON) + 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() + # 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 diff --git a/cmake/QtBuildPathsHelpers.cmake b/cmake/QtBuildPathsHelpers.cmake index 18082ac6a5f..ad4b7a1365a 100644 --- a/cmake/QtBuildPathsHelpers.cmake +++ b/cmake/QtBuildPathsHelpers.cmake @@ -7,7 +7,7 @@ macro(qt_internal_setup_default_install_prefix) # is specified. # This detection only happens when building qtbase, and later is propagated via the generated # QtBuildInternalsExtra.cmake file. - if (PROJECT_NAME STREQUAL "QtBase" AND NOT QT_BUILD_STANDALONE_TESTS) + if(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 @@ -56,7 +56,8 @@ 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 are built against a super-built Qt. + # 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, diff --git a/cmake/QtBuildRepoExamplesHelpers.cmake b/cmake/QtBuildRepoExamplesHelpers.cmake index 4c60bdd79e3..96b804ec814 100644 --- a/cmake/QtBuildRepoExamplesHelpers.cmake +++ b/cmake/QtBuildRepoExamplesHelpers.cmake @@ -8,11 +8,18 @@ macro(qt_examples_build_begin) cmake_parse_arguments(arg "${options}" "${singleOpts}" "${multiOpts}" ${ARGN}) + # Examples are not unity-ready. set(CMAKE_UNITY_BUILD OFF) # 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 @@ -171,6 +178,11 @@ 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() diff --git a/cmake/QtBuildRepoHelpers.cmake b/cmake/QtBuildRepoHelpers.cmake index f2d25e03130..9c30b6793e7 100644 --- a/cmake/QtBuildRepoHelpers.cmake +++ b/cmake/QtBuildRepoHelpers.cmake @@ -98,7 +98,7 @@ macro(qt_enable_cmake_languages) # 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. + # 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") @@ -158,7 +158,22 @@ macro(qt_internal_prepare_single_repo_target_set_build) 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}") @@ -300,14 +315,14 @@ endmacro() 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_BUILD_STANDALONE_TESTS) + if(NOT QT_INTERNAL_BUILD_STANDALONE_PARTS) include(QtPostProcess) endif() endif() endmacro() macro(qt_build_repo_end) - if(NOT QT_BUILD_STANDALONE_TESTS) + if(NOT QT_INTERNAL_BUILD_STANDALONE_PARTS) qt_build_repo_post_process() # Install the repo-specific cmake find modules. @@ -391,7 +406,7 @@ 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) + 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) @@ -408,7 +423,7 @@ macro(qt_build_repo_impl_find_package_tests) endmacro() macro(qt_build_repo_impl_src) - if(NOT QT_BUILD_STANDALONE_TESTS) + if(NOT QT_INTERNAL_BUILD_STANDALONE_PARTS) if (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/src/CMakeLists.txt") add_subdirectory(src) endif() @@ -420,7 +435,7 @@ macro(qt_build_repo_impl_src) endmacro() macro(qt_build_repo_impl_tools) - if(NOT QT_BUILD_STANDALONE_TESTS) + if(NOT QT_INTERNAL_BUILD_STANDALONE_PARTS) if (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/tools/CMakeLists.txt") add_subdirectory(tools) endif() @@ -428,7 +443,12 @@ macro(qt_build_repo_impl_tools) endmacro() macro(qt_build_repo_impl_tests) - if (QT_BUILD_TESTS AND EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/tests/CMakeLists.txt") + 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}) @@ -441,9 +461,13 @@ macro(qt_build_repo_impl_tests) 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) + 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) @@ -466,22 +490,19 @@ macro(qt_set_up_standalone_tests_build) # 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") +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") - # 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(path_suffix "${INSTALL_LIBDIR}/cmake/${INSTALL_CMAKE_NAMESPACE}BuildInternals/${dir_name}") + set(path "${QT_BUILD_INTERNALS_RELOCATABLE_INSTALL_PREFIX}/${path_suffix}") set("${out_var}" "${path}" PARENT_SCOPE) endfunction() -function(qt_internal_get_standalone_tests_config_file_name out_var) +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. @@ -490,46 +511,17 @@ function(qt_internal_get_standalone_tests_config_file_name out_var) 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_build_tests) - 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") - - 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) - +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. @@ -540,17 +532,62 @@ macro(qt_build_tests) 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() - 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() + # 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 @@ -628,17 +665,22 @@ function(qt_get_relocatable_install_prefix out_var) set(${out_var} "${CMAKE_INSTALL_PREFIX}" PARENT_SCOPE) endfunction() -function(qt_set_up_fake_standalone_tests_install_prefix) +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() - set(new_install_prefix "${CMAKE_BINARY_DIR}/fake_prefix") + qt_internal_get_fake_standalone_install_prefix(new_install_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. + # 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) @@ -656,12 +698,16 @@ function(qt_set_up_fake_standalone_tests_install_prefix) 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). +# 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 - set(QT_NO_CREATE_TARGETS TRUE) + + # 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) diff --git a/cmake/QtPluginConfig.cmake.in b/cmake/QtPluginConfig.cmake.in index 35cea1bcc5c..1dc30b03380 100644 --- a/cmake/QtPluginConfig.cmake.in +++ b/cmake/QtPluginConfig.cmake.in @@ -3,7 +3,7 @@ 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/QtPostProcessHelpers.cmake b/cmake/QtPostProcessHelpers.cmake index 0c89d37f8ea..44df18714f7 100644 --- a/cmake/QtPostProcessHelpers.cmake +++ b/cmake/QtPostProcessHelpers.cmake @@ -819,7 +819,7 @@ function(qt_internal_create_config_file_for_standalone_tests) # 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) diff --git a/cmake/QtPublicExternalProjectHelpers.cmake b/cmake/QtPublicExternalProjectHelpers.cmake index ae4541d89c7..07096523d0b 100644 --- a/cmake/QtPublicExternalProjectHelpers.cmake +++ b/cmake/QtPublicExternalProjectHelpers.cmake @@ -24,8 +24,22 @@ function(_qt_internal_get_build_vars_for_external_projects) "${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. - if(QT_SUPERBUILD OR QtBase_BINARY_DIR) + 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 diff --git a/cmake/QtWrapperScriptHelpers.cmake b/cmake/QtWrapperScriptHelpers.cmake index e583a413dd5..62d9290ffe4 100644 --- a/cmake/QtWrapperScriptHelpers.cmake +++ b/cmake/QtWrapperScriptHelpers.cmake @@ -224,11 +224,12 @@ function(qt_internal_create_wrapper_scripts) 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_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) @@ -238,17 +239,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. - set(script_passed_args "-DQT_BUILD_STANDALONE_TESTS=ON -DQT_USE_ORIGINAL_COMPILER=ON") + if(component STREQUAL "STANDALONE_TESTS") + set(script_name "qt-internal-configure-tests") + set(script_passed_args "-DQT_BUILD_STANDALONE_TESTS=ON -DQT_BUILD_EXAMPLES=OFF") + elseif(component STREQUAL "STANDALONE_EXAMPLES") + set(script_name "qt-internal-configure-examples") + set(script_passed_args "-DQT_BUILD_STANDALONE_EXAMPLES=ON -DQT_BUILD_TESTS=OFF") + else() + message(FATAL_ERROR "Invalid component type: ${component}") + endif() + + string(APPEND script_passed_args " -DQT_USE_ORIGINAL_COMPILER=ON") file(RELATIVE_PATH relative_path_from_libexec_dir_to_bin_dir ${__qt_libexec_dir_absolute} diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index fe9ce29ee00..d1b6b67aa0a 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -1,6 +1,17 @@ # Copyright (C) 2022 The Qt Company Ltd. # SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause +if(QT_BUILD_STANDALONE_EXAMPLES) + # Needed for early feature values, despite it being found later on in qt_build_tests(). + # Needs to be find_package, not qt_find_package, because qt_find_package doesn't handle finding + # component for a super-package that has already been found. + find_package(Qt6 ${PROJECT_VERSION} CONFIG REQUIRED COMPONENTS Core) + + # Modify the optimization flags specifically for qtbase standalone examples. Other projects + # are handled by qt_enable_cmake_languages(). + qt_internal_set_up_config_optimizations_like_in_qmake() +endif() + qt_examples_build_begin(EXTERNAL_BUILD) add_compile_definitions(QT_NO_CONTEXTLESS_CONNECT) diff --git a/libexec/qt-internal-configure-examples.bat.in b/libexec/qt-internal-configure-examples.bat.in new file mode 100644 index 00000000000..6b69910c669 --- /dev/null +++ b/libexec/qt-internal-configure-examples.bat.in @@ -0,0 +1,34 @@ +@echo off +setlocal ENABLEDELAYEDEXPANSION ENABLEEXTENSIONS +set script_dir_path=%~dp0 +set script_dir_path=%script_dir_path:~0,-1% + +rem Extracts the source path, make it native, and put it +rem back again. This is a workaround on Windows LLVM/MINGW +rem to help CMake find source files when doing Unity Build. +set args=%* +set source_dir_path= +set native_source_dir_path= +for %%i in (%args%) do ( + if "%%i"=="-S" ( + set found=true + ) else if defined found ( + set source_dir_path=%%i + set native_source_dir_path=%%~dpnxi + set found= + ) +) + +if NOT "%native_source_dir_path%" == "" ( + set args=!args:%source_dir_path%=%native_source_dir_path%! +) + +set cmake_scripts_dir=%script_dir_path% + +set relative_bin_dir=@relative_path_from_libexec_dir_to_bin_dir@ +if NOT "%relative_bin_dir%" == "" ( +set relative_bin_dir="%relative_bin_dir%"\ +) + +call "%script_dir_path%"\%relative_bin_dir%"qt-cmake.bat" ^ + @script_passed_args@ %args% diff --git a/libexec/qt-internal-configure-examples.in b/libexec/qt-internal-configure-examples.in new file mode 100755 index 00000000000..d0bf333ee6e --- /dev/null +++ b/libexec/qt-internal-configure-examples.in @@ -0,0 +1,5 @@ +#!/bin/sh +script_dir_path=`dirname $0` +script_dir_path=`(cd "$script_dir_path"; /bin/pwd)` + +"$script_dir_path/@relative_path_from_libexec_dir_to_bin_dir@/qt-cmake" @script_passed_args@ "$@"