Visual Studio + Qt, compilation abort with 100+ erros
-
You have circular dependencies for sure.
It has nothing to do with Qt at all, but basic C++. Your nodescene.hpp and node.hpp include each other which causes that problem.
By moving the include to a cpp you removed the circular dependency.
-
Hi just guessing but maybe VS2012 is the problem.
When a new version of Qt and Qt Creator is released I need to rebuild an editing plugin I use in Qt Creator, and this involves also first rebuilding Qt Creator itself (takes about 15 minutes).
I also have used VS2012 for this, and up to Qt 5.2.1 this worked flawlessly. But in Qt 5.3 and in Qt 5.3.1 compilations of Qt Creator were aborted with funny errors like "....cpp file doesn't exist".
Then I tried compiling the exact same Qt Creator source with either MinGW or VS2013: no errors. So I've switched to VS2013.
Note: recently I've read somewhere there's supposedly a threading problem in VS2012 (both for RTM and Update 4 versions) that affects jom.exe, and that could be the reason.
So another suggestion for you, try disabling jom.exe in your project settings (and instead fall back to the old nmake.exe). -
hskoglund, I will try that later
ambershark,
They do include each other but both are in #ifndef blocks so she should only include once, right?@
#ifndef NODE_HPP
#define NODE_HPP#include "nodescene.hpp"
//...
#endif
@And the other header
@
#ifndef NODESCENE_HPP
#define NODESCENE_HPP#include "node.hpp"
//...
#endif
@ -
Under a normal include situation then yes the header guard would work like that.
However, in a circular dependency Class A depends on Class B and vice-versa. This causes the circular dependency, even under an ifndef macro.
Here is the "wikipedia page":http://en.wikipedia.org/wiki/Circular_dependency that describes it way better than I could. But you will see that having the interdependency will cause the exact problem you are seeing, even with the header guard.
Basically, the compiler is trying to resolve the declaration of Node to use in NodeScene but then Node immediately tries to resolve what NodeScene is, thus the compiler enters into the circular dependency problem.
To resolve this issue you might need to redesign Node a bit. It shouldn't need to know anything about NodeScene. Having those 2 rely on each other breaks object orientation.
-
Hi,
thanks for the help. I didn't realy knew that include protection doesn't help with this problem. ;) Might have skipped a class the semester we had c++.
However, when it comes to breaking object orientation: QGraphicsItem also knows QGraphicsScene and even has a pointer to its current scene. I actually don't do anything else. My Node-Class is a derivates from QGeraphicsItem and NodeScene from QGraphicsScene. ;) So I don't think there is realy a problem. In some cases objects have to know the context they are in, right?
-
Yea, I was just guessing on the breaking object oriented part. Without seeing the code I wouldn't be able to tell for real. But even then, it's not like you have to follow all the rules all the time. I've had a few classes here and there that should have been designed with more OOP in mind. :)
Anyway, if they need to know about each other what you do is predeclare the class, so like in NodeScene you would remove #include "node.hpp" and do something like this:
@
class Node;class NodeScene
{
....
}
@Then inside the cpp file you #include "node.hpp". This will fix your dependency issues but it also has the side effect of making compilation faster. :) I tend to try to do that all the time.
When you predeclare like that with "class Node;" you can not use the object at all in the hpp. You can use pointers and references but nothing else, for example:
@
class Node;class NodeScene
{
public:
void doSomething(const Node &n); // valid since it uses a reference
void doSomethingBroken(Node n); // invalid, needs to know about Node
Node *getNode() const; // valid
Node getBrokenNode() const; // invalidprivate:
Node *mNode; // valid because it's a pointer
Node mBroken; // invalid since it needs to know about Node
}
@ -
Good advice with predeclaring a "class Node;" I've seen Qt as well uses that a lot, also for another reason, binary compatibility across releases, it's called the "d-pointer pattern":https://qt-project.org/wiki/Dpointer
I've started using that as well in my own library classes, I'm quite new to Qt, should have switched to Qt earlier!
-
That was a good read. I hadn't ever really thought about the purpose behind the d_ptr stuff Qt uses. Knowing that now, I may even redesign some of my public libs (going forward) to use that method of data hiding. Very cool.
As for predeclaring stuff, I mostly just do it to make compilation faster. If a header includes a ton of headers it will slow down compilation big time. So if the headers just have things like class QString; but don't #include <QString> they will build much faster. Then I just #include <QString> in the cpp file. That way only if that particular cpp file changes does it need to deal with header dependencies.
That and on bigger projects I use ninja now instead of make. Which has made me lean more towards cmake instead of qmake for my bigger Qt projects. That way I can use cmake to make ninja files to use. And luckily cmake integrates super well with Qt. Ninja and make are similar in speed for small projects though so I usually use qmake on those.
-
Hi,
thanks for the tip. I didn't realy knew this approach but it should work realy well. I also only work with pointers to Node anyway so I could get around the invalid stuff. ;)
Thanks!
-
Yea, you'll end up using it a ton in C++.
I use it so much it now annoys me when other people working on my code just randomly #include "something.h" in the header rather than using forward declaration. I know it can just causes problems and can of course slows down builds. :)