{"id":30216752,"url":"https://github.com/4d-star/libplugin","last_synced_at":"2025-08-14T03:49:48.415Z","repository":{"id":308418328,"uuid":"1032048102","full_name":"4D-STAR/libplugin","owner":"4D-STAR","description":null,"archived":false,"fork":false,"pushed_at":"2025-08-05T19:40:57.000Z","size":6116,"stargazers_count":0,"open_issues_count":0,"forks_count":1,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-08-05T21:29:37.267Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/4D-STAR.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2025-08-04T18:12:15.000Z","updated_at":"2025-08-05T19:41:02.000Z","dependencies_parsed_at":"2025-08-05T21:39:44.407Z","dependency_job_id":null,"html_url":"https://github.com/4D-STAR/libplugin","commit_stats":null,"previous_names":["4d-star/libplugin"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/4D-STAR/libplugin","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/4D-STAR%2Flibplugin","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/4D-STAR%2Flibplugin/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/4D-STAR%2Flibplugin/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/4D-STAR%2Flibplugin/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/4D-STAR","download_url":"https://codeload.github.com/4D-STAR/libplugin/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/4D-STAR%2Flibplugin/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":270359005,"owners_count":24570445,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-08-14T02:00:10.309Z","response_time":75,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-08-14T03:49:43.832Z","updated_at":"2025-08-14T03:49:48.378Z","avatar_url":"https://github.com/4D-STAR.png","language":"C++","funding_links":[],"categories":[],"sub_categories":[],"readme":"# libplugin\n\nlibplugin is a simple, dynamic library based, plugin framework developed for\nSERiF, a 4D-STAR project. libplugin has been developed with the primary goal of\nbeing easy and type safe for plugin developers to use. It includes support for\nplugin bundles, which allow packaging multiple plugins together with metadata\nand resources into a single distributable file.\n\n# Funding\n\nlibplugin is a part of the 4D-STAR collaboration.\n4D-STAR is funded by European Research Council (ERC) under the Horizon Europe\nprogramme (Synergy Grant agreement No. 101071505: 4D-STAR) Work for this\nproject is funded by the European Union. Views and opinions expressed are\nhowever those of the author(s) only and do not necessarily reflect those of the\nEuropean Union or the European Research Council.\n\n# Installation\n\nThe primary installation channel for libplugin is directly from source. Note that you will need a C++ compiler supporting C++23.\n\n```bash\ngit clone https://github.com/4D-STAR/libplugin\ncd libplugin\nmeson setup build\nmeson compile -C build\nmeson test -C build\nmeson install -C build\n```\n\n# Examples\nThere are robust examples in the `examples/` directory. Users are strongly\nencoraged to make use of these examples as learning tools.\n\n# Usage\nThe primary usage flow for libplugin is\n\n1. Define some common and pure virtual plugin interface as a decendent of\n   `fourdst::plugin::PluginBase`. Generally this will be defined by whatever\nprogram expects the plugins to be made for it. That is to say that if I was the\nmaintainer of the `GridFire` project and I wanted users to be able to make\nplugins for `GridFire::solver::DirectNetworkSolver::RHSManager::observe()` I\nwould need to make some header file which defined the plugin class interface.\n2. The plugin author must then make a specific implimentation of that\n   interface. So if `GridFire` presents an interface called\n`RHSManagerObservePlugin` then the plugin author must make a concrete\nimplimentation of that pure virtual interface.\n3. The plugin author compiles their plugin as a dynamic library (`*.dylib` on\n   macOS, `*.so` on linux). They must tell the compiler to include the\nlibplugin headers (and libplugin library) of course, but also the common\ninterface header.\n4. The \"Host\" program (in the above examples this would be `GridFire`) must\nthen be somehow informed of the location of the dynamic library. The method\nto do this is up to the Host program to impliment (this could be something like\ncommand line arguments or a config file)\n5. Within the Host program the\n   `fourdst::plugin::manager::PluginManager::load(\"path.dylib\")` must then be\ncalled for that path. Again it is on the Host program to impliment the details\nof how this path is recived (though presumably it should be a runtime argument\nwith safe handling for if no path is recived.)\n\n## Plugin Bundles\n\nlibplugin supports plugin bundles, which are single-file packages containing one or more plugins along with their metadata, resources, and signatures. Bundles are distributed as `.fourdst` files and provide several benefits:\n\n- **Single-file distribution** - Easy to share and deploy\n- **Code signing** - Verify the authenticity of plugins\n- **Dependency management** - Specify required system libraries and versions\n- **Metadata** - Include author, version, and description information\n- **Resource packaging** - Bundle additional files needed by the plugins\n\n### Creating a Bundle\n\nUse the `fourdst-cli bundle create` command to create a new bundle:\n\nFirst create a plugin (or multiple plugins)\n```bash\nfourdst-cli plugin init test_1_plugin -H host_provided_interface.h\nfourdst-cli plugin init test_2_plugin -H host_provided_interface.h\n```\nNow edit those to do what you want them to do.\n\nNext create a bundle from multiple plugins\n\n```bash\nfourdst-cli bundle create -o example.fbundle --name TestPluginBundle --ver 0.1.0 --author \"Emily M. Boudreaux\" --target-macos-version 12.0  test_1_plugin test_2_plugin\n```\n\nNow fill the bundle with precompiled dynamic libraries for various systems (mac binaries can only be produced on macos, linux binaries can be produced on any system using docker)\nIn order to use docker the docker daemon must be running.\n\n```bash\nfourdst-cli bundle fill example.fbundle\n```\n\nThen create a key (or use an existing one to sign)\n\n```bash\n# Creating a key if you dont already have one\nfourdst-cli keys generate --name example\nfourdst-cli keys add example.pub.pem # This adds your personal key to the fourdst keyring\nfourdst-cli bundle sign example.fbundle --key example.pub.pem\n```\n\n\nFinally, you can inspect and or verify the bundle\n\n```bash\nfourdst-cli bundle inspect example.fbundle\nfourdst-cli bundle verify example.fbundle\n```\n\n### Loading a Bundle\n\nIn your application, load a bundle using the `PluginManager`:\n\n```cpp\n#include \u003cfourdst/plugin/manager/plugin_manager.h\u003e\n#include \u003cfourdst/plugin/bundle/plugin_bundle.h\u003e\n\nfourdst::plugin::manager::PluginManager\u0026 manager = fourdst::plugin::manager::PluginManager::getInstance();\nfourdst::plugin::bundle::PluginBundle bundle(\"path/to/bundle.fbundle\");\n\n// Access plugins from the bundle\nauto* plugin = manager.get\u003cMyPluginInterface\u003e(\"plugin_name\");\n```\n\n## Examples\nA very simple example follows\n\n### Host Program\nWe start with what the host program needs. Remember this includes \n\n- Some common and pure virtual interface for what kind of plugin it will expect\n- A way to get the path to a dynamic library from a plugin author\n\n#### Host Program Entry Point\n```c++\n// File main.cpp\n// This is intended to be the entry point for the host\n\n#include \u003cfourdst/plugin/plugin.h\u003e\n#include \"host_interface.h\"\n\nint main() {\n  fourdst::plugin::manager::PluginManager\u0026 manager = fourdst::plugin::manager::PluginManager::getInstance();\n  manager.load(\"libsimple_plugin.dylib\"); // For now I will just assume that the plugin is at this fixed path\n  auto* plugin = manager.get\u003cIHostDefinedPlugin\u003e(\"plugin_main\");\n  plugin -\u003e say_hello();\n}\n```\n\n#### Host Program Interface\n```c++\n// File: host_interface.h\n// This is a file the host program must provide so that both it and the plugin author can know about the plugin interface\n\n#pragma once\n#include \u003cfourdst/plugin/plugin.h\u003e\n\nclass IHostDefinedPlugin : public fourdst::plugin::PluginBase {\npublic:\n  ~HostDefinedPlugin() override = default;\n  virtual void say_hello() const = 0;\n}\n```\n\n### Plugin Program\nThe plugin author then only needs to write one file\n\n```c++\n// File: plugin.cpp\n// This is the file a plugin author would write\n#include \u003cfourdst/plugin/plugin.h\u003e\n#include \"host_interface.h\" // Note that it is generally up to the host to sort out how to inform the plugin author where this file is...\n\n#include \u003ciostream\u003e\n\nclass CustomPlugin : public IHostDefinedPlugin {\n  void say_hello() const override {\n    std::cout \u003c\u003c \"Hello, World!\\n\";\n  }\n}\n\n// The first argument is the name of the plugin authors implimentation\n// The second argument is the name of the plugin that the host will call. The names the host expects to call should be documented *by the host*\n// The last argument is the version number\nFOURDST_REGISTER_PLUGIN(CustomPlugin, \"plugin_main\", \"1.0.0\")\n```\n\n### Compiling a plugin\nYou very well could call the compiler directly; however, we strongly recommend you use a build system to compile your plugins. We use meson\n\n```meson\n# File: meson.build\nproject('simple_plugin, 'cpp', version: '1.0.0', default_options: ['cpp_std=c++23'])\n\n# Find the fourdst plugin library\nfourdst_plugin_dep = dependency('fourdst_plugin', required: true)\n\n# We need some way of informing the plugin about the header from the host program\n# if your host program has been installed in a find-able manner this could perhapse done like this\n# alternitivley you could use meson's shared_library's include_directories directive and point it\n# at whatever directory that header file is in\nhost_program_dep = dependency('host_program', required: true)\n\nsimple_plugin = shared_library(\n    'simple_plugin',\n    'plugin.cpp',\n    dependencies: [fourdst_plugin_dep, host_program_dep],\n    install: false,  # Set to true if you want to install the plugin\n    cpp_args: ['-fPIC']  # Ensure position-independent code\n)\n```\nthen you would simply run the standard set of meson commands\n\n```bash\nmeson setup buildPlugin\nmeson compile -C buildPlugin\n```\n\nnow you will have a file in build named `libsimple_plugin.cpp`\n\n## Templates\nWe include a simple `FunctorPlugin_T\u003cT\u003e` template plugin allowing Host authors\nto impliment functor style plugins. This plugin expects that operator() will be overloaded with the signature\n\n```c++\nT operator()(T arg);\n```\nAn example usage might be\n\n### Host\n#### Host interface file\n\n```c++\n// File: TimestepFunctorInterface.h\n#include \u003cfourdst/plugin/plugin.h\u003e\n\nstruct TimestepContext {\n  double time;\n  double dt;\n  double value;\n  size_t step;\n}\n\nclass ITimestepFunctor : public fourdst::plugin::templates::FunctorPlugin_T\u003cTimestepContext\u003e {};\n```\n\n#### Host usage of plugin\n```c++\n#include \u003cfourdst/plugin/plugin.h\u003e\n\n#include \"TimestepFunctorInterface.h\"\n\nvoid foo() {\n  fourdst::plugin::manager::PluginManager manager;\n  TimestepContext context {54.3, 0.1, 10.892745, 7}\n  manager.load(\"path.dylib\");\n  auto* plugin = manager.get\u003cITimestepFunctor\u003e(\"plugin_A\")\n  TimestepContext result = (*plugin)(context);\n}\n```\n\n#### Plugin author usage\n```c++\n#include \u003cfourdst/plugin/plugin.h\u003e\n\n#include \"TimestepFunctorInterface.h\"\n\nclass TimestepFunctor : public ITimestepFunctor {\n  TimestepContext operator()(TimestepContext ctx) {\n    std::cout \u003c\u003c \"Time: \" \u003c\u003c ctx.time \u003c\u003c \", value: \" \u003c\u003c ctx.value \u003c\u003c \"\\n\";\n    return ctx;\n  }\n}\n```\n\n## fourdst-cli\nThe [fourdst](https://github.com/4D-STAR/fourdst) library contains cli tool\nnamed `fourdst-cli`. One function of this tool is to make the lives of plugin\nauthors much easier. See [here](./examples/FOURDST-CLI.md) for more details but\nthe basics are covered below.\n\nOnce `fourdst-cli` is installed it is invoked using a git like syntax from\n\n```bash\nfourdst-cli plugin init PluginName --header \u003cpath/to/interface/defined/by/host\u003e\n```\n\nThis will let setup all the required files so that the author can just go in\nand impliment the functions they want to then build with meson.\n\n## Future\nWe hope to add support for python plugins being called from C++ in the near future.\n\n\n\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2F4d-star%2Flibplugin","html_url":"https://awesome.ecosyste.ms/projects/github.com%2F4d-star%2Flibplugin","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2F4d-star%2Flibplugin/lists"}