WebAssembly的Qt

  • Post author:
  • Post category:其他


Qt for WebAssembly

WebAssembly的Qt

Qt for Webassembly lets you to run Qt applications on the web.

Qt for Webassembly允许您在web上运行Qt应用程序。

WebAssembly (abbreviated Wasm) is a binary instruction format intended to be executed in a virtual machine, for example in a web browser.

WebAssembly(缩写为Wasm)是一种二进制指令格式,旨在虚拟机中执行,例如在web浏览器中执行。

With Qt for WebAssembly, you can distribute your application as a web application that runs in a browser sandbox. This approach is suitable for web distributed applications that do not require full access to host device capabilities.

使用Qt for WebAssembly,您可以将应用程序作为在浏览器沙盒中运行的web应用程序分发。这种方法适用于不需要完全访问主机设备功能的web分布式应用程序。


Note:

Qt for WebAssembly is a supported platform, but some modules are not yet supported or are in Tech Preview. See supported modules.

注:Qt for WebAssembly是一个受支持的平台,但有些模块尚不受支持或在技术预览版中。请参阅支持的模块。

Getting Started with Qt for WebAssembly

Qt for WebAssembly入门

Building Qt applications for WebAssembly is similar to building Qt for other platforms. You need to install an SDK (Emscripten), install Qt (or build Qt from source), and finally, build the application. Some differences exist, for example, Qt for WebAssambly supports fewer modules and less features than other Qt builds.

为WebAssembly构建Qt应用程序与为其他平台构建Qt类似。您需要安装SDK(Emscripten)、安装Qt(或从源代码构建Qt),最后构建应用程序。存在一些差异,例如,与其他Qt构建相比,Qt for WebAssambly支持的模块和功能更少。

Installing Emscripten

安装Emscripten


Emscripten

is a toolchain for compiling to WebAssembly. It lets you run Qt on the web at near-native speed without browser plugins.

Emscripten是用于编译到WebAssembly的工具链。它可以让你在没有浏览器插件的情况下以接近本机速度在web上运行Qt。

Refer to the

Emscripten documentation

for more information about installing the Emscripten SDK.

有关安装Emscripten SDK的更多信息,请参阅Emscripten文档。

After installation, you should have the Emscripten compiler in your path. Check this with the following command:

安装后,路径中应该有Emscripten编译器。使用以下命令进行检查:

em++ --version

Each minor version of Qt targets a specific minimum Emcsripten version, which will not change for the lifetime of that minor version. Qt’s binary packages are built using this version of the Emscripten SDK. Install the minimum Emcsripten version that corresponds to the Qt version you use, especially if you use the binary packages.

Qt的每个次要版本都针对一个特定的最小Emcscripten版本,在该次要版本的生命周期内不会更改。Qt的二进制包是使用此版本的Emscripten SDK构建的。安装与您使用的Qt版本相对应的最低Emcscripten版本,尤其是在您使用二进制软件包时。

Later versions of Emscripten may work (and often do), but may introduce behavior changes which require changes to Qt.

稍后版本的Emscripten可能有效(并且经常有效),但可能会引入需要更改Qt的行为更改。

The minimum versions are:

最低版本为:

  • Qt 6.2: 2.0.14
  • Qt 6.3: 3.0.0
  • Qt 6.4: 3.1.14

Use

emsdk

to install specific

Emscripten

versions. For example, to install it for Qt 6.4 enter:

使用emsdk安装特定的Emscripten版本。例如,要为Qt 6.4安装它,请输入:

  • ./emsdk install 3.1.14
  • ./emsdk activate 3.1.14

On Windows, Emscripten is in your path after installation. On macOS or Linux you need to add it to your path, like this:

在Windows上,Emscripten在安装后位于您的路径中。在macOS或Linux上,您需要将其添加到路径中,如下所示:

source /path/to/emsdk/emsdk_env.sh

Check this with the following command:

使用以下命令进行检查:

em++ --version

Installing Qt

安装Qt

Download Qt from the Downloads section of your Qt account. We provide builds for Linux, macOS, and Windows as development platforms.

从Qt帐户的下载部分下载Qt。我们为Linux、macOS和Windows提供构建作为开发平台。

The binary builds are designed to run on as many browsers as possible, and do not enable features such as threads or SIMD support.

二进制版本设计为在尽可能多的浏览器上运行,并且不支持线程或SIMD支持等功能。

Building Qt from Source

从源代码构建Qt

Building from source lets you set Qt configuration options such as thread support, OpenGL ES level, or SIMD support. Download the Qt sources from the Downloads section of your Qt account.

