Qt配置文件总是不知其然,每次工程建立,需要改配置文件,不论是qmake的.pro,还是cmake的CMakeLists.txt,都是靠一手浏览器解决,从未真正掌握过。因此这篇文章开始学习和掌握Qt配置文件的语法和书写,进行知识总结。

以参考官方手册为佳

一、Qt工具moc,uic,rcc详解

Qt可看作一个C++界面库,对C++语法进行了扩展,可以跨平台编译。

MOC

Qt将源码交给标准C++编译器前,需要事先将这些扩展的语法解析,完成这一操作的就是moc。

moc全称Meta-Object Compiler,元对象编译器。MOC分析Qt的C++源文件时,如果发现在一个头文件中包含了宏Q_OBJECT,则会生成另一个C++源文件,该文件中包含了Q_OBJECT宏的实现代码,该文件的名称将会是原文件名前加上“moc_”构成。moc的执行在预处理器之前,因为预处理器执行后,Q_OBJECT宏就不存在了。新生成的源文件参与到标准编译器的编译中,编译过程中如果找不到对应的moc文件将出现链接错误。

1
moc myclass.h -o moc_myclass.cpp

UIC

用designer设计的x.ui文件可通过uic工具转换为头文件,名称为ui_x.ui。ui文件的使用就是利用默认工具uic自动产生一个类,然后用该类的setui函数加载界面到相应的对象上。

.ui文件使用有三种形式:1.直接使用,2.定义一个新类,声明一个ui子对象,利用该对象来加载界面,3.将ui作为基类派生新的类。

1
uic app.ui -o ui_app.h

RCC

rcc用于将.qrc里面描述的图片、文档等编译成对应的源代码文件qrc_*.cpp或者独立的二进制资源文件*.rcc。

生成独立的二进制资源文件.rcc

对于太大的图片、音频、视频等文件,不适合集成到目标程序内部,可以放到操作系统文件目录,或单独编译成外挂资源.rcc。

1
rcc -binary myresource.qrc -o myresource.rcc

代码中使用myresource.rcc,需要在main函数开始的位置注册这个独立的二进制资源文件:

1
QResource::registerResource("/path/to/myresource.rcc");

使用文件时用虚拟文件路径,在qml中使用rcc的内容,前缀是qrc:/;在Qt C++中前缀是:

应用程序内嵌资源

如果希望一个资源描述文件application.qrc在程序编译时内嵌到目标程序里,需要在*.pro文件里添加:

1
RESOURCES += application.qrc

qmake会自动为application.qrc添加编译脚本。

rcc工具会解析 application.qrc内的 XML文本,找到需要添加的各种文件,默认情况下,rcc 工具会对这些文件做ZIP压缩,然后将压缩后的ZIP数据的每个字节转换成比如 0x6f数值形式,所有文件压缩后的数据对应一个C++静态数组 qt_resource_data[],并添加注册、取消注册、初始化、清除等函数和资源描述结构体,最终形成一个 qrc_application.cpp文件。然后用编译器编译qrc_application.cpp文件,得到 qrc_applicaotion.o ,链接到目标程序内部,就可以用 “:/images/copy.png” 等形式访问程序内嵌资源了。
注意到刚才向 .pro 文件里添加 qrc 资源描述文件使用的运算符是+=,也就是说可以为应用程序添加多个.qrc 文件,如果涉及的图片比较多,可以用多个*.qrc 对图片分类存放:

1
2
RESOURCES += buttons.qrc 
RESOURCES += backgrounds.qrc

使用多个*.qrc 与使用一个*.qrc 的方式是一样的,虚拟文件路径都类似 “:/buttons/ok.png” 、”:/backgrounds/bgmain.png” 等,这里的 ok.png 放在项目文件夹的 buttons 子文件夹里,而 bgmain.png 是放在项目文件夹的 backgrounds 子文件夹里,因此两个文件的路径是不同的。
qmake 为内嵌资源添加的 rcc 编译命令,类似下面这样:

1
rcc -name application  application.qrc -o qrc_application.cpp

得到 qrc_application.cpp 源文件之后,剩下的编译、链接就与普通 .cpp 文件一模一样了。
qrc_application.cpp 文件中不仅有各种图片、文档对应的静态数组,还有些结构体和函数,比如初始化和清除函数。
对于rcc命令,如果不加-name application选项参数,那么在 qrc_application.cpp 里面生成的初始化和清除函数名为:

1
2
int QT_RCC_MANGLE_NAMESPACE(qInitResources)();
int QT_RCC_MANGLE_NAMESPACE(qCleanupResources)();

如果加了-name application选项参数,那么资源的初始化和清除函数名变为:

