Plugin library allows extending application compiling C++ source to executable code at runtime.
#include "Libraries/Async/Async.h"
#include "Libraries/FileSystemWatcher/FileSystemWatcher.h"
namespace SC
{
struct IPluginContract
{
static constexpr auto InterfaceHash =
PluginHash(
"IPluginContract");
};
struct PluginClient : public IPluginContract
{
PluginClient()
{
IPluginContract::onDraw = []()
{
};
}
bool init() { return true; }
bool close() { return true; }
};
SC_PLUGIN_DEFINE(PluginClient);
SC_PLUGIN_EXPORT_INTERFACES(PluginClient, IPluginContract);
struct PluginHost
{
{
eventLoop = &loop;
SC_TRY(PluginCompiler::findBestCompiler(compiler));
SC_TRY(PluginSysroot::findBestSysroot(compiler.
type, sysroot));
SC_TRY(fileSystemWatcher.init(fileSystemWatcherRunner, *eventLoop));
watcher.notifyCallback.bind<PluginHost, &PluginHost::onFileChanged>(*this);
SC_TRY(fileSystemWatcher.watch(watcher, pluginsPath.
view()));
}
{
SC_TRY(fileSystemWatcher.close());
eventLoop = nullptr;
}
{
SC_TRY(PluginScanner::scanDirectory(pluginsPath.
view(), definitions))
}
{
PluginRegistry::LoadMode::Reload));
}
void draw()
{
if (contract)
{
contract->onDraw();
}
}
private:
IPluginContract* contract = nullptr;
{
auto reload = [
this](
const PluginIdentifier& plugin) { (void)load(plugin.view()); };
}
};
}
constexpr unsigned int PluginHash(const char(&str)[N])
Compute compile time FNV hash for a char array.
Definition PluginHash.h:33
StringView relativePath
Relative path of the file being notified from basePath
Definition FileSystemWatcher.h:107
A structure to describe modified time.
Definition FileSystem.h:304
Time::Realtime modifiedTime
Time when file was last modified.
Definition FileSystem.h:306
Result setLastModifiedTime(StringView file, Time::Realtime time)
Change last modified time of a given file.
Result getFileStat(StringView file, FileStat &fileStat)
Obtains stats (size, modified time) about a file.
Compiles a plugin to a dynamic library.
Definition Plugin.h:113
SmallVector< StringNative< 256 >, 8 > includePaths
Path to include directories used to compile plugin.
Definition Plugin.h:144
Type type
Compile Type.
Definition Plugin.h:140
Plugin description, category, dependencies, files and directory location.
Definition Plugin.h:54
SmallString< 255 > description
Long description of plugin.
Definition Plugin.h:56
SmallVector< PluginIdentifier, 8 > dependencies
Dependencies necessary to load this plugin.
Definition Plugin.h:60
PluginIdentity identity
Uniquely identifier a plugin.
Definition Plugin.h:55
SmallVector< SmallString< 10 >, 8 > build
Build options.
Definition Plugin.h:61
SmallString< 10 > category
Category where plugin belongs to.
Definition Plugin.h:57
A plugin dynamic library loaded from a SC::PluginRegistry.
Definition Plugin.h:188
SystemDynamicLibrary dynamicLibrary
System handle of plugin's dynamic library.
Definition Plugin.h:190
bool queryInterface(T *&outInterface) const
Try to obtain a given interface as exported by a plugin through SC_PLUGIN_EXPORT_INTERFACES macro.
Definition Plugin.h:199
SmallString< 10 > version
Plugin version (x.y.z)
Definition Plugin.h:44
SmallString< 30 > name
Plugin name.
Definition Plugin.h:43
Holds a registry of plugins, loading and compiling them on the fly.
Definition Plugin.h:224
Result unloadPlugin(const StringView identifier)
Unloads an already loaded plugin by its identifier.
Result loadPlugin(const StringView identifier, const PluginCompiler &compiler, const PluginSysroot &sysroot, StringView executablePath, LoadMode loadMode=LoadMode::Load)
Loads a plugin with given identifier, compiling it with given PluginCompiler.
Result removeAllBuildProducts(const StringView identifier)
Removes all temporary build products of the Plugin with given identifier.
const PluginDynamicLibrary * findPlugin(const StringView identifier)
Find a PluginDynamicLibrary in the registry with a given identifier.
Result replaceDefinitions(Vector< PluginDefinition > &&definitions)
Appends the definitions to registry.
void getPluginsToReloadBecauseOf(StringView relativePath, Time::Milliseconds tolerance, Function< void(const PluginIdentifier &)> onPlugin)
Enumerates all plugins that must be reloaded when relativePath is modified.
Holds include and library paths for a system toolchain, used to let plugins link to libc and libc++.
Definition Plugin.h:163
StringView libraryRootDirectory
Path to sources directory for library.
Definition Testing.h:27
StringView executableFile
Path to current executable.
Definition Testing.h:28
Type-safe wrapper of uint64 used to represent milliseconds.
Definition Time.h:44
The main use case is for now splitting applications in smaller pieces that can be hot-reloaded at runtime.
A secondary use case could be allowing customization on a delivered application (mainly on Desktop systems). Plugins are always meant to be delivered in source code form (.cpp
) and they're compiled on the fly. A plugin is made of a single .cpp
file and it declares itself through a special comment in the source code. Such comment can declare the name, the version, a description / category and a list of dependencies.
A plugin can be modified, unloaded, re-compiled and re-loaded to provide additional functionality.
The list of dependencies makes it possible to find recursive dependencies and unload them before unload a plugin.
As of today this is all implemented using native dynamic library mechanisms that are being loaded directly in the process.
Doing the wrong thing with memory or forgetting to clean everything during shutdown can quickly crash the main executable.
This is the list of videos that have been recorded showing some usages of the library:
There are plans to experiment with out of process plugins using some sort of RPC system (like Audio Unit plugins on macOS) and / or experimenting using WASM as a plugin host to eliminate such instability / security issues. Other ideas include redistribute a minimal C++ toolchain (probably a customized clang) that can compile the plugins without needing a system compiler or a sysroot, as all public headers of libraries in this project do not need any system or compiler header.