Sane C++ Libraries
C++ Platform Abstraction Libraries
Loading...
Searching...
No Matches
Plugin

🟨 Compile source-delivered C++ extensions and reload them inside a running process (see Plugin for more details) More...

Classes

struct  SC::PluginFile
 Holds path to a given plugin source file. More...
 
struct  SC::PluginIdentity
 Represents the unique signature / identity of a Plugin. More...
 
struct  SC::PluginDefinition
 Plugin description, category, dependencies, files and directory location. More...
 
struct  SC::PluginScanner
 Scans a directory for PluginDefinition. More...
 
struct  SC::PluginCompiler
 Compiles a plugin to a dynamic library. More...
 
struct  SC::PluginSysroot
 Holds include and library paths for a system toolchain, used to let plugins link to libc and libc++. More...
 
struct  SC::PluginCompilerEnvironment
 Reads and holds CFLAGS and LDFLAGS environment variables, mainly to pass down sysroot location. More...
 
struct  SC::PluginDynamicLibrary
 A plugin dynamic library loaded from a SC::PluginRegistry. More...
 
struct  SC::PluginRegistry
 Holds a registry of plugins, loading and compiling them on the fly. More...
 
union  SC::PluginErrorContext
 A typed scalar payload for a Plugin error. Its interpretation is selected by PluginErrorContextKind. More...
 
struct  SC::ResultPlugin
 Plugin result retaining a stable operation detail and one scalar diagnostic context. More...
 

Enumerations

enum class  SC::PluginError : uint32_t {
  PathNotNullTerminated = 1 ,
  UnsupportedPathEncoding ,
  InvalidDefinition ,
  DynamicLibraryOperationUnsupported ,
  PathCapacityExceeded ,
  DefinitionCapacityExceeded ,
  ScannerCapacityExceeded ,
  RegistryCapacityExceeded ,
  CompilerConfigurationCapacityExceeded ,
  SysrootCapacityExceeded ,
  ArgumentCapacityExceeded ,
  FileOpenFailed ,
  FileSizeQueryFailed ,
  FileBufferCapacityExceeded ,
  FileReadFailed ,
  FileReadIncomplete ,
  FileRemoveFailed ,
  DirectoryOpenFailed ,
  DirectoryReadFailed ,
  CompilerNotFound ,
  SysrootNotFound ,
  CompilerEnvironmentReadFailed ,
  CompilerExitedWithFailure ,
  LinkerExitedWithFailure ,
  DynamicLibraryAlreadyLoaded ,
  DynamicLibraryLoadFailed ,
  DynamicLibraryCloseFailed ,
  DynamicLibraryNotLoaded ,
  SymbolNameConversionFailed ,
  SymbolNameCapacityExceeded ,
  SymbolNotFound ,
  InitializationEntryPointNotFound ,
  CloseEntryPointNotFound ,
  PluginNotFound ,
  PluginInitializationFailed ,
  PluginShutdownFailed ,
  DebuggerUnlockFailed ,
  ReloadUnsupported
}
 Stable portable failures returned by the Plugin library. More...
 