1
2
int QT_RCC_MANGLE_NAMESPACE(qInitResources_application)();
int QT_RCC_MANGLE_NAMESPACE(qCleanupResources_application)();

QT_RCC_MANGLE_NAMESPACE() 这个宏其实没什么用,仅用于提示作用。资源的初始化函数和清除函数会在资源加载和卸载时自动被调用。
应用程序的内嵌资源通常不需要手动初始化,但也有例外情况,比如在使用某些链接库中的资源文件时,如果出现使用了正确的文件路径 “:/images/copy.png” 却找不到资源里图片文件的情况,那么需要在使用该资源的类声明里或者在 main 函数里打头的位置加入一句手动初始化:

1
Q_INIT_RESOURCE(resources);

resources 是指 resources.qrc 的简短名字形式,不需要扩展名。

二、qmake的.pro配置

应当仔细阅读Qt qmake手册

qmake工具是与Qt一起提供的,为不同平台和编译器生成Makefile。

对于某些简单的项目,可以在其项目顶层目录下直接执行qmake -project命令来自动生成.pro文件,对复杂程序,需要手动改写.pro文件。

常用Pro文件变量

HEADERS

指定项目的头文件。qmake会自动检测头文件的类中是否需要moc,并增加适当的依赖关系和文件到项目中,来生成和链接moc文件

SOURCES

指定项目的C++文件

TEMPLATE

模板变量告诉qmake为这个应用程序生成哪种makefile。

选项 说明
qpp 创建一个用于构建应用程序的Makefile(默认)。
lib 创建一个用于构建库的Makefile。
subdirs 创建一个用于构建目标子目录的Makefile,子目录使用SUBDIRS变量指定。
aux 创建一个不建任何东西的Makefile。如果没有编译器需要被调用来创建目标,比如你的项目使用解释型语言写的,使用此功能。注:此模板类型只能用于Makefile-based生成器。特别是,它不会工作在vcxproj和Xcode生成器。
vcapp 仅适用于Windows。创建一个Visual Studio应用程序项目。
vclib 仅适用于Windows。创建一个Visual Studio库项目。
vcsubdirs Visual Studio解决方案,构建子目录项目

FORMS

指定需要uic处理的由Qt designer 生成的.ui文件。所有的构建这些UI文件所需的依赖、头文件和源文件都会被自动添加到项目中

RESOURCES

指定需要rcc处理的.qrc文件

DEFINES

指定预定义的C++预处理器符号

INCLUDEPATH

指定C++编译器搜索全局头文件的路径。如果包含空格,需引号。

LIBS

指定工程要链接的库。-l library -L library_path

CONFIG

指定各种用于工程配置和编译的参数。

QT

指定工程所要使用的Qt模板(默认是core,gui对应于QtCore和QtGui,以确保标准的GUI应用程序无需进一步的配置就可以构建)。如果想建立一个不包含Qt GUI模块的项目,可以使用-=操作符。

TARGET

指定可执行文件的基本文件名

DESTDIR

指定可执行文件放置的目录

DEPENDPATH

指定查看解决依赖关系的目录列表,当包含文件时使用

MOC_DIR

指定来自moc的所有中间文件(含Q_OBJECT宏的头文件转换成标准.h文件的存放目录)放置的目录

OBJECTS_DIR

指定所有中间文件.o放置的目录

RCC_DIR

指定Qt资源编译器输出文件的目录

TRANSLATIONS

指定包含用户界面翻译文本的翻译(.ts)文件列表

1
2
TRANSLATIONS += Resource/myapp_zh.ts \
Resource/myapp_en.ts

UI_DIR

指定来自uic的所有中间文件放置的目录

|————————————————————————————————————|

CONFIG变量用于指定编译器选项和项目配置,参数如下:

选项 说明
qt 指应用程序使用Qt。此选项是默认包括的。CONFIG如果包含qt,可以使用QT变量(QT变量默认包含gui和core模块)控制应用程序需要的任何附加Qt模块
debug 编译出具有调试信息的可执行程序
release 使用release模式构建,如果debug也被指定会被忽略
dll 动态编译库文件
staticlib 静态编译库文件
console 指应用程序需要写控制台(使用cout、cerro、qWarning()等)
debug_and_release 项目准备以debug和release两种模式构建。
debug_and_release_target 此选项默认设置。如果也指定了debug_and_release,最终的debug和release构建在不同的目录。
build_all 如果指定了debug_and_release,默认情况下,该项目会构建为debug和release模式。
autogen_precompile_source 自动生成一个.cpp文件,包含在.pro中指定的预编译头文件。
ordered 使用subdirs模板时,此选项指定应该按照目录列表的顺序处理它们。
precompile_header 可以在项目中使用预编译头文件的支持。
warn_on 编译器应该输出尽可能多的警告。如果也指定了warn_off,最后一个生效。
warn_off 编译器应该输出尽可能少的警告。
exceptions 启用异常支持。默认设置。
exceptions_off 禁用异常支持。
rtti 启用RTTI支持。默认情况下,使用编译器默认。
rtti_off 禁用RTTI支持。默认情况下,使用编译器默认。
stl 启用STL支持。默认情况下,使用编译器默认。
stl_off 禁用STL支持。默认情况下,使用编译器默认。
thread 启用线程支持。当CONFIG包括qt时启用,这是缺省设置。
c++11 启用c++11支持。如果编译器不支持c++11这个选项,没有影响。默认情况下,支持是禁用的。
c++14 启用c++14支持。如果编译器不支持c++14这个选项,没有影响。默认情况下,支持是禁用的。

