I'm designing a plugin system using shared library. It works as follow: a plugin base class is provided as a template with virtual functions, and its header file includes all dependencies those plugin would need; plugin developers need to override those virtual functions to fulfill their targets, using only dependencies of the plugin system; the main executable includes header file of plugin base class to inherit dependencies. The main executable runs as a loop and it could load shared library in runtime (using dlopen), and a singleton called 'PluginManager' will call functions in loaded plugins once per frame.
A simple example below:
// plugin.h
#include "third_party/test.pb.h" // which is not used in main executable, but in one of the plugins
#include "basic/math/math_util.h" // which is used in main executable
class Plugin {
public:
Plugin() = default;
virtual ~Plugin() {}
virtual void Execute() {}
};
// do_something.h
// It has a do_something.cc, but we omit it here since it's not so important
#include "plugin.h"
class DoSomething : public Plugin {
public:
DoSomething() : Plugin() {}
~DoSomething() {}
virtual void Execute() override; // It will do something using data structures and functions described in test.pb.h and math_util.h
private:
test::TestBody test_; // described in test.pb.h
};
// main.cc
#include "plugin.h"
int main(int argc, char** argv) {
int should_continue = 1;
while (should_continue) {
// Do something about dlopen, and call Execute() in plugins after loaded.
}
}
In this little example, the plugin DoSomething
is using functions from math_util.h
, which is also used by our main executable, and functions from test.pb.h
, which is included by main executable but not used. The compiling works nicely, but when loading DoSomething
plugin, it will throw dlerror()
like
Can't open handle: /opt/ourprogram/plugins/libdo_something.so: undefined symbol: _ZTIN4test8TestBodyE
I understand that it's an expected behavior, since our main executable don't have a reason to really export this symbol. If I remove usage of TestBody
in DoSomething
plugin, or add a simple instancing in main executable like test::Testbody body
, the shared library could be loaded as a charm.
The thing is, it's a plugin system and we don't want users to mess up with our core code except for including something, not to mention in our entry file. Is there any easy way for us to make the plugin work? Any help would be appreciated.