Jak określić różne katalogi wyjściowe Debug / Release w pliku QMake .pro

106

Mam projekt Qt i chciałbym wyprowadzić pliki kompilacji poza drzewo źródłowe.

Obecnie mam następującą strukturę katalogów:

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

W zależności od konfiguracji (debug / release), chciałbym wyprowadzić pliki wynikowe w katalogu build w katalogach build / debug lub build / release.

Jak mogę to zrobić używając pliku .pro?

Etienne Savard
źródło
Sposób, w jaki Qt traktuje kompilacje debugowania i wydania, zmieniał się wewnętrznie w czasie. Dlatego odkryliśmy, że poprzednie działające przełączniki między debugowaniem a wydaniem nie działały w późniejszych wersjach. Zobacz moje rozwiązanie, które działa na wszystkich platformach i wszystkich dotychczasowych wersjach Qt. stackoverflow.com/questions/32046181/…
adlag
2
Ponieważ jest to stare pytanie, warto zwrócić uwagę, że są lepsze odpowiedzi, na które oddano znacznie mniej głosów.
wardw

Odpowiedzi:

4

Krótka odpowiedź brzmi: nie .

Powinieneś uruchomić, qmakea następnie makew dowolnym katalogu kompilacji, w którym chcesz wbudować. Więc uruchom go raz w debugkatalogu, raz w releasekatalogu.

W ten sposób każdy, kto buduje twój projekt, spodziewałby się, że zadziała, i tak samo Qt jest skonfigurowane do budowania, tak samo Qt Creator oczekuje, że twój .proplik będzie się zachowywał: po prostu uruchamia się, qmakea następnie makew folderze kompilacji dla wybranej konfiguracji celu.

Jeśli chcesz utworzyć te foldery i wykonać w nich dwie (lub więcej) kompilacje, będziesz potrzebować pliku makefile najwyższego poziomu, prawdopodobnie utworzonego z pliku projektu najwyższego poziomu za pomocą qmake.

Nierzadko zdarza się, że istnieje więcej niż dwie konfiguracje kompilacji, więc niepotrzebnie zobowiązujesz się do rozróżnienia tylko między kompilacją a wydaniem; możesz mieć kompilacje z różnymi poziomami optymalizacji itp . Dychotomię debug / release najlepiej pozostawić w spokoju.

Przywróć Monikę
źródło
152

W moim projekcie Qt używam tego schematu w pliku * .pro:

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

To proste, ale przyjemne! :)

mosg
źródło
18
Dokładnie to, czego potrzebowałem! I uwaga: Żeby było jeszcze łatwiej przełączać się dookoła, tylko zdefiniować DESTDIRs warunkowo, a następnie użyć tej wartości we wszystkich innych ścieżek: OBJECTS_DIR = $${DESTDIR}/.obj. Twoje zdrowie!
Xavier Holt
4
Zastanów się, jak to jest używane / co robi? Wydaje się, że nie ma to żadnego skutku, kiedy je wdrażam. edycja: jeśli zmienię debugowanie na debugowanie (małe litery), to działa. Podejrzewam, że jest to kwestia rozróżniania wielkości liter w systemie Windows i unix.
notlesh
9
Głosowałem na to, ponieważ działa w systemie Windows. W systemie Linux (Ubuntu 15.04, Qt 5.5.0) musiałem zmienić Debugna debugi Releasena release.
Jepessen,
Wth? Tyle na wiele platform? @Jepessen ??
Nils
2
Działa to tylko wtedy, gdy w CONFIG masz tylko wydanie lub debugowanie. Jeśli oba są w konfiguracji, zostanie użyty ten drugi.
weeska
52

Aby zmienić katalog docelowy dll / exe, użyj tego w swoim pliku pro:

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

Możesz również chcieć zmienić katalogi dla innych celów kompilacji, takich jak pliki obiektowe i pliki moc (sprawdź opis zmiennej qmake, aby uzyskać szczegółowe informacje, lub odwołanie do funkcji qmake CONFIG () ).

chalup
źródło
5
Ale o wiele przyjemniej jest uwzględnić w tym $$ OUT_PWD, więc DESTDIR = $$ OUT_PWD / debug
Ivo
1
@Ivo: Ach! Dziękuję Ci! Szukałem wszędzie, która zmienna zawierała tę ścieżkę! : D
Cameron
1
Następnie możesz dodać linie takie jak: OBJECTS_DIR = $$DESTDIR/.obj MOC_DIR = $$DESTDIR/.moc RCC_DIR = $$DESTDIR/.qrc UI_DIR = $$DESTDIR/.ui CONFIG()Okazuje się, że rozwiązuje niektóre problemy z używaniem release:idebug:
Carson Ip
Ten działał lepiej niż wybrana odpowiedź. Wybrany działa, ale jeśli skonfigurowane są zarówno debugowanie, jak i wydanie, drugi blok ustawień pozostaje.
Paulo Carvalho
42

Mam bardziej zwarte podejście:

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

