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

Qmake debug_and_release conflict in unix makefiles



  • I have the following qmake project which is configured as debug_and_release.
    When I generate the makefiles, I get the following output files.
    The project generated unix makefiles for a shared library.

    Project.pro
    Makefile-linux-x86-g++
    Makefile-linux-x86-g++.Debug
    Makefile-linux-x86-g++.Release
    

    My problems begin when I try to compile the debug version at the same time as the release version.
    I get truncated output files when I compile both versions at the same time.

    I properly set the following variables in order to specify different output directories based on the debug or release configuration:

    • OBJECTS_DIR
    • MOC_DIR
    • UI_HEADERS_DIR
    • RCC_DIR
    • TRANSLATION_DIR
    • DESTDIR

    I ended up finding that the temporary library and its symlinks are created in the current folder before being copied over to the DESTDIR. This creates a clash when the dbg and the rls version of the following targets are executed at the same time:

    all: Makefile-linux-x86-g++.Release  ../../../output/linux-x86-g++/rls/$(TARGET)
    
    ../../../output/linux-x86-g++/rls/$(TARGET):  $(OBJECTS) $(SUBLIBS) $(OBJCOMP)  
    	@$(CHK_DIR_EXISTS) ../../../output/linux-x86-g++/rls/ || $(MKDIR) ../../../output/linux-x86-g++/rls/ 
    	-$(DEL_FILE) $(TARGET) $(TARGET0) $(TARGET1) $(TARGET2)
    	$(LINK) $(LFLAGS) -o $(TARGET) $(OBJECTS) $(LIBS) $(OBJCOMP)
    	-ln -s $(TARGET) $(TARGET0)
    	-ln -s $(TARGET) $(TARGET1)
    	-ln -s $(TARGET) $(TARGET2)
    	-$(DEL_FILE) ../../../output/linux-x86-g++/rls/$(TARGET)
    	-$(DEL_FILE) ../../../output/linux-x86-g++/rls/$(TARGET0)
    	-$(DEL_FILE) ../../../output/linux-x86-g++/rls/$(TARGET1)
    	-$(DEL_FILE) ../../../output/linux-x86-g++/rls/$(TARGET2)
    	-$(MOVE) $(TARGET) $(TARGET0) $(TARGET1) $(TARGET2) ../../../output/linux-x86-g++/rls/
    

    I am using qmake from qt 4.8.4. I looked at the code of qmake in 5.7 and the routine that generates this piece of makefile does the same job as the 4.8.4 version.

    Has anyone found a clean way of specifying a temporary output folder for the link and symlinks commands?

    Thank you!


  • Lifetime Qt Champion

    Hi and welcome to devnet,

    The current method to build projects is rather to use "shadow builds" folders, one for each type of build. This avoids clashes and leaves the source tree clean.



  • Our build system is quite complex and mature. Introducing the concept of shadow builds could be challenging in the short term.

    I didn't find any qmake documentation about shadow build. Would you happen to know a good source of information on how to implement that?

    Another point, when using debug_and_release and shadow build, won't I get the same problem where the debug and the release makefiles will be generated in the same folder and will use it as a temp folder to generate the shared object lib and its symlinks? I understand that the makefiles are going to be generated outside of the source tree, but how would that fix this particular problem?

    Thank you!


  • Lifetime Qt Champion

    Basically:

    mkdir myproject_build_release myproject_build_debug
    pushd myproject_build_release
    qmake ../myproject CONFIG+=release
    make -jX where X = 2 * core + 1
    popd
    pushd myproject_build_debug
    qmake ../myproject CONFIG+=debug
    make -jX where X = 2 * core + 1
    popd
    


  • Just building on what @SGaist said, the basic issue in my opinion is that qmake's DESTDIR default value is platform dependant, and on Linux uses the same directory for both debug and release builds (so those builds clash), whereas, for example it defaults to separate directories on Windows (and Mac OSX if I recall correctly).

    To get around that (and generally provide more consistent output, which helps with CI tests and such), I like to do this in my *.pro files:

    CONFIG(debug,debug|release):  DESTDIR = debug
    CONFIG(release,debug|release):DESTDIR = release
    MOC_DIR = $$DESTDIR/$$TARGET-tmp
    OBJECTS_DIR = $$DESTDIR/$$TARGET-tmp
    RCC_DIR = $$DESTDIR/$$TARGET-tmp
    

    Then, instead of running qmake twice as @SGaist showed above (which works too), I do:

    mkdir myproject_build
    pushd myproject_build
    qmake CONFIG+=debug_and_release ../myproject
    make all
    popd
    

    Of course, the difference is just a matter of personal preference :)

    One small tip: you can skip the pushd and popd commands by using qmake's -o and make's -C options (handy for keeping build scripts neat and tidy) such as:

    mkdir -p some-new-build-dir
    qmake -o some-new-build-dir CONFIG+=debug_and_release project-dir
    make -C some-new-build-dir all
    

    Unfortunately, Windows' nmake.exe has no -C equivalent :(

    Cheers.



  • Thank you guys for your answers!
    Paul, I am already setting the DESTDIR differently for debug and release builds. Unfortunately, The piece of generated makefile I posted doesn't execute in the DESTDIR. It executes where the makefiles were generated, thus the clash in the symlink commands. But thanks for the tips!

    If I understand correctly, if I want to fix this, I need to build release and debug in different makefiles tree using shadow builds.
    This would change the structure of our projects a lot for now. I won't be able to implement that without affecting a whole bunch of other scripts relying on the current build structure. I think that qmake should have used a unique tmp folder for performing this symlink creation operation. This really looks like a bug in the unix makefiles generation for shared objects.

    Thank anyway guys!


Log in to reply