if (CMAKE_VERSION VERSION_LESS 3.1.0) message(FATAL_ERROR "Qt requires at least CMake version 3.1.0") endif() ###################################### # # Macros for building Qt modules # ###################################### set(QT_BACKUP_CMAKE_INSTALL_PREFIX_BEFORE_EXTRA_INCLUDE "${CMAKE_INSTALL_PREFIX}") if(EXISTS "${CMAKE_CURRENT_LIST_DIR}/QtBuildInternalsExtra.cmake") include(${CMAKE_CURRENT_LIST_DIR}/QtBuildInternalsExtra.cmake) endif() macro(qt_set_up_build_internals_paths) # Set up the paths for the cmake modules located in the prefix dir. Prepend, so the paths are # least important compared to the source dir ones, but more important than command line # provided ones. set(QT_CMAKE_MODULE_PATH "${QT_BUILD_INTERNALS_PATH}/../${QT_CMAKE_EXPORT_NAMESPACE}") list(PREPEND CMAKE_MODULE_PATH "${QT_CMAKE_MODULE_PATH}") # Prepend the qtbase source cmake directory to CMAKE_MODULE_PATH, # so that if a change is done in cmake/QtBuild.cmake, it gets automatically picked up when # building qtdeclarative, rather than having to build qtbase first (which will copy # QtBuild.cmake to the build dir). This is similar to qmake non-prefix builds, where the # source qtbase/mkspecs directory is used. if(EXISTS "${QT_SOURCE_TREE}/cmake") list(PREPEND CMAKE_MODULE_PATH "${QT_SOURCE_TREE}/cmake") endif() # If the repo has its own cmake modules, include those in the module path. if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/cmake") list(PREPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") endif() # Find the cmake files when doing a standalone tests build. if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/../cmake") list(PREPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/../cmake") endif() endmacro() # Set up the build internal paths unless explicitly requested not to. if(NOT QT_BUILD_INTERNALS_SKIP_CMAKE_MODULE_PATH_ADDITION) qt_set_up_build_internals_paths() endif() # Define some constants to check for certain platforms, etc. # Needs to be loaded before qt_repo_build() to handle require() clauses before even starting a repo # build. include(QtPlatformSupport) macro(qt_build_internals_set_up_private_api) # Qt specific setup common for all modules: include(QtSetup) include(FeatureSummary) # Optionally include a repo specific Setup module. include(${PROJECT_NAME}Setup OPTIONAL) include(QtRepoSetup OPTIONAL) # Find Apple frameworks if needed. qt_find_apple_system_frameworks() # Decide whether tools will be built. qt_check_if_tools_will_be_built() endmacro() macro(qt_enable_cmake_languages) include(CheckLanguage) set(__qt_required_language_list C CXX) set(__qt_optional_language_list ) # https://gitlab.kitware.com/cmake/cmake/-/issues/20545 if(APPLE) list(APPEND __qt_optional_language_list OBJC OBJCXX) endif() foreach(__qt_lang ${__qt_required_language_list}) enable_language(${__qt_lang}) endforeach() foreach(__qt_lang ${__qt_optional_language_list}) check_language(${__qt_lang}) if(CMAKE_${__qt_lang}_COMPILER) enable_language(${__qt_lang}) endif() endforeach() 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() macro(qt_build_repo_begin) qt_build_internals_set_up_private_api() qt_enable_cmake_languages() # 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_docs) add_custom_target(install_qch_docs_docs) add_custom_target(install_docs_docs) endif() string(TOLOWER ${PROJECT_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_install_html_target_name} ${qt_docs_html_target_name}) add_dependencies(${qt_docs_install_qch_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 global doc targets depend on the module ones. add_dependencies(docs ${qt_docs_target_name}) add_dependencies(prepare_docs ${qt_docs_prepare_target_name}) add_dependencies(generate_docs ${qt_docs_generate_target_name}) add_dependencies(html_docs ${qt_docs_html_target_name}) add_dependencies(qch_docs ${qt_docs_qch_target_name}) add_dependencies(install_html_docs_docs ${qt_docs_install_html_target_name}) add_dependencies(install_qch_docs_docs ${qt_docs_install_qch_target_name}) add_dependencies(install_docs_docs ${qt_docs_install_target_name}) endmacro() macro(qt_build_repo_end) if(NOT QT_BUILD_STANDALONE_TESTS) # Delayed actions on some of the Qt targets: include(QtPostProcess) # Install the repo-specific cmake find modules. qt_path_join(__qt_repo_install_dir ${QT_CONFIG_INSTALL_DIR} ${INSTALL_CMAKE_NAMESPACE}) if(NOT PROJECT_NAME STREQUAL "QtBase") if (EXISTS cmake) qt_copy_or_install(DIRECTORY cmake/ DESTINATION "${__qt_repo_install_dir}" FILES_MATCHING PATTERN "Find*.cmake" ) endif() endif() if(NOT QT_SUPERBUILD) qt_print_feature_summary() endif() endif() if(NOT QT_SUPERBUILD) qt_print_build_instructions() endif() endmacro() macro(qt_build_repo) qt_build_repo_begin(${ARGN}) # 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 (BUILD_TESTING AND NOT QT_BUILD_STANDALONE_TESTS) find_package(Qt6 ${PROJECT_VERSION} CONFIG REQUIRED COMPONENTS Test) endif() if(NOT QT_BUILD_STANDALONE_TESTS) if (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/src/CMakeLists.txt") add_subdirectory(src) endif() if (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/tools/CMakeLists.txt") add_subdirectory(tools) endif() endif() if (BUILD_TESTING AND EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/tests/CMakeLists.txt") add_subdirectory(tests) if(QT_NO_MAKE_TESTS) set_property(DIRECTORY tests PROPERTY EXCLUDE_FROM_ALL TRUE) endif() endif() qt_build_repo_end() if (BUILD_EXAMPLES AND BUILD_SHARED_LIBS AND EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/examples/CMakeLists.txt" AND NOT QT_BUILD_STANDALONE_TESTS) add_subdirectory(examples) if(QT_NO_MAKE_EXAMPLES) set_property(DIRECTORY examples PROPERTY EXCLUDE_FROM_ALL TRUE) 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_tests_confg_files_path out_var) set(path "${QT_CONFIG_INSTALL_DIR}/${INSTALL_CMAKE_NAMESPACE}BuildInternals/StandaloneTests") # QT_CONFIG_INSTALL_DIR is relative in prefix builds. if(QT_WILL_INSTALL) qt_path_join(path "${CMAKE_INSTALL_PREFIX}" "${path}") endif() set("${out_var}" "${path}" PARENT_SCOPE) endfunction() macro(qt_build_tests) if(QT_BUILD_STANDALONE_TESTS) # Find location of TestsConfig.cmake. These contain the modules that need to be # find_package'd when testing. qt_get_standalone_tests_confg_files_path(_qt_build_tests_install_prefix) include("${_qt_build_tests_install_prefix}/${PROJECT_NAME}TestsConfig.cmake" OPTIONAL) # Of course we always need the test module as well. find_package(Qt6 ${PROJECT_VERSION} CONFIG REQUIRED COMPONENTS Test) # Set language standards after finding Core, because that's when the relevant # feature variables are available, and the call in QtSetup is too early when building # standalone tests, because Core was not find_package()'d yet. qt_set_language_standards() if(NOT QT_SUPERBUILD) # Set up fake standalone tests install prefix, so we don't pollute the Qt install # prefix. For super builds it needs to be done in qt5/CMakeLists.txt. qt_set_up_fake_standalone_tests_install_prefix() endif() endif() if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/auto/CMakeLists.txt") add_subdirectory(auto) 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") # add_subdirectory(manual) don't build manual tests for now, because qmake doesn't. endif() endmacro() function(qt_compute_relative_path_from_cmake_config_dir_to_prefix) # Compute the reverse relative path from the CMake config dir to the install prefix. # This is used in QtBuildInternalsExtras to create a relocatable relative install prefix path. # This path is used for finding syncqt and other things, regardless of initial install prefix # (e.g installed Qt was archived and unpacked to a different path on a different machine). # # This is meant to be called only once when configuring qtbase. # # Similar code exists in Qt6CoreConfigExtras.cmake.in and src/corelib/CMakeLists.txt which # might not be needed anymore. if(QT_WILL_INSTALL) get_filename_component(clean_config_prefix "${CMAKE_INSTALL_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}" "${CMAKE_INSTALL_PREFIX}") set(qt_path_from_cmake_config_dir_to_prefix "${qt_path_from_cmake_config_dir_to_prefix}" PARENT_SCOPE) endfunction() function(qt_get_relocatable_install_prefix out_var) # We need to compute it only once while building qtbase. Afterwards it's loaded from # QtBuildInternalsExtras.cmake. if(QT_BUILD_INTERNALS_RELOCATABLE_INSTALL_PREFIX) return() endif() # The QtBuildInternalsExtras value is dynamically computed, whereas the initial qtbase # configuration uses an absolute path. set(${out_var} "${CMAKE_INSTALL_PREFIX}" PARENT_SCOPE) endfunction() function(qt_set_up_fake_standalone_tests_install_prefix) # Set a fake local (non-cache) CMAKE_INSTALL_PREFIX. # Needed for standalone tests, we don't want to accidentally install a test into the Qt prefix. # Allow opt-out, if a user knows what they're doing. if(QT_NO_FAKE_STANDALONE_TESTS_INSTALL_PREFIX) return() endif() set(new_install_prefix "${CMAKE_BINARY_DIR}/fake_prefix") # It's IMPORTANT that this is not a cache variable. Otherwise # qt_get_standalone_tests_confg_files_path() will not work on re-configuration. message(STATUS "Setting local standalone test install prefix (non-cached) to '${new_install_prefix}'.") set(CMAKE_INSTALL_PREFIX "${new_install_prefix}" PARENT_SCOPE) endfunction() macro(qt_examples_build_begin) # Examples that are built as part of the Qt build need to use the CMake config files from the # build dir, because they are not installed yet in a prefix build. # Appending to CMAKE_PREFIX_PATH helps find the initial Qt6Config.cmake. # Appending to QT_EXAMPLES_CMAKE_PREFIX_PATH helps find components of Qt6, because those # find_package calls use NO_DEFAULT_PATH, and thus CMAKE_PREFIX_PATH is ignored. list(APPEND CMAKE_PREFIX_PATH "${QT_BUILD_DIR}") list(APPEND QT_EXAMPLES_CMAKE_PREFIX_PATH "${QT_BUILD_DIR}") # Also make sure the CMake config files do not recreate the already-existing targets set(QT_NO_CREATE_TARGETS TRUE) set(BACKUP_CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ${CMAKE_FIND_ROOT_PATH_MODE_PACKAGE}) set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE "BOTH") # Because CMAKE_INSTALL_RPATH is empty by default in the repo project, examples need to have # it set here, so they can run when installed. # This means that installed examples are not relocatable at the moment. We would need to # annotate where each example is installed to, to be able to derive a relative rpath, and it # seems there's no way to query such information from CMake itself. set(CMAKE_INSTALL_RPATH "${_default_install_rpath}") set(QT_DISABLE_QT_ADD_PLUGIN_COMPATIBILITY TRUE) endmacro() macro(qt_examples_build_end) # We use AUTOMOC/UIC/RCC in the examples. Make sure to not fail on a fresh Qt build, that e.g. the moc binary does not exist yet. # This function gets all targets below this directory function(get_all_targets _result _dir) get_property(_subdirs DIRECTORY "${_dir}" PROPERTY SUBDIRECTORIES) foreach(_subdir IN LISTS _subdirs) get_all_targets(${_result} "${_subdir}") endforeach() get_property(_sub_targets DIRECTORY "${_dir}" PROPERTY BUILDSYSTEM_TARGETS) set(${_result} ${${_result}} ${_sub_targets} PARENT_SCOPE) endfunction() get_all_targets(targets "${CMAKE_CURRENT_SOURCE_DIR}") foreach(target ${targets}) qt_autogen_tools(${target} ENABLE_AUTOGEN_TOOLS "moc" "rcc") if(TARGET Qt::Widgets) qt_autogen_tools(${target} ENABLE_AUTOGEN_TOOLS "uic") endif() endforeach() set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ${BACKUP_CMAKE_FIND_ROOT_PATH_MODE_PACKAGE}) endmacro() if (ANDROID) include(${CMAKE_CURRENT_LIST_DIR}/QtBuildInternalsAndroid.cmake) endif()