Unsolved When do you actually need to re-run qmake (or force recompilation)?
-
[EDIT In view of responses below, this question should probably be "When do you need to delete object files/force rebuild compilation?" rather than actually re-run
qmake
.]Having previously advised others to periodically clean out build directory and re-run
qmake
from Creator when "odd" things happen, I'd like to understand if there is any rule to this or whether it's black-magic/trial-and-error?I returned to my code this morning, not quite remembering what I had done last night, to be confronted with nasty behaviour.
-
I have a base class,
Base
, and two classes derived from it,Derived1
&Derived2
. -
All three of these classes already derived from
QObject
, and already hadQ_OBJECT
macro in.h
files. So it's not an issue about addingQ_OBJECT
, which I know does require re-runningqmake
. Everything was working. -
I added to
Base
twovirtual
methods,method1()
&method2()
. Note that these arevirtual
but notpure virtual
, soBase
has default method body for both. -
Both
Derived1
&Derived2
haveoverride
s ofmethod1()
. Callingmethod1()
on either worked fine. -
Derived1
alsooverride
smethod2()
. Calling that worked fine. -
But
Derived2
does notoverride
method2()
, it is happy forBase::method2()
to be called. -
Upon the outside world calling
derived2->method2()
I was confronted with (Linux)SIGSEGV
, at the calling line. I scratched my head and tried various changes, with rebuilds, for an hour, no change. -
Eventually I had a brainwave/desperation. I deleted all files from build directory, re-ran
qmake
, and lo and behold, everything now works again!
So my question is: what is it about adding a
virtual
method to a base class which a derived class does notoverride
that requires me to realize I need to delete all previously-built files and re-runqmake
??!! -
-
@JonB I don't think this is related to qmake. Deleting object files and building would probably have fixed the issue.
-
@jsulm
OK, forget theqmake
. What is it about adding a virtual method to a base class which a derived class does not override that requires me to realize I need to delete all previously-built files and re-build??!!I love Qt, but I never had to do this from e.g. Visual Studio. I'm sorry, but this is really nasty behaviour if the user needs to know to do this manually. I'd still like to understand what the pattern is, so that I know what things I might alter in code which will require me to clean out, please?
-
@JonB Maybe the issue was: after adding virtual method to the base class the derived class was not rebuild and then you tried to call the virtual method on the derived class instance - vtable did not contain the pointer to the virtual method -> crash. This could be an issues with how qmake generates Makefiles. Usually derived class code should be rebuilt if base class was changed.
-
OK, I'm going to make a guess, but I'd still appreciate an answer:
-
I added the new
virtual
toBase.cpp
&Base.h
. So that file must get recompiled, presumably OK. -
In
Derived1.cpp
&Derived1.h
I chose to write anoverride
, so that file must get recompiled, presumably OK. -
However, in
Derived2.cpp
&Derived2.h
I do not make any change, since it does notoverride
. This must be the problem, somehow? -
I call
derived1->method2()
&derived2->method2()
form some other outside-world file. That gets recompiled, presumably OK.
Because in #3
Derived2.cpp
&Derived2.h
needed recompiling but did not get recompiled, that is why I crashed??But
Derived2.cpp
&Derived2.h
does#include
Base.h
, so it should have gotten recompiled, but didn't? Dependencies not being properly dealt with?? If so, NASTY :( -
-
@jsulm said in When do you actually need to re-run qmake?:
@JonB Maybe the issue was: after adding virtual method to the base class the derived class was not rebuild and then you tried to call the virtual method on the derived class instance - vtable did not contain the pointer to the virtual method -> crash. This could be an issues with how qmake generates Makefiles. Usually derived class code should be rebuilt if base class was changed.
Your post has crossed with the one I have just posted. Would you be kind enough to read through what I have just itemized, I suspect we are saying the same thing?
Is this a
qmake
issue then? Did I hear that Qt6 is abandoning and moving tocmake
, so that's just how it is withqmake
and devs won't care now? -
My first question is this: Can you reproduce this problem? (In other words, can you create a new project, and follow the steps in your original post to produce a
SIGSEGV
)?If so, then you can track down the culprit without relying on guesswork.
@JonB said in When do you actually need to re-run qmake?:
Is this a
qmake
issue then?We don't have enough info to say for sure.
It could be that qmake is generating a faulty Makefile.
It could be that your PC clock changed between your builds (perhaps NTP syncing activated and produced a big time jump) -- this would mess up your build system's dependency checks.
I deleted all files from build directory, re-ran
qmake
Once you've deleted the build directory, you don't need to manually run
qmake
. You've already deleted the Makefile, so qmake will need to automatically run to re-create the Makefile -- nothing can be compiled otherwise. -
@JonB said in When do you actually need to re-run qmake?:
so it should have gotten recompiled, but didn't?
I don't know, I don't have the build log :-)
"However, in Derived2.cpp & Derived2.h I do not make any change, since it does not override. This must be the problem, somehow?" - I guess so, yes. It should has been recompiled after Base.* changes.
-
@JKSH said in When do you actually need to re-run qmake?:
My first question is this: Can you reproduce this problem? (In other words, can you create a new project, and follow the steps in your original post to produce a SIGSEGV)?
Point taken. But I just don't have time/will now, have spent enough time this morning to get back to a working executable :( I will bear this in mind for the future.
What I will say: I retrieved the old
Makefile
prior to delete from the waste basket, and compared it against the newly generated one. Identical. So not aMakefile
issue.In the
Makefile
I see:moc_form1040.cpp: ../src/form1040.h \ ../src/models/common.h \ ../src/uiutils.h \ moc_predefs.h \ /usr/lib/qt5/bin/moc /usr/lib/qt5/bin/moc $(DEFINES) --include /home/jon/AtH/debug/moc_predefs.h -I/usr/lib/x86_64-linux-gnu/qt5/mkspecs/linux-g++ -I/home/jon/AtH/src -I/usr/include/x86_64-linux-gnu/qt5 -I/usr/include/x86_64-linux-gnu/qt5/QtWidgets -I/usr/include/x86_64-linux-gnu/qt5/QtGui -I/usr/include/x86_64-linux-gnu/qt5/QtCore -I. -I/usr/include/c++/8 -I/usr/include/x86_64-linux-gnu/c++/8 -I/usr/include/c++/8/backward -I/usr/lib/gcc/x86_64-linux-gnu/8/include -I/usr/local/include -I/usr/lib/gcc/x86_64-linux-gnu/8/include-fixed -I/usr/include/x86_64-linux-gnu -I/usr/include ../src/form1040.h -o moc_form1040.cpp
form1040.cpp
/.h
contains myDerived2
class which segmented when called/needed rebuilding.../src/uiutils.h
contains myBase
class, where I added thevirtual
method. So in principle that dependency looks right to me....For now I'll have to settle for a mental note about potential need to delete all object files if I do something like introduce a new
virtual
method, at least where some derivations do not have their ownoverride
s of it.I'll leave this open for a day in case some other Qt expert says "yes, I have observed, you need to do this when that".....
-
@JonB said in When do you actually need to re-run qmake (or force recompilation)?:
moc_form1040.cpp
This is the moc file, what about form1040.cpp?
-
@jsulm
Not 100% sure what you mean. Yes, it's themoc
file, that is what gets generated offform1040.cpp
. It has a rule to generate it, which is what we are interested in;form1040.cpp
will not have a generation rule as it's a source file so it doesn't get generated.Anyway, to keep you happy, here is the rule for
form1040.o
:form1040.o: ../src/form1040.cpp ../src/uiutils.h \ ../src/form1040.h \ ../src/models/common.h \ ui_form1040.h \ ../src/models/form1040model.h $(CXX) -c $(CXXFLAGS) $(INCPATH) -o form1040.o ../src/form1040.cpp
Again, this has correct dependency of
../src/uiutils.h
, which is the header file with thevirtual
function. -
I just perused all the back and forth on this thread, and I just want to provide simple "positive affirmation" to OP.
My team has used
qmake
for several years on different types of projects. Most of us have observed on various occasions that the Makefile(s) generated byqmake
have subtle "holes" where they don't capture all rebuild dependencies in the dependency graph, and it is sometimes (only in "edge cases") necessary to delete build binaries and force a clean rebuild after certain kinds of changes.In another similarity to @JonB - we also have usually not taken the extra effort to extract the problematic edge case into a min repro and report the reproducible bug. It happens infrequently, and (due to lengthy experience with many legacy codebases) I usually have a rapid intuition about it happening and haven't felt that too much of my time was wasted. So the trade-offs (infrequency multiplied by only minor annoyance level) have never led me to track down the exact issue.
Now... (said in a "jesting" tone)... just to make sure there is something in my comments to displease everyone...
Where my experience deviates from OP: I have indeed encountered quite similar issues when working with Visual Studio.
-
@KH-219Design said in When do you actually need to re-run qmake (or force recompilation)?:
All of your post was interesting :)
Where my experience deviates from OP: I have indeed encountered quite similar issues when working with Visual Studio.
Excellent! It's nice to know that all IDEs/builds are messed up :) I want my C# back, I never had these issues...!
On a serious note, I will try to learn that when I don't see what I'm doing wrong, it might be worth trying a rebuild. If I even do so much as look at a
.h
file ;-) -
@JonB Qt6 will use CMake instead of qmake by default as far as I know (though you can use CMake with Qt5) :-)
-
@JonB said in When do you actually need to re-run qmake (or force recompilation)?:
moc_form1040.cpp
This reminds me of a problem I think I might have seen (at least on Windows). Usually, Qt sets up release and debug builds. Also, there are a few things related to shadow builds (having them on or off). What I remember is that the paths to auto-generated Qt files (i.e. moc_.cpp and ui_.h) might not always be consistent. Especially with the ui header files the include path (automatically put in by qmake) might look at one place first before looking in the directory where the newly generated files are located. Not sure if qmake can similarly mess up locations of moc_.cpp files.
At least this would explain that the moc_.cpp gets newly generated (because of dependencies), but then the moc_.cpp gets recompiled from a different directory and this one will then not contain the changes.