Como especificar diferentes diretórios de saída de depuração / liberação no arquivo QMake .pro


106

Eu tenho um projeto Qt e gostaria de gerar arquivos de compilação fora da árvore de origem.

Atualmente, tenho a seguinte estrutura de diretório:

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

Dependendo da configuração (depuração / liberação), gostaria de enviar os arquivos resultantes dentro do diretório de compilação nos diretórios de compilação / depuração ou compilação / liberação.

Como posso fazer isso usando um arquivo .pro?


A maneira como o Qt trata as compilações de depuração e lançamento mudou internamente com o tempo. Portanto, descobrimos que as alternâncias de trabalho anteriores entre depuração e lançamento quebraram em versões posteriores. Veja minha solução que funciona em todas as plataformas e em todas as versões do Qt até agora. stackoverflow.com/questions/32046181/…
adlag

2
Como esta é uma questão antiga, vale a pena apontar que existem respostas melhores com muito menos votos.
wardw

Respostas:


5

A resposta curta é: você não .

Você deve executar qmakeseguido por makeem qualquer diretório de construção que deseja construir. Portanto, execute-o uma vez em um debugdiretório, uma vez em um releasediretório.

É assim que qualquer pessoa que está construindo seu projeto esperaria que ele funcionasse, e é assim que o próprio Qt é configurado para ser construído, é assim que o Qt Creator espera que seu .proarquivo se comporte: ele simplesmente inicia qmakee então makena pasta de construção para a configuração escolhida por seu destino.

Se você deseja criar essas pastas e realizar as duas (ou mais) compilações nelas, você precisará de um makefile de nível superior, possivelmente criado a partir de um arquivo de projeto de nível superior via qmake.

Não é incomum ter mais de duas configurações de compilação, portanto, você desnecessariamente se compromete a apenas diferenciar entre uma compilação e uma versão; você pode ter compilações com diferentes níveis de otimização, etc. É melhor deixar a dicotomia depurar / liberar para descansar.


151

Para o meu projeto Qt, eu uso este esquema no arquivo * .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

É simples, mas legal! :)


18
Exatamente o que eu precisava! E uma nota: Para tornar as coisas ainda mais fácil de mudar em torno de apenas definir seus DESTDIRs condicionalmente, e, em seguida, usar esse valor em todos os seus outros caminhos: OBJECTS_DIR = $${DESTDIR}/.obj. Felicidades!
Xavier Holt,

4
Importa-se de explicar como isso é usado / o que faz? Parece não ter efeito quando o implemento. editar: se eu alterar Debug para debug (minúsculas), ele funciona. Eu suspeito que isso seja uma questão de distinção entre maiúsculas e minúsculas do Windows vs Unix.
notlesh

9
Votei porque funciona no Windows. No Linux (Ubuntu 15.04, Qt 5.5.0), tive que mudar Debugpara debuge Releasepara release.
Jepessen

Wth? Tanto para plataforma cruzada? @Jepessen ??
Nils

2
Isso só funciona quando você só tem liberação ou depuração no CONFIG. Se ambos estiverem em configuração, o último será usado.
weeska

52

Para alterar o diretório para dll / exe de destino, use isso em seu arquivo pro:

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

Você também pode querer alterar os diretórios para outros destinos de construção, como arquivos de objeto e arquivos moc (verifique a referência de variável qmake para obter detalhes ou a referência de função qmake CONFIG () ).


5
Mas eu achei muito melhor incluir $$ OUT_PWD nisso, então DESTDIR = $$ OUT_PWD / debug
Ivo

1
@Ivo: Ah! Obrigado! Estive procurando em todos os lugares quais variáveis ​​continham esse caminho! : D
Cameron

1
Depois disso, você pode adicionar linhas como: OBJECTS_DIR = $$DESTDIR/.obj MOC_DIR = $$DESTDIR/.moc RCC_DIR = $$DESTDIR/.qrc UI_DIR = $$DESTDIR/.ui CONFIG()acaba resolvendo alguns problemas de uso release:edebug:
Carson Ip

Esta funcionou melhor do que a resposta selecionada. O selecionado funciona, mas se a depuração e a liberação estiverem configuradas, o segundo bloco de configurações permanece.
Paulo Carvalho

