使用Qt6 和现代 c++ 进行跨平台开发 9:跨平台开发

自从最初发布以来,Qt就以其跨平台的能力而闻名——这是创建这个框架背后的主要愿景。您可以在自己喜欢的桌面平台(如Windows、Linux和macOS)上使用Qt Creator,并使用相同的代码库或稍加修改,创建流畅、现代、触摸友好的图形用户界面(GUI)和桌面、移动或嵌入式应用程序。您可以轻松地修改代码并将其部署在目标平台上。Qt有几个内置工具来分析您的应用程序及其在各种支持平台上的性能。此外,与其他跨平台框架不同,它易于使用,具有直观的用户界面(UI)。

在这一章中,你将学习跨平台开发的要点,以及如何在不同的平台上构建应用程序。有了它,您将能够在您喜爱的桌面和移动平台上运行示例应用程序。

在本章中,我们将讨论以下主要话题:

  • 了解跨平台开发
  • 了解编译器
  • 使用qmake构建
  • Qt项目(.pro)文件
  • 了解构建设置
  • 特定平台的设置
  • 在Microsoft Visual Studio中使用Qt
  • 在Linux上运行Qt应用程序
  • 在macOS和iOS上运行Qt应用程序
  • 其他Qt支持的平台
  • 从Qt 5移植到Qt 6

本章结束时,你将理解Qt项目文件,基本设置,以及如何在移动设备上运行你的Qt应用程序。我们开始吧!

技术要求

本章的技术要求包括安装在最新桌面平台(如Windows 10、Ubuntu 20.04或macOS 10.14)上的Qt 6.0.0和Qt Creator 4.14.0的以上版本。

了解跨平台开发

市场上有几个跨平台的框架,但是Qt是一个更好的选择,因为它很成熟并且有社区支持。对于一个传统的C++开发者来说,很容易更快的适应Qt,开发出高质量的应用。Qt框架允许开发人员开发与多种平台兼容的应用程序,如Windows、Linux、macOS、QNX(最初称为Quick Unix [Qunix])、iOS和Android。它以更好的代码质量、一次编码随处部署的理念促进了更快的应用程序开发。Qt在内部处理特定于平台的实现,并使您能够在微控制器驱动的设备上用令人印象深刻的GUI,构建惊人的超轻量应用程序。

要使用Qt为嵌入式平台开发应用程序,您需要一个商业许可证来使用Qt for Device Creation。Qt还支持一些微控制器单元(MCU)平台,如瑞萨、STM32和恩智浦。在写这本书的时候,推出了Qt for MCUs 1.8,它提供了超轻量级的模块,内存占用很小。

下面列出了使用Qt框架进行跨平台开发的一些优势:

  • 降低开发成本的成本效益
  • 更好的代码可重用性
  • 便利性
  • 更快的上市时间(TTM)
  • 更广泛的市场覆盖面
  • 提供近乎本土的体验
  • 高性能

也有一些缺点,例如:

  • 平台特定功能不可用,无法访问所有平台应用程序编程接口(API)
  • 本地和非本地组件之间的通信挑战
  • 某些特定于设备的功能和硬件兼容性挑战
  • 平台更新延迟

在本节中,您了解了Qt跨平台特性的基本概念,并了解了跨平台开发的优缺点。在您可以在任何平台上运行应用程序之前,您需要一个编译器来为目标平台编译应用程序。在下一节中,我们将了解Qt框架支持的编译器。

了解编译器

在本节中,您将学习什么是编译器,以及如何使用它进行跨平台开发。编译器是一种软件,它将你的程序转换成机器代码或低级指令,可以被计算机读取和执行。这些低级机器指令因平台而异。您可以使用不同的编译器来编译Qt应用程序,比如GNU Compiler Collection (GCC ),也可以使用供应商提供的编译器。在Qt Creator中,您可以在Kits选项卡下找到工具包支持的编译器,以及在特定平台(如Windows、Linux或macOS)上构建应用程序的其他基本工具。Qt安装程序并没有提供所有支持的编译器,但是您可以在推荐的工具包中找到自动列出的最广泛使用的编译器。Qt可能会停止对某些套件配置的支持,或者用最新版本替换它们。

