How to make app plugins/extensions?

I don't know if this is possible. If I create an application, distributed as a closed-source native binary, can I also distribute plugins a separate binary files that extend the functionality of that app? Or is there not enough stable ABI for this?

The plugin would need to be able to use types in the application, and implement traits defined in the application.

// Define in app binary
pub trait Plugin {
    fn name(&self) -> String;
    fn startup(&self) -> anyhow::Result<()>;
    ...
}
pub struct Document {
    fn block(&self, node_id: NodeId) -> Option<&Block> { ... }
    fn span(&self, node_id: NodeId) -> Option<&Span> { ... }
}

// In plugin binary
struct ThisPlugin { ... }
impl Plugin for ThisPlugin { ... }

fn do_stuff(doc: &Document) {
    let b = doc.block(id) ...
} 

From what I know, you have 2 options:

  1. Use C ABI
  2. Create plugins as external apps and use some kind of IPC (either OS-provided like COM or D-Bus or custom one, based on sockets, shared memory or pipes).

The second option also gives you ability to write plugins in any language and even run them on another host (if you decided to use sockets), but it is not an option for hot paths.
In both cases, you would need to publish a "Plugin SDK" openly.

There are some hacks, though: abi_stable - Rust but I've never tried them.

In order to achieve this, no matter what strategy you use beyond that, you must put the relevant types and traits in a crate whose source is available to the plugin authors.[1] This crate might be a plugin API crate without any of the logic of your application, though.


  1. Technically you can distribute a compiled .rlib, but this requires the author to use a specific version of rustc, and doesn't necessarily hide much. ↩︎

The "I" there is probably more important than you realized.

If you build it all together at one time, and want to ship subsets, that's entirely feasible.

If you want to add extensions later, particular extensions by others, things get much more complicated.

Unless you want to have a plugin as a closure having access to all object of the main application you need to define:

  1. plugin interface, so your main app will use the interface to invoke the plugin functionality
  2. plugin discovery mechanism, so you main application ca figure out what plugins are available and for which functionality
  3. plugin authentication mechanism (optional) when your main application can decide if the plugin is legit or possible malware

After defining that, implementing a plugin should be fairly easy.