1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Copyright (C) 2018 Intel Corporation.
5** Contact: https://www.qt.io/licensing/
6**
7** This file is part of the QtCore module of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:LGPL$
10** Commercial License Usage
11** Licensees holding valid commercial Qt licenses may use this file in
12** accordance with the commercial license agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and The Qt Company. For licensing terms
15** and conditions see https://www.qt.io/terms-conditions. For further
16** information use the contact form at https://www.qt.io/contact-us.
17**
18** GNU Lesser General Public License Usage
19** Alternatively, this file may be used under the terms of the GNU Lesser
20** General Public License version 3 as published by the Free Software
21** Foundation and appearing in the file LICENSE.LGPL3 included in the
22** packaging of this file. Please review the following information to
23** ensure the GNU Lesser General Public License version 3 requirements
24** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
25**
26** GNU General Public License Usage
27** Alternatively, this file may be used under the terms of the GNU
28** General Public License version 2.0 or (at your option) the GNU General
29** Public license version 3 or any later version approved by the KDE Free
30** Qt Foundation. The licenses are as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
32** included in the packaging of this file. Please review the following
33** information to ensure the GNU General Public License requirements will
34** be met: https://www.gnu.org/licenses/gpl-2.0.html and
35** https://www.gnu.org/licenses/gpl-3.0.html.
36**
37** $QT_END_LICENSE$
38**
39****************************************************************************/
40
41#include "qplatformdefs.h"
42
43#include "qplugin.h"
44#include "qcoreapplication.h"
45#include "qpluginloader.h"
46#include <qfileinfo.h>
47#include "qfactoryloader_p.h"
48#include "qdebug.h"
49#include "qdir.h"
50
51QT_BEGIN_NAMESPACE
52
53#if QT_CONFIG(library)
54
55/*!
56 \class QPluginLoader
57 \inmodule QtCore
58 \reentrant
59 \brief The QPluginLoader class loads a plugin at run-time.
60
61
62 \ingroup plugins
63
64 QPluginLoader provides access to a \l{How to Create Qt
65 Plugins}{Qt plugin}. A Qt plugin is stored in a shared library (a
66 DLL) and offers these benefits over shared libraries accessed
67 using QLibrary:
68
69 \list
70 \li QPluginLoader checks that a plugin is linked against the same
71 version of Qt as the application.
72 \li QPluginLoader provides direct access to a root component object
73 (instance()), instead of forcing you to resolve a C function manually.
74 \endlist
75
76 An instance of a QPluginLoader object operates on a single shared
77 library file, which we call a plugin. It provides access to the
78 functionality in the plugin in a platform-independent way. To
79 specify which plugin to load, either pass a file name in
80 the constructor or set it with setFileName().
81
82 The most important functions are load() to dynamically load the
83 plugin file, isLoaded() to check whether loading was successful,
84 and instance() to access the root component in the plugin. The
85 instance() function implicitly tries to load the plugin if it has
86 not been loaded yet. Multiple instances of QPluginLoader can be
87 used to access the same physical plugin.
88
89 Once loaded, plugins remain in memory until all instances of
90 QPluginLoader has been unloaded, or until the application
91 terminates. You can attempt to unload a plugin using unload(),
92 but if other instances of QPluginLoader are using the same
93 library, the call will fail, and unloading will only happen when
94 every instance has called unload(). Right before the unloading
95 happens, the root component will also be deleted.
96
97 See \l{How to Create Qt Plugins} for more information about
98 how to make your application extensible through plugins.
99
100 Note that the QPluginLoader cannot be used if your application is
101 statically linked against Qt. In this case, you will also have to
102 link to plugins statically. You can use QLibrary if you need to
103 load dynamic libraries in a statically linked application.
104
105 \sa QLibrary, {Plug & Paint Example}
106*/
107
108/*!
109 Constructs a plugin loader with the given \a parent.
110*/
111QPluginLoader::QPluginLoader(QObject *parent)
112 : QObject(parent), d(nullptr), did_load(false)
113{
114}
115
116/*!
117 Constructs a plugin loader with the given \a parent that will
118 load the plugin specified by \a fileName.
119
120 To be loadable, the file's suffix must be a valid suffix for a
121 loadable library in accordance with the platform, e.g. \c .so on
122 Unix, - \c .dylib on \macos and iOS, and \c .dll on Windows. The suffix
123 can be verified with QLibrary::isLibrary().
124
125 \sa setFileName()
126*/
127QPluginLoader::QPluginLoader(const QString &fileName, QObject *parent)
128 : QObject(parent), d(nullptr), did_load(false)
129{
130 setFileName(fileName);
131 setLoadHints(QLibrary::PreventUnloadHint);
132}
133
134/*!
135 Destroys the QPluginLoader object.
136
137 Unless unload() was called explicitly, the plugin stays in memory
138 until the application terminates.
139
140 \sa isLoaded(), unload()
141*/
142QPluginLoader::~QPluginLoader()
143{
144 if (d)
145 d->release();
146}
147
148/*!
149 Returns the root component object of the plugin. The plugin is
150 loaded if necessary. The function returns \nullptr if the plugin could
151 not be loaded or if the root component object could not be
152 instantiated.
153
154 If the root component object was destroyed, calling this function
155 creates a new instance.
156
157 The root component, returned by this function, is not deleted when
158 the QPluginLoader is destroyed. If you want to ensure that the root
159 component is deleted, you should call unload() as soon you don't
160 need to access the core component anymore. When the library is
161 finally unloaded, the root component will automatically be deleted.
162
163 The component object is a QObject. Use qobject_cast() to access
164 interfaces you are interested in.
165
166 \sa load()
167*/
168QObject *QPluginLoader::instance()
169{
170 if (!isLoaded() && !load())
171 return nullptr;
172 return d->pluginInstance();
173}
174
175/*!
176 Returns the meta data for this plugin. The meta data is data specified
177 in a json format using the Q_PLUGIN_METADATA() macro when compiling
178 the plugin.
179
180 The meta data can be queried in a fast and inexpensive way without
181 actually loading the plugin. This makes it possible to e.g. store
182 capabilities of the plugin in there, and make the decision whether to
183 load the plugin dependent on this meta data.
184 */
185QJsonObject QPluginLoader::metaData() const
186{
187 if (!d)
188 return QJsonObject();
189 return d->metaData;
190}
191
192/*!
193 Loads the plugin and returns \c true if the plugin was loaded
194 successfully; otherwise returns \c false. Since instance() always
195 calls this function before resolving any symbols it is not
196 necessary to call it explicitly. In some situations you might want
197 the plugin loaded in advance, in which case you would use this
198 function.
199
200 \sa unload()
201*/
202bool QPluginLoader::load()
203{
204 if (!d || d->fileName.isEmpty())
205 return false;
206 if (did_load)
207 return d->pHnd && d->instanceFactory.loadAcquire();
208 if (!d->isPlugin())
209 return false;
210 did_load = true;
211 return d->loadPlugin();
212}
213
214/*!
215 Unloads the plugin and returns \c true if the plugin could be
216 unloaded; otherwise returns \c false.
217
218 This happens automatically on application termination, so you
219 shouldn't normally need to call this function.
220
221 If other instances of QPluginLoader are using the same plugin, the
222 call will fail, and unloading will only happen when every instance
223 has called unload().
224
225 Don't try to delete the root component. Instead rely on
226 that unload() will automatically delete it when needed.
227
228 \sa instance(), load()
229*/
230bool QPluginLoader::unload()
231{
232 if (did_load) {
233 did_load = false;
234 return d->unload();
235 }
236 if (d) // Ouch
237 d->errorString = tr("The plugin was not loaded.");
238 return false;
239}
240
241/*!
242 Returns \c true if the plugin is loaded; otherwise returns \c false.
243
244 \sa load()
245 */
246bool QPluginLoader::isLoaded() const
247{
248 return d && d->pHnd && d->instanceFactory.loadRelaxed();
249}
250
251#if defined(QT_SHARED)
252static QString locatePlugin(const QString& fileName)
253{
254 const bool isAbsolute = QDir::isAbsolutePath(fileName);
255 if (isAbsolute) {
256 QFileInfo fi(fileName);
257 if (fi.isFile()) {
258 return fi.canonicalFilePath();
259 }
260 }
261 QStringList prefixes = QLibraryPrivate::prefixes_sys();
262 prefixes.prepend(QString());
263 QStringList suffixes = QLibraryPrivate::suffixes_sys(QString());
264 suffixes.prepend(QString());
265
266 // Split up "subdir/filename"
267 const int slash = fileName.lastIndexOf(QLatin1Char('/'));
268 const auto baseName = QStringView{fileName}.mid(slash + 1);
269 const auto basePath = isAbsolute ? QStringView() : QStringView{fileName}.left(slash + 1); // keep the '/'
270
271 const bool debug = qt_debug_component();
272
273 QStringList paths;
274 if (isAbsolute) {
275 paths.append(fileName.left(slash)); // don't include the '/'
276 } else {
277 paths = QCoreApplication::libraryPaths();
278 }
279
280 for (const QString &path : qAsConst(paths)) {
281 for (const QString &prefix : qAsConst(prefixes)) {
282 for (const QString &suffix : qAsConst(suffixes)) {
283#ifdef Q_OS_ANDROID
284 {
285 QString pluginPath = basePath + prefix + baseName + suffix;
286 const QString fn = path + QLatin1String("/lib") + pluginPath.replace(QLatin1Char('/'), QLatin1Char('_'));
287 if (debug)
288 qDebug() << "Trying..." << fn;
289 if (QFileInfo(fn).isFile())
290 return fn;
291 }
292#endif
293 const QString fn = path + QLatin1Char('/') + basePath + prefix + baseName + suffix;
294 if (debug)
295 qDebug() << "Trying..." << fn;
296 if (QFileInfo(fn).isFile())
297 return fn;
298 }
299 }
300 }
301 if (debug)
302 qDebug() << fileName << "not found";
303 return QString();
304}
305#endif
306
307/*!
308 \property QPluginLoader::fileName
309 \brief the file name of the plugin
310
311 We recommend omitting the file's suffix in the file name, since
312 QPluginLoader will automatically look for the file with the appropriate
313 suffix (see QLibrary::isLibrary()).
314
315 When loading the plugin, QPluginLoader searches
316 in all plugin locations specified by QCoreApplication::libraryPaths(),
317 unless the file name has an absolute path. After loading the plugin
318 successfully, fileName() returns the fully-qualified file name of
319 the plugin, including the full path to the plugin if one was given
320 in the constructor or passed to setFileName().
321
322 If the file name does not exist, it will not be set. This property
323 will then contain an empty string.
324
325 By default, this property contains an empty string.
326
327 \sa load()
328*/
329void QPluginLoader::setFileName(const QString &fileName)
330{
331#if defined(QT_SHARED)
332 QLibrary::LoadHints lh = QLibrary::PreventUnloadHint;
333 if (d) {
334 lh = d->loadHints();
335 d->release();
336 d = nullptr;
337 did_load = false;
338 }
339
340 const QString fn = locatePlugin(fileName);
341
342 d = QLibraryPrivate::findOrCreate(fn, QString(), lh);
343 if (!fn.isEmpty())
344 d->updatePluginState();
345
346#else
347 if (qt_debug_component()) {
348 qWarning("Cannot load %s into a statically linked Qt library.",
349 (const char *)QFile::encodeName(fileName));
350 }
351 Q_UNUSED(fileName);
352#endif
353}
354
355QString QPluginLoader::fileName() const
356{
357 if (d)
358 return d->fileName;
359 return QString();
360}
361
362/*!
363 \since 4.2
364
365 Returns a text string with the description of the last error that occurred.
366*/
367QString QPluginLoader::errorString() const
368{
369 return (!d || d->errorString.isEmpty()) ? tr("Unknown error") : d->errorString;
370}
371
372/*! \since 4.4
373
374 \property QPluginLoader::loadHints
375 \brief Give the load() function some hints on how it should behave.
376
377 You can give hints on how the symbols in the plugin are
378 resolved. By default since Qt 5.7, QLibrary::PreventUnloadHint is set.
379
380 See the documentation of QLibrary::loadHints for a complete
381 description of how this property works.
382
383 \sa QLibrary::loadHints
384*/
385
386void QPluginLoader::setLoadHints(QLibrary::LoadHints loadHints)
387{
388 if (!d) {
389 d = QLibraryPrivate::findOrCreate(QString()); // ugly, but we need a d-ptr
390 d->errorString.clear();
391 }
392 d->setLoadHints(loadHints);
393}
394
395QLibrary::LoadHints QPluginLoader::loadHints() const
396{
397 return d ? d->loadHints() : QLibrary::LoadHints();
398}
399
400#endif // QT_CONFIG(library)
401
402typedef QList<QStaticPlugin> StaticPluginList;
403Q_GLOBAL_STATIC(StaticPluginList, staticPluginList)
404
405/*!
406 \relates QPluginLoader
407 \since 5.0
408
409 Registers the \a plugin specified with the plugin loader, and is used
410 by Q_IMPORT_PLUGIN().
411*/
412void Q_CORE_EXPORT qRegisterStaticPluginFunction(QStaticPlugin plugin)
413{
414 staticPluginList()->append(plugin);
415}
416
417/*!
418 Returns a list of static plugin instances (root components) held
419 by the plugin loader.
420 \sa staticPlugins()
421*/
422QObjectList QPluginLoader::staticInstances()
423{
424 QObjectList instances;
425 const StaticPluginList *plugins = staticPluginList();
426 if (plugins) {
427 const int numPlugins = plugins->size();
428 instances.reserve(numPlugins);
429 for (int i = 0; i < numPlugins; ++i)
430 instances += plugins->at(i).instance();
431 }
432 return instances;
433}
434
435/*!
436 Returns a list of QStaticPlugins held by the plugin
437 loader. The function is similar to \l staticInstances()
438 with the addition that a QStaticPlugin also contains
439 meta data information.
440 \sa staticInstances()
441*/
442QList<QStaticPlugin> QPluginLoader::staticPlugins()
443{
444 StaticPluginList *plugins = staticPluginList();
445 if (plugins)
446 return *plugins;
447 return QList<QStaticPlugin>();
448}
449
450/*!
451 \class QStaticPlugin
452 \inmodule QtCore
453 \since 5.2
454
455 \brief QStaticPlugin is a struct containing a reference to a
456 static plugin instance together with its meta data.
457
458 \sa QPluginLoader, {How to Create Qt Plugins}
459*/
460
461/*!
462 \fn QStaticPlugin::QStaticPlugin(QtPluginInstanceFunction i, QtPluginMetaDataFunction m)
463 \internal
464*/
465
466/*!
467 \fn QObject *QStaticPlugin::instance()
468
469 Returns the plugin instance.
470
471 \sa QPluginLoader::staticInstances()
472*/
473
474/*!
475 Returns a the meta data for the plugin as a QJsonObject.
476
477 \sa Q_PLUGIN_METADATA()
478*/
479QJsonObject QStaticPlugin::metaData() const
480{
481 auto ptr = static_cast<const char *>(rawMetaData);
482
483 QString errMsg;
484 QJsonDocument doc = qJsonFromRawLibraryMetaData(ptr, rawMetaDataSize, &errMsg);
485 Q_ASSERT(doc.isObject());
486 Q_ASSERT(errMsg.isEmpty());
487 return doc.object();
488}
489
490QT_END_NAMESPACE
491
492#include "moc_qpluginloader.cpp"
493