Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. on windows can't export from a dll a class inheriting from QList<QVariant>

on windows can't export from a dll a class inheriting from QList<QVariant>

Scheduled Pinned Locked Moved Solved General and Desktop
10 Posts 2 Posters 2.9k Views
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • lemmelL Offline
    lemmelL Offline
    lemmel
    wrote on last edited by
    #1

    Well in short I can't export from dll symbols that are perfectly valid otherwise.
    I realized an application under Linux:

    • using mostly Qt as library;
    • consisting of several libraries and a main gui application.

    And as I'm making my code compliant to Visual Studio 2015's compiler I stumbled on the following dllexport problem (it is in fact a snipped code):

    #include <QVariant>
    #include <QList>
    
    class SNIPPEDSHARED_EXPORT Snipped : public QList<QVariant>
    {
    
    public:
      Snipped();
    };
    

    SNIPPEDSHARED_EXPORT being the classical:

    #if defined(SNIPPED_LIBRARY)
    #  define SNIPPEDSHARED_EXPORT __declspec(dllexport)
    #else
    #  define SNIPPEDSHARED_EXPORT __declspec(dllimport)
    #endif
    

    That code generating:

    C:\Qt\5.7\msvc2015_64\include\QtCore\qhashfunctions.h:110: erreur : C2665: 'qHash': none of the 22 overloads could convert all the argument types
    C:\Qt\5.7\msvc2015_64\include\QtCore\qhashfunctions.h:110: erreur : C2056: illegal expression
    

    The error message is explicit enough and I even found people that have defined their own qHash:

    • http://www.qtforum.org/article/19733/qmultihash-qvariant-compiler-error-c2665.html
    • http://stackoverflow.com/questions/17208813/qvariant-as-key-in-qhash

    What is troubling me:

    • I'm using QList and not qHash direcly; I'm well aware that QList may use qHash internally but the code runs smoothly with gcc: so it seems that Qt is providing what is required;
    • when I build the exact class in a regular binary (not a library one), all runs perfectly (either windows or linux).
    • when I removed the __declspec, then the library is building perfectly

    I took time to read documentations about exporting templates as it seems the real problem (I even took time to read Qt source code :

    • using Explicit template instantiation: https://anteru.net/blog/2008/11/19/318/ and https://msdn.microsoft.com/en-us/library/by56e477.aspx
    • digging up some history bit: How to export an instantiation of a Standard Template Library (STL) class and a class that contains a data member that is an STL object : https://support.microsoft.com/en-us/kb/168958

    But the described problem doesn't seem to apply. I tried all kind of combinations but none did the trick (and it would have been a fluke).

    The code being so short and simple, I think that I missed something basic (sorry: it is not really an interesting question and it is fustrating).

    Has someone an idea?
    P.S.: Full technical data:

    • Visual Studio 2015 Community Edition, with the last update: 14.0.25424.00 Update 3
    • Visual C++ 2015 00322-20000-00000-AA285
    • Using the Windows Kit 10: 10.0.10586.0
    • creation of an library project through QtCreator:
      • snipped.pro
        QT       -= gui
        TARGET   = snipped
        TEMPLATE = lib
        DEFINES += SNIPPED_LIBRARY
        SOURCES += snipped.cpp
        
      • snipped.cpp
        #include "snipped.h"
        #include <QDebug>
        
        Snipped::Snipped()
        {
          qDebug("Coucou !");/*some code is required otherwise the build will generate nothing*/
        }
        
      • snipped.h
        #ifndef SNIPPED_H
        #define SNIPPED_H
        
        #include "snipped_global.h"
        #include <QVariant>
        #include <QList>
        
        class SNIPPEDSHARED_EXPORT Snipped : public QList<QVariant>
        {
        public:
          Snipped();
        };
        
        #endif // SNIPPED_H
        
      • snipped_global.h
        #ifndef SNIPPED_GLOBAL_H
        #define SNIPPED_GLOBAL_H
        
        #include <QtCore/qglobal.h>
        
        #if defined(SNIPPED_LIBRARY)
        #  define SNIPPEDSHARED_EXPORT __declspec(dllexport)
        #else
        #  define SNIPPEDSHARED_EXPORT __declspec(dllimport)
        #endif
        
        #endif // SNIPPED_GLOBAL_H
        
    1 Reply Last reply
    0
    • VRoninV Offline
      VRoninV Offline
      VRonin
      wrote on last edited by
      #2

      does using QVariantList instead of QList<QVariant> work?

      "La mort n'est rien, mais vivre vaincu et sans gloire, c'est mourir tous les jours"
      ~Napoleon Bonaparte

      On a crusade to banish setIndexWidget() from the holy land of Qt

      1 Reply Last reply
      0
      • lemmelL Offline
        lemmelL Offline
        lemmel
        wrote on last edited by
        #3

        That change nothing (and I did try previously any kind of typedefs :-) ).

        1 Reply Last reply
        0
        • VRoninV Offline
          VRoninV Offline
          VRonin
          wrote on last edited by
          #4

          Ok, the problem is that, QList::toSet() needs qHash to work.
          you just need to declare your own QHash function

          snipped.h:

          #ifndef SNIPPED_H
          #define SNIPPED_H
          
          #include "snipped_global.h"
          #include <QVariant>
          #include <QList>
          
          class SNIPPEDSHARED_EXPORT Snipped : public QList<QVariant>
          {
          public:
            Snipped();
          };
          uint qHash(const QVariant& val,uint seed);
          #endif // SNIPPED_H
          
          

          snipped.cpp

          #include "snipped.h"
          #include <QDebug>
          
          Snipped::Snipped()
          {
            qDebug("Coucou !");/*some code is required otherwise the build will generate nothing*/
          }
          uint qHash(const QVariant& val,uint seed){
              return qHash(&val,seed);
          }
          

          "La mort n'est rien, mais vivre vaincu et sans gloire, c'est mourir tous les jours"
          ~Napoleon Bonaparte

          On a crusade to banish setIndexWidget() from the holy land of Qt

          1 Reply Last reply
          0
          • lemmelL Offline
            lemmelL Offline
            lemmel
            wrote on last edited by
            #5

            Thanks for your time, but I did found such a « solution » (see in my first post) and I keep thinking it is not the right solution.

            Why should I need that ? Why the code builds perfectly if there is no export at all ?
            Why when there is no export the compiler found a qHash implementation ?

            I would really not make « magic code » and then later have bizarre errors (Windows and the dll complexity).

            Furthermore I should have an understanding of the problem, don't you think so ?

            P.S. : I'm be off 2 hours from now.

            1 Reply Last reply
            0
            • VRoninV Offline
              VRoninV Offline
              VRonin
              wrote on last edited by VRonin
              #6

              Why the code builds perfectly if there is no export at all ?

              It does not find it, but if you don't export it doesn't care. Try removing the export but then call Snipped::toSet() somewhere and it will not compile either

              just as much as:

              // This compiles
              class A{
              int a;
              public:
              A():a(0){}
              void noBody();
              void methodA(int val){a=val;}
              }
              
              // This doesn't
              class A{
              int a;
              public:
              A():a(0){}
              void noBody();
              void methodA(int val){a=val; noBody();}
              }
              

              Why when there is no export the compiler found a qHash implementation ?

              No there isn't, see http://doc.qt.io/qt-5/qhash.html, no QVariant there

              « magic code »

              it is not magic code, it's the requirement to make QHash and QSet work. Since there is a generic qHash template for pointers I leveraged it

              "La mort n'est rien, mais vivre vaincu et sans gloire, c'est mourir tous les jours"
              ~Napoleon Bonaparte

              On a crusade to banish setIndexWidget() from the holy land of Qt

              1 Reply Last reply
              0
              • lemmelL Offline
                lemmelL Offline
                lemmel
                wrote on last edited by
                #7

                I don't quite get it; If you are right, then why this code runs perfectly (either on Windows or Linux) :

                • snipped_main
                  QT += core
                  QT -= gui
                  
                  CONFIG += c++11
                  
                  TARGET = snipped_main
                  CONFIG += console
                  CONFIG -= app_bundle
                  
                  TEMPLATE = app
                  
                  SOURCES += main.cpp snipped.cpp
                  HEADERS += snipped.h
                  
                • main.cpp
                  #include <QCoreApplication>
                  #include "snipped.h"
                  
                  int main(int argc, char *argv[])
                  {
                    QCoreApplication a(argc, argv);
                    Snipped toto;
                    toto.append(QString("TOTO"));
                    return EXIT_SUCCESS;//a.exec();
                  }
                  
                • snipped.cpp
                  #include "snipped.h"
                  #include <QDebug>
                  
                  Snipped::Snipped()
                  {
                    qDebug("Coucou !");/*some code is required otherwise the build will generate nothing*/
                  }
                  
                • snipped.h
                  #ifndef SNIPPED_H
                  #define SNIPPED_H
                  
                  #include <QVariant>
                  #include <QList>
                  
                  class Snipped : public QList<QVariant>
                  {
                  public:
                    Snipped();
                  };
                  
                  #endif // SNIPPED_H
                  
                1 Reply Last reply
                0
                • lemmelL Offline
                  lemmelL Offline
                  lemmel
                  wrote on last edited by
                  #8

                  I further tried to use my first example (the one as a library) and altered snipped.cpp:

                  #include "snipped.h"
                  #include <QDebug>
                  
                  Snipped toto;
                  Snipped::Snipped()
                  {
                    qDebug("Coucou !");
                  }
                  

                  and it build too without any problem.

                  I understand the problem of exporting symbols, but why MS compiler needs all methods defined when gcc has no problem or MS compiler even builds the library correctly when there is no export and no call to ::toSet ?

                  1 Reply Last reply
                  0
                  • lemmelL Offline
                    lemmelL Offline
                    lemmel
                    wrote on last edited by
                    #9

                    I found why I had this problem on « Microsoft Specific »: https://msdn.microsoft.com/en-us/library/81h27t8c.aspx
                    I quote:

                    When you declare a class dllexport, all its member functions and static data members are exported. You must provide the definitions of all such members in the same program.  Otherwise, a linker error is generated.
                    

                    And in order to be complete:

                    The one exception to this rule applies to pure virtual functions, for which you need not provide explicit definitions. However, because a destructor for an abstract class is always called by the destructor for the base class, pure virtual destructors must always provide a definition. Note that these rules are the same for nonexportable classes.
                    
                    If you export data of class type or functions that return classes, be sure to export the class.
                    

                    It will teach me not to glance over the documentation.

                    1 Reply Last reply
                    0
                    • lemmelL Offline
                      lemmelL Offline
                      lemmel
                      wrote on last edited by
                      #10

                      Thanks VRonin for your help.
                      Sorry I have insisted, but I always prefer to have « proof ».

                      1 Reply Last reply
                      0

                      • Login

                      • Login or register to search.
                      • First post
                        Last post
                      0
                      • Categories
                      • Recent
                      • Tags
                      • Popular
                      • Users
                      • Groups
                      • Search
                      • Get Qt Extensions
                      • Unsolved