QPlugin: move some of the logic from moc's output to qplugin.h

This will allow us to make changes in QtCore itself, without having to
worry about moc compatibility.

The output uses an #ifdef so this version of moc can still be used to
compile earlier versions of Qt (usually, in cross-compilation
environments). See discussion in the mailing list[1].

[1] https://lists.qt-project.org/pipermail/development/2021-September/041732.html

Change-Id: I2de1b4dfacd443148279fffd16a39784c80c5f3b
Reviewed-by: Lars Knoll <lars.knoll@qt.io>
This commit is contained in:
Thiago Macieira 2021-09-10 15:48:06 -07:00
parent 2adf444b5e
commit 788a7bfdb1
3 changed files with 129 additions and 58 deletions

View File

@ -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 <size_t OSize, typename OO, size_t ISize, typename II>
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 <auto (&PluginMetaData)> 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> 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> md{}; return md; } \
QT_MOC_EXPORT_PLUGIN_COMMON(PLUGINCLASS, MANGLEDNAME)
#endif
#define Q_EXPORT_PLUGIN(PLUGIN) \

View File

@ -1573,14 +1573,7 @@ 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);
@ -1621,14 +1614,35 @@ void Generator::generatePluginMetaData()
// Close the CBOR map manually
dev.nextItem();
cbor_encoder_close_container(&enc, &map);
fputs("\n};\n", out);
};
// '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")

View File

@ -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<QString>("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<const char *>(&header), sizeof(header));
QByteArray cborValid = [] {
QCborMap m;