从源代码构建允许您设置Qt配置选项,例如线程支持、OpenGL ES级别或SIMD支持。从Qt帐户的下载部分下载Qt源代码。

Configure Qt as a cross-compile build for the

wasm-emscripten

platform. This sets the

-static

,

-no-feature-thread

, and

-no-make examples

configure options. You can enable thread support with the

-feature-thread

, configure option. Shared library builds are not supported.

将Qt配置为wasm-emscripten平台的交叉编译版本。这将设置-static、-no feature thread和-no make examples配置选项。您可以使用-feature-thread,configure选项启用线程支持。不支持共享库生成。

You need a host build of the same version of Qt and specify that path in the

QT_HOST_PATH

CMake variable or by using the

-qt-host-path

configure argument.

您需要同一版本Qt的主机构建,并在

QT_HOST_PATH

CMake变量中或使用

-qt-host-path

配置参数指定该路径。

Although it should be detected, you may optionally set the

CMAKE_TOOLCHAIN_FILE

CMake variable to the Emscripten.cmake toolchain file that comes with Emscripten SDK. This can be done by setting the environment variable

CMAKE_TOOLCHAIN_FILE

or by passing

CMAKE_TOOLCHAIN_FILE=/path/to/Emscripten.cmake

to configure.

尽管应该检测到它,但您可以选择将CMAKE_TOOLCHAIN_FILE CMAKE变量设置为Emscripten.cmake(Emscripten SDK附带的cmake工具链文件)。这可以通过设置环境变量CMAKE_TOOLCHAIN_FILE或使用

CMAKE_TOOLCHAIN_FILE

=/path/to/Emscripten.cmake来完成配置。

./configure -qt-host-path /path/to/Qt -platform wasm-emscripten -prefix $PWD/qtbase

On Windows, make sure you have MinGW in your

PATH

and configure with the following:

在Windows上,确保您的PATH中有MinGW,并使用以下配置:

configure -qt-host-path C:\Path\to\Qt -no-warnings-are-errors -platform wasm-emscripten -prefix %CD%\qtbase

Then build the required modules:

然后构建所需的模块:

cmake --build . -t qtbase -t qtdeclarative [-t another_module]

Building Applications on the Command Line

在命令行上构建应用程序

Qt for WebAssembly supports building applications using qmake and make, or CMake with ninja or make.

Qt for WebAssembly支持使用qmake and make或CMake with ninja或make构建应用程序。

$ /path/to/qt-wasm/qtbase/bin/qt-cmake .
$ cmake --build .

Building the application generates several output files, including a .wasm file that contains the application and Qt code (statically linked), a .html file that can be opened in the browser to run the application.

构建应用程序会生成几个输出文件,包括一个包含应用程序的.wasm文件和Qt代码(静态链接),一个可在浏览器中打开以运行应用程序的.html文件。


Note:

Emscripten produces relatively large .wasm files at the “-g” debug level. Consider linking with “-g2” for debug builds.

注意:Emscripten在“-g”调试级别生成相对较大的.wasm文件。考虑使用“-g2”链接进行调试版本。

Running Applications

运行应用程序

Running the application requires a web server. The build output files are all static content, so any web server will do. Some use cases might require special server configuration, such as providing https certificates or setting http headers required to enable multithreading support.

运行应用程序需要web服务器。构建输出文件都是静态内容,所以任何web服务器都可以。某些用例可能需要特殊的服务器配置,例如提供https证书或设置启用多线程支持所需的http头。

Emrun

Emscripten provides the

emrun

utility for test-running applications. Emrun starts a web server, launches a browser, and will also capture and forward stdout/stderr (which will normally go to the JavaScript console).

Emscripten为测试运行的应用程序提供了emrun实用程序。Emrun启动web服务器,启动浏览器,还将捕获和转发stdout/stderr(通常会转到JavaScript控制台)。

/path/to/emscripten/emrun --browser=firefox appname.html

Python http.server

Another option is to start a development web server and then launch the web browser separately. One of the simplest options is http.server from Python:

另一种选择是启动开发web服务器,然后单独启动web浏览器。最简单的选项之一是来自Python的服务器http.server。

python -m http.server

qtwasmserver

Qt provides a developer web server which uses

mkcert

to generate https certificates. This allows testing web features which require a

secure context

. Note that delivery over http://localhost is also considered secure, without requiring a certificate.

Qt提供了一个开发人员web服务器,它使用mkcert生成https证书。这允许测试需要安全上下文的web功能。请注意,交付结束http://localhost也被认为是安全的,不需要证书。

The web server also sets the

COOP

and

COEP

headers to values which enalbles support for

SharedArrayBuffer

