moc: Add a standard way of specifying a URI as part of Q_PLUGIN_METADATA

Usually, when you load a plugin, you don't want to load just any plugin
that fulfills a given interface, but rather a specific one. When loading
dynamic plugins you can differentiate the plugins by file name. This
doesn't work in the static case, and file names are also separate from
the plugin metadata shipped inside the plugin files.

To solve this problem, different hacks have been developed in various
places. QML extension plugins add a special property "uri" via the -M
option of moc, QML debug plugins expect you to add a json file with
an array of "Keys", Qt Creator plugins have a "Name" in their json
files, etc.

By allowing the identifier for the plugin to be specified inline with
the metadata declaration we can make many of the above workarounds
obsolete and provide a clean way for users to find their plugins.

Task-number: QTBUG-74775
Change-Id: Ie2af16c49d4c5aa5a77fab0fae1e0a4449bd7a39
Reviewed-by: Olivier Goffart (Woboq GmbH) <ogoffart@woboq.com>
This commit is contained in:
Ulf Hermann 2019-03-29 16:05:25 +01:00
parent 217f3d83d7
commit e7e557cea2
6 changed files with 17 additions and 3 deletions

View File

@ -60,7 +60,8 @@ enum class QtPluginMetaDataKeys {
Requirements,
IID,
ClassName,
MetaData
MetaData,
URI
};
// F(IntKey, StringKey, Description)
@ -68,7 +69,8 @@ enum class QtPluginMetaDataKeys {
#define QT_PLUGIN_FOREACH_METADATA(F) \
F(QtPluginMetaDataKeys::IID, "IID", "Plugin's Interface ID") \
F(QtPluginMetaDataKeys::ClassName, "className", "Plugin class name") \
F(QtPluginMetaDataKeys::MetaData, "MetaData", "Other meta data")
F(QtPluginMetaDataKeys::MetaData, "MetaData", "Other meta data") \
F(QtPluginMetaDataKeys::URI, "URI", "Plugin URI")
QT_END_NAMESPACE

View File

@ -1652,6 +1652,12 @@ void Generator::generatePluginMetaData()
jsonObjectToCbor(&map, o);
}
if (!cdef->pluginData.uri.isEmpty()) {
dev.nextItem("\"URI\"");
cbor_encode_int(&map, int(QtPluginMetaDataKeys::URI));
cbor_encode_text_string(&map, cdef->pluginData.uri.constData(), cdef->pluginData.uri.size());
}
// Add -M args from the command line:
for (auto it = cdef->pluginData.metaArgs.cbegin(), end = cdef->pluginData.metaArgs.cend(); it != end; ++it) {
const QJsonArray &a = it.value();

View File

@ -1311,6 +1311,9 @@ void Moc::parsePluginData(ClassDef *def)
if (l == "IID") {
next(STRING_LITERAL);
def->pluginData.iid = unquotedLexem();
} else if (l == "URI") {
next(STRING_LITERAL);
def->pluginData.uri = unquotedLexem();
} else if (l == "FILE") {
next(STRING_LITERAL);
QByteArray metaDataFile = unquotedLexem();
@ -1351,6 +1354,7 @@ void Moc::parsePluginData(ClassDef *def)
+ " does not contain a valid JSON object. Declaration will be ignored";
warning(msg.constData());
def->pluginData.iid = QByteArray();
def->pluginData.uri = QByteArray();
return;
}
}

View File

@ -167,6 +167,7 @@ struct ClassDef : BaseDef {
struct PluginData {
QByteArray iid;
QByteArray uri;
QMap<QString, QJsonArray> metaArgs;
QJsonDocument metaData;
} pluginData;

View File

@ -31,7 +31,7 @@
class StaticPlugin : public QObject
{
Q_OBJECT
Q_PLUGIN_METADATA(IID "SomeIID")
Q_PLUGIN_METADATA(IID "SomeIID" URI "qt.test.pluginloader.staticplugin")
public:
StaticPlugin() {}
};

View File

@ -552,6 +552,7 @@ void tst_QPluginLoader::staticPlugins()
QCOMPARE(metaData.value("version").toInt(), QT_VERSION);
QCOMPARE(metaData.value("IID").toString(), "SomeIID");
QCOMPARE(metaData.value("ExtraMetaData"), QJsonArray({ "StaticPlugin", "foo" }));
QCOMPARE(metaData.value("URI").toString(), "qt.test.pluginloader.staticplugin");
}