aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDominik Holland <dominik.holland@pelagicore.com>2018-04-26 17:38:03 +0200
committerRobert Griebl <robert.griebl@pelagicore.com>2018-05-03 12:00:10 +0000
commitc2a46c9363e2ef5cf6e5ef2372f07570118369e5 (patch)
tree4f0077660385171e6a4aed69d9591307a1eb42d0
parent967b83e30cde5ca04c126a4d9631d887513c2e98 (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>
-rw-r--r--src/ivicore/qiviservicemanager.cpp94
-rw-r--r--src/ivicore/qiviservicemanager_p.h1
-rw-r--r--tests/auto/core/servicemanagertest/simple_plugin/simple_plugin.pro7
-rw-r--r--tests/auto/core/servicemanagertest/tst_servicemanager.pro6
-rw-r--r--tests/auto/core/servicemanagertest/tst_servicemanagertest.cpp11
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);