ChatGPT解决这个技术问题 Extra ChatGPT

How to specify different Debug/Release output directories in QMake .pro file

I have a Qt project and I would like to output compilation files outside the source tree.

I currently have the following directory structure:

/
|_/build
|_/mylib
  |_/include
  |_/src
  |_/resources

Depending on the configuration (debug/release), I will like to output the resulting files inside the build directory under build/debug or build/release directories.

How can I do that using a .pro file?

The way Qt treats debug and release builds internally changed over time. So we discovered that previous working switches between debug and release broke in later versions. See my solution that works on all platforms and on all Qt versions up to now. stackoverflow.com/questions/32046181/…
Since this is an old question it's worth pointing out there are better answers with much fewer votes.

m
mosg

For my Qt project, I use this scheme in *.pro file:

HEADERS += src/dialogs.h
SOURCES += src/main.cpp \
           src/dialogs.cpp

Release:DESTDIR = release
Release:OBJECTS_DIR = release/.obj
Release:MOC_DIR = release/.moc
Release:RCC_DIR = release/.rcc
Release:UI_DIR = release/.ui

Debug:DESTDIR = debug
Debug:OBJECTS_DIR = debug/.obj
Debug:MOC_DIR = debug/.moc
Debug:RCC_DIR = debug/.rcc
Debug:UI_DIR = debug/.ui

