Building & installing a plugin

ABI versioning

Easy Writer loads a plugin only when the plugin's abiVersion() equals the app's kPluginAbiVersion. The interface's IID carries the same version as a /N suffix:

#define EW_PLUGIN_IID "games.loomwright.easywriter.Plugin/1"

Both are bumped together on any incompatible change to the Plugin or PluginContext vtable, so a plugin built against an older SDK is rejected rather than mis-called. Always return ew::app::kPluginAbiVersion from abiVersion() and use EW_PLUGIN_IID in your Q_PLUGIN_METADATA — never hard-code a number.

CMake

Build the plugin as a Qt plugin with qt_add_plugin, linking the Easy Writer libraries and Qt Core:

qt_add_plugin(my_plugin CLASS_NAME MyPlugin)
target_sources(my_plugin PRIVATE MyPlugin.cpp)
target_link_libraries(my_plugin
    PRIVATE
        ew::app
        ew::core
        Qt6::Core)

CLASS_NAME must match the plugin's C++ class. Build it with the same compiler, C++ standard, and Qt version as the app (MSVC 2022 x64, C++20, Qt 6.8.3) — a plugin is a native library sharing the app's ABI.

Installing

At startup the app scans the plugins/ folder next to the executable (applicationDirPath()/plugins). Copy your built plugin library there and restart. Every file it examines — loaded or skipped, with the skip reason — is listed in Preferences ▸ Plugins; a bad file (not a Qt plugin, wrong IID, incompatible ABI, or a build-key mismatch) is skipped without aborting the scan or crashing the app.

What a plugin can contribute

For the current ABI, a plugin contributes through the PluginContext:

Both are pure value types, copied into the app's ContributionRegistry — a plugin never holds a live pointer into the app, keeping the boundary clean.