本章介绍如何为基于 Qt 的三种常见项目类型设置 qmake 项目文件:应用程序、库和插件。尽管所有项目类型都使用许多相同的变量,但每个变量都使用特定于项目的变量来自定义输出文件。
此处不介绍特定于平台的变量。有关详细信息,可以参阅 Qt for Windows - Deployment 和 Qt for macOS
1. 构建应用程序
app 模板告诉 qmake 生成一个 Makefile 来构建应用程序。使用此模板,可以通过向 CONFIG 变量定义添加以下选项之一来指定应用程序的类型:
选项 | 描述 |
---|---|
windows | 该应用程序是一个 GUI 应用程序。 |
console | 仅限 app 模板使用:该应用程序是一个控制台应用程序。 |
testcase | 该应用是一个自动化测试 |
使用此模板时,将识别下列 qmake 系统变量。我们应该在 .pro 文件中使用它们来指定有关应用程序的信息。对于其他附加的平台相关的系统变量,我们可以查看平台相关事项来进一步了解。
- HEADERS - 应用程序使用的头文件列表
- SOURCES - 应用程序使用的C++源文件列表
- FORMS - 应用程序使用的 UI 文件列表 (由 Qt Designer) 创建
- LEXSOURCES - 应用使用的 Lex 资源文件列表
- YACCSOURCES - 应用使用的 Yacc 资源文件列表
- TARGET - 应用程序的可执行文件的名称。默认情况下为项目文件的名称。(如果有后缀名,例如 Windows 平台上的 .exe,会自动添加)
- DESTDIR - 目标可执行文件所在的目录
- DEFINES - 应用程序所需的任何其他预处理器定义的列表
- INCLUDEPATH - 应用所需的任何附加 include 路径列表
- DEPENDPATH - 应用程序的依赖项搜索路径
- VPATH - 告诉 qmake 在何处搜索无法打开的文件。例如,qmake 查找 SOURCES 并找到一个它无法打开的条目,它将遍历整个 VPATH 列表,以查看是否可以自行找到该文件
- DEF_FILE - 仅适用于 Windows 平台: 应用程序要链接的 .def 文件
对于上面列出的这些变量,我们只需要使用具有值的系统变量即可。例如,如果我们没有任何额外的包含路径,那么我们就不需要使用 INCLUDEPATH。qmake 会自动添加必要的默认值。一个项目文件的例子像下面这样:
TEMPLATE = app
DESTDIR = c:/helloapp
HEADERS += hello.h
SOURCES += hello.cpp
SOURCES += main.cpp
DEFINES += USE_MY_STUFF
CONFIG += release
对于只需要单一值的属性项,例如 TEMPLATE 或 DESTDIR,我们使用“=”;但是对于多值项,我们使用“+=”来将现有项添加到该类型。使用“=”将使值替换为新值。例如,我们写成 DEFINES = USE_MY_STUFF,则删除列表中所有其他的预处理器定义。
2. 构建一个测试用例
testcase 项目是一个 app 项目,它将作为一个自动测试来运行。任何应用程序都可以通过向 CONFIG 变量添加值 testcase 来标记为 testcase
对于 testcase 项目,qmake 将在生成的 Makefile 中插入一个 check target。这个 target 将运行应用程序。如果测试终止时退出码为零,则认为测试通过。
check target 可以通过 SUBDIRS 自动递归。这意味着可以在 SUBDIRS 项目中运行 make check 命令来运行整个测试套件。
check target 的执行行为可以由某些 Makefile 变量定制。这些变量是:
变量 | 描述 |
---|---|
TESTRUNNER | 每个测试命令的前置命令或 shell 片段。一个示例的用例是“timeout”脚本,如果测试没有在指定的时间内完成,它将终止测试。 |
TESTARGS | 附加到每个测试命令的其他参数。例如,传递额外的参数来设置测试中输出的文件名和格式可能很有用(例如 QTestLib 支持的 -o filename,format 选项)。 |
注意:上面的变量是在调用 make 工具时设置,而不是在 .pro 文件中设置的。大多数 make 工具支持直接在命令行上设置 Makefile 变量:
# Run tests through test-wrapper and use xunitxml output format.
# In this example, test-wrapper is a fictional wrapper script which terminates
# a test if it does not complete within the amount of seconds set by "--timeout".
# The "-o result.xml,xunitxml" options are interpreted by QTestLib.
make check TESTRUNNER="test-wrapper --timeout 120" TESTARGS="-o result.xml,xunitxml"
Testcase 项目可以通过以下 CONFIG 选项进一步定制:
选项 | 描述 |
---|---|
insignificant_test | 在进行 make check 时,将忽略测试的退出代码。 |
测试用例通常是用 QTest 或 TestCase 编写的,但是使用 CONFIG += testcase 和 make check 并不是必需的。唯一必须的要求是测试程序在成功时退出码为零,失败时退出码为非零。
3. 构建库
lib 模板告诉 qmake 生成一个 Makefile 来构建一个库。在使用 lib 模板时,除了具有 app 模板支持的系统变量之外,它还支持 VERSION 变量。使用它可以在 .pro 文件中指定有关库的信息。
在使用 lib 模板时,可以在 CONFIG 变量中添加以下选项来确定要构建的库的类型:
|选项|描述|
|dll|该库是一个共享库(dll)|
|staticlib|该库是一个静态库|
|plugin|该库是一个插件|
还可以定义以下选项来提供关于库的其他信息。
win32:VERSION = 1.2.3.4 # major.minor.patch.build
else:VERSION = 1.2.3 # major.minor.patch
库的目标文件名是与平台相关的。例如,在 X11、macOS 和 iOS 上,库名将由 lib 作为前缀。在 Windows 上,文件名不添加前缀。
4. 构建插件
插件是使用 lib 模板构建的,如前一节所述。这告诉 qmake 为项目生成 Makefile,该 Makefile 将以适合每个平台的形式(通常是库的形式)构建插件。与普通库一样,VERSION 变量也可用于指定关于插件的信息。
win32:VERSION = 1.2.3.4 # major.minor.patch.build
else:VERSION = 1.2.3 # major.minor.patch
4.1 构建 Qt Designer 插件
Qt Designer 插件是使用一组特定的配置设置来构建的,这些设置依赖于 Qt 为我们的系统配置的方式。为了方便起见,可以通过将 designe r添加到 QT 变量来启用这些设置。例如:
QT += widgets designer
有关基于插件的项目的更多示例,请参见 Qt Designer示例。
5. 在调试和发布模式下创建和安装
有时,以调试和发布模式构建项目是必要的。尽管 CONFIG 变量可以同时包含 debug 和 release 选项,但是只应用最后指定的选项。
5.1 在调试和发布模式下构建
要使项目能够在两种模式下构建,我们必须将 debug_and_release 选项添加到 CONFIG 变量:
CONFIG += debug_and_release
CONFIG(debug, debug|release) {
TARGET = debug_binary
} else {
TARGET = release_binary
}
上面代码段中的作用域在每种模式下修改构建目标,以确保生成的目标具有不同的名称。为目标提供不同的名称可以确保其中一个不会覆盖另一个。
当 qmake 处理项目文件时,它将生成一个 Makefile 规则,以允许在两种模式下构建项目。这可以通过以下方式调用:
make all
build_all 选项可以添加到项目文件中的 CONFIG 变量中,以确保项目在默认情况下以两种模式构建:
CONFIG += build_all
这允许使用默认规则处理 Makefile:
make
5.2 在调试和发布模式下安装
build_all 选项还确保在调用安装规则时将安装目标的两个版本:
make install
可以根据目标平台定制构建目标的名称。例如,一个库或插件可以在 Windows 上使用与 Unix 平台不同的约定来命名:
CONFIG(debug, debug|release) {
mac: TARGET = $$join(TARGET,,,_debug)
win32: TARGET = $$join(TARGET,,d)
}
上面代码段中的行为是在以调试模式构建时修改用于构建目标的名称。可以将 else 子句添加到其后,以对发布模式执行类似的操作。如果保持原样,发布模式下目标名称将保持不变。