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
qpluginloader.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// Copyright (C) 2018 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 "qpluginloader.h"
6
7#include "qcoreapplication.h"
8#include "qdebug.h"
9#include "qdir.h"
10#include "qfactoryloader_p.h"
11#include "qfileinfo.h"
12#include "qjsondocument.h"
13
14#if QT_CONFIG(library)
15# include "qlibrary_p.h"
16#endif
17
19
20using namespace Qt::StringLiterals;
21
22#if QT_CONFIG(library)
23
77static constexpr QLibrary::LoadHints defaultLoadHints = QLibrary::PreventUnloadHint;
78
82QPluginLoader::QPluginLoader(QObject *parent)
83 : QObject(parent), d(nullptr), did_load(false)
84{
85}
86
98QPluginLoader::QPluginLoader(const QString &fileName, QObject *parent)
99 : QObject(parent), d(nullptr), did_load(false)
100{
102 setLoadHints(defaultLoadHints);
103}
104
113QPluginLoader::~QPluginLoader()
114{
115 if (d)
116 d->release();
117}
118
139QObject *QPluginLoader::instance()
140{
141 if (!isLoaded() && !load())
142 return nullptr;
143 return d->pluginInstance();
144}
145
156QJsonObject QPluginLoader::metaData() const
157{
158 if (!d)
159 return QJsonObject();
160 return d->metaData.toJson();
161}
162
173bool QPluginLoader::load()
174{
175 if (!d || d->fileName.isEmpty())
176 return false;
177 if (did_load)
178 return d->pHnd && d->instanceFactory.loadAcquire();
179 if (!d->isPlugin())
180 return false;
181 did_load = true;
182 return d->loadPlugin();
183}
184
201bool QPluginLoader::unload()
202{
203 if (did_load) {
204 did_load = false;
205 return d->unload();
206 }
207 if (d) // Ouch
208 d->errorString = tr("The plugin was not loaded.");
209 return false;
210}
211
217bool QPluginLoader::isLoaded() const
218{
219 return d && d->pHnd && d->instanceFactory.loadRelaxed();
220}
221
222#if defined(QT_SHARED)
223static QString locatePlugin(const QString& fileName)
224{
225 const bool isAbsolute = QDir::isAbsolutePath(fileName);
226 if (isAbsolute) {
228 if (fi.isFile()) {
229 return fi.canonicalFilePath();
230 }
231 }
233 prefixes.prepend(QString());
235 suffixes.prepend(QString());
236
237 // Split up "subdir/filename"
238 const qsizetype slash = fileName.lastIndexOf(u'/');
239 const auto baseName = QStringView{fileName}.mid(slash + 1);
240 const auto basePath = isAbsolute ? QStringView() : QStringView{fileName}.left(slash + 1); // keep the '/'
241
243 if (isAbsolute) {
244 paths.append(fileName.left(slash)); // don't include the '/'
245 } else {
246 paths = QCoreApplication::libraryPaths();
247 }
248
249 for (const QString &path : std::as_const(paths)) {
250 for (const QString &prefix : std::as_const(prefixes)) {
251 for (const QString &suffix : std::as_const(suffixes)) {
252#ifdef Q_OS_ANDROID
253 {
254 QString pluginPath = basePath + prefix + baseName + suffix;
255 const QString fn = path + "/lib"_L1 + pluginPath.replace(u'/', u'_');
256 qCDebug(qt_lcDebugPlugins) << "Trying..." << fn;
257 if (QFileInfo(fn).isFile())
258 return fn;
259 }
260#endif
261 const QString fn = path + u'/' + basePath + prefix + baseName + suffix;
262 qCDebug(qt_lcDebugPlugins) << "Trying..." << fn;
263 if (QFileInfo(fn).isFile())
264 return fn;
265 }
266 }
267 }
268 qCDebug(qt_lcDebugPlugins) << fileName << "not found";
269 return QString();
270}
271#endif
272
295void QPluginLoader::setFileName(const QString &fileName)
296{
297#if defined(QT_SHARED)
298 QLibrary::LoadHints lh = defaultLoadHints;
299 if (d) {
300 lh = d->loadHints();
301 d->release();
302 d = nullptr;
303 did_load = false;
304 }
305
306 const QString fn = locatePlugin(fileName);
307
309 if (!fn.isEmpty())
310 d->updatePluginState();
311
312#else
313 qCWarning(qt_lcDebugPlugins, "Cannot load '%ls' into a statically linked Qt library.",
315#endif
316}
317
318QString QPluginLoader::fileName() const
319{
320 if (d)
321 return d->fileName;
322 return QString();
323}
324
330QString QPluginLoader::errorString() const
331{
332 return (!d || d->errorString.isEmpty()) ? tr("Unknown error") : d->errorString;
333}
334
349void QPluginLoader::setLoadHints(QLibrary::LoadHints loadHints)
350{
351 if (!d) {
352 d = QLibraryPrivate::findOrCreate({}, {}, loadHints); // ugly, but we need a d-ptr
353 d->errorString.clear();
354 } else {
355 d->setLoadHints(loadHints);
356 }
357}
358
359QLibrary::LoadHints QPluginLoader::loadHints() const
360{
361 // Not having a d-pointer means that the user hasn't called
362 // setLoadHints() / setFileName() yet. In setFileName() we will
363 // then force defaultLoadHints on loading, so we must return them
364 // from here as well.
365
366 return d ? d->loadHints() : defaultLoadHints;
367}
368
369#endif // QT_CONFIG(library)
370
371typedef QList<QStaticPlugin> StaticPluginList;
372Q_GLOBAL_STATIC(StaticPluginList, staticPluginList)
373
374
382{
383 // using operator* because we shouldn't be registering plugins while
384 // unloading the application!
385 StaticPluginList &plugins = *staticPluginList;
386
387 // insert the plugin in the list, sorted by address, so we can detect
388 // duplicate registrations
389 auto comparator = [=](const QStaticPlugin &p1, const QStaticPlugin &p2) {
390 using Less = std::less<decltype(plugin.instance)>;
391 return Less{}(p1.instance, p2.instance);
392 };
393 auto pos = std::lower_bound(plugins.constBegin(), plugins.constEnd(), plugin, comparator);
394 if (pos == plugins.constEnd() || pos->instance != plugin.instance)
395 plugins.insert(pos, plugin);
396}
397
404{
405 QObjectList instances;
406 if (staticPluginList.exists()) {
407 const StaticPluginList &plugins = *staticPluginList;
408 instances.reserve(plugins.size());
409 for (QStaticPlugin plugin : plugins)
410 instances += plugin.instance();
411 }
412 return instances;
413}
414
422QList<QStaticPlugin> QPluginLoader::staticPlugins()
423{
424 StaticPluginList *plugins = staticPluginList();
425 if (plugins)
426 return *plugins;
427 return QList<QStaticPlugin>();
428}
429
460{
461 QByteArrayView data(static_cast<const char *>(rawMetaData), rawMetaDataSize);
463 Q_ASSERT(!parsed.isError());
464 return parsed.toJson();
465}
466
468
469#include "moc_qpluginloader.cpp"
static bool isAbsolutePath(const QString &path)
Returns true if path is absolute; returns false if it is relative.
Definition qdir.h:184
\inmodule QtCore\reentrant
Definition qjsonobject.h:20
static QStringList suffixes_sys(const QString &fullVersion)
static QStringList prefixes_sys()
static QLibraryPrivate * findOrCreate(const QString &fileName, const QString &version=QString(), QLibrary::LoadHints loadHints={ })
Definition qlibrary.cpp:459
@ PreventUnloadHint
Definition qlibrary.h:26
void reserve(qsizetype size)
Definition qlist.h:753
\inmodule QtCore
Definition qobject.h:103
static QList< QStaticPlugin > staticPlugins()
Returns a list of QStaticPlugins held by the plugin loader.
static QObjectList staticInstances()
Returns a list of static plugin instances (root components) held by the plugin loader.
QJsonObject toJson() const
\inmodule QtCore
\inmodule QtCore
Definition qstringview.h:78
constexpr QStringView mid(qsizetype pos, qsizetype n=-1) const noexcept
Returns the substring of length length starting at position start in this object.
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:129
QString & replace(qsizetype i, qsizetype len, QChar after)
Definition qstring.cpp:3824
bool isEmpty() const noexcept
Returns true if the string has no characters; otherwise returns false.
Definition qstring.h:192
QPixmap p2
p1 load("image.bmp")
QPixmap p1
[0]
Combined button and popup list for selecting options.
Q_MULTIMEDIA_EXPORT QString errorString(HRESULT hr)
DBusConnection const char DBusError DBusBusType DBusError return DBusConnection DBusHandleMessageFunction void DBusFreeFunction return DBusConnection return DBusConnection return const char DBusError return DBusConnection DBusMessage dbus_uint32_t return DBusConnection dbus_bool_t DBusConnection DBusAddWatchFunction DBusRemoveWatchFunction DBusWatchToggledFunction void DBusFreeFunction return DBusConnection DBusDispatchStatusFunction void DBusFreeFunction DBusTimeout return DBusTimeout return DBusWatch return DBusWatch unsigned int return DBusError const DBusError return const DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessageIter int const void return DBusMessageIter DBusMessageIter return DBusMessageIter void DBusMessageIter void int return DBusMessage DBusMessageIter return DBusMessageIter return DBusMessageIter DBusMessageIter const char const char const char const char return DBusMessage return DBusMessage const char return DBusMessage dbus_bool_t return DBusMessage dbus_uint32_t return DBusMessage void
#define Q_GLOBAL_STATIC(TYPE, NAME,...)
#define qCWarning(category,...)
#define qCDebug(category,...)
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLint left
GLsizei const GLuint * paths
GLsizei const GLchar *const * path
void Q_CORE_EXPORT qRegisterStaticPluginFunction(QStaticPlugin staticPlugin)
QList< QStaticPlugin > StaticPluginList
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
#define qUtf16Printable(string)
Definition qstring.h:1543
#define tr(X)
ptrdiff_t qsizetype
Definition qtypes.h:165
file setFileName("readme.txt")
QObject::connect nullptr
\inmodule QtCore
Definition qplugin.h:110
QJsonObject metaData() const
\variable QStaticPlugin::instance