QMake是一个通过编译Pro文件自动生成Makefile文件的工具。
这里扩展一下make、makefile、cmake、CMakeLists.txt、qmake等之间的关系:
- 首先,当我们初学helloworld项目的时候,一般是用gcc命令进行编译的,gcc是GNU Compiler Collection(GNU编译器套件),可以理解为编译器。
- 当项目比较复杂,需要编译的文件比较多时,再用gcc命令逐个编译就不现实了,所以就衍生出了makefile文件和make工具。
- makefile是一个项目的编译规则文件,描述了项目的编译和链接的规则,比如项目中哪些文件需要编译,哪些文件不需要编译,哪些文件要先编译,哪些文件要后编译等等。当然文件编译还是需要通过调用gcc编译器(或其他编译器)去编译文件。
- make工具就是通过调用makefile文件进行编译和链接项目。
- 因为makefile文件非常复杂,需要使用CMake工具来生成,CMake工具支持跨平台生成makefile文件。
- 但是,CMake是怎么生成makefile文件的呢?这里又牵扯到了一个CMakeLists.txt文件(相信大家对这个很熟悉)。
- CMakeLists.txt文件有自己的语法、函数,主要是定义项目文件路径、项目环境以及编译信息等。这个文件一般都由IDE自动生成,当然自己能写是最好的。
- qmake和CMake的意义是差不多的,都是用来生成makefile文件的,有区别的是qmake还包含了moc(元对象编译器)和uic(用户界面编译器)的构建规则。
- qmake是怎么生成makefile文件的呢?当然是通过Qt的工程文件(.pro文件)来生成,那么下面就详细介绍一下pro文件相关的语法
qmake的基本行为受到变量声明的影响,这些声明定义了每个项目的构建过程。其中一些声明资源,例如HEADERS和SOURCES是每个平台所共有的。其他的则是用来定制特定平台上的编译器和链接器的行为。
QTQT变量主要包含项目所需的Qt模块,Qt基础模块有以下:
基础模块描述core(默认包含该模块)核心模块gui(默认包含该模块)图形用户界面模块multimedia音频、视频、广播和相机功能模块multimedia widgets用于实现多媒体功能的widget模块network网络编程模块qml支持QML和JavaScript语言的模块quick构建具有自定义用户动态界面的应用程序模块quick controls提供轻量级QML控件类型的模块quick dialogs为quick应用程序提供对话框的模块quick layouts基于Qt Quick 2项目的用户界面布局模块quick testQML单元测试模块sql数据库模块testQt应用程序和库的单元测试模块widgets扩展GUI窗口类的模块默认Qt项目将包含core和gui两个模块,如果项目不需要界面显示,则需要添加以下代码:
QT -= gui
Qt还扩展了很多附加模块:
附加模块开发平台应用平台描述Active QtWindowsWindows支持ActiveX和COM模块Qt 3DAllAll实时仿真系统,支持2D和3D渲染Qt Android ExtrasAllAndroid为Android提供特定于平台的APIQt BluetoothAllAndroid,ios,Linux,MacOS,UWP提供对蓝牙的访问Qt ConcurrentAllAll在不使用低级线程语法下编写多线程程序Qt D-BusAllAll通过D-Bus协议进行进程间通信Qt GamepadAllAndroid,ios,macOS,tvOS,Linux,Windows,QNX支持游戏手柄硬件的应用程序Qt Graphical EffectsAllAll用于Qt Quick 2的图形效果Qt HelpAllAll像Qt助手一样将文档集成到应用程序中Qt Image FormatsAllAll支持其他图形格式:TIFF、MNG、TGA、WBMPQt LocationAllAll在QML应用程序中显示地图、导航和地点内容Qt Mac ExtrasAllmacOS为macOS提供特定于平台的APIQt NFCAllAndroid,Linux支持NFC硬件访问Qt PositioningAllAndroid,ios,macOS,Linux,UWP提供对位置、卫星和区域监控类的访问Qt Print SupportAllAll提供更便捷的打印类Qt Quick ExtrasAllAll提供一组专门的Quick控件Qt Quick TimelineAllAll启用基于关键帧的动画和参数化Qt Quick WidgetsAllAll提供用于显示Quick用户界面的小部件类Qt Remote ObjectsAllAll提供一种用于在进程或设备之间共享QObject的APIQt SCXMLAllAll提供从SCXML文件中创建状态机并将其嵌入到应用程序中Qt Serial PortAllWindows,Linux,macOS,QNX提供对硬件和虚拟串口的访问Qt SpeechAllAll except QNX提供对语音方面的支持Qt SVGAllAll用于显示SVG文件内容的类Qt UI ToolsAllAll运行时动态加载基于QWidget的表单类Qt WebChannelAllAll提供从HTML客户端对QObject或QML对象的访问,用来实现应用程序和HTML/JavaScript客户端的联系Qt WebEngineAllWindows,Linux,macOS将Chromium浏览器引擎嵌入应用程序中Qt WebSocketsAllAll提供符合RFC6455的Websocket通信Qt WebViewAllAll支持原生API显示Web浏览器视图Qt Windows ExtrasAllWindows为Windows提供特定于平台的API以下在商业许可证或GNU通用公共许可证V3下可以用的附加模块:Qt ChartsAllAll图表模块Qt Data VisualizationAllAll3D数据可视化组件Qt Lottie AnimationAllAll以JSON格式渲染图形和动画的QML APIQt Virtual KeyboardAllLinux,Windows desktop,Boot to Qt targets支持本地的虚拟键盘Qt Quick 3DAllAll提供Quick 3D相关APIQt Quick WebGLAllWebGL-enabled web browsers支持WebGL插件 HEADERS项目包含头文件列表:
HEADERS += widget.h
SOURCES
项目包含源文件列表:
SOURCES += main.cpp \
widget.cpp
FORMS
项目包含UI文件列表:
FORMS += widget.ui
RESOURCES
指定目标的资源文件(qrc)的名称。
RESOURCES += src.qrc
INCLUDEPATH
指定编译项目时要包含当前目录。例如:
INCLUDEPATH = c:/msdev/include d:/stl/include
LIBS
该变量包含链接到工程的库列表。可以使用Unix平台-L(库路径)和-l(库名称)的标识,qmake会正确处理Windows和symbian平台上的这些库。例如:
LIBS += -L./lib -ltest # 链接到./bin目录下的test.lib
LIBS += -ltest # 链接到当前目录下的test.lib
CONFIG
通用配置,主要包含编译器选项和属性以及链接库标志。
选项描述release该项目以发布模式构建。如果同时定义了debug,则将忽略releasedebug该项目以调试模式构建。debug_and_release该项目以调试和发布模式构建。debug_and_release_target该项目使用debug和release两种模式构建,目标会被构建到debug和release两个目录下build_all如果指定了debug_and_release,项目默认以调试和发布模式构建。autogen_precompile_source自动生成一个.cpp文件,包含.pro文件中指定的预编译头文件。ordered当使用subdirs模板时,该选项指定按照列出的目录顺序构建。precompile_header项目支持预编译头文件precompile_header_c项目支持对C的预编译头文件warn_on编译器警告信息输出打开warn_off编译器警告信息输出关闭exceptions默认启用异常exceptions_off关闭异常ltcg启用链接时间代码生成,默认是关闭的rtti启用对RTTI的支持,默认情况下使用编译器的默认值rtti_off关闭对RTTI的支持,默认情况下使用编译器的默认值stl启用对STL的支持,默认情况下使用编译器的默认值stl_off关闭对STL的支持,默认情况下使用编译器的默认值thread启用对线程的支持,当CONFIG包含了qt模块时,这将被启用,这是默认的。c99启用对C99的支持。如果编译器不支持C99,或者不能选择C标准,这个选项就没有作用。默认情况下使用编译器的默认值c11启用对C11的支持。如果编译器不支持C11,或者不能选择C标准,这个选项就没有作用。默认情况下使用编译器的默认值strict_c禁用对C编译器扩展的支持。默认情况下被启用。c++11启用对C++11标准的支持。如果编译器不支持C++11,或者不能选择C++标准,这个选项就没有作用。默认情况下是启用的。c++14启用对C++14标准的支持。如果编译器不支持C++14,或者不能选择C++标准,这个选项就没有作用。默认情况下使用编译器的默认值。c++1z / c++17启用对C++17标准的支持。如果编译器不支持C++17,或者不能选择C++标准,这个选项就没有作用。默认情况下是禁用的。c++2a启用对C++2a标准的支持。如果编译器不支持C++2a,或者不能选择C++标准,这个选项就没有作用。默认情况下是禁用的。c++latest启用编译器所支持的最新C++标准的支持,默认情况下是禁用的。strict_c++禁用对C++编译器扩展的支持。默认情况下是被启用的。depend_includepath启用将INCLUDEPATH的值追加到DEPENDPATH。默认启用lrelease对 TRANSLATIONS 和 EXTRA_TRANSLATIONS 中列出的所有文件运行 lrelease。如果 embed_translations 没有被设置,请将生成的 .qm 文件安装到 QM_FILES_INSTALL_PATH。使用 QMAKE_LRELEASE_FLAGS 来为 lrelease 调用添加选项。默认情况下不设置。embed_translations在QM_FILES_RESOURCE_PREFIX下的可执行文件中嵌入从lrelease生成的翻译。需要lrelease也被设置。默认情况下不设置。create_libtool为当前构建的库创建一个libtool.la文件create_pc为当前构建的库创建一个pkg-config .pc 文件。no_batch仅限NMake。关闭NMake批处理规则或推理规则的生成。skip_target_version_ext在Windows下,禁止自动附加在DLL文件名上的版本号。suppress_vcproj_warnings禁止VS项目生成警告信息。windeployqt在链接后自动调用windeployqt,并将输出添加为部署项。dont_recurse禁止qmake递归当前子项目no_include_pwd不要将当前目录添加到INCLUDEPATHS中compile_include_sources默认情况下,qmake不编译包含在其他源文件中的源文件当您使用该debug_and_release
选项(Windows 下的默认设置)时,项目将被处理三次:一次生成“元”Makefile,另外两次生成 Makefile.Debug 和 Makefile.Release。
在后者构建时,debug
orrelease
选项被附加到CONFIG
. 这使得执行特定于构建的任务成为可能。
以下选项定义应用程序或库的类型:
选项描述qt默认定义。该项目依赖Qt库x11该项目是一个X11应用程序或库testcase该项目是自动化测试。检查并添加到生成的Makefile中以运行测试insignificant_test自动测试的退出代码将被忽略。windows该项目是一个win32窗口应用程序console该项目是一个win32控制台应用shared该项目是一个共享项目dll该项目是一个动态库项目,构建后自动生成dll文件dylib该项目是一个Mac OS的动态库项目,构建后自动生成dylib文件static该项目是一个静态库项目staticlib该项目是一个静态库项目plugin该项目是一个插件项目designer该项目是一个Qt designer插件项目uic3no_Iflags_merge配置该项使LIBS的库列表不会被简化为唯一名称的列表resources配置rcc资源模块 DESTDIR指定目标(可执行文件)放置的路径
SUBDIRS该变量和subdirs模板类型一起使用时,指定项目需要构建的所有子项目(子目录)名称。包含的子目录必须包含自己的pro文件。例如:
SUBDIRS = kernel \
tools \
myapp
注意:当CONFIG 配置添加了 ordered,则SUBDIRS包含子目录的顺序决定了构建的顺序。
TARGET指定目标文件的名称。默认包含项目文件的基本名称。例如:
TARGET = myapp
TEMPLATE
指定生成项目时要使用的模板名称。模板选项包含以下:
选项描述app(默认)。构建为应用程序lib构建为库subdirs构建子目录aux不构建任何东西vcapp构建为Windows系统下的VS应用程序项目vclib构建为Windows系统下的库项目 DEPENDPATH指定qmake要扫描的目录列表,用来解决项目中的依赖关系。该变量在qmake抓取你的源代码中#include的头文件时使用。
DEFINESqmake将该变量的值作为C编译器的预处理宏。
VERSION如果模板类型为app,则表示应用程序的版本号;如果模板类型为lib,则表示库的版本号。
win32:VERSION = 1.2.3.4 # major.minor.patch.build
else:VERSION = 1.2.3 # major.minor.patch
DLLDESTDIR
指定复制目标dll的目录。注意:该变量只适用于Windows平台。
RCC_DIR指定Qt资源编译器输出文件的目录。例如:
unix:RCC_DIR = ../myproject/resources
win32:RCC_DIR = c:/myproject/resources
_PRO_FILE_
pro文件的绝对路径,包含pro文件名称,例如:
message(_PRO_FILE_)
# out:
# Project MESSAGE: E:/Test/ProTest/ProTest.pro
_PRO_FILE_PWD_
pro文件的目录路径,不包含pro文件名称,例如:
message(_PRO_FILE_PWD_)
# out:
# Project MESSAGE: E:/Test/ProTest
测试函数
CONFIG(config)
这个函数是用来测试放在CONFIG变量中的变量的,功能类似于条件作用域。函数的第二个参数是用来指定互斥条件的,例如:
# test1:
CONFIG += debug
CONFIG(debug) : message(debug build!)
CONFIG(release) : message(release build!)
# out: 因为没有指定互斥量,所以两种输出都将执行
# Project MESSAGE: debug build!
# Project MESSAGE: release build!
# Project MESSAGE: debug build!
# Project MESSAGE: release build!
# Project MESSAGE: debug build!
# Project MESSAGE: release build!
# test2:
CONFIG += debug
CONFIG(debug, debug|release) : message(debug build!)
CONFIG(release, debug|release) : message(release build!)
# out: 当前指定debug模式,所以只会输出debug build!
# Project MESSAGE: debug build!
# Project MESSAGE: debug build!
# Project MESSAGE: debug build!
# test3:
CONFIG += release
CONFIG(debug, debug|release) : message(debug build!)
CONFIG(release, debug|release) : message(release build!)
# out:当前指定release模式,所以只会输出release build!
# Project MESSAGE: release build!
# Project MESSAGE: release build!
# Project MESSAGE: release build!
# test4:
CONFIG(debug, debug|release) : message(debug build!)
CONFIG(release, debug|release) : message(release build!)
# release构建 out:
# Project MESSAGE: release build!
# Project MESSAGE: release build!
# Project MESSAGE: debug build!
# debug构建 out:
# Project MESSAGE: debug build!
# Project MESSAGE: debug build!
# Project MESSAGE: release build!
注意上面测试示例输出的内容为什么会有三次呢?因为在缺省情况下,qmake将创建三个makefile文件,分别为Makefile,Makefile.debug以及Makefile.release三个。所以当测试示例4中没有指定固定的构建配置,IDE选择release模式时Makefile和Makefile.release两个文件对应输出release build!,而Makefile.debug会输出debug build!
contains(variablename, value)如果变量variablename包含value值,则成功,否则失败。
# 如果QT添加了network模块,则把对应的头文件和源文件添加到项目中
contains( QT, network ) {
message( "Configuring for network build..." )
HEADERS += network.h
SOURCES += network.cpp
}
上面示例代码是contains的主要应用场景,通过判断是否添加某些模块来自动添加对应模块的代码文件。
count(variablename,number)如果variablename比哪里中包含指定数量number的值列表则成功,反之失败。 该函数主要用于确保作用域内的声明仅在变量包含正确数值的情况下才会被处理。例如:
options = $$find(CONFIG, "debug") $$find(CONFIG, "release")
count(options, 2) { message(Both release and debug specified.)}
include(filename)
意义和C++中的include是一样的,将指定的文件名包含到当前项目中,返回true表示包含成功,反之包含失败。你可以通过使用这个函数作为条件来检查是否被包含。示例如下:
!include(test.pri) {
message("test.pri加载失败")
}
一般我们用于包含pri文件。
if(condition)条件判断,和C++的if语句一样。
for(iterate, list)循环变量list中的所有值。示例如下:
LIST = 1 2 3
for(a, LIST):message(I see a file.$${a}!)
# out:
# Project MESSAGE: I see a file.1!
# Project MESSAGE: I see a file.2!
# Project MESSAGE: I see a file.3!
message(string)
将字符串以一般信息输出给用户。
message( "This is a message" ) # 引号是可选的,建议使用
注意:默认情况下,qmake为特定项目生成的每个makefile都会输出信息。如果你想确保每个项目只输出一次信息,请参考下面的示例:
!build_pass:message( "This is a message" )
mkpath(dirPath)
创建目录路径dirPath,这个函数是QDir::mkpath函数的一个封装器。 该函数在Qt5.0中被引入。
system(command)执行shell命令。执行命令返回0表示成功,否则失败。示例如下:
system("ls /bin"): HAS_BIN = TRUE
unset(variablename)
将变量名从当前上下文中移除。
NARF = zort
unset(NARF)
!defined(NARF, var) {
message("NARF is not defined.")
}
# out:
# Project MESSAGE: NARF is not defined.
versionAtLeast(variablename, versionNumber)
比较variablename的版本好是否大于等于versionNumber。一般用于判断当前Qt的版本,示例如下:
versionAtLeast(QT_VERSION, 5.12.0):message("Qt 5.12.0")
# out:
# Project MESSAGE: Qt 5.12.0
versionAtMost(variablename, versionNumber)
比较variablename的版本好是否小于等于versionNumber。一般用于判断当前Qt的版本,示例如下:
versionAtMost(QT_VERSION, 5.15.2):message("Qt 5.15.2")
# out
# Project MESSAGE: Qt 5.15.2
warning(string)
以警告的形式输出字符串。同时会在IDE的问题栏中输出信息。
error(string)以错误的形式输出字符串。同时会在IDE的问题栏中输出信息。
eval(string)使用qmake语法规则评估字符串的内容并返回true。定义新的变量或修改现有变量的值。示例如下:
# TARGETS 变量没有定义时
eval(TARGETS = myapp) {
message($$TARGETS)
}
# out:
# Project MESSAGE: myapp
# TARGET 变量已定义时
message($$TARGET)
eval(TARGET = myapp) {
message($$TARGET)
}
# out: ProTest是当前测试项目的名称
# Project MESSAGE: ProTest
# Project MESSAGE: myapp
exists(filename)
判断文件名的文件是否存在。如果存在则返回成功,否则返回失败。
isEmpty(variablename)如果variablename变量为空则返回true,反之返回false。等价于count(variablename,0)。例如:
isEmpty(CONFIG) {
CONFIG += qt warn_on debug}
替换函数
basename(variablename)
返回指定文件的base文件名称。例如:
FILE = /etc/passwd
FILENAME = $$basename(FILE)
# out:
# passwd
dirname(file)
返回指定文件的目录部分。例如:
FILE = /etc/X11R6/XF86Config
DIRNAME = $$dirname(FILE)
# out:
# /etc/X11R6
find(variablename, substr)
在variablename变量的所有值中查找匹配substr字符串的值,substr可能是正则表达式。例如:
MY_VAR = one two three four
MY_VAR2 = $$find(MY_VAR, t.*)
message($$MY_VAR2)
# out:
# two three
join(variablename,glue,before,after)
使用glue连接variablename变量中的值。如果变量的值非空,在值前面加一个前缀before,在值的后面加一个后缀after。Variablename是必须参数,其它参数默认是空字符串。如果需要在glue、before、after中对空格进行编码,必须对它们使用引号。例如:
MY_VAR = one two three four
MY_VAR2 = $$join(MY_VAR, " -L", -L) -Lfive
MY_VAR3 = $$join(MY_VAR, " -L", -L, -M)
message($$MY_VAR2) #out: -Lone -Ltwo -Lthree -Lfour -Lfive
message($$MY_VAR3) #out: -Lone -Ltwo -Lthree -Lfour-M
member(variablename,position)
返回variablename变量的值列表中位置为position的值。如果找不到对应位置,则返回空字符串。如果不指定position参数,则默认为0,返回值列表中的第一个值。
可以理解variablename为一个数组,而position为数组的下标。例如:
MY_VAR = one two three four
MY_VAR2 = $$member(MY_VAR, 3)
MY_VAR3 = $$member(MY_VAR, 2)
message($$MY_VAR2) #out: four
message($$MY_VAR3) #out: three
replace(string, old_string, new_string)
在string字符串中找到old_string字符串,然后用new_string进行替换。例如:
MESSAGE = This is a tent.
message($$replace(MESSAGE, tent, test))
# out:
# This is a test.
unique(variablename)
返回variablename变量的所有值,如果有重复的则删除。例如:
ARGS = 1 2 3 2 5 1
ARGS = $$unique(ARGS) #out: 1 2 3 5
其他
自定义变量以及变量内容的访问
CUSTOMVAL = ./bin # 自定义变量名为CUSTOMVAL
message($$CUSTOMVAL) # 输出CUSTOMVAL变量值
# out:
# Project MESSAGE: ./bin
值列表(每个值之间用空格分割)
LIST = 1 2 3
for(a, LIST):message(I see a file.$${a}!)
# out:
# Project MESSAGE: I see a file.1!
# Project MESSAGE: I see a file.2!
# Project MESSAGE: I see a file.3!
单值(单值且中间包含空格时需要用双引号来包含)
LIST = "1 2 3"
for(a, LIST):message(I see a file.$${a}!)
# out:
# Project MESSAGE: I see a file.1 2 3!
注释
# 注释是以'#'符合作为注释的开头,以行末尾作为结束
如果要在变量中使用’#'字符,必须使用内置变量LITERAL_HASH,示例如下:
urlPieces = http://doc.qt.io/qt-5/qtextdocument.html pageCount
message($$join(urlPieces, $$LITERAL_HASH))
# out:
# Project MESSAGE: http://doc.qt.io/qt-5/qtextdocument.html#pageCount
# 注意,想要在变量中使用'#'字符,只有这一种方式,用双引号来包含也是没有用的
QMake指南(Pro文件指南)_枫焱宇的博客-CSDN博客_qmake生成pro