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
qqmlpluginimporter.cpp
Go to the documentation of this file.
1// Copyright (C) 2021 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
5#include "qqmlimport_p.h"
6
7#include <private/qqmlextensionplugin_p.h>
8#include <private/qqmltypeloader_p.h>
9#include <private/qqmlglobal_p.h>
10
11#include <QtCore/qobject.h>
12#include <QtCore/qpluginloader.h>
13#include <QtCore/qdir.h>
14#include <QtCore/qloggingcategory.h>
15#include <QtCore/qjsonarray.h>
16
17#include <unordered_map>
18
20
22
23struct QmlPlugin {
24 std::unique_ptr<QPluginLoader> loader;
25};
26
28{
29 Q_DISABLE_COPY_MOVE(PluginMap)
30public:
31 PluginMap() = default;
32 ~PluginMap() = default;
33
34 // This is a std::unordered_map because QHash cannot handle move-only types.
35 using Container = std::unordered_map<QString, QmlPlugin>;
36
37private:
38 QBasicMutex mutex;
39 Container plugins;
40 friend class PluginMapPtr;
41};
42
44{
45 Q_DISABLE_COPY_MOVE(PluginMapPtr)
46public:
47 PluginMapPtr(PluginMap *map) : map(map), locker(&map->mutex) {}
48 ~PluginMapPtr() = default;
49
50 PluginMap::Container &operator*() { return map->plugins; }
51 const PluginMap::Container &operator*() const { return map->plugins; }
52
53 PluginMap::Container *operator->() { return &map->plugins; }
54 const PluginMap::Container *operator->() const { return &map->plugins; }
55
56private:
57 PluginMap *map;
58 QMutexLocker<QBasicMutex> locker;
59};
60
61Q_GLOBAL_STATIC(PluginMap, qmlPluginsById); // stores the uri and the PluginLoaders
62
63static QVector<QStaticPlugin> makePlugins()
64{
65 QVector<QStaticPlugin> plugins;
66 // To avoid traversing all static plugins for all imports, we cut down
67 // the list the first time called to only contain QML plugins:
68 const auto staticPlugins = QPluginLoader::staticPlugins();
69 for (const QStaticPlugin &plugin : staticPlugins) {
70 const QString iid = plugin.metaData().value(QLatin1String("IID")).toString();
75 qWarning()
76 << "Found plugin with old IID, this will be unsupported in upcoming Qt releases:"
77 << plugin.metaData();
78 }
79 plugins.append(plugin);
80 }
81 }
82 return plugins;
83}
84
85/*
86 Returns the list of possible versioned URI combinations. For example, if \a uri is
87 QtQml.Models, \a vmaj is 2, and \a vmin is 0, this method returns the following:
88 [QtQml.Models.2.0, QtQml.2.0.Models, QtQml.Models.2, QtQml.2.Models, QtQml.Models]
89 */
91{
94 int index = uri.size();
95 do {
96 QString versionUri = uri;
99 result += versionUri;
100
101 index = uri.lastIndexOf(u'.', index - 1);
102 } while (index > 0 && mode != QQmlImports::Unversioned);
103 }
104 return result;
105}
106
107static bool unloadPlugin(const std::pair<const QString, QmlPlugin> &plugin)
108{
109 const auto &loader = plugin.second.loader;
110 if (!loader)
111 return false;
112
113#if QT_CONFIG(library)
114 if (auto extensionPlugin = qobject_cast<QQmlExtensionPlugin *>(loader->instance()))
115 extensionPlugin->unregisterTypes();
116
117# ifndef Q_OS_MACOS
118 if (!loader->unload()) {
119 qWarning("Unloading %s failed: %s", qPrintable(plugin.first),
120 qPrintable(loader->errorString()));
121 return false;
122 }
123# endif
124#endif
125
126 return true;
127}
128
130{
131 PluginMapPtr plugins(qmlPluginsById());
132 for (const auto &plugin : std::as_const(*plugins))
133 unloadPlugin(plugin);
134 plugins->clear();
135}
136
138{
139 PluginMapPtr plugins(qmlPluginsById());
140
141 auto it = plugins->find(pluginId);
142 if (it == plugins->end())
143 return false;
144
145 const bool success = unloadPlugin(*it);
146
147 plugins->erase(it);
148 return success;
149}
150
152{
153 PluginMapPtr plugins(qmlPluginsById());
155 for (auto it = plugins->cbegin(), end = plugins->cend(); it != end; ++it) {
156 if (it->second.loader != nullptr)
157 results.append(it->first);
158 }
159 return results;
160}
161
162QString QQmlPluginImporter::truncateToDirectory(const QString &qmldirFilePath)
163{
164 const int slash = qmldirFilePath.lastIndexOf(u'/');
165 return slash > 0 ? qmldirFilePath.left(slash) : qmldirFilePath;
166}
167
168void QQmlPluginImporter::finalizePlugin(QObject *instance, const QString &pluginId) {
169 // The plugin's per-engine initialization does not need lock protection, as this function is
170 // only called from the engine specific loader thread and importDynamicPlugin as well as
171 // importStaticPlugin are the only places of access.
172
173 database->initializedPlugins.insert(pluginId);
174 if (auto *extensionIface = qobject_cast<QQmlExtensionInterface *>(instance))
175 typeLoader->initializeEngine(extensionIface, uri.toUtf8().constData());
176 else if (auto *engineIface = qobject_cast<QQmlEngineExtensionInterface *>(instance))
177 typeLoader->initializeEngine(engineIface, uri.toUtf8().constData());
178}
179
181 // Dynamic plugins are differentiated by their filepath. For static plugins we
182 // don't have that information so we use their address as key instead.
183 QTypeRevision importVersion = version;
184 {
185 PluginMapPtr plugins(qmlPluginsById());
186
187 // Plugin types are global across all engines and should only be
188 // registered once. But each engine still needs to be initialized.
189 bool typesRegistered = plugins->find(pluginId) != plugins->end();
190
191 if (!typesRegistered) {
192 plugins->insert(std::make_pair(pluginId, QmlPlugin()));
194 instance, QFileInfo(qmldirPath).absoluteFilePath(), uri,
195 qmldir->typeNamespace(), importVersion, errors)
197 return QTypeRevision();
198 }
199
200 importVersion = QQmlImportDatabase::lockModule(
201 uri, qmldir->typeNamespace(), importVersion, errors);
202 if (!importVersion.isValid())
203 return QTypeRevision();
204 }
205
206 // Release the lock on plugins early as we're done with the global part. Releasing the lock
207 // also allows other QML loader threads to acquire the lock while this thread is blocking
208 // in the initializeEngine call to the gui thread (which in turn may be busy waiting for
209 // other QML loader threads and thus not process the initializeEngine call).
210 }
211
212 if (!database->initializedPlugins.contains(pluginId))
213 finalizePlugin(instance, pluginId);
214
215 return QQmlImports::validVersion(importVersion);
216}
217
219 const QString &filePath, const QString &pluginId, bool optional)
220{
221 QObject *instance = nullptr;
222 QTypeRevision importVersion = version;
223
224 const bool engineInitialized = database->initializedPlugins.contains(pluginId);
225 {
226 PluginMapPtr plugins(qmlPluginsById());
227 bool typesRegistered = plugins->find(pluginId) != plugins->end();
228
229 if (!engineInitialized || !typesRegistered) {
230 const QFileInfo fileInfo(filePath);
231 if (!typesRegistered && optional) {
233 nullptr, fileInfo.absolutePath(), uri, qmldir->typeNamespace(),
234 importVersion, errors)) {
236 // try again with plugin
237 break;
239 importVersion = QQmlImportDatabase::lockModule(
240 uri, qmldir->typeNamespace(), importVersion, errors);
241 if (!importVersion.isValid())
242 return QTypeRevision();
243 // instance and loader intentionally left at nullptr
244 plugins->insert(std::make_pair(pluginId, QmlPlugin()));
245 // Not calling initializeEngine with null instance
246 database->initializedPlugins.insert(pluginId);
247 return importVersion;
249 return QTypeRevision();
250 }
251 }
252
253#if QT_CONFIG(library)
254 if (!typesRegistered) {
255
256 // Check original filePath. If that one is empty, not being able
257 // to load the plugin is not an error. We were just checking if
258 // the types are already available. absoluteFilePath can still be
259 // empty if filePath is not.
260 if (filePath.isEmpty())
261 return QTypeRevision();
262
263 const QString absoluteFilePath = fileInfo.absoluteFilePath();
265 if (errors) {
267 error.setDescription(
268 QQmlImportDatabase::tr("File name case mismatch for \"%1\"")
270 errors->prepend(error);
271 }
272 return QTypeRevision();
273 }
274
275 QmlPlugin plugin;
276 plugin.loader = std::make_unique<QPluginLoader>(absoluteFilePath);
277 if (!plugin.loader->load()) {
278 if (errors) {
280 error.setDescription(plugin.loader->errorString());
281 errors->prepend(error);
282 }
283 return QTypeRevision();
284 }
285
286 instance = plugin.loader->instance();
287 plugins->insert(std::make_pair(pluginId, std::move(plugin)));
288
289 // Continue with shared code path for dynamic and static plugins:
291 instance, fileInfo.absolutePath(), uri, qmldir->typeNamespace(),
292 importVersion, errors)
294 return QTypeRevision();
295 }
296
297 importVersion = QQmlImportDatabase::lockModule(
298 uri, qmldir->typeNamespace(), importVersion, errors);
299 if (!importVersion.isValid())
300 return QTypeRevision();
301 } else {
302 auto it = plugins->find(pluginId);
303 if (it != plugins->end() && it->second.loader)
304 instance = it->second.loader->instance();
305 }
306#else
307 // Here plugin is not optional and NOT QT_CONFIG(library)
308 // Cannot finalize such plugin and return valid, because no types are registered.
309 // Just return invalid.
310 if (!optional)
311 return QTypeRevision();
312#endif // QT_CONFIG(library)
313 }
314
315 // Release the lock on plugins early as we're done with the global part. Releasing the lock
316 // also allows other QML loader threads to acquire the lock while this thread is blocking
317 // in the initializeEngine call to the gui thread (which in turn may be busy waiting for
318 // other QML loader threads and thus not process the initializeEngine call).
319 }
320
321 if (!engineInitialized)
322 finalizePlugin(instance, pluginId);
323
324 return QQmlImports::validVersion(importVersion);
325}
326
357QString QQmlPluginImporter::resolvePlugin(const QString &qmldirPluginPath, const QString &baseName)
358{
359#if defined(Q_OS_WIN)
360 static const QString prefix;
361 static const QStringList suffixes = {
362 # ifdef QT_DEBUG
363 QLatin1String("d.dll"), // try a qmake-style debug build first
364 QLatin1String(".dll")
365 #else
366 QLatin1String(".dll"),
367 QLatin1String("d.dll") // try a qmake-style debug build after
368 # endif
369 };
370#elif defined(Q_OS_DARWIN)
371 static const QString prefix = QLatin1String("lib");
372 static const QStringList suffixes = {
373 # ifdef QT_DEBUG
374 QLatin1String("_debug.dylib"), // try a qmake-style debug build first
375 QLatin1String(".dylib"),
376 # else
377 QLatin1String(".dylib"),
378 QLatin1String("_debug.dylib"), // try a qmake-style debug build after
379 # endif
380 QLatin1String(".so"),
381 QLatin1String(".bundle")
382 };
383#else // Unix
384 static const QString prefix = QLatin1String("lib");
385 static const QStringList suffixes = {
386 # if defined(Q_OS_ANDROID)
387 QStringLiteral(LIBS_SUFFIX),
388 # endif
389 QLatin1String(".so")
390 };
391#endif
392
393 QStringList searchPaths = database->filePluginPath;
394 bool qmldirPluginPathIsRelative = QDir::isRelativePath(qmldirPluginPath);
395 if (!qmldirPluginPathIsRelative)
396 searchPaths.prepend(qmldirPluginPath);
397
398 for (const QString &pluginPath : std::as_const(searchPaths)) {
399 QString resolvedBasePath;
400 if (pluginPath == QLatin1String(".")) {
401 if (qmldirPluginPathIsRelative && !qmldirPluginPath.isEmpty()
402 && qmldirPluginPath != QLatin1String(".")) {
403 resolvedBasePath = QDir::cleanPath(qmldirPath + u'/' + qmldirPluginPath);
404 } else {
405 resolvedBasePath = qmldirPath;
406 }
407 } else {
408 if (QDir::isRelativePath(pluginPath))
409 resolvedBasePath = QDir::cleanPath(qmldirPath + u'/' + pluginPath);
410 else
411 resolvedBasePath = pluginPath;
412 }
413
414 // hack for resources, should probably go away
415 if (resolvedBasePath.startsWith(u':'))
416 resolvedBasePath = QCoreApplication::applicationDirPath();
417
418 if (!resolvedBasePath.endsWith(u'/'))
419 resolvedBasePath += u'/';
420
421 QString resolvedPath = resolvedBasePath + prefix + baseName;
422 for (const QString &suffix : suffixes) {
423 QString absolutePath = typeLoader->absoluteFilePath(resolvedPath + suffix);
424 if (!absolutePath.isEmpty())
425 return absolutePath;
426 }
427
428#if defined(Q_OS_ANDROID)
429 if (qmldirPath.size() > 25 && qmldirPath.at(0) == QLatin1Char(':')
430 && qmldirPath.at(1) == QLatin1Char('/')
431 && qmldirPath.startsWith(QStringLiteral(":/android_rcc_bundle/qml/"),
433 QString pluginName = qmldirPath.mid(21) + u'/' + baseName;
434 pluginName.replace(QLatin1Char('/'), QLatin1Char('_'));
435 QString bundledPath = resolvedBasePath + QLatin1String("lib") + pluginName;
436 for (const QString &suffix : suffixes) {
437 const QString absolutePath = typeLoader->absoluteFilePath(bundledPath + suffix);
438 if (!absolutePath.isEmpty()) {
439 qWarning("The implicit resolving of Qml plugin locations using the URI "
440 "embedded in the filename has been deprecated. Please use the "
441 "modern CMake API to create QML modules or set the name of "
442 "QML plugin in qmldir file, that matches the name of plugin "
443 "on file system. The correct plugin name is '%s'.",
444 qPrintable(pluginName));
445 return absolutePath;
446 }
447 }
448 }
449#endif
450 }
451
452 qCDebug(lcQmlImport) << "resolvePlugin" << "Could not resolve dynamic plugin with base name"
453 << baseName << "in" << qmldirPath
454 << " file does not exist";
455
456 return QString();
457}
458
459/*
460 Get all static plugins that are QML plugins and has a meta data URI that matches with one of
461 \a versionUris, which is a list of all possible versioned URI combinations - see versionUriList()
462 above.
463 */
464bool QQmlPluginImporter::populatePluginDataVector(QVector<StaticPluginData> &result, const QStringList &versionUris)
465{
466 static const QVector<QStaticPlugin> plugins = makePlugins();
467 for (const QStaticPlugin &plugin : plugins) {
468 // Since a module can list more than one plugin,
469 // we keep iterating even after we found a match.
470 QObject *instance = plugin.instance();
471 if (qobject_cast<QQmlEngineExtensionPlugin *>(instance)
472 || qobject_cast<QQmlExtensionPlugin *>(instance)) {
473 const QJsonArray metaTagsUriList = plugin.metaData().value(
474 QStringLiteral("uri")).toArray();
475 if (metaTagsUriList.isEmpty()) {
476 if (errors) {
478 error.setDescription(QQmlImportDatabase::tr(
479 "static plugin for module \"%1\" with name \"%2\" "
480 "has no metadata URI")
482 instance->metaObject()->className())));
483 error.setUrl(QUrl::fromLocalFile(qmldir->qmldirLocation()));
484 errors->prepend(error);
485 }
486 return false;
487 }
488 // A plugin can be set up to handle multiple URIs, so go through the list:
489 for (const QJsonValueConstRef metaTagUri : metaTagsUriList) {
490 if (versionUris.contains(metaTagUri.toString())) {
491 result.append({ plugin, metaTagsUriList });
492 break;
493 }
494 }
495 }
496 }
497 return true;
498}
499
501 const auto qmldirPlugins = qmldir->plugins();
502 const int qmldirPluginCount = qmldirPlugins.size();
503 QTypeRevision importVersion = version;
504
505 // If the path contains a version marker or if we have more than one plugin,
506 // we need to use paths. In that case we cannot fall back to other instances
507 // of the same module if a qmldir is rejected. However, as we don't generate
508 // such modules, it shouldn't be a problem.
509 const bool canUseUris = qmldirPluginCount == 1
510 && qmldirPath.endsWith(u'/' + QString(uri).replace(u'.', u'/'));
511 const QString moduleId = canUseUris ? uri : qmldir->qmldirLocation();
512
513 if (!database->modulesForWhichPluginsHaveBeenLoaded.contains(moduleId)) {
514 // First search for listed qmldir plugins dynamically. If we cannot resolve them all, we
515 // continue searching static plugins that has correct metadata uri. Note that since we
516 // only know the uri for a static plugin, and not the filename, we cannot know which
517 // static plugin belongs to which listed plugin inside qmldir. And for this reason,
518 // mixing dynamic and static plugins inside a single module is not recommended.
519
520 int dynamicPluginsFound = 0;
521 int staticPluginsFound = 0;
522
523 for (const QQmlDirParser::Plugin &plugin : qmldirPlugins) {
524 const QString resolvedFilePath = resolvePlugin(plugin.path, plugin.name);
525
526 if (!canUseUris && resolvedFilePath.isEmpty())
527 continue;
528
529 importVersion = importDynamicPlugin(
530 resolvedFilePath,
531 canUseUris ? uri : QFileInfo(resolvedFilePath).absoluteFilePath(),
532 plugin.optional);
533 if (importVersion.isValid())
534 ++dynamicPluginsFound;
535 else if (!resolvedFilePath.isEmpty())
536 return QTypeRevision();
537 }
538
539 if (dynamicPluginsFound < qmldirPluginCount) {
540 // Check if the missing plugins can be resolved statically. We do this by looking at
541 // the URIs embedded in a plugins meta data. Since those URIs can be anything from
542 // fully versioned to unversioned, we need to compare with differnt version strings.
543 // If a module has several plugins, they must all have the same version. Start by
544 // populating pluginPairs with relevant plugins to cut the list short early on:
545 const QStringList versionUris = versionUriList(uri, importVersion);
546 QVector<StaticPluginData> pluginPairs;
547 if (!populatePluginDataVector(pluginPairs, versionUris))
548 return QTypeRevision();
549
550 for (const QString &versionUri : versionUris) {
551 for (const StaticPluginData &pair : std::as_const(pluginPairs)) {
552 for (const QJsonValueConstRef metaTagUri : pair.uriList) {
553 if (versionUri == metaTagUri.toString()) {
554 staticPluginsFound++;
555 QObject *instance = pair.plugin.instance();
556 importVersion = importStaticPlugin(
557 instance,
558 canUseUris ? uri : QString::asprintf("%p", instance));
559 if (!importVersion.isValid()){
560 if (errors) {
561 Q_ASSERT(!errors->isEmpty());
562 const QQmlError poppedError = errors->takeFirst();
564 error.setDescription(
565 QQmlImportDatabase::tr(
566 "static plugin for module \"%1\" with "
567 "name \"%2\" cannot be loaded: %3")
569 instance->metaObject()->className()),
570 poppedError.description()));
571 error.setUrl(QUrl::fromLocalFile(qmldir->qmldirLocation()));
572 errors->prepend(error);
573 }
574 return QTypeRevision();
575 }
576
578 << "importExtension" << "loaded static plugin " << versionUri;
579
580 break;
581 }
582 }
583 }
584 if (staticPluginsFound > 0)
585 break;
586 }
587 }
588
589 if ((dynamicPluginsFound + staticPluginsFound) < qmldirPluginCount) {
590 if (errors) {
592 if (qmldirPluginCount > 1 && staticPluginsFound > 0) {
593 error.setDescription(QQmlImportDatabase::tr(
594 "could not resolve all plugins for module \"%1\"")
595 .arg(uri));
596 } else {
597 error.setDescription(QQmlImportDatabase::tr(
598 "module \"%1\" plugin \"%2\" not found")
599 .arg(uri, qmldirPlugins[dynamicPluginsFound].name));
600 }
601 error.setUrl(QUrl::fromLocalFile(qmldir->qmldirLocation()));
602 errors->prepend(error);
603 }
604 return QTypeRevision();
605 }
606
607 database->modulesForWhichPluginsHaveBeenLoaded.insert(moduleId);
608 }
609 return QQmlImports::validVersion(importVersion);
610}
611
const PluginMap::Container & operator*() const
PluginMap::Container * operator->()
~PluginMapPtr()=default
const PluginMap::Container * operator->() const
PluginMap::Container & operator*()
PluginMapPtr(PluginMap *map)
std::unordered_map< QString, QmlPlugin > Container
~PluginMap()=default
PluginMap()=default
const char * constData() const noexcept
Returns a pointer to the const data stored in the byte array.
Definition qbytearray.h:124
static QString applicationDirPath()
Returns the directory that contains the application executable.
static bool isRelativePath(const QString &path)
Returns true if path is relative; returns false if it is absolute.
Definition qdir.cpp:2412
static QString cleanPath(const QString &path)
Returns path with directory separators normalized (that is, platform-native separators converted to "...
Definition qdir.cpp:2398
QString absoluteFilePath() const
QString absolutePath() const
Returns the absolute path of the file system entry this QFileInfo refers to, excluding the entry's na...
\inmodule QtCore\reentrant
Definition qjsonarray.h:18
qsizetype size() const noexcept
Definition qlist.h:397
bool isEmpty() const noexcept
Definition qlist.h:401
value_type takeFirst()
Definition qlist.h:566
void prepend(rvalue_ref t)
Definition qlist.h:473
void append(parameter_type t)
Definition qlist.h:458
\inmodule QtCore
Definition qmutex.h:281
\inmodule QtCore
Definition qobject.h:103
static QList< QStaticPlugin > staticPlugins()
Returns a list of QStaticPlugins held by the plugin loader.
The QQmlError class encapsulates a QML error.
Definition qqmlerror.h:18
static QTypeRevision lockModule(const QString &uri, const QString &typeNamespace, QTypeRevision version, QList< QQmlError > *errors)
static QString versionString(QTypeRevision version, ImportVersion importVersion)
static QTypeRevision validVersion(QTypeRevision version=QTypeRevision())
static RegistrationResult registerPluginTypes(QObject *instance, const QString &basePath, const QString &uri, const QString &typeNamespace, QTypeRevision version, QList< QQmlError > *errors)
QTypeRevision importStaticPlugin(QObject *instance, const QString &pluginId)
static bool removePlugin(const QString &pluginId)
QTypeRevision importPlugins()
QTypeRevision importDynamicPlugin(const QString &filePath, const QString &pluginId, bool optional)
static QStringList plugins()
QString absoluteFilePath(const QString &path)
Returns the absolute filename of path via a directory cache.
void initializeEngine(QQmlEngineExtensionInterface *, const char *)
bool contains(const T &value) const
Definition qset.h:71
iterator insert(const T &value)
Definition qset.h:155
\inmodule QtCore
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:129
qsizetype lastIndexOf(QChar c, Qt::CaseSensitivity cs=Qt::CaseSensitive) const noexcept
Definition qstring.h:296
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
QString & replace(qsizetype i, qsizetype len, QChar after)
Definition qstring.cpp:3824
QString mid(qsizetype position, qsizetype n=-1) const &
Definition qstring.cpp:5300
bool isEmpty() const noexcept
Returns true if the string has no characters; otherwise returns false.
Definition qstring.h:192
qsizetype size() const noexcept
Returns the number of characters in this string.
Definition qstring.h:186
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
const QChar at(qsizetype i) const
Returns the character at the given index position in the string.
Definition qstring.h:1226
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 & insert(qsizetype i, QChar c)
Definition qstring.cpp:3132
QByteArray toUtf8() const &
Definition qstring.h:634
static QString static QString asprintf(const char *format,...) Q_ATTRIBUTE_FORMAT_PRINTF(1
Definition qstring.cpp:7263
\inmodule QtCore
static QUrl fromLocalFile(const QString &localfile)
Returns a QUrl representation of localFile, interpreted as a local file.
Definition qurl.cpp:3368
QMap< QString, QString > map
[6]
QSet< QString >::iterator it
Combined button and popup list for selecting options.
@ CaseInsensitive
#define Q_UNLIKELY(x)
DBusConnection const char DBusError * error
#define Q_GLOBAL_STATIC(TYPE, NAME,...)
#define qWarning
Definition qlogging.h:166
#define qCDebug(category,...)
#define Q_DECLARE_LOGGING_CATEGORY(name)
GLenum mode
GLuint index
[2]
GLuint GLuint end
GLuint name
GLuint64EXT * result
[6]
bool QQml_isFileCaseCorrect(const QString &fileName, int lengthIn)
Returns true if the case of fileName is equivalent to the file case of fileName on disk,...
#define QQmlEngineExtensionInterface_iid
#define QQmlExtensionInterface_iid
#define QQmlExtensionInterface_iid_old
const QLoggingCategory & lcQmlImport()
void qmlClearEnginePlugins()
static QStringList versionUriList(const QString &uri, QTypeRevision version)
static QVector< QStaticPlugin > makePlugins()
static bool unloadPlugin(const std::pair< const QString, QmlPlugin > &plugin)
static QString absolutePath(const QString &path)
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
SSL_CTX int void * arg
#define qPrintable(string)
Definition qstring.h:1531
QLatin1StringView QLatin1String
Definition qstringfwd.h:31
#define QStringLiteral(str)
static QString absoluteFilePath(const Options *options, const QString &relativeFileName)
Definition main.cpp:1902
QMutex mutex
[2]
char * toString(const MyType &t)
[31]
\inmodule QtCore \reentrant
Definition qchar.h:18
\inmodule QtCore
Definition qplugin.h:110
std::unique_ptr< QPluginLoader > loader