summaryrefslogtreecommitdiffstats
path: root/cmake/QtModuleHelpers.cmake
diff options
context:
space:
mode:
Diffstat (limited to 'cmake/QtModuleHelpers.cmake')
-rw-r--r--cmake/QtModuleHelpers.cmake624
1 files changed, 624 insertions, 0 deletions
diff --git a/cmake/QtModuleHelpers.cmake b/cmake/QtModuleHelpers.cmake
new file mode 100644
index 0000000000..6a4f49dc76
--- /dev/null
+++ b/cmake/QtModuleHelpers.cmake
@@ -0,0 +1,624 @@
+# 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;SKIP_DEPENDS_INCLUDE"
+ "MODULE_INCLUDE_NAME;CONFIG_MODULE_NAME;PRECOMPILED_HEADER;CONFIGURE_FILE_PATH;${__default_target_info_args}"
+ "${__default_private_args};${__default_public_args};${__default_private_module_args};QMAKE_MODULE_CONFIG;EXTRA_CMAKE_FILES;EXTRA_CMAKE_INCLUDES;NO_PCH_SOURCES" ${ARGN})
+
+ qt_internal_add_qt_repo_known_module("${target}")
+
+ if(NOT DEFINED arg_CONFIG_MODULE_NAME)
+ set(arg_CONFIG_MODULE_NAME "${module_lower}")
+ endif()
+
+ ### 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(property_prefix "INTERFACE_")
+ if(NOT arg_HEADER_MODULE)
+ qt_set_common_target_properties(${target})
+ set(property_prefix "")
+ endif()
+
+ set_target_properties(${target} PROPERTIES
+ _qt_config_module_name "${arg_CONFIG_MODULE_NAME}"
+ ${property_prefix}QT_QMAKE_MODULE_CONFIG "${arg_QMAKE_MODULE_CONFIG}")
+ set_property(TARGET "${target}" APPEND PROPERTY EXPORT_PROPERTIES _qt_config_module_name)
+
+ 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(QT_FEATURE_separate_debug_info AND is_shared_lib AND (UNIX OR MINGW))
+ qt_enable_separate_debug_info(${target} ${INSTALL_LIBDIR})
+ 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}")
+ _qt_internal_apply_strict_cpp("${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}")
+ set_target_properties(${target_private} PROPERTIES
+ _qt_config_module_name ${arg_CONFIG_MODULE_NAME}_private)
+ set_property(TARGET "${target_private}" APPEND PROPERTY
+ EXPORT_PROPERTIES _qt_config_module_name)
+ 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_set_target_info_properties(${target} ${ARGN})
+ qt_handle_multi_config_output_dirs("${target}")
+
+ if(NOT BUILD_SHARED_LIBS AND LINUX)
+ # Horrible workaround for static build failures due to incorrect static library link
+ # order. By increasing the multiplicity to 3, each library cycle will be repeated
+ # 3 times on the link line, reducing the probability of undefined symbols at
+ # link time.
+ # These failures are only observed on Linux with the ld linker (not sure about
+ # ld.gold).
+ # Allow opting out and modifying the value via cache value, in case if we urgently
+ # need to increase it without waiting for the qtbase change to propagate to
+ # other dependent repos.
+ # The proper fix will be to get rid of the cycles in the future.
+ # See QTBUG-83498 for details.
+ set(default_link_cycle_multiplicity "3")
+ if(DEFINED QT_LINK_CYCLE_MULTIPLICITY)
+ set(default_link_cycle_multiplicity "${QT_LINK_CYCLE_MULTIPLICITY}")
+ endif()
+ if(default_link_cycle_multiplicity)
+ set_property(TARGET "${target}"
+ PROPERTY
+ LINK_INTERFACE_MULTIPLICITY "${default_link_cycle_multiplicity}")
+ endif()
+ endif()
+
+ if (arg_SKIP_DEPENDS_INCLUDE)
+ set_target_properties(${target} PROPERTIES QT_MODULE_SKIP_DEPENDS_INCLUDE TRUE)
+ endif()
+ 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()
+
+ qt_internal_apply_win_prefix_and_suffix("${target}")
+
+ 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()
+ if(arg_MODULE_INCLUDE_NAME)
+ set(module_include_name ${arg_MODULE_INCLUDE_NAME})
+ else()
+ set(module_include_name ${module})
+ endif()
+ set_target_properties("${target}" PROPERTIES INTERFACE_MODULE_INCLUDE_NAME "${module_include_name}")
+
+ # 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_include_name}"
+ -version "${PROJECT_VERSION}"
+ -outdir "${QT_BUILD_DIR}"
+ -builddir "${PROJECT_BINARY_DIR}"
+ "${PROJECT_SOURCE_DIR}")
+ message(STATUS "Running syncqt for module: '${module_include_name}' ")
+ execute_process(COMMAND ${syncqt_full_command})
+
+ set_target_properties("${target}" PROPERTIES INTERFACE_MODULE_HAS_HEADERS ON)
+
+ ### FIXME: Can we replace headers.pri?
+ set(module_include_dir "${QT_BUILD_DIR}/include/${module_include_name}")
+ qt_read_headers_pri("${module_include_dir}" "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_include_name}")
+ 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_include_name}/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()
+
+ # Save the non-sanitized plugin type values for qmake consumption via .pri files.
+ set_property(TARGET "${target}"
+ PROPERTY QMAKE_MODULE_PLUGIN_TYPES "${arg_PLUGIN_TYPES}")
+ 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")
+ endif()
+
+ # Make sure the BUILD_INTERFACE include paths come before the framework headers, so that the
+ # the compiler prefers the build dir includes.
+ #
+ # Make sure to add non-framework "build_dir/include" as an include path for moc to find the
+ # currently built module headers. qmake does this too.
+ # Framework-style include paths are found by moc when cmQtAutoMocUic.cxx detects frameworks by
+ # looking at an include path and detecting a "QtFoo.framework/Headers" path.
+ # Make sure to create such paths for both the the BUILD_INTERFACE and the INSTALL_INTERFACE.
+ #
+ # Only add syncqt headers if they exist.
+ # This handles cases like QmlDevTools which do not have their own headers, but 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_includes
+ # For the syncqt headers
+ "$<BUILD_INTERFACE:${module_repo_include_dir}>"
+ "$<BUILD_INTERFACE:${module_include_dir}>")
+ endif()
+
+ if(is_framework)
+ set(fw_bundle_subdir "${INSTALL_LIBDIR}/Qt${target}.framework")
+ list(APPEND public_includes
+ # Add the lib/Foo.framework dir as include path to let CMake generate
+ # the -F compiler flag for framework-style includes to work.
+ "$<INSTALL_INTERFACE:${fw_bundle_subdir}>"
+
+ # Add the framework Headers subdir, so that non-framework-style includes work. The
+ # BUILD_INTERFACE Headers symlink was previously claimed not to exist at the relevant
+ # time, and a fully specified Header path was used instead. This doesn't seem to be a
+ # problem anymore.
+ "$<BUILD_INTERFACE:${QT_BUILD_DIR}/${fw_bundle_subdir}/Headers>"
+ "$<INSTALL_INTERFACE:${fw_bundle_subdir}/Headers>"
+ )
+ 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")
+
+ # Provide a *_timestamp target that can be used to trigger the build of custom_commands.
+ set(timestamp_file "${CMAKE_CURRENT_BINARY_DIR}/timestamp")
+ add_custom_command(OUTPUT "${timestamp_file}"
+ COMMAND ${CMAKE_COMMAND} -E touch "${timestamp_file}"
+ DEPENDS ${module_headers_public}
+ VERBATIM)
+ add_custom_target(${target}_timestamp ALL DEPENDS "${timestamp_file}")
+ endif()
+
+ set(defines_for_extend_target "")
+
+ if(NOT arg_HEADER_MODULE)
+ list(APPEND defines_for_extend_target
+ 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}"
+ )
+ 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}
+ ${defines_for_extend_target}
+ 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(arg_CONFIGURE_FILE_PATH)
+ set(configureFile "${arg_CONFIGURE_FILE_PATH}")
+ endif()
+ 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
+ )
+
+ qt_apply_rpaths(TARGET "${target}" INSTALL_PATH "${INSTALL_LIBDIR}" RELATIVE_RPATH)
+
+ 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()
+
+ ### 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})
+ target_link_libraries("${target_private}" INTERFACE "${target}")
+ endif()
+
+ if(is_framework AND NOT is_interface_lib)
+ qt_finalize_framework_headers_copy(${target})
+ endif()
+
+ qt_describe_module(${target})
+ qt_add_list_file_finalizer(qt_finalize_module ${target} ${arg_INTERNAL_MODULE} ${header_module})
+endfunction()
+
+function(qt_finalize_module target)
+ qt_generate_prl_file(${target} "${INSTALL_LIBDIR}")
+ qt_generate_module_pri_file("${target}" ${ARGN})
+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}/include" PARENT_SCOPE)
+ set("${result}_include_dir" "${QT_BUILD_DIR}/include/${module}" PARENT_SCOPE)
+ set("${result}_define" "${define}" PARENT_SCOPE)
+endfunction()
+
+# 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_CROSSCOMPILING)
+ set(cross_compilation "true")
+ endif()
+ configure_file("${descfile_in}" "${descfile_out}")
+
+ qt_install(FILES "${descfile_out}" DESTINATION "${install_dir}")
+endfunction()