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