1 #ifndef Corrade_PluginManager_AbstractManager_h
2 #define Corrade_PluginManager_AbstractManager_h
3 /*
4     This file is part of Corrade.
5 
6     Copyright © 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016,
7                 2017, 2018, 2019, 2020 Vladimír Vondruš <mosra@centrum.cz>
8 
9     Permission is hereby granted, free of charge, to any person obtaining a
10     copy of this software and associated documentation files (the "Software"),
11     to deal in the Software without restriction, including without limitation
12     the rights to use, copy, modify, merge, publish, distribute, sublicense,
13     and/or sell copies of the Software, and to permit persons to whom the
14     Software is furnished to do so, subject to the following conditions:
15 
16     The above copyright notice and this permission notice shall be included
17     in all copies or substantial portions of the Software.
18 
19     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20     IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21     FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
22     THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23     LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
24     FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
25     DEALINGS IN THE SOFTWARE.
26 */
27 
28 /** @file
29  * @brief Class @ref Corrade::PluginManager::AbstractManager, macro @ref CORRADE_PLUGIN_VERSION, @ref CORRADE_PLUGIN_REGISTER()
30  */
31 
32 #include "Corrade/Containers/EnumSet.h"
33 #include "Corrade/Containers/Pointer.h"
34 #include "Corrade/PluginManager/PluginManager.h"
35 #include "Corrade/PluginManager/visibility.h"
36 #include "Corrade/Utility/StlForwardString.h"
37 #include "Corrade/Utility/StlForwardVector.h"
38 #include "Corrade/Utility/Utility.h"
39 
40 #ifdef CORRADE_TARGET_WINDOWS
41 /* I didn't find a better way to circumvent the need for including windows.h */
42 struct HINSTANCE__;
43 typedef struct HINSTANCE__* HMODULE;
44 
45 /* combaseapi.h in Windows does this insane thing. Can be worked around by
46    defining WIN32_LEAN_AND_MEAN but not everybody does that. */
47 #ifdef interface
48 #undef interface
49 #endif
50 #endif
51 
52 namespace Corrade { namespace PluginManager {
53 
54 /**
55 @brief Plugin load state
56 
57 @see @ref LoadStates, @ref AbstractManager::loadState(),
58     @ref AbstractManager::load(), @ref AbstractManager::unload()
59 */
60 enum class LoadState: unsigned short {
61     /**
62      * The plugin cannot be found. Returned by @ref AbstractManager::loadState()
63      * and @ref AbstractManager::load().
64      */
65     NotFound = 1 << 0,
66 
67     #ifndef CORRADE_PLUGINMANAGER_NO_DYNAMIC_PLUGIN_SUPPORT
68     /**
69      * The plugin is build with different version of plugin manager and cannot
70      * be loaded. Returned by @ref AbstractManager::load().
71      * @partialsupport Not available on platforms without
72      *      @ref CORRADE_PLUGINMANAGER_NO_DYNAMIC_PLUGIN_SUPPORT "dynamic plugin support".
73      */
74     WrongPluginVersion = 1 << 1,
75 
76     /**
77      * The plugin uses different interface than the interface used by plugin
78      * manager and cannot be loaded. Returned by @ref AbstractManager::load().
79      * @partialsupport Not available on platforms without
80      *      @ref CORRADE_PLUGINMANAGER_NO_DYNAMIC_PLUGIN_SUPPORT "dynamic plugin support".
81      */
82     WrongInterfaceVersion = 1 << 2,
83 
84     /**
85      * The plugin doesn't have any associated `*.conf` metadata file or the
86      * metadata file contains errors. Returned by
87      * @ref AbstractManager::loadState() and @ref AbstractManager::load().
88      * @partialsupport Not available on platforms without
89      *      @ref CORRADE_PLUGINMANAGER_NO_DYNAMIC_PLUGIN_SUPPORT "dynamic plugin support".
90      */
91     WrongMetadataFile = 1 << 3,
92 
93     /**
94      * The plugin depends on another plugin, which cannot be loaded (e.g. not
95      * found or wrong version). Returned by @ref AbstractManager::load(). Note
96      * that plugins may have cross-manager dependencies, and to resolve these
97      * you need to explicitly pass a manager instance containing the
98      * dependencies to @ref AbstractManager::registerExternalManager().
99      * @partialsupport Not available on platforms without
100      *      @ref CORRADE_PLUGINMANAGER_NO_DYNAMIC_PLUGIN_SUPPORT "dynamic plugin support".
101      */
102     UnresolvedDependency = 1 << 4,
103 
104     /**
105      * The plugin failed to load for other reason (e.g. linking failure).
106      * Returned by @ref AbstractManager::load().
107      * @partialsupport Not available on platforms without
108      *      @ref CORRADE_PLUGINMANAGER_NO_DYNAMIC_PLUGIN_SUPPORT "dynamic plugin support".
109      */
110     LoadFailed = 1 << 5,
111     #endif
112 
113     /**
114      * The plugin is static. Returned by @ref AbstractManager::loadState() and
115      * @ref AbstractManager::load().
116      */
117     Static = 1 << 6,
118 
119     /**
120      * The plugin is successfully loaded. Returned by @ref AbstractManager::loadState()
121      * and @ref AbstractManager::load(). The value includes value of @ref LoadState::Static,
122      * see @ref LoadStates for more information. In @ref CORRADE_TARGET_EMSCRIPTEN "Emscripten",
123      * @ref CORRADE_TARGET_WINDOWS_RT "Windows RT", @ref CORRADE_TARGET_IOS "iOS"
124      * and @ref CORRADE_TARGET_ANDROID the value is equivalent to
125      * @ref LoadState::Static.
126      */
127     #ifndef CORRADE_PLUGINMANAGER_NO_DYNAMIC_PLUGIN_SUPPORT
128     Loaded = (1 << 7) | LoadState::Static,
129     #else
130     Loaded = LoadState::Static,
131     #endif
132 
133     #ifndef CORRADE_PLUGINMANAGER_NO_DYNAMIC_PLUGIN_SUPPORT
134     /**
135      * The plugin is not loaded. Plugin can be unloaded only if is dynamic and
136      * is not required by any other plugin. Returned by
137      * @ref AbstractManager::loadState() and @ref AbstractManager::load().
138      * @partialsupport Not available on platforms without
139      *      @ref CORRADE_PLUGINMANAGER_NO_DYNAMIC_PLUGIN_SUPPORT "dynamic plugin support".
140      */
141     NotLoaded = 1 << 8,
142 
143     /**
144      * The plugin failed to unload. Returned by @ref AbstractManager::unload().
145      * @partialsupport Not available on platforms without
146      *      @ref CORRADE_PLUGINMANAGER_NO_DYNAMIC_PLUGIN_SUPPORT "dynamic plugin support".
147      */
148     UnloadFailed = 1 << 9,
149 
150     /**
151      * The plugin cannot be unloaded because another plugin is depending on it.
152      * Unload that plugin first and try again. Returned by @ref AbstractManager::unload().
153      * @partialsupport Not available on platforms without
154      *      @ref CORRADE_PLUGINMANAGER_NO_DYNAMIC_PLUGIN_SUPPORT "dynamic plugin support".
155      */
156     Required = 1 << 10,
157 
158     /**
159      * @ref AbstractManager::unload() returns this if the plugin has an active
160      * instance and cannot be unloaded. Destroy all instances and try again.
161      * @ref AbstractManager::load() returns this if loading a file path
162      * directly and a plugin with the same name already exists.
163      * @partialsupport Not available on platforms without
164      *      @ref CORRADE_PLUGINMANAGER_NO_DYNAMIC_PLUGIN_SUPPORT "dynamic plugin support".
165      */
166     Used = 1 << 11
167     #endif
168 };
169 
170 /** @debugoperatorenum{LoadState} */
171 CORRADE_PLUGINMANAGER_EXPORT Utility::Debug& operator<<(Utility::Debug& debug, PluginManager::LoadState value);
172 
173 /**
174 @brief Plugin load states
175 
176 Useful when checking whether @ref LoadState in in given set of values, for
177 example:
178 
179 @snippet PluginManager.cpp LoadStates
180 
181 Note that @ref LoadState::Loaded includes the value of @ref LoadState::Static,
182 so you can use @cpp loadState & PluginManager::LoadState::Loaded @ce instead of
183 much more verbose
184 @cpp loadState & (PluginManager::LoadState::Loaded|PluginManager::LoadState::Static) @ce.
185 @see @ref AbstractManager::loadState(), @ref AbstractManager::load(),
186     @ref AbstractManager::unload()
187 */
188 typedef Containers::EnumSet<LoadState> LoadStates;
189 
190 CORRADE_ENUMSET_OPERATORS(LoadStates)
191 
192 /** @debugoperatorenum{LoadStates} */
193 CORRADE_PLUGINMANAGER_EXPORT Utility::Debug& operator<<(Utility::Debug& debug, PluginManager::LoadStates value);
194 
195 namespace Implementation {
196     struct StaticPlugin;
197 }
198 
199 /**
200 @brief Base for plugin managers
201 
202 See @ref Manager and @ref plugin-management for more information.
203  */
204 class CORRADE_PLUGINMANAGER_EXPORT AbstractManager {
205     friend AbstractPlugin;
206 
207     public:
208         /** @brief Plugin version */
209         static const int Version;
210 
211         /** @brief Copying is not allowed */
212         AbstractManager(const AbstractManager&) = delete;
213 
214         /** @brief Moving is not allowed */
215         AbstractManager(AbstractManager&&) = delete;
216 
217         /** @brief Copying is not allowed */
218         AbstractManager& operator=(const AbstractManager&) = delete;
219 
220         /** @brief Moving is not allowed */
221         AbstractManager& operator=(AbstractManager&&) = delete;
222 
223         /**
224          * @brief Plugin interface
225          *
226          * Only plugins with the same plugin interface string can be used
227          * in this plugin manager.
228          */
229         std::string pluginInterface() const;
230 
231         #ifndef CORRADE_PLUGINMANAGER_NO_DYNAMIC_PLUGIN_SUPPORT
232         /**
233          * @brief Plugin directory
234          *
235          * @partialsupport Not available on platforms without
236          *      @ref CORRADE_PLUGINMANAGER_NO_DYNAMIC_PLUGIN_SUPPORT "dynamic plugin support".
237          */
238         std::string pluginDirectory() const;
239 
240         /**
241          * @brief Set another plugin directory
242          *
243          * Keeps loaded plugins untouched, removes unloaded plugins which are
244          * not existing anymore and adds newly found plugins. The directory is
245          * expected to be in UTF-8.
246          * @partialsupport Not available on platforms without
247          *      @ref CORRADE_PLUGINMANAGER_NO_DYNAMIC_PLUGIN_SUPPORT "dynamic plugin support".
248          */
249         void setPluginDirectory(std::string directory);
250 
251         /**
252          * @brief Reload plugin directory
253          *
254          * Convenience equivalent to @cpp setPluginDirectory(pluginDirectory()) @ce.
255          * @partialsupport Not available on platforms without
256          *      @ref CORRADE_PLUGINMANAGER_NO_DYNAMIC_PLUGIN_SUPPORT "dynamic plugin support".
257          */
258         void reloadPluginDirectory();
259         #endif
260 
261         /**
262          * @brief Set preferred plugins for given alias
263          *
264          * By default, if more than one plugin provides given @p alias, one of
265          * them is arbitrarily chosen. With this function it's possible to
266          * control the behavior. For given @p alias the function goes through
267          * the list in @p plugins and uses the first plugin that is available.
268          * The @p alias is expected to exist and be defined by plugins in
269          * @p plugins. If none of @p plugins is available, nothing is done.
270          *
271          * Note that after calling @ref setPluginDirectory() or @ref reloadPluginDirectory()
272          * this preference gets reset and you may need to call this function
273          * again.
274          */
275         void setPreferredPlugins(const std::string& alias, std::initializer_list<std::string> plugins);
276 
277         /**
278          * @brief List of all available plugin names
279          *
280          * Returns a list of names that correspond to concrete unique static or
281          * dynamic plugins.
282          * @see @ref aliasList()
283          */
284         std::vector<std::string> pluginList() const;
285 
286         /**
287          * @brief List of all available alias names
288          *
289          * In addition to everything returned by @ref pluginList() contains
290          * also all plugin aliases.
291          */
292         std::vector<std::string> aliasList() const;
293 
294         /**
295          * @brief Plugin metadata
296          *
297          * Returns pointer to plugin metadata or @cpp nullptr @ce, if given
298          * plugin is not found.
299          * @see @ref AbstractPlugin::metadata()
300          */
301         PluginMetadata* metadata(const std::string& plugin);
302         const PluginMetadata* metadata(const std::string& plugin) const; /**< @overload */
303 
304         /**
305          * @brief Load state of a plugin
306          *
307          * Returns @ref LoadState::Loaded if the plugin is loaded or
308          * @ref LoadState::NotLoaded if not. For static plugins returns always
309          * @ref LoadState::Static. On failure returns @ref LoadState::NotFound
310          * or @ref LoadState::WrongMetadataFile.
311          * @see @ref load(), @ref unload()
312          */
313         LoadState loadState(const std::string& plugin) const;
314 
315         /**
316          * @brief Load a plugin
317          *
318          * Returns @ref LoadState::Loaded if the plugin is already loaded or if
319          * loading succeeded. For static plugins returns always
320          * @ref LoadState::Static. On failure returns @ref LoadState::NotFound,
321          * @ref LoadState::WrongPluginVersion,
322          * @ref LoadState::WrongInterfaceVersion,
323          * @ref LoadState::UnresolvedDependency or @ref LoadState::LoadFailed.
324          *
325          * If the plugin has any dependencies, they are recursively processed
326          * before loading given plugin.
327          *
328          * If @p plugin is a plugin file path (i.e., ending with a
329          * platform-specific extension such as `.so` or `.dll`), it's loaded
330          * from given location and, if the loading succeeds, its basename
331          * (without extension) is exposed as an available plugin name. It's
332          * expected that a plugin with the same name is not already loaded. The
333          * plugin will reside in the plugin list as long as it's loaded or,
334          * after calling @ref unload() on it, until next call to
335          * @ref setPluginDirectory() or @ref reloadPluginDirectory().
336          *
337          * @note If passing a file path, the implementation expects forward
338          *      slashes as directory separators. Use @ref Utility::Directory::fromNativeSeparators()
339          *      to convert from platform-specific format.
340          *
341          * @see @ref unload(), @ref loadState(), @ref Manager::instantiate(),
342          *      @ref Manager::loadAndInstantiate()
343          * @partialsupport On platforms without
344          *      @ref CORRADE_PLUGINMANAGER_NO_DYNAMIC_PLUGIN_SUPPORT "dynamic plugin support"
345          *      returns always either @ref LoadState::Static or
346          *      @ref LoadState::NotFound.
347          */
348         LoadState load(const std::string& plugin);
349 
350         /**
351          * @brief Unload a plugin
352          *
353          * Returns @ref LoadState::NotLoaded if the plugin is not loaded or
354          * unloading succeeded. For static plugins always returns
355          * @ref LoadState::Static. On failure returns @ref LoadState::NotFound,
356          * @ref LoadState::UnloadFailed, @ref LoadState::Required or
357          * @ref LoadState::Used.
358          *
359          * @see @ref load(), @ref loadState()
360          * @partialsupport On platforms without
361          *      @ref CORRADE_PLUGINMANAGER_NO_DYNAMIC_PLUGIN_SUPPORT "dynamic plugin support"
362          *      returns always either @ref LoadState::Static or
363          *      @ref LoadState::NotFound.
364          */
365         LoadState unload(const std::string& plugin);
366 
367         /**
368          * @brief Register an external manager for resolving inter-manager dependencies
369          * @m_since{2020,06}
370          *
371          * To be used for loading dependencies from different plugin
372          * interfaces. Once registered, the @p manager is expected to stay in
373          * scope for the whole lifetime of this instance.
374          */
375         void registerExternalManager(AbstractManager& manager);
376 
377     protected:
378         /**
379          * @brief Destructor
380          *
381          * Destroys all plugin instances and unloads all plugins.
382          */
383         /* Nobody will need to have (and delete) AbstractManager*, thus this is
384            faster than public virtual destructor */
385         ~AbstractManager();
386 
387     #ifdef DOXYGEN_GENERATING_OUTPUT
388     private:
389     #else
390     public:
391     #endif
392         struct CORRADE_PLUGINMANAGER_LOCAL Plugin;
393         typedef void* (*Instancer)(AbstractManager&, const std::string&);
394         static void importStaticPlugin(int version, Implementation::StaticPlugin& plugin);
395         static void ejectStaticPlugin(int version, Implementation::StaticPlugin& plugin);
396 
397     #ifdef DOXYGEN_GENERATING_OUTPUT
398     private:
399     #else
400     protected:
401     #endif
402         #ifndef CORRADE_PLUGINMANAGER_NO_DYNAMIC_PLUGIN_SUPPORT
403         explicit AbstractManager(std::string pluginInterface, const std::vector<std::string>& pluginSearchPaths, std::string pluginSuffix, std::string pluginConfSuffix, std::string pluginDirectory);
404         #else
405         explicit AbstractManager(std::string pluginInterface, std::string pluginConfSuffix);
406         #endif
407 
408         Containers::Pointer<AbstractPlugin> instantiateInternal(const std::string& plugin);
409         Containers::Pointer<AbstractPlugin> loadAndInstantiateInternal(const std::string& plugin);
410 
411     private:
412         struct State;
413 
414         CORRADE_PLUGINMANAGER_LOCAL void registerDynamicPlugin(const std::string& name, Containers::Pointer<Plugin>&& plugin);
415 
416         CORRADE_PLUGINMANAGER_LOCAL void registerInstance(const std::string& plugin, AbstractPlugin& instance, const PluginMetadata*& metadata);
417         CORRADE_PLUGINMANAGER_LOCAL void reregisterInstance(const std::string& plugin, AbstractPlugin& oldInstance, AbstractPlugin* newInstance);
418 
419         #ifndef CORRADE_PLUGINMANAGER_NO_DYNAMIC_PLUGIN_SUPPORT
420         CORRADE_PLUGINMANAGER_LOCAL LoadState loadInternal(Plugin& plugin);
421         CORRADE_PLUGINMANAGER_LOCAL LoadState loadInternal(Plugin& plugin, const std::string& filename);
422         CORRADE_PLUGINMANAGER_LOCAL LoadState unloadInternal(Plugin& plugin);
423         CORRADE_PLUGINMANAGER_LOCAL LoadState unloadRecursiveInternal(Plugin& plugin);
424         #endif
425 
426         Containers::Pointer<State> _state;
427 };
428 
429 namespace Implementation {
430 
431 struct StaticPlugin {
432     /* Assuming both plugin and interface are static strings produced by the
433        CORRADE_PLUGIN_REGISTER() macro, so there's no need to make an allocated
434        copy of them, just a direct reference */
435     const char* plugin;
436     const char* interface;
437     AbstractManager::Instancer instancer;
438     void(*initializer)();
439     void(*finalizer)();
440     /* This field shouldn't be written to by anything else than
441        importStaticPlugin() / ejectStaticPlugin(). It's zero-initilized by
442        default and those use it to avoid inserting a single item to the linked
443        list more than once. */
444     StaticPlugin* next;
445 };
446 
447 }
448 
449 /** @hideinitializer
450 @brief Import a static plugin
451 @param name      Static plugin name (the same as defined with
452     @ref CORRADE_PLUGIN_REGISTER())
453 
454 If you link static plugins to your executable, they can't automatically
455 register themselves at startup to be known to
456 @ref Corrade::PluginManager::Manager "PluginManager::Manager", and you need to
457 load them explicitly by calling @ref CORRADE_PLUGIN_IMPORT() at the beginning
458 of the @cpp main() @ce function. You can also wrap these macro calls in another
459 function (which will then be compiled into a dynamic library or the main
460 executable) and use the @ref CORRADE_AUTOMATIC_INITIALIZER() macro for an
461 automatic call:
462 
463 @snippet PluginManager.cpp CORRADE_PLUGIN_IMPORT
464 
465 @attention This macro should be called outside of any namespace. If you are
466     running into linker errors with `pluginImporter_*`, this could be the
467     reason. See @ref CORRADE_RESOURCE_INITIALIZE() documentation for more
468     information.
469 
470 Functions called by this macro don't do any dynamic allocation or other
471 operations that could fail, so it's safe to call it even in restricted phases
472 of application exection. It's also safe to call this macro more than once.
473 
474 @see @ref CORRADE_PLUGIN_EJECT()
475 */
476 /* This "bundles" CORRADE_RESOURCE_INITIALIZE() in itself. Keep in sync. */
477 #define CORRADE_PLUGIN_IMPORT(name)                                         \
478     extern int pluginImporter_##name();                                     \
479     extern int resourceInitializer_##name();                                \
480     pluginImporter_##name();                                                \
481     resourceInitializer_##name();
482 
483 /** @hideinitializer
484 @brief Eject a previously imported static plugin
485 @param name      Static plugin name (the same as defined with
486     @ref CORRADE_PLUGIN_REGISTER())
487 @m_since{2019,10}
488 
489 Deregisters a plugin previously registered using @ref CORRADE_PLUGIN_IMPORT().
490 
491 @attention This macro should be called outside of any namespace. See the
492     @ref CORRADE_RESOURCE_INITIALIZE() macro for more information.
493 
494 Functions called by this macro don't do any dynamic allocation or other
495 operations that could fail, so it's safe to call it even in restricted phases
496 of application exection. It's also safe to call this macro more than once.
497 */
498 /* This "bundles" CORRADE_RESOURCE_FINALIZE() in itself. Keep in sync. */
499 #define CORRADE_PLUGIN_EJECT(name)                                          \
500     extern int pluginEjector_##name();                                      \
501     extern int resourceFinalizer_##name();                                  \
502     pluginEjector_##name();                                                 \
503     resourceFinalizer_##name();
504 
505 /** @brief Plugin version */
506 #define CORRADE_PLUGIN_VERSION 6
507 
508 /** @hideinitializer
509 @brief Register a static or dynamic plugin
510 @param name          Name of the static plugin (equivalent of dynamic plugin
511      filename)
512 @param className     Plugin class name
513 @param interface     Interface name (the same as is defined by the
514     @ref Corrade::PluginManager::AbstractPlugin::pluginInterface() "pluginInterface()"
515     member of given plugin class)
516 
517 If the plugin is built as **static** (using the CMake
518 @ref corrade-cmake-add-static-plugin "corrade_add_static_plugin()" command),
519 registers it, so it will be loaded automatically when PluginManager instance
520 with corresponding interface is created. When building as static plugin,
521 `CORRADE_STATIC_PLUGIN` preprocessor directive is defined.
522 
523 If the plugin is built as **dynamic** (using the CMake
524 @ref corrade-cmake-add-plugin "corrade_add_plugin()" command), registers it, so
525 it can be dynamically loaded via @ref Corrade::PluginManager::Manager by
526 supplying a name of the plugin. When building as dynamic plugin,
527 `CORRADE_DYNAMIC_PLUGIN` preprocessor directive is defined.
528 
529 If the plugin is built as dynamic or static **library or executable** (not as
530 a plugin, using e.g. CMake command @cmake add_library() @ce /
531 @cmake add_executable() @ce), this macro won't do anything to prevent linker
532 issues when linking more plugins together. No plugin-related preprocessor
533 directive is defined.
534 
535 See @ref plugin-management for more information about plugin compilation.
536 
537 @attention This macro should be called outside of any namespace. If you are
538     running into linker errors with `pluginImporter_`, this could be the
539     reason.
540 */
541 #ifdef CORRADE_STATIC_PLUGIN
542 #define CORRADE_PLUGIN_REGISTER(name, className, interface_)                \
543     namespace {                                                             \
544         Corrade::PluginManager::Implementation::StaticPlugin staticPlugin_##name; \
545     }                                                                       \
546     int pluginImporter_##name();                                            \
547     int pluginImporter_##name() {                                           \
548         staticPlugin_##name.plugin = #name;                                 \
549         staticPlugin_##name.interface = interface_;                         \
550         staticPlugin_##name.instancer =                                     \
551             [](Corrade::PluginManager::AbstractManager& manager, const std::string& plugin) -> void* { \
552                 return new className(manager, plugin);                      \
553             };                                                              \
554         staticPlugin_##name.initializer = className::initialize;            \
555         staticPlugin_##name.finalizer = className::finalize;                \
556         Corrade::PluginManager::AbstractManager::importStaticPlugin(CORRADE_PLUGIN_VERSION, staticPlugin_##name); \
557         return 1;                                                           \
558     }                                                                       \
559     int pluginEjector_##name();                                             \
560     int pluginEjector_##name() {                                            \
561         Corrade::PluginManager::AbstractManager::ejectStaticPlugin(CORRADE_PLUGIN_VERSION, staticPlugin_##name); \
562         return 1;                                                           \
563     }
564 #elif defined(CORRADE_DYNAMIC_PLUGIN)
565 #define CORRADE_PLUGIN_REGISTER(name, className, interface)                 \
566     extern "C" CORRADE_PLUGIN_EXPORT int pluginVersion();                   \
567     extern "C" CORRADE_PLUGIN_EXPORT int pluginVersion() { return CORRADE_PLUGIN_VERSION; } \
568     extern "C" CORRADE_PLUGIN_EXPORT void* pluginInstancer(Corrade::PluginManager::AbstractManager& manager, const std::string& plugin); \
569     extern "C" CORRADE_PLUGIN_EXPORT void* pluginInstancer(Corrade::PluginManager::AbstractManager& manager, const std::string& plugin) \
570         { return new className{manager, plugin}; }                          \
571     extern "C" CORRADE_PLUGIN_EXPORT void pluginInitializer();              \
572     extern "C" CORRADE_PLUGIN_EXPORT void pluginInitializer()               \
573         { className::initialize(); }                                        \
574     extern "C" CORRADE_PLUGIN_EXPORT void pluginFinalizer();                \
575     extern "C" CORRADE_PLUGIN_EXPORT void pluginFinalizer()                 \
576         { className::finalize(); }                                          \
577     extern "C" CORRADE_PLUGIN_EXPORT const char* pluginInterface();         \
578     extern "C" CORRADE_PLUGIN_EXPORT const char* pluginInterface() { return interface; }
579 #else
580 #define CORRADE_PLUGIN_REGISTER(name, className, interface)
581 #endif
582 
583 }}
584 
585 #endif
586