Warning, /education/labplot/src/doc/plugins.dox is written in an unsupported language. File is not indexed.

0001 /**\page plugins Plugins
0002 
0003 
0004 \section Plugins based on Qt's plugin system
0005 
0006 This article is meant to explain the inner workings of the plugin system used in the backend to a degree where it completely loses any 'mystic aura'. 'Plugin system' may sound like something complicated, but it really isn't. All it takes is to know how to build and link libraries and to understand two macros (and to know how to use another two for implementing plugins).
0007 
0008 \section How do Qt plugins work?
0009 
0010 A Qt plugin is basically a library which uses a standardized way to access the so-called root component object, a normal C++ object which inherits from QObject. Once you have this root object, you use qobject_cast to check which of your predefined plugin interfaces it implements. See 'Q_DECLARE_INTERFACE' and 'Q_INTERFACES' in the Qt documentation for details. In short, these two macros register your interfaces (i.e., abstract C++ classes) to Qt's meta object system.
0011 
0012 Such a library can be statically or dynamically linked into the application.
0013 
0014 To understand how the plugin system works internally, one has to look at the involved macros defined in qplugin.h (to be found in /src/corelib/plugin in the official source archive):
0015 
0016 @code
0017 Q_EXPORT_PLUGIN2
0018 @endcode
0019 and
0020 @code
0021 Q_IMPORT_PLUGIN
0022 @endcode
0023 .
0024 
0025 These macros are different based on whether 'QT_STATICPLUGIN' is defined or not. Important to note here is that 'static plugin' does not mean statically linked but that there is a static (using the 'static' C++ keyword) object involved. Static plugins can also be linked as dynamic libraries. The difference to a dynamic plugin is that the application will not start if a static plugin is missing, it will run without dynamic plugins though. Since being optional is basically the whole point of plugins, static plugins are usually only used to unify the interface to mandatory and optional components.
0026 
0027 \section Declaring a plugin: Q_EXPORT_PLUGIN2
0028 
0029 The 'Q_EXPORT_PLUGIN2' macro is responsible for declaring the necessary code to access the plugin. It is defined in the code implementing the plugin.
0030 
0031 For static plugins the 'Q_EXPORT_PLUGIN2(PLUGIN, PLUGINCLASS)' macro expands to roughly this (somewhat simplified):
0032 @code
0033 QObject *qt_plugin_instance_PLUGIN()
0034 {
0035   static QPointer _instance;
0036   if (!_instance)
0037     _instance = new PLUGINCLASS;
0038   return _instance;
0039 }
0040 @endcode
0041 So, basically, you have a static instance of the root object and a function named using a standard prefix followed by the plugin name to get a pointer to this instance.
0042 BTW: In this case (i.e., with 'QT_STATICPLUGIN' defined), 'Q_EXPORT_STATIC_PLUGIN2(PLUGIN, PLUGINCLASS)' is exactly the same as 'Q_EXPORT_PLUGIN2(PLUGIN, PLUGINCLASS)'.
0043 
0044 For dynamic plugins, 'Q_EXPORT_PLUGIN2(PLUGIN, PLUGINCLASS)' expands to (also somewhat simplified):
0045 @code
0046 extern "C" {
0047   QObject * qt_plugin_instance();
0048   {
0049     static QPointer _instance;
0050     if (!_instance)
0051       _instance = new PLUGINCLASS;
0052     return _instance;
0053   }
0054 }
0055 @endcode
0056 So it boils down to defining the root object access function as 'extern 'C''. In addition, a function called 'qt_plugin_query_verification_data()' is defined which is used to check whether the plugin is compatible with the application its loaded in (same Qt version etc.).
0057 BTW: 'Q_EXPORT_STATIC_PLUGIN2(PLUGIN, PLUGINCLASS)' does nothing if 'QT_STATICPLUGIN' is not defined.
0058 
0059 \section Using static plugins: Q_IMPORT_PLUGIN
0060 
0061 The 'Q_IMPORT_PLUGIN(PLUGIN)' macro, which is used in the code using the static plugin, expands to the following:
0062 @code
0063 extern QObject *qt_plugin_instance_##PLUGIN();
0064 class Static##PLUGIN##PluginInstance {
0065   public:
0066     Static##PLUGIN##PluginInstance() {
0067     qRegisterStaticPluginInstanceFunction(qt_plugin_instance_##PLUGIN);
0068   }
0069 };
0070 static Static##PLUGIN##PluginInstance static##PLUGIN##Instance;
0071 @endcode
0072 This is the static object I was talking about at the beginning. It is created during the static initialization of the application and registers the plugin root object access function to a global list. This list is used by 'static QObjectList QPluginLoader::staticInstances()' which returns all plugin root component objects.
0073 
0074 The simplest way to make your static plugin available via 'QPluginLoader::staticInstances()' therefore is:
0075 @code
0076 #define QT_STATICPLUGIN
0077 Q_EXPORT_PLUGIN2(scidavis_standardcurvesymbolfactory, StandardCurveSymbolFactory)
0078 Q_IMPORT_PLUGIN(scidavis_standardcurvesymbolfactory)
0079 @endcode
0080 Together with 'Q_DECLARE_INTERFACE' and 'Q_INTERFACES' that's all it takes to define a static plugin.
0081 
0082 \section Using dynamic plugins: QPluginLoader/PluginManager
0083 
0084 As mentioned above, static plugins must be present for the application to run. They are completely normal library dependencies of the executable. Dynamic plugins are what plugins really should be: optional functionality which can be added at runtime. They are always compiled as dynamic libraries and then loaded at runtime by 'QPluginLoader' (no 'Q_IMPORT_PLUGIN' involved here). 'QPluginLoader' is well documented in the Qt docs, so I won't go into detail here, there is no need to know it anyway, neither when writing plugins nor building the application.
0085 
0086 There exists a class called 'PluginManager' in the backend which encapsulates the whole usage of 'QPluginLoader'. All you need to do is call 'PluginManager::plugins()' which works like 'QPluginLoader::staticInstances()' but also includes all dynamically loaded plugins. You can enable and disable plugins permanently (or at least until someone deletes the application config file because QSettings are used to store the list of enabled plugins) by calling 'PluginManager::enablePlugin()' or 'PluginManager::disablePlugin()', respectively.
0087 
0088 
0089 */