C++ – In C++, how to call an ‘init’ routine as a class is loaded

cclassconfigurationinitialization

I have a program that loads a bunch of "addons" (different meters that measure and display system values).

The "addons" have "grown" over time and the code of what addons to "activate",
and how many of each (if there is more than one of the "device" in the
system (cpu's, net-interfaces, etc) is hard-coded into the master. Ug
(and ick).

What I want is for each addon-meter to place it's name and init-routine-addr
into an array as they are loaded. Right now, what meters that are loaded
are fixed in the master at compile time. What I want is for the possibility
of dynamic loading, but more importantly, for external "script-extensions"
(that could measure "almost anything" and rely on the master to display
the collected data (like a script that would read outdoor temperature via
some 3rd party device). In other words — long after the master has been
compiled, I want to provide the ability for other addon meters to be added
as long as they supply a specific callable API.

Thus, as a new extension is added, I need some init routine to be called
as it loads that will place the new meter-name and routine to be called
in a class-singleton that has an array of the extension names and
their init-routine addresses (as in a dynamically loaded extension).

Then when execution starts, each extension will already have have "registered"
itself with a central list that the "master" can look at and know what
to call.

In Perl, I've used something in a "BEGIN{…} block" in loaded extensions
to call a Plug_Common->register("plugin name", \%Plugin_Description_Data); so when the main routine started it would look in the plugin-registry to see
what was available, dynamically, at runtime.

The question is, how do I do this in C++?

I've setup register routine, but I've no idea how to have the extensions
get their "name & address" registered before the main-master runs. Theoretically, since some of the extensions could be added via scripts long after the main-master was written — it wouldn't be able to know their names in advance.

Off the top of my head, I can only think of a "user-edited" static text file, that might be able to have the master, "somehow(?!)" call each extensions init and 'get_config' routine. Then I can get rid of all the 'extension/meter-specific'-knowledge out of the the master. I don't like the text-file idea as it's too prone to user-error — having something being able to automatically call a register-function as it is loaded, seems much less likely to have problems like the static-config file being out-of-sync with what extensions can be used on the system.

Any ideas? (I'd rather not have to build in a copy of something like Perl to handle the dynamic "loadability" of modules…to me, that would be 'ugly'…

Seem a bit unreliable for the master program to try to look through some
symbol table at runtime — especially with C++'s strong typing. I keep coming up with flaws in virtually every method I think of. :-(. Anyone know a better way? ;-)…


Update:
Had a thought (well more than one, but this one is a bit unconventional, but might work) What if each of the plugins declared a shared pointer to a global list in the master?) If the shared pointers were used in module level inits, then wouldn't the shared 'use count' be incremented as the modules were loaded?…hmmm… I don't know yet how to get the modules' addresses into the main array (without them getting any execution time), but if I can figure out a way for an initializer statement using the shared_ptr, then since loading it a non-multithreaded (at least at this point) if that pointer could be leveraged to increment and store the address of an init function, in a global array, that might give me my dynamic config? Right now, the only thing I know for sure is that shared pointers do have an accessible 'use_count' — which would only help me in determining how many plugins had registered. Maybe there is no way to make this work, but just a thought (at 5:45am after I've been up all night… so, may be completely flawed and I just don't see it yet…;-))… Anyway, thought I'd add my latest thoughts; For scripts I'm thinking of splitting off that type of plugin into a separate handler that would have to read some config… I don't really like it, but it does isolate those things that wouldn't load @ program start time… Anyone think it is possible to leverage the shared-pointer to do this?

Best Answer

In most plugin systems in C and C++, the loading of plugins works like this:

The main application specifies a path where the plugins should be located (or allows such a path to be configured). On startup, the application looks for either dynamically loadable libraries (DLLs on Windows, .so on Linux, in case of compiled plugins) or scripts (in case of interpreted/scripted plugins) in the plugin path.
For each plugin that it finds, the application tries to call an init/registration function that allows the plugin to register itself with the application. For interpreted/scripted plugins, this could be the main body of the script.

To support interpreted/scripted plugins, the application needs to incorporate a scripting engine that understands the language that the plugin is written in.

When writing a compiled plugin, one of the rules is that you build it as a dynamically loadable library and that you provide the initialization function with the exact name and signature that the main application expects.
Furthermore, any classes that the plugin provides must be derived from an interface specified by the main application for plugins that provide a certain service.

For a scripted plugin, the requirement is that the initialization function performs the initializations and registrations that are expected by the main application.

Related Topic