and multi-threading.

​web服务器还将COOP和COEP头设置为启用SharedArrayBuffer和多线程支持的值。

The qtwasmserver script starts one server which binds to localhost by default. You may add additional addresses using the

-a

command-line argument, or use

–all

to bind to all available addresses.

qtwasmserver脚本启动一个默认绑定到localhost的服务器。您可以使用-a命令行参数添加其他地址,或者使用–all绑定到所有可用地址。

python /path/to/qtbase/util/wasm/qtwasmserver/qtwasmserver.py --all

Building Applications using Qt Creator

使用Qt Creator构建应用程序


Setting Up Qt Creator for WebAssembly

.

为WebAssembly设置Qt Creator

Deploying Applications on the web

在web上部署应用程序

Building an application generates several files (substitute “app” with the application name in the following table).

构建应用程序会生成多个文件(用下表中的应用程序名称替换“app”)。

Generated file

产生的文件

Brief Description

简描

app.html

HTML container

HTML容器

qtloader.js

JavaScript API for loading Qt apps

用于加载Qt应用程序的JavaScript API

app.js

JS API for loading Qt apps

用于加载Qt应用程序的JS API

app.wasm

app binary

应用程序二进制文件

You can deploy

app.html

as-is, or discard it in favor favor of a custom html file. Smaller adjustments, such as changing the splash screen image from the Qt logo to the app logo, is also possible. In both cases,

qtloader.js

provides a JavaScript API for loading the application.

您可以部署

app.html

,或者放弃它,转而使用自定义html文件。也可以进行较小的调整,例如将闪屏图像从Qt徽标更改为应用程序徽标。在这两种情况下,qtloader.js提供了用于加载应用程序的JavaScript API。

We recommend compressing the wasm file using e.g. gzip or brotli before deployment, as this can provide a significant reduction in file size.

我们建议在部署之前使用例如gzip或brotli压缩wasm文件,因为这样可以显著减小文件大小。

Enabling certain features, such as multi-threading and SIMD, produces .wasm binaries that are incompatible with browsers that do not support the enabled feature. It is possible to work around this limitation by building multiple .wasm files and then use JavaScript feature detection to select the correct one, but note that Qt does not provide any functionality for doing this.

启用某些功能(如多线程和SIMD)会生成.wasm二进制文件,这些文件与不支持启用功能的浏览器不兼容。通过构建多个.wasm文件,然后使用JavaScript特性检测来选择正确的文件,可以绕过这个限制,但请注意,Qt没有提供任何功能来实现这一点。

Supported Browsers

支持的浏览器

Desktop

桌面端

Qt for WebAssembly is developed and tested on the following browsers:

Qt for WebAssembly在以下浏览器上开发和测试:

  • Chrome
  • Firefox
  • Safari
  • Edge

Qt should run if the browser supports WebAssembly. Qt has a fixed WebGL requirement, even if the application itself does not use hardware accelerated graphics. Browsers that support WebAssembly often support WebGL, though some browsers blacklist older or unsupported GPUs. s/

qtloader.js

provides APIs to check if WebGL is available.

如果浏览器支持WebAssembly,则应可以运行Qt。Qt有固定的WebGL要求,即使应用程序本身不使用硬件加速图形。支持WebAssembly的浏览器通常支持WebGL,但有些浏览器会将较旧或不受支持的GPU列入黑名单。s/qtloader.js提供API来检查WebGL是否可用。

Qt does not make direct use of operating system features and it makes no difference if, for example, FireFox runs on Windows or macOS. Qt does use some operating system adaptations, for example for ctrl/cmd key handling on macOS.

Qt不会直接使用操作系统功能,如果FireFox在Windows或macOS上运行,则不会有任何区别。Qt确实使用了一些操作系统调整,例如在macOS上处理ctrl/cmd按键。

Mobile

移动端

Qt for WebAssembly applications runs on mobile browsers such as mobile Safari and Android Chrome.

Qt for WebAssembly应用程序运行在移动浏览器上,如移动Safari和Android Chrome。

Supported Qt Modules

支持的Qt模块

Qt for WebAssembly supports a subset of the Qt modules and features. Tested modules are listed below, other modules may or may not work.

Qt for WebAssembly支持Qt模块和功能的子集。下面列出了测试的模块,其他模块可能工作,也可能不工作。

In all cases, module support may not be complete and and there may be additional limitations, either due to the browser sandbox or due to incompleteness of the Qt platform port. See

Developing with Qt for WebAssembly

for further info.

​在所有情况下,模块支持可能不完整,并且可能存在其他限制,这可能是由于浏览器沙盒或Qt平台端口不完整造成的。有关更多信息,请参阅使用Qt开发WebAssembly。

