Question

What are the “normal” ways to do plug-ins in compiled languages (C#/C/C++/D)? I am specifically interested in language agnostic approaches but language specific is not unacceptable.

For the time being, “compile time” plug in approaches (just include the code or not and everything works) are valid but things that can migrate to a more dynamic approach are preferred.

Regarding the runtime type, I'm more interested in the mechanics of loading the plug-in and whatnot than designing the plug-in/app interface

EDIT: BTW the plugin would be a slave not a master. The basic action of a plug-in would be to that under a given situation, it would be called on to "do its thing" and be given an environment object that it should use to get what it needs to operate.

Was it helpful?

Solution

For compiled languages (where compiled means the program runs as a native executable, without any sort of virtual machine), you pretty much need to use some sort of platform-specific shared library approach. In Windows, this means using DLLs.

You define your plugin interface in terms of a set of functions (with specific names, arguments, and calling conventions). Then, you load the addresses of the functions within the shared library and go to town. In Windows, this means using GetProcAddress(), and then casting the return value to a function pointer of the appropriate type in C, or whatever the equivalent is in the language you're using.

Another option that may or may not be more desirable would be to run a virtual machine for another language from within your native application, and have plugins be code for that language. For example, you could run a Python VM using CPython and dynamically load Python modules.

OTHER TIPS

Mono.Addins seems to be a good solution for .NET. I believe it includes API to allow you to download plugins (or addins) from a repo and dynamically load it into a running assembly.

I've found that the hard parts about plugins are: finding them, resolving their dependencies, and handling version issues. How you handle these issues should be clear to you and to your plug in authors. If you get these issues wrong, it will cause no end of pain. I would look at scripting languages and applications which use plugins for ideas on what works well.

Static constructors are more often than not, "clever" in the bad sense. Since you are going to have to load (C/C++: dlopen and friends under Linux) the plugins one at a time anyway (in the dynamic case), you may as well manifestly initialized them as you do so. Among other things, that may give you an opportunity to reject plugins without expected api's.

Note, you don't have to use dynamic load libraries for plugins. Other mechanisms can also be used: shared memory, sockets, etc....

It really depends on what you want to do. The common Unix pattern as seen in Emacs and the Gimp is to write a program that consists of a small compiled component that exposes essential functionality that an interpreted component uses to do everything. Pluglins that provide new functionality that can be built on top of the app are easy, but you need to be very flexible in the primatives you provide for this to be possible. At the opposite extreme imagine a photo editor which can save in multiple formats. You want to allow people to write their own file format handlers. This requires making your code use a simple set of primitives, then picking an implementation at runtime. In straight (Unix) C use dlopen, in C++ use extern C which limits what you can do and dlopen. In Objective-C you have a class to do it for you. In the first case you are making or reusing an interpreter so you have free reign to do it however you want.

For a slave-type plugin where each plugin encapsulates a different implementation of a common set of functions, I would just deposit the DLLs in a plugin folder known to the host application (e.g. "c:\program files\myapp\plugins), and then call the DLLs from the host via Reflection.

You could do some sort of elaborate registration process when each DLL is installed, but I've never experienced any problems with the simple plugins-in-one-folder approach.

Edit: To do this in C#, you just add a public class to the DLL (named "Plugin" or whatever), and implement needed functions there. From your host, you then create an object of type Plugin and call its methods (all using Reflection).

Interfaces with a void Register(EventSource) seem to work well - see ASP.NET's IHttpModule.Init(HttpApplication) for an example.

This allows the app author (who controls EventSource) to add events as needed, without needing to extend the IPlugin interface (inevitably leading to IPluginEx, IPlugin2, IPlugin2Ex, etc.)

An approach I've used (in .NET) is to have the host make an initial call to the plugin (via Reflection), starting the plugin and passing a reference to the host that the plugin saves. The plugin then calls methods on the host (also via reflection) as necessary.

I think with most plugins, the calls would usually be made in the other direction (i.e. the host would call the plugin as necessary). In my case, the plugins themselves had UI elements that needed to make use of host functionality.

low level module implementation issues aside (e.g. windows DLLs and implementation issues), a game engine I use just has a global registration function in the DLLs, and attempts to find and call it on every dll in the plugin directory. the registartion function does any bookkeeping necessary to expose functionality.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top