diff options
Diffstat (limited to 'cmake/QtBuild.cmake')
-rw-r--r-- | cmake/QtBuild.cmake | 4165 |
1 files changed, 4165 insertions, 0 deletions
diff --git a/cmake/QtBuild.cmake b/cmake/QtBuild.cmake new file mode 100644 index 0000000000..90306a44c8 --- /dev/null +++ b/cmake/QtBuild.cmake @@ -0,0 +1,4165 @@ +include(CMakePackageConfigHelpers) + +# Install locations: +set(INSTALL_BINDIR "bin" CACHE STRING "Executables [PREFIX/bin]") +set(INSTALL_INCLUDEDIR "include" CACHE STRING "Header files [PREFIX/include]") +set(INSTALL_LIBDIR "lib" CACHE STRING "Libraries [PREFIX/lib]") +set(INSTALL_MKSPECSDIR "mkspecs" CACHE STRING "Mkspecs files [PREFIX/mkspecs]") +set(INSTALL_ARCHDATADIR "." CACHE STRING "Arch-dependent data [PREFIX]") +set(INSTALL_PLUGINSDIR "${INSTALL_ARCHDATADIR}/plugins" CACHE STRING + "Plugins [ARCHDATADIR/plugins]") + +set(INSTALL_TARGETS_DEFAULT_ARGS + RUNTIME DESTINATION "${INSTALL_BINDIR}" + LIBRARY DESTINATION "${INSTALL_LIBDIR}" + ARCHIVE DESTINATION "${INSTALL_LIBDIR}" COMPONENT Devel + INCLUDES DESTINATION "${INSTALL_INCLUDEDIR}" +) + +if (WIN32) + set(_default_libexec "${INSTALL_ARCHDATADIR}/bin") +else() + set(_default_libexec "${INSTALL_ARCHDATADIR}/libexec") +endif() + +set(INSTALL_LIBEXECDIR "${_default_libexec}" CACHE STRING + "Helper programs [ARCHDATADIR/bin on Windows, ARCHDATADIR/libexec otherwise]") +set(INSTALL_QMLDIR "${INSTALL_ARCHDATADIR}/qml" CACHE STRING + "QML2 imports [ARCHDATADIR/qml]") +set(INSTALL_DATADIR "." CACHE STRING "Arch-independent data [PREFIX]") +set(INSTALL_DOCDIR "${INSTALL_DATADIR}/doc" CACHE STRING "Documentation [DATADIR/doc]") +set(INSTALL_TRANSLATIONSDIR "${INSTALL_DATADIR}/translations" CACHE STRING + "Translations [DATADIR/translations]") +set(INSTALL_SYSCONFDIR "etc/xdg" CACHE STRING + "Settings used by Qt programs [PREFIX/etc/xdg]") +set(INSTALL_EXAMPLESDIR "examples" CACHE STRING "Examples [PREFIX/examples]") +set(INSTALL_TESTSDIR "tests" CACHE STRING "Tests [PREFIX/tests]") +set(INSTALL_DESCRIPTIONSDIR "${INSTALL_DATADIR}/modules" CACHE STRING + "Module description files directory") + +# The variables might have already been set in QtBuildInternalsExtra.cmake if the file is included +# while building a new module and not QtBase. In that case, stop overriding the value. +if(NOT INSTALL_CMAKE_NAMESPACE) + set(INSTALL_CMAKE_NAMESPACE "Qt${PROJECT_VERSION_MAJOR}" + CACHE STRING "CMake namespace [Qt${PROJECT_VERSION_MAJOR}]") +endif() +if(NOT QT_CMAKE_EXPORT_NAMESPACE) + set(QT_CMAKE_EXPORT_NAMESPACE "Qt${PROJECT_VERSION_MAJOR}" + CACHE STRING "CMake namespace used when exporting targets [Qt${PROJECT_VERSION_MAJOR}]") +endif() + +set(QT_CMAKE_DIR "${CMAKE_CURRENT_LIST_DIR}") + +# Find the path to mkspecs/, depending on whether we are building as part of a standard qtbuild, +# or a module against an already installed version of qt. +if(NOT QT_MKSPECS_DIR) + if("${QT_BUILD_INTERNALS_PATH}" STREQUAL "") + get_filename_component(QT_MKSPECS_DIR "${CMAKE_CURRENT_LIST_DIR}/../mkspecs" ABSOLUTE) + else() + # We can rely on CMAKE_INSTALL_PREFIX being set by QtBuildInternalsExtra.cmake + get_filename_component(QT_MKSPECS_DIR "${CMAKE_INSTALL_PREFIX}/${INSTALL_MKSPECSDIR}" ABSOLUTE) + endif() + set(QT_MKSPECS_DIR "${QT_MKSPECS_DIR}" CACHE INTERNAL "") +endif() + +# the default RPATH to be used when installing, but only if it's not a system directory +LIST(FIND CMAKE_PLATFORM_IMPLICIT_LINK_DIRECTORIES "${CMAKE_INSTALL_PREFIX}/${INSTALL_LIBDIR}" isSystemDir) +IF("${isSystemDir}" STREQUAL "-1") + SET(_default_install_rpath "${CMAKE_INSTALL_PREFIX}/${INSTALL_LIBDIR}") +ENDIF("${isSystemDir}" STREQUAL "-1") + +# Default rpath settings: Use rpath for build tree as well as a full path for the installed binaries. +# For origin builds, one needs to override CMAKE_INSTALL_RPATH for example with $ORIGIN/../lib +SET(CMAKE_INSTALL_RPATH "${_default_install_rpath}" CACHE PATH "RPATH for installed binaries") + +# add the automatically determined parts of the RPATH +# which point to directories outside the build tree to the install RPATH +SET(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE) + +# Generate a module description file based on the template in ModuleDescription.json.in +function(qt_describe_module target) + set(path_suffix "${INSTALL_DESCRIPTIONSDIR}") + qt_path_join(build_dir ${QT_BUILD_DIR} ${path_suffix}) + qt_path_join(install_dir ${QT_INSTALL_DIR} ${path_suffix}) + + set(descfile_in "${QT_CMAKE_DIR}/ModuleDescription.json.in") + set(descfile_out "${build_dir}/${target}.json") + set(cross_compilation "false") + if(CMAKE_CROSSCOMPILE) + set(cross_compilation "true") + endif() + configure_file("${descfile_in}" "${descfile_out}") + + qt_install(FILES "${descfile_out}" DESTINATION "${install_dir}") +endfunction() + +function(qt_setup_tool_path_command) + if(NOT WIN32) + return() + endif() + set(bindir "${CMAKE_INSTALL_PREFIX}/${INSTALL_BINDIR}") + file(TO_NATIVE_PATH "${bindir}" bindir) + list(APPEND command COMMAND) + list(APPEND command set PATH=${bindir}$<SEMICOLON>%PATH%) + set(QT_TOOL_PATH_SETUP_COMMAND "${command}" CACHE INTERNAL "internal command prefix for tool invocations" FORCE) +endfunction() +qt_setup_tool_path_command() + +# Platform define path, etc. +set(QT_QMAKE_TARGET_MKSPEC "") +if(WIN32) + set(QT_DEFAULT_PLATFORM_DEFINITIONS UNICODE _UNICODE WIN32 _ENABLE_EXTENDED_ALIGNED_STORAGE) + if(CMAKE_SIZEOF_VOID_P EQUAL 8) + list(APPEND QT_DEFAULT_PLATFORM_DEFINITIONS WIN64 _WIN64) + endif() + if(MSVC) + set(QT_QMAKE_TARGET_MKSPEC win32-msvc) + elseif(CLANG AND MINGW) + set(QT_QMAKE_TARGET_MKSPEC win32-clang-g++) + elseif(MINGW) + set(QT_QMAKE_TARGET_MKSPEC win32-g++) + endif() + + if (MINGW) + list(APPEND QT_DEFAULT_PLATFORM_DEFINITIONS _WIN32_WINNT=0x0601) + endif() +elseif(LINUX) + if(GCC) + set(QT_QMAKE_TARGET_MKSPEC linux-g++) + elseif(CLANG) + set(QT_QMAKE_TARGET_MKSPEC linux-clang) + elseif(ICC) + set(QT_QMAKE_TARGET_MKSPEC linux-icc-64) + endif() +elseif(ANDROID) + if(GCC) + set(QT_QMAKE_TARGET_MKSPEC android-g++) + elseif(CLANG) + set(QT_QMAKE_TARGET_MKSPEC android-clang) + endif() +elseif(APPLE) + set(QT_QMAKE_TARGET_MKSPEC macx-clang) +elseif(EMSCRIPTEN) + set(QT_QMAKE_TARGET_MKSPEC wasm-emscripten) +endif() + +# TODO: Fixme to be correct. +set(QT_QMAKE_HOST_MKSPEC "${QT_QMAKE_TARGET_MKSPEC}") + +# Platform definition dir provided by user on command line. +# Derive the absolute one relative to the current source dir. +if(QT_PLATFORM_DEFINITION_DIR) + set(QT_DEFAULT_PLATFORM_DEFINITION_DIR "${QT_PLATFORM_DEFINITION_DIR}") + get_filename_component( + QT_DEFAULT_PLATFORM_DEFINITION_DIR_ABSOLUTE + "${QT_PLATFORM_DEFINITION_DIR}" + ABSOLUTE) +elseif(QT_QMAKE_TARGET_MKSPEC) + # Used by consumers of prefix builds via INSTALL_INTERFACE (relative path). + set(QT_DEFAULT_PLATFORM_DEFINITION_DIR "${INSTALL_MKSPECSDIR}/${QT_QMAKE_TARGET_MKSPEC}") + # Used by qtbase itself and consumers of non-prefix builds via BUILD_INTERFACE (absolute path). + set(QT_DEFAULT_PLATFORM_DEFINITION_DIR_ABSOLUTE "${QT_MKSPECS_DIR}/${QT_QMAKE_TARGET_MKSPEC}") +endif() + +if(NOT DEFINED QT_DEFAULT_PLATFORM_DEFINITIONS) + set(QT_DEFAULT_PLATFORM_DEFINITIONS "") +endif() + +set(QT_PLATFORM_DEFINITIONS ${QT_DEFAULT_PLATFORM_DEFINITIONS} + CACHE STRING "Qt platform specific pre-processor defines") +set(QT_PLATFORM_DEFINITION_DIR "${QT_DEFAULT_PLATFORM_DEFINITION_DIR}" + CACHE PATH "Path to directory that contains qplatformdefs.h") +set(QT_PLATFORM_DEFINITION_DIR_ABSOLUTE "${QT_DEFAULT_PLATFORM_DEFINITION_DIR_ABSOLUTE}" + CACHE INTERNAL "Path to directory that contains qplatformdefs.h") +set(QT_NAMESPACE "" CACHE STRING "Qt Namespace") +if(QT_NAMESPACE STREQUAL "") + set(QT_HAS_NAMESPACE OFF) +else() + set(QT_HAS_NAMESPACE ON) +endif() + + +function(qt_internal_clear_qt_repo_known_modules) + set(QT_REPO_KNOWN_MODULES "" CACHE INTERNAL "Known current repo Qt modules" FORCE) +endfunction() + +function(qt_internal_add_qt_repo_known_module) + set(QT_REPO_KNOWN_MODULES ${QT_REPO_KNOWN_MODULES} ${ARGN} + CACHE INTERNAL "Known current repo Qt modules" FORCE) +endfunction() + +function(qt_internal_get_qt_repo_known_modules out_var) + set("${out_var}" "${QT_REPO_KNOWN_MODULES}" PARENT_SCOPE) +endfunction() + +# Gets the list of all known Qt modules both found and that were built as part of the +# current project. +function(qt_internal_get_qt_all_known_modules out_var) + qt_internal_get_qt_repo_known_modules(repo_known_modules) + set(known_modules ${QT_ALL_MODULES_FOUND_VIA_FIND_PACKAGE} ${repo_known_modules}) + list(REMOVE_DUPLICATES known_modules) + set("${out_var}" "${known_modules}" PARENT_SCOPE) +endfunction() + +macro(qt_internal_set_qt_known_plugins) + set(QT_KNOWN_PLUGINS ${ARGN} CACHE INTERNAL "Known Qt plugins" FORCE) +endmacro() + +### Global plug-in types handling ### +# QT_REPO_KNOWN_PLUGIN_TYPES and QT_ALL_PLUGIN_TYPES_FOUND_VIA_FIND_PACKAGE +# hold a list of plug-in types (e.G. "imageformats;bearer") +function(qt_internal_clear_qt_repo_known_plugin_types) + set(QT_REPO_KNOWN_PLUGIN_TYPES "" CACHE INTERNAL "Known current repo Qt plug-in types" FORCE) +endfunction() + +function(qt_internal_add_qt_repo_known_plugin_types) + set(QT_REPO_KNOWN_PLUGIN_TYPES ${QT_REPO_KNOWN_PLUGIN_TYPES} ${ARGN} + CACHE INTERNAL "Known current repo Qt plug-in types" FORCE) +endfunction() + +function(qt_internal_get_qt_repo_known_plugin_types out_var) + set("${out_var}" "${QT_REPO_KNOWN_PLUGIN_TYPES}" PARENT_SCOPE) +endfunction() + +function(qt_internal_get_qt_all_known_plugin_types out_var) + qt_internal_get_qt_repo_known_plugin_types(repo_known_plugin_types) + set(known ${QT_ALL_PLUGIN_TYPES_FOUND_VIA_FIND_PACKAGE} ${repo_known_plugin_types}) + list(REMOVE_DUPLICATES known) + set("${out_var}" "${known}" PARENT_SCOPE) +endfunction() + +# Reset: +qt_internal_clear_qt_repo_known_modules() +qt_internal_clear_qt_repo_known_plugin_types() +qt_internal_set_qt_known_plugins("") + +set(QT_KNOWN_MODULES_WITH_TOOLS "" CACHE INTERNAL "Known Qt modules with tools" FORCE) +macro(qt_internal_append_known_modules_with_tools module) + if(NOT ${module} IN_LIST QT_KNOWN_MODULES_WITH_TOOLS) + set(QT_KNOWN_MODULES_WITH_TOOLS "${QT_KNOWN_MODULES_WITH_TOOLS};${module}" + CACHE INTERNAL "Known Qt modules with tools" FORCE) + set(QT_KNOWN_MODULE_${module}_TOOLS "" + CACHE INTERNAL "Known Qt module ${module} tools" FORCE) + endif() +endmacro() + +macro(qt_internal_append_known_module_tool module tool) + if(NOT ${tool} IN_LIST QT_KNOWN_MODULE_${module}_TOOLS) + list(APPEND QT_KNOWN_MODULE_${module}_TOOLS "${tool}") + set(QT_KNOWN_MODULE_${module}_TOOLS "${QT_KNOWN_MODULE_${module}_TOOLS}" + CACHE INTERNAL "Known Qt module ${module} tools" FORCE) + endif() +endmacro() + +# Reset syncqt cache variable, to make sure it gets recomputed on reconfiguration, otherwise +# it might not get installed. +unset(QT_SYNCQT CACHE) + +# For adjusting variables when running tests, we need to know what +# the correct variable is for separating entries in PATH-alike +# variables. +if(CMAKE_HOST_SYSTEM_NAME STREQUAL "Windows") + set(QT_PATH_SEPARATOR "\\;") +else() + set(QT_PATH_SEPARATOR ":") +endif() + +# 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. +# +# These values should be prepended to file paths in commands or properties, +# in order to correctly place generated Config files, generated Targets files, +# excutables / libraries, when copying / installing files, etc. +# +# The build dir variables will always be absolute paths. +# The QT_INSTALL_DIR variable will have a relative path in a prefix build, +# which means that it can be empty, so use qt_join_path to prevent accidental absolute paths. +if(QT_SUPERBUILD) + # In this case, we always copy all the build products in qtbase/{bin,lib,...} + if(QT_WILL_INSTALL) + set(QT_BUILD_DIR "${QtBase_BINARY_DIR}") + set(QT_INSTALL_DIR "") + else() + set(QT_BUILD_DIR "${QtBase_BINARY_DIR}") + set(QT_INSTALL_DIR "${QtBase_BINARY_DIR}") + endif() +else() + if(QT_WILL_INSTALL) + # In the usual prefix build case, the build dir is the current module build dir, + # and the install dir is the prefix, so we don't set it. + set(QT_BUILD_DIR "${CMAKE_BINARY_DIR}") + set(QT_INSTALL_DIR "") + else() + # When doing a non-prefix build, both the build dir and install dir are the same, + # pointing to the qtbase build dir. + set(QT_BUILD_DIR "${CMAKE_INSTALL_PREFIX}") + set(QT_INSTALL_DIR "${QT_BUILD_DIR}") + endif() +endif() + +set(__config_path_part "${INSTALL_LIBDIR}/cmake") +set(QT_CONFIG_BUILD_DIR "${QT_BUILD_DIR}/${__config_path_part}") +set(QT_CONFIG_INSTALL_DIR "${QT_INSTALL_DIR}") +if(QT_CONFIG_INSTALL_DIR) + string(APPEND QT_CONFIG_INSTALL_DIR "/") +endif() +string(APPEND QT_CONFIG_INSTALL_DIR ${__config_path_part}) +unset(__config_path_part) + +# This is used to hold extra cmake code that should be put into QtBuildInternalsExtra.cmake file +# at the QtPostProcess stage. +set(QT_BUILD_INTERNALS_EXTRA_CMAKE_CODE "") + +# Save the value of the current first project source dir. +# This will be /path/to/qtbase for qtbase both in a super-build and a non super-build. +# This will be /path/to/qtbase/tests when building standalone tests. +set(QT_TOP_LEVEL_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}") + +# Prevent warnings about object files without any symbols. This is a common +# thing in Qt as we tend to build files unconditionally, and then use ifdefs +# to compile out parts that are not relevant. +if(CMAKE_HOST_APPLE AND APPLE) + foreach(lang ASM C CXX) + # We have to tell 'ar' to not run ranlib by itself, by passing the 'S' option + set(CMAKE_${lang}_ARCHIVE_CREATE "<CMAKE_AR> qcS <TARGET> <LINK_FLAGS> <OBJECTS>") + set(CMAKE_${lang}_ARCHIVE_APPEND "<CMAKE_AR> qS <TARGET> <LINK_FLAGS> <OBJECTS>") + set(CMAKE_${lang}_ARCHIVE_FINISH "<CMAKE_RANLIB> -no_warning_for_no_symbols <TARGET>") + endforeach() +endif() + +# Functions and macros: + +# qt_remove_args can remove arguments from an existing list of function +# arguments in order to pass a filtered list of arguments to a different function. +# Parameters: +# out_var: result of remove all arguments specified by ARGS_TO_REMOVE from ALL_ARGS +# ARGS_TO_REMOVE: Arguments to remove. +# ALL_ARGS: All arguments supplied to cmake_parse_arguments or +# qt_parse_all_arguments +# from which ARGS_TO_REMOVE should be removed from. We require all the +# arguments or we can't properly identify the range of the arguments detailed +# in ARGS_TO_REMOVE. +# ARGS: Arguments passed into the function, usually ${ARGV} +# +# E.g.: +# We want to forward all arguments from foo to bar, execpt ZZZ since it will +# trigger an error in bar. +# +# foo(target BAR .... ZZZ .... WWW ...) +# bar(target BAR.... WWW...) +# +# function(foo target) +# qt_parse_all_arguments(arg "" "" "BAR;ZZZ;WWW ${ARGV}) +# qt_remove_args(forward_args +# ARGS_TO_REMOVE ${target} ZZZ +# ALL_ARGS ${target} BAR ZZZ WWW +# ARGS ${ARGV} +# ) +# bar(${target} ${forward_args}) +# endfunction() +# +function(qt_remove_args out_var) + cmake_parse_arguments(arg "" "" "ARGS_TO_REMOVE;ALL_ARGS;ARGS" ${ARGN}) + set(result ${arg_ARGS}) + foreach(arg IN LISTS arg_ARGS_TO_REMOVE) + # find arg + list(FIND result ${arg} find_result) + if (NOT find_result EQUAL -1) + # remove arg + list(REMOVE_AT result ${find_result}) + list(LENGTH result result_len) + list(GET result ${find_result} arg_current) + # remove values until we hit another arg + while(NOT ${arg_current} IN_LIST arg_ALL_ARGS AND find_result LESS result_len) + list(REMOVE_AT result ${find_result}) + list(GET result ${find_result} arg_current) + list(LENGTH result result_len) + endwhile() + endif() + endforeach() + set(${out_var} "${result}" PARENT_SCOPE) +endfunction() +# Wraps install() command. In a prefix build, simply passes along arguments to install(). +# In a non-prefix build, handles association of targets to export names, and also calls export(). +function(qt_install) + set(flags) + set(options EXPORT DESTINATION NAMESPACE) + set(multiopts TARGETS) + cmake_parse_arguments(arg "${flags}" "${options}" "${multiopts}" ${ARGN}) + + if(arg_TARGETS) + set(is_install_targets TRUE) + endif() + + # In a prefix build, always invoke install() without modification. + # In a non-prefix build, pass install(TARGETS) commands to allow + # association of targets to export names, so we can later use the export names + # in export() commands. + if(QT_WILL_INSTALL OR is_install_targets) + install(${ARGV}) + endif() + + # Exit early if this is a prefix build. + if(QT_WILL_INSTALL) + return() + endif() + + # In a non-prefix build, when install(EXPORT) is called, + # also call export(EXPORT) to generate build tree target files. + if(NOT is_install_targets AND arg_EXPORT) + set(namespace_option "") + if(arg_NAMESPACE) + set(namespace_option NAMESPACE ${arg_NAMESPACE}) + endif() + export(EXPORT ${arg_EXPORT} + ${namespace_option} + FILE "${arg_DESTINATION}/${arg_EXPORT}.cmake") + endif() +endfunction() + +# Copies files using file(COPY) signature in non-prefix builds. +function(qt_non_prefix_copy) + if(NOT QT_WILL_INSTALL) + file(${ARGV}) + endif() +endfunction() + +# Use case is installing files in a prefix build, or copying them to the correct build dir +# in a non-prefix build. +# Pass along arguments as you would pass them to install(). +# Only supports FILES, PROGRAMS and DIRECTORY signature, and without fancy things +# like OPTIONAL or RENAME or COMPONENT. +function(qt_copy_or_install) + set(flags FILES PROGRAMS DIRECTORY) + set(options) + set(multiopts) + cmake_parse_arguments(arg "${flags}" "${options}" "${multiopts}" ${ARGN}) + + # Remember which option has to be passed to the install command. + set(argv_copy ${ARGV}) + if(arg_FILES) + set(install_option "FILES") + elseif(arg_PROGRAMS) + set(install_option "PROGRAMS") + elseif(arg_DIRECTORY) + set(install_option "DIRECTORY") + endif() + + list(REMOVE_AT argv_copy 0) + qt_install(${install_option} ${argv_copy}) + qt_non_prefix_copy(COPY ${argv_copy}) +endfunction() + +# Hacky way to remove the install target 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, replace the generated +# cmake_install.cmake file with an empty file. To do this, always create a new temporary file +# at CMake configuration step, and use it as an input to a custom command that replaces the +# cmake_install.cmake file with an empty one. This means we will always replace the file on +# every reconfiguration, but not when doing null builds. +function(qt_remove_install_target) + # On superbuilds we only do this for qtbase - it will correctly remove the + # cmake_install.cmake at the root of the repository. + if(QT_SUPERBUILD) + if(NOT (PROJECT_NAME STREQUAL "QtBase")) + return() + endif() + endif() + + set(file_in "${CMAKE_BINARY_DIR}/.remove_cmake_install_in.txt") + set(file_generated "${CMAKE_BINARY_DIR}/.remove_cmake_install_generated.txt") + set(cmake_install_file "${CMAKE_BINARY_DIR}/cmake_install.cmake") + file(WRITE ${file_in} "") + + add_custom_command(OUTPUT ${file_generated} + COMMAND ${CMAKE_COMMAND} -E copy ${file_in} ${file_generated} + COMMAND ${CMAKE_COMMAND} -E remove ${cmake_install_file} + COMMAND ${CMAKE_COMMAND} -E touch ${cmake_install_file} + COMMENT "Removing cmake_install.cmake" + MAIN_DEPENDENCY ${file_in}) + + add_custom_target(remove_cmake_install ALL DEPENDS ${file_generated}) +endfunction() + +function(qt_set_up_nonprefix_build) + if(NOT QT_WILL_INSTALL) + qt_remove_install_target() + endif() +endfunction() + +function(qt_is_imported_target target out_var) + if(NOT TARGET "${target}") + set(target "${QT_CMAKE_EXPORT_NAMESPACE}::${target}") + endif() + if(NOT TARGET "${target}") + message(FATAL_ERROR "Invalid target given to qt_is_imported_target: ${target}") + endif() + get_target_property(is_imported "${target}" IMPORTED) + set(${out_var} "${is_imported}" PARENT_SCOPE) +endfunction() + +# Generates module .pri files for consumption by qmake +function(qt_generate_module_pri_file target target_path pri_files_var) + set(flags INTERNAL_MODULE HEADER_MODULE) + set(options) + set(multiopts QMAKE_MODULE_CONFIG) + cmake_parse_arguments(arg "${flags}" "${options}" "${multiopts}" ${ARGN}) + + qt_internal_module_info(module "${target}") + set(pri_files) + + set(property_prefix) + if(arg_HEADER_MODULE) + set(property_prefix "interface_") + endif() + + get_target_property(enabled_features "${target}" + "${property_prefix}QT_ENABLED_PUBLIC_FEATURES") + get_target_property(disabled_features "${target}" + "${property_prefix}QT_DISABLED_PUBLIC_FEATURES") + get_target_property(enabled_private_features "${target}" + "${property_prefix}QT_ENABLED_PRIVATE_FEATURES") + get_target_property(disabled_private_features "${target}" + "${property_prefix}QT_DISABLED_PRIVATE_FEATURES") + + foreach(var enabled_features disabled_features enabled_private_features disabled_private_features) + if(${var} STREQUAL "${var}-NOTFOUND") + set(${var} "") + else() + string (REPLACE ";" " " ${var} "${${var}}") + endif() + endforeach() + + if(arg_QMAKE_MODULE_CONFIG) + string(REPLACE ";" " " module_config "${arg_QMAKE_MODULE_CONFIG}") + set(module_config "\nQT.${module_lower}.CONFIG = ${module_config}") + else() + set(module_config "") + endif() + + if (NOT ${arg_INTERNAL_MODULE}) + qt_path_join(pri_file_name "${target_path}" "qt_lib_${module_lower}.pri") + list(APPEND pri_files "${pri_file_name}") + + file(GENERATE + OUTPUT "${pri_file_name}" + CONTENT + "QT.${module_lower}.VERSION = ${PROJECT_VERSION} +QT.${module_lower}.name = ${module} +QT.${module_lower}.module = ${module_versioned} +QT.${module_lower}.libs = $$QT_MODULE_LIB_BASE +QT.${module_lower}.includes = $$QT_MODULE_INCLUDE_BASE $$QT_MODULE_INCLUDE_BASE/${module} +QT.${module_lower}.frameworks = +QT.${module_lower}.bins = $$QT_MODULE_BIN_BASE +QT.${module_lower}.depends = +QT.${module_lower}.uses = +QT.${module_lower}.module_config = v2 +QT.${module_lower}.DEFINES = QT_${module_define}_LIB +QT.${module_lower}.enabled_features = ${enabled_features} +QT.${module_lower}.disabled_features = ${disabled_features}${module_config} +QT_MODULES += ${module_lower} +" + ) + endif() + + qt_path_join(private_pri_file "${target_path}" "qt_lib_${module_lower}_private.pri") + list(APPEND pri_files "${private_pri_file}") + + file(GENERATE + OUTPUT "${private_pri_file}" + CONTENT + "QT.${module_lower}_private.VERSION = ${PROJECT_VERSION} +QT.${module_lower}_private.name = ${module} +QT.${module_lower}_private.module = +QT.${module_lower}_private.libs = $$QT_MODULE_LIB_BASE +QT.${module_lower}_private.includes = $$QT_MODULE_INCLUDE_BASE/${module}/${PROJECT_VERSION} $$QT_MODULE_INCLUDE_BASE/${module}/${PROJECT_VERSION}/${module} +QT.${module_lower}_private.frameworks = +QT.${module_lower}_private.depends = ${module_lower} +QT.${module_lower}_private.uses = +QT.${module_lower}_private.module_config = v2 +QT.${module_lower}_private.enabled_features = ${enabled_private_features} +QT.${module_lower}_private.disabled_features = ${disabled_private_features} +" + ) + + set("${pri_files_var}" "${pri_files}" PARENT_SCOPE) +endfunction() + +function(qt_generate_global_config_pri_file) + qt_path_join(qconfig_pri_target_path ${PROJECT_BINARY_DIR} ${INSTALL_MKSPECSDIR}) + qt_path_join(qconfig_pri_target_path "${qconfig_pri_target_path}" "qconfig.pri") + + get_target_property(enabled_features GlobalConfig INTERFACE_QT_ENABLED_PUBLIC_FEATURES) + get_target_property(disabled_features GlobalConfig INTERFACE_QT_DISABLED_PUBLIC_FEATURES) + + # configure2cmake skips the "static" feature, so emulate it here for qmake support: + if(QT_BUILD_SHARED_LIBS OR BUILD_SHARED_LIBS) + list(APPEND enabled_features shared) + list(APPEND disabled_features static) + set(qt_build_config_type "shared") + else() + list(APPEND enabled_features static) + list(APPEND disabled_features shared) + set(qt_build_config_type "static") + endif() + + # configure2cmake skips the "rpath" feature, so emulate it here for qmake support: + if(CMAKE_SKIP_RPATH) + list(APPEND disabled_features rpath) + elseif(LINUX OR APPLE) + list(APPEND enabled_features rpath) + endif() + + string (REPLACE ";" " " enabled_features "${enabled_features}") + string (REPLACE ";" " " disabled_features "${disabled_features}") + + # Add some required CONFIG entries. + set(config_entries "") + if(CMAKE_BUILD_TYPE STREQUAL Debug) + list(APPEND config_entries "debug") + elseif(CMAKE_BUILD_TYPE STREQUAL Release) + list(APPEND config_entries "release") + endif() + list(APPEND config_entries "${qt_build_config_type}") + string (REPLACE ";" " " config_entries "${config_entries}") + + file(GENERATE + OUTPUT "${qconfig_pri_target_path}" + CONTENT + "QT_ARCH = ${TEST_architecture_arch} +QT_BUILDABI = ${TEST_buildAbi} +QT.global.enabled_features = ${enabled_features} +QT.global.disabled_features = ${disabled_features} +QT_VERSION = ${PROJECT_VERSION} +QT_MAJOR_VERSION = ${PROJECT_VERSION_MAJOR} +QT_MINOR_VERSION = ${PROJECT_VERSION_MINOR} +QT_PATCH_VERSION = ${PROJECT_VERSION_PATCH} +CONFIG -= link_prl # we do not create prl files right now +CONFIG += ${config_entries} +" + ) + qt_install(FILES "${qconfig_pri_target_path}" DESTINATION ${INSTALL_MKSPECSDIR}) +endfunction() + +# Takes a list of path components and joins them into one path separated by forward slashes "/", +# and saves the path in out_var. +function(qt_path_join out_var) + # Remove output variable. + set(argv ${ARGV}) + list(REMOVE_AT argv 0) + + # Join the path components. + string(JOIN "/" path ${argv}) + set(${out_var} ${path} PARENT_SCOPE) +endfunction() + +function(qt_internal_export_modern_cmake_config_targets_file) + cmake_parse_arguments(__arg "" "EXPORT_NAME_PREFIX;CONFIG_INSTALL_DIR" "TARGETS" ${ARGN}) + + set(export_name "${__arg_EXPORT_NAME_PREFIX}VersionlessTargets") + foreach(target ${__arg_TARGETS}) + if (TARGET "${target}Versionless") + continue() + endif() + + add_library("${target}Versionless" INTERFACE) + target_link_libraries("${target}Versionless" INTERFACE "${target}") + set_target_properties("${target}Versionless" PROPERTIES EXPORT_NAME "${target}") + qt_install(TARGETS "${target}Versionless" EXPORT ${export_name}) + endforeach() + qt_install(EXPORT ${export_name} NAMESPACE Qt:: DESTINATION "${__arg_CONFIG_INSTALL_DIR}") +endfunction() + +# Print all variables defined in the current scope. +macro(qt_debug_print_variables) + cmake_parse_arguments(__arg "DEDUP" "" "MATCH;IGNORE" ${ARGN}) + message("Known Variables:") + get_cmake_property(__variableNames VARIABLES) + list (SORT __variableNames) + if (__arg_DEDUP) + list(REMOVE_DUPLICATES __variableNames) + endif() + + foreach(__var ${__variableNames}) + set(__ignore OFF) + foreach(__i ${__arg_IGNORE}) + if(__var MATCHES "${__i}") + set(__ignore ON) + break() + endif() + endforeach() + + if (__ignore) + continue() + endif() + + set(__show OFF) + foreach(__i ${__arg_MATCH}) + if(__var MATCHES "${__i}") + set(__show ON) + break() + endif() + endforeach() + + if (__show) + message(" ${__var}=${${__var}}.") + endif() + endforeach() +endmacro() + + +macro(assert) + if (${ARGN}) + else() + message(FATAL_ERROR "ASSERT: ${ARGN}.") + endif() +endmacro() + + +function(qt_create_nolink_target target dependee_target) + if(NOT TARGET "${target}") + message(FATAL_ERROR "${target} does not exist when trying to build a nolink target.") + endif() + get_target_property(type "${target}" TYPE) + if(type STREQUAL EXECUTABLE) + message(FATAL_ERROR "${target} must be a library of some kind.") + endif() + if(type STREQUAL OBJECT_LIBRARY) + message(FATAL_ERROR "${target} must not be an object library.") + endif() + + # Strip off the namespace prefix, so from Vulkan::Vulkan to Vulkan, and then append _nolink. + string(REGEX REPLACE "^.*::" "" non_prefixed_target ${target}) + set(nolink_target "${non_prefixed_target}_nolink") + + # Create the nolink interface target, assign the properties from the original target, + # associate the nolink target with the same export which contains + # the target that uses the _nolink target. + # Also create a namespaced alias of the form ${target}::${target}_nolink which is used by + # our modules. + # Also create a Qt namespaced alias target, because when exporting via install(EXPORT) + # Vulkan::Vulkan_nolink transforms into Qt6::Vulkan_nolink, and the latter needs to be an + # accessible alias for standalone tests. + if(NOT TARGET "${nolink_target}") + add_library("${nolink_target}" INTERFACE) + set(prefixed_nolink_target "${target}_nolink") + set_target_properties("${nolink_target}" PROPERTIES + INTERFACE_INCLUDE_DIRECTORIES + $<TARGET_PROPERTY:${target},INTERFACE_INCLUDE_DIRECTORIES> + INTERFACE_SYSTEM_INCLUDE_DIRECTORIES + $<TARGET_PROPERTY:${target},INTERFACE_SYSTEM_INCLUDE_DIRECTORIES> + INTERFACE_COMPILE_DEFINITIONS + $<TARGET_PROPERTY:${target},INTERFACE_COMPILE_DEFINITIONS> + INTERFACE_COMPILE_OPTIONS + $<TARGET_PROPERTY:${target},INTERFACE_COMPILE_OPTIONS> + INTERFACE_COMPILE_FEATURES + $<TARGET_PROPERTY:${target},INTERFACE_COMPILE_FEATURES>) + + add_library(${prefixed_nolink_target} ALIAS ${nolink_target}) + add_library("${INSTALL_CMAKE_NAMESPACE}::${nolink_target}" ALIAS ${nolink_target}) + + set(export_name "${INSTALL_CMAKE_NAMESPACE}${dependee_target}Targets") + qt_install(TARGETS ${nolink_target} EXPORT ${export_name}) + endif() +endfunction() + +function(qt_ensure_perl) + if(DEFINED HOST_PERL) + return() + endif() + find_program(HOST_PERL "perl" DOC "Perl binary") + if (NOT HOST_PERL) + message(FATAL_ERROR "Perl needs to be available to build Qt.") + endif() +endfunction() + + +function(qt_ensure_sync_qt) + qt_ensure_perl() + if(DEFINED QT_SYNCQT) + return() + endif() + + # When building qtbase, use the source syncqt, otherwise use the installed one. + set(SYNCQT_FROM_SOURCE "${QtBase_SOURCE_DIR}/bin/syncqt.pl") + if(NOT ("${QtBase_SOURCE_DIR}" STREQUAL "") AND EXISTS "${SYNCQT_FROM_SOURCE}") + set(QT_SYNCQT "${SYNCQT_FROM_SOURCE}" CACHE FILEPATH "syncqt script") + message(STATUS "Using source syncqt found at: ${QT_SYNCQT}") + + qt_path_join(syncqt_install_dir ${QT_INSTALL_DIR} ${INSTALL_LIBEXECDIR}) + qt_copy_or_install(PROGRAMS "${SYNCQT_FROM_SOURCE}" + DESTINATION "${syncqt_install_dir}") + elseif(QT_HOST_PATH) + get_filename_component(syncqt_absolute_path + "${QT_HOST_PATH}/${INSTALL_LIBEXECDIR}/syncqt.pl" + ABSOLUTE) + set(QT_SYNCQT "${syncqt_absolute_path}" CACHE FILEPATH "syncqt script") + message(STATUS "Using host syncqt found at: ${QT_SYNCQT}") + else() + get_filename_component(syncqt_absolute_path + "${CMAKE_INSTALL_PREFIX}/${INSTALL_LIBEXECDIR}/syncqt.pl" + ABSOLUTE) + set(QT_SYNCQT "${syncqt_absolute_path}" CACHE FILEPATH "syncqt script") + message(STATUS "Using installed syncqt found at: ${QT_SYNCQT}") + endif() +endfunction() + +# A version of cmake_parse_arguments that makes sure all arguments are processed and errors out +# with a message about ${type} having received unknown arguments. +macro(qt_parse_all_arguments result type flags options multiopts) + cmake_parse_arguments(${result} "${flags}" "${options}" "${multiopts}" ${ARGN}) + if(DEFINED ${result}_UNPARSED_ARGUMENTS) + message(FATAL_ERROR "Unknown arguments were passed to ${type} (${${result}_UNPARSED_ARGUMENTS}).") + endif() +endmacro() + +include(CheckCXXSourceCompiles) + +function(qt_internal_add_link_flags_no_undefined target) + if (NOT QT_BUILD_SHARED_LIBS) + return() + endif() + if (GCC OR CLANG) + set(previous_CMAKE_REQUIRED_LINK_OPTIONS ${CMAKE_REQUIRED_LINK_OPTIONS}) + + set(CMAKE_REQUIRED_LINK_OPTIONS "-Wl,-undefined,error") + check_cxx_source_compiles("int main() {}" HAVE_DASH_UNDEFINED_ERROR) + if(HAVE_DASH_UNDEFINED_ERROR) + set(no_undefined_flag "-Wl,-undefined,error") + endif() + + set(CMAKE_REQUIRED_LINK_OPTIONS "-Wl,--no-undefined") + check_cxx_source_compiles("int main() {}" HAVE_DASH_DASH_NO_UNDEFINED) + if(HAVE_DASH_DASH_NO_UNDEFINED) + set(no_undefined_flag "-Wl,--no-undefined") + endif() + + set(CMAKE_REQUIRED_LINK_OPTIONS ${previous_CMAKE_REQUIRED_LINK_OPTIONS}) + + if (NOT HAVE_DASH_UNDEFINED_ERROR AND NOT HAVE_DASH_DASH_NO_UNDEFINED) + message(FATAL_ERROR "Platform linker doesn't support erroring upon encountering undefined symbols. Target:\"${target}\".") + endif() + target_link_options("${target}" PRIVATE "${no_undefined_flag}") + endif() +endfunction() + +function(qt_internal_add_link_flags_gc_sections target visibility) + set(possible_visibilities PRIVATE INTERFACE PUBLIC) + list(FIND possible_visibilities "${visibility}" known_visibility) + if (known_visibility EQUAL "-1") + message(FATAL_ERROR "Visibitily setting must be one of PRIVATE, INTERFACE or PUBLIC.") + endif() + + if ((GCC OR CLANG) AND NOT EMSCRIPTEN) + if(APPLE) + set(gc_sections_flag "-Wl,-dead_strip") + elseif(LINUX OR BSD OR SOLARIS OR WIN32 OR ANDROID) + set(gc_sections_flag "-Wl,--gc-sections") + else() + message(FATAL_ERROR "Platform linker doesn't support gc sections. Target:\"${target}\".") + endif() + target_link_options("${target}" ${visibility} "${gc_sections_flag}") + endif() +endfunction() + +function(qt_internal_add_linker_version_script target) + qt_parse_all_arguments(arg "qt_internal_add_linker" "INTERNAL" "" "PRIVATE_HEADERS" ${ARGN}) + + if (TEST_ld_version_script) + if (arg_INTERNAL) + set(contents "Qt_${PROJECT_VERSION_MAJOR}_PRIVATE_API { *; };") + else() + set(contents "Qt_${PROJECT_VERSION_MAJOR}_PRIVATE_API {\n qt_private_api_tag*;\n") + foreach(ph ${arg_PRIVATE_HEADERS}) + string(APPEND contents " @FILE:${ph}@\n") + endforeach() + string(APPEND contents "};\n") + set(current "Qt_${PROJECT_VERSION_MAJOR}") + if (QT_NAMESPACE STREQUAL "") + set(tag_symbol "qt_version_tag") + else() + set(tag_symbol "qt_version_tag_${QT_NAMESPACE}") + endif() + string(APPEND contents "${current} { *; };\n") + + foreach(minor_version RANGE ${PROJECT_VERSION_MINOR}) + set(previous "${current}") + set(current "Qt_${PROJECT_VERSION_MAJOR}.${minor_version}") + if (minor_version EQUAL ${PROJECT_VERSION_MINOR}) + string(APPEND contents "${current} { ${tag_symbol}; } ${previous};\n") + else() + string(APPEND contents "${current} {} ${previous};\n") + endif() + endforeach() + + set(infile "${CMAKE_CURRENT_BINARY_DIR}/${target}.version.in") + set(outfile "${CMAKE_CURRENT_BINARY_DIR}/${target}.version") + + file(GENERATE OUTPUT "${infile}" CONTENT "${contents}") + + qt_ensure_perl() + + add_custom_command(TARGET "${target}" PRE_LINK + COMMAND "${HOST_PERL}" "${QT_MKSPECS_DIR}/features/data/unix/findclasslist.pl" < "${infile}" > "${outfile}" + BYPRODUCTS "${outfile}" DEPENDS "${infile}" + WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" + COMMENT "Generating version linker script" + ) + target_link_options("${target}" PRIVATE "-Wl,--version-script,${outfile}") + endif() + endif() +endfunction() + + +# Get a set of Qt module related values based on the target name. +# When doing qt_internal_module_info(foo Core) this method will set +# the following variables in the caller's scope: +# * foo with the value "QtCore" +# * foo_versioned with the value "Qt6Core" (based on major Qt version) +# * foo_upper with the value "CORE" +# * foo_lower with the value "core" +# * foo_repo_include_dir with the module's include directory +# e.g for QtQuick it would be qtdeclarative_build_dir/include for a prefix build or +# qtbase_build_dir/include for a non-prefix build +# * foo_include_dir with the module's include directory +# e.g for QtQuick it would be qtdeclarative_build_dir/include/QtQuick for a prefix build or +# qtbase_build_dir/include/QtQuick for a non-prefix build +# * foo_define same as foo_uper but with - replaced as _ +function(qt_internal_module_info result target) + set(module "Qt${target}") + set("${result}" "${module}" PARENT_SCOPE) + set("${result}_versioned" "Qt${PROJECT_VERSION_MAJOR}${target}" PARENT_SCOPE) + string(TOUPPER "${target}" upper) + string(TOLOWER "${target}" lower)# * foo_upper with the value "CORE" + string(REPLACE "-" "_" define "${upper}") + string(REPLACE "." "_" define "${define}") + set("${result}_upper" "${upper}" PARENT_SCOPE) + set("${result}_lower" "${lower}" PARENT_SCOPE) + set("${result}_repo_include_dir" "${QT_BUILD_DIR}/${INSTALL_INCLUDEDIR}" PARENT_SCOPE) + set("${result}_include_dir" "${QT_BUILD_DIR}/${INSTALL_INCLUDEDIR}/${module}" PARENT_SCOPE) + set("${result}_define" "${define}" PARENT_SCOPE) +endfunction() + + +set(__default_private_args "SOURCES;LIBRARIES;INCLUDE_DIRECTORIES;DEFINES;DBUS_ADAPTOR_BASENAME;DBUS_ADAPTOR_FLAGS;DBUS_ADAPTOR_SOURCES;DBUS_INTERFACE_BASENAME;DBUS_INTERFACE_FLAGS;DBUS_INTERFACE_SOURCES;FEATURE_DEPENDENCIES;COMPILE_OPTIONS;LINK_OPTIONS;MOC_OPTIONS;DISABLE_AUTOGEN_TOOLS;ENABLE_AUTOGEN_TOOLS;PLUGIN_TYPES") + +set(__default_public_args "PUBLIC_LIBRARIES;PUBLIC_INCLUDE_DIRECTORIES;PUBLIC_DEFINES;PUBLIC_COMPILE_OPTIONS;PUBLIC_LINK_OPTIONS") +set(__default_private_module_args "PRIVATE_MODULE_INTERFACE") + +option(QT_CMAKE_DEBUG_EXTEND_TARGET "Debug extend_target calls in Qt's build system" OFF) + +# Initial autogen setup for a target to specify certain CMake properties which are common +# to all autogen tools. Also enable AUTOMOC by default. +function(qt_autogen_tools_initial_setup target) + set_property(TARGET "${target}" PROPERTY INTERFACE_QT_MAJOR_VERSION ${PROJECT_VERSION_MAJOR}) + set_property(TARGET "${target}" APPEND PROPERTY COMPATIBLE_INTERFACE_STRING QT_MAJOR_VERSION) + + set_directory_properties(PROPERTIES + QT_VERSION_MAJOR ${PROJECT_VERSION_MAJOR} + QT_VERSION_MINOR ${PROJECT_VERSION_MINOR} + QT_VERSION_PATCH ${PROJECT_VERSION_PATCH} + ) + + qt_enable_autogen_tool(${target} "moc" ON) +endfunction() + +# Enables or disables an autogen tool like moc, uic or rcc on ${target}. +function(qt_enable_autogen_tool target tool enable) + string(TOUPPER "${tool}" captitalAutogenTool) + + get_target_property(tool_enabled ${target} AUTO${captitalAutogenTool}) + get_target_property(autogen_target_depends ${target} AUTOGEN_TARGET_DEPENDS) + + if(NOT autogen_target_depends) + set(autogen_target_depends "") + endif() + set(tool_executable "$<TARGET_FILE:${QT_CMAKE_EXPORT_NAMESPACE}::${tool}>") + set(tool_target_name ${QT_CMAKE_EXPORT_NAMESPACE}::${tool}) + + if(enable) + list(APPEND autogen_target_depends ${tool_target_name}) + else() + list(REMOVE_ITEM autogen_target_depends ${tool_target_name}) + endif() + + # f66c1db16c050c9d685a44a38ad7c5cf9f6fcc96 in qtbase introduced a new macro + # that the moc scanner has to look for. Inform the CMake moc scanner about it. + if(tool STREQUAL "moc" AND enable) + set_target_properties("${target}" PROPERTIES + AUTOMOC_MACRO_NAMES "Q_OBJECT;Q_GADGET;Q_NAMESPACE;Q_NAMESPACE_EXPORT;Q_ENUM_NS") + endif() + + set_target_properties("${target}" + PROPERTIES + AUTO${captitalAutogenTool} "${enable}" + AUTO${captitalAutogenTool}_EXECUTABLE "${tool_executable}" + AUTOGEN_TARGET_DEPENDS "${autogen_target_depends}" + ) +endfunction() + +# This function adds or removes additional AUTOGEN tools to a target: AUTOMOC/UIC/RCC +function(qt_autogen_tools target) + qt_parse_all_arguments(arg "qt_autogen_tools" "" "" "${__default_private_args}" ${ARGN}) + + if (arg_ENABLE_AUTOGEN_TOOLS) + foreach(tool ${arg_ENABLE_AUTOGEN_TOOLS}) + qt_enable_autogen_tool(${target} ${tool} ON) + endforeach() + endif() + + if (arg_DISABLE_AUTOGEN_TOOLS) + foreach(tool ${arg_DISABLE_AUTOGEN_TOOLS}) + qt_enable_autogen_tool(${target} ${tool} OFF) + endforeach() + endif() +endfunction() + +# This function stores the list of Qt modules a library depend on, +# along with their version info, for usage in ${target}Depends.cmake file +function(qt_register_target_dependencies target public_libs private_libs) + get_target_property(target_deps "${target}" _qt_target_deps) + if(NOT target_deps) + set(target_deps "") + endif() + + # Only process private dependencies if target is a static library + get_target_property(target_type ${target} TYPE) + set(lib_list ${public_libs}) + if (target_type STREQUAL "STATIC_LIBRARY") + list(APPEND lib_list ${private_libs}) + endif() + + foreach(lib IN LISTS lib_list) + if ("${lib}" MATCHES "^Qt::(.*)") + set(lib "${CMAKE_MATCH_1}") + if (lib STREQUAL Platform + OR lib STREQUAL GlobalConfig + OR lib STREQUAL GlobalConfigPrivate + OR lib STREQUAL PlatformModuleInternal + OR lib STREQUAL PlatformPluginInternal + OR lib STREQUAL PlatformToolInternal) + list(APPEND target_deps "Qt6\;${PROJECT_VERSION}") + elseif ("${lib}" MATCHES "(.*)Private") + list(APPEND target_deps "${INSTALL_CMAKE_NAMESPACE}${CMAKE_MATCH_1}\;${PROJECT_VERSION}") + else() + list(APPEND target_deps "${INSTALL_CMAKE_NAMESPACE}${lib}\;${PROJECT_VERSION}") + endif() + endif() + endforeach() + + set_target_properties("${target}" PROPERTIES _qt_target_deps "${target_deps}") +endfunction() + +function(qt_update_precompiled_header target precompiled_header) + if (precompiled_header AND BUILD_WITH_PCH) + set_property(TARGET "${target}" APPEND PROPERTY "PRECOMPILE_HEADERS" "$<$<COMPILE_LANGUAGE:CXX>:${precompiled_header}>") + endif() +endfunction() + +function(qt_update_precompiled_header_with_library target library) + if (TARGET "${library}") + get_target_property(TARGET_TYPE "${library}" TYPE) + if (NOT TARGET_TYPE STREQUAL "INTERFACE_LIBRARY") + get_target_property(HEADER "${library}" MODULE_HEADER) + qt_update_precompiled_header("${target}" "${HEADER}") + endif() + endif() +endfunction() + +function(qt_update_ignore_pch_source target sources) + if (sources) + set_source_files_properties(${sources} PROPERTIES SKIP_PRECOMPILE_HEADERS ON) + endif() +endfunction() + +function(qt_ignore_pch_obj_c_sources target sources) + list(FILTER sources INCLUDE REGEX "\\.mm$") + qt_update_ignore_pch_source("${target}" "${sources}") +endfunction() + +# This function can be used to add sources/libraries/etc. to the specified CMake target +# if the provided CONDITION evaluates to true. +function(qt_extend_target target) + # Don't try to extend_target when cross compiling an imported host target (like a tool). + qt_is_imported_target("${target}" is_imported) + if(is_imported) + return() + endif() + + if (NOT TARGET "${target}") + message(FATAL_ERROR "Trying to extend non-existing target \"${target}\".") + endif() + qt_parse_all_arguments(arg "qt_extend_target" "HEADER_MODULE" "PRECOMPILED_HEADER" + "CONDITION;${__default_public_args};${__default_private_args};${__default_private_module_args};COMPILE_FLAGS;NO_PCH_SOURCES" ${ARGN}) + if ("x${arg_CONDITION}" STREQUAL x) + set(arg_CONDITION ON) + endif() + + qt_evaluate_config_expression(result ${arg_CONDITION}) + if (${result}) + if(QT_CMAKE_DEBUG_EXTEND_TARGET) + message("qt_extend_target(${target} CONDITION ${arg_CONDITION} ...): Evaluated") + endif() + set(dbus_sources "") + foreach(adaptor ${arg_DBUS_ADAPTOR_SOURCES}) + qt_create_qdbusxml2cpp_command("${target}" "${adaptor}" ADAPTOR BASENAME "${arg_DBUS_ADAPTOR_BASENAME}" FLAGS "${arg_DBUS_ADAPTOR_FLAGS}") + list(APPEND dbus_sources "${sources}") + endforeach() + + foreach(interface ${arg_DBUS_INTERFACE_SOURCES}) + qt_create_qdbusxml2cpp_command("${target}" "${interface}" INTERFACE BASENAME "${arg_DBUS_INTERFACE_BASENAME}" FLAGS "${arg_DBUS_INTERFACE_FLAGS}") + list(APPEND dbus_sources "${sources}") + endforeach() + + get_target_property(target_type ${target} TYPE) + set(is_library FALSE) + if (${target_type} STREQUAL "STATIC_LIBRARY" OR ${target_type} STREQUAL "SHARED_LIBRARY") + set(is_library TRUE) + endif() + foreach(lib ${arg_PUBLIC_LIBRARIES} ${arg_LIBRARIES}) + # Automatically generate PCH for 'target' using dependencies + # if 'target' is a library/module! + if (${is_library}) + qt_update_precompiled_header_with_library("${target}" "${lib}") + endif() + + string(REGEX REPLACE "_nolink$" "" base_lib "${lib}") + if(NOT base_lib STREQUAL lib) + qt_create_nolink_target("${base_lib}" ${target}) + endif() + endforeach() + + # Find dependencies to internal libraries + get_target_property(target_deps "${target}" _qt_target_deps) + if(NOT target_deps) + set(target_deps "") + endif() + + foreach(lib ${arg_LIBRARIES}) + if (TARGET "${lib}") + get_target_property(_is_exported "${lib}" INTERFACE_QT_EXPORTED_LIBRARY) + if("${_is_exported}") + list(APPEND target_deps "${lib}\;${PROJECT_VERSION}") + endif() + endif() + endforeach() + # Set-up the target + target_sources("${target}" PRIVATE ${arg_SOURCES} ${dbus_sources}) + if (arg_COMPILE_FLAGS) + set_source_files_properties(${arg_SOURCES} PROPERTIES COMPILE_FLAGS "${arg_COMPILE_FLAGS}") + endif() + + set(public_visibility_option "PUBLIC") + set(private_visibility_option "PRIVATE") + if(arg_HEADER_MODULE) + set(public_visibility_option "INTERFACE") + set(private_visibility_option "INTERFACE") + endif() + target_include_directories("${target}" + ${public_visibility_option} ${arg_PUBLIC_INCLUDE_DIRECTORIES} + ${private_visibility_option} ${arg_INCLUDE_DIRECTORIES}) + target_compile_definitions("${target}" + ${public_visibility_option} ${arg_PUBLIC_DEFINES} + ${private_visibility_option} ${arg_DEFINES}) + target_link_libraries("${target}" + ${public_visibility_option} ${arg_PUBLIC_LIBRARIES} + ${private_visibility_option} ${arg_LIBRARIES}) + target_compile_options("${target}" + ${public_visibility_option} ${arg_PUBLIC_COMPILE_OPTIONS} + ${private_visibility_option} ${arg_COMPILE_OPTIONS}) + target_link_options("${target}" + ${public_visibility_option} ${arg_PUBLIC_LINK_OPTIONS} + ${private_visibility_option} ${arg_LINK_OPTIONS}) + + if(NOT arg_HEADER_MODULE) + set_property (TARGET "${target}" APPEND PROPERTY + AUTOMOC_MOC_OPTIONS "${arg_MOC_OPTIONS}" + ) + set_property(TARGET "${target}" PROPERTY + _qt_target_deps "${target_deps}" + ) + endif() + + # When computing the private library dependencies, we need to check not only the known + # modules added by this repo's qt_build_repo(), but also all module dependencies that + # were found via find_package(). + qt_internal_get_qt_all_known_modules(known_modules) + + # When a public module depends on a private module (Gui on CorePrivate) + # make its private module depend on the other private module (GuiPrivate will depend on + # CorePrivate). + set(qt_libs_private "") + foreach(it ${known_modules}) + list(FIND arg_LIBRARIES "Qt::${it}Private" pos) + if(pos GREATER -1) + list(APPEND qt_libs_private "Qt::${it}Private") + endif() + endforeach() + + set(target_private "${target}Private") + if(TARGET "${target_private}") + target_link_libraries("${target_private}" + INTERFACE "${target}" ${arg_PRIVATE_MODULE_INTERFACE}) + endif() + qt_register_target_dependencies("${target}" + "${arg_PUBLIC_LIBRARIES}" + "${qt_libs_private};${arg_LIBRARIES}") + + + qt_autogen_tools(${target} + ENABLE_AUTOGEN_TOOLS ${arg_ENABLE_AUTOGEN_TOOLS} + DISABLE_AUTOGEN_TOOLS ${arg_DISABLE_AUTOGEN_TOOLS}) + + qt_update_precompiled_header("${target}" "${arg_PRECOMPILED_HEADER}") + qt_update_ignore_pch_source("${target}" "${arg_NO_PCH_SOURCES}") + ## Ignore objective-c files for PCH (not supported atm) + qt_ignore_pch_obj_c_sources("${target}" "${arg_SOURCES}") + + else() + if(QT_CMAKE_DEBUG_EXTEND_TARGET) + message("qt_extend_target(${target} CONDITION ${arg_CONDITION} ...): Skipped") + endif() + endif() +endfunction() + + +function(qt_internal_library_deprecation_level result) + if(WIN32) + # On Windows, due to the way DLLs work, we need to export all functions, + # including the inlines + list(APPEND deprecations "QT_DISABLE_DEPRECATED_BEFORE=0x040800") + else() + # On other platforms, Qt's own compilation goes needs to compile the Qt 5.0 API + list(APPEND deprecations "QT_DISABLE_DEPRECATED_BEFORE=0x050000") + endif() + list(APPEND deprecations "QT_DEPRECATED_WARNINGS_SINCE=0x060000") + set("${result}" deprecations PARENT_SCOPE) +endfunction() + + +function(qt_install_injections target build_dir install_dir) + set(injections ${ARGN}) + set(module "Qt${target}") + get_target_property(target_type ${target} TYPE) + if (target_type STREQUAL "INTERFACE_LIBRARY") + set(is_framework FALSE) + else() + get_target_property(is_framework ${target} FRAMEWORK) + endif() + # examples: + # SYNCQT.INJECTIONS = src/corelib/global/qconfig.h:qconfig.h:QtConfig src/corelib/global/qconfig_p.h:5.12.0/QtCore/private/qconfig_p.h + # SYNCQT.INJECTIONS = src/gui/vulkan/qvulkanfunctions.h:^qvulkanfunctions.h:QVulkanFunctions:QVulkanDeviceFunctions src/gui/vulkan/qvulkanfunctions_p.h:^5.12.0/QtGui/private/qvulkanfunctions_p.h + # The are 3 parts to the assignment, divded by colons ':'. + # The first part contains a path to a generated file in a build folder. + # The second part contains the file name that the forwarding header should have, which points + # to the file in the first part. + # The third part contains multiple UpperCaseFileNames that should be forwarding headers to the + # header specified in the second part. + separate_arguments(injections UNIX_COMMAND "${injections}") + foreach(injection ${injections}) + string(REPLACE ":" ";" injection ${injection}) + # Part 1. + list(GET injection 0 file) + # Part 2. + list(GET injection 1 destination) + string(REGEX REPLACE "^\\^" "" destination "${destination}") + list(REMOVE_AT injection 0 1) + # Part 3. + set(fwd_hdrs ${injection}) + get_filename_component(destinationdir ${destination} DIRECTORY) + get_filename_component(destinationname ${destination} NAME) + get_filename_component(original_file_name ${file} NAME) + + # This describes a concrete example for easier comprehension: + # A file 'qtqml-config.h' is generated by qt_internal_feature_write_file into + # ${qtdeclarative_build_dir}/src/{module}/qtqml-config.h (part 1). + # + # Generate a lower case forwarding header (part 2) 'qtqml-config.h' at the following + # location: + # ${some_prefix}/include/${module}/qtqml-config.h. + # + # Inside this file, we #include the originally generated file, + # ${qtdeclarative_build_dir}/src/{module}/qtqml-config.h. + # + # ${some_prefix}'s value depends on the build type. + # If doing a prefix build, it should point to + # ${current_repo_build_dir} which is ${qtdeclarative_build_dir}. + # If doing a non-prefix build, it should point to + # ${qtbase_build_dir}. + # + # In the code below, ${some_prefix} == ${build_dir}. + set(lower_case_forwarding_header_path "${build_dir}/${INSTALL_INCLUDEDIR}/${module}") + if(destinationdir) + string(APPEND lower_case_forwarding_header_path "/${destinationdir}") + endif() + set(current_repo_build_dir "${PROJECT_BINARY_DIR}") + + file(RELATIVE_PATH relpath + "${lower_case_forwarding_header_path}" + "${current_repo_build_dir}/${file}") + set(main_contents "#include \"${relpath}\"") + file(GENERATE OUTPUT "${lower_case_forwarding_header_path}/${original_file_name}" + CONTENT "${main_contents}") + + if(is_framework) + if(file MATCHES "_p\\.h$") + set(header_type PRIVATE) + else() + set(header_type PUBLIC) + endif() + qt_copy_framework_headers(${target} ${header_type} + ${current_repo_build_dir}/${file}) + else() + # Copy the actual injected (generated) header file (not the just created forwarding one) + # to its install location when doing a prefix build. In an non-prefix build, the qt_install + # will be a no-op. + qt_path_join(install_destination + ${install_dir} ${INSTALL_INCLUDEDIR} ${module} ${destinationdir}) + qt_install(FILES ${current_repo_build_dir}/${file} + DESTINATION ${install_destination} + RENAME ${destinationname} OPTIONAL) + endif() + + # Generate UpperCaseNamed forwarding headers (part 3). + foreach(fwd_hdr ${fwd_hdrs}) + set(upper_case_forwarding_header_path "${INSTALL_INCLUDEDIR}/${module}") + if(destinationdir) + string(APPEND upper_case_forwarding_header_path "/${destinationdir}") + endif() + + # Generate upper case forwarding header like QVulkanFunctions or QtConfig. + file(GENERATE OUTPUT "${build_dir}/${upper_case_forwarding_header_path}/${fwd_hdr}" + CONTENT "#include \"${destinationname}\"\n") + + if(is_framework) + # Copy the forwarding header to the framework's Headers directory. + qt_copy_framework_headers(${target} PUBLIC + "${build_dir}/${upper_case_forwarding_header_path}/${fwd_hdr}") + else() + # Install the forwarding header. + qt_path_join(install_destination + ${install_dir} ${upper_case_forwarding_header_path}) + qt_install(FILES "${build_dir}/${upper_case_forwarding_header_path}/${fwd_hdr}" + DESTINATION ${install_destination} OPTIONAL) + endif() + endforeach() + endforeach() +endfunction() + + +function(qt_read_headers_pri target resultVarPrefix) + qt_internal_module_info(module "${target}") + file(STRINGS "${module_include_dir}/headers.pri" headers_pri_contents) + foreach(line ${headers_pri_contents}) + if("${line}" MATCHES "SYNCQT.HEADER_FILES = (.*)") + set(public_module_headers "${CMAKE_MATCH_1}") + separate_arguments(public_module_headers UNIX_COMMAND "${public_module_headers}") + elseif("${line}" MATCHES "SYNCQT.PRIVATE_HEADER_FILES = (.*)") + set(private_module_headers "${CMAKE_MATCH_1}") + separate_arguments(private_module_headers UNIX_COMMAND "${private_module_headers}") + elseif("${line}" MATCHES "SYNCQT.GENERATED_HEADER_FILES = (.*)") + set(generated_module_headers "${CMAKE_MATCH_1}") + separate_arguments(generated_module_headers UNIX_COMMAND "${generated_module_headers}") + foreach(generated_header ${generated_module_headers}) + list(APPEND public_module_headers "${module_include_dir}/${generated_header}") + endforeach() + elseif("${line}" MATCHES "SYNCQT.INJECTIONS = (.*)") + set(injections "${CMAKE_MATCH_1}") + elseif("${line}" MATCHES "SYNCQT.([A-Z_]+)_HEADER_FILES = (.+)") + set(prefix "${CMAKE_MATCH_1}") + string(TOLOWER "${prefix}" prefix) + set(entries "${CMAKE_MATCH_2}") + separate_arguments(entries UNIX_COMMAND "${entries}") + set("${resultVarPrefix}_${prefix}" "${entries}" PARENT_SCOPE) + endif() + endforeach() + set(${resultVarPrefix}_public "${public_module_headers}" PARENT_SCOPE) + set(${resultVarPrefix}_private "${private_module_headers}" PARENT_SCOPE) + set(${resultVarPrefix}_injections "${injections}" PARENT_SCOPE) +endfunction() + + +# Add Qt::target and Qt6::target as aliases for the target +function(qt_internal_add_target_aliases target) + get_target_property(type "${target}" TYPE) + if (type STREQUAL EXECUTABLE) + add_executable("Qt::${target}" ALIAS "${target}") + add_executable("Qt${PROJECT_VERSION_MAJOR}::${target}" ALIAS "${target}") + else() + add_library("Qt::${target}" ALIAS "${target}") + add_library("Qt${PROJECT_VERSION_MAJOR}::${target}" ALIAS "${target}") + endif() +endfunction() + +# Sets the exceptions flags for the given target +function(qt_internal_set_no_exceptions_flags target) + target_compile_definitions("${target}" PRIVATE "QT_NO_EXCEPTIONS") + if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") + target_compile_options("${target}" PRIVATE "/wd4530" "/wd4577") + elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") + target_compile_options("${target}" PRIVATE "-fno-exceptions") + elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "AppleClang") + target_compile_options("${target}" PRIVATE "-fno-exceptions") + elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") + target_compile_options("${target}" PRIVATE "-fno-exceptions") + elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Intel") + target_compile_options("${target}" PRIVATE "-fno-exceptions") + endif() +endfunction() + +function(qt_skip_warnings_are_errors target) + get_target_property(target_type "${target}" TYPE) + if(target_type STREQUAL "INTERFACE_LIBRARY") + return() + endif() + set_target_properties("${target}" PROPERTIES QT_SKIP_WARNINGS_ARE_ERRORS ON) +endfunction() + +function(qt_skip_warnings_are_errors_when_repo_unclean target) + if(QT_REPO_NOT_WARNINGS_CLEAN) + qt_skip_warnings_are_errors("${target}") + endif() +endfunction() + +function(qt_disable_warnings target) + get_target_property(target_type "${target}" TYPE) + if(target_type STREQUAL "INTERFACE_LIBRARY") + return() + endif() + set_target_properties("${target}" PROPERTIES QT_COMPILE_OPTIONS_DISABLE_WARNINGS ON) +endfunction() + +function(qt_set_symbol_visibility_preset target value) + get_target_property(target_type "${target}" TYPE) + if(target_type STREQUAL "INTERFACE_LIBRARY") + return() + endif() + + set_target_properties("${target}" PROPERTIES C_VISIBILITY_PRESET "${value}") + set_target_properties("${target}" PROPERTIES CXX_VISIBILITY_PRESET "${value}") +endfunction() + +function(qt_set_symbol_visibility_hidden target) + qt_set_symbol_visibility_preset("${target}" "hidden") +endfunction() + +function(qt_get_sanitized_plugin_type plugin_type out_var) + # Used to handle some edge cases such as platforms/darwin + string(REGEX REPLACE "[-/]" "_" plugin_type "${plugin_type}") + set("${out_var}" "${plugin_type}" PARENT_SCOPE) +endfunction() + +# Copy header files to QtXYZ.framework/Versions/6/Headers/ +# Use this function for header files that +# - are not added as source files to the target +# - are not marked as PUBLIC_HEADER +# - or are private and supposed to end up in the 6.7.8/QtXYZ/private subdir. +function(qt_copy_framework_headers target) + get_target_property(is_fw ${target} FRAMEWORK) + if(NOT "${is_fw}") + return() + endif() + + set(options PUBLIC PRIVATE QPA) + set(oneValueArgs) + set(multiValueArgs) + cmake_parse_arguments(ARG "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) + + get_target_property(fw_version ${target} FRAMEWORK_VERSION) + get_target_property(fw_bundle_version ${target} MACOSX_FRAMEWORK_BUNDLE_VERSION) + get_target_property(fw_dir ${target} LIBRARY_OUTPUT_DIRECTORY) + get_target_property(fw_name ${target} OUTPUT_NAME) + set(fw_headers_dir ${fw_dir}/${fw_name}.framework/Versions/${fw_version}/Headers/) + if(ARG_PRIVATE) + string(APPEND fw_headers_dir "${fw_bundle_version}/Qt${target}/private/") + elseif(ARG_QPA) + string(APPEND fw_headers_dir "${fw_bundle_version}/Qt${target}/qpa/") + endif() + + set(out_files) + foreach(hdr IN LISTS ARG_UNPARSED_ARGUMENTS) + get_filename_component(in_file_path ${hdr} ABSOLUTE) + get_filename_component(in_file_name ${hdr} NAME) + set(out_file_path ${fw_headers_dir}${in_file_name}) + add_custom_command( + OUTPUT ${out_file_path} + DEPENDS ${in_file_path} + COMMAND ${CMAKE_COMMAND} -E make_directory "${fw_headers_dir}" + COMMAND ${CMAKE_COMMAND} -E copy "${in_file_path}" "${fw_headers_dir}") + list(APPEND out_files ${out_file_path}) + endforeach() + + get_target_property(fw_copied_headers ${target} QT_COPIED_FRAMEWORK_HEADERS) + if(NOT fw_copied_headers) + set(fw_copied_headers "") + endif() + list(APPEND fw_copied_headers ${out_files}) + set_target_properties(${target} PROPERTIES QT_COPIED_FRAMEWORK_HEADERS "${fw_copied_headers}") +endfunction() + +function(qt_finalize_framework_headers_copy target) + get_target_property(target_type ${target} TYPE) + if(${target_type} STREQUAL "INTERFACE_LIBRARY") + return() + endif() + get_target_property(is_fw ${target} FRAMEWORK) + if(NOT "${is_fw}") + return() + endif() + get_target_property(headers ${target} QT_COPIED_FRAMEWORK_HEADERS) + if(headers) + # Hack to create the "Headers" symlink in the framework: + # Create a fake header file and copy it into the framework by marking it as PUBLIC_HEADER. + # CMake now takes care of creating the symlink. + set(fake_header ${target}_fake_header.h) + qt_get_main_cmake_configuration(main_config) + file(GENERATE OUTPUT ${fake_header} CONTENT "// ignore this file\n" + CONDITION "$<CONFIG:${main_config}>") + string(PREPEND fake_header "${CMAKE_CURRENT_BINARY_DIR}/") + target_sources(${target} PRIVATE ${fake_header}) + set_source_files_properties(${fake_header} PROPERTIES GENERATED ON) + set_property(TARGET ${target} APPEND PROPERTY PUBLIC_HEADER ${fake_header}) + + # Add a target, e.g. Core_framework_headers, that triggers the header copy. + add_custom_target(${target}_framework_headers DEPENDS ${headers}) + add_dependencies(${target} ${target}_framework_headers) + endif() +endfunction() + +function(qt_clone_property_for_configs target property configs) + get_target_property(value "${target}" "${property}") + foreach(config ${configs}) + string(TOUPPER "${config}" upper_config) + set_property(TARGET "${target}" PROPERTY "${property}_${upper_config}" "${value}") + endforeach() +endfunction() + +function(qt_handle_multi_config_output_dirs target) + set(possible_configs "${CMAKE_BUILD_TYPE}") + if(CMAKE_CONFIGURATION_TYPES) + set(possible_configs "${CMAKE_CONFIGURATION_TYPES}") + endif() + qt_clone_property_for_configs(${target} LIBRARY_OUTPUT_DIRECTORY "${possible_configs}") + qt_clone_property_for_configs(${target} RUNTIME_OUTPUT_DIRECTORY "${possible_configs}") + qt_clone_property_for_configs(${target} ARCHIVE_OUTPUT_DIRECTORY "${possible_configs}") +endfunction() + +# This is the main entry function for creating a Qt module, that typically +# consists of a library, public header files, private header files and configurable +# features. +# +# A CMake target with the specified target parameter is created. If the current source +# directory has a configure.cmake file, then that is also processed for feature definition +# and testing. Any features defined as well as any features coming from dependencies to +# this module are imported into the scope of the calling feature. +# +# Target is without leading "Qt". So e.g. the "QtCore" module has the target "Core". +function(qt_add_module target) + qt_internal_module_info(module "${target}") + + # Process arguments: + qt_parse_all_arguments(arg "qt_add_module" + "NO_MODULE_HEADERS;STATIC;DISABLE_TOOLS_EXPORT;EXCEPTIONS;INTERNAL_MODULE;NO_SYNC_QT;NO_PRIVATE_MODULE;HEADER_MODULE;GENERATE_METATYPES;NO_CONFIG_HEADER_FILE" + "CONFIG_MODULE_NAME;PRECOMPILED_HEADER" + "${__default_private_args};${__default_public_args};${__default_private_module_args};QMAKE_MODULE_CONFIG;EXTRA_CMAKE_FILES;EXTRA_CMAKE_INCLUDES;NO_PCH_SOURCES" ${ARGN}) + + if(NOT DEFINED arg_CONFIG_MODULE_NAME) + set(arg_CONFIG_MODULE_NAME "${module_lower}") + endif() + + qt_internal_add_qt_repo_known_module("${target}") + + ### Define Targets: + set(is_interface_lib 0) + set(is_shared_lib 0) + if(${arg_HEADER_MODULE}) + add_library("${target}" INTERFACE) + set(is_interface_lib 1) + elseif(${arg_STATIC}) + add_library("${target}" STATIC) + elseif(${QT_BUILD_SHARED_LIBS}) + add_library("${target}" SHARED) + set(is_shared_lib 1) + else() + add_library("${target}" STATIC) + endif() + + set(is_framework 0) + if(QT_FEATURE_framework AND NOT ${arg_HEADER_MODULE} AND NOT ${arg_STATIC}) + set(is_framework 1) + set_target_properties(${target} PROPERTIES + FRAMEWORK TRUE + FRAMEWORK_VERSION ${PROJECT_VERSION_MAJOR} + MACOSX_FRAMEWORK_IDENTIFIER org.qt-project.Qt${target} + MACOSX_FRAMEWORK_BUNDLE_VERSION ${PROJECT_VERSION} + MACOSX_FRAMEWORK_SHORT_VERSION_STRING ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR} + ) + endif() + + if(QT_FEATURE_reduce_relocations AND UNIX AND NOT is_interface_lib) + # On x86 and x86-64 systems with ELF binaries (especially Linux), due to + # a new optimization in GCC 5.x in combination with a recent version of + # GNU binutils, compiling Qt applications with -fPIE is no longer + # enough. + # Applications now need to be compiled with the -fPIC option if the Qt option + # \"reduce relocations\" is active. + target_compile_options(${target} INTERFACE -fPIC) + if(GCC AND is_shared_lib) + target_link_options(${target} PRIVATE LINKER:-Bsymbolic-functions) + endif() + endif() + + if (ANDROID) + qt_android_apply_arch_suffix("${target}") + endif() + qt_internal_add_target_aliases("${target}") + qt_skip_warnings_are_errors_when_repo_unclean("${target}") + + # Add _private target to link against the private headers: + if(NOT ${arg_NO_PRIVATE_MODULE}) + set(target_private "${target}Private") + add_library("${target_private}" INTERFACE) + qt_internal_add_target_aliases("${target_private}") + endif() + + if(NOT arg_HEADER_MODULE) + set_target_properties(${target} PROPERTIES + LIBRARY_OUTPUT_DIRECTORY "${QT_BUILD_DIR}/${INSTALL_LIBDIR}" + RUNTIME_OUTPUT_DIRECTORY "${QT_BUILD_DIR}/${INSTALL_BINDIR}" + ARCHIVE_OUTPUT_DIRECTORY "${QT_BUILD_DIR}/${INSTALL_LIBDIR}" + VERSION ${PROJECT_VERSION} + SOVERSION ${PROJECT_VERSION_MAJOR} + QT_TARGET_VERSION "${PROJECT_VERSION}.0" + QT_TARGET_COMPANY_NAME "The Qt Company Ltd." + QT_TARGET_DESCRIPTION "C++ Application Development Framework" + QT_TARGET_COPYRIGHT "Copyright (C) 2020 The Qt Company Ltd." + QT_TARGET_PRODUCT_NAME "Qt6" + ) + qt_handle_multi_config_output_dirs("${target}") + + if(is_framework) + set_target_properties(${target} PROPERTIES + OUTPUT_NAME Qt${target} + ) + else() + set_target_properties(${target} PROPERTIES + OUTPUT_NAME "${INSTALL_CMAKE_NAMESPACE}${target}" + ) + endif() + + if (WIN32 AND BUILD_SHARED_LIBS) + qt6_generate_win32_rc_file(${target}) + endif() + endif() + + # Module headers: + if(${arg_NO_MODULE_HEADERS} OR ${arg_NO_SYNC_QT}) + set_target_properties("${target}" PROPERTIES INTERFACE_MODULE_HAS_HEADERS OFF) + else() + # Use QT_BUILD_DIR for the syncqt call. + # So we either write the generated files into the qtbase non-prefix build root, or the + # module specific build root. + qt_ensure_sync_qt() + set(syncqt_full_command "${HOST_PERL}" -w "${QT_SYNCQT}" + -quiet + -check-includes + -module "${module}" + -version "${PROJECT_VERSION}" + -outdir "${QT_BUILD_DIR}" + -builddir "${PROJECT_BINARY_DIR}" + "${PROJECT_SOURCE_DIR}") + execute_process(COMMAND ${syncqt_full_command}) + + set_target_properties("${target}" PROPERTIES INTERFACE_MODULE_HAS_HEADERS ON) + + ### FIXME: Can we replace headers.pri? + qt_read_headers_pri("${target}" "module_headers") + set(module_depends_header "${module_include_dir}/${module}Depends") + if(is_framework) + if(NOT is_interface_lib) + set(public_headers_to_copy "${module_headers_public}" "${module_depends_header}") + qt_copy_framework_headers(${target} PUBLIC "${public_headers_to_copy}") + qt_copy_framework_headers(${target} PRIVATE "${module_headers_private}") + endif() + else() + set_property(TARGET ${target} APPEND PROPERTY PUBLIC_HEADER "${module_headers_public}") + set_property(TARGET ${target} APPEND PROPERTY PUBLIC_HEADER ${module_depends_header}) + set_property(TARGET ${target} APPEND PROPERTY PRIVATE_HEADER "${module_headers_private}") + endif() + if (NOT ${arg_HEADER_MODULE}) + set_property(TARGET "${target}" PROPERTY MODULE_HEADER "${module_include_dir}/${module}") + endif() + + if(module_headers_qpa) + if(is_framework) + qt_copy_framework_headers(${target} QPA "${module_headers_qpa}") + else() + qt_install( + FILES ${module_headers_qpa} + DESTINATION ${INSTALL_INCLUDEDIR}/${module}/${PROJECT_VERSION}/${module}/qpa) + endif() + endif() + endif() + + if(NOT arg_HEADER_MODULE) + # This property is used for super builds with static libraries. We use + # it in QtPlugins.cmake.in to avoid "polluting" the dependency chain + # for the target in it's project directory. + # E.g: When we process find_package(Qt6 ... Gui) in QtDeclarative, the + # rules in QtPugins.cmake add all the known Gui plugins as interface + # dependencies. This in turn causes circular dependencies on every + # plugin which links against Gui. Plugin A -> GUI -> Plugin A .... + + set_target_properties(${target} PROPERTIES QT_BUILD_PROJECT_NAME ${PROJECT_NAME}) + # Plugin types associated to a module + if(NOT "x${arg_PLUGIN_TYPES}" STREQUAL "x") + # Reset the variable containing the list of plugins for the given plugin type + foreach(plugin_type ${arg_PLUGIN_TYPES}) + qt_get_sanitized_plugin_type("${plugin_type}" plugin_type) + set_property(TARGET "${target}" APPEND PROPERTY MODULE_PLUGIN_TYPES "${plugin_type}") + qt_internal_add_qt_repo_known_plugin_types("${plugin_type}") + endforeach() + endif() + endif() + + qt_internal_library_deprecation_level(deprecation_define) + + if(NOT arg_HEADER_MODULE) + qt_autogen_tools_initial_setup(${target}) + endif() + + set(private_includes + "$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>" + "$<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}>" + ${arg_INCLUDE_DIRECTORIES} + ) + + set(public_includes "") + set(public_headers_list "public_includes") + if(is_framework) + set(public_headers_list "private_includes") + set(fw_bundle_subdir "${INSTALL_LIBDIR}/Qt${target}.framework") + set(fw_headers_subdir "Versions/${PROJECT_VERSION_MAJOR}/Headers") + list(APPEND public_includes + # Add the lib/Foo.framework dir as include path to let CMake generate + # the -F compiler flag. + "$<BUILD_INTERFACE:${QT_BUILD_DIR}/${fw_bundle_subdir}>" + "$<INSTALL_INTERFACE:${fw_bundle_subdir}>" + + # Add the fully resolved Headers subdir, because the Headers symlink might + # not be there yet. + "$<BUILD_INTERFACE:${QT_BUILD_DIR}/${fw_bundle_subdir}/${fw_headers_subdir}>" + + # After installing, the Headers symlink is guaranteed to exist. + "$<INSTALL_INTERFACE:${fw_bundle_subdir}/Headers>" + ) + endif() + + # Handle cases like QmlDevTools which do not have their own headers, but rather borrow them + # from another module. + if(NOT arg_NO_SYNC_QT AND NOT arg_NO_MODULE_HEADERS) + # Don't include private headers unless they exist, aka syncqt created them. + if(module_headers_private) + list(APPEND private_includes + "$<BUILD_INTERFACE:${module_include_dir}/${PROJECT_VERSION}>" + "$<BUILD_INTERFACE:${module_include_dir}/${PROJECT_VERSION}/${module}>") + endif() + + list(APPEND ${public_headers_list} + # For the syncqt headers + "$<BUILD_INTERFACE:${module_repo_include_dir}>" + "$<BUILD_INTERFACE:${module_include_dir}>") + endif() + + if(NOT arg_NO_MODULE_HEADERS AND NOT arg_NO_SYNC_QT) + # For the syncqt headers + list(APPEND ${public_headers_list} "$<INSTALL_INTERFACE:${INSTALL_INCLUDEDIR}/${module}>") + endif() + list(APPEND ${public_headers_list} ${arg_PUBLIC_INCLUDE_DIRECTORIES}) + + set(header_module) + if(arg_HEADER_MODULE) + set(header_module "HEADER_MODULE") + endif() + + qt_extend_target("${target}" + ${header_module} + SOURCES ${arg_SOURCES} + INCLUDE_DIRECTORIES + ${private_includes} + PUBLIC_INCLUDE_DIRECTORIES + ${public_includes} + PUBLIC_DEFINES + ${arg_PUBLIC_DEFINES} + QT_${module_define}_LIB + DEFINES + ${arg_DEFINES} + QT_NO_CAST_TO_ASCII QT_ASCII_CAST_WARNINGS + QT_MOC_COMPAT #we don't need warnings from calling moc code in our generated code + QT_USE_QSTRINGBUILDER + QT_DEPRECATED_WARNINGS + QT_BUILDING_QT + QT_BUILD_${module_define}_LIB ### FIXME: use QT_BUILD_ADDON for Add-ons or remove if we don't have add-ons anymore + "${deprecation_define}" + PUBLIC_LIBRARIES ${arg_PUBLIC_LIBRARIES} + LIBRARIES ${arg_LIBRARIES} Qt::PlatformModuleInternal + PRIVATE_MODULE_INTERFACE ${arg_PRIVATE_MODULE_INTERFACE} + FEATURE_DEPENDENCIES ${arg_FEATURE_DEPENDENCIES} + DBUS_ADAPTOR_SOURCES ${arg_DBUS_ADAPTOR_SOURCES} + DBUS_ADAPTOR_FLAGS ${arg_DBUS_ADAPTOR_FLAGS} + DBUS_INTERFACE_SOURCES ${arg_DBUS_INTERFACE_SOURCES} + DBUS_INTERFACE_FLAGS ${arg_DBUS_INTERFACE_FLAGS} + COMPILE_OPTIONS ${arg_COMPILE_OPTIONS} + PUBLIC_COMPILE_OPTIONS ${arg_PUBLIC_COMPILE_OPTIONS} + LINK_OPTIONS ${arg_LINK_OPTIONS} + PUBLIC_LINK_OPTIONS ${arg_PUBLIC_LINK_OPTIONS} + MOC_OPTIONS ${arg_MOC_OPTIONS} + ENABLE_AUTOGEN_TOOLS ${arg_ENABLE_AUTOGEN_TOOLS} + DISABLE_AUTOGEN_TOOLS ${arg_DISABLE_AUTOGEN_TOOLS} + PRECOMPILED_HEADER ${arg_PRECOMPILED_HEADER} + NO_PCH_SOURCES ${arg_NO_PCH_SOURCES} + ) + + if(NOT ${arg_EXCEPTIONS} AND NOT ${arg_HEADER_MODULE}) + qt_internal_set_no_exceptions_flags("${target}") + endif() + + set(configureFile "${CMAKE_CURRENT_SOURCE_DIR}/configure.cmake") + if(EXISTS "${configureFile}" AND NOT arg_NO_CONFIG_HEADER_FILE) + qt_feature_module_begin( + LIBRARY "${target}" + PUBLIC_FILE "qt${arg_CONFIG_MODULE_NAME}-config.h" + PRIVATE_FILE "qt${arg_CONFIG_MODULE_NAME}-config_p.h" + PUBLIC_DEPENDENCIES ${arg_FEATURE_DEPENDENCIES} + PRIVATE_DEPENDENCIES ${arg_FEATURE_DEPENDENCIES} + ) + include(${configureFile}) + qt_feature_module_end("${target}") + + set_property(TARGET "${target}" APPEND PROPERTY PUBLIC_HEADER "${CMAKE_CURRENT_BINARY_DIR}/qt${arg_CONFIG_MODULE_NAME}-config.h") + set_property(TARGET "${target}" APPEND PROPERTY PRIVATE_HEADER "${CMAKE_CURRENT_BINARY_DIR}/qt${arg_CONFIG_MODULE_NAME}-config_p.h") + endif() + + if(NOT arg_HEADER_MODULE) + if(DEFINED module_headers_private) + qt_internal_add_linker_version_script("${target}" PRIVATE_HEADERS ${module_headers_private} ${module_headers_qpa}) + else() + qt_internal_add_linker_version_script("${target}") + endif() + endif() + + # Handle injections. Aka create forwarding headers for certain headers that have been + # automatically generated in the build dir (for example qconfig.h, qtcore-config.h, + # qvulkanfunctions.h, etc) + # module_headers_injections come from the qt_read_headers_pri() call. + # extra_library_injections come from the qt_feature_module_end() call. + set(final_injections "") + if(module_headers_injections) + string(APPEND final_injections "${module_headers_injections} ") + endif() + if(extra_library_injections) + string(APPEND final_injections "${extra_library_injections} ") + endif() + + if(final_injections) + qt_install_injections(${target} "${QT_BUILD_DIR}" "${QT_INSTALL_DIR}" ${final_injections}) + endif() + + # Handle creation of cmake files for consumers of find_package(). + set(path_suffix "${INSTALL_CMAKE_NAMESPACE}${target}") + qt_path_join(config_build_dir ${QT_CONFIG_BUILD_DIR} ${path_suffix}) + qt_path_join(config_install_dir ${QT_CONFIG_INSTALL_DIR} ${path_suffix}) + + set(extra_cmake_files) + set(extra_cmake_includes) + if (EXISTS "${CMAKE_CURRENT_LIST_DIR}/${INSTALL_CMAKE_NAMESPACE}${target}Macros.cmake") + list(APPEND extra_cmake_files "${CMAKE_CURRENT_LIST_DIR}/${INSTALL_CMAKE_NAMESPACE}${target}Macros.cmake") + list(APPEND extra_cmake_includes "${INSTALL_CMAKE_NAMESPACE}${target}Macros.cmake") + endif() + if (EXISTS "${CMAKE_CURRENT_LIST_DIR}/${INSTALL_CMAKE_NAMESPACE}${target}ConfigExtras.cmake.in") + configure_file("${CMAKE_CURRENT_LIST_DIR}/${INSTALL_CMAKE_NAMESPACE}${target}ConfigExtras.cmake.in" + "${config_build_dir}/${INSTALL_CMAKE_NAMESPACE}${target}ConfigExtras.cmake" + @ONLY) + list(APPEND extra_cmake_files "${config_build_dir}/${INSTALL_CMAKE_NAMESPACE}${target}ConfigExtras.cmake") + list(APPEND extra_cmake_includes "${INSTALL_CMAKE_NAMESPACE}${target}ConfigExtras.cmake") + endif() + + foreach(cmake_file IN LISTS arg_EXTRA_CMAKE_FILES) + get_filename_component(basename ${cmake_file} NAME) + file(COPY ${cmake_file} DESTINATION ${config_build_dir}) + list(APPEND extra_cmake_files "${config_build_dir}/${basename}") + endforeach() + list(APPEND extra_cmake_includes ${arg_EXTRA_CMAKE_INCLUDES}) + + set(extra_cmake_code "") + + if(target STREQUAL Core) + # Propagate non-build related variables that are needed for consuming Qt packages. + # Do this in CoreConfig instead of Qt6Config, so that consumers can also use + # find_package(Qt6Core) instead of find_package(Qt6 COMPONENTS Core) + string(APPEND extra_cmake_code " +set(QT_CMAKE_EXPORT_NAMESPACE ${QT_CMAKE_EXPORT_NAMESPACE})") + endif() + + # Generate metatypes + set(QT_MODULE_HAS_META_TYPES_FILE FALSE) + if (${arg_GENERATE_METATYPES}) + set(QT_MODULE_HAS_META_TYPES_FILE TRUE) + set(metatypes_install_dir ${INSTALL_LIBDIR}/metatypes) + set(args) + if (NOT QT_WILL_INSTALL) + set(args COPY_OVER_INSTALL INSTALL_DIR "${QT_BUILD_DIR}/${metatypes_install_dir}") + else() + set(args INSTALL_DIR "${metatypes_install_dir}") + endif() + qt6_generate_meta_types_json_file(${target} ${args}) + endif() + configure_package_config_file( + "${QT_CMAKE_DIR}/QtModuleConfig.cmake.in" + "${config_build_dir}/${INSTALL_CMAKE_NAMESPACE}${target}Config.cmake" + INSTALL_DESTINATION "${config_install_dir}" + ) + + if (EXISTS "${CMAKE_CURRENT_LIST_DIR}/${INSTALL_CMAKE_NAMESPACE}${target}BuildInternals.cmake") + configure_file("${CMAKE_CURRENT_LIST_DIR}/${INSTALL_CMAKE_NAMESPACE}${target}BuildInternals.cmake" + "${config_build_dir}/${INSTALL_CMAKE_NAMESPACE}${target}BuildInternals.cmake" + @ONLY) + list(APPEND extra_cmake_files "${config_build_dir}/${INSTALL_CMAKE_NAMESPACE}${target}BuildInternals.cmake") + endif() + + write_basic_package_version_file( + "${config_build_dir}/${INSTALL_CMAKE_NAMESPACE}${target}ConfigVersion.cmake" + VERSION ${PROJECT_VERSION} + COMPATIBILITY AnyNewerVersion + ) + qt_install(FILES + "${config_build_dir}/${INSTALL_CMAKE_NAMESPACE}${target}Config.cmake" + "${config_build_dir}/${INSTALL_CMAKE_NAMESPACE}${target}ConfigVersion.cmake" + ${extra_cmake_files} + DESTINATION "${config_install_dir}" + COMPONENT Devel + ) + + file(COPY ${extra_cmake_files} DESTINATION "${config_build_dir}") + set(exported_targets ${target}) + if(NOT ${arg_NO_PRIVATE_MODULE}) + list(APPEND exported_targets ${target_private}) + endif() + set(export_name "${INSTALL_CMAKE_NAMESPACE}${target}Targets") + qt_install(TARGETS ${exported_targets} + EXPORT ${export_name} + RUNTIME DESTINATION ${INSTALL_BINDIR} + LIBRARY DESTINATION ${INSTALL_LIBDIR} + ARCHIVE DESTINATION ${INSTALL_LIBDIR} + FRAMEWORK DESTINATION ${INSTALL_LIBDIR} + PUBLIC_HEADER DESTINATION ${INSTALL_INCLUDEDIR}/${module} + PRIVATE_HEADER DESTINATION ${INSTALL_INCLUDEDIR}/${module}/${PROJECT_VERSION}/${module}/private + ) + + if (ANDROID AND NOT arg_HEADER_MODULE) + # Record install library location so it can be accessed by + # qt_android_dependencies without having to specify it again. + set_target_properties(${target} PROPERTIES + QT_ANDROID_MODULE_INSTALL_DIR ${INSTALL_LIBDIR}) + endif() + + qt_install(EXPORT ${export_name} + NAMESPACE ${QT_CMAKE_EXPORT_NAMESPACE}:: + DESTINATION ${config_install_dir}) + + qt_internal_export_modern_cmake_config_targets_file( + TARGETS ${exported_targets} + EXPORT_NAME_PREFIX ${INSTALL_CMAKE_NAMESPACE}${target} + CONFIG_INSTALL_DIR "${config_install_dir}") + + if (${arg_INTERNAL_MODULE}) + set(arg_INTERNAL_MODULE "INTERNAL_MODULE") + else() + unset(arg_INTERNAL_MODULE) + endif() + + qt_path_join(pri_target_path ${PROJECT_BINARY_DIR} ${INSTALL_MKSPECSDIR}/modules) + qt_generate_module_pri_file("${target}" "${pri_target_path}" module_pri_files + ${arg_INTERNAL_MODULE} + ${header_module} + QMAKE_MODULE_CONFIG + ${arg_QMAKE_MODULE_CONFIG} + ) + qt_install(FILES "${module_pri_files}" DESTINATION ${INSTALL_MKSPECSDIR}/modules) + + ### fixme: cmake is missing a built-in variable for this. We want to apply it only to modules and plugins + # that belong to Qt. + if(NOT arg_HEADER_MODULE) + qt_internal_add_link_flags_no_undefined("${target}") + endif() + + set(interface_includes "") + + # Handle cases like QmlDevTools which do not have their own headers, but rather borrow them + # from another module. + if(NOT arg_NO_SYNC_QT) + list(APPEND interface_includes "$<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}>") + + # syncqt.pl does not create a private header directory like 'include/6.0/QtFoo' unless + # the module has foo_p.h header files. For QtZlib, there are no such private headers, so we + # need to make sure not to add such include paths unless the directory exists, otherwise + # consumers of the module will fail at CMake generation time stating that + # INTERFACE_INCLUDE_DIRECTORIES contains a non-existent path. + if(NOT arg_NO_MODULE_HEADERS + AND EXISTS "${module_include_dir}/${PROJECT_VERSION}/${module}") + list(APPEND interface_includes + "$<BUILD_INTERFACE:${module_include_dir}/${PROJECT_VERSION}>" + "$<BUILD_INTERFACE:${module_include_dir}/${PROJECT_VERSION}/${module}>") + + if(is_framework) + set(fw_headers_dir + "${INSTALL_LIBDIR}/${module}.framework/Headers/") + list(APPEND interface_includes + "$<INSTALL_INTERFACE:${fw_headers_dir}${PROJECT_VERSION}>" + "$<INSTALL_INTERFACE:${fw_headers_dir}${PROJECT_VERSION}/${module}>") + else() + list(APPEND interface_includes + "$<INSTALL_INTERFACE:${INSTALL_INCLUDEDIR}/${module}/${PROJECT_VERSION}>" + "$<INSTALL_INTERFACE:${INSTALL_INCLUDEDIR}/${module}/${PROJECT_VERSION}/${module}>") + endif() + endif() + endif() + + if(NOT ${arg_NO_PRIVATE_MODULE}) + target_include_directories("${target_private}" INTERFACE ${interface_includes}) + endif() + + if(is_framework AND NOT is_interface_lib) + qt_finalize_framework_headers_copy(${target}) + endif() + + qt_describe_module(${target}) + +endfunction() + +function(qt_export_tools module_name) + # If no tools were defined belonging to this module, don't create a config and targets file. + # Guards against the case when doing a cross-build. + + if(NOT "${module_name}" IN_LIST QT_KNOWN_MODULES_WITH_TOOLS OR CMAKE_CROSSCOMPILING) + return() + endif() + + # The tools target name. For example: CoreTools + set(target "${module_name}Tools") + + set(path_suffix "${INSTALL_CMAKE_NAMESPACE}${target}") + qt_path_join(config_build_dir ${QT_CONFIG_BUILD_DIR} ${path_suffix}) + qt_path_join(config_install_dir ${QT_CONFIG_INSTALL_DIR} ${path_suffix}) + + # Add the extra cmake statements to make the tool targets global, so it doesn't matter where + # find_package is called. + # Also assemble a list of tool targets to expose in the config file for informational purposes. + set(extra_cmake_statements "") + set(tool_targets "") + set(tool_targets_non_prefixed "") + + # List of package dependencies that need be find_package'd when using the Tools package. + set(package_deps "") + + foreach(tool_name ${QT_KNOWN_MODULE_${module_name}_TOOLS}) + # Specific tools can have package dependencies. + # e.g. qtwaylandscanner depends on WaylandScanner (non-qt package). + get_target_property(extra_packages "${tool_name}" QT_EXTRA_PACKAGE_DEPENDENCIES) + if(extra_packages) + list(APPEND package_deps "${extra_packages}") + endif() + + set(extra_cmake_statements "${extra_cmake_statements} +if (NOT QT_NO_CREATE_TARGETS) + get_property(is_global TARGET ${INSTALL_CMAKE_NAMESPACE}::${tool_name} PROPERTY IMPORTED_GLOBAL) + if(NOT is_global) + set_property(TARGET ${INSTALL_CMAKE_NAMESPACE}::${tool_name} PROPERTY IMPORTED_GLOBAL TRUE) + endif() +endif() +") + list(APPEND tool_targets "${QT_CMAKE_EXPORT_NAMESPACE}::${tool_name}") + list(APPEND tool_targets_non_prefixed "${tool_name}") + endforeach() + + string(APPEND extra_cmake_statements +"set(${QT_CMAKE_EXPORT_NAMESPACE}${module_name}Tools_TARGETS \"${tool_targets}\")") + + # Extract package dependencies that were determined in QtPostProcess, but only if ${module_name} + # is an actual target. + # module_name can be a non-existent target, if the tool doesn't have an existing associated + # module, e.g. qtwaylandscanner. + if(TARGET "${module_name}") + get_target_property(module_package_deps "${module_name}" _qt_tools_package_deps) + if(module_package_deps) + list(APPEND package_deps "${module_package_deps}") + endif() + endif() + + # Configure and install dependencies file for the ${module_name}Tools package. + configure_file( + "${QT_CMAKE_DIR}/QtModuleToolsDependencies.cmake.in" + "${config_build_dir}/${INSTALL_CMAKE_NAMESPACE}${target}Dependencies.cmake" + @ONLY + ) + + qt_install(FILES + "${config_build_dir}/${INSTALL_CMAKE_NAMESPACE}${target}Dependencies.cmake" + DESTINATION "${config_install_dir}" + COMPONENT Devel + ) + + # Configure and install the ${module_name}Tools package Config file. + configure_package_config_file( + "${QT_CMAKE_DIR}/QtModuleToolsConfig.cmake.in" + "${config_build_dir}/${INSTALL_CMAKE_NAMESPACE}${target}Config.cmake" + INSTALL_DESTINATION "${config_install_dir}" + ) + write_basic_package_version_file( + "${config_build_dir}/${INSTALL_CMAKE_NAMESPACE}${target}ConfigVersion.cmake" + VERSION ${PROJECT_VERSION} + COMPATIBILITY AnyNewerVersion + ) + + qt_install(FILES + "${config_build_dir}/${INSTALL_CMAKE_NAMESPACE}${target}Config.cmake" + "${config_build_dir}/${INSTALL_CMAKE_NAMESPACE}${target}ConfigVersion.cmake" + DESTINATION "${config_install_dir}" + COMPONENT Devel + ) + + set(export_name "${INSTALL_CMAKE_NAMESPACE}${target}Targets") + qt_install(EXPORT "${export_name}" + NAMESPACE "${QT_CMAKE_EXPORT_NAMESPACE}::" + DESTINATION "${config_install_dir}") + + + # Create versionless targets file. + configure_file( + "${QT_CMAKE_DIR}/QtModuleToolsVersionlessTargets.cmake.in" + "${config_build_dir}/${INSTALL_CMAKE_NAMESPACE}${target}VersionlessTargets.cmake" + @ONLY + ) + + qt_install(FILES + "${config_build_dir}/${INSTALL_CMAKE_NAMESPACE}${target}VersionlessTargets.cmake" + DESTINATION "${config_install_dir}" + COMPONENT Devel + ) +endfunction() + +# This function records a dependency between ${target_name} and ${dep_package_name}. +# at the CMake package level. +# E.g. The Tools package that provides the qtwaylandscanner target +# needs to call find_package(WaylandScanner) (non-qt-package). +# main_target_name = qtwaylandscanner +# dep_package_name = WaylandScanner +function(qt_record_extra_package_dependency main_target_name dep_package_name dep_package_version) + get_target_property(extra_packages "${main_target_name}" QT_EXTRA_PACKAGE_DEPENDENCIES) + if(NOT extra_packages) + set(extra_packages "") + endif() + + list(APPEND extra_packages "${dep_package_name}\;${dep_package_version}") + set_target_properties("${main_target_name}" PROPERTIES QT_EXTRA_PACKAGE_DEPENDENCIES + "${extra_packages}") +endfunction() + +# This function records a dependency between ${main_target_name} and ${dep_target_name} +# at the CMake package level. +# E.g. Qt6CoreConfig.cmake needs to find_package(Qt6WinMain). +# main_target_name = Core +# dep_target_name = WinMain +# This is just a convenience function that deals with Qt targets and their associated packages +# instead of raw package names. +function(qt_record_extra_qt_package_dependency main_target_name dep_target_name + dep_package_version) + # WinMain -> Qt6WinMain. + qt_internal_module_info(qtfied_target_name "${dep_target_name}") + qt_record_extra_package_dependency("${main_target_name}" "${qtfied_target_name_versioned}" + "${dep_package_version}") +endfunction() + +function(qt_internal_check_directory_or_type name dir type default result_var) + if ("x${dir}" STREQUAL x) + if("x${type}" STREQUAL x) + message(FATAL_ERROR "qt_add_plugin called without setting either TYPE or ${name}.") + endif() + set(${result_var} "${default}" PARENT_SCOPE) + else() + set(${result_var} "${dir}" PARENT_SCOPE) + endif() +endfunction() + +# Utility function to find the module to which a plug-in belongs. +# This will set the QT_MODULE target property on the plug-in - e.g. "Gui", "Sql"... +function(qt_get_module_for_plugin target target_type) + qt_internal_get_qt_all_known_modules(known_modules) + + qt_get_sanitized_plugin_type("${target_type}" target_type) + foreach(qt_module ${known_modules}) + get_target_property(module_type "${QT_CMAKE_EXPORT_NAMESPACE}::${qt_module}" TYPE) + # Assuming interface libraries can't have plugins. Otherwise we'll need to fix the property + # name, because the current one would be invalid for interface libraries. + if(module_type STREQUAL "INTERFACE_LIBRARY") + continue() + endif() + + get_target_property(plugin_types + "${QT_CMAKE_EXPORT_NAMESPACE}::${qt_module}" + MODULE_PLUGIN_TYPES) + if(plugin_types) + foreach(plugin_type ${plugin_types}) + if("${target_type}" STREQUAL "${plugin_type}") + set_target_properties("${target}" PROPERTIES QT_MODULE "${qt_module}") + return() + endif() + endforeach() + endif() + endforeach() + message(AUTHOR_WARNING "The plug-in '${target}' does not belong to any Qt module.") +endfunction() + + +# Collection of qt_add_plugin arguments so they can be shared across different +# plugin type wrappers +set(__qt_add_plugin_optional_args + "STATIC;EXCEPTIONS;ALLOW_UNDEFINED_SYMBOLS" +) +set(__qt_add_plugin_single_args + "TYPE;CLASS_NAME;OUTPUT_DIRECTORY;INSTALL_DIRECTORY;ARCHIVE_INSTALL_DIRECTORY;QML_TARGET_PATH;OUTPUT_NAME" +) +set(__qt_add_plugin_multi_args + "${__default_private_args};${__default_public_args};DEFAULT_IF" +) +# This is the main entry point for defining Qt plugins. +# A CMake target is created with the given target. The TYPE parameter is needed to place the +# plugin into the correct plugins/ sub-directory. +function(qt_add_plugin target) + qt_internal_module_info(module "${target}") + + qt_internal_set_qt_known_plugins("${QT_KNOWN_PLUGINS}" "${target}") + + qt_parse_all_arguments(arg "qt_add_plugin" + "${__qt_add_plugin_optional_args};SKIP_INSTALL" + "${__qt_add_plugin_single_args}" + "${__qt_add_plugin_multi_args}" + "${ARGN}" + ) + + qt_get_sanitized_plugin_type("${arg_TYPE}" arg_TYPE) + + set(output_directory_default "${QT_BUILD_DIR}/${INSTALL_PLUGINSDIR}/${arg_TYPE}") + set(install_directory_default "${INSTALL_PLUGINSDIR}/${arg_TYPE}") + set(archive_install_directory_default "${INSTALL_LIBDIR}/${arg_TYPE}") + + if (arg_QML_TARGET_PATH) + set(target_path "${arg_QML_TARGET_PATH}") + set(output_directory_default "${QT_BUILD_DIR}/${INSTALL_QMLDIR}/${target_path}") + set(install_directory_default "${INSTALL_QMLDIR}/${target_path}") + set(archive_install_directory_default "${INSTALL_QMLDIR}/${target_path}") + endif() + + # Derive the class name from the target name if it's not explicitly specified. + # Don't set it for qml plugins though. + set(plugin_class_name "") + if (NOT arg_CLASS_NAME AND NOT "${arg_TYPE}" STREQUAL "qml_plugin") + set(plugin_class_name "${target}") + endif() + + qt_internal_check_directory_or_type(OUTPUT_DIRECTORY "${arg_OUTPUT_DIRECTORY}" "${arg_TYPE}" + "${output_directory_default}" output_directory) + if (NOT arg_SKIP_INSTALL) + qt_internal_check_directory_or_type(INSTALL_DIRECTORY "${arg_INSTALL_DIRECTORY}" "${arg_TYPE}" + "${install_directory_default}" install_directory) + if (NOT arg_ARCHIVE_INSTALL_DIRECTORY AND arg_INSTALL_DIRECTORY) + set(arg_ARCHIVE_INSTALL_DIRECTORY "${arg_INSTALL_DIRECTORY}") + endif() + endif() + + if(arg_STATIC OR NOT BUILD_SHARED_LIBS) + add_library("${target}" STATIC) + else() + add_library("${target}" MODULE) + if(APPLE) + # CMake defaults to using .so extensions for loadable modules, aka plugins, + # but Qt plugins are actually suffixed with .dylib. + set_property(TARGET "${target}" PROPERTY SUFFIX ".dylib") + endif() + endif() + + # Make sure the Qt6 plugin library names are like they were in Qt5 qmake land. + # Whereas the Qt6 CMake target names are like the Qt5 CMake target names. + set(output_name "${target}") + if(arg_OUTPUT_NAME) + set(output_name "${arg_OUTPUT_NAME}") + endif() + set_property(TARGET "${target}" PROPERTY OUTPUT_NAME "${output_name}") + + # Add a custom target with the Qt5 qmake name for a more user friendly ninja experience. + if(arg_OUTPUT_NAME AND NOT TARGET "${output_name}") + add_custom_target("${output_name}") + add_dependencies("${output_name}" "${target}") + endif() + + if (ANDROID) + qt_android_apply_arch_suffix("${target}") + set_target_properties(${target} + PROPERTIES + LIBRARY_OUTPUT_NAME "plugins_${arg_TYPE}_${output_name}" + ) + endif() + qt_internal_add_target_aliases("${target}") + qt_skip_warnings_are_errors_when_repo_unclean("${target}") + + # Disable linking of plugins against other plugins during static regular and + # super builds. The latter causes cyclic dependencies otherwise. + set_target_properties(${target} PROPERTIES QT_DEFAULT_PLUGINS 0) + + set_target_properties("${target}" PROPERTIES + LIBRARY_OUTPUT_DIRECTORY "${output_directory}" + RUNTIME_OUTPUT_DIRECTORY "${output_directory}" + ARCHIVE_OUTPUT_DIRECTORY "${output_directory}" + QT_PLUGIN_CLASS_NAME "${plugin_class_name}") + qt_handle_multi_config_output_dirs("${target}") + + qt_internal_library_deprecation_level(deprecation_define) + + qt_autogen_tools_initial_setup(${target}) + + set(static_plugin_define "") + if (arg_STATIC OR NOT QT_BUILD_SHARED_LIBS) + set(static_plugin_define "QT_STATICPLUGIN") + endif() + + # Save the Qt module in the plug-in's properties + if(NOT arg_TYPE STREQUAL "qml_plugin") + qt_get_module_for_plugin("${target}" "${arg_TYPE}") + get_target_property(qt_module "${target}" QT_MODULE) + endif() + + # Add the plug-in to the list of plug-ins of this module + if(TARGET "${qt_module}") + set_property(TARGET "${qt_module}" APPEND PROPERTY QT_PLUGINS "${target}") + endif() + + set(_default_plugin 1) + if (DEFINED arg_DEFAULT_IF) + if (NOT ${arg_DEFAULT_IF}) + set(_default_plugin 0) + endif() + endif() + + set_property(TARGET "${target}" PROPERTY QT_DEFAULT_PLUGIN "${_default_plugin}") + set_property(TARGET "${target}" APPEND PROPERTY EXPORT_PROPERTIES "QT_PLUGIN_CLASS_NAME;QT_PLUGIN_TYPE;QT_MODULE;QT_DEFAULT_PLUGIN") + + set(private_includes + "${CMAKE_CURRENT_SOURCE_DIR}" + "${CMAKE_CURRENT_BINARY_DIR}" + # For the syncqt headers + "$<BUILD_INTERFACE:${module_repo_include_dir}>" + ${arg_INCLUDE_DIRECTORIES} + ) + + set(public_includes + ${arg_PUBLIC_INCLUDE_DIRECTORIES} + ) + + qt_extend_target("${target}" + SOURCES ${arg_SOURCES} + INCLUDE_DIRECTORIES + ${private_includes} + PUBLIC_INCLUDE_DIRECTORIES + ${public_includes} + LIBRARIES ${arg_LIBRARIES} Qt::PlatformPluginInternal + PUBLIC_LIBRARIES ${arg_PUBLIC_LIBRARIES} + DEFINES + ${arg_DEFINES} + QT_DEPRECATED_WARNINGS + "${deprecation_define}" + "${static_plugin_define}" + QT_PLUGIN + PUBLIC_DEFINES + QT_${module_define}_LIB + ${arg_PUBLIC_DEFINES} + FEATURE_DEPENDENCIES ${arg_FEATURE_DEPENDENCIES} + DBUS_ADAPTOR_SOURCES "${arg_DBUS_ADAPTOR_SOURCES}" + DBUS_ADAPTOR_FLAGS "${arg_DBUS_ADAPTOR_FLAGS}" + DBUS_INTERFACE_SOURCES "${arg_DBUS_INTERFACE_SOURCES}" + DBUS_INTERFACE_FLAGS "${arg_DBUS_INTERFACE_FLAGS}" + COMPILE_OPTIONS ${arg_COMPILE_OPTIONS} + PUBLIC_COMPILE_OPTIONS ${arg_PUBLIC_COMPILE_OPTIONS} + LINK_OPTIONS ${arg_LINK_OPTIONS} + PUBLIC_LINK_OPTIONS ${arg_PUBLIC_LINK_OPTIONS} + MOC_OPTIONS ${arg_MOC_OPTIONS} + ENABLE_AUTOGEN_TOOLS ${arg_ENABLE_AUTOGEN_TOOLS} + DISABLE_AUTOGEN_TOOLS ${arg_DISABLE_AUTOGEN_TOOLS} + ) + if(NOT ${arg_EXCEPTIONS}) + qt_internal_set_no_exceptions_flags("${target}") + endif() + + + set(qt_libs_private "") + qt_internal_get_qt_all_known_modules(known_modules) + foreach(it ${known_modules}) + list(FIND arg_LIBRARIES "Qt::${it}Private" pos) + if(pos GREATER -1) + list(APPEND qt_libs_private "Qt::${it}Private") + endif() + endforeach() + + qt_register_target_dependencies("${target}" "${arg_PUBLIC_LIBRARIES}" "${qt_libs_private}") + + if (NOT arg_SKIP_INSTALL) + # Handle creation of cmake files for consumers of find_package(). + # If we are part of a Qt module, the plugin cmake files are installed as part of that module. + if(qt_module) + set(path_suffix "${INSTALL_CMAKE_NAMESPACE}${qt_module}") + else() + set(path_suffix "${INSTALL_CMAKE_NAMESPACE}${target}") + endif() + + qt_path_join(config_build_dir ${QT_CONFIG_BUILD_DIR} ${path_suffix}) + qt_path_join(config_install_dir ${QT_CONFIG_INSTALL_DIR} ${path_suffix}) + + configure_package_config_file( + "${QT_CMAKE_DIR}/QtPluginConfig.cmake.in" + "${config_build_dir}/${target}Config.cmake" + INSTALL_DESTINATION "${config_install_dir}" + ) + write_basic_package_version_file( + "${config_build_dir}/${target}ConfigVersion.cmake" + VERSION ${PROJECT_VERSION} + COMPATIBILITY AnyNewerVersion + ) + + qt_install(FILES + "${config_build_dir}/${target}Config.cmake" + "${config_build_dir}/${target}ConfigVersion.cmake" + DESTINATION "${config_install_dir}" + COMPONENT Devel + ) + + # Make the export name of plugins be consistent with modules, so that + # qt_add_resource adds its additional targets to the same export set in a static Qt build. + set(export_name "${INSTALL_CMAKE_NAMESPACE}${target}Targets") + qt_install(TARGETS "${target}" + EXPORT ${export_name} + RUNTIME DESTINATION "${install_directory}" + LIBRARY DESTINATION "${install_directory}" + ARCHIVE DESTINATION "${archive_install_directory}" + ) + qt_install(EXPORT ${export_name} + NAMESPACE ${QT_CMAKE_EXPORT_NAMESPACE}:: + DESTINATION "${config_install_dir}" + ) + endif() + + # Store the plug-in type in the target property + set_property(TARGET "${target}" PROPERTY QT_PLUGIN_TYPE "${arg_TYPE}") + + if (NOT arg_ALLOW_UNDEFINED_SYMBOLS) + ### fixme: cmake is missing a built-in variable for this. We want to apply it only to + # modules and plugins that belong to Qt. + qt_internal_add_link_flags_no_undefined("${target}") + endif() + + qt_internal_add_linker_version_script(${target}) +endfunction() + +function(qt_install_qml_files target) + + qt_parse_all_arguments(arg "qt_install_qml_files" + "" "" "FILES" ${ARGN} + ) + + if (NOT arg_FILES) + message(FATAL_ERROR "No files specified for qt_install_qml_files. Please specify them using the FILES parameter.") + endif() + + get_target_property(target_path ${target} QT_QML_MODULE_TARGET_PATH) + if (NOT target_path) + message(FATAL_ERROR "Target ${target} is not a qml module.") + endif() + + qt_path_join(qml_module_install_dir ${QT_INSTALL_DIR} "${INSTALL_QMLDIR}/${target_path}") + qt_copy_or_install(FILES ${arg_FILES} + DESTINATION ${qml_module_install_dir} + ) + +endfunction() + + +function(qt_add_resource target resourceName) + # Don't try to add resources when cross compiling, and the target is actually a host target + # (like a tool). + qt_is_imported_target("${target}" is_imported) + if(is_imported) + return() + endif() + + qt_parse_all_arguments(arg "qt_add_resource" "" "PREFIX;LANG;BASE" "FILES" ${ARGN}) + + QT6_PROCESS_RESOURCE(${target} ${resourceName} + PREFIX "${arg_PREFIX}" + LANG "${arg_LANG}" + BASE "${arg_BASE}" + FILES ${arg_FILES} + OUTPUT_TARGETS out_targets + ) + + if (out_targets) + qt_install(TARGETS ${out_targets} + EXPORT "${INSTALL_CMAKE_NAMESPACE}${target}Targets" + DESTINATION ${INSTALL_LIBDIR} + ) + endif() + +endfunction() + +# Collection of qt_add_executable arguments so they can be shared across qt_add_executable +# and qt_add_test_helper. +set(__qt_add_executable_optional_args + "GUI;BOOTSTRAP;NO_QT;NO_INSTALL;EXCEPTIONS" +) +set(__qt_add_executable_single_args + "OUTPUT_DIRECTORY;INSTALL_DIRECTORY;VERSION" +) +set(__qt_add_executable_multi_args + "EXE_FLAGS;${__default_private_args};${__default_public_args}" +) + +# This function creates a CMake target for a generic console or GUI binary. +# Please consider to use a more specific version target like the one created +# by qt_add_test or qt_add_tool below. +function(qt_add_executable name) + qt_parse_all_arguments(arg "qt_add_executable" + "${__qt_add_executable_optional_args}" + "${__qt_add_executable_single_args}" + "${__qt_add_executable_multi_args}" + ${ARGN}) + + if ("x${arg_OUTPUT_DIRECTORY}" STREQUAL "x") + set(arg_OUTPUT_DIRECTORY "${QT_BUILD_DIR}/${INSTALL_BINDIR}") + endif() + + get_filename_component(arg_OUTPUT_DIRECTORY "${arg_OUTPUT_DIRECTORY}" + ABSOLUTE BASE_DIR "${QT_BUILD_DIR}") + + if ("x${arg_INSTALL_DIRECTORY}" STREQUAL "x") + set(arg_INSTALL_DIRECTORY "${INSTALL_BINDIR}") + endif() + + if (ANDROID) + add_library("${name}" MODULE) + qt_android_apply_arch_suffix("${name}") + qt_android_generate_deployment_settings("${name}") + qt_android_add_apk_target("${name}") + # On our qmake builds we don't compile the executables with + # visibility=hidden. Not having this flag set will cause the + # executable to have main() hidden and can then no longer be loaded + # through dlopen() + set_property(TARGET ${name} PROPERTY C_VISIBILITY_PRESET default) + set_property(TARGET ${name} PROPERTY CXX_VISIBILITY_PRESET default) + else() + add_executable("${name}" ${arg_EXE_FLAGS}) + endif() + + if (arg_VERSION) + + if(arg_VERSION MATCHES "[0-9]+\\.[0-9]+\\.[0-9]+\\.[0-9]+") + # nothing to do + elseif(arg_VERSION MATCHES "[0-9]+\\.[0-9]+\\.[0-9]+") + set(arg_VERSION "${arg_VERSION}.0") + elseif(arg_VERSION MATCHES "[0-9]+\\.[0-9]+") + set(arg_VERSION "${arg_VERSION}.0.0") + elseif (arg_VERSION MATCHES "[0-9]+") + set(arg_VERSION "${arg_VERSION}.0.0.0") + else() + message(FATAL_ERROR "Invalid version format") + endif() + + set_target_properties(${name} PROPERTIES QT_TARGET_VERSION "${arg_VERSION}") + endif() + + if (WIN32) + qt6_generate_win32_rc_file(${name}) + endif() + + qt_autogen_tools_initial_setup(${name}) + qt_skip_warnings_are_errors_when_repo_unclean("${name}") + + set(extra_libraries "") + if(NOT arg_BOOTSTRAP AND NOT arg_NO_QT) + set(extra_libraries "Qt::Core") + endif() + + set(private_includes + "${CMAKE_CURRENT_SOURCE_DIR}" + "${CMAKE_CURRENT_BINARY_DIR}" + ${arg_INCLUDE_DIRECTORIES} + ) + + qt_extend_target("${name}" + SOURCES ${arg_SOURCES} + INCLUDE_DIRECTORIES ${private_includes} + DEFINES ${arg_DEFINES} + LIBRARIES ${arg_LIBRARIES} Qt::PlatformCommonInternal + PUBLIC_LIBRARIES ${extra_libraries} ${arg_PUBLIC_LIBRARIES} + DBUS_ADAPTOR_SOURCES "${arg_DBUS_ADAPTOR_SOURCES}" + DBUS_ADAPTOR_FLAGS "${arg_DBUS_ADAPTOR_FLAGS}" + DBUS_INTERFACE_SOURCES "${arg_DBUS_INTERFACE_SOURCES}" + DBUS_INTERFACE_FLAGS "${arg_DBUS_INTERFACE_FLAGS}" + COMPILE_OPTIONS ${arg_COMPILE_OPTIONS} + LINK_OPTIONS ${arg_LINK_OPTIONS} + MOC_OPTIONS ${arg_MOC_OPTIONS} + ENABLE_AUTOGEN_TOOLS ${arg_ENABLE_AUTOGEN_TOOLS} + DISABLE_AUTOGEN_TOOLS ${arg_DISABLE_AUTOGEN_TOOLS} + ) + set_target_properties("${name}" PROPERTIES + RUNTIME_OUTPUT_DIRECTORY "${arg_OUTPUT_DIRECTORY}" + LIBRARY_OUTPUT_DIRECTORY "${arg_OUTPUT_DIRECTORY}" + WIN32_EXECUTABLE "${arg_GUI}" + MACOSX_BUNDLE "${arg_GUI}" + ) + if(NOT ${arg_EXCEPTIONS}) + qt_internal_set_no_exceptions_flags("${name}") + endif() + + + if(NOT arg_NO_INSTALL) + qt_install(TARGETS "${name}" + RUNTIME DESTINATION "${arg_INSTALL_DIRECTORY}" + LIBRARY DESTINATION "${arg_INSTALL_DIRECTORY}" + BUNDLE DESTINATION "${arg_INSTALL_DIRECTORY}") + endif() +endfunction() + +# Simple wrapper around qt_add_executable for benchmarks which insure that +# the binary is built under ${CMAKE_CURRENT_BINARY_DIR} and never installed. +# See qt_add_executable() for more details. +function(qt_add_benchmark target) + + qt_parse_all_arguments(arg "qt_add_benchmark" + "${__qt_add_executable_optional_args}" + "${__qt_add_executable_single_args}" + "${__qt_add_executable_multi_args}" + ${ARGN} + ) + + qt_remove_args(exec_args + ARGS_TO_REMOVE + ${target} + OUTPUT_DIRECTORY + INSTALL_DIRECTORY + ALL_ARGS + "${__qt_add_executable_optional_args}" + "${__qt_add_executable_single_args}" + "${__qt_add_executable_multi_args}" + ARGS + ${ARGV} + ) + + qt_add_executable(${target} + NO_INSTALL # we don't install benchmarks + OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}" # avoid polluting bin directory + ${exec_args} + ) + +endfunction() + +# Simple wrapper around qt_add_executable for manual tests which insure that +# the binary is built under ${CMAKE_CURRENT_BINARY_DIR} and never installed. +# See qt_add_executable() for more details. +function(qt_add_manual_test target) + + qt_parse_all_arguments(arg "qt_add_manual_test" + "${__qt_add_executable_optional_args}" + "${__qt_add_executable_single_args}" + "${__qt_add_executable_multi_args}" + ${ARGN} + ) + + qt_remove_args(exec_args + ARGS_TO_REMOVE + ${target} + OUTPUT_DIRECTORY + INSTALL_DIRECTORY + ALL_ARGS + "${__qt_add_executable_optional_args}" + "${__qt_add_executable_single_args}" + "${__qt_add_executable_multi_args}" + ARGS + ${ARGV} + ) + + qt_add_executable(${target} + NO_INSTALL # we don't install benchmarks + OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}" # avoid polluting bin directory + ${exec_args} + ) + +endfunction() + + +# This function creates a CMake test target with the specified name for use with CTest. +function(qt_add_test name) + qt_parse_all_arguments(arg "qt_add_test" + "RUN_SERIAL;EXCEPTIONS;GUI;QMLTEST" + "OUTPUT_DIRECTORY;WORKING_DIRECTORY;TIMEOUT;VERSION" + "QML_IMPORTPATH;TESTDATA;${__default_private_args};${__default_public_args}" ${ARGN} + ) + + if (NOT arg_OUTPUT_DIRECTORY) + set(arg_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}") + endif() + + if (${arg_EXCEPTIONS}) + set(exceptions_text "EXCEPTIONS") + endif() + + if (${arg_GUI}) + set(gui_text "GUI") + endif() + + if (arg_VERSION) + set(version_arg VERSION "${arg_VERSION}") + endif() + + # Handle cases where we have a qml test without source files + if (arg_SOURCES) + set(private_includes + "${CMAKE_CURRENT_SOURCE_DIR}" + "${CMAKE_CURRENT_BINARY_DIR}" + "$<BUILD_INTERFACE:${QT_BUILD_DIR}/${INSTALL_INCLUDEDIR}>" + ${arg_INCLUDE_DIRECTORIES} + ) + + qt_add_executable("${name}" + ${exceptions_text} + ${gui_text} + ${version_arg} + NO_INSTALL + OUTPUT_DIRECTORY "${arg_OUTPUT_DIRECTORY}" + SOURCES "${arg_SOURCES}" + INCLUDE_DIRECTORIES + ${private_includes} + DEFINES + QT_TESTCASE_BUILDDIR="${CMAKE_CURRENT_BINARY_DIR}" + QT_TESTCASE_SOURCEDIR="${CMAKE_CURRENT_SOURCE_DIR}" + ${arg_DEFINES} + PUBLIC_LIBRARIES ${QT_CMAKE_EXPORT_NAMESPACE}::Core ${QT_CMAKE_EXPORT_NAMESPACE}::Test ${arg_PUBLIC_LIBRARIES} + LIBRARIES ${arg_LIBRARIES} + COMPILE_OPTIONS ${arg_COMPILE_OPTIONS} + LINK_OPTIONS ${arg_LINK_OPTIONS} + MOC_OPTIONS ${arg_MOC_OPTIONS} + ENABLE_AUTOGEN_TOOLS ${arg_ENABLE_AUTOGEN_TOOLS} + DISABLE_AUTOGEN_TOOLS ${arg_DISABLE_AUTOGEN_TOOLS} + ) + + # Tests should not be bundles on macOS even if arg_GUI is true, because some tests make + # assumptions about the location of helper processes, and those paths would be different + # if a test is built as a bundle. + set_property(TARGET "${name}" PROPERTY MACOSX_BUNDLE FALSE) + # The same goes for WIN32_EXECUTABLE, but because it will detach from the console window + # and not print anything. + set_property(TARGET "${name}" PROPERTY WIN32_EXECUTABLE FALSE) + + # QMLTest specifics + + qt_extend_target("${name}" CONDITION arg_QMLTEST + PUBLIC_LIBRARIES ${QT_CMAKE_EXPORT_NAMESPACE}::QuickTest + ) + + qt_extend_target("${name}" CONDITION arg_QMLTEST AND NOT ANDROID + DEFINES + QUICK_TEST_SOURCE_DIR="${CMAKE_CURRENT_SOURCE_DIR}" + ) + + qt_extend_target("${name}" CONDITION arg_QMLTEST AND ANDROID + DEFINES + QUICK_TEST_SOURCE_DIR=":/" + ) + endif() + + foreach(path IN LISTS arg_QML_IMPORTPATH) + list(APPEND extra_test_args "-import" "${path}") + endforeach() + + # Generate a label in the form tests/auto/foo/bar/tst_baz + # and use it also for XML output + file(RELATIVE_PATH label "${PROJECT_SOURCE_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}/${name}") + + if (ANDROID) + qt_android_add_test("${name}") + else() + if(arg_QMLTEST AND NOT arg_SOURCES) + set(test_working_dir "${CMAKE_CURRENT_SOURCE_DIR}") + set(test_executable ${QT_CMAKE_EXPORT_NAMESPACE}::qmltestrunner) + else() + if (arg_WORKING_DIRECTORY) + set(test_working_dir "${arg_WORKING_DIRECTORY}") + elseif(arg_OUTPUT_DIRECTORY) + set(test_working_dir "${arg_OUTPUT_DIRECTORY}") + else() + set(test_working_dir "${CMAKE_CURRENT_BINARY_DIR}") + endif() + set(test_executable "${name}") + endif() + + add_test(NAME "${name}" COMMAND ${test_executable} ${extra_test_args} -o ${name}.xml,xml -o -,txt WORKING_DIRECTORY "${test_working_dir}") + endif() + set_tests_properties("${name}" PROPERTIES RUN_SERIAL "${arg_RUN_SERIAL}" LABELS "${label}") + if (arg_TIMEOUT) + set_tests_properties(${name} PROPERTIES TIMEOUT ${arg_TIMEOUT}) + endif() + # Get path to qtbase/bin, then prepend this path containing the shared libraries to PATH + set(INSTALL_PREFIX_BIN "${CMAKE_INSTALL_PREFIX}/${INSTALL_BINDIR}") + set(test_env_path "PATH=${CMAKE_CURRENT_BINARY_DIR}${QT_PATH_SEPARATOR}${INSTALL_PREFIX_BIN}${QT_PATH_SEPARATOR}$ENV{PATH}") + string(REPLACE ";" "\;" test_env_path "${test_env_path}") + set_property(TEST "${name}" APPEND PROPERTY ENVIRONMENT "${test_env_path}") + set_property(TEST "${name}" APPEND PROPERTY ENVIRONMENT "QT_TEST_RUNNING_IN_CTEST=1") + + # Add the install prefix to list of plugin paths when doing a prefix build + if(NOT QT_INSTALL_DIR) + list(APPEND plugin_paths "${CMAKE_INSTALL_PREFIX}/${INSTALL_PLUGINSDIR}") + endif() + #TODO: Collect all paths from known repositories when performing a super + # build. + list(APPEND plugin_paths "${PROJECT_BINARY_DIR}/${INSTALL_PLUGINSDIR}") + list(JOIN plugin_paths "${QT_PATH_SEPARATOR}" plugin_paths_joined) + set_property(TEST "${name}" APPEND PROPERTY ENVIRONMENT "QT_PLUGIN_PATH=${plugin_paths_joined}") + + if(ANDROID OR IOS OR WINRT) + set(builtin_testdata TRUE) + endif() + + if(builtin_testdata) + # Safe guard against qml only tests, no source files == no target + if (TARGET "${name}") + target_compile_definitions("${name}" PRIVATE BUILTIN_TESTDATA) + + foreach(testdata IN LISTS arg_TESTDATA) + list(APPEND builtin_files ${testdata}) + endforeach() + + set(blacklist_path "BLACKLIST") + if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/${blacklist_path}") + list(APPEND builtin_files ${blacklist_path}) + endif() + + list(REMOVE_DUPLICATES builtin_files) + + # Skip Qt quick compiler when embedding test resources + foreach(file IN LISTS builtin_files) + set_source_files_properties(${file} + PROPERTIES QT_SKIP_QUICKCOMPILER TRUE + ) + endforeach() + + if (builtin_files) + qt_add_resource(${name} "${name}_testdata_builtin" + PREFIX "/" + FILES ${builtin_files} + BASE ${CMAKE_CURRENT_SOURCE_DIR}) + endif() + endif() + else() + # Install test data + file(RELATIVE_PATH relative_path_to_test_project + "${QT_TOP_LEVEL_SOURCE_DIR}" + "${CMAKE_CURRENT_SOURCE_DIR}") + qt_path_join(testdata_install_dir ${QT_INSTALL_DIR} + "${relative_path_to_test_project}") + foreach(testdata IN LISTS arg_TESTDATA) + set(testdata "${CMAKE_CURRENT_SOURCE_DIR}/${testdata}") + if (IS_DIRECTORY "${testdata}") + qt_install( + DIRECTORY "${testdata}" + DESTINATION "${testdata_install_dir}") + else() + qt_install( + FILES "${testdata}" + DESTINATION "${testdata_install_dir}") + endif() + endforeach() + endif() + +endfunction() + + +# This function creates an executable for use as a helper program with tests. Some +# tests launch separate programs to test certain input/output behavior. +# Specify OVERRIDE_OUTPUT_DIRECTORY if you dont' want to place the helper in the parent directory, +# in which case you should specify OUTPUT_DIRECTORY "/foo/bar" manually. +function(qt_add_test_helper name) + + set(qt_add_test_helper_optional_args + "OVERRIDE_OUTPUT_DIRECTORY" + ) + + qt_parse_all_arguments(arg "qt_add_test_helper" + "${qt_add_test_helper_optional_args};${__qt_add_executable_optional_args}" + "${__qt_add_executable_single_args}" + "${__qt_add_executable_multi_args}" + ${ARGN}) + + qt_remove_args(forward_args + ARGS_TO_REMOVE + "${name}" + ${qt_add_test_helper_optional_args} + ALL_ARGS + ${qt_add_test_helper_optional_args} + ${__qt_add_executable_optional_args} + ${__qt_add_executable_single_args} + ${__qt_add_executable_multi_args} + ARGS + ${ARGV} + ) + + set(extra_args_to_pass) + if(NOT arg_OVERRIDE_OUTPUT_DIRECTORY) + set(extra_args_to_pass OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/..") + endif() + + qt_add_executable("${name}" NO_INSTALL ${extra_args_to_pass} ${forward_args}) +endfunction() + +# Sets QT_WILL_BUILD_TOOLS if tools will be built. +function(qt_check_if_tools_will_be_built) + if(NOT CMAKE_CROSSCOMPILING AND NOT QT_FORCE_FIND_TOOLS) + set(will_build_tools TRUE) + else() + set(will_build_tools FALSE) + endif() + set(QT_WILL_BUILD_TOOLS ${will_build_tools} CACHE INTERNAL "Are tools going to be built" FORCE) +endfunction() + +# Wrapper function to create a regular cmake target and forward all the +# arguments collected by the conversion script. This is only meant for tests! +function(qt_add_cmake_library target) + # Process arguments: + qt_parse_all_arguments(arg "qt_add_cmake_library" + "SHARED;MODULE;STATIC;INTERFACE" + "OUTPUT_DIRECTORY;ARCHIVE_INSTALL_DIRECTORY;INSTALL_DIRECTORY" + "${__default_private_args};${__default_public_args}" + ${ARGN} + ) + + ### Define Targets: + if(${arg_INTERFACE}) + add_library("${target}" INTERFACE) + elseif(${arg_STATIC} OR (${arg_MODULE} AND NOT BUILD_SHARED_LIBS)) + add_library("${target}" STATIC) + elseif(${arg_SHARED}) + add_library("${target}" SHARED) + elseif(${arg_MODULE}) + add_library("${target}" MODULE) + set_property(TARGET ${name} PROPERTY C_VISIBILITY_PRESET default) + set_property(TARGET ${name} PROPERTY CXX_VISIBILITY_PRESET default) + + if(APPLE) + # CMake defaults to using .so extensions for loadable modules, aka plugins, + # but Qt plugins are actually suffixed with .dylib. + set_property(TARGET "${target}" PROPERTY SUFFIX ".dylib") + endif() + else() + add_library("${target}") + endif() + + if (NOT arg_ARCHIVE_INSTALL_DIRECTORY AND arg_INSTALL_DIRECTORY) + set(arg_ARCHIVE_INSTALL_DIRECTORY "${arg_INSTALL_DIRECTORY}") + endif() + + if (ANDROID) + qt_android_apply_arch_suffix("${target}") + endif() + qt_skip_warnings_are_errors_when_repo_unclean("${target}") + + if (arg_INSTALL_DIRECTORY) + set(install_arguments + ARCHIVE_INSTALL_DIRECTORY ${arg_ARCHIVE_INSTALL_DIRECTORY} + INSTALL_DIRECTORY ${arg_INSTALL_DIRECTORY} + ) + endif() + + if (arg_OUTPUT_DIRECTORY) + set_target_properties(${target} PROPERTIES + ARCHIVE_OUTPUT_DIRECTORY ${arg_OUTPUT_DIRECTORY} + RUNTIME_OUTPUT_DIRECTORY ${arg_OUTPUT_DIRECTORY} + LIBRARY_OUTPUT_DIRECTORY ${arg_OUTPUT_DIRECTORY} + ) + endif() + + qt_extend_target("${target}" + SOURCES ${arg_SOURCES} + INCLUDE_DIRECTORIES + ${arg_INCLUDE_DIRECTORIES} + PUBLIC_INCLUDE_DIRECTORIES + ${arg_PUBLIC_INCLUDE_DIRECTORIES} + PUBLIC_DEFINES + ${arg_PUBLIC_DEFINES} + DEFINES + ${arg_DEFINES} + PUBLIC_LIBRARIES ${arg_PUBLIC_LIBRARIES} + LIBRARIES ${arg_LIBRARIES} Qt::PlatformModuleInternal + COMPILE_OPTIONS ${arg_COMPILE_OPTIONS} + PUBLIC_COMPILE_OPTIONS ${arg_PUBLIC_COMPILE_OPTIONS} + LINK_OPTIONS ${arg_LINK_OPTIONS} + PUBLIC_LINK_OPTIONS ${arg_PUBLIC_LINK_OPTIONS} + MOC_OPTIONS ${arg_MOC_OPTIONS} + ENABLE_AUTOGEN_TOOLS ${arg_ENABLE_AUTOGEN_TOOLS} + DISABLE_AUTOGEN_TOOLS ${arg_DISABLE_AUTOGEN_TOOLS} + ${install_arguments} + ) + +endfunction() + +# +# This function replaces qmake's qt_helper_lib feature. It is intended to +# compile 3rdparty libraries as part of the build. +# +function(qt_add_3rdparty_library target) + # Process arguments: + qt_parse_all_arguments(arg "qt_add_3rdparty_library" + "SHARED;MODULE;STATIC;INTERFACE;EXCEPTIONS;INSTALL" + "OUTPUT_DIRECTORY" + "${__default_private_args};${__default_public_args}" + ${ARGN} + ) + + ### Define Targets: + if(${arg_INTERFACE}) + add_library("${target}" INTERFACE) + elseif(${arg_STATIC} OR (${arg_MODULE} AND NOT BUILD_SHARED_LIBS)) + add_library("${target}" STATIC) + elseif(${arg_SHARED}) + add_library("${target}" SHARED) + elseif(${arg_MODULE}) + add_library("${target}" MODULE) + set_property(TARGET ${name} PROPERTY C_VISIBILITY_PRESET default) + set_property(TARGET ${name} PROPERTY CXX_VISIBILITY_PRESET default) + + if(APPLE) + # CMake defaults to using .so extensions for loadable modules, aka plugins, + # but Qt plugins are actually suffixed with .dylib. + set_property(TARGET "${target}" PROPERTY SUFFIX ".dylib") + endif() + else() + add_library("${target}") + endif() + + if (NOT arg_ARCHIVE_INSTALL_DIRECTORY AND arg_INSTALL_DIRECTORY) + set(arg_ARCHIVE_INSTALL_DIRECTORY "${arg_INSTALL_DIRECTORY}") + endif() + + qt_internal_add_qt_repo_known_module(${target}) + qt_internal_add_target_aliases(${target}) + + if (ANDROID) + qt_android_apply_arch_suffix("${target}") + endif() + + qt_skip_warnings_are_errors_when_repo_unclean("${target}") + + if(NOT arg_HEADER_MODULE) + set_target_properties(${target} PROPERTIES + LIBRARY_OUTPUT_DIRECTORY "${QT_BUILD_DIR}/${INSTALL_LIBDIR}" + RUNTIME_OUTPUT_DIRECTORY "${QT_BUILD_DIR}/${INSTALL_BINDIR}" + ARCHIVE_OUTPUT_DIRECTORY "${QT_BUILD_DIR}/${INSTALL_LIBDIR}" + VERSION ${PROJECT_VERSION} + SOVERSION ${PROJECT_VERSION_MAJOR} + QT_MODULE_IS_3RDPARTY_LIBRARY TRUE + ) + qt_handle_multi_config_output_dirs("${target}") + + set_target_properties(${target} PROPERTIES + OUTPUT_NAME "${INSTALL_CMAKE_NAMESPACE}${target}" + ) + endif() + + if(NOT arg_INTERFACE) + # This property is used for super builds with static libraries. We use + # it in QtPlugins.cmake.in to avoid "polluting" the dependency chain + # for the target in it's project directory. + # E.g: When we process find_package(Qt6 ... Gui) in QtDeclarative, the + # rules in QtPugins.cmake add all the known Gui plugins as interface + # dependencies. This in turn causes circular dependencies on every + # plugin which links against Gui. Plugin A -> GUI -> Plugin A .... + set_target_properties(${target} PROPERTIES QT_BUILD_PROJECT_NAME ${PROJECT_NAME}) + endif() + + if(NOT arg_EXCEPTIONS AND NOT arg_INTERFACE) + qt_internal_set_no_exceptions_flags("${target}") + endif() + + qt_extend_target("${target}" + SOURCES ${arg_SOURCES} + INCLUDE_DIRECTORIES + ${arg_INCLUDE_DIRECTORIES} + PUBLIC_INCLUDE_DIRECTORIES + ${arg_PUBLIC_INCLUDE_DIRECTORIES} + PUBLIC_DEFINES + ${arg_PUBLIC_DEFINES} + DEFINES + ${arg_DEFINES} + PUBLIC_LIBRARIES ${arg_PUBLIC_LIBRARIES} + LIBRARIES ${arg_LIBRARIES} + COMPILE_OPTIONS ${arg_COMPILE_OPTIONS} + PUBLIC_COMPILE_OPTIONS ${arg_PUBLIC_COMPILE_OPTIONS} + LINK_OPTIONS ${arg_LINK_OPTIONS} + PUBLIC_LINK_OPTIONS ${arg_PUBLIC_LINK_OPTIONS} + MOC_OPTIONS ${arg_MOC_OPTIONS} + ENABLE_AUTOGEN_TOOLS ${arg_ENABLE_AUTOGEN_TOOLS} + DISABLE_AUTOGEN_TOOLS ${arg_DISABLE_AUTOGEN_TOOLS} + ${install_arguments} + ) + + if(NOT BUILD_SHARED_LIBS OR arg_INSTALL) + set(path_suffix "${INSTALL_CMAKE_NAMESPACE}${target}") + qt_path_join(config_build_dir ${QT_CONFIG_BUILD_DIR} ${path_suffix}) + qt_path_join(config_install_dir ${QT_CONFIG_INSTALL_DIR} ${path_suffix}) + set(export_name "${INSTALL_CMAKE_NAMESPACE}${target}Targets") + + configure_package_config_file( + "${QT_CMAKE_DIR}/Qt3rdPartyLibraryConfig.cmake.in" + "${config_build_dir}/${INSTALL_CMAKE_NAMESPACE}${target}Config.cmake" + INSTALL_DESTINATION "${config_install_dir}" + ) + + write_basic_package_version_file( + "${config_build_dir}/${INSTALL_CMAKE_NAMESPACE}${target}ConfigVersion.cmake" + VERSION ${PROJECT_VERSION} + COMPATIBILITY AnyNewerVersion + ) + + qt_install(FILES + "${config_build_dir}/${INSTALL_CMAKE_NAMESPACE}${target}Config.cmake" + "${config_build_dir}/${INSTALL_CMAKE_NAMESPACE}${target}ConfigVersion.cmake" + DESTINATION "${config_install_dir}" + COMPONENT Devel + ) + + qt_install(TARGETS ${target} + EXPORT "${export_name}" + RUNTIME DESTINATION ${INSTALL_BINDIR} + LIBRARY DESTINATION ${INSTALL_LIBDIR} + ARCHIVE DESTINATION ${INSTALL_LIBDIR} + ) + + qt_install(EXPORT ${export_name} + NAMESPACE "${QT_CMAKE_EXPORT_NAMESPACE}::" + DESTINATION "${config_install_dir}" + ) + + qt_internal_export_modern_cmake_config_targets_file( + TARGETS ${target} + EXPORT_NAME_PREFIX ${INSTALL_CMAKE_NAMESPACE}${target} + CONFIG_INSTALL_DIR "${config_install_dir}" + ) + endif() +endfunction() + +function(qt_get_tool_cmake_configuration out_var) + qt_get_main_cmake_configuration("${out_var}") + string(TOUPPER "${${out_var}}" upper_config) + set("${out_var}" "${upper_config}" PARENT_SCOPE) +endfunction() + +function(qt_get_main_cmake_configuration out_var) + if(CMAKE_BUILD_TYPE) + set(config "${CMAKE_BUILD_TYPE}") + elseif(QT_MULTI_CONFIG_FIRST_CONFIG) + set(config "${QT_MULTI_CONFIG_FIRST_CONFIG}") + endif() + set("${out_var}" "${config}" PARENT_SCOPE) +endfunction() + +# This function is used to define a "Qt tool", such as moc, uic or rcc. +# The BOOTSTRAP option allows building it as standalone program, otherwise +# it will be linked against QtCore. +function(qt_add_tool name) + qt_parse_all_arguments(arg "qt_add_tool" "BOOTSTRAP;NO_QT;NO_INSTALL" "TOOLS_TARGET" + "${__default_private_args}" ${ARGN}) + + # Handle case when a tool does not belong to a module and it can't be built either (like + # during a cross-compile). + if(NOT arg_TOOLS_TARGET AND NOT QT_WILL_BUILD_TOOLS) + message(FATAL_ERROR "The tool \"${name}\" has not been assigned to a module via" + " TOOLS_TARGET (so it can't be found) and it can't be built" + " (QT_WILL_BUILD_TOOLS is ${QT_WILL_BUILD_TOOLS}).") + endif() + + set(full_name "${QT_CMAKE_EXPORT_NAMESPACE}::${name}") + if(TARGET ${full_name}) + get_property(path TARGET ${full_name} PROPERTY LOCATION) + message(STATUS "Tool '${full_name}' was found at ${path}.") + return() + endif() + + if(arg_TOOLS_TARGET AND NOT QT_WILL_BUILD_TOOLS) + set(tools_package_name "Qt6${arg_TOOLS_TARGET}Tools") + message(STATUS "Searching for tool '${full_name}' in package ${tools_package_name}.") + + # Only search in path provided by QT_HOST_PATH. We need to do it with CMAKE_PREFIX_PATH + # instead of PATHS option, because any find_dependency call inside a Tools package would + # not get the proper prefix when using PATHS. + set(BACKUP_CMAKE_PREFIX_PATH ${CMAKE_PREFIX_PATH}) + set(CMAKE_PREFIX_PATH "${QT_HOST_PATH}") + + # Search both with sysroots prepended as well as in the host system. When cross compiling + # the mode_package might be set to ONLY only, and the Qt6 tools packages are actually + # in the host system. + set(BACKUP_CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ${CMAKE_FIND_ROOT_PATH_MODE_PACKAGE}) + set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE "BOTH") + set(BACKUP_CMAKE_SIZEOF_VOID_P "${CMAKE_SIZEOF_VOID_P}") + set(CMAKE_SIZEOF_VOID_P "") + find_package( + ${tools_package_name} + ${PROJECT_VERSION} + NO_PACKAGE_ROOT_PATH + NO_CMAKE_ENVIRONMENT_PATH + NO_SYSTEM_ENVIRONMENT_PATH + NO_CMAKE_PACKAGE_REGISTRY + NO_CMAKE_SYSTEM_PATH + NO_CMAKE_SYSTEM_PACKAGE_REGISTRY) + set(CMAKE_SIZEOF_VOID_P "${BACKUP_CMAKE_SIZEOF_VOID_P}") + set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE "${BACKUP_CMAKE_FIND_ROOT_PATH_MODE_PACKAGE}") + set(CMAKE_PREFIX_PATH "${BACKUP_CMAKE_PREFIX_PATH}") + + if(${${tools_package_name}_FOUND} AND TARGET ${full_name}) + # Even if the tool is already visible, make sure that our modules remain associated + # with the tools. + qt_internal_append_known_modules_with_tools("${arg_TOOLS_TARGET}") + get_property(path TARGET ${full_name} PROPERTY LOCATION) + message(STATUS "${full_name} was found at ${path} using package ${tools_package_name}.") + return() + endif() + endif() + + if(NOT QT_WILL_BUILD_TOOLS) + message(FATAL_ERROR "The tool \"${full_name}\" was not found in the " + "${tools_package_name} package. " + "Package found: ${${tools_package_name}_FOUND}") + else() + message(STATUS "Tool '${full_name}' will be built from source.") + endif() + + set(disable_autogen_tools "${arg_DISABLE_AUTOGEN_TOOLS}") + if (arg_NO_QT) + # FIXME: Remove NO_QT again once qmake can use a "normal" Qt! + if (arg_BOOTSTRAP) + message(FATAL_ERROR "Tool can not be NO_QT and BOOTSTRAP at the same time!") + endif() + set(corelib "") + else() + if (arg_BOOTSTRAP) + set(corelib ${QT_CMAKE_EXPORT_NAMESPACE}::Bootstrap) + list(APPEND disable_autogen_tools "uic" "moc" "rcc") + else() + set(corelib ${QT_CMAKE_EXPORT_NAMESPACE}::Core) + endif() + endif() + + set(bootstrap "") + if(arg_BOOTSTRAP) + set(bootstrap BOOTSTRAP) + endif() + + set(no_qt "") + if(arg_NO_QT) + set(no_qt NO_QT) + endif() + + set(no_install "") + if(arg_NO_INSTALL) + set(no_install NO_INSTALL) + endif() + + qt_add_executable("${name}" OUTPUT_DIRECTORY "${QT_BUILD_DIR}/${INSTALL_BINDIR}" + ${bootstrap} + ${no_qt} + ${no_install} + SOURCES ${arg_SOURCES} + INCLUDE_DIRECTORIES + ${arg_INCLUDE_DIRECTORIES} + DEFINES ${arg_DEFINES} + PUBLIC_LIBRARIES ${corelib} + LIBRARIES ${arg_LIBRARIES} Qt::PlatformToolInternal + COMPILE_OPTIONS ${arg_COMPILE_OPTIONS} + LINK_OPTIONS ${arg_LINK_OPTIONS} + MOC_OPTIONS ${arg_MOC_OPTIONS} + DISABLE_AUTOGEN_TOOLS ${disable_autogen_tools} + ) + qt_internal_add_target_aliases("${name}") + + # If building with a multi-config configuration, the main configuration tool will be placed in + # ./bin, while the rest will be in <CONFIG> specific subdirectories. + qt_get_tool_cmake_configuration(tool_cmake_configuration) + set_target_properties("${name}" PROPERTIES + RUNTIME_OUTPUT_DIRECTORY_${tool_cmake_configuration} "${QT_BUILD_DIR}/${INSTALL_BINDIR}" + ) + + if(NOT arg_NO_INSTALL AND arg_TOOLS_TARGET) + # Assign a tool to an export set, and mark the module to which the tool belongs. + qt_internal_append_known_modules_with_tools("${arg_TOOLS_TARGET}") + + # Also append the tool to the module list. + qt_internal_append_known_module_tool("${arg_TOOLS_TARGET}" "${name}") + + qt_install(TARGETS "${name}" + EXPORT "${INSTALL_CMAKE_NAMESPACE}${arg_TOOLS_TARGET}ToolsTargets" + DESTINATION ${INSTALL_TARGETS_DEFAULT_ARGS}) + endif() +endfunction() + +function(qt_create_tracepoints name tracePointsFile) + #### TODO + string(TOLOWER "${name}" name) + + file(GENERATE OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/qt${name}_tracepoints_p.h" CONTENT + "#include <private/qtrace_p.h>") +endfunction() + +# Handle files that need special SIMD-related flags. +# This creates an object library and makes target link +# to it (privately). +function(qt_add_simd_part target) + qt_parse_all_arguments(arg "qt_add_simd_part" "" "" + "NAME;SIMD;${__default_private_args};COMPILE_FLAGS" ${ARGN}) + if ("x${arg_SIMD}" STREQUAL x) + message(FATAL_ERROR "qt_add_simd_part needs a SIMD type to be set.") + endif() + + set(condition "QT_FEATURE_${arg_SIMD}") + if("${arg_SIMD}" STREQUAL arch_haswell) + set(condition "TEST_subarch_avx2 AND TEST_subarch_bmi AND TEST_subarch_bmi2 AND TEST_subarch_f16c AND TEST_subarch_fma AND TEST_subarch_lzcnt AND TEST_subarch_popcnt") + elseif("${arg_SIMD}" STREQUAL avx512common) + set(condition "TEST_subarch_avx512cd") + elseif("${arg_SIMD}" STREQUAL avx512core) + set(condition "TEST_subarch_avx512cd AND TEST_subarch_avx512bw AND TEST_subarch_avx512dq AND TEST_subarch_avx512vl") + endif() + + set(name "${arg_NAME}") + if("x${name}" STREQUAL x) + set(name "${target}_simd_${arg_SIMD}") + endif() + + qt_evaluate_config_expression(result ${condition}) + if(${result}) + if(QT_CMAKE_DEBUG_EXTEND_TARGET) + message("qt_add_simd_part(${target} SIMD ${arg_SIMD} ...): Evaluated") + endif() + string(TOUPPER "QT_CFLAGS_${arg_SIMD}" simd_flags) + + if (NOT TARGET "${name}") + add_library("${name}" OBJECT) + endif() + target_sources("${name}" PRIVATE ${arg_SOURCES}) + target_include_directories("${name}" PRIVATE + ${arg_INCLUDE_DIRECTORIES} + $<TARGET_PROPERTY:${target},INCLUDE_DIRECTORIES>) + target_compile_options("${name}" PRIVATE + ${${simd_flags}} + ${arg_COMPILE_FLAGS} + $<TARGET_PROPERTY:${target},COMPILE_OPTIONS>) + target_compile_definitions("${name}" PRIVATE + $<TARGET_PROPERTY:${target},COMPILE_DEFINITIONS>) + + target_link_libraries("${target}" PRIVATE "${name}") + + # Add a link-only dependency on the parent library, to force copying of framework headers + # before trying to compile a source file. + target_link_libraries("${name}" PRIVATE + $<FILTER:$<TARGET_PROPERTY:${target},LINK_LIBRARIES>,EXCLUDE,^${target}_simd_>) + + if(NOT BUILD_SHARED_LIBS) + qt_install( + TARGETS ${name} + EXPORT "${INSTALL_CMAKE_NAMESPACE}Targets" + ) + endif() + else() + if(QT_CMAKE_DEBUG_EXTEND_TARGET) + message("qt_add_simd_part(${target} SIMD ${arg_SIMD} ...): Skipped") + endif() + endif() +endfunction() + +# From Qt6CoreMacros +# Function used to create the names of output files preserving relative dirs +function(qt_make_output_file infile prefix suffix source_dir binary_dir result) + get_filename_component(outfilename "${infile}" NAME_WE) + + set(base_dir "${source_dir}") + string(FIND "${infile}" "${binary_dir}/" in_binary) + if (in_binary EQUAL 0) + set(base_dir "${binary_dir}") + endif() + + get_filename_component(abs_infile "${infile}" ABSOLUTE BASE_DIR "${base_dir}") + file(RELATIVE_PATH rel_infile "${base_dir}" "${abs_infile}") + string(REPLACE "../" "__/" mapped_infile "${rel_infile}") + + get_filename_component(abs_mapped_infile "${mapped_infile}" ABSOLUTE BASE_DIR "${binary_dir}") + get_filename_component(outpath "${abs_mapped_infile}" PATH) + + file(MAKE_DIRECTORY "${outpath}") + set("${result}" "${outpath}/${prefix}${outfilename}${suffix}" PARENT_SCOPE) +endfunction() + + +# Complete manual moc invocation with full control. +# Use AUTOMOC whenever possible. +function(qt_manual_moc result) + cmake_parse_arguments(arg "" "OUTPUT_MOC_JSON_FILES" "FLAGS" ${ARGN}) + set(moc_files) + set(metatypes_json_list) + foreach(infile ${arg_UNPARSED_ARGUMENTS}) + qt_make_output_file("${infile}" "moc_" ".cpp" + "${CMAKE_CURRENT_SOURCE_DIR}" "${CMAKE_CURRENT_BINARY_DIR}" outfile) + list(APPEND moc_files "${outfile}") + + set(moc_parameters_file "${outfile}_parameters$<$<BOOL:$<CONFIGURATION>>:_$<CONFIGURATION>>") + set(moc_parameters ${arg_FLAGS} -o "${outfile}" "${infile}") + + set(metatypes_byproducts) + if (arg_OUTPUT_MOC_JSON_FILES) + set(moc_json_file "${outfile}.json") + list(APPEND moc_parameters --output-json) + list(APPEND metatypes_json_list "${outfile}.json") + set(metatypes_byproducts "${outfile}.json") + endif() + + string (REPLACE ";" "\n" moc_parameters "${moc_parameters}") + + file(GENERATE OUTPUT "${moc_parameters_file}" CONTENT "${moc_parameters}\n") + + add_custom_command(OUTPUT "${outfile}" ${metatypes_byproducts} + COMMAND ${QT_CMAKE_EXPORT_NAMESPACE}::moc "@${moc_parameters_file}" + DEPENDS "${infile}" ${moc_depends} ${QT_CMAKE_EXPORT_NAMESPACE}::moc + WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" VERBATIM) + endforeach() + set("${result}" ${moc_files} PARENT_SCOPE) + + # Register generated json files + if (arg_OUTPUT_MOC_JSON_FILES) + set(${arg_OUTPUT_MOC_JSON_FILES} "${metatypes_json_list}" PARENT_SCOPE) + endif() +endfunction() + + +# helper to set up a qdbusxml2cpp rule +function(qt_create_qdbusxml2cpp_command target infile) + qt_parse_all_arguments(arg "qt_create_qdbusxml2cpp_command" "ADAPTOR;INTERFACE" "BASENAME" "FLAGS" ${ARGN}) + if((arg_ADAPTOR AND arg_INTERFACE) OR (NOT arg_ADAPTOR AND NOT arg_INTERFACE)) + message(FATAL_ERROR "qt_create_dbusxml2cpp_command needs either ADAPTOR or INTERFACE.") + endif() + + set(option "-a") + set(type "adaptor") + if (arg_INTERFACE) + set(option "-p") + set(type "interface") + endif() + + if ("${arg_BASENAME}" STREQUAL "") + get_filename_component(file_dir "${infile}" DIRECTORY) + get_filename_component(file_name "${infile}" NAME_WLE) + get_filename_component(file_ext "${infile}" LAST_EXT) + + if("${file_ext}" STREQUAL ".xml") + else() + message(FATAL_ERROR "DBUS ${type} input file is not xml.") + endif() + + # use last part of io.qt.something.xml! + get_filename_component(file_ext "${file_name}" LAST_EXT) + if("x${file_ext}" STREQUAL "x") + else() + string(SUBSTRING "${file_ext}" 1 -1 file_name) # cut of leading '.' + endif() + + string(TOLOWER "${file_name}" file_name) + set(file_name "${file_name}_${type}") + else() + set(file_name ${arg_BASENAME}) + endif() + + # Use absolute file path for the source file and set the current working directory to the + # current binary directory, because setting an absolute path for the header:source combo option + # does not work. Splitting on ":" breaks inside the dbus tool when running on Windows + # due to ":" being contained in the drive path (e.g C:\foo.h:C:\foo.cpp). + get_filename_component(absolute_in_file_path "${infile}" ABSOLUTE) + + set(header_file "${file_name}.h") + set(source_file "${file_name}.cpp") + + add_custom_command(OUTPUT "${header_file}" "${source_file}" + COMMAND ${QT_CMAKE_EXPORT_NAMESPACE}::qdbusxml2cpp ${arg_FLAGS} "${option}" + "${header_file}:${source_file}" "${absolute_in_file_path}" + DEPENDS "${absolute_in_file_path}" ${QT_CMAKE_EXPORT_NAMESPACE}::qdbusxml2cpp + WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}" + VERBATIM) + + target_sources("${target}" PRIVATE "${header_file}" "${source_file}") +endfunction() + +function(qt_compute_injection_forwarding_header target) + qt_parse_all_arguments(arg "qt_compute_injection_forwarding_header" + "PRIVATE" "SOURCE;OUT_VAR" "" ${ARGN}) + qt_internal_module_info(module "${target}") + get_filename_component(file_name "${arg_SOURCE}" NAME) + + set(source_absolute_path "${CMAKE_CURRENT_BINARY_DIR}/${arg_SOURCE}") + file(RELATIVE_PATH relpath "${PROJECT_BINARY_DIR}" "${source_absolute_path}") + + if (arg_PRIVATE) + set(fwd "${PROJECT_VERSION}/${module}/private/${file_name}") + else() + set(fwd "${file_name}") + endif() + + string(APPEND ${arg_OUT_VAR} " ${relpath}:${fwd}") + set(${arg_OUT_VAR} ${${arg_OUT_VAR}} PARENT_SCOPE) +endfunction() + + +function(qt_add_docs) + if(${ARGC} EQUAL 1) + # Function called from old generated CMakeLists.txt that was missing the target parameter + return() + endif() + if(NOT ${ARGC} EQUAL 2) + message(FATAL_ERROR "qt_add_docs called with the wrong number of arguments. Should be qt_add_docs(target path_to_project.qdocconf).") + return() + endif() + set(target ${ARGV0}) + set(doc_project ${ARGV1}) + + if (NOT QT_SUPERBUILD OR QT_WILL_INSTALL) + set(qdoc_bin "${CMAKE_INSTALL_PREFIX}/${INSTALL_BINDIR}/qdoc") + set(qtattributionsscanner_bin "${CMAKE_INSTALL_PREFIX}/${INSTALL_BINDIR}/qtattributionsscanner") + set(qhelpgenerator_bin "${CMAKE_INSTALL_PREFIX}/${INSTALL_BINDIR}/qhelpgenerator") + else() + set(qdoc_bin "${CMAKE_INSTALL_PREFIX}/qtbase/${INSTALL_BINDIR}/qdoc") + set(qtattributionsscanner_bin "${CMAKE_INSTALL_PREFIX}/qtbase/${INSTALL_BINDIR}/qtattributionsscanner") + set(qhelpgenerator_bin "${CMAKE_INSTALL_PREFIX}/qtbase/${INSTALL_BINDIR}/qhelpgenerator") + endif() + + get_target_property(target_type ${target} TYPE) + if (NOT target_type STREQUAL "INTERFACE_LIBRARY") + get_target_property(target_bin_dir ${target} BINARY_DIR) + get_target_property(target_source_dir ${target} SOURCE_DIR) + else() + set(target_bin_dir ${CMAKE_CURRENT_BINARY_DIR}) + set(target_source_dir ${CMAKE_CURRENT_SOURCE_DIR}) + endif() + set(doc_ouput_dir "${target_bin_dir}/.doc") + + + # Generate include dir list + set(target_include_dirs_file "${doc_ouput_dir}/$<CONFIG>/includes.txt") + + set(include_paths_property "$<TARGET_PROPERTY:${target},INCLUDE_DIRECTORIES>") + if (NOT target_type STREQUAL "INTERFACE_LIBRARY") + file(GENERATE + OUTPUT ${target_include_dirs_file} + CONTENT "-I$<JOIN:${include_paths_property},\n-I>" + ) + set(include_path_args "@${target_include_dirs_file}") + else() + set(include_path_args "") + endif() + + get_filename_component(doc_target "${doc_project}" NAME_WLE) + if (QT_WILL_INSTALL) + set(qdoc_output_dir "${CMAKE_BINARY_DIR}/${INSTALL_DOCDIR}/${doc_target}") + set(index_dir "${CMAKE_BINARY_DIR}/${INSTALL_DOCDIR}") + elseif (QT_SUPERBUILD) + set(qdoc_output_dir "${CMAKE_INSTALL_PREFIX}/qtbase/${INSTALL_DOCDIR}/${doc_target}") + set(index_dir "${CMAKE_INSTALL_PREFIX}/qtbase/${INSTALL_DOCDIR}") + else() + set(qdoc_output_dir "${CMAKE_INSTALL_PREFIX}/${INSTALL_DOCDIR}/${doc_target}") + set(index_dir "${CMAKE_INSTALL_PREFIX}/${INSTALL_DOCDIR}") + endif() + + # qtattributionsscanner + add_custom_target(qattributionsscanner_${target} + DEPENDS ${qattributionsscanner_bin} + COMMAND ${qtattributionsscanner_bin} + ${PROJECT_SOURCE_DIR} + --filter "QDocModule=${qdoc_target}" + -o "${target_bin_dir}/codeattributions.qdoc" + ) + + # prepare docs target + set(prepare_qdoc_args + -outputdir "${qdoc_output_dir}" + -installdir "${QT_INSTALL_DIR}/${INSTALL_DOCDIR}" + "${target_source_dir}/${doc_project}" + -prepare + -indexdir "${index_dir}" + -no-link-errors + "${include_path_args}" + ) + + if (QT_SUPERBUILD AND NOT QT_WILL_INSTALL) + set(qt_install_docs_env "${CMAKE_INSTALL_PREFIX}/qtbase/${INSTALL_DOCDIR}") + else() + set(qt_install_docs_env "${CMAKE_INSTALL_PREFIX}/${INSTALL_DOCDIR}") + endif() + + set(qdoc_env_args + "QT_INSTALL_DOCS=\"${qt_install_docs_env}\"" + "QT_VERSION=${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}" + "QT_VER=${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}" + "QT_VERSION_TAG=${PROJECT_VERSION_MAJOR}${PROJECT_VERSION_MINOR}${PROJECT_VERSION_PATCH}" + "BUILDDIR=${target_bin_dir}" + ) + + add_custom_target(prepare_docs_${target} + DEPENDS ${qdoc_bin} + COMMAND ${CMAKE_COMMAND} -E env ${qdoc_env_args} + ${qdoc_bin} + ${prepare_qdoc_args} + ) + + add_dependencies(prepare_docs_${target} qattributionsscanner_${target}) + + # generate docs target + set(generate_qdocs_args + -outputdir "${qdoc_output_dir}" + -installdir "${INSTALL_DOCDIR}" + "${target_source_dir}/${doc_project}" + -generate + -indexdir "${index_dir}" + "${include_path_args}" + ) + + add_custom_target(generate_docs_${target} + DEPENDS ${qdoc_bin} + COMMAND ${CMAKE_COMMAND} -E env ${qdoc_env_args} + ${qdoc_bin} + ${generate_qdocs_args} + ) + + add_dependencies(generate_docs_${target} prepare_docs_${target}) + + # generate html + set(html_qdocs_args + -outputdir "${qdoc_output_dir}" + -installdir "${INSTALL_DOCDIR}" + "${target_source_dir}/${doc_project}" + -indexdir "${index_dir}" + "${include_path_args}" + ) + + add_custom_target(html_docs_${target} + DEPENDS ${qdoc_bin} + COMMAND ${CMAKE_COMMAND} -E env ${qdoc_env_args} + ${qdoc_bin} + ${html_qdocs_args} + ) + + add_dependencies(html_docs_${target} generate_docs_${target}) + + # generate .qch + set(qch_file_name ${doc_target}.qch) + set(qch_file_path ${qdoc_output_dir}/${qch_file_name}) + + add_custom_target(qch_docs_${target} + DEPENDS ${qhelpgenerator_bin} + COMMAND ${qhelpgenerator_bin} + "${qdoc_output_dir}/${doc_target}.qhp" + -o "${qch_file_path}" + ) + add_dependencies(qch_docs_${target} generate_docs_${target}) + + if (QT_WILL_INSTALL) + add_custom_target(install_html_docs_${target} + COMMAND ${CMAKE_COMMAND} -E copy_directory + "${qdoc_output_dir}" + "${CMAKE_INSTALL_PREFIX}/${INSTALL_DOCDIR}/${doc_target}" + COMMENT "Installing html docs for target ${target}" + ) + + add_custom_target(install_qch_docs_${target} + COMMAND ${CMAKE_COMMAND} -E copy_if_different + "${qch_file_path}" + "${CMAKE_INSTALL_PREFIX}/${INSTALL_DOCDIR}/${qch_file_name}" + COMMENT "Installing qch docs for target ${target}" + ) + else() + # Don't need to do anything when not installing + add_custom_target(install_html_docs_${target}) + add_custom_target(install_qch_docs_${target}) + endif() + + add_dependencies(install_html_docs_${target} html_docs_${target}) + add_dependencies(install_qch_docs_${target} qch_docs_${target}) + + add_custom_target(install_docs_${target}) + add_dependencies(install_docs_${target} install_html_docs_${target} install_qch_docs_${target}) + + add_dependencies(${qt_docs_prepare_target_name} prepare_docs_${target}) + add_dependencies(${qt_docs_generate_target_name} generate_docs_${target}) + add_dependencies(${qt_docs_html_target_name} html_docs_${target}) + add_dependencies(${qt_docs_qch_target_name} qch_docs_${target}) + add_dependencies(${qt_docs_install_html_target_name} install_html_docs_${target}) + add_dependencies(${qt_docs_install_qch_target_name} install_qch_docs_${target}) + add_dependencies(${qt_docs_install_target_name} install_docs_${target}) + +endfunction() + +macro(qt_find_package) + # Get the target names we expect to be provided by the package. + set(options CONFIG NO_MODULE MODULE REQUIRED) + set(oneValueArgs) + set(multiValueArgs PROVIDED_TARGETS COMPONENTS) + cmake_parse_arguments(arg "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) + + # If some Qt internal project calls qt_find_package(WrapFreeType), but WrapFreeType was already + # found as part of a find_dependency() call from a ModuleDependencies.cmake file (or similar), + # and the provided target is also found, that means this might have been an unnecessary + # qt_find_package() call, because the dependency was already found via some other transitive + # dependency. Return early, so that CMake doesn't fail wiht an error with trying to promote the + # targets to be global. This behavior is not enabled by default, because there are cases + # when a regular find_package() (non qt_) can find a package (Freetype -> PNG), and a subsequent + # qt_find_package(PNG PROVIDED_TARGET PNG::PNG) still needs to succeed and register the provided + # targets. To enable the debugging behavior, set QT_DEBUG_QT_FIND_PACKAGE to 1. + set(_qt_find_package_skip_find_package FALSE) + if(QT_DEBUG_QT_FIND_PACKAGE AND ${ARGV0}_FOUND AND arg_PROVIDED_TARGETS) + set(_qt_find_package_skip_find_package TRUE) + foreach(qt_find_package_target_name ${arg_PROVIDED_TARGETS}) + if(NOT TARGET ${qt_find_package_target_name}) + set(_qt_find_package_skip_find_package FALSE) + endif() + endforeach() + + if(_qt_find_package_skip_find_package) + message(AUTHOR_WARNING "qt_find_package(${ARGV0}) called even though the package " + "was already found. Consider removing the call.") + endif() + endif() + + # Get the version if specified. + set(package_version "") + if(${ARGC} GREATER_EQUAL 2) + if(${ARGV1} MATCHES "^[0-9\.]+$") + set(package_version "${ARGV1}") + endif() + endif() + + if(arg_COMPONENTS) + # Re-append components to forward them. + list(APPEND arg_UNPARSED_ARGUMENTS "COMPONENTS;${arg_COMPONENTS}") + endif() + + if(NOT (arg_CONFIG OR arg_NO_MODULE OR arg_MODULE) AND NOT _qt_find_package_skip_find_package) + # Try to find a config package first in quiet mode + set(config_package_arg ${arg_UNPARSED_ARGUMENTS}) + list(APPEND config_package_arg "CONFIG;QUIET") + find_package(${config_package_arg}) + + # Double check that in config mode the targets become visible. Sometimes + # only the module mode creates the targets. For example with vcpkg, the sqlite + # package provides sqlite3-config.cmake, which offers multi-config targets but + # in their own way. CMake has FindSQLite3.cmake and with the original + # qt_find_package(SQLite3) call it is our intention to use the cmake package + # in module mode. + if (${ARGV0}_FOUND AND arg_PROVIDED_TARGETS) + unset(any_target_found) + foreach(expected_target ${arg_PROVIDED_TARGETS}) + if (TARGET ${expected_target}) + set(any_target_found TRUE) + break() + endif() + endforeach() + if(NOT any_target_found) + unset(${ARGV0}_FOUND) + endif() + endif() + endif() + + # Ensure the options are back in the original unparsed arguments + foreach(opt IN LISTS options) + if(arg_${opt}) + list(APPEND arg_UNPARSED_ARGUMENTS ${opt}) + endif() + endforeach() + + if (NOT ${ARGV0}_FOUND AND NOT _qt_find_package_skip_find_package) + # Unset the NOTFOUND ${package}_DIR var that might have been set by the previous + # find_package call, to get rid of "not found" messagees in the feature summary + # if the package is found by the next find_package call. + if(DEFINED CACHE{${ARGV0}_DIR} AND NOT ${ARGV0}_DIR) + unset(${ARGV0}_DIR CACHE) + endif() + + # Call original function without our custom arguments. + find_package(${arg_UNPARSED_ARGUMENTS}) + endif() + + if(${ARGV0}_FOUND AND arg_PROVIDED_TARGETS AND NOT _qt_find_package_skip_find_package) + # If package was found, associate each target with its package name. This will be used + # later when creating Config files for Qt libraries, to generate correct find_dependency() + # calls. Also make the provided targets global, so that the properties can be read in + # all scopes. + foreach(qt_find_package_target_name ${arg_PROVIDED_TARGETS}) + if(TARGET ${qt_find_package_target_name}) + # Allow usage of aliased targets by setting properties on the actual target + get_target_property(aliased_target ${qt_find_package_target_name} ALIASED_TARGET) + if(aliased_target) + set(qt_find_package_target_name ${aliased_target}) + endif() + + set_target_properties(${qt_find_package_target_name} + PROPERTIES INTERFACE_QT_PACKAGE_NAME ${ARGV0}) + if(package_version) + set_target_properties(${qt_find_package_target_name} + PROPERTIES INTERFACE_QT_PACKAGE_VERSION ${ARGV1}) + endif() + + if(arg_COMPONENTS) + string(REPLACE ";" " " components_as_string "${arg_COMPONENTS}") + set_property(TARGET ${qt_find_package_target_name} + PROPERTY INTERFACE_QT_PACKAGE_COMPONENTS ${components_as_string}) + endif() + + get_property(is_global TARGET ${qt_find_package_target_name} PROPERTY + IMPORTED_GLOBAL) + if(NOT is_global) + set_property(TARGET ${qt_find_package_target_name} PROPERTY + IMPORTED_GLOBAL TRUE) + endif() + endif() + + endforeach() + endif() +endmacro() + +# Creates a simple export set for the various Find* dependencies +# which are needed when creating a static build of Qt. +# This introduces a custom target property: INTERFACE_QT_EXPORTED_LIBRARY +# This target property indicates that Qt modules / plugins using this 3rd party library +# must add it to their list of dependencies when creating their own ${qtmodule}Config.cmake +function(qt_install_static_target_export target) + if(BUILD_SHARED_LIBS) + return() + endif() + + qt_parse_all_arguments(arg "qt_install_3rdparty_config_files" "" "EXPORT" "" ${ARGN}) + # TODO mark EXPORT as required + + set_target_properties(${target} + PROPERTIES + INTERFACE_QT_EXPORTED_LIBRARY 1) + + qt_path_join(config_install_dir ${QT_CONFIG_INSTALL_DIR} ${arg_EXPORT}) + + set(export_name "${arg_EXPORT}Targets") + qt_install( + TARGETS ${target} + EXPORT ${export_name} + LIBRARY DESTINATION ${INSTALL_LIBDIR} + ARCHIVE DESTINATION ${INSTALL_LIBDIR}) + + qt_install( + EXPORT ${export_name} + DESTINATION "${config_install_dir}" + ) +endfunction() + +# Create a set of ${target}Config.cmake and ${target}Version.cmake for a +# third-party library so that it can be found by client code linking statically. +function(qt_install_3rdparty_config_files target) + if(BUILD_SHARED_LIBS) + return() + endif() + + qt_parse_all_arguments(arg "qt_install_3rdparty_config_files" "" "EXPORT" "PACKAGES;ADDITIONAL_FILES" ${ARGN}) + # TODO mark EXPORT as required + + set(3RDPARTY_ADDITIONAL_SETUP_CODE) + foreach(package ${arg_PACKAGES}) + list(APPEND 3RDPARTY_ADDITIONAL_SETUP_CODE "find_package(${package})\n") + endforeach() + + set(path_suffix "${arg_EXPORT}") + qt_path_join(config_build_dir ${QT_CONFIG_BUILD_DIR} ${path_suffix}) + qt_path_join(config_install_dir ${QT_CONFIG_INSTALL_DIR} ${path_suffix}) + + configure_package_config_file( + "${PROJECT_SOURCE_DIR}/cmake/3rdpartyConfig.cmake.in" + "${config_build_dir}/${target}Config.cmake" + INSTALL_DESTINATION "${config_install_dir}" + ) + + write_basic_package_version_file( + "${config_build_dir}/${target}ConfigVersion.cmake" + VERSION ${PROJECT_VERSION} + COMPATIBILITY AnyNewerVersion + ) + + qt_install(FILES + "${config_build_dir}/${target}Config.cmake" + "${config_build_dir}/${target}ConfigVersion.cmake" + ${arg_ADDITIONAL_FILES} + DESTINATION "${config_install_dir}" + COMPONENT Devel + ) +endfunction() + +# Call this function in 3rdparty find modules that ought to be installed alongside +# Qt modules and must be found when linking statically. +function(qt_install_3rdparty_library target) + qt_install_static_target_export(${target} EXPORT ${target}) + qt_install_3rdparty_config_files(${target} EXPORT ${target} ${ARGN}) +endfunction() + +macro(qt_find_apple_system_frameworks) + if(APPLE) + find_library(FWAppKit AppKit) + find_library(FWAssetsLibrary AssetsLibrary) + find_library(FWAudioToolbox AudioToolbox) + find_library(FWApplicationServices ApplicationServices) + find_library(FWCarbon Carbon) + find_library(FWCoreFoundation CoreFoundation) + find_library(FWCoreServices CoreServices) + find_library(FWCoreGraphics CoreGraphics) + find_library(FWCoreText CoreText) + find_library(FWCoreVideo CoreVideo) + find_library(FWcups cups) + find_library(FWDiskArbitration DiskArbitration) + find_library(FWFoundation Foundation) + find_library(FWIOBluetooth IOBluetooth) + find_library(FWIOKit IOKit) + find_library(FWIOSurface IOSurface) + find_library(FWImageIO ImageIO) + find_library(FWMetal Metal) + find_library(FWMobileCoreServices MobileCoreServices) + find_library(FWQuartzCore QuartzCore) + find_library(FWSecurity Security) + find_library(FWSystemConfiguration SystemConfiguration) + find_library(FWUIKit UIKit) + find_library(FWWatchKit WatchKit) + find_library(FWGameController GameController) + endif() +endmacro() + +# Match the pattern 'regex' in 'input_line', replace the match with 'replacement' +# and set that result in 'out_var' in the parent scope. +function(qt_regex_match_and_get input_line regex replacement out_var) + string(REGEX MATCH "${regex}" match "${input_line}") + if(match) + string(REGEX REPLACE "${regex}" "${replacement}" match "${input_line}") + string(STRIP ${match} match) + set(${out_var} "${match}" PARENT_SCOPE) + endif() +endfunction() + +# Match 'regex' in a list of lines. When found, set the value to 'out_var' and break early. +function(qt_qlalr_find_option_in_list input_list regex out_var) + foreach(line ${input_list}) + qt_regex_match_and_get("${line}" "${regex}" "\\1" option) + if(option) + string(TOLOWER ${option} option) + set(${out_var} "${option}" PARENT_SCOPE) + return() + endif() + endforeach() + message(FATAL_ERROR "qt_qlalr_find_option_in_list: Could not extract ${out_var}") +endfunction() + +# Generate a few output files using qlalr, and assign those to 'consuming_target'. +# 'input_file_list' is a list of 'foo.g' file paths. +# 'flags' are extra flags to be passed to qlalr. +function(qt_process_qlalr consuming_target input_file_list flags) + foreach(input_file ${input_file_list}) + file(STRINGS ${input_file} input_file_lines) + qt_qlalr_find_option_in_list("${input_file_lines}" "^%parser(.+)" "parser") + qt_qlalr_find_option_in_list("${input_file_lines}" "^%decl(.+)" "decl") + qt_qlalr_find_option_in_list("${input_file_lines}" "^%impl(.+)" "impl") + get_filename_component(base_file_name ${input_file} NAME_WE) + + set(cpp_file "${parser}.cpp") + set(private_file "${parser}_p.h") + set(decl_file "${decl}") + set(impl_file "${impl}") + add_custom_command( + OUTPUT ${cpp_file} ${private_file} ${decl_file} ${impl_file} + COMMAND ${QT_CMAKE_EXPORT_NAMESPACE}::qlalr ${flags} ${input_file} + DEPENDS ${QT_CMAKE_EXPORT_NAMESPACE}::qlalr + MAIN_DEPENDENCY ${input_file} + ) + target_sources(${consuming_target} PRIVATE ${cpp_file} ${impl_file}) + endforeach() +endfunction() + +macro(qt_add_string_to_qconfig_cpp str) + string(LENGTH "${str}" length) + string(APPEND QT_CONFIG_STRS " \"${str}\\0\"\n") + string(APPEND QT_CONFIG_STR_OFFSETS " ${QT_CONFIG_STR_OFFSET},\n") + math(EXPR QT_CONFIG_STR_OFFSET "${QT_CONFIG_STR_OFFSET}+${length}+1") +endmacro() + +function(qt_generate_qconfig_cpp) + set(QT_CONFIG_STR_OFFSET "0") + set(QT_CONFIG_STR_OFFSETS "") + set(QT_CONFIG_STRS "") + + # Start first part. + qt_add_string_to_qconfig_cpp("doc") + qt_add_string_to_qconfig_cpp("include") + qt_add_string_to_qconfig_cpp("lib") + qt_add_string_to_qconfig_cpp("libexec") + qt_add_string_to_qconfig_cpp("bin") + qt_add_string_to_qconfig_cpp("plugins") + qt_add_string_to_qconfig_cpp("qml") + qt_add_string_to_qconfig_cpp(".") + qt_add_string_to_qconfig_cpp(".") + qt_add_string_to_qconfig_cpp("translations") + qt_add_string_to_qconfig_cpp("examples") + qt_add_string_to_qconfig_cpp("tests") + + # Save first part. + set(QT_CONFIG_STR_OFFSETS_FIRST "${QT_CONFIG_STR_OFFSETS}") + set(QT_CONFIG_STRS_FIRST "${QT_CONFIG_STRS}") + + # Start second part. + set(QT_CONFIG_STR_OFFSETS "") + set(QT_CONFIG_STRS "") + + qt_add_string_to_qconfig_cpp("") + qt_add_string_to_qconfig_cpp("false") + qt_add_string_to_qconfig_cpp("bin") + qt_add_string_to_qconfig_cpp("lib") + qt_add_string_to_qconfig_cpp(".") + qt_add_string_to_qconfig_cpp("${QT_QMAKE_TARGET_MKSPEC}") + qt_add_string_to_qconfig_cpp("${QT_QMAKE_HOST_MKSPEC}") + + # Save second part. + set(QT_CONFIG_STR_OFFSETS_SECOND "${QT_CONFIG_STR_OFFSETS}") + set(QT_CONFIG_STRS_SECOND "${QT_CONFIG_STRS}") + + # Settings path / sysconf dir. + if(APPLE) + set(QT_DEFAULT_SYS_CONF_DIR "/Library/Preferences/Qt") + else() + set(QT_DEFAULT_SYS_CONF_DIR "etc/xdg") + endif() + + # Compute and set relocation prefixes. + # TODO: Clean this up, there's a bunch of unrealistic assumptions here. + # See qtConfOutput_preparePaths in qtbase/configure.pri. + if(WIN32) + set(lib_location_absolute_path "${CMAKE_INSTALL_PREFIX}/${INSTALL_BINDIR}") + else() + set(lib_location_absolute_path "${CMAKE_INSTALL_PREFIX}/${INSTALL_LIBDIR}") + endif() + file(RELATIVE_PATH from_lib_location_to_prefix + "${lib_location_absolute_path}" "${CMAKE_INSTALL_PREFIX}") + + if(QT_HOST_PATH) + set(host_prefix "${QT_HOST_PATH}") + set(host_bin_dir_absolute_path "${QT_HOST_PATH}/${INSTALL_BINDIR}") + else() + set(host_prefix "${CMAKE_INSTALL_PREFIX}") + set(host_bin_dir_absolute_path "${CMAKE_INSTALL_PREFIX}/${INSTALL_BINDIR}") + endif() + + file(RELATIVE_PATH from_host_bin_dir_to_host_prefix + "${host_bin_dir_absolute_path}" "${host_prefix}") + + # TODO: Fix this to use the equivalent of extprefix on CMake (CMAKE_STAGING_PREFIX?) + # For now just assume ext prefix is same as regular prefix. + file(RELATIVE_PATH from_host_bin_dir_to_ext_prefix + "${host_bin_dir_absolute_path}" "${CMAKE_INSTALL_PREFIX}") + + + set(QT_CONFIGURE_LIBLOCATION_TO_PREFIX_PATH "${from_lib_location_to_prefix}") + set(QT_CONFIGURE_HOSTBINDIR_TO_HOSTPREFIX_PATH "${from_host_bin_dir_to_host_prefix}") + set(QT_CONFIGURE_HOSTBINDIR_TO_EXTPREFIX_PATH "${from_host_bin_dir_to_ext_prefix}") + + configure_file(global/qconfig.cpp.in global/qconfig.cpp @ONLY) +endfunction() + +function(qt_set_language_standards) + ## Use the latest standard the compiler supports (same as qt_common.prf) + if (QT_FEATURE_cxx2a) + set(CMAKE_CXX_STANDARD 20 PARENT_SCOPE) + else() + set(CMAKE_CXX_STANDARD 17 PARENT_SCOPE) + endif() + + if (c_std_11 IN_LIST CMAKE_C_COMPILE_FEATURES) + set(CMAKE_C_STANDARD 11 PARENT_SCOPE) + elseif (c_std_99 IN_LIST CMAKE_C_COMPILE_FEATURES) + set(CMAKE_C_STANDARD 99 PARENT_SCOPE) + endif() +endfunction() + +function(qt_enable_msvc_cplusplus_define target visibility) + # For MSVC we need to explicitly pass -Zc:__cplusplus to get correct __cplusplus. + # Check qt_config_compile_test for more info. + if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC" AND MSVC_VERSION GREATER_EQUAL 1913) + target_compile_options("${target}" ${visibility} "-Zc:__cplusplus") + endif() +endfunction() + +# Compatibility macros that should be removed once all their usages are removed. +function(extend_target) + qt_extend_target(${ARGV}) +endfunction() + +function(add_qt_module) + qt_add_module(${ARGV}) +endfunction() + +function(add_qt_plugin) + qt_add_plugin(${ARGV}) +endfunction() + +function(add_qt_tool) + qt_add_tool(${ARGV}) +endfunction() + +function(add_qt_test) + qt_add_test(${ARGV}) +endfunction() + +function(add_qt_test_helper) + qt_add_test_helper(${ARGV}) +endfunction() + +function(add_qt_manual_test) + qt_add_manual_test(${ARGV}) +endfunction() + +function(add_qt_benchmark) + qt_add_benchmark(${ARGV}) +endfunction() + +function(add_qt_executable) + qt_add_executable(${ARGV}) +endfunction() + +function(add_qt_simd_part) + qt_add_simd_part(${ARGV}) +endfunction() + +function(add_qt_docs) + qt_add_docs(${ARGV}) +endfunction() + +function(add_qt_resource) + qt_add_resource(${ARGV}) +endfunction() + +function(add_cmake_library) + qt_add_cmake_library(${ARGV}) +endfunction() |