Linking a QPlugin from another QPlugin corrupts the plugin loading?
-
Hello everybody,
I have a hierarchical plugin system, but there is something which is not working as it should. This topic is something that resembles "this previous discussion":http://developer.qt.nokia.com/forums/viewthread/2725 albeit I could not find a solution to my problem in there. Let me explain in more details w.r.t. the image below, you can also download the source "here":http://www.sfu.ca/~ata2/qtdevnet/source.zip
!http://www.sfu.ca/~ata2/qtdevnet/structure.png!
The structure is at follows: you have plugins that define models and then plugins that define extensions to these models. Because of this relationship the PluginModel will be loaded before the PluginExtension (see "main.cpp":www.sfu.ca/~ata2/qtdevnet/main.cpp).
In Particular, the PluginExtension access some of the resources defined by PluginModel: for example, it needs to be able to use MyClass defined therein. For this reason, in plugin_extension.pro, I import the path of MyClass's interface:
@
INCLUDEPATH += ../plugin_model
DEPENDPATH += ../plugin_model
@I originally thought that since PluginModel was already dynamically loaded, I would only need to import MyClass's headers, but unfortunately this is not the case! (why?) I get an undefined symbol for MyClass::MyClass() and MyClass::print().
Thus I thought that I could import the model plugin locally in plugin_extension.pro by a "LIBS+=" as follows:
@
INCLUDEPATH += ../plugin_model
DEPENDPATH += ../plugin_model
LIBS += ../plugins/libplugin_model.dylib
@While this compiles, at runtime it causes the "libplugin_extension.dylib" to be incorrectly loaded. See the output of main, (see "main.cpp":www.sfu.ca/~ata2/qtdevnet/main.cpp):
@
Loading: "/Users/ata2/workspace/starlab/tester/plugins/libplugin_model.dylib"
==> Loaded correct QPlugin
==> Loaded Model
Loading: "/Users/ata2/workspace/starlab/tester/plugins/libplugin_extension.dylib"
==> Cannot load incorrect QPlugin
@On the other hand, if I directly add the specification MyClass.cpp as follows:
@
INCLUDEPATH += ../plugin_model
DEPENDPATH += ../plugin_model
SOURCES += MyClass.cpp
@Then everything runs smoothly (notice that I am accessing MyClass):
@
Starting /Users/ata2/workspace/starlab/tester/main.bin...
Loading: "/Users/ata2/workspace/starlab/tester/plugins/libplugin_model.dylib"
==> Loaded correct QPlugin
==> Loaded Model
Loading: "/Users/ata2/workspace/starlab/tester/plugins/libplugin_extension.dylib"
==> Loaded correct QPlugin
==> Loaded Extension
Used something in MyClass
@However, this is basically just compiling MyClass.cpp all over again!!! And clearly I don't want to repeat the work already done while generating plugin_model!!! Thus my question is:
Why linking a plugin against another plugin causes it to become invalid? Is there a better way of doing things than just re-compiling MyClass.cpp all over again?
Thanks a lot for your input
Andrea
[EDIT: fixed download link for sources, Volker]
-
It seems that your MyClass is not pure abstract and you inherit from it in your extension plugin. This cannot work, as the linker must know of the base class object code. If you include the sources into the second plugin, you end up with object code for the same class in two different libraries, this cries for trouble in the future.
The only way I see to decouple the two plugins is to use a pure abstract base class (in other words: an interface that defines the methods, but provides no implementations). This is the way the plugins in Qt are built.
-
Hey Volker,
no, I don't inherit from MyClass in any way. I just use it in the extension plugin. Take a look at the attached sources. This is example code I wrote on the same model of my larger system, but it strictly address this problem... i.e. very brief and easy to read.
You have a good point compiling the sources twice is not a good idea, I perfectly reckon it. That's exactly why I don't want to do it. Initially I just thought of importing the DLL of the model plugin into the extension one, but something in Qt breaks down...
That's exactly the question.. why it breaks? (Cannot load incorrect QPlugin)
-
I think you could create a third shared library that is loaded by both plugins containing any classes that are needed by both plugin. As long as the plugin export code is not again loaded by the second plugin (i.e. it not importing the other plugin itself), you should be ok.
-
Hi loladiro, yes, indeed I thought of that solution as well. But I have a very good reason for not wanting to do that! You see.. In the full system a plugin_model is a wrapper for some data structure which allows it to be used within the system. The nice thing is that by not decoupling library & wrapper I can achieve a simple result: the library compiles altogether with the wrapper! Having to create an extra folder/plugin for it looks a bit like an overkill to me...
I am wondering whether I should just convert plugin_model to a normal dynamic library: one that isn't manually loaded within the application but that it is instead just loaded on application boot. I am wondering whether changing this would make any difference... Haven't played around with these types of loading though...
the question is still open :)
-
I think an answer to my question is somewhat connected to this:
http://doc.qt.nokia.com/latest/qlibrary.html#LoadHint-enumParticularly QLibrary::ExportExternalSymbolsHint. MyClass is exactly an external symbol loaded by another plugin... not sure how to use it though. Need to play around with it...
-
I played around with the one above but wasn't able to achieve much... HOWEVER!! I found another very very related post online:
"plugin fails to load with uresolved links":http://permalink.gmane.org/gmane.comp.lib.qt.general/32481
This guy was attempting to do exactly the same thing!!
Now the question is... why the QT guys didn't at least mention in the QPlugin documentation that you should NEVER have a plugin link against another plugin...I will move to the approach suggested above... A third "common" dynamic library that contains these definitions and against which all the relevant plugins must link... sob :(