Qt for WebAssembly Technology Preview modules and features. These features may require to reconfigure and build Qt. They may contain features that are still experimental in the browsers or Emscripten.

Qt for WebAssembly Technology预览模块和功能。这些功能可能需要重新配置和构建Qt。它们可能包含在浏览器或脚本中仍处于实验阶段的功能。

Developing with Qt for WebAssembly

使用Qt开发WebAssembly

OpenGL and WebGL

OpenGL和WebGL

Qt requires WebGL, also for applications which do not use OpenGL directly. All relevant browsers support WebGL, but note that some browsers blacklist certain older GPUs. The Qt loader will detect this and display an error message.

Qt需要WebGL,对于不直接使用OpenGL的应用程序也是如此。所有相关浏览器都支持WebGL,但请注意,有些浏览器将某些较旧的GPU列入黑名单。Qt加载程序将检测到这一点并显示错误消息。

Qt detects WebGL as OpenGL ES, with the following version mapping:

Qt使用以下版本映射将WebGL检测为OpenGL ES:

OpenGL WebGL
OpengL ES 2 WebGL 1
OpengL ES 3 WebGL 2

OpengL ES 2 is selected by default, OpenGL ES 3 can be enabled by configuring Qt with the -feature-opengles3 option.

默认选择OpengL ES 2,可以通过使用-feature-opengles3选项配置Qt来启用OpengL ES 3。

Qt for WebAssembly does not support mixing raster and OpenGL content. Supported use cases are pure raster apps using QWigets, and pure OpenGL apps using Qt Quick or

QOpenGLWindow

.

QOpenGLWidget

is not supported at this point (QTBUG-66944).

​Qt for WebAssembly不支持混合光栅和OpenGL内容。支持的用例是使用QWigets的纯光栅应用程序,以及使用Qt-Quick或QOpenGLWindow的纯OpenGL应用程序。此时不支持QOpenGLWidget(QTBUG-66944)。

Web and Desktop OpenGL differences are documented in:

WebGL and OpenGL Differences

There are additional differences between WebGL 1.0 and WebGL 2.0 which are documented in:

WebGL 2.0 Specification

​Web和桌面OpenGL的差异记录在:WebGL和OpenGL差异WebGL 1.0和WebGL 2.0之间还有其他差异,记录在:WebGL 2.0规范中

A WebGL-friendly subset of ES2 (and ES3) is used by default. If you need to use glDrawArrays and glDrawElements without bound buffers, you can enable full ES2 support by adding target_link_options(<your target> PRIVATE “SHELL:-s FULL_ES2=1”) and/or full ES3 emulation by adding target_link_options(<your target> PRIVATE “SHELL:-s FULL_ES3=1”) to your projects CMakeFiles.txt

