As we started using plugins, we started finding limitations on their use. First of all, plugins are expected to be used with signals. If not, then you run in a very simple problem: the plugin becomes a required library so you could as well compile it in as a .so file. It would be much easier and work as well. That's certainly the most important point. The following lists all the limits we are running into:
Since I now got a little practice, I have come up with a way to make it right from the start. The one most important concept for any plugin is to give the ability to the users to switch the plugin you are writing with another implementation. If you can see that this will work without having to re-implement any other plugin, then you are probably on the right track.
To test the validit, think of it this way:
1. You write your new plugin (N).
2. Plugin A wants to use your plugin. It sends an event using a boost signal and the expected data.
3. Another user wants a different implementation of your plugin (P). Now instead of loading N, that other user is going to load P. For P to work, P has to support all the same signals as N supports (and eventually more, in some cases possibly less if some are viewed as not required.)
As you can imagine if you implement things the wrong way then doing the exercise of creating P will fail.
Any global function called from the outside forces that plugin to exist. You'd have to call the replacement plugin exactly the same, C++ wise, which means you could not compile both instances of the two plugins you want to support.
The default method to attach plugin A to a signal of plugin B is to call this listen function. We use a macro by default as in:
boost::bind(&name::on_##signal, this, ##args));
The emitter_class is a C++ name, possibly qualified with namespaces, such as layout::layout. That makes it impossible to replace the layout plugin with another without calling it exactly the same and thus not being able to compile it along the original.
When implementing any class if they offer functions in a plugin, then that plugin is required to use that class. In other words, the plugin must be loaded or your code won't link properly.
The only way to do things right with plugins is to send signals. The plugin may use internal structures to keep track of all the data, but it is not a requirement (it may as well directly save the data in the Cassandra cluster.)
Note that this does not apply to private classes which are only used by the plugin defining those private classes,
Structures (or classes) that are 100% inline or have no functions are valid. This being said, you should limit those to definition of parameters to your functions. Using controlled_vars you can at least ensures that the values are valid (initialized to a valid default value and within a given range.)
Note however that having such structure definitions in your events you will force the creators of a new version of your plugin to include your plugin header to have access to your structure definitions.
Yes, structures are exactly the same thing as classes, only structures have members that are public by default.
Enumerations are fine, however they add a compilation dependency to your plugin since to create a signal with the exact same signature (very important!) you need to make use of the exact same declarations in both places.