diff --git a/src/corelib/plugin/qplugin.h b/src/corelib/plugin/qplugin.h index 411edba7926..a80ee28c52a 100644 --- a/src/corelib/plugin/qplugin.h +++ b/src/corelib/plugin/qplugin.h @@ -65,7 +65,36 @@ inline constexpr unsigned char qPluginArchRequirements() typedef QObject *(*QtPluginInstanceFunction)(); struct QPluginMetaData { - const uchar *data; + static constexpr quint8 CurrentMetaDataVersion = 0; + static constexpr char MagicString[] = { + 'Q', 'T', 'M', 'E', 'T', 'A', 'D', 'A', 'T', 'A', ' ', '!' + }; + + template + static constexpr void copy(OO (&out)[OSize], II (&in)[ISize]) + { + // std::copy is not constexpr until C++20 + static_assert(OSize <= ISize, "Output would not be fully initialized"); + for (size_t i = 0; i < OSize; ++i) + out[i] = in[i]; + } + + struct Header { + quint8 version = CurrentMetaDataVersion; + quint8 qt_major_version = QT_VERSION_MAJOR; + quint8 qt_minor_version = QT_VERSION_MINOR; + quint8 plugin_arch_requirements = qPluginArchRequirements(); + }; + static_assert(alignof(Header) == 1, "Alignment of header incorrect with this compiler"); + + struct MagicHeader { + char magic[sizeof(QPluginMetaData::MagicString)] = {}; + constexpr MagicHeader() { copy(magic, QPluginMetaData::MagicString); } + Header header = {}; + }; + static_assert(alignof(MagicHeader) == 1, "Alignment of header incorrect with this compiler"); + + const void *data; size_t size; }; typedef QPluginMetaData (*QtPluginMetaDataFunction)(); @@ -104,6 +133,24 @@ void Q_CORE_EXPORT qRegisterStaticPluginFunction(QStaticPlugin staticPlugin); # define QT_PLUGIN_METADATA_SECTION #endif +// Since Qt 6.3 +template class QPluginMetaDataV2 +{ + struct Payload { + QPluginMetaData::MagicHeader header = {}; + quint8 payload[sizeof(PluginMetaData)] = {}; + constexpr Payload() { QPluginMetaData::copy(payload, PluginMetaData); } + }; + +#define QT_PLUGIN_METADATAV2_SECTION QT_PLUGIN_METADATA_SECTION + Payload payload = {}; + +public: + operator QPluginMetaData() const + { + return { &payload, sizeof(payload) }; + } +}; #define Q_IMPORT_PLUGIN(PLUGIN) \ extern const QT_PREPEND_NAMESPACE(QStaticPlugin) qt_static_plugin_##PLUGIN(); \ @@ -134,25 +181,38 @@ void Q_CORE_EXPORT qRegisterStaticPluginFunction(QStaticPlugin staticPlugin); } #if defined(QT_STATICPLUGIN) +# define QT_MOC_EXPORT_PLUGIN_COMMON(PLUGINCLASS, MANGLEDNAME) \ + static QT_PREPEND_NAMESPACE(QObject) *qt_plugin_instance_##MANGLEDNAME() \ + Q_PLUGIN_INSTANCE(PLUGINCLASS) \ + const QT_PREPEND_NAMESPACE(QStaticPlugin) qt_static_plugin_##MANGLEDNAME() \ + { return { qt_plugin_instance_##MANGLEDNAME, qt_plugin_query_metadata_##MANGLEDNAME}; } \ + /**/ # define QT_MOC_EXPORT_PLUGIN(PLUGINCLASS, PLUGINCLASSNAME) \ - static QT_PREPEND_NAMESPACE(QObject) *qt_plugin_instance_##PLUGINCLASSNAME() \ - Q_PLUGIN_INSTANCE(PLUGINCLASS) \ static QPluginMetaData qt_plugin_query_metadata_##PLUGINCLASSNAME() \ { return { qt_pluginMetaData_##PLUGINCLASSNAME, sizeof qt_pluginMetaData_##PLUGINCLASSNAME }; } \ - const QT_PREPEND_NAMESPACE(QStaticPlugin) qt_static_plugin_##PLUGINCLASSNAME() { \ - return { qt_plugin_instance_##PLUGINCLASSNAME, qt_plugin_query_metadata_##PLUGINCLASSNAME}; \ - } + QT_MOC_EXPORT_PLUGIN_COMMON(PLUGINCLASS, PLUGINCLASSNAME) +# define QT_MOC_EXPORT_PLUGIN_V2(PLUGINCLASS, MANGLEDNAME, MD) \ + static QT_PREPEND_NAMESPACE(QPluginMetaData) qt_plugin_query_metadata_##MANGLEDNAME() \ + { static constexpr QPluginMetaDataV2 md{}; return md; } \ + QT_MOC_EXPORT_PLUGIN_COMMON(PLUGINCLASS, MANGLEDNAME) #else +# define QT_MOC_EXPORT_PLUGIN_COMMON(PLUGINCLASS, MANGLEDNAME) \ + extern "C" Q_DECL_EXPORT QT_PREPEND_NAMESPACE(QObject) *qt_plugin_instance() \ + Q_PLUGIN_INSTANCE(PLUGINCLASS) \ + /**/ # define QT_MOC_EXPORT_PLUGIN(PLUGINCLASS, PLUGINCLASSNAME) \ extern "C" Q_DECL_EXPORT \ QPluginMetaData qt_plugin_query_metadata() \ { return { qt_pluginMetaData_##PLUGINCLASSNAME, sizeof qt_pluginMetaData_##PLUGINCLASSNAME }; } \ - extern "C" Q_DECL_EXPORT QT_PREPEND_NAMESPACE(QObject) *qt_plugin_instance() \ - Q_PLUGIN_INSTANCE(PLUGINCLASS) + QT_MOC_EXPORT_PLUGIN_COMMON(PLUGINCLASS, PLUGINCLASSNAME) +# define QT_MOC_EXPORT_PLUGIN_V2(PLUGINCLASS, MANGLEDNAME, MD) \ + extern "C" Q_DECL_EXPORT QT_PREPEND_NAMESPACE(QPluginMetaData) qt_plugin_query_metadata() \ + { static constexpr QT_PLUGIN_METADATAV2_SECTION QPluginMetaDataV2 md{}; return md; } \ + QT_MOC_EXPORT_PLUGIN_COMMON(PLUGINCLASS, MANGLEDNAME) #endif #define Q_EXPORT_PLUGIN(PLUGIN) \ diff --git a/src/tools/moc/generator.cpp b/src/tools/moc/generator.cpp index a21e44ba8fa..3e838818f98 100644 --- a/src/tools/moc/generator.cpp +++ b/src/tools/moc/generator.cpp @@ -1573,62 +1573,76 @@ void Generator::generatePluginMetaData() if (cdef->pluginData.iid.isEmpty()) return; - fprintf(out, "\nQT_PLUGIN_METADATA_SECTION\n" - "static constexpr unsigned char qt_pluginMetaData_%s[] = {\n" - " 'Q', 'T', 'M', 'E', 'T', 'A', 'D', 'A', 'T', 'A', ' ', '!',\n" - " // metadata version, Qt version, architectural requirements\n" - " 0, QT_VERSION_MAJOR, QT_VERSION_MINOR, qPluginArchRequirements(),", - cdef->classname.constData()); + auto outputCborData = [this]() { + CborDevice dev(out); + CborEncoder enc; + cbor_encoder_init_writer(&enc, CborDevice::callback, &dev); + CborEncoder map; + cbor_encoder_create_map(&enc, &map, CborIndefiniteLength); - CborDevice dev(out); - CborEncoder enc; - cbor_encoder_init_writer(&enc, CborDevice::callback, &dev); + dev.nextItem("\"IID\""); + cbor_encode_int(&map, int(QtPluginMetaDataKeys::IID)); + cbor_encode_text_string(&map, cdef->pluginData.iid.constData(), cdef->pluginData.iid.size()); - CborEncoder map; - cbor_encoder_create_map(&enc, &map, CborIndefiniteLength); + dev.nextItem("\"className\""); + cbor_encode_int(&map, int(QtPluginMetaDataKeys::ClassName)); + cbor_encode_text_string(&map, cdef->classname.constData(), cdef->classname.size()); - dev.nextItem("\"IID\""); - cbor_encode_int(&map, int(QtPluginMetaDataKeys::IID)); - cbor_encode_text_string(&map, cdef->pluginData.iid.constData(), cdef->pluginData.iid.size()); + QJsonObject o = cdef->pluginData.metaData.object(); + if (!o.isEmpty()) { + dev.nextItem("\"MetaData\""); + cbor_encode_int(&map, int(QtPluginMetaDataKeys::MetaData)); + jsonObjectToCbor(&map, o); + } - dev.nextItem("\"className\""); - cbor_encode_int(&map, int(QtPluginMetaDataKeys::ClassName)); - cbor_encode_text_string(&map, cdef->classname.constData(), cdef->classname.size()); + 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()); + } - QJsonObject o = cdef->pluginData.metaData.object(); - if (!o.isEmpty()) { - dev.nextItem("\"MetaData\""); - cbor_encode_int(&map, int(QtPluginMetaDataKeys::MetaData)); - jsonObjectToCbor(&map, o); - } + // 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(); + QByteArray key = it.key().toUtf8(); + dev.nextItem(QByteArray("command-line \"" + key + "\"").constData()); + cbor_encode_text_string(&map, key.constData(), key.size()); + jsonArrayToCbor(&map, a); + } - 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(); - QByteArray key = it.key().toUtf8(); - dev.nextItem(QByteArray("command-line \"" + key + "\"").constData()); - cbor_encode_text_string(&map, key.constData(), key.size()); - jsonArrayToCbor(&map, a); - } - - // Close the CBOR map manually - dev.nextItem(); - cbor_encoder_close_container(&enc, &map); - fputs("\n};\n", out); + // Close the CBOR map manually + dev.nextItem(); + cbor_encoder_close_container(&enc, &map); + }; // 'Use' all namespaces. int pos = cdef->qualified.indexOf("::"); for ( ; pos != -1 ; pos = cdef->qualified.indexOf("::", pos + 2) ) fprintf(out, "using namespace %s;\n", cdef->qualified.left(pos).constData()); - fprintf(out, "QT_MOC_EXPORT_PLUGIN(%s, %s)\n\n", + + fputs("\n#ifdef QT_MOC_EXPORT_PLUGIN_V2", out); + + // Qt 6.3+ output + fprintf(out, "\nstatic constexpr unsigned char qt_pluginMetaDataV2_%s[] = {", + cdef->classname.constData()); + outputCborData(); + fprintf(out, "\n};\nQT_MOC_EXPORT_PLUGIN_V2(%s, %s, qt_pluginMetaDataV2_%s)\n", + cdef->qualified.constData(), cdef->classname.constData(), cdef->classname.constData()); + + // compatibility with Qt 6.0-6.2 + fprintf(out, "#else\nQT_PLUGIN_METADATA_SECTION\n" + "static constexpr unsigned char qt_pluginMetaData_%s[] = {\n" + " 'Q', 'T', 'M', 'E', 'T', 'A', 'D', 'A', 'T', 'A', ' ', '!',\n" + " // metadata version, Qt version, architectural requirements\n" + " 0, QT_VERSION_MAJOR, QT_VERSION_MINOR, qPluginArchRequirements(),", + cdef->classname.constData()); + outputCborData(); + fprintf(out, "\n};\nQT_MOC_EXPORT_PLUGIN(%s, %s)\n" + "#endif // QT_MOC_EXPORT_PLUGIN_V2\n", cdef->qualified.constData(), cdef->classname.constData()); + + fputs("\n", out); } QT_WARNING_DISABLE_GCC("-Wunused-function") diff --git a/tests/auto/corelib/plugin/qplugin/tst_qplugin.cpp b/tests/auto/corelib/plugin/qplugin/tst_qplugin.cpp index 8b221dfc7a6..14be0082c7f 100644 --- a/tests/auto/corelib/plugin/qplugin/tst_qplugin.cpp +++ b/tests/auto/corelib/plugin/qplugin/tst_qplugin.cpp @@ -1,7 +1,7 @@ /**************************************************************************** ** -** Copyright (C) 2016 The Qt Company Ltd. -** Copyright (C) 2018 Intel Corporation. +** Copyright (C) 2020 The Qt Company Ltd. +** Copyright (C) 2021 Intel Corporation. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the test suite of the Qt Toolkit. @@ -138,11 +138,8 @@ void tst_QPlugin::scanInvalidPlugin_data() QTest::addColumn("errMsg"); // CBOR metadata - QByteArray cprefix = "QTMETADATA !1234"; - cprefix[12] = 0; // current version - cprefix[13] = QT_VERSION_MAJOR; - cprefix[14] = QT_VERSION_MINOR; - cprefix[15] = qPluginArchRequirements(); + static constexpr QPluginMetaData::MagicHeader header = {}; + QByteArray cprefix(reinterpret_cast(&header), sizeof(header)); QByteArray cborValid = [] { QCborMap m;