OBJECTS_DIR = $$DESTDIR/.obj
MOC_DIR = $$DESTDIR/.moc
RCC_DIR = $$DESTDIR/.qrc
UI_DIR = $$DESTDIR/.ui
Witam W.
źródło
2
Twoja odpowiedź jest nowszym sposobem umieszczenia wyników kompilacji kompilatora w oddzielnym katalogu.
SIFE
1
czy próbowałeś tego ostatnio zarówno dla debugowania, jak i wydania? Wydaje się, że wynik kompilacji zawsze trafia do folderu wydania, niezależnie od konfiguracji; Zachowanie kreatora qmake / Qt mogło ulec zmianie od czasu opublikowania tej odpowiedzi ...
ssc
1
Spróbuj dodać "CONFIG - = debug" do dodatkowych argumentów qmake w trybie wydania
Witaj W
17

Prawidłowy sposób na zrobienie tego jest następujący (dzięki zespołowi wsparcia QT):

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

Więcej informacji tutaj: 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.3_the_2

ABCplus
źródło
13

Używam tej samej metody, którą sugeruje 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"
}
Sulla
źródło
12

Stare pytanie, ale nadal warte aktualnej odpowiedzi. Obecnie często robi się to, co robi Qt Creator, gdy używane są kompilacje w tle (są one domyślnie włączone podczas otwierania nowego projektu).

Dla każdego celu i typu kompilacji prawo qmakejest uruchamiane z właściwymi argumentami w innym katalogu kompilacji. To jest po prostu zbudowane za pomocą prostego make.

Tak więc wyobrażona struktura katalogów może wyglądać tak.

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

Ważną rzeczą jest to, że a qmakejest uruchamiany w katalogu kompilacji:

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

Następnie generuje makefile w katalogu kompilacji, a następnie makegeneruje również pliki w nim. Nie ma ryzyka pomieszania różnych wersji, o ile qmake nigdy nie zostanie uruchomiony w katalogu źródłowym (jeśli tak, to lepiej go wyczyść!).

A kiedy to zrobimy, .proplik z aktualnie zaakceptowanej odpowiedzi jest jeszcze prostszy:

HEADERS += src/dialogs.h
SOURCES += src/main.cpp \
           src/dialogs.cpp
hyde
źródło
Działa dobrze w przypadku pojedynczego projektu, ale co, jeśli masz projekt i bibliotekę? Następnie potrzebny jest sposób uwzględnienia afaics biblioteki, zależny od typu kompilacji.
Adversus
@Adversus Nie jestem pewien, co dokładnie masz na myśli, ale może zmienna Qmake $(OUT_PWD)jest rozwiązaniem?
hyde
Kiedy odnoszę moje pytanie do twojego przykładu, brzmi: jaki jest najczystszy sposób na odebranie wniosku mylib? Chciałbym, żeby istniał „wdzięczny” sposób na zrobienie tego, nie widzę innego sposobu niż użycie technik z innych odpowiedzi: użyj typu kompilacji i konfiguracji, aby wypełnić LIBSw inteligentny sposób, niwelując Zaleta budowy cienia.
Adversus
@Adversus Jeśli mylib jest projektem subdir w tym samym projekcie najwyższego poziomu, zwykle dodawałem plik mylib.pri i umieszczałem tam wszystko, czego potrzebują inne projekty subdir, używając zmiennych Qmake, aby zawsze uzyskać prawidłowe ścieżki, nawet jeśli jest to kompilacja w tle. Wtedy inne pliki subdir .pro po prostu miałybyinclude(../mylib/mylib.pri)
hyde
dzięki, to jest to, co teraz robię, byłoby miło mieć rozwiązanie, w którym jest to obsługiwane automatycznie, na przykład gdy masz projekt z podprojektami w cmake, a następnie możesz łatwo zrobić różne wyjścia z kompilacje źródłowe całego drzewa.
Adversus
3

Warto też mieć nieco inną nazwę wyjściowego pliku wykonywalnego. Nie możesz użyć czegoś takiego:

release: Target = ProgramName
debug: Target = ProgramName_d

Dlaczego to nie działa, nie jest jasne, ale tak nie jest. Ale:

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

Działa to tak długo, jak CONFIG +=poprzedza go wiersz.

Steve Besch
źródło
1

Nowa wersja Qt Creator posiada również opcję budowania "profilu" pomiędzy debugowaniem a wydaniem. Oto, jak to wykrywam:

CONFIG(debug, debug|release) {  DEFINES += DEBUG_MODE }
else:CONFIG(force_debug_info) { DEFINES += PROFILE_MODE }
else {                          DEFINES += RELEASE_MODE }
BuvinJ
źródło
0

1. Znajdź Debug / Release w CONFIG

Pobierz aktualny (debug | wydanie).

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

(Może być wiele, więc zachowaj tylko ostatnie określone w kompilacji):

2. Ustaw DESTDIR

Użyj go ma nazwę podkatalogu kompilacji

DESTDIR = $$PWD/build/$$build_subdir
automorficzny
źródło
0

To jest mój plik Makefile dla różnych katalogów wyjściowych debug / release. Ten plik Makefile został pomyślnie przetestowany w systemie Ubuntu Linux. Powinien działać bezproblemowo w systemie Windows pod warunkiem, że Mingw-w64 jest poprawnie zainstalowany.

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
źródło