It`s simple, but nice! :)


Just what I needed! And a note: To make things even easier to switch around, only define your DESTDIRs conditionally, and then use that value in all your other paths: OBJECTS_DIR = $${DESTDIR}/.obj. Cheers!
Mind explaining how this is used / what it does? It appears to have no effect when I implement it. edit: if i change Debug to debug (lower case) it works. I suspect this is a windows vs unix case sensitivity thing.
I voted it because it works on Windows. On Linux (Ubuntu 15.04, Qt 5.5.0) I had to change Debug to debug and Release to release.
This only works when you only have either release or debug in CONFIG. If both are in config, the latter one will be used.
The supported way of checking for debug and release builds on all platforms is for debug "CONFIG(debug, debug|release)" and for release "CONFIG(release, debug|release)" . Everything else might give you trouble in some cases: In the CONFIG variable, both debug and release can be contained, and the last entry is the one that is valid.
M
Marek R

To change the directory for target dll/exe, use this in your pro file:

CONFIG(debug, debug|release) {
    DESTDIR = build/debug
} else {
    DESTDIR = build/release
}

You might also want to change directories for other build targets like object files and moc files (check qmake variable reference for details or qmake CONFIG() function reference).


But I've found it much nicer to include $$OUT_PWD in this, so DESTDIR=$$OUT_PWD/debug
@Ivo: Ah! Thank you! I've been looking everywhere for which variable contained that path! :D
After this, you can add lines like: OBJECTS_DIR = $$DESTDIR/.obj MOC_DIR = $$DESTDIR/.moc RCC_DIR = $$DESTDIR/.qrc UI_DIR = $$DESTDIR/.ui CONFIG() turns out to solve some problems of using release: and debug:
This one worked better than the selected answer. The selected one works, but if both debug and release are configured, the second block of settings remains.
H
Hello W

I have a more compact approach:

release: DESTDIR = build/release
debug:   DESTDIR = build/debug

OBJECTS_DIR = $$DESTDIR/.obj
MOC_DIR = $$DESTDIR/.moc
RCC_DIR = $$DESTDIR/.qrc
UI_DIR = $$DESTDIR/.ui

Your answer is the more recent way to put compiler build output in separate directory.
have you tried this recently for both debug and release ? my build output always seems to end up in the release folder, no matter which configuration; qmake / Qt Creator behavior might have changed since you posted this answer though...
Try to add "CONFIG -=debug" to the additional arguments of qmake in the Release mode
A
ABCplus

The correct way to do this is the following (thanks QT Support Team):

CONFIG(debug, debug|release) {
    DESTDIR = build/debug
}
CONFIG(release, debug|release) {
    DESTDIR = build/release
}

OBJECTS_DIR = $$DESTDIR/.obj
MOC_DIR = $$DESTDIR/.moc
RCC_DIR = $$DESTDIR/.qrc
UI_DIR = $$DESTDIR/.u

More info here: https://wiki.qt.io/Qt_project_org_faq#What_does_the_syntax_CONFIG.28debug.2Cdebug.7Crelease.29_mean_.3F_What_does_the_1st_argument_specify_and_similarly_what_is_the_2nd_.3F


S
Sulla

I use the same method suggested by chalup,

ParentDirectory = <your directory>

RCC_DIR = "$$ParentDirectory\Build\RCCFiles"
UI_DIR = "$$ParentDirectory\Build\UICFiles"
MOC_DIR = "$$ParentDirectory\Build\MOCFiles"
OBJECTS_DIR = "$$ParentDirectory\Build\ObjFiles"

CONFIG(debug, debug|release) { 
    DESTDIR = "$$ParentDirectory\debug"
}
CONFIG(release, debug|release) { 
    DESTDIR = "$$ParentDirectory\release"
}

h
hyde

Old question, but still worth an up-to-date answer. Today it's common to do what Qt Creator does when shadow builds are used (they are enabled by default when opening a new project).

For each different build target and type, the right qmake is run with right arguments in a different build directory. Then that is just built with simple make.

So, imaginary directory structure might look like this.

/
|_/build-mylib-qt5-mingw32-debug
|_/build-mylib-qt5-mingw32-release
|_/build-mylib-qt4-msvc2010-debug
|_/build-mylib-qt4-msvc2010-release
|_/build-mylib-qt5-arm-debug
|_/build-mylib-qt5-arm-release
|_/mylib
  |_/include
  |_/src
  |_/resources

And the improtant thing is, a qmake is run in the build directory:

cd build-mylib-XXXX
/path/to/right/qmake ../mylib/mylib.pro CONFIG+=buildtype ...

Then it generates makefiles in build directory, and then make will generate files under it too. There is no risk of different versions getting mixed up, as long as qmake is never run in the source directory (if it is, better clean it up well!).

And when done like this, the .pro file from currently accepted answer is even simpler:

HEADERS += src/dialogs.h
SOURCES += src/main.cpp \
           src/dialogs.cpp

Works fine for a single project, but what about if you have a project and a library? Then you need a buildtype-dependent way of including the library afaics.
@Adversus I'm not sure what exactly you mean, but perhaps Qmake variable $(OUT_PWD) is solution?
When I apply my question to your example it becomes: what is the cleanest way for an application to pick up mylib? I'd like it if there would be a "graceful" way to do this, I don't see a way other than using the techniques from the other answers: use the build type and config to fill up LIBS in a smart way, nullifying the advantage of the shadow build.
@Adversus If mylib is subdir project under same top level project, I would usually add a mylib.pri file, and put everything other subdir projects need there, using Qmake variables to get paths right always, even if it is shadow build. Then other subdir .pro files would simply have include(../mylib/mylib.pri)
thanks, that's kind of what I'm doing now, would've been nice to have a solution where this is auto-taken care of, like when you have a project with subprojects in cmake and can then easily make different out-of-source builds of the whole tree.
K
Kuba hasn't forgotten Monica

The short answer is: you don't.

You should run qmake followed by make in whatever build directory you want to build in. So, run it once in a debug directory, once in a release directory.

That's how anyone building your project would expect it to work, and that's how Qt itself is set up to build, that's also how Qt Creator expects your .pro file to behave: it simply starts qmake and then make in the build folder for your target's chosen configuration.

If you wish to create these folders and perform the two (or more) builds in them, you'll need a top-level makefile, possibly created from a top-level project file via qmake.

It's not uncommon to have more than two build configurations, so you're unnecessarily committing yourself to only differentiating between a build and a release; you might have builds with different optimization levels, etc. The debug/release dichotomy is best left to rest in peace.


Nothing like CMake's cmake -B build-dir?
qmake is like cmake without -B: you first cd into the desired build directory, then run it there :) Also, it's generally terrible and there's no need for it: cmake or bust :)
Completely agree on part 2
This is not correct answer, you can and it IS expected. Otherwise it's some homemade project, not a production environment. In industry it IS expected to have output outside of source files directory, because it of VCS software, team integration, etc.
@Kubahasn'tforgottenMonica The only thing I've ever seen cmake do in practice that other build systems don't is increase training time for our new hires because it's so darn verbose. Also, there's good reasons to use cmake but 90% of the time I see teams invest time in making a switch to it, it's not for one of those reasons; it's because they didn't know how to use their previous build system and read that cmake solved all their problems. :)
S
Steve Besch

It's also useful to have a slightly different name for the output executable. You can't use something like:

release: Target = ProgramName
debug: Target = ProgramName_d

Why it doesn't work is not clear, but it does not. But:

CONFIG(debug, debug|release) {
    TARGET = ProgramName
} else {
    TARGET = ProgramName_d
}

This does work as long as the CONFIG += line precedes it.


B
BuvinJ

The new version of Qt Creator also has a "profile" build option between debug and release. Here's how I'm detecting that:

CONFIG(debug, debug|release) {  DEFINES += DEBUG_MODE }
else:CONFIG(force_debug_info) { DEFINES += PROFILE_MODE }
else {                          DEFINES += RELEASE_MODE }

A
Ahmed Rashed

This is my Makefile for different debug/release output directories. This Makefile was tested successfully on Ubuntu linux. It should work seamlessly on Windows provided that Mingw-w64 is installed correctly.

ifeq ($(OS),Windows_NT)
    ObjExt=obj
    mkdir_CMD=mkdir
    rm_CMD=rmdir /S /Q
else
    ObjExt=o
    mkdir_CMD=mkdir -p
    rm_CMD=rm -rf
endif

CC     =gcc
CFLAGS =-Wall -ansi
LD     =gcc

OutRootDir=.
DebugDir  =Debug
ReleaseDir=Release


INSTDIR =./bin
INCLUDE =.

SrcFiles=$(wildcard *.c)
EXEC_main=myapp

OBJ_C_Debug   =$(patsubst %.c,  $(OutRootDir)/$(DebugDir)/%.$(ObjExt),$(SrcFiles))
OBJ_C_Release =$(patsubst %.c,  $(OutRootDir)/$(ReleaseDir)/%.$(ObjExt),$(SrcFiles))

.PHONY: Release Debug cleanDebug cleanRelease clean

# Target specific variables
release: CFLAGS += -O -DNDEBUG
debug:   CFLAGS += -g

################################################
#Callable Targets
release: $(OutRootDir)/$(ReleaseDir)/$(EXEC_main)
debug:   $(OutRootDir)/$(DebugDir)/$(EXEC_main)

cleanDebug:
    -$(rm_CMD) "$(OutRootDir)/$(DebugDir)"
    @echo cleanDebug done

cleanRelease:
    -$(rm_CMD) "$(OutRootDir)/$(ReleaseDir)"
    @echo cleanRelease done

clean: cleanDebug cleanRelease
################################################

# Pattern Rules
# Multiple targets cannot be used with pattern rules [https://www.gnu.org/software/make/manual/html_node/Multiple-Targets.html]
$(OutRootDir)/$(ReleaseDir)/%.$(ObjExt): %.c | $(OutRootDir)/$(ReleaseDir)
    $(CC) -I$(INCLUDE) $(CFLAGS) -c $< -o"$@"

$(OutRootDir)/$(DebugDir)/%.$(ObjExt):   %.c | $(OutRootDir)/$(DebugDir)
    $(CC) -I$(INCLUDE) $(CFLAGS) -c $< -o"$@"

# Create output directory
$(OutRootDir)/$(ReleaseDir) $(OutRootDir)/$(DebugDir) $(INSTDIR):
    -$(mkdir_CMD) $@

# Create the executable
# Multiple targets [https://www.gnu.org/software/make/manual/html_node/Multiple-Targets.html]
$(OutRootDir)/$(ReleaseDir)/$(EXEC_main): $(OBJ_C_Release)
$(OutRootDir)/$(DebugDir)/$(EXEC_main):   $(OBJ_C_Debug)
$(OutRootDir)/$(ReleaseDir)/$(EXEC_main) $(OutRootDir)/$(DebugDir)/$(EXEC_main):
    $(LD) $^ -o$@

u
user2189731

Not sure if anyone will face issues like me, but I'd share my setup. I use a central proj.pri file to store general settings. I have PKG.pro in each subdirs which is already designed for debug mode. So when I try to build both debug and release, I don't want to modify every PKG.pro in each subdir. I added same

DESTDIR = $${SOMEOTHERPATH}
release: DESTDIR = $${DESTDIR}/release
debug:   DESTDIR = $${DESTDIR}/debug

OBJECTS_DIR = $$DESTDIR/.obj
MOC_DIR = $$DESTDIR/.moc
RCC_DIR = $$DESTDIR/.qrc
UI_DIR = $$DESTDIR/.ui

which doesn't work since in each subdir, DESTDIR will get evaluated again. it ends a double debug or release. To avoid this, you have to use only one DESTDIR set, then in each subdir, you can include this proj.pri file. This way, you don't need to write one DIR setup. And "qmake CONFIG=debug" or "qmake CONFIG=release" is needed to build debug or release. Anyone has better solution, please share.


关注公众号,不定期副业成功案例分享
Follow WeChat

Success story sharing

Want to stay one step ahead of the latest teleworks?

Subscribe Now