Skip to content

Commit

Permalink
CMake: Allow building all examples as standalone just like tests
Browse files Browse the repository at this point in the history
Introduce a new libexec/qt-internal-configure-examples script that
allows to configure and build "standalone examples" just like
"standalone tests".

This is a prerequisite for using deployment api in examples for prefix
builds, otherwise deployment api gets confused not finding various
information that it expects from an installed qt.

Because the various conditions in the build system for standalone
examples are similar to standalone tests, introduce a new
QT_BUILD_STANDALONE_PARTS variable and use that in the conditions.
The variable should not be set by the user, and is instead set by the
build system whenever QT_BUILD_STANDALONE_TESTS/EXAMPLES is set.

Unfortunately due to no common file being available before the first
project() call, in qtbase builds, per-repo builds and top-level builds,
we need to duplicate the code for setting QT_BUILD_STANDALONE_PARTS for
all three cases.

Task-number: QTBUG-90820
Task-number: QTBUG-96232
Change-Id: Ia40d03a0e8f5142abe5c7cd4ff3000df4a5f7a8a
Reviewed-by:  Alexey Edelev <[email protected]>
Reviewed-by: Qt CI Bot <[email protected]>
  • Loading branch information
alcroito committed Mar 14, 2024
1 parent d298a05 commit 6290516
Show file tree
Hide file tree
Showing 15 changed files with 271 additions and 96 deletions.
28 changes: 22 additions & 6 deletions cmake/QtBaseHelpers.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -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})
Expand Down Expand Up @@ -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()
Expand Down Expand Up @@ -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})

Expand Down Expand Up @@ -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()
Expand Down
25 changes: 20 additions & 5 deletions cmake/QtBaseTopLevelHelpers.cmake
Original file line number Diff line number Diff line change
@@ -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}'")
Expand All @@ -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}'")
Expand All @@ -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()
Expand All @@ -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)
Expand All @@ -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()
Expand Down
3 changes: 1 addition & 2 deletions cmake/QtBuildInformation.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand All @@ -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()
15 changes: 13 additions & 2 deletions cmake/QtBuildOptionsHelpers.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -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}")

Expand Down Expand Up @@ -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
Expand Down
5 changes: 3 additions & 2 deletions cmake/QtBuildPathsHelpers.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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,
Expand Down
12 changes: 12 additions & 0 deletions cmake/QtBuildRepoExamplesHelpers.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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()
Expand Down
Loading

0 comments on commit 6290516

Please sign in to comment.