diff options
-rw-r--r-- | src/qml/Qt6QmlMacros.cmake | 131 | ||||
-rw-r--r-- | src/qml/qml/qqmlpluginimporter.cpp | 52 |
2 files changed, 113 insertions, 70 deletions
diff --git a/src/qml/Qt6QmlMacros.cmake b/src/qml/Qt6QmlMacros.cmake index a75a8e794b..5ffc39d0ca 100644 --- a/src/qml/Qt6QmlMacros.cmake +++ b/src/qml/Qt6QmlMacros.cmake @@ -532,21 +532,19 @@ function(qt6_add_qml_module target) PROPERTIES QT_RESOURCE_ALIAS "qmldir" ) - if(NOT ANDROID) - foreach(prefix IN LISTS prefixes) - set(resource_targets) - qt6_add_resources(${target} ${qmldir_resource_name} - FILES ${arg_OUTPUT_DIRECTORY}/qmldir - PREFIX "${prefix}" - OUTPUT_TARGETS resource_targets - ) - list(APPEND output_targets ${resource_targets}) - # If we are adding the same file twice, we need a different resource - # name for the second one. It has the same QT_RESOURCE_ALIAS but a - # different prefix, so we can't put it in the same resource. - string(APPEND qmldir_resource_name "_copy") - endforeach() - endif() + foreach(prefix IN LISTS prefixes) + set(resource_targets) + qt6_add_resources(${target} ${qmldir_resource_name} + FILES ${arg_OUTPUT_DIRECTORY}/qmldir + PREFIX "${prefix}" + OUTPUT_TARGETS resource_targets + ) + list(APPEND output_targets ${resource_targets}) + # If we are adding the same file twice, we need a different resource + # name for the second one. It has the same QT_RESOURCE_ALIAS but a + # different prefix, so we can't put it in the same resource. + string(APPEND qmldir_resource_name "_copy") + endforeach() endif() if(NOT arg_NO_PLUGIN AND NOT arg_NO_CREATE_PLUGIN_TARGET) @@ -926,8 +924,12 @@ function(_qt_internal_target_generate_qmldir target) string(APPEND content "optional ") endif() - _qt_internal_get_qml_plugin_basename(plugin_basename ${plugin_target}) - string(APPEND content "plugin ${plugin_basename}\n") + get_target_property(target_path ${target} QT_QML_MODULE_TARGET_PATH) + _qt_internal_get_qml_plugin_output_name(plugin_output_name ${plugin_target} + TARGET_PATH "${target_path}" + URI "${uri}" + ) + string(APPEND content "plugin ${plugin_output_name}\n") _qt_internal_qmldir_item(classname QT_QML_MODULE_CLASS_NAME) endif() @@ -1140,32 +1142,15 @@ function(qt6_add_qml_plugin target) ) endif() - if (ANDROID) - # Adjust Qml plugin names on Android similar to qml_plugin.prf which calls - # $$qt5LibraryTarget($$TARGET, "qml/$$TARGETPATH/"). - # Example plugin names: - # qtdeclarative - # TARGET_PATH: QtQml/Models - # file name: libqml_QtQml_Models_modelsplugin_arm64-v8a.so - # qtquickcontrols2 - # TARGET_PATH: QtQuick/Controls.2/Material - # file name: - # libqml_QtQuick_Controls.2_Material_qtquickcontrols2materialstyleplugin_arm64-v8a.so - if(NOT arg_TARGET_PATH AND TARGET "${arg_BACKING_TARGET}") - get_target_property(arg_TARGET_PATH ${arg_BACKING_TARGET} QT_QML_MODULE_TARGET_PATH) - endif() - if(arg_TARGET_PATH) - string(REPLACE "/" "_" android_plugin_name_infix_name "${arg_TARGET_PATH}") - else() - string(REPLACE "." "_" android_plugin_name_infix_name "${arg_URI}") - endif() - - _qt_internal_get_qml_plugin_basename(plugin_basename ${target}) - set(final_android_qml_plugin_name - "qml_${android_plugin_name_infix_name}_${plugin_basename}") + if(ANDROID) + _qt_internal_get_qml_plugin_output_name(plugin_output_name ${target} + BACKING_TARGET "${arg_BACKING_TARGET}" + TARGET_PATH "${arg_TARGET_PATH}" + URI "${arg_URI}" + ) set_target_properties(${target} PROPERTIES - LIBRARY_OUTPUT_NAME "${final_android_qml_plugin_name}" + LIBRARY_OUTPUT_NAME "${plugin_output_name}" ) qt6_android_apply_arch_suffix(${target}) endif() @@ -2255,17 +2240,65 @@ function(_qt_internal_add_static_qml_plugin_dependencies plugin_target backing_t endif() endfunction() -# The function returns the base output name of a qml plugin that will be used as library output -# name and in a qmldir file as the 'plugin <plugin_basename>' record. -function(_qt_internal_get_qml_plugin_basename out_var plugin_target) - set(plugin_basename) +# The function returns the output name of a qml plugin that will be used as library output +# name and in a qmldir file as the 'plugin <plugin_output_name>' record. +function(_qt_internal_get_qml_plugin_output_name out_var plugin_target) + cmake_parse_arguments(arg + "" + "BACKING_TARGET;TARGET_PATH;URI" + "" + ${ARGN} + ) + set(plugin_name) if(TARGET ${plugin_target}) - get_target_property(plugin_basename ${plugin_target} OUTPUT_NAME) + get_target_property(plugin_name ${plugin_target} OUTPUT_NAME) endif() - if(NOT plugin_basename) - set(plugin_basename "${plugin_target}") + if(NOT plugin_name) + set(plugin_name "${plugin_target}") endif() - set(${out_var} "${plugin_basename}" PARENT_SCOPE) + + if(ANDROID) + # In Android all plugins are stored in directly the /libs directory. This means that plugin + # names must be unique in scope of apk. To make this work we prepend uri-based prefix to + # each qml plugin in case if users don't use the manually written qmldir files. + get_target_property(no_generate_qmldir ${target} QT_QML_MODULE_NO_GENERATE_QMLDIR) + if(TARGET "${arg_BACKING_TARGET}") + get_target_property(no_generate_qmldir ${arg_BACKING_TARGET} + QT_QML_MODULE_NO_GENERATE_QMLDIR) + + # Adjust Qml plugin names on Android similar to qml_plugin.prf which calls + # $$qt5LibraryTarget($$TARGET, "qml/$$TARGETPATH/"). + # Example plugin names: + # qtdeclarative + # TARGET_PATH: QtQml/Models + # file name: libqml_QtQml_Models_modelsplugin_x86_64.so + # qtquickcontrols2 + # TARGET_PATH: QtQuick/Controls.2/Material + # file name: + # libqml_QtQuick_Controls.2_Material_qtquickcontrols2materialstyleplugin_x86_64.so + if(NOT arg_TARGET_PATH) + get_target_property(arg_TARGET_PATH ${arg_BACKING_TARGET} + QT_QML_MODULE_TARGET_PATH) + endif() + endif() + if(arg_TARGET_PATH) + string(REPLACE "/" "_" android_plugin_name_infix_name "${arg_TARGET_PATH}") + else() + string(REPLACE "." "_" android_plugin_name_infix_name "${arg_URI}") + endif() + + # If plugin supposed to use manually written qmldir file we don't prepend the uri-based + # prefix to the plugin output name. User should keep the file name of a QML plugin in + # qmldir the same as the name of plugin on a file system. Exception is the + # ABI-/platform-specific suffix that has the separate processing and should not be + # a part of plugin name in qmldir. + if(NOT no_generate_qmldir) + set(plugin_name + "qml_${android_plugin_name_infix_name}_${plugin_name}") + endif() + endif() + + set(${out_var} "${plugin_name}" PARENT_SCOPE) endfunction() # Used to add extra dependencies between ${target} and ${dep_target} qml plugins in a static diff --git a/src/qml/qml/qqmlpluginimporter.cpp b/src/qml/qml/qqmlpluginimporter.cpp index 512e08731e..c6d2fbe5c2 100644 --- a/src/qml/qml/qqmlpluginimporter.cpp +++ b/src/qml/qml/qqmlpluginimporter.cpp @@ -429,49 +429,59 @@ QString QQmlPluginImporter::resolvePlugin(const QString &qmldirPluginPath, const searchPaths.prepend(qmldirPluginPath); for (const QString &pluginPath : qAsConst(searchPaths)) { - QString resolvedPath; + QString resolvedBasePath; if (pluginPath == QLatin1String(".")) { if (qmldirPluginPathIsRelative && !qmldirPluginPath.isEmpty() && qmldirPluginPath != QLatin1String(".")) { - resolvedPath = QDir::cleanPath(qmldirPath + u'/' + qmldirPluginPath); + resolvedBasePath = QDir::cleanPath(qmldirPath + u'/' + qmldirPluginPath); } else { - resolvedPath = qmldirPath; + resolvedBasePath = qmldirPath; } } else { if (QDir::isRelativePath(pluginPath)) - resolvedPath = QDir::cleanPath(qmldirPath + u'/' + pluginPath); + resolvedBasePath = QDir::cleanPath(qmldirPath + u'/' + pluginPath); else - resolvedPath = pluginPath; + resolvedBasePath = pluginPath; } // hack for resources, should probably go away - if (resolvedPath.startsWith(u':')) - resolvedPath = QCoreApplication::applicationDirPath(); + if (resolvedBasePath.startsWith(u':')) + resolvedBasePath = QCoreApplication::applicationDirPath(); - if (!resolvedPath.endsWith(u'/')) - resolvedPath += u'/'; + if (!resolvedBasePath.endsWith(u'/')) + resolvedBasePath += u'/'; -#if defined(Q_OS_ANDROID) + QString resolvedPath = resolvedBasePath + prefix + baseName; + for (const QString &suffix : suffixes) { + const QString absolutePath = typeLoader->absoluteFilePath(resolvedPath + suffix); + if (!absolutePath.isEmpty()) + return absolutePath; + } + +#if QT_VERSION >= QT_VERSION_CHECK(6, 4, 0) +# if defined(Q_OS_ANDROID) if (qmldirPath.size() > 25 && qmldirPath.at(0) == QLatin1Char(':') - && qmldirPath.at(1) == QLatin1Char('/') && - qmldirPath.startsWith(QStringLiteral(":/android_rcc_bundle/qml/"), - Qt::CaseInsensitive)) { + && qmldirPath.at(1) == QLatin1Char('/') + && qmldirPath.startsWith(QStringLiteral(":/android_rcc_bundle/qml/"), + Qt::CaseInsensitive)) { QString pluginName = qmldirPath.mid(21) + u'/' + baseName; pluginName.replace(QLatin1Char('/'), QLatin1Char('_')); - QString bundledPath = resolvedPath + QLatin1String("lib") + pluginName; + QString bundledPath = resolvedBasePath + QLatin1String("lib") + pluginName; for (const QString &suffix : suffixes) { const QString absolutePath = typeLoader->absoluteFilePath(bundledPath + suffix); - if (!absolutePath.isEmpty()) + if (!absolutePath.isEmpty()) { + qWarning("The implicit resolving of Qml plugin locations using the URI " + "embedded in the filename has been deprecated. Please use the " + "modern CMake API to create QML modules or set the name of " + "QML plugin in qmldir file, that matches the name of plugin " + "on file system. The correct plugin name is '%s'.", + qPrintable(pluginName)); return absolutePath; + } } } +# endif #endif - resolvedPath += prefix + baseName; - for (const QString &suffix : suffixes) { - const QString absolutePath = typeLoader->absoluteFilePath(resolvedPath + suffix); - if (!absolutePath.isEmpty()) - return absolutePath; - } } qCDebug(lcQmlImport) << "resolvePlugin" << "Could not resolve plugin" |