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 
51 QT_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     \class QStaticPlugin
110     \inmodule QtCore
111     \since 5.2
112 
113     \brief QStaticPlugin is a struct containing a reference to a
114     static plugin instance together with its meta data.
115 
116     \sa QPluginLoader, {How to Create Qt Plugins}
117 */
118 
119 /*!
120     \fn QObject *QStaticPlugin::instance()
121 
122     Returns the plugin instance.
123 
124     \sa QPluginLoader::staticInstances()
125 */
126 
127 /*!
128     \fn const char *QStaticPlugin::rawMetaData()
129 
130     Returns the raw meta data for the plugin.
131 
132     \sa metaData(), Q_PLUGIN_METADATA()
133 */
134 
135 /*!
136     Constructs a plugin loader with the given \a parent.
137 */
QPluginLoader(QObject * parent)138 QPluginLoader::QPluginLoader(QObject *parent)
139     : QObject(parent), d(nullptr), did_load(false)
140 {
141 }
142 
143 /*!
144     Constructs a plugin loader with the given \a parent that will
145     load the plugin specified by \a fileName.
146 
147     To be loadable, the file's suffix must be a valid suffix for a
148     loadable library in accordance with the platform, e.g. \c .so on
149     Unix, - \c .dylib on \macos and iOS, and \c .dll on Windows. The suffix
150     can be verified with QLibrary::isLibrary().
151 
152     \sa setFileName()
153 */
QPluginLoader(const QString & fileName,QObject * parent)154 QPluginLoader::QPluginLoader(const QString &fileName, QObject *parent)
155     : QObject(parent), d(nullptr), did_load(false)
156 {
157     setFileName(fileName);
158     setLoadHints(QLibrary::PreventUnloadHint);
159 }
160 
161 /*!
162     Destroys the QPluginLoader object.
163 
164     Unless unload() was called explicitly, the plugin stays in memory
165     until the application terminates.
166 
167     \sa isLoaded(), unload()
168 */
~QPluginLoader()169 QPluginLoader::~QPluginLoader()
170 {
171     if (d)
172         d->release();
173 }
174 
175 /*!
176     Returns the root component object of the plugin. The plugin is
177     loaded if necessary. The function returns \nullptr if the plugin could
178     not be loaded or if the root component object could not be
179     instantiated.
180 
181     If the root component object was destroyed, calling this function
182     creates a new instance.
183 
184     The root component, returned by this function, is not deleted when
185     the QPluginLoader is destroyed. If you want to ensure that the root
186     component is deleted, you should call unload() as soon you don't
187     need to access the core component anymore.  When the library is
188     finally unloaded, the root component will automatically be deleted.
189 
190     The component object is a QObject. Use qobject_cast() to access
191     interfaces you are interested in.
192 
193     \sa load()
194 */
instance()195 QObject *QPluginLoader::instance()
196 {
197     if (!isLoaded() && !load())
198         return nullptr;
199     return d->pluginInstance();
200 }
201 
202 /*!
203     Returns the meta data for this plugin. The meta data is data specified
204     in a json format using the Q_PLUGIN_METADATA() macro when compiling
205     the plugin.
206 
207     The meta data can be queried in a fast and inexpensive way without
208     actually loading the plugin. This makes it possible to e.g. store
209     capabilities of the plugin in there, and make the decision whether to
210     load the plugin dependent on this meta data.
211  */
metaData() const212 QJsonObject QPluginLoader::metaData() const
213 {
214     if (!d)
215         return QJsonObject();
216     return d->metaData;
217 }
218 
219 /*!
220     Loads the plugin and returns \c true if the plugin was loaded
221     successfully; otherwise returns \c false. Since instance() always
222     calls this function before resolving any symbols it is not
223     necessary to call it explicitly. In some situations you might want
224     the plugin loaded in advance, in which case you would use this
225     function.
226 
227     \sa unload()
228 */
load()229 bool QPluginLoader::load()
230 {
231     if (!d || d->fileName.isEmpty())
232         return false;
233     if (did_load)
234         return d->pHnd && d->instanceFactory.loadAcquire();
235     if (!d->isPlugin())
236         return false;
237     did_load = true;
238     return d->loadPlugin();
239 }
240 
241 
242 /*!
243     Unloads the plugin and returns \c true if the plugin could be
244     unloaded; otherwise returns \c false.
245 
246     This happens automatically on application termination, so you
247     shouldn't normally need to call this function.
248 
249     If other instances of QPluginLoader are using the same plugin, the
250     call will fail, and unloading will only happen when every instance
251     has called unload().
252 
253     Don't try to delete the root component. Instead rely on
254     that unload() will automatically delete it when needed.
255 
256     \sa instance(), load()
257 */
unload()258 bool QPluginLoader::unload()
259 {
260     if (did_load) {
261         did_load = false;
262         return d->unload();
263     }
264     if (d)  // Ouch
265         d->errorString = tr("The plugin was not loaded.");
266     return false;
267 }
268 
269 /*!
270     Returns \c true if the plugin is loaded; otherwise returns \c false.
271 
272     \sa load()
273  */
isLoaded() const274 bool QPluginLoader::isLoaded() const
275 {
276     return d && d->pHnd && d->instanceFactory.loadRelaxed();
277 }
278 
279 #if defined(QT_SHARED)
locatePlugin(const QString & fileName)280 static QString locatePlugin(const QString& fileName)
281 {
282     const bool isAbsolute = QDir::isAbsolutePath(fileName);
283     if (isAbsolute) {
284         QFileInfo fi(fileName);
285         if (fi.isFile()) {
286             return fi.canonicalFilePath();
287         }
288     }
289     QStringList prefixes = QLibraryPrivate::prefixes_sys();
290     prefixes.prepend(QString());
291     QStringList suffixes = QLibraryPrivate::suffixes_sys(QString());
292     suffixes.prepend(QString());
293 
294     // Split up "subdir/filename"
295     const int slash = fileName.lastIndexOf(QLatin1Char('/'));
296     const QStringRef baseName = fileName.midRef(slash + 1);
297     const QStringRef basePath = isAbsolute ? QStringRef() : fileName.leftRef(slash + 1); // keep the '/'
298 
299     const bool debug = qt_debug_component();
300 
301     QStringList paths;
302     if (isAbsolute) {
303         paths.append(fileName.left(slash)); // don't include the '/'
304     } else {
305         paths = QCoreApplication::libraryPaths();
306     }
307 
308     for (const QString &path : qAsConst(paths)) {
309         for (const QString &prefix : qAsConst(prefixes)) {
310             for (const QString &suffix : qAsConst(suffixes)) {
311 #ifdef Q_OS_ANDROID
312                 {
313                     QString pluginPath = basePath + prefix + baseName + suffix;
314                     const QString fn = path + QLatin1String("/lib") + pluginPath.replace(QLatin1Char('/'), QLatin1Char('_'));
315                     if (debug)
316                         qDebug() << "Trying..." << fn;
317                     if (QFileInfo(fn).isFile())
318                         return fn;
319                 }
320 #endif
321                 const QString fn = path + QLatin1Char('/') + basePath + prefix + baseName + suffix;
322                 if (debug)
323                     qDebug() << "Trying..." << fn;
324                 if (QFileInfo(fn).isFile())
325                     return fn;
326             }
327         }
328     }
329     if (debug)
330         qDebug() << fileName << "not found";
331     return QString();
332 }
333 #endif
334 
335 /*!
336     \property QPluginLoader::fileName
337     \brief the file name of the plugin
338 
339     We recommend omitting the file's suffix in the file name, since
340     QPluginLoader will automatically look for the file with the appropriate
341     suffix (see QLibrary::isLibrary()).
342 
343     When loading the plugin, QPluginLoader searches
344     in all plugin locations specified by QCoreApplication::libraryPaths(),
345     unless the file name has an absolute path. After loading the plugin
346     successfully, fileName() returns the fully-qualified file name of
347     the plugin, including the full path to the plugin if one was given
348     in the constructor or passed to setFileName().
349 
350     If the file name does not exist, it will not be set. This property
351     will then contain an empty string.
352 
353     By default, this property contains an empty string.
354 
355     \sa load()
356 */
setFileName(const QString & fileName)357 void QPluginLoader::setFileName(const QString &fileName)
358 {
359 #if defined(QT_SHARED)
360     QLibrary::LoadHints lh = QLibrary::PreventUnloadHint;
361     if (d) {
362         lh = d->loadHints();
363         d->release();
364         d = nullptr;
365         did_load = false;
366     }
367 
368     const QString fn = locatePlugin(fileName);
369 
370     d = QLibraryPrivate::findOrCreate(fn, QString(), lh);
371     if (!fn.isEmpty())
372         d->updatePluginState();
373 
374 #else
375     if (qt_debug_component()) {
376         qWarning("Cannot load %s into a statically linked Qt library.",
377             (const char*)QFile::encodeName(fileName));
378     }
379     Q_UNUSED(fileName);
380 #endif
381 }
382 
fileName() const383 QString QPluginLoader::fileName() const
384 {
385     if (d)
386         return d->fileName;
387     return QString();
388 }
389 
390 /*!
391     \since 4.2
392 
393     Returns a text string with the description of the last error that occurred.
394 */
errorString() const395 QString QPluginLoader::errorString() const
396 {
397     return (!d || d->errorString.isEmpty()) ? tr("Unknown error") : d->errorString;
398 }
399 
400 /*! \since 4.4
401 
402     \property QPluginLoader::loadHints
403     \brief Give the load() function some hints on how it should behave.
404 
405     You can give hints on how the symbols in the plugin are
406     resolved. By default since Qt 5.7, QLibrary::PreventUnloadHint is set.
407 
408     See the documentation of QLibrary::loadHints for a complete
409     description of how this property works.
410 
411     \sa QLibrary::loadHints
412 */
413 
setLoadHints(QLibrary::LoadHints loadHints)414 void QPluginLoader::setLoadHints(QLibrary::LoadHints loadHints)
415 {
416     if (!d) {
417         d = QLibraryPrivate::findOrCreate(QString());   // ugly, but we need a d-ptr
418         d->errorString.clear();
419     }
420     d->setLoadHints(loadHints);
421 }
422 
loadHints() const423 QLibrary::LoadHints QPluginLoader::loadHints() const
424 {
425     return d ? d->loadHints() : QLibrary::LoadHints();
426 }
427 
428 #endif // QT_CONFIG(library)
429 
430 typedef QVector<QStaticPlugin> StaticPluginList;
Q_GLOBAL_STATIC(StaticPluginList,staticPluginList)431 Q_GLOBAL_STATIC(StaticPluginList, staticPluginList)
432 
433 /*!
434     \relates QPluginLoader
435     \since 5.0
436 
437     Registers the \a plugin specified with the plugin loader, and is used
438     by Q_IMPORT_PLUGIN().
439 */
440 void Q_CORE_EXPORT qRegisterStaticPluginFunction(QStaticPlugin plugin)
441 {
442     staticPluginList()->append(plugin);
443 }
444 
445 /*!
446     Returns a list of static plugin instances (root components) held
447     by the plugin loader.
448     \sa staticPlugins()
449 */
staticInstances()450 QObjectList QPluginLoader::staticInstances()
451 {
452     QObjectList instances;
453     const StaticPluginList *plugins = staticPluginList();
454     if (plugins) {
455         const int numPlugins = plugins->size();
456         instances.reserve(numPlugins);
457         for (int i = 0; i < numPlugins; ++i)
458             instances += plugins->at(i).instance();
459     }
460     return instances;
461 }
462 
463 /*!
464     Returns a list of QStaticPlugins held by the plugin
465     loader. The function is similar to \l staticInstances()
466     with the addition that a QStaticPlugin also contains
467     meta data information.
468     \sa staticInstances()
469 */
staticPlugins()470 QVector<QStaticPlugin> QPluginLoader::staticPlugins()
471 {
472     StaticPluginList *plugins = staticPluginList();
473     if (plugins)
474         return *plugins;
475     return QVector<QStaticPlugin>();
476 }
477 
478 /*!
479     Returns a the meta data for the plugin as a QJsonObject.
480 
481     \sa rawMetaData()
482 */
metaData() const483 QJsonObject QStaticPlugin::metaData() const
484 {
485 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
486     // the data is already loaded, so this doesn't matter
487     qsizetype rawMetaDataSize = INT_MAX;
488     const char *ptr = rawMetaData();
489 #else
490     auto ptr = static_cast<const char *>(rawMetaData);
491 #endif
492 
493     QString errMsg;
494     QJsonDocument doc = qJsonFromRawLibraryMetaData(ptr, rawMetaDataSize, &errMsg);
495     Q_ASSERT(doc.isObject());
496     Q_ASSERT(errMsg.isEmpty());
497     return doc.object();
498 }
499 
500 QT_END_NAMESPACE
501 
502 #include "moc_qpluginloader.cpp"
503