For the C++ library I am currently developing I have seen the advantages of a plug-in system based on shared libraries. A feature will become available to the user of the library just if one of the shared libraries that are in a directory scanned at initialization time is offering that.
Using dlopen, the shared libraries will be searched for two symbols: one function that returns the string that names the feature they implement, and a create function that instantiates the class and returns a pointer to the basse class. Something like this:
In Library A
#include "Instance.hpp"
extern "C" const char* type() {
return "InstanceA";
}
//... class InstanceA definition, inherits from Instance
extern "C" Instance* create() {
return new InstanceA();
}
The Core library will scan the plug-ins directory and keep a map string->pointerToCreateFunction in order to create new instances.
This is really handy, and a pretty standard thing to do. If the user code tries to instantiate an InstanceX but no shared library implement that type, an error will be given, everything will work perfectly.
But this framework will be used also for iOs development, and the App Store doesn't allow loading 3rd party shared objects. I would like to keep this modular plug-in structure even when loading a self contained version of the library that links statically the plugins. Note that at project management level this would be as easy as defining a variable in CMake that creates static versions of the plugins and links them statically. This would also exclude the dynamic loading part of the code.
What I am missing is how to invert the mechanism: while for shared objects the core library will leverage on the file system to learn about the possible type of instances that can be used, I don't know how to "register" them without changing big part of the code, and without going in the static initialization fiasco. Looks like the only way to have that is subsituting the code that scans the types and the create function by including all the possible headers and having a big switch like
Instance* theInstance;
if (instanceRequired == "instanceA")
theInstance = new InstanceA();
etc etc...
Do you have any thought on a way to avoid including all the headers and having to change the code in Core each time a new instance is added?