如何在QMake .pro文件中指定不同的Debug/Release输出目录

115
我有一个Qt项目,希望在源代码树之外输出编译文件。
当前的目录结构如下:
/
|_/build
|_/mylib
  |_/include
  |_/src
  |_/resources

根据不同的配置(debug/release),我想要将生成的文件输出到build/debug或build/release目录下的build目录中。

如何使用.pro文件实现这一点?


Qt对待内部调试和发布版本的方式随着时间的推移而发生了变化。因此,我们发现以前在调试和发布之间工作的开关在后来的版本中被破坏了。请查看我的解决方案,它适用于所有平台和所有Qt版本,直到现在。https://dev59.com/po7da4cB1Zd3GeqP9Sil#32048654 - adlag
2
由于这是一个旧问题,值得指出的是有更好的答案 ,但投票更少。 - wardw
11个回答

160

在我的Qt项目中,我在*.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

很简单,但不错! :)


18
正是我需要的!顺便提一下:为了更轻松地切换路径,只需有条件地定义你的 DESTDIR,然后在所有其他路径中使用该值:OBJECTS_DIR = $${DESTDIR}/.obj。干杯! - Xavier Holt
4
能否解释一下它是如何使用/它做什么的?当我实现它时,它似乎没有任何效果。*编辑:*如果我将Debug更改为debug(小写),它就能起作用了。我怀疑这是Windows和Unix大小写敏感的问题。 - notlesh
12
我投票支持它,因为它可以在Windows上运行。但在Linux(Ubuntu 15.04,Qt 5.5.0)上,我不得不将“Debug”更改为“debug”,将“Release”更改为“release”。 - Jepessen
4
只有当CONFIG中只有release或debug时,此方法才有效。如果两者都在CONFIG中,则选择后面的那个。 - weeska
1
在所有平台上检查调试和发布版本的支持方式是使用debug "CONFIG(debug, debug|release)"和release "CONFIG(release, debug|release)"。其他任何方法可能会在某些情况下给您带来麻烦:在CONFIG变量中,debug和release都可以包含,并且最后一个条目是有效的。 - FourtyTwo
显示剩余2条评论

60

要更改目标 dll/exe 的目录,请在您的 pro 文件中使用以下内容:

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

你可能还想为其他构建目标(例如对象文件和 moc 文件)更改目录(请查看 qmake 变量参考qmake CONFIG() 函数参考 了解详情)。


5
但我发现在其中包含$$OUT_PWD更好,因此DESTDIR=$$OUT_PWD/debug。 - Ivo
1
@Ivo:啊!谢谢!我一直在寻找包含那个路径的变量! :D - Cameron
1
在此之后,您可以添加以下行:OBJECTS_DIR = $$DESTDIR/.obj MOC_DIR = $$DESTDIR/.moc RCC_DIR = $$DESTDIR/.qrc UI_DIR = $$DESTDIR/.ui CONFIG() 可以解决使用 release:debug: 时遇到的一些问题。 - Carson Ip
这个比被选答案更有效。被选的那个可以工作,但如果配置了调试和发布,第二个设置块仍然存在。 - Paulo Carvalho

47

我有一个更紧凑的方法:

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
你的答案是将编译器构建输出放在单独目录中的更近方法。 - SIFE
1
你最近尝试过在调试和发布模式下进行构建吗?我的构建输出似乎总是最终出现在发布文件夹中,无论使用哪种配置;不过自从你发表这个答案以来,qmake/Qt Creator的行为可能已经发生了变化... - ssc
1
尝试在发布模式下的qmake附加参数中添加“CONFIG -=debug”。 - Hello W

21

12

我使用了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

虽然这是一个老问题,但仍然值得给出最新的答案。今天,当使用影子构建(在打开新项目时默认启用)时,通常会像Qt Creator一样做。

对于每个不同的构建目标和类型,正确的qmake会在不同的构建目录中使用正确的参数运行。然后,只需使用简单的make进行构建。

因此,想象中的目录结构可能如下所示。

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

重要的是,在构建目录中运行qmake

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

然后它会在构建目录中生成makefiles,make将在其中生成文件。只要永远不在源目录中运行qmake(如果运行了,最好彻底清理!),就不会有不同版本混淆的风险。

像这样完成后,目前接受的答案中的.pro文件甚至更简单:

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

