summaryrefslogtreecommitdiffstats
path: root/cmake/QtTargetHelpers.cmake
diff options
context:
space:
mode:
Diffstat (limited to 'cmake/QtTargetHelpers.cmake')
-rw-r--r--cmake/QtTargetHelpers.cmake946
1 files changed, 879 insertions, 67 deletions
diff --git a/cmake/QtTargetHelpers.cmake b/cmake/QtTargetHelpers.cmake
index 74044ec166..e669047ff1 100644
--- a/cmake/QtTargetHelpers.cmake
+++ b/cmake/QtTargetHelpers.cmake
@@ -1,42 +1,110 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# This function can be used to add sources/libraries/etc. to the specified CMake target
# if the provided CONDITION evaluates to true.
+# One-value Arguments:
+# PRECOMPILED_HEADER
+# Name of the precompiled header that is used for the target.
+# Multi-value Arguments:
+# CONDITION
+# The condition under which the target will be extended.
+# CONDITION_INDEPENDENT_SOURCES
+# Source files that should be added to the target unconditionally. Note that if target is Qt
+# module, these files will raise a warning at configure time if the condition is not met.
+# COMPILE_FLAGS
+# Custom compilation flags.
+# EXTRA_LINKER_SCRIPT_CONTENT
+# Extra content that should be appended to a target linker script. Applicable for ld only.
+# EXTRA_LINKER_SCRIPT_EXPORTS
+# Extra content that should be added to export section of the linker script.
+# NO_PCH_SOURCES
+# Exclude the specified source files from PRECOMPILE_HEADERS and UNITY_BUILD builds.
function(qt_internal_extend_target target)
+ if(NOT TARGET "${target}")
+ message(FATAL_ERROR "${target} is not a target.")
+ endif()
+ qt_internal_is_skipped_test(skipped ${target})
+ if(skipped)
+ return()
+ endif()
+ qt_internal_is_in_test_batch(in_batch ${target})
+ if(in_batch)
+ _qt_internal_test_batch_target_name(target)
+ endif()
+
# 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(option_args
+ NO_UNITY_BUILD
+ )
+ set(single_args
+ PRECOMPILED_HEADER
+ EXTRA_LINKER_SCRIPT_CONTENT
+ )
+ set(multi_args
+ ${__default_public_args}
+ ${__default_private_args}
+ ${__default_private_module_args}
+ CONDITION
+ CONDITION_INDEPENDENT_SOURCES
+ COMPILE_FLAGS
+ EXTRA_LINKER_SCRIPT_EXPORTS
+ )
+
+ cmake_parse_arguments(PARSE_ARGV 1 arg
+ "${option_args}"
+ "${single_args}"
+ "${multi_args}"
+ )
+ _qt_internal_validate_all_args_are_parsed(arg)
+
+ if("x${arg_CONDITION}" STREQUAL "x")
set(arg_CONDITION ON)
endif()
qt_evaluate_config_expression(result ${arg_CONDITION})
- if (${result})
+ 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}")
+ qt_create_qdbusxml2cpp_command("${target}" "${adaptor}"
+ ADAPTOR
+ BASENAME "${arg_DBUS_ADAPTOR_BASENAME}"
+ FLAGS ${arg_DBUS_ADAPTOR_FLAGS}
+ )
list(APPEND dbus_sources "${adaptor}")
endforeach()
foreach(interface ${arg_DBUS_INTERFACE_SOURCES})
- qt_create_qdbusxml2cpp_command("${target}" "${interface}" INTERFACE BASENAME "${arg_DBUS_INTERFACE_BASENAME}" FLAGS "${arg_DBUS_INTERFACE_FLAGS}")
+ qt_create_qdbusxml2cpp_command("${target}" "${interface}"
+ INTERFACE
+ BASENAME "${arg_DBUS_INTERFACE_BASENAME}"
+ FLAGS ${arg_DBUS_INTERFACE_FLAGS}
+ )
list(APPEND dbus_sources "${interface}")
endforeach()
+ set(all_sources
+ ${arg_SOURCES}
+ ${dbus_sources}
+ )
+
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_interface_lib FALSE)
+ if(${target_type} STREQUAL "STATIC_LIBRARY" OR ${target_type} STREQUAL "SHARED_LIBRARY")
set(is_library TRUE)
+ elseif(target_type STREQUAL "INTERFACE_LIBRARY")
+ set(is_interface_lib TRUE)
endif()
+
foreach(lib ${arg_PUBLIC_LIBRARIES} ${arg_LIBRARIES})
# Automatically generate PCH for 'target' using public dependencies.
# But only if 'target' is a library/module that does not specify its own PCH file.
@@ -48,32 +116,58 @@ function(qt_internal_extend_target target)
if(NOT base_lib STREQUAL lib)
qt_create_nolink_target("${base_lib}" ${target})
endif()
+
+ # Collect _sync_headers targets from libraries that the target depends on. This is
+ # heuristic way of building the dependency tree between the _sync_headers targets of
+ # different Qt modules.
+ if(TARGET "${lib}")
+ get_target_property(is_imported ${lib} IMPORTED)
+ if(NOT is_imported)
+ get_target_property(is_private ${lib} _qt_is_private_module)
+ if(is_private)
+ get_target_property(lib ${lib} _qt_public_module_target_name)
+ endif()
+ set(out_genex "$<TARGET_PROPERTY:${lib},_qt_internal_sync_headers_target>")
+ set_property(TARGET ${target}
+ APPEND PROPERTY _qt_internal_sync_headers_deps "${out_genex}")
+ endif()
+ endif()
endforeach()
+ list(TRANSFORM arg_PUBLIC_LIBRARIES REPLACE "^Qt::" "${QT_CMAKE_EXPORT_NAMESPACE}::")
+ list(TRANSFORM arg_LIBRARIES REPLACE "^Qt::" "${QT_CMAKE_EXPORT_NAMESPACE}::")
+
# Set-up the target
# CMake versions less than 3.19 don't support adding the source files to the PRIVATE scope
# of the INTERFACE libraries. These PRIVATE sources are only needed by IDEs to display
# them in a project tree, so to avoid build issues and appearing the sources in
- # INTERFACE_SOURCES property of HEADER_MODULE let's simply exclude them for compatibility
- # with CMake versions less than 3.19.
- if(NOT arg_HEADER_MODULE OR CMAKE_VERSION VERSION_GREATER_EQUAL "3.19")
- target_sources("${target}" PRIVATE ${arg_SOURCES} ${dbus_sources})
- if (arg_COMPILE_FLAGS)
- set_source_files_properties(${arg_SOURCES} PROPERTIES
+ # INTERFACE_SOURCES property of INTERFACE_LIBRARY. Collect them inside the
+ # _qt_internal_target_sources property, since they can be useful in the source processing
+ # functions. The property itself is not exported and should only be used in the Qt internal
+ # build tree.
+ if(NOT is_interface_lib OR CMAKE_VERSION VERSION_GREATER_EQUAL "3.19")
+ target_sources("${target}" PRIVATE ${all_sources})
+ if(arg_COMPILE_FLAGS)
+ set_source_files_properties(${all_sources} PROPERTIES
COMPILE_FLAGS "${arg_COMPILE_FLAGS}")
endif()
+ else()
+ set_property(TARGET ${target} APPEND PROPERTY
+ _qt_internal_target_sources ${all_sources})
endif()
set(public_visibility_option "PUBLIC")
set(private_visibility_option "PRIVATE")
- if(arg_HEADER_MODULE)
+ if(is_interface_lib)
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_include_directories("${target}" SYSTEM
+ ${private_visibility_option} ${arg_SYSTEM_INCLUDE_DIRECTORIES})
target_compile_definitions("${target}"
${public_visibility_option} ${arg_PUBLIC_DEFINES}
${private_visibility_option} ${arg_DEFINES})
@@ -87,10 +181,14 @@ function(qt_internal_extend_target 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
+ if(NOT is_interface_lib)
+ set_property(TARGET "${target}" APPEND PROPERTY
AUTOMOC_MOC_OPTIONS "${arg_MOC_OPTIONS}"
)
+ # Plugin types associated to a module
+ if(NOT "x${arg_PLUGIN_TYPES}" STREQUAL "x")
+ qt_internal_add_plugin_types("${target}" "${arg_PLUGIN_TYPES}")
+ endif()
endif()
# When computing the private library dependencies, we need to check not only the known
@@ -138,15 +236,252 @@ function(qt_internal_extend_target target)
DISABLE_AUTOGEN_TOOLS ${arg_DISABLE_AUTOGEN_TOOLS})
qt_update_precompiled_header("${target}" "${arg_PRECOMPILED_HEADER}")
+ ## Also exclude them from unity build
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}")
+ if(arg_NO_UNITY_BUILD)
+ set_target_properties("${target}" PROPERTIES UNITY_BUILD OFF)
+ qt_update_ignore_unity_build_sources("${target}" "${arg_SOURCES}")
+ endif()
+ if(arg_NO_UNITY_BUILD_SOURCES)
+ qt_update_ignore_unity_build_sources("${target}" "${arg_NO_UNITY_BUILD_SOURCES}")
+ endif()
else()
if(QT_CMAKE_DEBUG_EXTEND_TARGET)
message("qt_extend_target(${target} CONDITION ${arg_CONDITION} ...): Skipped")
endif()
endif()
+
+ if(arg_CONDITION_INDEPENDENT_SOURCES)
+ set_source_files_properties(${arg_CONDITION_INDEPENDENT_SOURCES} PROPERTIES
+ _qt_extend_target_condition "${arg_CONDITION}"
+ SKIP_AUTOGEN TRUE
+ )
+
+ qt_internal_get_target_sources_property(sources_property)
+ set_property(TARGET ${target} APPEND PROPERTY
+ ${sources_property} "${arg_CONDITION_INDEPENDENT_SOURCES}")
+ endif()
+
+ if(arg_EXTRA_LINKER_SCRIPT_CONTENT)
+ set_target_properties(${target} PROPERTIES
+ _qt_extra_linker_script_content "${arg_EXTRA_LINKER_SCRIPT_CONTENT}")
+ endif()
+ if(arg_EXTRA_LINKER_SCRIPT_EXPORTS)
+ set_target_properties(${target} PROPERTIES
+ _qt_extra_linker_script_exports "${arg_EXTRA_LINKER_SCRIPT_EXPORTS}")
+ endif()
+endfunction()
+
+# Given CMAKE_CONFIG and ALL_CMAKE_CONFIGS, determines if a directory suffix needs to be appended
+# to each destination, and sets the computed install target destination arguments in OUT_VAR.
+# Defaults used for each of the destination types, and can be configured per destination type.
+function(qt_get_install_target_default_args)
+ cmake_parse_arguments(PARSE_ARGV 0 arg
+ ""
+ "OUT_VAR;CMAKE_CONFIG;RUNTIME;LIBRARY;ARCHIVE;INCLUDES;BUNDLE"
+ "ALL_CMAKE_CONFIGS")
+ _qt_internal_validate_all_args_are_parsed(arg)
+
+ if(NOT arg_CMAKE_CONFIG)
+ message(FATAL_ERROR "No value given for CMAKE_CONFIG.")
+ endif()
+ if(NOT arg_ALL_CMAKE_CONFIGS)
+ message(FATAL_ERROR "No value given for ALL_CMAKE_CONFIGS.")
+ endif()
+ list(LENGTH arg_ALL_CMAKE_CONFIGS all_configs_count)
+ list(GET arg_ALL_CMAKE_CONFIGS 0 first_config)
+
+ set(suffix "")
+ if(all_configs_count GREATER 1 AND NOT arg_CMAKE_CONFIG STREQUAL first_config)
+ set(suffix "/${arg_CMAKE_CONFIG}")
+ endif()
+
+ set(runtime "${INSTALL_BINDIR}")
+ if(arg_RUNTIME)
+ set(runtime "${arg_RUNTIME}")
+ endif()
+
+ set(library "${INSTALL_LIBDIR}")
+ if(arg_LIBRARY)
+ set(library "${arg_LIBRARY}")
+ endif()
+
+ set(archive "${INSTALL_LIBDIR}")
+ if(arg_ARCHIVE)
+ set(archive "${arg_ARCHIVE}")
+ endif()
+
+ set(includes "${INSTALL_INCLUDEDIR}")
+ if(arg_INCLUDES)
+ set(includes "${arg_INCLUDES}")
+ endif()
+
+ set(bundle "${INSTALL_BINDIR}")
+ if(arg_BUNDLE)
+ set(bundle "${arg_BUNDLE}")
+ endif()
+
+ set(args
+ RUNTIME DESTINATION "${runtime}${suffix}"
+ LIBRARY DESTINATION "${library}${suffix}"
+ ARCHIVE DESTINATION "${archive}${suffix}" COMPONENT Devel
+ BUNDLE DESTINATION "${bundle}${suffix}"
+ INCLUDES DESTINATION "${includes}${suffix}")
+ set(${arg_OUT_VAR} "${args}" PARENT_SCOPE)
+endfunction()
+
+macro(qt_internal_setup_default_target_function_options)
+ set(__default_private_args
+ SOURCES
+ LIBRARIES
+ INCLUDE_DIRECTORIES
+ SYSTEM_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
+ NO_PCH_SOURCES
+ NO_UNITY_BUILD_SOURCES
+ )
+ 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
+ )
+ set(__default_target_info_args
+ TARGET_VERSION
+ TARGET_PRODUCT
+ TARGET_DESCRIPTION
+ TARGET_COMPANY
+ TARGET_COPYRIGHT
+ )
+
+ # Collection of arguments so they can be shared across qt_internal_add_executable
+ # and qt_internal_add_test_helper.
+ set(__qt_internal_add_executable_optional_args
+ GUI
+ NO_INSTALL
+ EXCEPTIONS
+ DELAY_RC
+ DELAY_TARGET_INFO
+ QT_APP
+ NO_UNITY_BUILD
+ )
+ set(__qt_internal_add_executable_single_args
+ CORE_LIBRARY
+ OUTPUT_DIRECTORY
+ INSTALL_DIRECTORY
+ VERSION
+ ${__default_target_info_args}
+ )
+ set(__qt_internal_add_executable_multi_args
+ ${__default_private_args}
+ ${__default_public_args}
+ )
+endmacro()
+
+# Append a config-specific postfix to library names to ensure distinct names
+# in a multi-config build.
+# e.g. lib/libQt6DBus_relwithdebinfo.6.3.0.dylib
+# Don't apply the postfix to the first encountered release-like config, so we have at least one
+# config without a postifx.
+# If postfixes are set by user warn about potential issues.
+function(qt_internal_setup_cmake_config_postfix)
+ # Collect configuration that require postfix in Qt library names.
+ if(QT_GENERATOR_IS_MULTI_CONFIG)
+ set(postfix_configurations ${CMAKE_CONFIGURATION_TYPES})
+ else()
+ set(postfix_configurations ${CMAKE_BUILD_TYPE})
+
+ # Set the default postfix to empty by default for single-config builds.
+ string(TOLOWER "${CMAKE_BUILD_TYPE}" build_type_lower)
+ set(default_cmake_${build_type_lower}_postfix "")
+ endif()
+
+ # Override the generic debug postfixes above with custom debug postfixes (even in a single
+ # config build) to follow the conventions we had since Qt 5.
+ # e.g. lib/libQt6DBus_debug.6.3.0.dylib
+ if(WIN32)
+ if(MINGW)
+ # On MinGW we don't have "d" suffix for debug libraries like on Linux,
+ # unless we're building debug and release libraries in one go.
+ if(QT_GENERATOR_IS_MULTI_CONFIG)
+ set(default_cmake_debug_postfix "d")
+ endif()
+ else()
+ set(default_cmake_debug_postfix "d")
+ endif()
+ elseif(APPLE)
+ set(default_cmake_debug_postfix "_debug")
+ endif()
+
+ set(custom_postfix_vars "")
+ set(release_configs Release RelWithDebInfo MinSizeRel)
+ set(found_first_release_config FALSE)
+ foreach(config_type IN LISTS postfix_configurations)
+ string(TOLOWER "${config_type}" config_type_lower)
+ string(TOUPPER "${config_type}" config_type_upper)
+ set(postfix_var CMAKE_${config_type_upper}_POSTFIX)
+
+ # Skip assigning postfix for the first release-like config.
+ if(NOT found_first_release_config
+ AND config_type IN_LIST release_configs)
+ set(found_first_release_config TRUE)
+ if(NOT "${${postfix_var}}" STREQUAL "")
+ list(APPEND custom_postfix_vars ${postfix_var})
+ endif()
+ continue()
+ endif()
+
+ # Check if the default postfix is set, use '_<config_type_lower>' otherwise.
+ set(default_postfix_var
+ default_cmake_${config_type_lower}_postfix)
+ if(NOT DEFINED ${default_postfix_var})
+ set(${default_postfix_var}
+ "_${config_type_lower}")
+ endif()
+
+ # If postfix is set by user avoid changing it, but save postfix variable that has
+ # a non-default value for further warning.
+ if("${${postfix_var}}" STREQUAL "")
+ set(${postfix_var} "${${default_postfix_var}}" PARENT_SCOPE)
+ elseif(NOT "${${postfix_var}}" STREQUAL "${${default_postfix_var}}")
+ list(APPEND custom_postfix_vars ${postfix_var})
+ endif()
+
+ # Adjust framework postfixes accordingly
+ if(APPLE)
+ set(CMAKE_FRAMEWORK_MULTI_CONFIG_POSTFIX_${config_type_upper}
+ "${${postfix_var}}" PARENT_SCOPE)
+ endif()
+ endforeach()
+ if(custom_postfix_vars)
+ list(REMOVE_DUPLICATES custom_postfix_vars)
+ list(JOIN custom_postfix_vars ", " postfix_vars_string)
+
+ message(WARNING "You are using custom library postfixes: '${postfix_vars_string}' which are"
+ " considered experimental and are not officially supported by Qt."
+ " Expect unforeseen issues and user projects built with qmake to be broken."
+ )
+ endif()
endfunction()
function(qt_is_imported_target target out_var)
@@ -219,20 +554,20 @@ endfunction()
# On Windows, these properties are used to generate the version information resource.
function(qt_set_target_info_properties target)
cmake_parse_arguments(arg "" "${__default_target_info_args}" "" ${ARGN})
- if("${arg_TARGET_VERSION}" STREQUAL "")
+ if(NOT arg_TARGET_VERSION)
set(arg_TARGET_VERSION "${PROJECT_VERSION}.0")
endif()
- if("${arg_TARGET_PRODUCT}" STREQUAL "")
+ if(NOT arg_TARGET_PRODUCT)
set(arg_TARGET_PRODUCT "Qt6")
endif()
- if("${arg_TARGET_DESCRIPTION}" STREQUAL "")
+ if(NOT arg_TARGET_DESCRIPTION)
set(arg_TARGET_DESCRIPTION "C++ Application Development Framework")
endif()
- if("${arg_TARGET_COMPANY}" STREQUAL "")
+ if(NOT arg_TARGET_COMPANY)
set(arg_TARGET_COMPANY "The Qt Company Ltd.")
endif()
- if("${arg_TARGET_COPYRIGHT}" STREQUAL "")
- set(arg_TARGET_COPYRIGHT "Copyright (C) 2022 The Qt Company Ltd.")
+ if(NOT arg_TARGET_COPYRIGHT)
+ set(arg_TARGET_COPYRIGHT "${QT_COPYRIGHT}")
endif()
set_target_properties(${target} PROPERTIES
QT_TARGET_VERSION "${arg_TARGET_VERSION}"
@@ -479,56 +814,139 @@ endif()
endif()
# INTERFACE libraries don't have IMPORTED_LOCATION-like properties.
- # OBJECT libraries have properties like IMPORTED_OBJECTS instead.
- # Skip the rest of the procesing for those.
- if(target_type STREQUAL "INTERFACE_LIBRARY" OR target_type STREQUAL "OBJECT_LIBRARY")
+ # Skip the rest of the processing for those.
+ if(target_type STREQUAL "INTERFACE_LIBRARY")
continue()
endif()
set(properties_retrieved TRUE)
+ get_target_property(is_configure_time_target ${target} _qt_internal_configure_time_target)
+ if(is_configure_time_target)
+ # For Multi-config developer builds we should simply reuse IMPORTED_LOCATION of the
+ # target.
+ if(NOT QT_WILL_INSTALL AND QT_FEATURE_debug_and_release)
+ set(configure_time_target_build_location "")
+ get_target_property(configure_time_target_install_location ${target}
+ IMPORTED_LOCATION)
+ else()
+ if(IS_ABSOLUTE "${arg_CONFIG_INSTALL_DIR}")
+ file(RELATIVE_PATH reverse_relative_prefix_path
+ "${arg_CONFIG_INSTALL_DIR}" "${CMAKE_INSTALL_PREFIX}")
+ else()
+ file(RELATIVE_PATH reverse_relative_prefix_path
+ "${CMAKE_INSTALL_PREFIX}/${arg_CONFIG_INSTALL_DIR}"
+ "${CMAKE_INSTALL_PREFIX}")
+ endif()
+
+ get_target_property(configure_time_target_build_location ${target}
+ _qt_internal_configure_time_target_build_location)
+ string(TOUPPER "${QT_CMAKE_EXPORT_NAMESPACE}_INSTALL_PREFIX" install_prefix_var)
+ string(JOIN "" configure_time_target_build_location
+ "$\{CMAKE_CURRENT_LIST_DIR}/"
+ "${reverse_relative_prefix_path}"
+ "${configure_time_target_build_location}")
+
+ get_target_property(configure_time_target_install_location ${target}
+ _qt_internal_configure_time_target_install_location)
+
+ string(JOIN "" configure_time_target_install_location
+ "$\{CMAKE_CURRENT_LIST_DIR}/"
+ "${reverse_relative_prefix_path}"
+ "${configure_time_target_install_location}")
+ endif()
+ if(configure_time_target_install_location)
+ string(APPEND content "
+# Import configure-time executable ${full_target}
+if(NOT TARGET ${full_target})
+ set(_qt_imported_build_location \"${configure_time_target_build_location}\")
+ set(_qt_imported_install_location \"${configure_time_target_install_location}\")
+ set(_qt_imported_location \"\${_qt_imported_install_location}\")
+ if(NOT EXISTS \"$\{_qt_imported_location}\"
+ AND NOT \"$\{_qt_imported_build_location}\" STREQUAL \"\")
+ set(_qt_imported_location \"\${_qt_imported_build_location}\")
+ endif()
+ if(NOT EXISTS \"$\{_qt_imported_location}\")
+ message(FATAL_ERROR \"Unable to add configure time executable ${full_target}\"
+ \" $\{_qt_imported_location} doesn't exists\")
+ endif()
+ add_executable(${full_target} IMPORTED)
+ set_property(TARGET ${full_target} APPEND PROPERTY IMPORTED_CONFIGURATIONS ${default_cfg})
+ set_target_properties(${full_target} PROPERTIES IMPORTED_LOCATION_${uc_default_cfg}
+ \"$\{_qt_imported_location}\")
+ set_property(TARGET ${full_target} PROPERTY IMPORTED_GLOBAL TRUE)
+ unset(_qt_imported_location)
+ unset(_qt_imported_build_location)
+ unset(_qt_imported_install_location)
+endif()
+\n")
+ endif()
+ endif()
+
# Non-prefix debug-and-release builds: add check for the existence of the debug binary of
# the target. It is not built by default.
if(NOT QT_WILL_INSTALL AND QT_FEATURE_debug_and_release)
get_target_property(excluded_genex ${target} EXCLUDE_FROM_ALL)
- if(NOT excluded_genex STREQUAL "")
+ if(excluded_genex)
string(APPEND content "
# ${full_target} is not built by default in the Debug configuration. Check existence.
get_target_property(_qt_imported_location ${full_target} IMPORTED_LOCATION_DEBUG)
-if(NOT EXISTS \"$\\{_qt_imported_location}\")
+if(NOT EXISTS \"$\{_qt_imported_location}\")
get_target_property(_qt_imported_configs ${full_target} IMPORTED_CONFIGURATIONS)
list(REMOVE_ITEM _qt_imported_configs DEBUG)
- set_property(TARGET ${full_target} PROPERTY IMPORTED_CONFIGURATIONS $\\{_qt_imported_configs})
+ set_property(TARGET ${full_target} PROPERTY IMPORTED_CONFIGURATIONS $\{_qt_imported_configs})
set_property(TARGET ${full_target} PROPERTY IMPORTED_LOCATION_DEBUG)
-endif()\n\n")
+endif()\n")
endif()
endif()
set(write_implib FALSE)
set(write_soname FALSE)
+ set(write_objects FALSE)
+ set(write_location TRUE)
+
if(target_type STREQUAL "SHARED_LIBRARY")
if(WIN32)
set(write_implib TRUE)
+ elseif(WASM)
+ # Keep write_soname at FALSE
else()
set(write_soname TRUE)
endif()
+ elseif(target_type STREQUAL "OBJECT_LIBRARY")
+ set(write_objects TRUE)
+ set(write_location FALSE)
endif()
if(NOT "${uc_release_cfg}" STREQUAL "")
- string(APPEND content "get_target_property(_qt_imported_location ${full_target} IMPORTED_LOCATION_${uc_release_cfg})\n")
+ if(write_location)
+ string(APPEND content "get_target_property(_qt_imported_location ${full_target} IMPORTED_LOCATION_${uc_release_cfg})\n")
+ endif()
if(write_implib)
string(APPEND content "get_target_property(_qt_imported_implib ${full_target} IMPORTED_IMPLIB_${uc_release_cfg})\n")
endif()
if(write_soname)
string(APPEND content "get_target_property(_qt_imported_soname ${full_target} IMPORTED_SONAME_${uc_release_cfg})\n")
endif()
+ if(write_objects)
+ string(APPEND content "get_target_property(_qt_imported_objects ${full_target} IMPORTED_OBJECTS_${uc_release_cfg})\n")
+ # We generate CLR props as well, because that's what CMake generates for object
+ # libraries with CMake 3.27. They are usually empty strings though, aka "".
+ string(APPEND content "get_target_property(_qt_imported_clr ${full_target} IMPORTED_COMMON_LANGUAGE_RUNTIME_${uc_release_cfg})\n")
+ endif()
+ endif()
+ if(write_location)
+ string(APPEND content "get_target_property(_qt_imported_location_default ${full_target} IMPORTED_LOCATION_$\{QT_DEFAULT_IMPORT_CONFIGURATION})\n")
endif()
- string(APPEND content "get_target_property(_qt_imported_location_default ${full_target} IMPORTED_LOCATION_$\\{QT_DEFAULT_IMPORT_CONFIGURATION})\n")
if(write_implib)
- string(APPEND content "get_target_property(_qt_imported_implib_default ${full_target} IMPORTED_IMPLIB_$\\{QT_DEFAULT_IMPORT_CONFIGURATION})\n")
+ string(APPEND content "get_target_property(_qt_imported_implib_default ${full_target} IMPORTED_IMPLIB_$\{QT_DEFAULT_IMPORT_CONFIGURATION})\n")
endif()
if(write_soname)
- string(APPEND content "get_target_property(_qt_imported_soname_default ${full_target} IMPORTED_SONAME_$\\{QT_DEFAULT_IMPORT_CONFIGURATION})\n")
+ string(APPEND content "get_target_property(_qt_imported_soname_default ${full_target} IMPORTED_SONAME_$\{QT_DEFAULT_IMPORT_CONFIGURATION})\n")
+ endif()
+ if(write_objects)
+ string(APPEND content "get_target_property(_qt_imported_objects_default ${full_target} IMPORTED_OBJECTS_$\{QT_DEFAULT_IMPORT_CONFIGURATION})\n")
+ string(APPEND content "get_target_property(_qt_imported_clr_default ${full_target} IMPORTED_COMMON_LANGUAGE_RUNTIME_$\{QT_DEFAULT_IMPORT_CONFIGURATION})\n")
endif()
foreach(config ${configurations_to_export} "")
string(TOUPPER "${config}" ucconfig)
@@ -544,20 +962,32 @@ endif()\n\n")
set_property(TARGET ${full_target} APPEND PROPERTY IMPORTED_CONFIGURATIONS ${ucconfig})
")
endif()
- string(APPEND content "
+ if(write_location)
+ string(APPEND content "
if(_qt_imported_location${var_suffix})
- set_property(TARGET ${full_target} PROPERTY IMPORTED_LOCATION${property_suffix} \"$\\{_qt_imported_location${var_suffix}}\")
+ set_property(TARGET ${full_target} PROPERTY IMPORTED_LOCATION${property_suffix} \"$\{_qt_imported_location${var_suffix}}\")
endif()")
+ endif()
if(write_implib)
string(APPEND content "
if(_qt_imported_implib${var_suffix})
- set_property(TARGET ${full_target} PROPERTY IMPORTED_IMPLIB${property_suffix} \"$\\{_qt_imported_implib${var_suffix}}\")
+ set_property(TARGET ${full_target} PROPERTY IMPORTED_IMPLIB${property_suffix} \"$\{_qt_imported_implib${var_suffix}}\")
endif()")
endif()
if(write_soname)
string(APPEND content "
if(_qt_imported_soname${var_suffix})
- set_property(TARGET ${full_target} PROPERTY IMPORTED_SONAME${property_suffix} \"$\\{_qt_imported_soname${var_suffix}}\")
+ set_property(TARGET ${full_target} PROPERTY IMPORTED_SONAME${property_suffix} \"$\{_qt_imported_soname${var_suffix}}\")
+endif()")
+ endif()
+ if(write_objects)
+ string(APPEND content "
+if(_qt_imported_objects${var_suffix})
+ set_property(TARGET ${full_target} PROPERTY IMPORTED_OBJECTS${property_suffix} \"$\{_qt_imported_objects${var_suffix}}\")
+endif()")
+ string(APPEND content "
+if(_qt_imported_clr${var_suffix})
+ set_property(TARGET ${full_target} PROPERTY IMPORTED_COMMON_LANGUAGE_RUNTIME${property_suffix} \"$\{_qt_imported_clr${var_suffix}}\")
endif()")
endif()
string(APPEND content "\n")
@@ -570,6 +1000,10 @@ unset(_qt_imported_location)
unset(_qt_imported_location_default)
unset(_qt_imported_soname)
unset(_qt_imported_soname_default)
+unset(_qt_imported_objects)
+unset(_qt_imported_objects_default)
+unset(_qt_imported_clr)
+unset(_qt_imported_clr_default)
unset(_qt_imported_configs)")
endif()
@@ -583,25 +1017,51 @@ unset(_qt_imported_configs)")
endfunction()
function(qt_internal_export_modern_cmake_config_targets_file)
- cmake_parse_arguments(__arg "" "EXPORT_NAME_PREFIX;CONFIG_INSTALL_DIR" "TARGETS" ${ARGN})
+ cmake_parse_arguments(arg
+ ""
+ "EXPORT_NAME_PREFIX;CONFIG_BUILD_DIR;CONFIG_INSTALL_DIR"
+ "TARGETS"
+ ${ARGN}
+ )
- set(export_name "${__arg_EXPORT_NAME_PREFIX}VersionlessTargets")
- foreach(target ${__arg_TARGETS})
- if (TARGET "${target}Versionless")
- continue()
- endif()
+ if("${arg_TARGETS}" STREQUAL "")
+ message(FATAL_ERROR "Target list is empty")
+ endif()
- add_library("${target}Versionless" INTERFACE)
- target_link_libraries("${target}Versionless" INTERFACE "${target}")
- set_target_properties("${target}Versionless" PROPERTIES
- EXPORT_NAME "${target}"
- _qt_is_versionless_target "TRUE")
- set_property(TARGET "${target}Versionless"
- APPEND PROPERTY EXPORT_PROPERTIES _qt_is_versionless_target)
+ if("${arg_CONFIG_BUILD_DIR}" STREQUAL "")
+ message(FATAL_ERROR "CONFIG_BUILD_DIR is not specified")
+ endif()
- qt_install(TARGETS "${target}Versionless" EXPORT ${export_name})
- endforeach()
- qt_install(EXPORT ${export_name} NAMESPACE Qt:: DESTINATION "${__arg_CONFIG_INSTALL_DIR}")
+ if("${arg_CONFIG_INSTALL_DIR}" STREQUAL "")
+ message(FATAL_ERROR "CONFIG_INSTALL_DIR is not specified")
+ endif()
+
+ if("${arg_EXPORT_NAME_PREFIX}" STREQUAL "")
+ message(FATAL_ERROR "EXPORT_NAME_PREFIX is not specified")
+ endif()
+
+ set(versionless_targets ${arg_TARGETS})
+
+ # CMake versions < 3.18 compatibility code. Creates the mimics of the versioned libraries.
+ set(versionless_targets_export "${arg_CONFIG_BUILD_DIR}/${arg_EXPORT_NAME_PREFIX}VersionlessTargets.cmake")
+ configure_file("${QT_CMAKE_DIR}/QtVersionlessTargets.cmake.in"
+ "${versionless_targets_export}"
+ @ONLY
+ )
+
+ # CMake versions >= 3.18 code. Create the versionless ALIAS targets.
+ set(alias_export "${arg_CONFIG_BUILD_DIR}/${arg_EXPORT_NAME_PREFIX}VersionlessAliasTargets.cmake")
+ configure_file("${QT_CMAKE_DIR}/QtVersionlessAliasTargets.cmake.in"
+ "${alias_export}"
+ @ONLY
+ )
+
+ qt_install(FILES
+ "${alias_export}"
+ "${versionless_targets_export}"
+ DESTINATION "${arg_CONFIG_INSTALL_DIR}"
+ COMPONENT Devel
+ )
endfunction()
function(qt_internal_create_tracepoints name tracepoints_file)
@@ -610,20 +1070,22 @@ function(qt_internal_create_tracepoints name tracepoints_file)
set(header_filename "${provider_name}_tracepoints_p.h")
set(header_path "${CMAKE_CURRENT_BINARY_DIR}/${header_filename}")
- if(QT_FEATURE_lttng OR QT_FEATURE_etw)
+ if(QT_FEATURE_lttng OR QT_FEATURE_etw OR QT_FEATURE_ctf)
set(source_path "${CMAKE_CURRENT_BINARY_DIR}/${provider_name}_tracepoints.cpp")
qt_configure_file(OUTPUT "${source_path}"
CONTENT "#define TRACEPOINT_CREATE_PROBES
#define TRACEPOINT_DEFINE
#include \"${header_filename}\"")
target_sources(${name} PRIVATE "${source_path}")
- target_compile_definitions(${name} PRIVATE Q_TRACEPOINT)
+ target_compile_definitions(${name} PUBLIC Q_TRACEPOINT)
if(QT_FEATURE_lttng)
set(tracegen_arg "lttng")
target_link_libraries(${name} PRIVATE LTTng::UST)
elseif(QT_FEATURE_etw)
set(tracegen_arg "etw")
+ elseif(QT_FEATURE_ctf)
+ set(tracegen_arg "ctf")
endif()
if(NOT "${QT_HOST_PATH}" STREQUAL "")
@@ -646,12 +1108,87 @@ function(qt_internal_create_tracepoints name tracepoints_file)
endif()
endfunction()
+function(qt_internal_generate_tracepoints name provider)
+ cmake_parse_arguments(arg "" "" "SOURCES" ${ARGN} )
+ set(provider_name ${provider})
+ string(PREPEND provider_name "qt")
+ set(tracepoint_filename "${provider_name}.tracepoints")
+ set(tracepoints_path "${CMAKE_CURRENT_BINARY_DIR}/${tracepoint_filename}")
+ set(header_filename "${provider_name}_tracepoints_p.h")
+ set(header_path "${CMAKE_CURRENT_BINARY_DIR}/${header_filename}")
+
+ if(QT_FEATURE_lttng OR QT_FEATURE_etw OR QT_FEATURE_ctf)
+
+ set(absolute_file_paths "")
+ foreach(file IN LISTS arg_SOURCES)
+ get_filename_component(absolute_file ${file} ABSOLUTE)
+ list(APPEND absolute_file_paths ${absolute_file})
+ endforeach()
+
+ if(NOT "${QT_HOST_PATH}" STREQUAL "")
+ qt_path_join(tracepointgen
+ "${QT_HOST_PATH}"
+ "${QT${PROJECT_VERSION_MAJOR}_HOST_INFO_LIBEXECDIR}"
+ "tracepointgen")
+ else()
+ set(tracepointgen "${QT_CMAKE_EXPORT_NAMESPACE}::tracepointgen")
+ endif()
+
+ add_custom_command(OUTPUT "${tracepoints_path}"
+ COMMAND ${tracepointgen} ${provider_name} "${tracepoints_path}" "I$<JOIN:$<TARGET_PROPERTY:${name},INCLUDE_DIRECTORIES>,;>" ${absolute_file_paths}
+ DEPENDS ${absolute_file_paths}
+ VERBATIM)
+ add_custom_target(${name}_${provider_name}_tracepoints_file DEPENDS "${tracepoints_path}")
+ add_dependencies(${name} ${name}_${provider_name}_tracepoints_file)
+
+ set(source_path "${CMAKE_CURRENT_BINARY_DIR}/${provider_name}_tracepoints.cpp")
+ qt_configure_file(OUTPUT "${source_path}"
+ CONTENT "#define TRACEPOINT_CREATE_PROBES
+ #define TRACEPOINT_DEFINE
+ #include \"${header_filename}\"")
+ target_sources(${name} PRIVATE "${source_path}")
+ target_compile_definitions(${name} PUBLIC Q_TRACEPOINT)
+
+ if(QT_FEATURE_lttng)
+ set(tracegen_arg "lttng")
+ target_link_libraries(${name} PRIVATE LTTng::UST)
+ elseif(QT_FEATURE_etw)
+ set(tracegen_arg "etw")
+ elseif(QT_FEATURE_ctf)
+ set(tracegen_arg "ctf")
+ endif()
+
+ if(NOT "${QT_HOST_PATH}" STREQUAL "")
+ qt_path_join(tracegen
+ "${QT_HOST_PATH}"
+ "${QT${PROJECT_VERSION_MAJOR}_HOST_INFO_LIBEXECDIR}"
+ "tracegen")
+ else()
+ set(tracegen "${QT_CMAKE_EXPORT_NAMESPACE}::tracegen")
+ endif()
+
+ get_filename_component(tracepoints_filepath "${tracepoints_path}" ABSOLUTE)
+ add_custom_command(OUTPUT "${header_path}"
+ COMMAND ${tracegen} ${tracegen_arg} "${tracepoints_filepath}" "${header_path}"
+ DEPENDS "${tracepoints_path}"
+ VERBATIM)
+ add_custom_target(${name}_${provider_name}_tracepoints_header DEPENDS "${header_path}")
+ add_dependencies(${name} ${name}_${provider_name}_tracepoints_header)
+ else()
+ qt_configure_file(OUTPUT "${header_path}" CONTENT "#include <private/qtrace_p.h>\n")
+ endif()
+endfunction()
+
function(qt_internal_set_compile_pdb_names target)
if(MSVC)
get_target_property(target_type ${target} TYPE)
if(target_type STREQUAL "STATIC_LIBRARY" OR target_type STREQUAL "OBJECT_LIBRARY")
- set_target_properties(${target} PROPERTIES COMPILE_PDB_NAME "${INSTALL_CMAKE_NAMESPACE}${target}")
- set_target_properties(${target} PROPERTIES COMPILE_PDB_NAME_DEBUG "${INSTALL_CMAKE_NAMESPACE}${target}d")
+ get_target_property(output_name ${target} OUTPUT_NAME)
+ if(NOT output_name)
+ set(output_name "${INSTALL_CMAKE_NAMESPACE}${target}")
+ endif()
+ set_target_properties(${target} PROPERTIES COMPILE_PDB_NAME "${output_name}")
+ set_target_properties(${target} PROPERTIES COMPILE_PDB_NAME_DEBUG "${output_name}d")
endif()
endif()
endfunction()
@@ -660,12 +1197,12 @@ endfunction()
#
# MSVC generates 2 types of pdb files:
# - compile-time generated pdb files (compile flag /Zi + /Fd<pdb_name>)
-# - link-time genereated pdb files (link flag /debug + /PDB:<pdb_name>)
+# - link-time generated pdb files (link flag /debug + /PDB:<pdb_name>)
#
# CMake allows changing the names of each of those pdb file types by setting
# the COMPILE_PDB_NAME_<CONFIG> and PDB_NAME_<CONFIG> properties. If they are
# left empty, CMake will compute the default names itself (or rather in certain cases
-# leave it up to te compiler), without actually setting the property values.
+# leave it up to the compiler), without actually setting the property values.
#
# For installation purposes, CMake only provides a generator expression to the
# link time pdb file path, not the compile path one, which means we have to compute the
@@ -712,8 +1249,9 @@ function(qt_internal_install_pdb_files target install_dir_path)
"Can't install pdb file for static library ${target}. "
"The ARCHIVE_OUTPUT_DIRECTORY path is not known.")
endif()
- set(pdb_name "${INSTALL_CMAKE_NAMESPACE}${target}$<$<CONFIG:Debug>:d>.pdb")
- qt_path_join(compile_time_pdb_file_path "${lib_dir}" "${pdb_name}")
+ get_target_property(pdb_name "${target}" COMPILE_PDB_NAME)
+ qt_path_join(compile_time_pdb_file_path
+ "${lib_dir}" "${pdb_name}$<$<CONFIG:Debug>:d>.pdb")
qt_install(FILES "${compile_time_pdb_file_path}"
DESTINATION "${install_dir_path}" OPTIONAL)
@@ -725,8 +1263,9 @@ function(qt_internal_install_pdb_files target install_dir_path)
qt_path_join(pdb_dir "${pdb_dir}" "$<CONFIG>")
endif()
endif()
- set(pdb_name "${INSTALL_CMAKE_NAMESPACE}${target}$<$<CONFIG:Debug>:d>.pdb")
- qt_path_join(compile_time_pdb_file_path "${pdb_dir}" "${pdb_name}")
+ get_target_property(pdb_name "${target}" COMPILE_PDB_NAME)
+ qt_path_join(compile_time_pdb_file_path
+ "${pdb_dir}" "${pdb_name}$<$<CONFIG:Debug>:d>.pdb")
qt_install(FILES "${compile_time_pdb_file_path}"
DESTINATION "${install_dir_path}" OPTIONAL)
@@ -797,6 +1336,33 @@ endfunction()
# Needed to allow selectively applying certain flags via PlatformXInternal targets.
function(qt_internal_mark_as_internal_library target)
set_target_properties(${target} PROPERTIES _qt_is_internal_library TRUE)
+ qt_internal_mark_as_internal_target(${target})
+endfunction()
+
+# Marks a target with a property that it was built using the internal Qt API (qt_internal_*) as
+# opposed to it being a user project library or executable(qt_add_*, etc).
+#
+# Needed to allow selectively applying certain flags via PlatformXInternal targets.
+function(qt_internal_mark_as_internal_target target)
+ set_target_properties(${target} PROPERTIES _qt_is_internal_target TRUE)
+endfunction()
+
+# Marks a target with a property to skip it adding it as a dependency when building examples as
+# ExternalProjects.
+# Needed to create a ${repo}_src global target that examples can depend on in multi-config builds
+# due to a bug in AUTOUIC.
+#
+# See QTBUG-110369.
+function(qt_internal_skip_dependency_for_examples target)
+ set_target_properties(${target} PROPERTIES _qt_skip_dependency_for_examples TRUE)
+endfunction()
+
+function(qt_internal_is_target_skipped_for_examples target out_var)
+ get_property(is_skipped TARGET ${target} PROPERTY _qt_skip_dependency_for_examples)
+ if(NOT is_skipped)
+ set(is_skipped FALSE)
+ endif()
+ set(${out_var} "${is_skipped}" PARENT_SCOPE)
endfunction()
function(qt_internal_link_internal_platform_for_object_library target)
@@ -844,7 +1410,7 @@ endfunction()
# To achieve that, consumers of ${target} will only get the include directories of ${dep_target}
# if the latter package and target exists.
#
-# A find_package(dep_target) dependency is added to ${target}'s ModuleDependencies.cmake file.
+# A find_package(dep_target) dependency is added to ${target}'s *Dependencies.cmake file.
#
# We use target_include_directories(PRIVATE) instead of target_link_libraries(PRIVATE) because the
# latter would propagate a mandatory LINK_ONLY dependency on the ${dep_target} in a static Qt build.
@@ -857,3 +1423,249 @@ function(qt_internal_add_target_include_dirs_and_optionally_propagate target dep
qt_record_extra_third_party_dependency("${target}" "${dep_target}")
endfunction()
+
+# The function disables one or multiple internal global definitions that are defined by the
+# qt_internal_add_global_definition function for a specific 'target'.
+function(qt_internal_undefine_global_definition target)
+ if(NOT TARGET "${target}")
+ message(FATAL_ERROR "${target} is not a target.")
+ endif()
+ qt_internal_is_skipped_test(skipped ${target})
+ if(skipped)
+ return()
+ endif()
+ qt_internal_is_in_test_batch(in_batch ${target})
+ if(in_batch)
+ _qt_internal_test_batch_target_name(target)
+ endif()
+
+ if("${ARGN}" STREQUAL "")
+ message(FATAL_ERROR "The function expects at least one definition as an argument.")
+ endif()
+
+ foreach(definition IN LISTS ARGN)
+ set(undef_property_name "QT_INTERNAL_UNDEF_${definition}")
+ set_target_properties(${target} PROPERTIES "${undef_property_name}" TRUE)
+ endforeach()
+endfunction()
+
+# This function adds any defines which are local to the current repository (e.g. qtbase,
+# qtmultimedia). Those can be defined in the corresponding .cmake.conf file via
+# QT_EXTRA_INTERNAL_TARGET_DEFINES. QT_EXTRA_INTERNAL_TARGET_DEFINES accepts a list of definitions.
+# The definitions are passed to target_compile_definitions, which means that values can be provided
+# via the FOO=Bar syntax
+# This does nothing for interface targets
+function(qt_internal_add_repo_local_defines target)
+ get_target_property(type "${target}" TYPE)
+ if (${type} STREQUAL "INTERFACE_LIBRARY")
+ return()
+ endif()
+ if(DEFINED QT_EXTRA_INTERNAL_TARGET_DEFINES)
+ target_compile_definitions("${target}" PRIVATE ${QT_EXTRA_INTERNAL_TARGET_DEFINES})
+ endif()
+endfunction()
+
+# The function returns the value of the target's SOURCES property. The function takes into account
+# the limitation of the CMake version less than 3.19, that restricts to add non-interface sources
+# to an interface target.
+# Note: The function works correctly only if qt_internal_extend_target is used when adding source
+# files.
+function(qt_internal_get_target_sources out_var target)
+ qt_internal_get_target_sources_property(sources_property)
+ get_target_property(${out_var} ${target} ${sources_property})
+ set(${out_var} "${${out_var}}" PARENT_SCOPE)
+endfunction()
+
+# The function distinguishes what property supposed to store target sources, based on target TYPE
+# and the CMake version.
+function(qt_internal_get_target_sources_property out_var)
+ set(${out_var} "SOURCES")
+ get_target_property(target_type ${target} TYPE)
+ if(CMAKE_VERSION VERSION_LESS "3.19" AND target_type STREQUAL "INTERFACE_LIBRARY")
+ set(${out_var} "_qt_internal_target_sources")
+ endif()
+ set(${out_var} "${${out_var}}" PARENT_SCOPE)
+endfunction()
+
+# This function collects target properties that contain generator expressions and needs to be
+# exported. This function is needed since the CMake EXPORT_PROPERTIES property doesn't support
+# properties that contain generator expressions.
+# Usage: qt_internal_add_genex_properties_export(target properties...)
+function(qt_internal_add_genex_properties_export target)
+ get_cmake_property(is_multi_config GENERATOR_IS_MULTI_CONFIG)
+
+ set(config_check_begin "")
+ set(config_check_end "")
+ if(is_multi_config)
+ list(GET CMAKE_CONFIGURATION_TYPES 0 first_config_type)
+
+ # The genex snippet is evaluated to '$<NOT:$<BOOL:$<CONFIG>>>' in the generated cmake file.
+ # The check is only applicable to the 'main' configuration. If user project doesn't use
+ # multi-config generator, then the check supposed to return true and the value from the
+ # 'main' configuration supposed to be used.
+ string(JOIN "" check_if_config_empty
+ "$<1:$><NOT:"
+ "$<1:$><BOOL:"
+ "$<1:$><CONFIG$<ANGLE-R>"
+ "$<ANGLE-R>"
+ "$<ANGLE-R>"
+ )
+
+ # The genex snippet is evaluated to '$<CONFIG:'Qt config type'>' in the generated cmake
+ # file and checks if the config that user uses matches the generated cmake file config.
+ string(JOIN "" check_user_config
+ "$<1:$><CONFIG:$<CONFIG>$<ANGLE-R>"
+ )
+
+ # The genex snippet is evaluated to '$<$<OR:$<CONFIG:'Qt config type'>>:'Property content'>
+ # for non-main Qt configs and to
+ # $<$<OR:$<CONFIG:'Qt config type'>,$<NOT:$<BOOL:$<CONFIG>>>>:'Property content'> for the
+ # main Qt config. This guard is required to choose the correct value of the property for the
+ # user project according to the user config type.
+ # All genexes need to be escaped properly to protect them from evaluation by the
+ # file(GENERATE call in the qt_internal_export_genex_properties function.
+ string(JOIN "" config_check_begin
+ "$<1:$><"
+ "$<1:$><OR:"
+ "${check_user_config}"
+ "$<$<CONFIG:${first_config_type}>:$<COMMA>${check_if_config_empty}>"
+ "$<ANGLE-R>:"
+ )
+ set(config_check_end "$<ANGLE-R>")
+ endif()
+ set(target_name "${QT_CMAKE_EXPORT_NAMESPACE}::${target}")
+ foreach(property IN LISTS ARGN)
+ set(target_property_genex "$<TARGET_PROPERTY:${target_name},${property}>")
+ # All properties that contain lists need to be protected of processing by JOIN genex calls.
+ # So this escapes the semicolons for these list.
+ set(target_property_list_escape
+ "$<JOIN:$<GENEX_EVAL:${target_property_genex}>,\;>")
+ set(property_value
+ "\"${config_check_begin}${target_property_list_escape}${config_check_end}\"")
+ set_property(TARGET ${target} APPEND PROPERTY _qt_export_genex_properties_content
+ "${property} ${property_value}")
+ endforeach()
+endfunction()
+
+# This function executes generator expressions for the properties that are added by the
+# qt_internal_add_genex_properties_export function and sets the calculated values to the
+# corresponding properties in the generated ExtraProperties.cmake file. The file then needs to be
+# included after the target creation routines in Config.cmake files. It also supports Multi-Config
+# builds.
+# Arguments:
+# EXPORT_NAME_PREFIX:
+# The portion of the file name before ExtraProperties.cmake
+# CONFIG_INSTALL_DIR:
+# Installation location for the file.
+# TARGETS:
+# The internal target names.
+function(qt_internal_export_genex_properties)
+ set(option_args "")
+ set(single_args
+ EXPORT_NAME_PREFIX
+ CONFIG_INSTALL_DIR
+ )
+ set(multi_args TARGETS)
+ cmake_parse_arguments(arg "${option_args}" "${single_args}" "${multi_args}" ${ARGN})
+
+ if(NOT arg_EXPORT_NAME_PREFIX)
+ message(FATAL_ERROR "qt_internal_export_genex_properties: "
+ "Missing EXPORT_NAME_PREFIX argument.")
+ endif()
+
+ if(NOT arg_TARGETS)
+ message(FATAL_ERROR "qt_internal_export_genex_properties: "
+ "TARGETS argument must contain at least one target")
+ endif()
+
+ foreach(target IN LISTS arg_TARGETS)
+ get_cmake_property(is_multi_config GENERATOR_IS_MULTI_CONFIG)
+
+ set(output_file_base_name "${arg_EXPORT_NAME_PREFIX}ExtraProperties")
+ set(should_append "")
+ set(config_suffix "")
+ if(is_multi_config)
+ list(GET CMAKE_CONFIGURATION_TYPES 0 first_config_type)
+ set(config_suffix "$<$<NOT:$<CONFIG:${first_config_type}>>:-$<CONFIG>>")
+ # If the generated file belongs to the 'main' config type, we should set property
+ # but not append it.
+ string(JOIN "" should_append
+ "$<$<NOT:$<CONFIG:${first_config_type}>>: APPEND>")
+ endif()
+ set(file_name "${output_file_base_name}${config_suffix}.cmake")
+
+ qt_path_join(output_file "${arg_CONFIG_INSTALL_DIR}"
+ "${file_name}")
+
+ if(NOT IS_ABSOLUTE "${output_file}")
+ qt_path_join(output_file "${QT_BUILD_DIR}" "${output_file}")
+ endif()
+
+ set(target_name "${QT_CMAKE_EXPORT_NAMESPACE}::${target}")
+
+ string(JOIN "" set_property_begin "set_property(TARGET "
+ "${target_name}${should_append} PROPERTY "
+ )
+ set(set_property_end ")")
+ set(set_property_glue "${set_property_end}\n${set_property_begin}")
+ set(property_list
+ "$<GENEX_EVAL:$<TARGET_PROPERTY:${target},_qt_export_genex_properties_content>>")
+ string(JOIN "" set_property_content "${set_property_begin}"
+ "$<JOIN:${property_list},${set_property_glue}>"
+ "${set_property_end}")
+
+ if(is_multi_config)
+ set(config_includes "")
+ foreach(config IN LISTS CMAKE_CONFIGURATION_TYPES)
+ if(NOT first_config_type STREQUAL config)
+ set(include_file_name
+ "${output_file_base_name}-${config}.cmake")
+ list(APPEND config_includes
+ "include(\"\${CMAKE_CURRENT_LIST_DIR}/${include_file_name}\")")
+ endif()
+ endforeach()
+ list(JOIN config_includes "\n" config_includes_string)
+ set(config_includes_string
+ "\n$<$<CONFIG:${first_config_type}>:${config_includes_string}>")
+ endif()
+
+ file(GENERATE OUTPUT "${output_file}"
+ CONTENT "$<$<BOOL:${property_list}>:${set_property_content}${config_includes_string}>"
+ CONDITION "$<BOOL:${property_list}>"
+ )
+ endforeach()
+
+ qt_install(FILES "$<$<BOOL:${property_list}>:${output_file}>"
+ DESTINATION "${arg_CONFIG_INSTALL_DIR}"
+ COMPONENT Devel
+ )
+endfunction()
+
+# The macro promotes the Qt platform targets and their dependencies to global. The macro shouldn't
+# be called explicitly in regular cases. It's called right after the first find_package(Qt ...)
+# call in the qt_internal_project_setup macro.
+# This allows using the qt_find_package(Wrap<3rdparty> PROVIDED_TARGETS ...) function,
+# without the risk of having duplicated global promotion of Qt internals. This is especially
+# sensitive for the bundled 3rdparty libraries.
+macro(qt_internal_promote_platform_targets_to_global)
+ if(TARGET Qt6::Platform)
+ get_target_property(is_imported Qt6::Platform IMPORTED)
+ if(is_imported)
+ set(known_platform_targets
+ Platform
+ PlatformCommonInternal
+ PlatformModuleInternal
+ PlatformPluginInternal
+ PlatformAppInternal
+ PlatformToolInternal
+ )
+ set(versionless_platform_targets ${known_platform_targets})
+
+ list(TRANSFORM known_platform_targets PREPEND Qt6::)
+ list(TRANSFORM versionless_platform_targets PREPEND Qt::)
+ qt_find_package(Qt6 PROVIDED_TARGETS
+ ${known_platform_targets}
+ ${versionless_platform_targets})
+ endif()
+ endif()
+endmacro()