默认情况下使用ES2(和ES3)的WebGL友好子集。如果需要在不带绑定缓冲区的情况下使用glDrawArrays和glDrawElements,可以通过向项目CMakeFiles.txt中添加target_link_options(<your target>PRIVATE“SHELL:-s full_ES2=1”)或添加target_ link_option(<yourtarget>PRIVATE“SHELL:-s full_ES3=1”

Multithreading

多线程

Qt supports multithreading on WebAssembly, however this feature is experimental and is not enabled by default. Thread support can be enabled by building Qt from source and using the “-feature-thread” configure flag.

Qt支持WebAssembly上的多线程,但此功能是实验性的,默认情况下不启用。通过从源代码构建Qt并使用“-feature-Thread”配置标志,可以启用线程支持。

The Qt for WebAssembly binary packages do not support multithreading.

WebAssembly二进制包的Qt不支持多线程。

Emscripten implements support for pthreads using web workers, and this abstraction is not completely leak free. See

Pthreads Support

for further info.

​Emscripten使用web workers实现对pthreads的支持,而这种抽象并不是完全无泄漏的。有关详细信息,请参阅Pthreads支持。

Multithreading requires browser support for SharedArrayBuffer, see

caniuse sharedarraybuffer

for current supported status. If supported, SharedArrayBuffer will be enabled provided the web server sets the COOP and and COEP headers:

​多线程处理要求浏览器支持SharedArrayBuffer,有关当前支持的状态,请参阅caniuse SharedArrayBuffer。如果支持,将启用SharedArrayBuffer,前提是web服务器设置COOP和COEP头:

  • Cross-Origin-Opener-Policy: same-origin
  • Cross-Origin-Embedder-Policy: require-corp

SIMD

单指令多数据

The LLVM compiler supports generating

WebAssembly SIMD

. Pass the -msimd128 flag at compile time to enable. This enables LLVM auto-vectorization, which makes it possible to benefit from SIMD without making source code modifications.

​LLVM编译器支持生成WebAssembly SIMD。在编译时传递-msimd128标志以启用。这使LLVM能够自动矢量化,从而可以在不修改源代码的情况下从SIMD中获益。

You can target WebAssembly SIMD directly using either GCC/Clang SIMD Vector Extensions or WASM SIMD128 intrinsics. For more information, see the Emscripten

SIMD documentation

.

​您可以使用GCC/Clang SIMD矢量扩展或WASM SIMD128内部函数直接瞄准WebAssembly SIMD。有关更多信息,请参阅Emscripten SIMD文档。

In addition, Emscripten supports emulating/translating x86 SSE instructions to Wasm SIMD instructions. This emulation is no longer supported in Qt 6.5, as the use of SSE SIMD instructions that have no native Wasm SIMD equivalent may cause reduced performance.

此外,Emscripten支持将x86 SSE指令模拟/转换为Wasm SIMD指令。Qt 6.5不再支持此仿真,因为使用没有本机Wasm SIMD等效项的SSE SIMD指令可能会导致性能降低。

Note that SIMD-enabled binaries are incompatible with browsers that do not support WebAssembly SIMD, also if the SIMD code paths are not called at run-time. SIMD support may need to be enabled in the browsers advanced configurations, such as ‘about:config’ or ‘chrome:flags’

请注意,启用SIMD的二进制文件与不支持WebAssembly SIMD的浏览器不兼容,如果在运行时不调用SIMD代码路径也是如此。可能需要在浏览器的高级配置中启用SIMD支持,例如“about:config”或“chrome:flags”

Networking

网络设置

Qt provides limited support for networking. In general, network protocols which are already in use on the web can be use also from Qt, while others are not directly available due to the web sandbox.

Qt对网络的支持有限。通常,已经在web上使用的网络协议也可以从Qt使用,而其他协议由于web沙盒而无法直接使用。

The following protocols are supported:

支持以下协议:


  • QNetworkAccessManager

    http requests to the web page origin server, or to a server which supports CORS. This includes XMLHttpRequest from QML.
  • QNetworkAccessManager向网页源服务器或支持CORS的服务器发出http请求。这包括来自QML的XMLHttpRequest。

  • QWebSocket

    connections to any host. Note that web pages served over the secure https protocol allows websockets connections over secure wss protocol only.
  • QWebSocket与任何主机的连接。请注意,通过安全https协议提供的网页只允许通过安全wss协议进行websockets连接。
  • Emulated POSIX TCP Sockets over WebSockets, using functionality provided by

    Emscripten

    . Note that this requires running a

    forwarding server

    which handles socket translation.
  • ​使用Emscripten提供的功能,通过WebSockets仿真POSIX TCP套接字。请注意,这需要运行处理套接字转换的转发服务器。

All other network protocols are not supported.

不支持所有其他网络协议。

Local File Access

本地文件存取

File system access is sandboxed on the web, and this has implications for how the application works with files. The Web platform provides APIs for accessing the local file system in a way which is under user control, as well as APIs for accessing persistent storage. Emscripten and Qt wraps these features and provides APIs which are easier to use from C++ and Qt-based applications.

文件系统访问在web上是沙盒式的,这对应用程序如何处理文件有影响。Web平台提供了用于以用户控制的方式访问本地文件系统的API,以及用于访问持久存储的API。Emscripten和Qt包装了这些功能,并提供了更易于从基于C++和Qt的应用程序中使用的API。

The web platform provides features for accessing local files and persistent storage:

web平台提供了访问本地文件和永久存储的功能:

  • <input type=”file”> for showing a native open-file dialog where the user can pick a file.
  • <input type=“file”>用于显示用户可以在其中拾取文件的本机打开文件对话框。
  • IndexedDB provides persistent local storage (not accessible outside the browser)
  • IndexedDB提供持久的本地存储(在浏览器外无法访问)

Emscripten provides several file systems with a POSIX like API. These include:

Emscripten提供了几个具有类似POSIX的API的文件系统。其中包括:

  • the MEMFS ephemeral file system which stores files in-memory
  • 将文件存储在内存中的MEMFS临时文件系统
  • the IDBFS persistent file system which stores files using IndexedDB
  • 使用IndexedDB存储文件的IDBFS持久文件系统

Emscripten mounts a temporary MEMFS filesystem to “/” at app startup. This means that

QFile

can be used, and will read and write files to memory by default. Qt provides other API as well:

​Emscripten在应用程序启动时将临时MEMFS文件系统挂载到“/”。这意味着可以使用QFile,并在默认情况下将文件读写到内存中。Qt还提供其他API:


  • QSettings

    has an IndexedDB-based backend; Note that

    QSettings

    is asynchronous on WebAssembly.
  • QSettings有一个基于IndexedDB的后端;请注意,QSettings在WebAssembly上是异步的。

  • QFileDialog::getOpenFileContent()

    opens a native file dialog where the user can pick a file
  • QFileDialog::getOpenFileContent()打开一个本机文件对话框,用户可以在其中选择文件

  • QFileDialog::saveFileContent()

    saves a file to the local file system via file download}
  • QFileDialog::saveFileContent()通过文件下载将文件保存到本地文件系统

