diff options
author | Dominik Holland <dominik.holland@pelagicore.com> | 2018-04-26 17:38:03 +0200 |
---|---|---|
committer | Robert Griebl <robert.griebl@pelagicore.com> | 2018-05-03 12:00:10 +0000 |
commit | c2a46c9363e2ef5cf6e5ef2372f07570118369e5 (patch) | |
tree | 4f0077660385171e6a4aed69d9591307a1eb42d0 | |
parent | 967b83e30cde5ca04c126a4d9631d887513c2e98 (diff) |
Fix plugin loading with different configurations
Previously we stopped loading a plugin when the configuration
of QtIviCore didn't match the plugin version. E.g. a release
build loading a debug plugin.
This lead to problems when the plugin is only available in
a different configuration.
The new behavior tries to load the plugins with a matching
configuration, but also accepts different configurations as
a fallback
Task-number: AUTOSUITE-288
Change-Id: Ia6d5ddf74b7b2f04fec31244b7f7db1f5c8de555
Reviewed-by: Robert Griebl <robert.griebl@pelagicore.com>
5 files changed, 90 insertions, 29 deletions
diff --git a/src/ivicore/qiviservicemanager.cpp b/src/ivicore/qiviservicemanager.cpp index 062c3f0..6b7d859 100644 --- a/src/ivicore/qiviservicemanager.cpp +++ b/src/ivicore/qiviservicemanager.cpp @@ -70,6 +70,27 @@ namespace qtivi_helper { static const QString classNameLiteral = QStringLiteral("className"); static const QString simulationLiteral = QStringLiteral("simulation"); static const QString debugLiteral = QStringLiteral("debug"); +#ifdef Q_OS_WIN + static const QString debugSuffixLiteral = QStringLiteral("d"); +#else + static const QString debugSuffixLiteral = QStringLiteral("_debug"); +#endif + + QString backendBaseName(const QString fileName) + { + if (fileName.isEmpty()) + return fileName; + const QFileInfo fi(fileName); + //remove the library suffix + QString baseName = fileName; + baseName.chop(fi.suffix().count() + 1); + + //remove the configuration suffix + if (baseName.endsWith(debugSuffixLiteral)) + baseName.chop(debugSuffixLiteral.count()); + + return baseName; + } } using namespace qtivi_helper; @@ -177,19 +198,11 @@ void QIviServiceManagerPrivate::registerBackend(const QString &fileName, const Q return; } - if (Q_UNLIKELY(metaData.value(debugLiteral).toBool() != qtivi_helper::loadDebug)) { - qCWarning(qLcIviServiceManagement, "Skipping incompatible plugin %s. " - "Expected build configuration '%s'", - qPrintable(fileName), qtivi_helper::loadDebug ? "debug" : "release"); - return; - } - - //TODO check for other metaData like name etc. - backendMetaData.insert(fileNameLiteral, fileName); auto *backend = new Backend; backend->name = metaData.value(classNameLiteral).toString(); + backend->debug = metaData.value(debugLiteral).toBool(); backend->metaData = backendMetaData; backend->interface = nullptr; backend->interfaceObject = nullptr; @@ -209,13 +222,6 @@ void QIviServiceManagerPrivate::registerStaticBackend(QStaticPlugin plugin) return; } - if (Q_UNLIKELY(plugin.metaData().value(debugLiteral).toBool() != qtivi_helper::loadDebug)) { - qCWarning(qLcIviServiceManagement, "Skipping incompatible plugin %s. " - "Expected build configuration '%s'", - pluginName, qtivi_helper::loadDebug ? "debug" : "release"); - return; - } - QIviServiceInterface *backendInterface = qobject_cast<QIviServiceInterface*>(plugin.instance()); if (Q_UNLIKELY(!backendInterface)) qCWarning(qLcIviServiceManagement, "ServiceManager::serviceObjects - failed to cast to interface from '%s'", pluginName); @@ -224,6 +230,7 @@ void QIviServiceManagerPrivate::registerStaticBackend(QStaticPlugin plugin) auto *backend = new Backend; backend->name = plugin.metaData().value(classNameLiteral).toString(); + backend->debug = plugin.metaData().value(debugLiteral).toBool(); backend->metaData = backendMetaData; backend->interface = backendInterface; backend->interfaceObject = nullptr; @@ -252,6 +259,7 @@ bool QIviServiceManagerPrivate::registerBackend(QObject *serviceBackendInterface auto *backend = new Backend; backend->name = QString::fromLocal8Bit(serviceBackendInterface->metaObject()->className()); + backend->debug = false; backend->metaData = metaData; backend->interface = interface; backend->interfaceObject = serviceBackendInterface; @@ -293,13 +301,55 @@ void QIviServiceManagerPrivate::unloadAllBackends() void QIviServiceManagerPrivate::addBackend(Backend *backend) { Q_Q(QIviServiceManager); + //Check whether the same plugin is already in (maybe also in a different configuration) + //The current configuration of QtIviCore decides which configuration takes precedence + + const QString newBackendFile = backend->metaData.value(fileNameLiteral).toString(); + const QString newBackendFileBase = qtivi_helper::backendBaseName(newBackendFile); + const QSet<QString> newInterfaces = backend->metaData.value(interfacesLiteral).toStringList().toSet(); + + bool addBackend = true; + if (!newBackendFile.isEmpty()) { + for (int i = 0; i < m_backends.count(); i++) { + Backend *b = m_backends[i]; + const QSet<QString> interfaces = b->metaData.value(interfacesLiteral).toStringList().toSet(); + if (interfaces == newInterfaces && b->name == backend->name) { + const QString fileName = b->metaData.value(fileNameLiteral).toString(); + if (fileName == newBackendFile) { + qCDebug(qLcIviServiceManagement, "SKIPPING %s: already in the list", qPrintable(newBackendFile)); + return; + } + + QString base = backendBaseName(fileName); + //check whether the plugins name are the same after removing the debug and library suffixes + if (newBackendFileBase == base) { + qCInfo(qLcIviServiceManagement, "Found the same plugin in two configurations. " + "Using the '%s' configuration: %s", + qtivi_helper::loadDebug ? "debug" : "release", + qPrintable(b->debug == qtivi_helper::loadDebug ? fileName : newBackendFile)); + if (b->debug != qtivi_helper::loadDebug) { + qCDebug(qLcIviServiceManagement, "REPLACING %s with %s", qPrintable(fileName), qPrintable(newBackendFile)); + addBackend = false; + m_backends[i] = backend; + emit q->dataChanged(q->index(i, 0), q->index(i, 0)); + delete b; + break; + } else { + qCDebug(qLcIviServiceManagement, "SKIPPING %s: wrong configuration", qPrintable(newBackendFile)); + return; + } + } + } + } + } + if (addBackend) { + qCDebug(qLcIviServiceManagement, "ADDING %s", qPrintable(newBackendFile.isEmpty() ? backend->name : newBackendFile)); + q->beginInsertRows(QModelIndex(), m_backends.count(), m_backends.count()); + m_backends.append(backend); + q->endInsertRows(); + } - q->beginInsertRows(QModelIndex(), m_backends.count(), m_backends.count()); - m_backends.append(backend); - q->endInsertRows(); - - const auto interfaces = backend->metaData[interfacesLiteral].toStringList(); - for (const QString &interface : interfaces) + for (const QString &interface : newInterfaces) m_interfaceNames.insert(interface); } diff --git a/src/ivicore/qiviservicemanager_p.h b/src/ivicore/qiviservicemanager_p.h index 0cddffb..1ee7e73 100644 --- a/src/ivicore/qiviservicemanager_p.h +++ b/src/ivicore/qiviservicemanager_p.h @@ -74,6 +74,7 @@ Q_DECLARE_LOGGING_CATEGORY(qLcIviServiceManagement) struct Backend{ QString name; + bool debug; QVariantMap metaData; QIviServiceInterface *interface; QObject *interfaceObject; diff --git a/tests/auto/core/servicemanagertest/simple_plugin/simple_plugin.pro b/tests/auto/core/servicemanagertest/simple_plugin/simple_plugin.pro index fc7ce06..88db558 100644 --- a/tests/auto/core/servicemanagertest/simple_plugin/simple_plugin.pro +++ b/tests/auto/core/servicemanagertest/simple_plugin/simple_plugin.pro @@ -4,10 +4,9 @@ TEMPLATE = lib CONFIG += plugin QT += core ivicore -# On a macos framework build, we need both plugin versions, -# because debug/release is decided at runtime. -macos:qtConfig(framework) { - CONFIG += debug_and_release build_all +qtConfig(debug_and_release): CONFIG += build_all +!macos:!win32:build_pass:CONFIG(debug, debug|release) { + TARGET = $$join(TARGET,,,_debug) } SOURCES += simpleplugin.cpp \ diff --git a/tests/auto/core/servicemanagertest/tst_servicemanager.pro b/tests/auto/core/servicemanagertest/tst_servicemanager.pro index 3ede9a2..47cf688 100644 --- a/tests/auto/core/servicemanagertest/tst_servicemanager.pro +++ b/tests/auto/core/servicemanagertest/tst_servicemanager.pro @@ -3,6 +3,12 @@ QT += testlib ivicore ivicore-private TARGET = tst_servicemanagertest CONFIG += testcase +DESTDIR = $$OUT_PWD + +qtConfig(debug_and_release) { + DEFINES += DEBUG_AND_RELEASE +} + LIBS += -Lqtivi -l$$qtLibraryTarget(simple_plugin_static) -l$$qtLibraryTarget(wrongmetadata_plugin_static) TEMPLATE = app diff --git a/tests/auto/core/servicemanagertest/tst_servicemanagertest.cpp b/tests/auto/core/servicemanagertest/tst_servicemanagertest.cpp index ee08de0..4a2b684 100644 --- a/tests/auto/core/servicemanagertest/tst_servicemanagertest.cpp +++ b/tests/auto/core/servicemanagertest/tst_servicemanagertest.cpp @@ -114,15 +114,17 @@ void ServiceManagerTest::initTestCase() QCoreApplication::setLibraryPaths(QStringList()); QTest::ignoreMessage(QtWarningMsg, QRegularExpression("PluginManager - Malformed metaData in static plugin '.*'. MetaData must contain a list of interfaces")); QTest::ignoreMessage(QtWarningMsg, "No plugins found in search path: \"\""); - QTest::ignoreMessage(QtWarningMsg, QRegularExpression("PluginManager - Malformed metaData in '.*'. MetaData must contain a list of interfaces")); manager = QIviServiceManager::instance(); QList<QIviServiceObject *> services = manager->findServiceByInterface("simple_plugin"); QCOMPARE(services.count(), 0); QTest::ignoreMessage(QtWarningMsg, QRegularExpression("PluginManager - Malformed metaData in static plugin '.*'. MetaData must contain a list of interfaces")); - //Reset original setting + this folder for finding our test plugins - origList.append(QDir::currentPath()); + QTest::ignoreMessage(QtWarningMsg, QRegularExpression("PluginManager - Malformed metaData in '.*'. MetaData must contain a list of interfaces")); +#ifdef DEBUG_AND_RELEASE + QTest::ignoreMessage(QtInfoMsg, QRegularExpression("Found the same plugin in two configurations. Using the '.*' configuration: .*")); +#endif + //Reset original setting QCoreApplication::setLibraryPaths(origList); QIviServiceManagerPrivate::get(manager)->searchPlugins(); @@ -295,6 +297,9 @@ void ServiceManagerTest::pluginLoaderTest() //Test the error message for plugins with invalid metadata QTest::ignoreMessage(QtWarningMsg, QRegularExpression("PluginManager - Malformed metaData in '(.*)wrongmetadata_plugin(.*)'. MetaData must contain a list of interfaces")); QTest::ignoreMessage(QtWarningMsg, QRegularExpression("PluginManager - Malformed metaData in static plugin 'WrongMetadataStaticPlugin'. MetaData must contain a list of interfaces")); +#ifdef DEBUG_AND_RELEASE + QTest::ignoreMessage(QtInfoMsg, QRegularExpression("Found the same plugin in two configurations. Using the '.*' configuration: .*")); +#endif QIviServiceManagerPrivate::get(manager)->searchPlugins(); QVERIFY(manager->hasInterface("simple_plugin")); QList<QIviServiceObject *> services = manager->findServiceByInterface("simple_plugin", QIviServiceManager::IncludeProductionBackends); |