目前,Qt支持以下编译器:

  • GCC
  • 极简的Windows版GNU(MinGW)
  • Microsoft Visual C++ (MSVC)
  • 低级虚拟机(LLVM)
  • 英特尔C++编译器(ICC)
  • Clang和clang-cl
  • Nim
  • QCC

此外,Qt Creator裸机设备插件为以下编译器提供支持:

  • IAR嵌入式工作台(IAREW)
  • KEIL
  • 小型设备C编译器(SDCC)

除了前面的编译器,Qt在构建Qt项目时还使用了特定的内置编译器。下面列出了这些:

元对象编译器(moc)

用户界面编译器(uic)

资源编译器(rcc)

您可以使用上述编译器为目标平台构建应用程序,或者添加定制的编译器配置。在下一节中,您将学习如何创建一个定制的编译器配置。

添加自定义编译器

要添加一个不被Qt Creator自动检测到或者不可用的编译器,请使用Custom选项。您可以指定目录的编译器和工具链路径,并进行相应地配置。

要添加自定义编译器配置,请按照下列步骤操作:

1.要在Qt中创建新的编译器配置,单击菜单栏上的Tools菜单,然后从左侧窗格中选择Kits选项卡。

2.然后,单击编译器选项卡,并从添加下拉列表中选择自定义。您将在上下文菜单中看到C和C++选项。根据您的要求选择型号。您可以在下面的屏幕截图中看到对此的描述:

3.在下一步中,使用编译器的自定义名称来完成Name字段。

4.接下来,在编译器路径(Compiler path)字段中,选择编译器所在目录的路径。

5.接下来,在Make path字段中,浏览make工具所在目录的路径。

6.在下一步中,在ABI字段中指定应用程序二进制接口(ABI)版本。

如下图:

7.接下来,您可以在预定义的宏字段中指定默认的必需宏。按以下格式在单独的行中指定每个宏:MACRO [=value]。

8.在下一步中,在Header paths字段中指定编译器检查头的目录的路径。

9.接下来,在C++11标志字段中,指定打开C++11支持的标志。

10.在下一步中,在Qt mkspecs字段中指定mkspecs(编译规则)的位置。

11.接下来,在“错误解析器(Error parser)”字段中,选择一个合适的错误解析器。

12.单击“应用(Apply)”按钮保存配置。

在本节中,您了解了受支持的编译器以及如何在Qt Creator中创建新的编译器配置,但是要构建和运行一个项目,我们需要的不仅仅是一个编译器。为了方便起见,Qt提供了qmake作为内置的构建工具。在下一节中,我们将讨论qmake是什么。

使用qmake构建

Make是一个构建工具,它读取名为Makefile的项目配置文件,并构建可执行程序和库。qmake是Qt提供的构建工具,它简化了跨多个平台的开发项目的构建过程。它将每个项目文件中的信息扩展到一个Makefile文件中,该文件执行必要的编译和链接命令。它也可以用于非Qt项目。qmake基于项目文件中的信息生成Makefile,并包含支持Qt开发的补充特性,自动包含moc和uic的构建规则。qmake还可以为Microsoft Visual Studio创建项目,而不需要开发人员更改项目文件。

作为一个社区驱动的框架,Qt对开发人员来说非常灵活,让他们可以自由选择最适合自己项目的工具,而不会强迫他们使用自己的构建系统。Qt支持以下类型的构建系统:

qmake

CMake

Qbs

Meson

Incredibuild

您可以从Qt Creator UI或命令行运行qmake。每次对项目文件进行更改时,都应该运行qmake。下面是从命令行运行qmake的语法:

>qmake [mode] [options] files

qmake提供了两种不同的操作模式。在默认模式下,qmake使用项目文件中的信息来生成Makefile,但是它也可以生成项目文件。这些模式如下所示:

-makefile

-project

在Makefile模式下,qmake将生成一个用于构建项目的Makefile文件。在Makefile模式下运行qmake的语法如下所示:

>qmake -makefile [options] files

在项目模式下,qmake将生成一个项目文件。在项目模式下运行qmake的语法如下图所示:

>qmake -project [options] files