42

Tenho uma abordagem mais compacta:

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

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

2
Sua resposta é a maneira mais recente de colocar a saída da compilação do compilador em um diretório separado.
SIFE

1
você tentou isso recentemente para depuração e lançamento? minha saída de compilação sempre parece terminar na pasta de lançamento, não importa a configuração; O comportamento do qmake / Qt Creator pode ter mudado desde que você postou esta resposta ...
ssc

1
Tente adicionar "CONFIG - = debug" aos argumentos adicionais de qmake no modo Release
Olá W

17

A maneira correta de fazer isso é a seguinte (obrigado Equipe de Suporte 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

Mais informações aqui: 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_2


13

Eu uso o mesmo método sugerido por 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"
}

12

Pergunta antiga, mas ainda vale uma resposta atualizada. Hoje é comum fazer o que o Qt Creator faz quando construções de sombra são usadas (elas são ativadas por padrão ao abrir um novo projeto).

Para cada tipo e destino de construção diferente, o direito qmakeé executado com os argumentos certos em um diretório de construção diferente. Então isso é simplesmente construído com o simples make.

Portanto, a estrutura de diretório imaginária pode ter esta aparência.

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

E o importante é que a qmakeé executado no diretório de construção:

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

Em seguida, ele gera makefiles no diretório de construção e, em seguida, makeirá gerar arquivos nele também. Não há risco de misturar versões diferentes, desde que o qmake nunca seja executado no diretório de origem (se for, é melhor limpar bem!).

E quando feito assim, o .proarquivo da resposta aceita atualmente é ainda mais simples:

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

Funciona bem para um único projeto, mas e se você tiver um projeto e uma biblioteca? Então, você precisa de uma maneira dependente do tipo de construção de incluir os afaics da biblioteca.
Adversus de

@Adversus Não tenho certeza do que exatamente você quer dizer, mas talvez a variável Qmake $(OUT_PWD)seja a solução?
hyde de

Quando aplico minha pergunta ao seu exemplo, ela se torna: qual é a maneira mais limpa de pegar um aplicativo mylib? Eu gostaria que houvesse uma maneira "graciosa" de fazer isso, não vejo outra maneira além de usar as técnicas das outras respostas: use o tipo de construção e configuração para preencher de LIBSforma inteligente, anulando a vantagem da construção de sombra.
Adversus de

@Adversus Se mylib for um projeto de subdiretório no mesmo projeto de nível superior, eu normalmente adicionaria um arquivo mylib.pri e colocaria tudo o que outros projetos de subdiretório precisam lá, usando variáveis ​​Qmake para obter os caminhos sempre corretos, mesmo que seja uma construção de sombra. Então, outros arquivos subdirecionados .pro simplesmente teriaminclude(../mylib/mylib.pri)
hyde de

obrigado, é isso que estou fazendo agora, seria bom ter uma solução em que isso fosse resolvido automaticamente, como quando você tem um projeto com subprojetos no cmake e pode facilmente fazer diferentes compilações de origem de toda a árvore.
Adversus

3

Também é útil ter um nome ligeiramente diferente para o executável de saída. Você não pode usar algo como:

release: Target = ProgramName
debug: Target = ProgramName_d

Por que isso não funciona não está claro, mas não funciona. Mas:

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

Isso funciona, desde que a CONFIG +=linha o preceda.


1

A nova versão do Qt Creator também possui uma opção de construção de "perfil" entre depuração e liberação. Veja como estou detectando isso:

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

0

1. Encontre Debug / Release em CONFIG

Obtenha o atual (debug | release).

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

(Pode ser múltiplo, portanto, mantenha apenas o último especificado na construção):

2. Defina DESTDIR

Use-o com o nome do subdiretório build

DESTDIR = $$PWD/build/$$build_subdir

0

Este é o meu Makefile para diferentes diretórios de saída de depuração / liberação. Este Makefile foi testado com sucesso no Linux Ubuntu. Ele deve funcionar perfeitamente no Windows, desde que o Mingw-w64 esteja instalado corretamente.

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$@
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.