qmake语言
许多qmake项目文件只是使用name = value和name += value定义列表来描述项目使用的源文件和头文件。Qmake还提供了其他操作符、函数和作用域,可用于处理变量声明中提供的信息。这些高级特性允许从单个项目文件为多个平台生成makefile。
操作符
在许多项目文件中,可以使用赋值(=)和append(+=)操作符来包含项目的所有信息。典型的使用模式是将一个值列表赋值给变量,然后根据各种测试的结果添加更多的值。由于qmake使用默认值来定义某些变量,因此有时需要使用删除(-=)操作符来过滤掉不需要的值。下面几节介绍如何使用操作符操作变量的内容。
赋值
=操作符为变量赋值:
TARGET = myapp
上面这行代码将目标变量设置为myapp。这将覆盖之前用myapp为TARGET设置的任何值。
附加价值
+=操作符将一个新值添加到变量的值列表中:
DEFINES += USE_MY_STUFF
上面这行代码将USE_MY_STUFF添加到将要放入生成的Makefile中的预处理器定义列表中。
删除值
操作符-=从变量的值列表中删除一个值:
DEFINES -= USE_MY_STUFF
上述代码行将USE_MY_STUFF从生成的Makefile中的预处理器定义列表中删除。
添加唯一值
操作符*=将一个值添加到变量的值列表中,但仅当该值不存在时才添加。这可以防止在变量中多次包含值。例如:
DEFINES *= USE_MY_STUFF
在上面一行中,只有在USE_MY_STUFF尚未定义的情况下,才会将其添加到预处理器定义的列表中。注意,还可以使用unique()函数来确保每个变量只包含一个值的实例。
替换值
~=操作符可以用指定的值替换与正则表达式匹配的任何值:
DEFINES ~= s/QT_[DT].+/QT
在上面的代码行中,列表中所有以QT_D或QT_T开头的值都被替换为QT。
变量扩展
操作符用于提取变量的内容,可以用于在变量之间传递值或将值提供给函数:
EVERYTHING = $$SOURCES $$HEADERS
message("The project contains the following files:")
message($$EVERYTHING)
变量可以用来存储环境变量的内容。它们可以在qmake运行时进行评估,也可以在构建项目时包含在生成的Makefile中进行评估。
要在qmake运行时获得环境值的内容,可以使用$$(...)操作符:
DESTDIR = $$(PWD)
message(The project will be installed in $$DESTDIR)
在上面的赋值语句中,在处理项目文件时读取PWD环境变量的值。
要**获取处理生成的Makefile时环境值的内容**,可以使用$(...)操作符:
DESTDIR = $$(PWD)
message(The project will be installed in $$DESTDIR)
DESTDIR = $(PWD)
message(The project will be installed in the value of PWD)
message(when the Makefile is processed.)
在上面的赋值中,PWD的值在处理项目文件时立即读取,而$(PWD)被赋值给生成的Makefile中的DESTDIR。只要在处理Makefile时正确设置了环境变量,构建过程就会更加灵活。
### 访问qmake属性
特别的$$\[...\]操作符可以用来访问qmake属性:
message(Qt version: $$[QT_VERSION])
message(Qt is installed in $$[QT_INSTALL_PREFIX])
message(Qt resources can be found in the following locations:)
message(Documentation: $$[QT_INSTALL_DOCS])
message(Header files: $$[QT_INSTALL_HEADERS])
message(Libraries: $$[QT_INSTALL_LIBS])
message(Binary files (executables): $$[QT_INSTALL_BINS])
message(Plugins: $$[QT_INSTALL_PLUGINS])
message(Data files: $$[QT_INSTALL_DATA])
message(Translation files: $$[QT_INSTALL_TRANSLATIONS])
message(Settings: $$[QT_INSTALL_CONFIGURATION])
message(Examples: $$[QT_INSTALL_EXAMPLES])
有关更多信息,请参见[配置qmake](https://doc.qt.io/qt-5/qmake-environment-reference.html "配置qmake")。
通过该操作符可访问的属性通常用于使第三方插件和组件集成到Qt中。例如,Qt Designer插件可以与Qt Designer内置插件一起安装,只要在其项目文件中声明如下:
target.path = $$[QT_INSTALL_PLUGINS]/designer
INSTALLS += target
## 作用域
作用域类似于过程式编程语言中的if语句。如果某个条件为真,则处理作用域中的声明。
### 语法范围
作用域包括**一个条件,在同一行中紧跟一个左花括号,一系列命令和定义,以及在新一行中紧跟一个右花括号**:
{
...
}
左大括号必须与条件语句写在同一行。作用域可以连接起来包含多个条件,如以下各节所述。
### 适用范围及条件
作用域的形式是条件,后面是包含在一对大括号中的一系列声明。例如:
win32 {
SOURCES += paintwidget_win.cpp
}
在构建Windows平台时,上面的代码将把paintwidget_win.cpp文件添加到生成的Makefile中列出的源代码中。在为其他平台构建时,该定义将被忽略。
在给定作用域中使用的条件也可以被否定,从而提供一组替代声明,仅当原始条件为false时才进行处理。例如,要在为除Windows之外的所有平台构建时处理某些内容,可以像这样否定作用域:
!win32 {
SOURCES -= paintwidget_win.cpp
}
作用域可以嵌套以组合多个条件。例如,要仅在启用调试的情况下包含特定平台的特定文件,可编写如下代码:
macx {
CONFIG(debug, debug|release) {
HEADERS += debugging.h
}
}
为了避免编写许多嵌套作用域,可以使用:操作符嵌套作用域。上面例子中的嵌套作用域可以这样重写:
macx:CONFIG(debug, debug|release) {
HEADERS += debugging.h
}
也可以使用:操作符来执行单行条件赋值。例如:
win32:DEFINES += USE_MY_STUFF
上面这行代码仅在为Windows平台构建时才将USE_MY_STUFF添加到define变量中。一般来说,:操作符的行为类似于逻辑与操作符,将多个条件组合在一起,并且要求所有条件都为真。
\|操作符的作用类似于逻辑OR操作符,它将多个条件连接在一起,并且只要求其中一个条件为真。
win32|macx {
HEADERS += debugging.h
}
如果需要混合使用这两个运算符,可以使用**If函数指定运算符的优先级**。
if(win32|macos):CONFIG(debug, debug|release) {
# Do something on Windows and macOS,
# but only for the debug configuration.
}
win32|if(macos:CONFIG(debug, debug|release)) {
# Do something on Windows (regardless of debug or release)
# and on macOS (only for debug).
}
该条件接受通配符来匹配配置值或mkspec名称族。
win32-* {
# Matches every mkspec starting with "win32-"
SOURCES += win32_specific.cpp
}
注意:从历史上看,使用上面这样的通配符检查mkspec名称是qmake检查平台的方法。现在,我们建议使用mkspec在QMAKE_PLATFORM变量中定义的值。
还可以使用else作用域为作用域中的声明提供替代声明。如果上述作用域的条件为false,则处理其他作用域。这允许你在与其他作用域(用:操作符分隔)结合使用时编写复杂的测试。例如:
win32:xml {
message(Building for Windows)
SOURCES += xmlhandler_win.cpp
} else:xml {
SOURCES += xmlhandler.cpp
} else {
message("Unknown configuration")
}
### 配置和作用域
**存储在CONFIG变量中的值由qmake进行特殊处理。每一个可能的值都可以用作作用域的条件**。例如,CONFIG保存的值列表可以用opengl的值扩展:
CONFIG += opengl
这个操作的结果是,任何测试opengl的作用域都将被处理。我们可以使用这个特性给最终的可执行文件一个合适的名字:
opengl {
TARGET = application-gl
} else {
TARGET = application
}
此功能使更改项目的配置变得容易,而不会丢失特定配置可能需要的所有自定义设置。在上面的代码中,第一个作用域中的声明被处理,最终的可执行文件将被称为application-gl。但是,如果没有指定opengl,则处理第二个作用域中的声明,最终的可执行文件将被称为application。
由于可以在CONFIG行中添加自己的值,这为您提供了一种方便的方式来定制项目文件和微调生成的makefile。
### 平台范围值
除了在许多作用域条件下**使用的win32、macx和unix值**之外,还可以使用作用域测试**其他各种内置平台和特定于编译器的值**。这些都是基于Qt的mkspecs目录中提供的平台规范。例如,项目文件中的以下几行显示了当前正在使用和测试的linux-g++规范:
message($$QMAKESPEC)
linux-g++ {
message(Linux)
}
您可以测试任何其他平台-编译器组合,只要mkspecs目录中存在针对它的规范。
## 变量
项目文件中使用的许多变量都是qmake在生成makefile时使用的特殊变量,例如定义、源文件和头文件。此外,你还可以创建自己使用的变量。当Qmake遇到一个给定名称的赋值时,它会使用该名称创建新的变量。例如:
MY_VARIABLE = value
对你自己的变量做什么没有限制,因为qmake会忽略它们,除非它在处理作用域时需要计算它们。
您还可以通过在变量名前加上$$将当前变量的值赋值给另一个变量。例如:
MY_DEFINES = $$DEFINES
现在my_definitions变量包含项目文件中此时定义变量中的内容。这也等价于:
MY_DEFINES = $${DEFINES}
第二种表示法允许你将变量的内容附加到另一个值上,而无需用空格分隔。例如,下面的代码可以确保最终的可执行文件的名称中包含正在使用的项目模板:
TARGET = myproject_$${TEMPLATE}
## 替换功能
Qmake提供了一些**内置函数,以允许处理变量的内容**。这些函数处理提供给它们的参数,并返回一个值或值的列表。要将结果赋值给变量,可在这种类型的函数中使用$$操作符,就像将一个变量的内容赋值给另一个变量一样:
HEADERS = model.h
HEADERS += $$OTHER_HEADERS
HEADERS = $$unique(HEADERS)
这种类型的函数应该在赋值语句的右侧使用(即作为操作数使用)。
你可以像下面这样定义自己的函数来处理变量的内容:
defineReplace(functionName){
#function code
}
下面的例子只接受一个变量名作为参数,使用内置函数eval()从变量中提取值的列表,并编译一个文件列表:
defineReplace(headersAndSources) {
variable = $$1
names = $$eval($$variable)
headers =
sources =
for(name, names) {
header = $${name}.h
exists($$header) {
headers += $$header
}
source = $${name}.cpp
exists($$source) {
sources += $$source
}
}
return($$headers $$sources)
}
## 测试函数
Qmake**提供了内置函数,可以在编写作用域时用作条件**。这些函数不返回值,而是表示成功或失败:
count(options, 2) {
message(Both release and debug specified.)
}
这种类型的函数只能在条件表达式中使用。
你可以定义自己的函数来为作用域提供条件。下面的例子测试列表中的每个文件是否存在,如果都存在则返回true,否则返回false:
defineTest(allFiles) {
files = $$ARGS
for(file, files) {
!exists($$file) {
return(false)
}
}
return(true)
}
[qmake Language \| qmake Manual (qt.io)](https://doc.qt.io/qt-5/qmake-language.html "qmake Language | qmake Manual (qt.io)")