入门指南
Cmake可以简化跨平台项目的构建过程,可以自动生成Makefile或者Visual Studio等项目文件。
Cmake官方文档:https://cmake.org/documentation/ 本文详细介绍如何在CMake中使用qt5。使用Qt5所需的最低版本是CMake 2.8.3,但建议使用3.1.0及以上的版本。
使用CMake构建Qt工程时,首先使用 find_package 去找到所需的库文件和头文件。然后需要去链接我们所需要的库,在CMake 2.8.11本版中推荐的方法是使用 target_link_libraries 命令去链接所需要的库,在 Windows上 CMake 2.8.11及以后的版本会自动地添加相应地文件目录、编译定义、地址无关代码(一种机器码)标志等链接到 qtmain.lib 库文件。
下面构建一个 helloworld GUI 项目的典型的方法:
cmake_minimum_required(VERSION 2.8.11)
project(testproject)
# Find includes in corresponding build directories
set(CMAKE_INCLUDE_CURRENT_DIR ON)
# Instruct CMake to run moc automatically when needed.
set(CMAKE_AUTOMOC ON)
# Find the QtWidgets library
find_package(Qt5Widgets)
# Tell CMake to create the helloworld executable
add_executable(helloworld WIN32 main.cpp)
# Use the Widgets module from Qt 5.
target_link_libraries(helloworld Qt5::Widgets)
这样我们就直接可以:
#include <QWidget>
为了使find_package成功,Qt5必须能够找到CMAKE_PREFIX_PATH,或者Qt5_DIR必须在CMake缓存中被设置用来找到Qt5WidgetsConfig.cmake 文件的位置。最简单的方法是把CMAKE_PREFIX_PATH设置到系统的环境变量,其值为qt的安装目录的vs 的bin目录,比如我的目录是:
CMAKE_AUTOMOC 会在需要的时候自动运行moc工具,更多详情参考:CMake AUTOMOC documentation
导入目标
导入目标是为每个Qt模块创建,导入的名称最好就是模块的名称,而不是像 target_link_libraries 那样使用一个变量 。导入的库的完整路径可以通过 LOCATION 属性获得。CMake中的大多数api都能自动检测到我们所导入的模块,而不需要完整路径。可以使用 Qt::<模块名称>的方式。
find_package(Qt5Core)
get_target_property(QtCore_location Qt5::Core LOCATION)
message(${QtCore_location})
打印:
Starting to parse CMake project.
D:/Qt/Qt5.9.6/5.9.6/msvc2015/bin/Qt5Core.dll
Configuring done
导入目标时会根据当前的模式导入debug的库或者release的库。
如果我们自定义CMake构建配置,可能需要设置一个从自定义的配置到Qt debug或者release模式的设置的一个映射。
find_package(Qt5Core)
set(CMAKE_CXX_FLAGS_COVERAGE "${CMAKE_CXX_FLAGS_RELEASE} -fprofile-arcs -ftest-coverage")
# set up a mapping so that the Release configuration for the Qt imported target is
# used in the COVERAGE CMake configuration.
set_target_properties(Qt5::Core PROPERTIES MAP_IMPORTED_CONFIG_COVERAGE "RELEASE")
插件也可以作为CMake中的导入目标。 Qt Network,、Qt SQL, Qt GUI,和Qt Widgets 模块都有相关的插件。它们提供一系列的插件,可以通过Qt5<模块名称>_PLUGINS变量获得。
foreach(plugin ${Qt5Network_PLUGINS})
get_target_property(_loc ${plugin} LOCATION)
message("Plugin ${plugin} is at location ${_loc}")
endforeach()
打印:
Plugin Qt5::QGenericEnginePlugin is at location D:/Qt/Qt5.9.6/5.9.6/msvc2015/plugins/bearer/qgenericbearer.dll
使用Qt5和低于3.1.0版本的Cmake
Qt 5.7要求c++支持。从3.1.0版开始的CMake隐式地向Qt5模块目标添加了所需的最少编译器标志(例如-std=gnu++11)。如果使用大于3.1.0的CMake版本,则需要添加所需的-std=…你自己链接到Qt5模块的目标。如果您使用Qt 5.7和超过3.1.0的CMake版本,并且需要更近期的c++标准版本,请使用选择标准版本的CMake方法,或者指定所需的特性并让CMake计算标志。例子:
set(CMAKE_CXX_STANDARD 14)
参考:CMake cmake-compile-features Documentation
使用Qt 5和低于2.8.12版本的Cmake
当使用较旧版本的CMake时将Qt5<模块名称>_EXECUTABLE_COMPILE_FLAGS添加到CMAKE_CXX_FLAGS,以便于在需要的时候将-fPIC 标志添加到编译标志中去。
使用Qt 5和低于2.8.11版本的Cmake
推荐通过 qt5_use_modules 宏来使用qt的库和头文件。在使用 qt5_use_modules 宏之前需要使用 find_package 来找到qt的相关库。参考CMake find_package Documentation查看所有支持的选项。qt5_use_modules 宏封装了使用Qt模块所需的所有变量。如果没有找到给它的模块,它会自动在命令行中找到它们。
find_package(Qt5Widgets)
add_executable(helloworld WIN32 main.cpp)
qt5_use_modules(helloworld Widgets)
使用Qt 5和低于2.8.9版本的Cmake
如果使用早于2.8.9的CMake,则 qt5_use_modules 宏不可用。试图使用它将导致错误。需要使用target_link_libraries、include_directory和add_definitions命令,并使用qt5_generate_moc或qt5_wrap_cpp手动指定moc需求:
cmake_minimum_required(VERSION 2.8.3)
project(testproject)
# Find includes in corresponding build directories
set(CMAKE_INCLUDE_CURRENT_DIR ON)
# Find the QtWidgets library
find_package(Qt5Widgets)
# Add the include directories for the Qt 5 Widgets module to
# the compile lines.
include_directories(${Qt5Widgets_INCLUDE_DIRS})
# Use the compile definitions defined in the Qt 5 Widgets module
add_definitions(${Qt5Widgets_DEFINITIONS})
# Add compiler flags for building executables (-fPIE)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${Qt5Widgets_EXECUTABLE_COMPILE_FLAGS}")
qt5_generate_moc(main.cpp main.moc)
# Tell CMake to create the helloworld executable
add_executable(helloworld main.cpp main.moc)
#Link the helloworld executable to the Qt 5 widgets library.
target_link_libraries(helloworld Qt5::Widgets)
变量的引用
模块变量
调用find_package导入的目标,将用于target_link_libraries,一些变量将填充配置构建所需的信息,并提供可用的宏。每个模块导入的目标名称与模块名称匹配,前缀为’Qt5::’,例如Qt5::Widgets。所有用于模块的变量都有一个与模块名称前缀一致的名称。例如,find_package(Qt5Widgets)如果成功找到,将提供以下变量:
- Qt5Widgets_VERSION: 描述模块版本。
- Qt5Widgets_VERSION_STRING: 和Qt5Widgets_VERSION一样,弃用,使用Qt5Widgets_VERSION代替。
- Qt5Widgets_LIBRARIES: 用于target_link_libraries命令的库列表。
- Qt5Widgets_INCLUDE_DIRS: 用于include_directory命令的头文件目录列表。
- Qt5Widgets_DEFINITIONS:用于add_definitions的定义列表。
- Qt5Widgets_COMPILE_DEFINITIONS:与COMPILE_DEFINITIONS目标属性一起使用的定义列表。
- Qt5Widgets_FOUND: bool类型,是否成功找到模块。
- Qt5Widgets_EXECUTABLE_COMPILE_FLAGS: 在构建可执行文件时使用的标志。
使用find_package找到的所有包都可以使用这些变量。注意变量的大小写。
安装变量
此外,还有一些其他变量可用,这些变量与特定包无关,而与Qt安装本身有关。
- QT_VISIBILITY_AVAILABLE: Boolean类型,描述Qt是否使用隐藏可见性构建
- QT_LIBINFIX: 包含库名称中使用的中缀的字符串。
宏
Qt5Core 宏
当找到Qt5Core时,宏可用。
宏 | 描述 |
---|---|
qt5_wrap_cpp(outfiles inputfile … OPTIONS …) | 使用Q_OBJECT声明从包含Qt类的文件列表创建moc代码。 还添加了每个目录的预处理器定义。 可以向moc提供选项,例如在执行“moc -help”时找到的选项。 |
qt5_add_resources(outfiles inputfile … OPTIONS …) | 从Qt资源文件列表中创建代码。 可以给rcc选项,例如执行“rcc -help”时找到的选项。 |
qt5_add_binary_resources(target inputfile … OPTIONS … DESTINATION …) | 从Qt资源文件列表中创建RCC文件。 可以给rcc选项,例如执行“rcc -help”时找到的选项。 可以给出目的地以使用RCC文件的不同文件名或路径。 |
qt5_generate_moc(inputfile outputfile ) | 创建一个规则以在infile上运行moc并创建outfile。 如果由于某种原因QT5_WRAP_CPP()不合适,请使用此选项,例如: 因为您需要moc文件的自定义文件名或类似的东西。 |
qt5_use_modules(target [LINK_PUBLIC|LINK_PRIVATE] module … ) | 表示目标使用指定的Qt 5模块。 目标将链接到指定的模块,使用这些模块安装的include目录,使用这些模块设置的COMPILE_DEFINITIONS,并使用模块设置的COMPILE_FLAGS。 可以选择指定LINK_PRIVATE或LINK_PUBLIC说明符。 如果指定了LINK_PRIVATE,则模块不会成为目标链接接口的一部分。 有关更多信息,请参阅target_link_libraries的文档。请注意,此宏仅在使用CMake 2.8.9或更高版本时可用。 这个宏已经过时了。 请将target_link_libraries与IMPORTED目标一起使用。 |
Qt5Widgets 宏
找到Qt5Widgets时可用的宏。
宏 | 描述 |
---|---|
qt5_wrap_ui(outfiles inputfile … OPTIONS …) | 从Qt设计器ui文件列表中创建代码。 可以给uic选项,例如执行“uic -help”时找到的选项 |
Qt5DBus 宏
找到Qt5DBus时可用的宏。
宏 | 描述 |
---|---|
qt5_add_dbus_interface(outfiles interface basename) | 使用给定接口xml文件中的给定basename创建接口头文件和实现文件,并将其添加到源列表中 |
qt5_add_dbus_interfaces(outfiles inputfile … ) | 为所有列出的接口xml文件创建接口头文件和实现文件,名称将根据xml文件的名称自动确定 |
qt5_add_dbus_adaptor(outfiles xmlfile parentheader parentclassname [basename] [classname]) | 从描述接口的xml文件创建dbus适配器(头文件和实现文件),并将其添加到源列表中。 适配器将调用转发到父类,在parentheader中定义并命名为parentclassname。 生成的文件的名称将是 adapter。{cpp,h}其中basename默认为xml文件的基本名称。 如果提供了,那么它将用作适配器本身的类名。 |
qt5_generate_dbus_interface( header [interfacename] OPTIONS …) | 从给定标头生成xml接口文件。 如果省略了可选参数interfacename,则接口文件的名称将从标头的基本名称构造,并附加后缀.xml。 选项可以给qdbuscpp2xml,例如执行“qdbuscpp2xml --help”时找到的选项 |
Qt5LinguistTools 宏
找到Qt5LinguistTools时可用的宏。
宏 | 描述 |
---|---|
qt5_create_translation( qm_files directories … sources … ts_files … OPTIONS …) | Out:qm_files In:目录源ts_files选项:传递给lupdate的标志,例如-extensions,用于指定目录扫描的Extensions。 生成命令以创建.ts(通过lupdate)和.qm(通过lrelease) - 来自目录和/或源的文件。 ts文件在源树中创建和/或更新(除非以完整路径给出)。 qm文件在构建树中生成。 更新翻译可以通过将qm_files添加到库/可执行文件的源列表中来完成,因此它们总是会更新,或者通过添加自定义目标来控制它们何时更新/生成。 |
qt5_add_translation( qm_files ts_files … ) | Out:qm_files In:ts_files生成命令以从.ts文件创建.qm。 生成的文件名可以在qm_files中找到。 ts_files必须存在且不以任何方式更新。 |
简单的示例:
cmake_minimum_required(VERSION 2.8)
project(TestCmake)
find_package(Qt5Widgets)
set(CMAKE_AUTOMOC ON)
add_executable(${PROJECT_NAME} main.cpp mainwindow.cpp)
target_link_libraries(TestCmake Qt5::Widgets)