A lightweight, cross-platform C++17 Plugin Framework.
Linux Clang | Linux GCC | MacOS Clang | MacOS GCC | Windows M2sys | Windows MSVC | |
---|---|---|---|---|---|---|
Github |
Flaked Tuna is free and open source software distributed under the MIT software license. Currently it is located on GitHub and presumably you already know the link if you are reading this document. If not, you can download it at: github.com/ralck/flakedTuna
Simply put, it is a plugin framework for C++ designed to be light-weight, portable, and allow for easy dynamic loading. It is comprised of two halves that take care of bridging between the plugin code and application code. It uses the idea of Inversion of Control (IoC) to make the magic happen.
Flaked Tuna is designed around the C++11 standard and thus needs compiler support. It is also designed as a static library for easy of maintainability.
On each side of the framework is an IoC container specifically tasked with one part of the plugin loading. The plugin side is where the Plugin Registry lives. This part of the framework makes it easy for a developer to register a plugin object without having to know the details. Similarly, on the application side lives the Plugin Loader. Its task is to find all plugin objects registered in plugin modules and pull them into the application side.
Okay, so it is not really a magical bridge in between. In reality, it is C style exports baked into a couple easy macros to allow the developer to focus on the plugin and application code rather than loading the plugins.
Aha, here is the part of this guide you have been waiting for! Usage is broken down into a couple easy steps:
- Build the library. This is pretty simple; add the source files to your favorite IDE or make file system. If you are on Windows, make sure you have the WIN32 preprocessor flag defined. Build it into a static library (.lib on Windows or usually .a on Linux).
- Include the necessary header files in your plugin code. As far as Flaked Tuna, all you need is PluginRegistry.h. Typically, you also need to include your plugin's base class, depending on how you have set up your plugin, but I will leave that implementation up to you.
- Set up the plugin macros to register your plugin. These are: FLAKED_TUNA_EXPORTS_BEGIN // Begins the plugin registration FLAKED_TUNA_PLUGIN( concrete, base ) // Registers each plugin per base type FLAKED_TUNA_EXPORTS_END // Ends the plugin registration There is also an optional macro for setting up the plugin version. FLAKED_TUNA_PLUGIN_VERSION( version )
- Set your compiler to compile the plugin as a shared library. On Windows this is a .dll; on Linux it is usually a .so. Note: The default extension (.dll or .so) is not required for the Flaked Tuna framework, so use what ever tickles your fancy!
- Include the necessary header files in your application code. For Flaked Tuna, this is just PluginLoader.h. Again, I will leave the other implementation details up to you.
- Set up your linker so that your application code links to FlakedTuna.lib (built in Step 1).
- In your application code, create an instance of a PluginLoader object, add search directories, and load in plugins.
FlakedTuna::PluginLoader loader;
loader.FindPluginsAtDirectory("Path\\To\\Plugin", "dll"); // Windows
loader.FindPluginsAtDirectory("Path/To/Plugin", "so"); // Linux
std::vector<std::shared_ptr<IPlugin>> plugins = loader.BuildAndResolvePlugin<IPlugin>();
- Build your plugin and your application. That is it! You are now using the Flaked Tuna plugin framework. ☺
There is also some example code already set up (with Visual Studio solution/project files) that you can examine or try out the pre-compiled versions. You can find this in the example directory on github. The example has been updated to compile on Linux, but no make file is included yet.
First and foremost, the PluginLoader must remain in memory while your plugins are active. As shown above, it creates the bridge to your plugin code. If it is garbage collected while you are still using your plugins, the bridge collapses, all boat traffic is stuck in the harbor, and bad things may happen (i.e. segfault). TL;DR: Don't delete or let the system garbage collect your PluginLoader while you are using your plugins.
Secondly, a sometimes overlooked feature of C++ is object instantiation and destruction. Objects are created in the order they are listed and destructed in the reverse order. Order of members is important. The PluginLoader should not be destructed before the objects holding your plugins are. TL;DR: Put the PluginLoader ahead of your plugin objects so it is destructed last.