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

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.

    1. I have a base class, Base, and two classes derived from it, Derived1 & Derived2.

    2. All three of these classes already derived from QObject, and already had Q_OBJECT macro in .h files. So it's not an issue about adding Q_OBJECT, which I know does require re-running qmake. Everything was working.

    3. I added to Base two virtual methods, method1() & method2(). Note that these are virtual but not pure virtual, so Base has default method body for both.

    4. Both Derived1 & Derived2 have overrides of method1(). Calling method1() on either worked fine.

    5. Derived1 also overrides method2(). Calling that worked fine.

    6. But Derived2 does not override method2(), it is happy for Base::method2() to be called.

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

    8. 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 not override that requires me to realize I need to delete all previously-built files and re-run qmake??!!


  • Lifetime Qt Champion

    @JonB I don't think this is related to qmake. Deleting object files and building would probably have fixed the issue.



  • @jsulm
    OK, forget the qmake. 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?


  • Lifetime Qt Champion

    @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:

    1. I added the new virtual to Base.cpp & Base.h. So that file must get recompiled, presumably OK.

    2. In Derived1.cpp & Derived1.h I chose to write an override, so that file must get recompiled, presumably OK.

    3. However, in Derived2.cpp & Derived2.h I do not make any change, since it does not override. This must be the problem, somehow?

    4. 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 to cmake, so that's just how it is with qmake and devs won't care now?


  • Moderators

    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.


  • Lifetime Qt Champion

    @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 a Makefile 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 my Derived2 class which segmented when called/needed rebuilding. ../src/uiutils.h contains my Base class, where I added the virtual 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 own overrides 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".....


  • Lifetime Qt Champion

    @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 the moc file, that is what gets generated off form1040.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 the virtual 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 by qmake 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 ;-)


  • Lifetime Qt Champion

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


Log in to reply