enum class  SC::PluginErrorDetail : uint16_t {
  None = 0 ,
  PathAssign ,
  PathAppend ,
  MetadataName ,
  MetadataVersion ,
  MetadataDescription ,
  MetadataCategory ,
  MetadataDependency ,
  MetadataBuildOption ,
  ScannerDefinitionStorage ,
  ScannerCandidatePath ,
  ScannerCandidateFile ,
  IteratorAssignDirectory ,
  IteratorBuildSearchPath ,
  IteratorBuildEntryPath ,
  CompilerFindConfiguration ,
  CompilerBuildArguments ,
  CompilerWriteArguments ,
  CompilerBuildObjectPath ,
  LinkerBuildArguments ,
  LinkerWriteArguments ,
  LinkerBuildOutputPath ,
  SysrootFindVersion ,
  SysrootBuildIncludePath ,
  SysrootBuildLibraryPath ,
  RegistryUnloadList ,
  RegistryStoreDefinition ,
  RegistryFindPlugin ,
  WindowsFileCreate ,
  WindowsFileGetSize ,
  WindowsFileRead ,
  WindowsFileDelete ,
  PosixFileOpen ,
  PosixFileStat ,
  PosixFileRead ,
  PosixFileRemove ,
  WindowsDirectoryFindFirst ,
  WindowsDirectoryFindNext ,
  PosixDirectoryOpen ,
  PosixDirectoryRead ,
  WindowsDynamicLibraryLoad ,
  WindowsDynamicLibraryClose ,
  WindowsDynamicLibraryGetSymbol ,
  PosixDynamicLibraryLoad ,
  PosixDynamicLibraryClose ,
  PosixDynamicLibraryGetSymbol ,
  WindowsSymbolNameConversion ,
  PosixSymbolNameAssign ,
  WindowsDebuggerUnlock ,
  WindowsDebuggerDelete
}
 Stable operation or backend stage retained for a Plugin failure. More...
 
enum class  SC::PluginErrorContextKind : uint16_t {
  None = 0 ,
  NativeError ,
  ExitCode ,
  RequiredBytes ,
  RequiredElements
}
 Kind of the scalar diagnostic context stored in ResultPlugin. More...
 

Detailed Description

🟨 Compile source-delivered C++ extensions and reload them inside a running process (see Plugin for more details)

