So geben Sie verschiedene Debug / Release-Ausgabeverzeichnisse in der QMake .pro-Datei an

106

Ich habe ein Qt-Projekt und möchte Kompilierungsdateien außerhalb des Quellbaums ausgeben.

Ich habe derzeit die folgende Verzeichnisstruktur:

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

Abhängig von der Konfiguration (Debug / Release) möchte ich die resultierenden Dateien im Build-Verzeichnis unter den Verzeichnissen build / debug oder build / release ausgeben.

Wie kann ich das mit einer .pro-Datei machen?

Etienne Savard
quelle
Die Art und Weise, wie Qt Debug- und Release-Builds behandelt, hat sich im Laufe der Zeit intern geändert. Daher haben wir festgestellt, dass frühere funktionierende Wechsel zwischen Debug und Release in späteren Versionen fehlgeschlagen sind. Sehen Sie sich meine Lösung an, die bisher auf allen Plattformen und auf allen Qt-Versionen funktioniert. stackoverflow.com/questions/32046181/…
adlag
2
Da dies eine alte Frage ist, sollte darauf hingewiesen werden, dass es bessere Antworten mit viel weniger Stimmen gibt.
Wardw

Antworten:

5

Die kurze Antwort lautet: Sie nicht .

Sie sollten qmakegefolgt von dem makeBuild-Verzeichnis ausführen, in das Sie erstellen möchten. Führen Sie es also einmal in einem debugVerzeichnis und einmal in einem releaseVerzeichnis aus.

So würde jeder, der Ihr Projekt erstellt, erwarten, dass es funktioniert, und so ist Qt selbst für die Erstellung eingerichtet. So erwartet Qt Creator auch, dass sich Ihre .proDatei verhält: Sie startet einfach qmakeund befindet sich dann makeim Erstellungsordner für die von Ihrem Ziel ausgewählte Konfiguration.

Wenn Sie diese Ordner erstellen und die zwei (oder mehr) Builds in ihnen ausführen möchten, benötigen Sie ein Makefile der obersten Ebene, das möglicherweise über qmake aus einer Projektdatei der obersten Ebene erstellt wurde.

Es ist nicht ungewöhnlich, dass mehr als zwei Build-Konfigurationen vorhanden sind. Sie verpflichten sich daher unnötig, nur zwischen einem Build und einem Release zu unterscheiden. Möglicherweise haben Sie Builds mit unterschiedlichen Optimierungsstufen usw. Die Dichotomie zwischen Debug und Release lässt sich am besten in Ruhe.

Stellen Sie Monica wieder her
quelle
151

Für mein Qt-Projekt verwende ich dieses Schema in der * .pro-Datei:

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

Es ist einfach, aber schön! :) :)

mosg
quelle
18
Genau das, was ich brauchte! Und ein Hinweis: Um das Umschalten noch einfacher zu gestalten, definieren Sie Ihr DESTDIRs nur bedingt und verwenden Sie diesen Wert dann in allen anderen Pfaden : OBJECTS_DIR = $${DESTDIR}/.obj. Prost!
Xavier Holt
4
Möchten Sie erklären, wie dies verwendet wird / was es tut? Es scheint keine Wirkung zu haben, wenn ich es implementiere. Bearbeiten: Wenn ich Debug in Debug (Kleinbuchstaben) ändere, funktioniert es. Ich vermute, dies ist eine Sache zwischen Windows und Unix.
Notlesh
9
Ich habe dafür gestimmt, weil es unter Windows funktioniert. Unter Linux (Ubuntu 15.04, Qt 5.5.0) musste ich Debugauf debugund Releaseum wechseln release.
Jepessen
Wth? So viel zu plattformübergreifend? @Jepessen ??
Nils
2
Dies funktioniert nur, wenn Sie nur entweder CONFIG freigegeben oder debuggt haben. Wenn beide in der Konfiguration sind, wird die letztere verwendet.
Weeska
52

Verwenden Sie dies in Ihrer Pro-Datei, um das Verzeichnis für die Ziel-DLL / Exe zu ändern:

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

Möglicherweise möchten Sie auch Verzeichnisse für andere Build-Ziele wie Objektdateien und MOC-Dateien ändern ( Details finden Sie unter qmake-Variablenreferenz oder qmake CONFIG () -Funktionsreferenz ).

Chalup
quelle
5
Aber ich fand es viel schöner, $$ OUT_PWD darin aufzunehmen, also DESTDIR = $$ OUT_PWD / debug
Ivo
1
@ Ivo: Ah! Danke dir! Ich habe überall gesucht, welche Variable diesen Pfad enthält! : D
Cameron
1
Danach können Sie Zeilen hinzufügen wie: Es OBJECTS_DIR = $$DESTDIR/.obj MOC_DIR = $$DESTDIR/.moc RCC_DIR = $$DESTDIR/.qrc UI_DIR = $$DESTDIR/.ui CONFIG()stellt sich heraus, einige Probleme bei der Verwendung von release:unddebug:
Carson Ip
Dieser funktionierte besser als die ausgewählte Antwort. Die ausgewählte Funktion funktioniert, aber wenn sowohl Debug als auch Release konfiguriert sind, bleibt der zweite Einstellungsblock erhalten.
Paulo Carvalho
42

Ich habe einen kompakteren Ansatz:

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

