Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

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.


  • Lifetime Qt Champion

    Hi,

    Did you follow Qt's documentation about creating shared libraries ?

    There should be no problem for QObject based classes.


  • Qt Champions 2017

    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.


  • Moderators

    @CoBo
    the case you described definitely works as expected.
    How does your MYDLL_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 private target_compile_definitions, for example target_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?



  • @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.


Log in to reply