#include "Libraries/Async/Async.h"
#include "Libraries/FileSystemWatcher/FileSystemWatcher.h"
namespace SC
{
//-----------------------------------------------------------------------------
// IPluginContract.h
//-----------------------------------------------------------------------------
// CLIENT - HOST Contract (Interface)
struct IPluginContract
{
static constexpr auto InterfaceHash = PluginHash("IPluginContract");
Function<void(void)> onDraw;
};
//-----------------------------------------------------------------------------
// PluginClient.cpp
//-----------------------------------------------------------------------------
// CLIENT Plugin (binds to contract functions)
struct PluginClient : public IPluginContract
{
PluginClient()
{
IPluginContract::onDraw = []()
{
// Draw stuff...
};
}
// Called when plugin is init
bool init() { return true; }
// Called when plugin is closed
bool close() { return true; }
};
SC_PLUGIN_DEFINE(PluginClient);
SC_PLUGIN_EXPORT_INTERFACES(PluginClient, IPluginContract);
//-----------------------------------------------------------------------------
// PluginHost.cpp
//-----------------------------------------------------------------------------
// Plugin HOST (loads plugin, obtains interface and calls functions)
struct PluginHost
{
// Fill directories before calling create
StringPath executablePath; // Where executable lives
StringPath libraryRootDirectory; // Where Sane C++ Libraries live
StringPath someLibraryDirectory; // Where 3rd party-lib headers live
StringPath pluginsPath; // Where Plugins live
PluginRegistry registry;
Result create(AsyncEventLoop& loop)
{
eventLoop = &loop;
// Setup Compiler
SC_TRY(PluginCompiler::findBestCompiler(compiler));
SC_TRY(PluginSysroot::findBestSysroot(compiler.type, sysroot));
// Add includes used by plugins...
SC_TRY(compiler.includePaths.push_back(libraryRootDirectory));
SC_TRY(compiler.includePaths.push_back(someLibraryDirectory));
// Setup File System Watcher
fileSystemWatcherRunner.init(*eventLoop);
SC_TRY(fileSystemWatcher.init(fileSystemWatcherRunner));
watcher.notifyCallback.bind<PluginHost, &PluginHost::onFileChanged>(*this);
SC_TRY(fileSystemWatcher.watch(watcher, pluginsPath.view()));
return Result(true);
}
Result close()
{
SC_TRY(fileSystemWatcher.close());
eventLoop = nullptr;
return Result(true);
}
Result syncRegistry()
{
// Max 16 definitions, but you can use heap allocation if you need an arbitrary limit
PluginDefinition definitions[16];
Span<PluginDefinition> definitionsSpan;
Buffer fileStorage;
SC_TRY(PluginScanner::scanDirectory(pluginsPath.view(), definitions, fileStorage, definitionsSpan))
SC_TRY(registry.replaceDefinitions(move(definitionsSpan)));
return Result(true);
}
// Call this to load a plugin with a given identifier
Result load(StringView identifier)
{
// Force reload of plugin if already loaded
SC_TRY(registry.loadPlugin(identifier, compiler, sysroot, executablePath.view(),
PluginRegistry::LoadMode::Reload));
// Obtain contract
const PluginDynamicLibrary* plugin = registry.findPlugin(identifier);
SC_TRY(plugin->queryInterface(contract));
return Result(true);
}
void draw()
{
if (contract)
{
contract->onDraw();
}
}
private:
AsyncEventLoop* eventLoop;
PluginCompiler compiler;
PluginSysroot sysroot;
IPluginContract* contract = nullptr;
FileSystemWatcher fileSystemWatcher;
FileSystemWatcherAsync fileSystemWatcherRunner;
void onFileChanged(const FileSystemWatcher::Notification& notification)
{
auto reload = [this](const PluginIdentifier& plugin) { (void)load(plugin.view()); };
registry.getPluginsToReloadBecauseOf(notification.relativePath, Time::Milliseconds(500), reload);
}
};
} // namespace SC
PluginErrorContextKind
Kind of the scalar diagnostic context stored in ResultPlugin.
Definition PluginError.h:112
PluginErrorDetail
Stable operation or backend stage retained for a Plugin failure.
Definition PluginError.h:57
constexpr unsigned int PluginHash(const char(&str)[N])
Compute compile time FNV hash for a char array.
Definition PluginHash.h:33
StringSpan relativePath
Relative path of the file being notified from basePath
Definition FileSystemWatcher.h:132
Definition Plugin.h:41
Reads and holds CFLAGS and LDFLAGS environment variables, mainly to pass down sysroot location.
Definition Plugin.h:259
Compiles a plugin to a dynamic library.
Definition Plugin.h:189
StringPath linkerPath
Path to the linker.
Definition Plugin.h:219
ResultPlugin compile(const PluginDefinition &definition, const PluginSysroot &sysroot, const PluginCompilerEnvironment &environment, Span< char > &compilerLog) const
Compiles a Definition to an object file.
FixedVector< StringPath, 8 > includePaths
Path to include directories used to compile plugin.
Definition Plugin.h:221
static ResultPlugin findBestCompiler(PluginCompiler &compiler)
Look for best compiler on current system.
Type type
Compile Type.
Definition Plugin.h:217
StringPath compilerPath
Path to the compiler.
Definition Plugin.h:218
Plugin description, category, dependencies, files and directory location.
Definition Plugin.h:115
StringPath directory
Path to the directory holding the plugin.
Definition Plugin.h:120
FixedVector< PluginFile, 10 > files
Source files that compose this plugin.
Definition Plugin.h:124
PluginIdentity identity
Uniquely identifier a plugin.
Definition Plugin.h:116
FixedString< 256 > description
Long description of plugin.
Definition Plugin.h:118
FixedVector< PluginIdentifier, 8 > dependencies
Dependencies necessary to load this plugin.
Definition Plugin.h:122
static ResultPlugin parse(StringSpan text, PluginDefinition &pluginDefinition, bool &parsed)
Parses an extracted plugin definition text.
FixedString< 64 > category
Category where plugin belongs to.
Definition Plugin.h:119
FixedVector< PluginBuildOption, 8 > build
Build options.
Definition Plugin.h:123
A plugin dynamic library loaded from a SC::PluginRegistry.
Definition Plugin.h:269
SystemDynamicLibrary dynamicLibrary
System handle of plugin's dynamic library.
Definition Plugin.h:271
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:282
Holds path to a given plugin source file.
Definition Plugin.h:96
StringPath absolutePath
Absolute path to a plugin source file.
Definition Plugin.h:97
PluginIdentifier identifier
Unique string identifying the plugin.
Definition Plugin.h:103
FixedString< 64 > name
Plugin name.
Definition Plugin.h:104
FixedString< 16 > version
Plugin version (x.y.z)
Definition Plugin.h:105
Holds a registry of plugins, loading and compiling them on the fly.
Definition Plugin.h:307
PluginDynamicLibrary * findPlugin(StringSpan identifier)
Find a PluginDynamicLibrary in the registry with a given identifier.
void init(Span< PluginDynamicLibrary > librariesStorage)
Init a PluginRegistry with some given storage.
ResultPlugin replaceDefinitions(Span< PluginDefinition > &&definitions)
Appends the definitions to registry.
void getPluginsToReloadBecauseOf(StringSpan relativePath, TimeMs tolerance, Function< void(const PluginIdentifier &)> onPlugin)
Enumerates all plugins that must be reloaded when relativePath is modified.
ResultPlugin removeAllBuildProducts(StringSpan identifier)
Removes all temporary build products of the Plugin with given identifier.
ResultPlugin loadPlugin(StringSpan identifier, const PluginCompiler &compiler, const PluginSysroot &sysroot, StringSpan executablePath, LoadMode loadMode=LoadMode::Load)
Loads a plugin with given identifier, compiling it with given PluginCompiler.
ResultPlugin unloadPlugin(StringSpan identifier)
Unloads an already loaded plugin by its identifier.
static ResultPlugin scanDirectory(StringSpan directory, Span< PluginDefinition > definitionsStorage, T &tempFileBuffer, Span< PluginDefinition > &foundDefinitions)
Scans a directory for PluginDefinition.
Definition Plugin.h:175
Holds include and library paths for a system toolchain, used to let plugins link to libc and libc++.
Definition Plugin.h:244
Reads current process environment variables.
Definition Process.h:402
bool get(size_t index, StringSpan &name, StringSpan &value) const
Get the environment variable at given index, returning its name and value.
Execute a child process with standard file descriptors redirection.
Definition Process.h:86
int32_t getExitStatus() const
gets the return code from the exited child process (valid only after exec or waitForExitSync)
Definition Process.h:246
ResultProcess exec(Span< const StringSpan > cmd, Out &&stdOut=Out(), In &&stdIn=In(), Err &&stdErr=Err())
Executes a child process with the given arguments, waiting (blocking) until it's fully finished.
Definition Process.h:239
ResultProcess setEnvironment(StringSpan environmentVariable, StringSpan value)
Sets the environment variable for the newly spawned child process.
Plugin result retaining a stable operation detail and one scalar diagnostic context.
Definition PluginError.h:151
StringPath executableFile
Path to current executable.
Definition Testing.h:66
StringPath libraryRootDirectory
Path to sources directory for library.
Definition Testing.h:65
Type-safe wrapper of uint64 used to represent milliseconds.
Definition Time.h:50
A typed scalar payload for a Plugin error. Its interpretation is selected by PluginErrorContextKind.
Definition PluginError.h:122

Enumeration Type Documentation

◆ PluginError

enum class SC::PluginError : uint32_t
strong

#include <PluginError.h>

Stable portable failures returned by the Plugin library.

◆ PluginErrorContextKind

enum class SC::PluginErrorContextKind : uint16_t
strong

#include <PluginError.h>

Kind of the scalar diagnostic context stored in ResultPlugin.

◆ PluginErrorDetail

enum class SC::PluginErrorDetail : uint16_t
strong

#include <PluginError.h>

Stable operation or backend stage retained for a Plugin failure.