单个项目运行良好,但是如果你有一个项目和一个库怎么办?那么你需要一种依赖于 buildtype 的方式来包含库 afaics。 - Adversus
@Adversus 我不确定你的意思,但也许 Qmake 变量 $(OUT_PWD) 是解决方案? - hyde
当我将我的问题应用于您的示例时,它变成了:一个应用程序选择mylib的最干净的方法是什么?如果有一种“优雅”的方式来做到这一点,那就太好了。除了使用其他答案中的技术之外,我没有看到其他的方法:聪明地使用构建类型和配置来填充LIBS,从而抵消阴影构建的优势。 - Adversus
@Adversus 如果mylib是同一顶级项目下的子目录项目,我通常会添加一个mylib.pri文件,并将其他子目录项目需要的所有内容放在那里,使用Qmake变量始终正确获取路径,即使它是阴影构建。然后,其他子目录.pro文件只需包含include(../mylib/mylib.pri)即可。 - hyde
谢谢,这差不多是我现在正在做的事情,如果有一个自动处理这个问题的解决方案就好了,就像在cmake中有子项目的项目一样,可以轻松地对整个树进行不同的外部构建。 - Adversus
是的,不幸的是,在Windows上使用第三方库时,您仍然经常需要在.pro文件中区分调试和发布版本,因为库路径和文件名通常会发生变化(Windows调试和发布库是不同的东西,并且使用不同的C运行时)。 - Jason C

3

为输出可执行文件使用稍微不同的名称也很有用。你不能使用这样的东西:

release: Target = ProgramName
debug: Target = ProgramName_d

为什么它不起作用并不清楚,但它确实没有。但是:
CONFIG(debug, debug|release) {
    TARGET = ProgramName
} else {
    TARGET = ProgramName_d
}

只要CONFIG +=行在其之前,这个方法就可以起作用。

3
简短的回答是:你不需要这么做
你应该在想要构建的任何构建目录中运行qmake后跟make。因此,在debug目录中运行一次,在release目录中运行一次。
这就是任何构建您项目的人所期望的工作方式,也是Qt本身设置的构建方式,Qt Creator也期望您的.pro文件像这样运行:它简单地在目标选择的配置的构建文件夹中启动qmakemake
如果您希望创建这些文件夹并在其中执行两个(或多个)构建,则需要一个顶级makefile,可能会通过qmake从顶级项目文件创建。
拥有超过两个构建配置并不少见,因此您不必仅区分构建和发布;您可能具有具有不同优化级别等不同的构建。 调试/发布二元性最好被放弃。

1
qmake 就像没有 -Bcmake:你首先要 cd 到所需的构建目录,然后在那里运行它 :) 此外,它通常很糟糕,没有必要使用它:要么使用 cmake,要么放弃 :) - Kuba hasn't forgotten Monica
1
这不是正确的答案,你可以并且应该这样做。否则它只是一个自制项目,而不是生产环境。在工业界中,我们期望在源文件目录之外有输出,因为这涉及到版本控制软件、团队集成等方面。 - Swift - Friday Pie
@Kubahasn'tforgottenMonica 我在实践中看到 cmake 所做的唯一一件事情,其他构建系统都没有做到,那就是因为它太啰嗦了,所以增加了我们新员工的培训时间。此外,使用 cmake 的好理由很多,但我看到团队投入时间来切换到它的时候,90% 的情况下不是出于这些原因,而是因为他们不知道如何使用他们之前的构建系统,并且听说 cmake 可以解决他们所有的问题。 :) - Jason C
这种策略并不总是适用于在Windows上使用第三方库的情况,因为.pro文件必须知道调试与发布版本,因为库路径和/或文件名通常会发生变化。Q仅涉及更改输出目录,但Google也会将寻找qmake调试与发布检测的人带到这里。 - Jason C
每个我见过的基于cmake的设置都将debug和release放在构建目录的单独子目录中,与arch子目录相同;我从未见过需要进入debug或release目标并从那里构建的设置。这肯定是意外和不寻常的。让cmake完成这项工作,这就是它的用途。 - Jason C
显示剩余2条评论

2
Qt Creator的新版本还增加了一个“profile”构建选项,位于调试和发布之间。以下是我检测它的方法:
CONFIG(debug, debug|release) {  DEFINES += DEBUG_MODE }
else:CONFIG(force_debug_info) { DEFINES += PROFILE_MODE }
else {                          DEFINES += RELEASE_MODE }

1
这是我的Makefile,用于不同的调试/发布输出目录。该Makefile在Ubuntu Linux上成功测试过。如果正确安装了Mingw-w64,则应在Windows上无缝运行。
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$@

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接