如果您将Visual Studio用作集成开发环境(IDE),则可以将现有的qmake项目导入到Visual Studio中。qmake可以创建一个包含开发环境所需的所有基本信息的Visual Studio项目。它可以递归地在子目录中生成一个.vcproj文件,在主目录中生成一个.sln文件,并使用以下命令:

>qmake -tp vc -r

例如,您可以通过运行以下命令为您的HelloWord项目生成一个Visual Studio项目:

>qmake -tp vc HelloWorld.pro

请注意,每次修改项目文件时,都需要运行qmake来生成更新的Visual Studio项目。您可以在以下链接中找到更多关于qmake的细节:

doc.qt.io/qt-6/qmake-ma

大多数qmake项目文件使用名称=值(name=vale)和名称+=值(name += value )定义的列表,定义项目使用的源文件和头文件,但是qmake中有其他的高级功能,它们使用其他操作符、函数、平台范围和条件来创建跨平台应用程序。关于qmake语言的更多细节可以在以下链接中找到: Qt Documentation | Page Not Found

Qt团队在Qt 6上投入了大量精力,通过转向广泛采用、流行的构建工具CMake,使其成为未来。通过使用Conan作为一些插组件的包管理器,实现了一些更改,使Qt更加模块化。Qt 6中的一些Qt模块不再可以在Qt在线安装程序中作为二进制软件包获得,但可以作为Conan包获得。您可以在以下链接了解更多关于构建系统更改和CMake作为默认构建工具的信息: Qt Documentation | Page Not Found

重要信息:在Qt 5中,构建系统是在qmake之上构建的,但在Qt 6中,CMake是从源代码构建Qt的构建系统。这个变化只影响那些希望从源代码构建Qt的开发人员。您仍然可以使用qmake作为Qt应用程序的构建工具。

在本节中,您了解了qmake。我们正在跳过高级qmake的主题来进行探索。在下一节中,我们将讨论由qmake解析的Qt项目文件。

Qt项目(.pro)文件

在前面的示例中,由Qt Creator创建的.pro文件实际上是Qt项目文件。.pro文件包含qmake构建应用程序、库或插件所需的所有信息。项目文件同时支持简单的和复杂的构建系统。一个简单的项目文件可以使用直接的声明,定义标准变量来指示在项目中使用的源文件和头文件。复杂的项目可以使用多个流结构来优化构建过程。项目文件包含一系列用来指定资源的声明,例如到源文件和头文件的链接、项目所需的库、针对不同平台的自定义构建过程等等。

Qt项目文件有几个部分,并使用某些预定义的qmake变量。让我们在这里看看我们早期的HelloWorld的例子.pro文件:

QT += core gui
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
CONFIG += c++17
# You can make your code fail to compile if it uses 
# deprecated APIs.
# In order to do so, uncomment the following line.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000
# disables all the APIs deprecated before Qt 6.0.0
SOURCES += \
 main.cpp \
 widget.cpp
HEADERS += \
 widget.h
FORMS += \
 widget.ui
# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target

项目文件只是告诉qmake项目中所需的Qt模块是什么,以及可执行程序的名称。它还链接到项目中需要包含的头文件、源文件、表单文件和资源文件。所有这些信息对于qmake创建配置文件和构建应用程序都是至关重要的。对于更复杂的项目,您可以针对不同的操作系统对项目文件进行不同的配置。

下表描述了最常用的变量及其用途:

Qt:项目中使用的QT模块列表

CONFIG:一般项目配置选项

DESTDIR:放置可执行文件或二进制文件的目录

FORMS:由UI编译器(uic)处理的UI文件列表

HEADERS:头的文件名列表构建项目时使用的.h文件

RESOURCES:资源列表包含在最终项目中(.qrc)文件

SOURCE:源代码列表,在构建项目时使用的(.cpp)文件

TEMPLATE:用于项目的模板

您可以向项目中添加不同的Qt模块、配置和定义。让我们来看看如何实现这一点。要添加额外的模块,只需在QT +=后添加module关键字,如下所示:

QT += core gui sql

您还可以在前面添加一个条件,以确定何时向项目中添加一个特定的模块,如下:

greaterThan(QT_MAJOR_VERSION, 4): QT += widgets