Clipboard Access

剪贴板访问

Qt supports copying and pasting text to the system clipboard, with some differences due to the web sandbox. In general clipboard access require user permission, which can be obtained by handling an input event (e.g. CTRL+c), or by using the

Clipboard API

.

​Qt支持将文本复制和粘贴到系统剪贴板,但由于web沙盒的原因,存在一些差异。通常,剪贴板访问需要用户权限,可以通过处理输入事件(如CTRL+c)或使用剪贴板API获得用户权限。

Browsers that support the Clipboard API are preferred. Note that a requirement for this API is that the web page is served over a secure connection (e.g. https), and that some browsers my require changing configuration flags.

首选支持剪贴板API的浏览器。请注意,此API的一个要求是通过安全连接(例如https)提供网页,并且一些浏览器需要更改配置标志。

At the time of writing the following browsers support the Clipboard API, see

caniuse

for the current support level.

​在编写以下浏览器支持剪贴板API时,请参阅caniuse以了解当前支持级别。

  • Chrome supports the Clipboard API
  • Chrome支持剪贴板API
  • Firefox supports the Clipboard API behind a flag: dom.events.asyncClipboard.dataTransfer
  • Firefox支持标志后面的剪贴板API:dom.events.asyncClipboard.dataTransfer

Fonts

字体

The Qt WASM module contains 3 embedded fonts: “Bitstream Vera Sans” (fallback font), “DejaVu Sans”, “DejaVu Sans Mono”.

Qt WASM模块包含3种嵌入式字体:“Bitstream Vera Sans”(回退字体)、“DejaVu Sans”、“DejaVu Sans-Mono”。

These fonts provide a limited character set. Qt provides several options for adding additional fonts:

这些字体提供有限的字符集。Qt提供了几种添加其他字体的选项:

One is using

FontLoader

in QML, which can either fetch a font by URL or using

Qt Resource System

(the same way the usual desktop apps work).

​一种是在QML中使用FontLoader,它可以通过URL获取字体,也可以使用Qt资源系统(与普通桌面应用程序的工作方式相同)。

The other way to use font is to add it via

QFontDatabase::addApplicationFontFromData

.

​另一种使用字体的方法是通过QFontDatabase::addApplicationFontFromData添加字体。

Application Startup and the Event Loop

应用程序启动和事件循环

Qt for WebAssembly supports the standard Qt startup approach, where the application creates a

QApplication

object and calls the exec function:

​Qt for WebAssembly支持标准的Qt启动方法,其中应用程序创建QApplication对象并调用exec函数:

int main(int argc, char **argc)
{
    QApplication app(argc, argv);

    QWindow appWindow;

    return app.exec();
}

The exec() call above normally blocks and processes events until application shutdown. Unfortunately this is not possible on the web platform where blocking the main thread is not allowed. Instead, control must be returned to the browser’s event loop after processing each event.

上面的exec()调用通常会阻塞和处理事件,直到应用程序关闭。不幸的是,在不允许阻塞主线程的web平台上,这是不可能的。相反,必须在处理每个事件后将控件返回到浏览器的事件循环。

Qt works around this by making exec() return main thread control to the browser, while preserving the stack. From the point of view of application code, the exec() function is entered and event processing happens as usual. However, the exec() call never returns, also not on application exit.

Qt通过使exec()向浏览器返回主线程控制,同时保留堆栈来解决这个问题。从应用程序代码的角度来看,进入exec()函数,事件处理照常进行。但是,exec()调用永远不会返回,在应用程序退出时也不会返回。

This behavior is usually acceptable since the browser will free up application memory at app shutdown time. It does mean that shutdown code does not run, since the application object is leaked and its destructor does not run.

这种行为通常是可以接受的,因为浏览器会在应用程序关闭时释放应用程序内存。这确实意味着关闭代码不会运行,因为应用程序对象已泄漏,且其析构函数未运行。