OBJECTS_DIR = $$DESTDIR/.obj
MOC_DIR = $$DESTDIR/.moc
RCC_DIR = $$DESTDIR/.qrc
UI_DIR = $$DESTDIR/.ui
Hallo W.
quelle
2
Ihre Antwort ist die neuere Methode, um die Compiler-Build-Ausgabe in einem separaten Verzeichnis abzulegen.
SIFE
1
Haben Sie dies kürzlich sowohl für das Debuggen als auch für das Release versucht? Meine Build-Ausgabe scheint immer im Release-Ordner zu landen, unabhängig von der Konfiguration. qmake / Qt Creator Verhalten hat sich möglicherweise geändert, seit Sie diese Antwort gepostet haben ...
ssc
1
Versuchen Sie, "CONFIG - = debug" zu den zusätzlichen Argumenten von qmake im Release-Modus hinzuzufügen
Hallo W
13

Ich benutze die gleiche Methode, die von Chalup vorgeschlagen wurde.

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"
}
Sulla
quelle
12

Alte Frage, aber dennoch eine aktuelle Antwort wert. Heutzutage ist es üblich, das zu tun, was Qt Creator tut, wenn Schattenbuilds verwendet werden (diese werden standardmäßig beim Öffnen eines neuen Projekts aktiviert).

Für jedes unterschiedliche Build-Ziel und jeden unterschiedlichen Build-Typ wird das Recht qmakemit den richtigen Argumenten in einem anderen Build-Verzeichnis ausgeführt. Dann wird das einfach mit einfach gebaut make.

Die imaginäre Verzeichnisstruktur könnte also so aussehen.

/
|_/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

Und das Wichtigste ist, dass a qmakeim Build-Verzeichnis ausgeführt wird:

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

Dann generiert es Makefiles im Build-Verzeichnis und makegeneriert auch Dateien darunter. Es besteht kein Risiko, dass verschiedene Versionen verwechselt werden, solange qmake nie im Quellverzeichnis ausgeführt wird (wenn ja, bereinigen Sie es besser!).

Und wenn dies so gemacht wird, ist die .proDatei aus der aktuell akzeptierten Antwort noch einfacher:

HEADERS += src/dialogs.h
SOURCES += src/main.cpp \
           src/dialogs.cpp
Hyde
quelle
Funktioniert gut für ein einzelnes Projekt, aber was ist, wenn Sie ein Projekt und eine Bibliothek haben? Dann benötigen Sie eine vom Buildtyp abhängige Methode zum Einbeziehen der Bibliotheks-Afaics.
Adversus
@Adversus Ich bin nicht sicher, was genau du meinst, aber vielleicht ist Qmake Variable $(OUT_PWD)eine Lösung?
Hyde
Wenn ich meine Frage auf Ihr Beispiel anwende, lautet die Frage: Wie kann eine Anwendung am saubersten aufgenommen werden mylib? Ich würde es mögen, wenn es einen "anmutigen" Weg gäbe, dies zu tun. Ich sehe keinen anderen Weg als die Techniken aus den anderen Antworten zu verwenden: Verwenden Sie den Build-Typ und die Konfiguration, um auf LIBSintelligente Weise zu füllen und aufzuheben der Vorteil des Schattenbaus.
Adversus
@Adversus Wenn mylib ein Subdir-Projekt unter demselben Top-Level-Projekt ist, füge ich normalerweise eine mylib.pri-Datei hinzu und platziere alles, was andere Subdir-Projekte benötigen, dort, wobei Qmake-Variablen verwendet werden, um Pfade immer richtig zu machen, selbst wenn es sich um Schattenerstellung handelt. Dann hätten andere Subdir .pro-Dateien einfachinclude(../mylib/mylib.pri)
hyde
danke, das ist genau das, was ich jetzt mache. Es wäre schön gewesen, eine Lösung zu haben, bei der dies automatisch erledigt wird, beispielsweise wenn Sie ein Projekt mit Teilprojekten in cmake haben und dann leicht andere Ergebnisse erzielen können. Quell-Builds des gesamten Baumes.
Adversus
3

Es ist auch nützlich, einen etwas anderen Namen für die ausführbare Ausgabedatei zu haben. Sie können so etwas nicht verwenden:

release: Target = ProgramName
debug: Target = ProgramName_d

Warum es nicht funktioniert, ist nicht klar, aber es funktioniert nicht. Aber:

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

Dies funktioniert so lange, wie die CONFIG +=Zeile davor steht.

Steve Besch
quelle
1

Die neue Version von Qt Creator verfügt außerdem über eine "Profil" -Erstellungsoption zwischen Debug und Release. So erkenne ich das:

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

1. Suchen Sie Debug / Release in CONFIG

Holen Sie sich die aktuelle (Debug | Release).

specified_configs=$$find(CONFIG, "\b(debug|release)\b")
build_subdir=$$last(specified_configs)

(Kann mehrfach sein, also nur das zuletzt im Build angegebene beibehalten):

2. Stellen Sie DESTDIR ein

Verwenden Sie es hat den Build-Unterverzeichnisnamen

DESTDIR = $$PWD/build/$$build_subdir
automorph
quelle
0

Dies ist mein Makefile für verschiedene Debug- / Release-Ausgabeverzeichnisse. Dieses Makefile wurde erfolgreich unter Ubuntu Linux getestet. Es sollte nahtlos unter Windows funktionieren, vorausgesetzt, Mingw-w64 ist korrekt installiert.

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$@
Ahmed Rashed
quelle