内置函数和控制流

include()可引用外部项目

1
include(other.pro)

通过作用域实现条件语句,类似编程语言中的if语句

1
2
3
win32 {
SOURCES += paintwidget_win.cpp
}

其它包括find(),unique(),count()等

同时CONFIG()可以用来测试配置选项是否被包含

1
2
3
4
5
CONFIG(opengl){
message(Building with OpenGL support.)
}else{
message(OpenGL support is not avilable.)
}

变量扩展

$$操作符用来提取变量的值,可被用来将值在变量与函数间传递

访问qmake特性

特殊$$[...]操作符可用来访问qmake特性:

1
2
3
4
5
6
7
8
9
10
11
12
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])

三、cmake的CMakeLists.txt

应参考

cmake-qt手册(中文)

cmake-qt手册(英文)

前言

CMake可以找到并使用Qt 4 和Qt 5。Qt 4库是由CMake附带的 FindQt4 查找模块找到的,而Qt 5库是使用Qt 5附带的“配置文件包”找到的。

Qt 4和Qt 5可以在同一 CMake buildsystem 一起使用:

1
2
3
4
5
6
7
8
9
10
11
12
13
cmake_minimum_required(VERSION 3.8.0 FATAL_ERROR)

project(Qt4And5)

set(CMAKE_AUTOMOC ON)

find_package(Qt5 COMPONENTS Widgets DBus REQUIRED)
add_executable(publisher publisher.cpp)
target_link_libraries(publisher Qt5::Widgets Qt5::DBus)

find_package(Qt4 REQUIRED)
add_executable(subscriber subscriber.cpp)
target_link_libraries(subscriber Qt4::QtGui Qt4::QtDBus)

一个 CMake 目标不能同时链接到 Qt 4 和 Qt 5。如果试图这样做或者是目标依赖性评估的结果,就会发出一个诊断。

Qt构建工具

Qt依赖于一些捆绑的代码生成工具,例如moc用于元对象代码生成,uic用于小部件布局和填充,以及rcc用于虚拟文件系统内容生成。如果满足适当的条件,这些工具可以有cmake自动调用。自动工具调用可以与Qt 4和Qt 5一起使用。

AUTOMOC

AUTOMOC属性控制cmake是否检查目标中的C++文件,以确定它们是否需要运行moc,并在适当的时间创建规则执行moc。

如果在头文件中找到来自AUTOMOC_MACRO_NAMES的宏,则将在该文件上运行moc。结果将放入如moc_<basename>.cpp命名的文件中。如果在C++实现文件中找到该宏,则将按照Qt约定将moc输出到如<basename>.moc命名的文件中。用户必须使用预处理器#include将<basename>.moc包含在C++实现文件中。

包含的moc_*.cpp*.moc文件将在<AUTOGEN_BUILD_DIR>/include目录中生成,该目录会自动添加到目标的INCLUDE_DIRECTORIES中。

  • 这与CMake 3.7及以下版本不同,详情请看他们的文档
  • 对于multi configuration generators,include目录为<AUTOGEN_BUILD_DIR>/include_<CONFIG>
  • 参见AUTOGEN_BUILD_DIR

不包括在内的moc_<basename>.cpp文件将在自定义文件夹中生成,以避免名称冲突,并包含在一个单独的文件中,该文件已编译到目标中,名为<AUTOGEN_BUILD_DIR>/mocs_compilation.cpp<AUTOGEN_BUILD_DIR>/mocs_compilation_$<CONFIG>.cpp

moc命令行将消耗从被调用的目标中处理COMPILE_DEFINITIONS和INCLUDE_DIRECTORIES目标属性为适当的构建配置。

通过设置CMAKE_AUTOMOC变量,AUTOMOC目标属性可为之后所有目标预置。AUTOMOC_MOC_OPTIONS可以填充设置选项传递给moc。可以填充CMAKE_AUTOMOC_MOC_OPTIONS变量,以为之后所有目标预置选项。

