Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qfactoryloader.cpp
Go to the documentation of this file.
1// Copyright (C) 2021 The Qt Company Ltd.
2// Copyright (C) 2022 Intel Corporation.
3// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
4
5#include "qfactoryloader_p.h"
6
7#ifndef QT_NO_QOBJECT
8#include "private/qcoreapplication_p.h"
9#include "private/qduplicatetracker_p.h"
10#include "private/qloggingregistry_p.h"
11#include "private/qobject_p.h"
12#include "qcborarray.h"
13#include "qcbormap.h"
14#include "qcborstreamreader.h"
15#include "qcborvalue.h"
16#include "qdirlisting.h"
17#include "qfileinfo.h"
18#include "qjsonarray.h"
19#include "qjsondocument.h"
20#include "qjsonobject.h"
21#include "qmutex.h"
22#include "qplugin.h"
23#include "qplugin_p.h"
24#include "qpluginloader.h"
25
26#if QT_CONFIG(library)
27# include "qlibrary_p.h"
28#endif
29
30#include <qtcore_tracepoints_p.h>
31
32#include <map>
33#include <vector>
34
36
37using namespace Qt::StringLiterals;
38
39Q_TRACE_POINT(qtcore, QFactoryLoader_update, const QString &fileName);
40
41namespace {
42struct IterationResult
43{
44 enum Result {
45 FinishedSearch = 0,
46 ContinueSearch,
47
48 // parse errors
49 ParsingError = -1,
50 InvalidMetaDataVersion = -2,
51 InvalidTopLevelItem = -3,
52 InvalidHeaderItem = -4,
53 };
54 Result result;
56
57 Q_IMPLICIT IterationResult(Result r) : result(r) {}
58 Q_IMPLICIT IterationResult(QCborError e) : result(ParsingError), error(e) {}
59};
60
61struct QFactoryLoaderIidSearch
62{
64 bool matchesIid = false;
65 QFactoryLoaderIidSearch(QLatin1StringView iid) : iid(iid)
66 { Q_ASSERT(!iid.isEmpty()); }
67
68 static IterationResult::Result skip(QCborStreamReader &reader)
69 {
70 // skip this, whatever it is
71 reader.next();
72 return IterationResult::ContinueSearch;
73 }
74
75 IterationResult::Result operator()(QtPluginMetaDataKeys key, QCborStreamReader &reader)
76 {
78 return skip(reader);
79 matchesIid = (reader.readAllString() == iid);
80 return IterationResult::FinishedSearch;
81 }
82 IterationResult::Result operator()(QUtf8StringView, QCborStreamReader &reader)
83 {
84 return skip(reader);
85 }
86};
87
88struct QFactoryLoaderMetaDataKeysExtractor : QFactoryLoaderIidSearch
89{
91 QFactoryLoaderMetaDataKeysExtractor(QLatin1StringView iid)
92 : QFactoryLoaderIidSearch(iid)
93 {}
94
95 IterationResult::Result operator()(QtPluginMetaDataKeys key, QCborStreamReader &reader)
96 {
98 QFactoryLoaderIidSearch::operator()(key, reader);
99 return IterationResult::ContinueSearch;
100 }
102 return skip(reader);
103
104 if (!matchesIid)
105 return IterationResult::FinishedSearch;
106 if (!reader.isMap() || !reader.isLengthKnown())
107 return IterationResult::InvalidHeaderItem;
108 if (!reader.enterContainer())
109 return IterationResult::ParsingError;
110 while (reader.isValid()) {
111 // the metadata is JSON, so keys are all strings
112 QByteArray key = reader.readAllUtf8String();
113 if (key == "Keys") {
114 if (!reader.isArray() || !reader.isLengthKnown())
115 return IterationResult::InvalidHeaderItem;
116 keys = QCborValue::fromCbor(reader).toArray();
117 break;
118 }
119 skip(reader);
120 }
121 // warning: we may not have finished iterating over the header
122 return IterationResult::FinishedSearch;
123 }
124 using QFactoryLoaderIidSearch::operator();
125};
126} // unnamed namespace
127
128template <typename F> static IterationResult iterateInPluginMetaData(QByteArrayView raw, F &&f)
129{
131 Q_ASSERT(raw.size() >= qsizetype(sizeof(header)));
132 memcpy(&header, raw.data(), sizeof(header));
134 return IterationResult::InvalidMetaDataVersion;
135
136 // use fromRawData to keep QCborStreamReader from copying
137 raw = raw.sliced(sizeof(header));
138 QByteArray ba = QByteArray::fromRawData(raw.data(), raw.size());
139 QCborStreamReader reader(ba);
140 if (reader.isInvalid())
141 return reader.lastError();
142 if (!reader.isMap())
143 return IterationResult::InvalidTopLevelItem;
144 if (!reader.enterContainer())
145 return reader.lastError();
146 while (reader.isValid()) {
147 IterationResult::Result r;
148 if (reader.isInteger()) {
149 // integer key, one of ours
150 qint64 value = reader.toInteger();
152 if (qint64(key) != value)
153 return IterationResult::InvalidHeaderItem;
154 if (!reader.next())
155 return reader.lastError();
156 r = f(key, reader);
157 } else if (reader.isString()) {
158 QByteArray key = reader.readAllUtf8String();
159 if (key.isNull())
160 return reader.lastError();
161 r = f(QUtf8StringView(key), reader);
162 } else {
163 return IterationResult::InvalidTopLevelItem;
164 }
165
166 if (QCborError e = reader.lastError())
167 return e;
168 if (r != IterationResult::ContinueSearch)
169 return r;
170 }
171
172 if (!reader.leaveContainer())
173 return reader.lastError();
174 return IterationResult::FinishedSearch;
175}
176
178{
179 QFactoryLoaderIidSearch search(iid);
180 iterateInPluginMetaData(raw, search);
181 return search.matchesIid;
182}
183
185{
187 auto r = iterateInPluginMetaData(raw, [&](const auto &key, QCborStreamReader &reader) {
188 QCborValue item = QCborValue::fromCbor(reader);
189 if (item.isInvalid())
190 return IterationResult::ParsingError;
191 if constexpr (std::is_enum_v<std::decay_t<decltype(key)>>)
192 map[int(key)] = item;
193 else
195 return IterationResult::ContinueSearch;
196 });
197
198 switch (r.result) {
199 case IterationResult::FinishedSearch:
200 case IterationResult::ContinueSearch:
201 break;
202
203 // parse errors
204 case IterationResult::ParsingError:
205 return setError(QFactoryLoader::tr("Metadata parsing error: %1").arg(r.error.toString()));
206 case IterationResult::InvalidMetaDataVersion:
207 return setError(QFactoryLoader::tr("Invalid metadata version"));
208 case IterationResult::InvalidTopLevelItem:
209 case IterationResult::InvalidHeaderItem:
210 return setError(QFactoryLoader::tr("Unexpected metadata contents"));
211 }
212
213 // header was validated
214 auto header = qFromUnaligned<QPluginMetaData::Header>(raw.data());
215
216 DecodedArchRequirements archReq =
217 header.version == 0 ? decodeVersion0ArchRequirements(header.plugin_arch_requirements)
218 : decodeVersion1ArchRequirements(header.plugin_arch_requirements);
219
220 // insert the keys not stored in the top-level CBOR map
222 QT_VERSION_CHECK(header.qt_major_version, header.qt_minor_version, 0);
223 map[int(QtPluginMetaDataKeys::IsDebug)] = archReq.isDebug;
224 map[int(QtPluginMetaDataKeys::Requirements)] = archReq.level;
225
226 data = std::move(map);
227 return true;
228}
229
231{
232 // convert from the internal CBOR representation to an external JSON one
234 for (auto it : data.toMap()) {
235 QString key;
236 if (it.first.isInteger()) {
237 switch (it.first.toInteger()) {
238#define CONVERT_TO_STRING(IntKey, StringKey, Description) \
239 case int(IntKey): key = QStringLiteral(StringKey); break;
241 }
242 } else {
243 key = it.first.toString();
244 }
245
246 if (!key.isEmpty())
247 o.insert(key, it.second.toJsonValue());
248 }
249 return o;
250}
251
253{
254 Q_DECLARE_PUBLIC(QFactoryLoader)
255 Q_DISABLE_COPY_MOVE(QFactoryLoaderPrivate)
256public:
259#if QT_CONFIG(library)
261 mutable QMutex mutex;
262 QDuplicateTracker<QString> loadedPaths;
263 std::vector<QLibraryPrivate::UniquePtr> libraries;
264 std::map<QString, QLibraryPrivate*> keyMap;
265 QString suffix;
266 QString extraSearchPath;
268
269 void updateSinglePath(const QString &pluginDir);
270#endif
271};
272
273#if QT_CONFIG(library)
274
275static Q_LOGGING_CATEGORY_WITH_ENV_OVERRIDE(lcFactoryLoader, "QT_DEBUG_PLUGINS",
276 "qt.core.plugin.factoryloader")
277
278namespace {
279struct QFactoryLoaderGlobals
280{
281 // needs to be recursive because loading one plugin could cause another
282 // factory to be initialized
284 QList<QFactoryLoader *> loaders;
285};
286}
287
288Q_GLOBAL_STATIC(QFactoryLoaderGlobals, qt_factoryloader_global)
289
290QFactoryLoaderPrivate::~QFactoryLoaderPrivate()
291 = default;
292
293inline void QFactoryLoaderPrivate::updateSinglePath(const QString &path)
294{
295 struct LibraryReleaser {
296 void operator()(QLibraryPrivate *library)
297 { if (library) library->release(); }
298 };
299
300 // If we've already loaded, skip it...
301 if (loadedPaths.hasSeen(path))
302 return;
303
304 qCDebug(lcFactoryLoader) << "checking directory path" << path << "...";
305
306 QDirListing plugins(path,
307#if defined(Q_OS_WIN)
308 QStringList(QStringLiteral("*.dll")),
309#elif defined(Q_OS_ANDROID)
310 QStringList("libplugins_%1_*.so"_L1.arg(suffix)),
311#endif
313
314 for (const auto &dirEntry : plugins) {
315 const QString &fileName = dirEntry.fileName();
316#ifdef Q_OS_DARWIN
317 const bool isDebugPlugin = fileName.endsWith("_debug.dylib"_L1);
318 const bool isDebugLibrary =
319 #ifdef QT_DEBUG
320 true;
321 #else
322 false;
323 #endif
324
325 // Skip mismatching plugins so that we don't end up loading both debug and release
326 // versions of the same Qt libraries (due to the plugin's dependencies).
327 if (isDebugPlugin != isDebugLibrary)
328 continue;
329#elif defined(Q_PROCESSOR_X86)
330 if (fileName.endsWith(".avx2"_L1) || fileName.endsWith(".avx512"_L1)) {
331 // ignore AVX2-optimized file, we'll do a bait-and-switch to it later
332 continue;
333 }
334#endif
335 qCDebug(lcFactoryLoader) << "looking at" << fileName;
336
337 Q_TRACE(QFactoryLoader_update, fileName);
338
340 library.reset(QLibraryPrivate::findOrCreate(dirEntry.canonicalFilePath()));
341 if (!library->isPlugin()) {
342 qCDebug(lcFactoryLoader) << library->errorString << Qt::endl
343 << " not a plugin";
344 continue;
345 }
346
348 bool metaDataOk = false;
349
350 QString iid = library->metaData.value(QtPluginMetaDataKeys::IID).toString();
351 if (iid == QLatin1StringView(this->iid.constData(), this->iid.size())) {
352 QCborMap object = library->metaData.value(QtPluginMetaDataKeys::MetaData).toMap();
353 metaDataOk = true;
354
355 const QCborArray k = object.value("Keys"_L1).toArray();
356 for (QCborValueConstRef v : k)
357 keys += cs ? v.toString() : v.toString().toLower();
358 }
359 qCDebug(lcFactoryLoader) << "Got keys from plugin meta data" << keys;
360
361 if (!metaDataOk)
362 continue;
363
364 int keyUsageCount = 0;
365 for (const QString &key : std::as_const(keys)) {
366 // first come first serve, unless the first
367 // library was built with a future Qt version,
368 // whereas the new one has a Qt version that fits
369 // better
370 constexpr int QtVersionNoPatch = QT_VERSION_CHECK(QT_VERSION_MAJOR, QT_VERSION_MINOR, 0);
371 QLibraryPrivate *&previous = keyMap[key];
372 int prev_qt_version = 0;
373 if (previous)
374 prev_qt_version = int(previous->metaData.value(QtPluginMetaDataKeys::QtVersion).toInteger());
375 int qt_version = int(library->metaData.value(QtPluginMetaDataKeys::QtVersion).toInteger());
376 if (!previous || (prev_qt_version > QtVersionNoPatch && qt_version <= QtVersionNoPatch)) {
377 previous = library.get(); // we WILL .release()
378 ++keyUsageCount;
379 }
380 }
381 if (keyUsageCount || keys.isEmpty()) {
382 library->setLoadHints(QLibrary::PreventUnloadHint); // once loaded, don't unload
383 QMutexLocker locker(&mutex);
384 libraries.push_back(std::move(library));
385 }
386 };
387}
388
389void QFactoryLoader::update()
390{
391#ifdef QT_SHARED
392 Q_D(QFactoryLoader);
393
394 const QStringList paths = QCoreApplication::libraryPaths();
395 for (const QString &pluginDir : paths) {
396#ifdef Q_OS_ANDROID
397 QString path = pluginDir;
398#else
399 QString path = pluginDir + d->suffix;
400#endif
401
402 d->updateSinglePath(path);
403 }
404 if (!d->extraSearchPath.isEmpty())
405 d->updateSinglePath(d->extraSearchPath);
406#else
407 Q_D(QFactoryLoader);
408 qCDebug(lcFactoryLoader) << "ignoring" << d->iid
409 << "since plugins are disabled in static builds";
410#endif
411}
412
413QFactoryLoader::~QFactoryLoader()
414{
415 if (!qt_factoryloader_global.isDestroyed()) {
416 QMutexLocker locker(&qt_factoryloader_global->mutex);
417 qt_factoryloader_global->loaders.removeOne(this);
418 }
419}
420
421#if defined(Q_OS_UNIX) && !defined (Q_OS_DARWIN)
422QLibraryPrivate *QFactoryLoader::library(const QString &key) const
423{
424 Q_D(const QFactoryLoader);
425 const auto it = d->keyMap.find(d->cs ? key : key.toLower());
426 if (it == d->keyMap.cend())
427 return nullptr;
428 return it->second;
429}
430#endif
431
432void QFactoryLoader::refreshAll()
433{
434 if (qt_factoryloader_global.exists()) {
435 QMutexLocker locker(&qt_factoryloader_global->mutex);
436 for (QFactoryLoader *loader : std::as_const(qt_factoryloader_global->loaders))
437 loader->update();
438 }
439}
440
441#endif // QT_CONFIG(library)
442
444 const QString &suffix,
447{
448 Q_ASSERT_X(suffix.startsWith(u'/'), "QFactoryLoader",
449 "For historical reasons, the suffix must start with '/' (and it can't be empty)");
450
452 Q_D(QFactoryLoader);
453 d->iid = iid;
454#if QT_CONFIG(library)
455 d->cs = cs;
456 d->suffix = suffix;
457# ifdef Q_OS_ANDROID
458 if (!d->suffix.isEmpty() && d->suffix.at(0) == u'/')
459 d->suffix.remove(0, 1);
460# endif
461
462 QMutexLocker locker(&qt_factoryloader_global->mutex);
463 update();
464 qt_factoryloader_global->loaders.append(this);
465#else
466 Q_UNUSED(suffix);
467 Q_UNUSED(cs);
468#endif
469}
470
472{
473#if QT_CONFIG(library)
474 Q_D(QFactoryLoader);
475 if (d->extraSearchPath == path)
476 return; // nothing to do
477
478 QMutexLocker locker(&qt_factoryloader_global->mutex);
479 QString oldPath = std::exchange(d->extraSearchPath, path);
480 if (oldPath.isEmpty()) {
481 // easy case, just update this directory
482 d->updateSinglePath(d->extraSearchPath);
483 } else {
484 // must re-scan everything
485 d->loadedPaths.clear();
486 d->libraries.clear();
487 d->keyMap.clear();
488 update();
489 }
490#else
491 Q_UNUSED(path);
492#endif
493}
494
496{
497 Q_D(const QFactoryLoader);
498 QList<QPluginParsedMetaData> metaData;
499#if QT_CONFIG(library)
500 QMutexLocker locker(&d->mutex);
501 for (const auto &library : d->libraries)
502 metaData.append(library->metaData);
503#endif
504
505 QLatin1StringView iid(d->iid.constData(), d->iid.size());
506 const auto staticPlugins = QPluginLoader::staticPlugins();
507 for (const QStaticPlugin &plugin : staticPlugins) {
508 QByteArrayView pluginData(static_cast<const char *>(plugin.rawMetaData), plugin.rawMetaDataSize);
509 QPluginParsedMetaData parsed(pluginData);
510 if (parsed.isError() || parsed.value(QtPluginMetaDataKeys::IID) != iid)
511 continue;
512 metaData.append(std::move(parsed));
513 }
514
515 // other portions of the code will cast to int (e.g., keyMap())
516 Q_ASSERT(metaData.size() <= std::numeric_limits<int>::max());
517 return metaData;
518}
519
520QList<QCborArray> QFactoryLoader::metaDataKeys() const
521{
522 Q_D(const QFactoryLoader);
523 QList<QCborArray> metaData;
524#if QT_CONFIG(library)
525 QMutexLocker locker(&d->mutex);
526 for (const auto &library : d->libraries) {
527 const QCborValue md = library->metaData.value(QtPluginMetaDataKeys::MetaData);
528 metaData.append(md["Keys"_L1].toArray());
529 }
530#endif
531
532 QLatin1StringView iid(d->iid.constData(), d->iid.size());
533 const auto staticPlugins = QPluginLoader::staticPlugins();
534 for (const QStaticPlugin &plugin : staticPlugins) {
535 QByteArrayView pluginData(static_cast<const char *>(plugin.rawMetaData),
536 plugin.rawMetaDataSize);
537 QFactoryLoaderMetaDataKeysExtractor extractor{ iid };
539 if (extractor.matchesIid)
540 metaData += std::move(extractor.keys);
541 }
542
543 // other portions of the code will cast to int (e.g., keyMap())
544 Q_ASSERT(metaData.size() <= std::numeric_limits<int>::max());
545 return metaData;
546}
547
549{
550 Q_D(const QFactoryLoader);
551 if (index < 0)
552 return nullptr;
553
554#if QT_CONFIG(library)
555 QMutexLocker lock(&d->mutex);
556 if (size_t(index) < d->libraries.size()) {
557 QLibraryPrivate *library = d->libraries[index].get();
558 if (QObject *obj = library->pluginInstance()) {
559 if (!obj->parent())
561 return obj;
562 }
563 return nullptr;
564 }
565 // we know d->libraries.size() <= index <= numeric_limits<decltype(index)>::max() → no overflow
566 index -= static_cast<int>(d->libraries.size());
567 lock.unlock();
568#endif
569
570 QLatin1StringView iid(d->iid.constData(), d->iid.size());
571 const QList<QStaticPlugin> staticPlugins = QPluginLoader::staticPlugins();
572 for (QStaticPlugin plugin : staticPlugins) {
573 QByteArrayView pluginData(static_cast<const char *>(plugin.rawMetaData), plugin.rawMetaDataSize);
574 if (!isIidMatch(pluginData, iid))
575 continue;
576
577 if (index == 0)
578 return plugin.instance();
579 --index;
580 }
581
582 return nullptr;
583}
584
585QMultiMap<int, QString> QFactoryLoader::keyMap() const
586{
587 QMultiMap<int, QString> result;
588 const QList<QCborArray> metaDataList = metaDataKeys();
589 for (int i = 0; i < int(metaDataList.size()); ++i) {
590 const QCborArray &keys = metaDataList[i];
592 result.insert(i, key.toString());
593 }
594 return result;
595}
596
597int QFactoryLoader::indexOf(const QString &needle) const
598{
599 const QList<QCborArray> metaDataList = metaDataKeys();
600 for (int i = 0; i < int(metaDataList.size()); ++i) {
601 const QCborArray &keys = metaDataList[i];
602 for (QCborValueConstRef key : keys) {
603 if (key.toString().compare(needle, Qt::CaseInsensitive) == 0)
604 return i;
605 }
606 }
607 return -1;
608}
609
611
612#include "moc_qfactoryloader_p.cpp"
613
614#endif // QT_NO_QOBJECT
\inmodule QtCore
Definition qbytearray.h:57
static QByteArray fromRawData(const char *data, qsizetype size)
Constructs a QByteArray that uses the first size bytes of the data array.
Definition qbytearray.h:409
\inmodule QtCore\reentrant
Definition qcborarray.h:20
\inmodule QtCore\reentrant
Definition qcbormap.h:21
\inmodule QtCore\reentrant
\inmodule QtCore\reentrant
Definition qcborvalue.h:47
qint64 toInteger(qint64 defaultValue=0) const
Returns the integer value stored in this QCborValue, if it is of the integer type.
Definition qcborvalue.h:187
static QThread * mainThread()
The QDirListing class provides an STL-style iterator for directory entries.
Definition qdirlisting.h:18
@ Files
Definition qdir.h:23
void setExtraSearchPath(const QString &path)
int indexOf(const QString &needle) const
QMultiMap< int, QString > keyMap() const
QList< QPluginParsedMetaData > MetaDataList
QFactoryLoader(const char *iid, const QString &suffix=QString(), Qt::CaseSensitivity=Qt::CaseSensitive)
MetaDataList metaData() const
QList< QCborArray > metaDataKeys() const
QObject * instance(int index) const
\inmodule QtCore\reentrant
Definition qjsonobject.h:20
constexpr bool isEmpty() const noexcept
QPluginParsedMetaData metaData
Definition qlibrary_p.h:90
std::unique_ptr< QLibraryPrivate, Deleter > UniquePtr
Definition qlibrary_p.h:63
QObject * pluginInstance()
Definition qlibrary.cpp:499
static QLibraryPrivate * findOrCreate(const QString &fileName, const QString &version=QString(), QLibrary::LoadHints loadHints={ })
Definition qlibrary.cpp:459
@ PreventUnloadHint
Definition qlibrary.h:26
\inmodule QtCore
Definition qmutex.h:313
\inmodule QtCore
Definition qmutex.h:281
\inmodule QtCore
Definition qobject.h:103
bool moveToThread(QThread *thread QT6_DECL_NEW_OVERLOAD_TAIL)
Changes the thread affinity for this object and its children and returns true on success.
Definition qobject.cpp:1643
static QList< QStaticPlugin > staticPlugins()
Returns a list of QStaticPlugins held by the plugin loader.
QCborValue value(QtPluginMetaDataKeys k) const
bool parse(QByteArrayView input)
QJsonObject toJson() const
\inmodule QtCore
Definition qmutex.h:309
const_iterator cend() const noexcept
Definition qset.h:142
iterator find(const T &value)
Definition qset.h:159
\inmodule QtCore
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:129
bool startsWith(const QString &s, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
Returns true if the string starts with s; otherwise returns false.
Definition qstring.cpp:5455
const QChar * constData() const
Returns a pointer to the data stored in the QString.
Definition qstring.h:1246
static QString fromUtf8(QByteArrayView utf8)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qstring.cpp:6018
bool endsWith(const QString &s, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
Returns true if the string ends with s; otherwise returns false.
Definition qstring.cpp:5506
QString & remove(qsizetype i, qsizetype len)
Removes n characters from the string, starting at the given position index, and returns a reference t...
Definition qstring.cpp:3466
#define this
Definition dialogs.cpp:9
QMap< QString, QString > map
[6]
QSet< QString >::iterator it
Combined button and popup list for selecting options.
CaseSensitivity
@ CaseInsensitive
QTextStream & endl(QTextStream &stream)
Writes '\n' to the stream and flushes the stream.
QImageReader reader("image.png")
[1]
#define Q_UNLIKELY(x)
#define Q_IMPLICIT
QList< QString > QStringList
Constructs a string list that contains the given string, str.
DBusConnection const char DBusError * error
static QString header(const QString &name)
EGLOutputLayerEXT EGLint EGLAttrib value
[5]
static bool isIidMatch(QByteArrayView raw, QLatin1StringView iid)
#define CONVERT_TO_STRING(IntKey, StringKey, Description)
static IterationResult iterateInPluginMetaData(QByteArrayView raw, F &&f)
#define Q_GLOBAL_STATIC(TYPE, NAME,...)
#define qCDebug(category,...)
#define Q_LOGGING_CATEGORY_WITH_ENV_OVERRIDE(name, env, categoryName)
GLsizei const GLfloat * v
[13]
GLuint64 key
GLuint index
[2]
GLboolean r
[2]
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLfloat GLfloat f
GLsizei const GLuint * paths
GLhandleARB obj
[2]
GLsizei const GLchar *const * path
GLuint64EXT * result
[6]
QtPluginMetaDataKeys
Definition qplugin_p.h:22
#define QT_PLUGIN_FOREACH_METADATA(F)
Definition qplugin_p.h:34
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
#define Q_ASSERT_X(cond, x, msg)
Definition qrandom.cpp:48
SSL_CTX int void * arg
QBasicUtf8StringView< false > QUtf8StringView
Definition qstringfwd.h:46
#define QStringLiteral(str)
#define Q_UNUSED(x)
#define Q_TRACE(x,...)
Definition qtrace_p.h:144
#define Q_TRACE_POINT(provider, tracepoint,...)
Definition qtrace_p.h:232
#define QT_VERSION_CHECK(major, minor, patch)
ptrdiff_t qsizetype
Definition qtypes.h:165
long long qint64
Definition qtypes.h:60
static const struct @450 keyMap[]
QByteArray ba
[0]
QStringList keys
QMutex mutex
[2]
QReadWriteLock lock
[0]
QGraphicsItem * item
char * toString(const MyType &t)
[31]
\inmodule QtCore \inheaderfile QtCborCommon \reentrant
Definition qcborcommon.h:63
static constexpr quint8 CurrentMetaDataVersion
Definition qplugin.h:39
\inmodule QtCore
Definition qplugin.h:110