Backstory. The main reason why we keep getting "unable to promote 3rd party 'X' target to global scope" errors when building Qt repositories, is because we try to promote 3rd party imported targets in a different scope than where the imported targets were created. What were the main motivations for promoting 3rd party targets to global? 1) imported targets are by default local to the directory scope they were created in 2) we want 3rd party targets to be accessible across subdirectory scopes, but looked up once, e.g. qt_find_package(JPEG) looked up in src/gui/CMakeLists.txt, but the target should also be usable in the sibling scope src/plugins/imageformats/CMakeLists.txt Having the package lookup close to the consuming qt module is easier to maintain, because all the other 3rd party dependency lookups are in the same file. This goes against the conventional CMake advice where each subdirectory should look for its own dependencies, or the dependency should be available directly in the root project scope. 3) to make the 3rd party targets available in the root project scope as part of the following flow: QtPostProcess.cmake -> qt_internal_create_module_depends_file() -> qt_collect_third_party_deps() -> get_property(INTERFACE_QT_PACKAGE_NAME) -> write 3rd party Dependencies.cmake file for each qt module. Properties can only be queried from an imported target if it's in the same scope or was promoted to global, otherwise you get 'non-existent target' errors. 4) for prl and pri file generation, where we need the targets to be available during generator expression evaluation within the relevant qt module directory scope Here is a list of approaches I came up with on how to improve the situation. 1) Make all imported targets global during the Qt build, by iterating over the directory property IMPORTED_TARGETS and making each one global. Requires CMake 3.21. Status: Already implemented for a long time, but is opt-in. Pros: Relatively robust Cons: Minimum CMake version for building Qt is 3.16. 2) Make all imported targets global during the Qt build using the CMAKE_FIND_PACKAGE_TARGETS_GLOBAL variable. Requires CMake 3.24. Status: Not implemented, but can be set by Qt builders directly on the command line. Pros: Should be robust Cons: Minimum CMake version for building Qt is 3.16. 3) Abandon the desire to have a single qt_find_package in a single directory scope, and embrace the CMake-way of repeating the dependency in each subdirectory that requires it. Status: Not implemented. Pros: Should be robust Cons: A lot of qt_find_package duplication, will require rewriting various code paths, QtPostProcess would have to be done at directory scope, unclear if dependency tracking will still work work reliably when there might be multiple same-named directory-scoped targets, other unknown unknowns 4) Move all qt_find_package calls into a $repo_name/dependencies.cmake file which would be read at project root scope. This would potentially avoid all scoping issues, because all dependencies will have to be specified at root scope. Status: Not implemented. Pros: No duplication Cons: Dependencies are not scoped anymore to module directories, won't be able to conditionally look for dependencies based on module feature evaluation, not clear yet how this will tie into standalone tests which are in tests/ subdir, other unknown unknowns 5) Try to promote as many 3rd party libraries at project root scope as possible. Currently we have 2 general locations where we look up dependencies. One is each qt_find_package call. The other is Qt6FooDependencies.cmake -> _qt_internal_find_third_party_dependencies(). Many 3rd party targets are created by _qt_internal_find_third_party_dependencies() in the root scope, but not promoted, and then we try to promote them in child scopes using qt_find_package, which causes the promotion errors. Starting with 58eefbd0b6169d0749b312268c1ae1e594e04362 and 37a5e001277db9e1392a242171ab2b88cb6c3049 we now record the provided targets of previous qt_find_package calls. So instead of waiting to try and promote targets later during the configuration process, we can make sure we promote the targets at _qt_internal_find_third_party_dependencies() call time, right when we lookup the Qt dependencies of the qt repo, in the root scope. Status: Implemented in this change Notably, we only promote 3rd party targets to global for qt builds, and not user projects, to not accidentally break user project behaviors. Also, we only promote 3rd party targets, and not Qt internal targets like Qt6::Core, Qt6::Platform, Qt6::PlatformCommonInternal, Qt6::GlobalConfig, etc, for a few reasons: - the code that requires targets to be global only cares about 3rd party targets - promoting the internal targets is more prone to breaking, because there is more than one place where find_package(Qt6Foo) might be called, and if that ends up being in a different directory scope, we encounter the same global promotion errors. Some notable cases where this happens: - tests/CMakeLists.txt brings in extra Qt packages via StandaloneTestsConfig.cmake files - qtbase standalone tests qt_internal_qtbase_pre_project_setup() calls find_package(Qt6 COMPONENTS BuildInternals) which ends up creating the Platform target in the root scope instead of the tests/ scope - Qt6::BundledLibpng links against Core, which ends up trying to promote Core's internal dependencies Platform and GlobalConfig To only promote 3rd party targets, we walk the dependencies of an initial target recursively, and skip promoting targets that have the _qt_is_internal_target or _qt_should_skip_global_promotion_always properties set. Pros: Improves the situation compared to the status quo Cons: Still not ideal due to the various filtering of internal targets and having to mark them as such. 6) Avoid promoting targets to global if we can detect that the target was created in a different scope than where we are trying to promote it. We can do that by comparing the target's BINARY_DIR to the CMAKE_CURRENT_BINARY_DIR and skip promotion if they are not equal. Status: Not implemented, but we can consider it because it's quick to do. Pros: More robust than newly implemented approach (5) Cons: Requires CMake 3.18, because trying to read the BINARY_DIR property on an INTERFACE_LIBRARY would error out. Also, if we implement it and make it the default when using 3.18+, we might 'collect' a lot more hidden promotion errors that will only be revealed later once someone uses CMake 3.16 or 3.17, because most will probably use newer CMake versions. Perhaps the trade-off is worth it? Fixes: QTBUG-89204 Fixes: QTBUG-94356 Fixes: QTBUG-95052 Fixes: QTBUG-98807 Fixes: QTBUG-125371 Change-Id: I088a17a98ef35aa69537a3ad208c61de40def581 Reviewed-by: Joerg Bornemann <joerg.bornemann@qt.io> Reviewed-by: Alexey Edelev <alexey.edelev@qt.io> (cherry picked from commit d2e85cede01c0898ca73cbc3fb9f53aa9612cab5) Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
1088 lines
45 KiB
CMake
1088 lines
45 KiB
CMake
# 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()
|
|
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)
|
|
set_property(GLOBAL PROPERTY _qt_repo_deps_${project_name_lower} ${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()
|
|
|
|
_qt_internal_sbom_begin_project(
|
|
INSTALL_PREFIX "${QT_STAGING_PREFIX}"
|
|
INSTALL_SBOM_DIR "${INSTALL_SBOMDIR}"
|
|
QT_CPE
|
|
)
|
|
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()
|
|
|
|
_qt_internal_sbom_end_project()
|
|
|
|
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()
|