You can avoid this by rewriting main() to be asynchronous, which is possible since Emscripten does not exit the runtime when main() returns. Application code then omits making the exec() call, and can shut down Qt cleanly by deleting the top-level window and application objects.

您可以通过将main()重写为异步来避免这种情况,这是可能的,因为当main()返回时,Emscripten不会退出运行时。然后,应用程序代码将省略exec()调用,并可以通过删除顶级窗口和应用程序对象来干净地关闭Qt。

QApplication *g_app = nullptr;
AppWindow *g_appWindow = nullptr;

int main(int argc, char **argc)
{
    g_app = new QApplication(argc, argv);
    g_appWindow = new AppWindow();
    return 0;
}

Asyncify

异步

The default build of Qt for WebAssembly does not support reentering the event loop, for example by calling

QEventLoop::exec

() or

QDialog::exec

(), due to restrictions of the web platform.

​由于web平台的限制,Qt for WebAssembly的默认构建不支持重新进入事件循环,例如通过调用QEventLoop::exec()或QDialog::exec()。

Emscripten’s

asyncify

feature lifts these restrictions by allowing synchronous calls (like

QEventLoop::exec

() and

QDialog::exec

()) to yield to the event loop. Nested calls are not supported, and for this reason asyncify is not used for the top-level

QApplication::exec

() call.

​Emscripten的异步特性通过允许同步调用(如QEventLoop::exec()和QDialog::exex())屈服于事件循环来解除这些限制。不支持嵌套调用,因此,顶级QApplication::exec()调用不使用异步。

As of Qt 6.4, Asyncify support is enabled in the binary package, but needs to be enabled for applications by adding -sASYNCIFY -Os to linker options:

从Qt 6.4开始,二进制包中启用了异步支持,但需要通过向链接器选项添加-sASYNCIFY-Os来为应用程序启用异步支持:

CMake:

set target_link_options(<target> PUBLIC -sASYNCIFY -Os)

qmake:

QMAKE_LFLAGS += -sASYNCIFY -Os

Enabling asyncify adds overhead in the form of increased binary sizes and increased CPU usage. Build with optimizations enabled to minimize the overhead.

启用异步以增加二进制大小和CPU使用量的形式增加了开销。启用优化以最小化开销的构建。

Debugging and Profiling

调试和分析

Wasm debugging is done on browser JavaScript console, debugging applications on Wasm directly within Qt Creator is not possible.

Wasm调试是在浏览器JavaScript控制台上完成的,无法在Qt Creator中直接在Wasm上调试应用程序。

You can add more verbosity to help debug using Emscripten linker arguments:

您可以添加更多详细信息,以帮助使用Emscripten链接器参数进行调试:

  • -s LIBRARY_DEBUG=1 (print out library calls)
  • -s LIBRARY_DEBUG=1(打印出库调用)
  • -s SYSCALL_DEBUG=1 (print out sys calls)
  • -s SYSCALL_DEBUG=1(打印出系统调用)
  • -s FS_LOG=1 (print out filesystem operations)
  • -s FS_LOG=1(打印输出文件系统操作)
  • -s SOCKET_DEBUG (print out socket, network data transfer)
  • -s SOCKET_DEBUG(打印输出socket,网络数据传输)

Using cmake:

使用cmake:

target_link_options(<your target> PRIVATE "SHELL:-s LIBRARY_DEBUG=1")

Using qmake:

使用qmake:

QMAKE_LFLAGS_DEBUG += -s LIBRARY_DEBUG=1

Asyncify

异步

Asyncify is an Emscripten feature which enables synchronous C++ code to interact with asynchronous JavaScript.

Asyncify是一个Emscripten特性,它使同步C++代码能够与异步JavaScript交互。

Qt uses it to allow calling blocking APIs like one level of nested

QEventLoop::exec

() and returning normally.

​Qt使用它来允许像一级嵌套QEventLoop::exec()那样调用阻塞API并正常返回。

Asyncify’s unwinding and rewinding the stack add overhead to executable size as well as performance. To enable asyncify, configure Qt using:

Asyncify对堆栈的展开和回放增加了可执行文件大小和性能的开销。要启用异步,请使用以下命令配置Qt:

-device-option QT_EMSCRIPTEN_ASYNCIFY=1

Known Issues

