I found myself recently needing to embed an open source library which used a similar mechanism for its plugin system. The goals of the plugin design of this system were to make it possible to cleanly register plugins for a range of different types in a manner which preserved type safety and to be able to use the same registration mechanism to define any of these plugins within arbitrary compilation units so that plugins could be easily added by consumers of the system -- using the same mechanism as used for the built in plugins... Including for plugins loaded at runtime.
The plugin registration mechanism involves a pre processor macro that authors invoke on each plugin class after definition -- this macro declares that the specified plugin implements a special factoryinstance template class. The factoryinstance template class is paramterized by the plugin type and the specific plugin implementation and provides a default constructor that retrieves the class name of the plugin implementation class via the qt meta object system and adds it to a central registry for each plugin type. This template class also contains a static member variable of the self same factoryinstance template class. This member variable gets initialized by default by the compiler during static initialization which causes the default constructor for the specialized type to be called which causes the plugin to be added to a registry with correct name and correct type information intact ...
This was all well and good however had a very annoying consequence for me as i wanted to embed some of the functionality of this system into a reusable static archive (the original system authors were only concerned with shared library scenarios). At the end of the day no code linking against this archive will make any reference to any symbols of any of these template class implementations -- so the linker will strip all these symbols away and remove all the static initialization calls -- leaving an empty plugin registry in the runtime environment of
The final binary ...
For now I work around the issue by requiring that each consumer of the static library pass linker flags to force load the whole static -- this works however makes the binaries larger than needed as each binary must include all plugins and the linker is not able to include just the ones used ... At some point I'm going to need to figure out the smallest set of changes to this registration mechanism to adapt this library to the embedded use case such that a consumer of the library will include only the plugins they use ... I haven't figured out what that looks like yet ...
This issue was kind of a mind warping ... Sometimes the more I learn about C++, the more insane it seems ...
The plugin registration mechanism involves a pre processor macro that authors invoke on each plugin class after definition -- this macro declares that the specified plugin implements a special factoryinstance template class. The factoryinstance template class is paramterized by the plugin type and the specific plugin implementation and provides a default constructor that retrieves the class name of the plugin implementation class via the qt meta object system and adds it to a central registry for each plugin type. This template class also contains a static member variable of the self same factoryinstance template class. This member variable gets initialized by default by the compiler during static initialization which causes the default constructor for the specialized type to be called which causes the plugin to be added to a registry with correct name and correct type information intact ...
This was all well and good however had a very annoying consequence for me as i wanted to embed some of the functionality of this system into a reusable static archive (the original system authors were only concerned with shared library scenarios). At the end of the day no code linking against this archive will make any reference to any symbols of any of these template class implementations -- so the linker will strip all these symbols away and remove all the static initialization calls -- leaving an empty plugin registry in the runtime environment of The final binary ...
For now I work around the issue by requiring that each consumer of the static library pass linker flags to force load the whole static -- this works however makes the binaries larger than needed as each binary must include all plugins and the linker is not able to include just the ones used ... At some point I'm going to need to figure out the smallest set of changes to this registration mechanism to adapt this library to the embedded use case such that a consumer of the library will include only the plugins they use ... I haven't figured out what that looks like yet ...
This issue was kind of a mind warping ... Sometimes the more I learn about C++, the more insane it seems ...