可将其它要搜索的宏名称添加到AUTOMOC_MACRO_NAMES中。

可使用AUTOMOC_DEPEND_FILTERS从源代码中提取其它moc依赖项文件名。

通过启用SKIP_AUTOMOC或更广泛的SKIP_AUTOGEN,可将C++源文件从AUTOMOC处理中排除。

AUTOUIC

AUTOUIC目标属性控制cmake是否检查目标中的C++文件,以确定它们是否需要运行uic,并在合适时机创建规则运行uic。

如果找到与 <path>ui_<basename>.h 匹配的预处理器 #include 指令,并且存在 <basename>.ui 文件,则将执行 uic 生成适当的文件。该 <basename>.ui 文件中搜索在以下地方

  1. <source_dir>/<basename>.ui
  2. <source_dir>/<path><basename>.ui
  3. <AUTOUIC_SEARCH_PATHS>/<basename>.ui
  4. <AUTOUIC_SEARCH_PATHS>/<path><basename>.ui

其中, 是C ++文件的目录,而 AUTOUIC_SEARCH_PATHS 是其他搜索路径的列表。

生成的 ui_*.h文件放置在/include目录中,该目录会自动添加到目标的 INCLUDE_DIRECTORIES 中。

该 AUTOUIC 目标属性可以通过设置对所有以下目标预先设定 CMAKE_AUTOUIC 变量。该 AUTOUIC_OPTIONS 目标属性可被填充设置选项传递给 uic 。该 CMAKE_AUTOUIC_OPTIONS 变量可被填充到预先设定的所有以下目标的选项。所述 AUTOUIC_OPTIONS 源文件属性可以在被设置 <basename>.ui 文件为文件组特定选项。这将覆盖来自 AUTOUIC_OPTIONS 目标属性的选项。

目标可以使用调用 uic 时应使用的选项来填充 INTERFACE_AUTOUIC_OPTIONS 目标属性。这必须与 AUTOUIC_OPTIONS 目标的AUTOUIC_OPTIONS目标属性内容一致。所述 CMAKE_DEBUG_TARGET_PROPERTIES 变量可被用于跟踪这样的原点目标 INTERFACE_AUTOUIC_OPTIONS 。这意味着为Qt提供替代翻译系统的库可以指定在运行 uic 时应使用的选项:

1
2
3
4
5
6
7
8
9
10
11
12
13
add_library(KI18n klocalizedstring.cpp)
target_link_libraries(KI18n Qt5::Core)

# KI18n uses the tr2i18n() function instead of tr(). That function is
# declared in the klocalizedstring.h header.
set(autouic_options
-tr tr2i18n
-include klocalizedstring.h
)

set_property(TARGET KI18n APPEND PROPERTY
INTERFACE_AUTOUIC_OPTIONS ${autouic_options}
)

链接到从上游导出的目标的消耗项目当uic由于AUTOUIC而运行时自动使用适当的选项,作为与导入目标链接的结果:

1
2
3
4
5
6
7
set(CMAKE_AUTOUIC ON)
# Uses a libwidget.ui file:
add_library(LibWidget libwidget.cpp)
target_link_libraries(LibWidget
KF5::KI18n
Qt5::Widgets
)

通过启用 SKIP_AUTOUIC 或更广泛的 SKIP_AUTOGEN ,可以将源文件从 AUTOUIC 处理中排除。

AUTORCC

AUTORCC目标属性控制cmake是否创建规则来执行 rcc 在适当的时间在其上具有后缀源文件 .qrc

1
add_executable(myexe main.cpp resource_file.qrc)

该 AUTORCC 目标属性可以通过设置对所有以下目标预先设定 CMAKE_AUTORCC 变量。该 AUTORCC_OPTIONS 目标属性可被填充设置选项传递给 rcc 。该 CMAKE_AUTORCC_OPTIONS 变量可被填充到预先设定的所有以下目标的选项。所述 AUTORCC_OPTIONS 源文件属性可以在被设置 <name>.qrc 文件设置为文件特定的选项。这将覆盖来自 AUTORCC_OPTIONS 目标属性的选项。

通过启用 SKIP_AUTORCC 或更广泛的 SKIP_AUTOGEN ,可以将源文件从 AUTORCC 处理中排除。

<ORIGIN>_autogen目标

moc 和 uic 工具作为由CMake生成的综合的<ORIGIN>_autogen custom target 一部分被执行。默认情况下该 <ORIGIN>_autogen 目标继承 <ORIGIN> 目标的依赖(见 AUTOGEN_ORIGIN_DEPENDS )。可以通过将目标依赖项添加到 AUTOGEN_TARGET_DEPENDS 目标属性中的方式将它们添加到<ORIGIN>_autogen 目标中。