已知问题

  • Nested event loops are not supported. Applications should not call API like

    QDialog::exec

    () and

    QEventLoop::exec

    (). Experimental feature Asyncify could be used.
  • ​不支持嵌套事件循环。应用程序不应调用QDialog::exec()和QEventLoop::exec()之类的API。可以使用实验特性异步。
  • Printing is not supported
  • 不支持打印

  • QDnsLookup

    lookups,

    QTcpSocket

    ,

    QSsl

    do not work and are not supported due to the web sandbox
  • QDnsLookup查找、QTcpSocket、QSsl不工作,并且由于web沙盒的原因不受支持
  • Accessibility is not supported: Qt draws application content to a canvas element and does not use (other) native DOM elements.
  • 不支持辅助功能:Qt将应用程序内容绘制到画布元素,并且不使用(其他)本机DOM元素。
  • Fonts: Wasm sandbox does not allow access to system fonts. Font files must be distributed with the application, for example in Qt resources or downloading. Qt for WebAssembly itself embeds one such font.
  • 字体:Wasm沙盒不允许访问系统字体。字体文件必须与应用程序一起分发,例如在Qt资源或下载中分发。Qt for WebAssembly本身嵌入了一种这样的字体。
  • There may be artifacts of uninitialized graphics memory on some Qt Quick Controls 2 components, such as checkboxes. This can sometimes be seen on HighDPi displays.
  • 某些Qt Quick Controls 2组件上可能存在未初始化图形内存的瑕疵,例如复选框。这有时可以在HighDPi显示器上看到。
  • Native styles for Windows and macOS are not supported as Wasm as a platform is not providing that capability
  • Windows和macOS的本机样式不受支持,因为Wasm平台不提供该功能
  • Link time error such as “wasm-ld: error: initial memory too small”, requires adjustment of the initial memory size. Use QT_WASM_INITIAL_MEMORY to set the initial size in kb, which must be a multiple of 64KB (65536). Default is 50 MB. In CMakeFiles.txt: set(QT_WASM_INITIAL_MEMORY, “50MB”);
  • 链接时间错误,如“wasm-ld:error:initial memory too small”,需要调整初始内存大小。使用QT_WASM_INITIAL_MEMORY以kb为单位设置初始大小,该值必须是64KB(65536)的倍数。默认值为50 MB。在CMakeFiles.txt中:设置(QT_WASM_INITIAL_MEMORY,“50MB”);
  • add_executable in CMakeLists.txt does not produce <target>.html or copy qtloader.js. Use qt_add_executable instead.
  • CMakeLists.txt中的add_executable不会生成<target>.html或复制qtloader.js。改用qt_add_executable。

Other Topics

其他议题

Qt Configure Options Reference

Qt配置选项参考

The following configure options are relevant when building Qt for WebAssembly from source.

从源代码构建WebAssembly的Qt时,以下配置选项是相关的。

Configure Argument

配置参数

Brief Description

简述

-sse2

Enables SIMD support.

启用SIMD支持。

-feature-thread

Multi-threaded wasm

多线程wasm

-device-option QT_WASM_SOURCE_MAP=1

Debugging option for creating source maps

用于创建源映射的调试选项

-device-option QT_EMSCRIPTEN_ASYNCIFY=1

Debugging option for creating source maps

用于创建源映射的调试选项

-feature-opengles3

Use opengles3 in addition to the default opengles2

除了默认的opengles2之外,还使用opengles3

-device-option QT_EMSCRIPTEN_ASYNCIFY=1

Use asyncify

使用异步

Typical Download Sizes

典型下载大小

Expected footprint (download size): Wasm modules as produced by the compiler can be large, but compress well:

预期占用空间(下载大小):编译器生成的Wasm模块可能很大,但压缩效果很好:

Example

示例

gzip brotli
helloglwindow (

QtCore

+

QtGui

)
2.8M 2.1M
wiggly widget (

QtCore

+

QtGui

+ QtWidgets)
4.3M 3.2M
SensorTag (

QtCore

+

QtGui

+ QtWidgets +

QtQuick

+

QtCharts

)
8.6M 6.3M

Compression is typically handled on the web server side, using standard compression features: the server compresses automatically or picks up pre-compressed versions of the files. There’s generally no need to have special handling of wasm files.

压缩通常在web服务器端处理,使用标准的压缩特性:服务器自动压缩或提取文件的预压缩版本。通常不需要对wasm文件进行特殊处理。

Examples

实例

External resources

外部资源

License

许可

Qt for WebAssembly is available under commercial licenses from

The Qt Company

. In addition, it is available under the

GNU General Public License, version 3

. See

Qt Licensing

for further details.

​Qt for WebAssembly在Qt公司的商业许可下提供。此外,它在GNU通用公共许可证版本3下提供。有关更多详细信息,请参阅Qt许可。

© 2022 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the

GNU Free Documentation License version 1.3

as published by the Free Software Foundation. Qt and respective logos are

trademarks

of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.