您还可以向项目中添加配置设置。例如,如果您想在编译项目时指定c++17规范,请将以下行添加到.pro文件中:

CONFIG += c++17

您可以向项目文件添加注释,以井号(#)开头,生成系统将忽略相应的文本行。现在,让我们来看看模板变量。这决定了构建过程的输出是应用程序、库还是插件。有不同的变量可以用来描述qmake将要生成的文件类型。这些因素如下:

app用于构建应用程序。

1ib用于构建库。

aux用于不构建任何内容。如果不需要调用编译器来创建目标,就使用这个方法——例如,因为您的项目是用解释型语言编写的。

subdirs用于使用SUBDIRS变量指定的子目录。每个子目录必须包含自己的项目文件。

vcapp用于创建Visual Studio项目文件来构建应用程序。

vclib用于创建Visual Studio项目文件来构建库。

vcsubdirs用于创建Visual Studio解决方案文件,以在子目录中构建项目。

Qt项目文件有时需要依赖include特性。在Qt项目文件中,还可以定义两个重要的变量:INCLUDEPATH和DEPENDPATH。您可以使用SUBDIRS变量来编译一组相关的库或模块。现在,让我们讨论什么是. pri文件。

理解.pro和.pri之间的差异

您可以创建一个. pri文件来包含复杂项目中的项目文件。这提高了可读性并隔离了不同的模块,. pri文件通常称为项目包含文件或qmake包含文件,其格式类似于. pro文件。主要区别在于使用目的;. pro文件是我们期望直接运行qmake的文件,而. pri文件包含在. pro文件中。您可以添加常见配置,如源文件、头文件。用户界面文件,以及。qrc文件放入.pri文件,并在多个.pro文件根据您的项目需求包含.pri文件。

include($$PWD/common.pri)

在本节中,您学习了什么是Qt项目文件,以及其中使用的不同变量。在下一节中,我们将讨论不同的构建设置。

了解生成设置

在编译或生成项目之前,编译器需要某些细节,这些细节称为生成设置。这是编译过程中非常重要的一部分。在本节中,您将了解构建设置以及如何以正确的方式配置它们。同一项目可以有多个生成配置。通常,Qt Creator会自动创建调试、发布和概要构建配置。调试版本包含调试应用程序所需的附加调试符号,而发布版本是没有这些符号的优化版本。通常,开发人员使用调试配置进行测试,使用发布配置创建最终的二进制文件。概要文件构建是一个优化的发布构建,它与单独的调试信息一起交付,最适合于分析应用程序。

可以在项目模式下指定构建设置。如果IDE中没有打开任何项目,您可能会发现“项目(Project)”按钮被禁用。通过单击“添加(Add)”下拉按钮,然后选择要添加的配置类型,可以添加新的构建配置。这些选项可能取决于为项目选择的构建系统。您可以根据需要添加多个构建配置。你可以点击克隆(Clone)...按钮添加一个基于当前构建配置的构建配置,或者单击重命名(Rename)...按钮来重命名当前选定的生成配置。单击“移除(Remove)”按钮移除构建配置。

你可以在下面的屏幕截图中看到对这个问题的概述:

通常,Qt Creator在来自源目录的不同目录中构建项目,称为影子构建。这将隔离为每个构建和运行工具包生成的文件。如果您只希望使用单个工具包进行构建和运行,则可以取消选中“阴影构建(Shadow build)”复选框。Qt Creator项目向导会创建一个可以编译的Qt Quick项目来使用Qt资源系统。要使用默认设置,请选择“使用默认(Leave as Default)”。要编译Qt Quick代码,请在Qt Quick编译器字段中选择“启用(Enable)”,如图5.3所示。您可以在以下链接中了解更多关于不同构建配置的信息: Specifying Build Settings

在本节中,我们讨论了构建设置。在构建跨平台应用程序时,将特定于平台的配置添加到项目文件中是很重要的。在下一节中,我们将了解特定于平台的设置。

平台特定的设置

您可以为不同的平台定义不同的配置,因为不是每个配置都适合所有的用例。例如,如果要为不同的操作系统包含不同的头路径,可以将以下代码行添加到您的.pro文件:

win32: INCLUDEPATH += "C:/mylibs/windows_headers"