Export QObject based class from DLL
-
If you want to export a C++ class from a DLL (Windows), you need to declare it with proper __declspec(dllexport) (if building the DLL) or __declspec(dllimport) (when using the DLL). That's just what Windows wants you to do, and it is normally done with properly defined preprocessor macros, like
class MYDLL_EXPORT myClass { ... }
But if now this class happens to be derived from QObject, this is not working any more - and I have not found a solution yet:
class MYDLL_EXPORT myClass: public QObject { Q_OBJECT ... }
The point is that this header will have to be MOC'ed, and this tool will generate some code that is not allowed together with __declspec(dllimport) and the compiler gives an error message like this:
moc_myClass.cpp(89): error C2491: 'atgCategoriesManager::staticMetaObject': definition of dllimport static data member not allowed
and that's it!
Now the point is that I used Google and found MANY mentions of this problem, but bad enough: not one single solution!
So my question still remains: What can I do so solve that problem?
The point is simply: the Q_OBJECT macro generates code that is not acceptable for the MSVC compiler if you do not only export it from a dll, but also want to import it - which is finally the purpose of any DLL! It really starts to drive me a little crazy: Maybe I should totally redesign my software and make sure that QObject derived classes are never exported from DLLs!??
-
Conclusion: problem solved - thanks to the hint of VRonin!
An additional hint I found somewhere else for CMake users. There you can do it as follows:
In the configuration file you need this:
INCLUDE(GenerateExportHeader) SET(MOC_SOURCES) QT5_WRAP_CPP( MOC_SOURCES myDllClass.h ) ADD_LIBRARY(MyDll SHARED myDllClass.h myDllClass.cpp ${MOC_SOURCES} ) GENERATE_EXPORT_HEADER(MyDll)
Then in the header file you need:
#include <mydll_export.h> class MYDLL_EXPORT atgCategoriesManager: public QObject { Q_OBJECT ...
This seems to be the most elegant way if you are working with CMake: the GENERATE_EXPORT_HEADER macro will generate that mydll_export.h file that keeps all that Microsoftish blah-blah, so your real code stays nice, clean and readable.
-
Hi,
Did you follow Qt's documentation about creating shared libraries ?
There should be no problem for QObject based classes.
-
Only way I can think of is through exported C functions which are wrapped around the object calls. This not a elegant but it works.
-
@CoBo
the case you described definitely works as expected.
How does yourMYDLL_EXPORT
macro look like? I guess you just forgot to define the macro which switched between import/export? -
Thanks for your quick replies!
Actually I found and followed that link by SGaist for long - and it did not work for me if the class is derived from QObject.
And answering to raven-worx: I am pretty sure that I did it all as advertised:
In the cpp I have code like
#define DEF_MYDLL #include <myDll.h>
and in the header it looks like this:
#ifdef DEF_MYDLL #define MYDLL_EXPORT Q_DECL_EXPORT #else #define MYDLL_EXPORT Q_DECL_IMPORT #endif class MYDLL_EXPORT myDllClass: public QObject { Q_OBJECT ...
I am pretty sure that this is correct.
Right at this moment I am busy implementing a solution that is similar to what dheerendra is proposing: I generate a "singleton" class in plain C++ in the way as described - with the macro Microsoft blablah. Which so far seems to work: it compiles, links - and I can pass a single "int" value from one DLL to another!
Next step I will try to extend this as kind of a global "singleton class manager": In the main program I generate the different singleton classes and give the pointers to that "manager", and in other DLLs I retrieve the pointers from the manager and do whatever is required. And I guess that in this way I should also be able to handle classes/objects that are derived from QObject - because they will always only reside in the main program.
PS: I have one guess why it might be possible that still both statements are true: "it works" and "it doesn't". I see that my own class is not only derived from QObject, but includes also a static function. It is not defined in the header, so I don't see why there SHOULD be trouble, but maybe the error message is actually wrong: it complains about the "staticMetaObject" (which is a MOC product), but maybe the real root cause is still the fact that there is a static function in the class!?? However, no time yet to check this option.
-
The export of
QObject
works, Qt uses it extensively internally. It also works with custom made libraries see this for an example.The problem you have is that
DEF_MYDLL
should not go in the source or header files with#define DEF_MYDLL
but should be passed to the compiler preprocessors.- In qmake/Qt Creator you can change the .pro file by adding
DEFINES += DEF_MYDLL
and re-running qmake - in CMake add
DEF_MYDLL
to the privatetarget_compile_definitions
, for exampletarget_compile_definitions(myLibrary PRIVATE DEF_MYDLL)
- in Visual Studio right click on the project->properties->C/C++->Preprocessor->Preprocessor Definitions->Edit and append
DEF_MYDLL
to the list (repeat the process for Debug, Release, 32 and 64bit versions using the comboboxes at the top)
Now the point is that I used Google and found MANY mentions of this problem, but bad enough: not one single solution!
If the above solves your problem could you post a link to this topic to the other forums you googled so the next time if someone googles he'll find the solution?
- In qmake/Qt Creator you can change the .pro file by adding
-
@VRonin Wow, that sounds really promising - and I have not seen it mentioned otherwise! Also not tried at this moment, but somehow makes sense.
Although I must say that some of the readings were talking about adding the defines to the qmake configuration, but since I am working with CMake (+QtCreator) this did not look adequate for me.
But since you seem to really understand that issue I have one additional understanding question: If I add the definition to the configuration (be it qmake, cmake or vs) I basically add it either to that specific C++ implementation file (like I do it with the #define...), or I add it to all files - which then "kills" the effect because it will be defined wherever the header is included - no?
What I guess is that "somehow" it has to be made sure that it is also defined in some MOC generated files - and that your method SOMEHOW does this trick!?
Ah, ok: if I do target_compile_definitions(myLibrary PRIVATE DEF_MYDLL) I actually add it to whatever is compiled into that library - and that indeed includes also the "MOC products"...
Right!?
Regarding your last remark I am not sure I will be able to really do it - because after seeing these instructions with the macros so many times - without your important hint! - I did not really keep these links any more...
-
@CoBo said in Export QObject based class from DLL:
Ah, ok: if I do target_compile_definitions(myLibrary PRIVATE DEF_MYDLL) I actually add it to whatever is compiled into that library - and that indeed includes also the "MOC products"
Correct. That's basically equivalent to add
#define DEF_MYDLL
at the top of every header and source file for that target -
Conclusion: problem solved - thanks to the hint of VRonin!
An additional hint I found somewhere else for CMake users. There you can do it as follows:
In the configuration file you need this:
INCLUDE(GenerateExportHeader) SET(MOC_SOURCES) QT5_WRAP_CPP( MOC_SOURCES myDllClass.h ) ADD_LIBRARY(MyDll SHARED myDllClass.h myDllClass.cpp ${MOC_SOURCES} ) GENERATE_EXPORT_HEADER(MyDll)
Then in the header file you need:
#include <mydll_export.h> class MYDLL_EXPORT atgCategoriesManager: public QObject { Q_OBJECT ...
This seems to be the most elegant way if you are working with CMake: the GENERATE_EXPORT_HEADER macro will generate that mydll_export.h file that keeps all that Microsoftish blah-blah, so your real code stays nice, clean and readable.