Unresolved External Symbols Because of __declspec
-
I use MSVC 2014, MinGw-w64 4.2.0 and Qt 5.6.0 and qmake for creating my build Makefiles.
My project consists of several .dll files and depends itself on 3rd party dlls. I would like to declare a class in one of my dlls that inherits from QObject and from another class from one of the 3rd party dlls.
If I add "__declspec(dllexport)" to some methods of my class, build the dll and link other dlls against that dll, I get the following linker errors:
... unresolved external symbol ... MyClass::metaObject(void)const...
... unresolved external symbol ... MyClass::qt_metacast(char const *)...
... unresolved external symbol ... MyClass::qt_metacall(enum QMetaObject::Call,int,void * *)...This seems to have nothing to do with my project configuration (build.pro), since when I add "__declspec(dllexport)" to the class instead of some of its methods, the linker errors disappear. To make it clear:
This snippet leads to the linker error:
class MyClass: public QObject, ...
{
Q_OBJECTpublic:
__declspec(dllexport) MyClass();
...
while this snippet works great:
class __declspec(dllexport) MyClass: public QObject, ...
{
Q_OBJECTpublic:
MyClass();
...
Therefore it seems to me as if the respective symbols "metaObject", "qt_metacast" and "qt_metacall" are not exported from the dll as long as I do not tell the compiler to export the whole class. This annoys me, since it might be impossible to export the whole class. Let's assume that it inherits from another 3rd party dll class which is not completely exported, but has just some exported methods. In this case I cannot export the whole child class as far as I know. The only thing I can do is selectively export child class methods. But in this case these linker errors appear, since the Qt symbols are not exported.
Am I understanding the issue correctly? What is the standard way to deal with that? Is there an easy way to not export the whole class, but to export the Qt symbols?
Thank you very much!
-
hi
Its not an option to use
http://doc.qt.io/qt-5/plugins-howto.html
The Low-Level API: Extending Qt Applicationsand use interfaces classes?
-
Hi,
Export/import declaration are a bit more complex than that. See the Creating Shared Libraries chapter of Qt's documentation.
-
@mrjj Thanks for your reply, but I guess this is no option, if I have understood you correctly. The exact type hierarchy is necessary, since I want to use the classes inside a given framework. But on the other hand... perhaps another class could emit the Qt signal, therefore I could perhaps simplify my type hierarchies... I will think about it. Thank you!
-
@Bihlerben
You have to export the whole class, how else the members generated by themoc
(theQ_OBJECT
macro) will be found? Additionally, only your public members are exported from the class, so this begs the question, why would you want to export only some of the public methods?And a note: Exporting symbols is only relevant for Windows, on Linux
Q_DECL_EXPORT
would simply expand to nothing. Linux exports the whole public interface of the class by default.Note 2:
You should useQ_DECL_EXPORT
andQ_DECL_IMPORT
wrapped in the preprocessorifdef
(as in the link @SGaist sourced), so when including the headers from the user application/libarary you get the__declspec(dllimport)
specifier, which is required for Windows. -
Hi,
@kshegunov said:
You have to export the whole class, how else the members generated by the
moc
(theQ_OBJECT
macro) will be found?@Bihlerben said:
it seems to me as if the respective symbols "metaObject", "qt_metacast" and "qt_metacall" are not exported from the dll as long as I do not tell the compiler to export the whole class.
That's correct, for classes that inherit QObject.
To clarify @kshegunov's post, the
Q_OBJECT
macro expansion includes additional members likemetaObject
,qt_metacast
, etc.. If you don't export the class, then these members don't get exported since you can't add__declspec
to the individual members.This annoys me, since it might be impossible to export the whole class. Let's assume that it inherits from another 3rd party dll class which is not completely exported
Are you planning to create a class that mulitply-inherits a partially-exported 3rd party class as well as QObject?
-
-
Just a small remark: if I have understood it correctly, also g++ has introduced visibility that allows preventing export of all members (search for gcc and visibility).
Yes, the feature had been around for ages. However, by default (as I mentioned before) you have full visibility. Additionally, this is supported in Qt through
Q_DECL_HIDDEN
not byQ_DECL_EXPORT
/Q_DECL_IMPORT
.Also, by the way, I don't see a reason for you not to be able to derive from multiple types (not that it's a good practice), and why hiding part of the interface would be important.
-
@kshegunov My explanation was bad (the topic is quite complicated for my poor brains).
A better explanation is this:
I use Open CASCADE, a free CAD kernel. They have some sophisticated RTTI mechanisms which they implement with macros. Now these macros sometimes add an export hint to the methods defined by themselves (like DEFINE_STANDARD_RTTIEXT for those who know it). This is okay, since in Open CASCADE classes are never completely exported, but only methods are exported.Now I want to subclass Open CASCADE classes and I want to use their macros to have the RTTI mechanisms available. But if I export my whole subclass and the macro adds export hints to the macro-defined methods, MSVC gives error C2487 "member of dll interface class may not be declared with dll interface". I have not found a way to suppress this.
-
@Bihlerben
Then, delegate the interface. You're not required to subclass both classes anyways. For example hold a reference to one of the CAD classes in yourQObject
objects and inline the calls you're going to use, or better yet have an access method that returns the CAD object.class SomeCadClassThatComesFromDll; class MyQObjectDelegatingToCAD : public QObject { Q_OBJECT public: MyQObject(int someParameterForInitialization, QObject * parent = NULL) : QObject(parent), cadObjectInstance(someParameterForInitialization) { } SomeCadClassThatComesFromDll & cadObject() { return cadObjectInstance; } const SomeCadClassThatComesFromDll & cadObject() const { return cadObjectInstance; } private: SomeCadClassThatComesFromDll cadObjectInstance; };
-
This is also what I had meant with "simplifying the type hierarchy".
If you ask me, this should be the preferred approach anyway. I particularly dislike the idea of having multiple-inheritance, especially when there doesn't seem to be a good reason for it.