CMake: Duplicate backing library metatypes to its associated plugin

qmltyperegistar and other tooling expect a list of foreign metatypes
derived from the full set of dependencies of the target it's
processing.

If a target was linking to a qml plugin, and not its backing library,
the metatypes of the backing library were not passed to the tooling.

The mechanism by which the metatypes are collected is via CMake's
INTERFACE_SOURCES, and because the qml plugin links PRIVATEly to its
backing library, in the chain app <- plugin <- backing lib
the backing lib's interface sources were not passed to app.

To work around this, use new qtbase api to duplicate the metatypes
of the backing library to its associated qml plugin's
INTERFACE_SOURCES, thus avoiding the issue.

This is the best we can do given the CMake limitation of not being able
to transitively propagate values of any custom property and without
relying on finalizers.
See https://gitlab.kitware.com/cmake/cmake/-/issues/20416

Fixes: QTBUG-115152
Change-Id: I8a1652a9b12bad01abce38bb6f381949eaa1feab
Reviewed-by: Alexey Edelev <alexey.edelev@qt.io>
This commit is contained in:
Alexandru Croitor 2023-07-10 17:34:19 +02:00
parent 2cf9aeccdd
commit 7d01e7ef87
2 changed files with 52 additions and 0 deletions

View File

@ -391,6 +391,25 @@ function(qt_internal_add_qml_module target)
FILES ${arg_OUTPUT_DIRECTORY}/$<TARGET_PROPERTY:${target},QT_QML_MODULE_TYPEINFO>
DESTINATION "${arg_INSTALL_DIRECTORY}"
)
# Assign the install time metatypes file of the backing library to the plugin.
# Only do it if the backing library is different from the plugin and we do generate
# qml types.
# The install time metatypes only apply to Qt's own qml plugins, not to user project
# qml plugins.
if(arg_PLUGIN_TARGET AND
TARGET "${arg_PLUGIN_TARGET}" AND NOT target STREQUAL arg_PLUGIN_TARGET)
_qt_internal_get_metatypes_install_dir(
""
"${INSTALL_ARCHDATADIR}"
install_dir
)
_qt_internal_assign_install_metatypes_files_and_properties(
"${arg_PLUGIN_TARGET}"
INSTALL_DIR "${install_dir}"
)
endif()
endif()
if(NOT arg_NO_GENERATE_QMLDIR)

View File

@ -537,7 +537,10 @@ Check https://doc.qt.io/qt-6/qt-cmake-policy-qtp0001.html for policy details."
if(arg_NAMESPACE)
list(APPEND type_registration_extra_args NAMESPACE ${arg_NAMESPACE})
endif()
set_target_properties(${target} PROPERTIES _qt_internal_has_qmltypes TRUE)
_qt_internal_qml_type_registration(${target} ${type_registration_extra_args})
else()
set_target_properties(${target} PROPERTIES _qt_internal_has_qmltypes FALSE)
endif()
set(output_targets)
@ -1747,6 +1750,36 @@ function(qt6_add_qml_plugin target)
)
endif()
# Work around QTBUG-115152.
# Assign / duplicate the backing library's metatypes file to the qml plugin.
# This ensures that the metatypes are passed as foreign types to qmltyperegistrar when
# a consumer links against the plugin, but not the backing library.
# This is needed because the plugin links PRIVATEly to the backing library and thus the
# backing library's INTERFACE_SOURCES don't end up in the final consumer's SOURCES.
# Arguably doing this is cleaner than changing the linkage to PUBLIC, because that will
# propagate not only the INTERFACE_SOURCES, but also other link dependencies, which might
# be unwanted.
# In general this is a workaround due to CMake's limitations around support for propagating
# custom properties across targets to a final consumer target.
# https://gitlab.kitware.com/cmake/cmake/-/issues/20416
if(arg_BACKING_TARGET
AND TARGET "${arg_BACKING_TARGET}" AND NOT arg_BACKING_TARGET STREQUAL target)
get_target_property(plugin_meta_types_file "${target}" INTERFACE_QT_META_TYPES_BUILD_FILE)
get_target_property(
backing_meta_types_file "${arg_BACKING_TARGET}" INTERFACE_QT_META_TYPES_BUILD_FILE)
get_target_property(
backing_meta_types_file_name
"${arg_BACKING_TARGET}" INTERFACE_QT_META_TYPES_FILE_NAME)
get_target_property(backing_has_qmltypes "${arg_BACKING_TARGET}" _qt_internal_has_qmltypes)
if(backing_has_qmltypes AND NOT plugin_meta_types_file)
_qt_internal_assign_build_metatypes_files_and_properties(
"${target}"
METATYPES_FILE_NAME "${backing_meta_types_file_name}"
METATYPES_FILE_PATH "${backing_meta_types_file}"
)
endif()
endif()
if(ANDROID)
_qt_internal_get_qml_plugin_output_name(plugin_output_name ${target}
BACKING_TARGET "${arg_BACKING_TARGET}"