这是用户在 2024-9-21 17:39 为 https://doc.qt.io/qt-6/wasm.html#installing-qt 保存的双语快照页面,由 沉浸式翻译 提供双语支持。了解如何保存?

Qt for WebAssembly

Qt for Webassembly lets you to run Qt applications on the web.
Qt for Webassembly 可让你在网络上运行 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)是一种二进制指令格式,用于在虚拟机(如网络浏览器)中执行。

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,您可以将应用程序作为在浏览器沙盒中运行的网络应用程序发布。这种方法适用于不需要完全访问主机设备功能的网络分布式应用程序。

Note: Qt for WebAssembly is a supported platform, but some modules are not yet supported or are in Tech Preview. See Supported Qt Modules.
注意:Qt for WebAssembly 是一个受支持的平台,但某些模块尚未受支持或处于技术预览阶段。请参阅支持的 Qt 模块。

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 WebAssembly supports fewer modules and less features than other Qt builds.
为 WebAssembly 构建 Qt 应用程序与为其他平台构建 Qt 相似。你需要安装 SDK(Emscripten),安装 Qt(或从源代码构建 Qt),最后构建应用程序。但也有一些不同之处,例如,与其他 Qt 版本相比,WebAssembly 版 Qt 支持的模块和功能较少。

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 的工具链。它能让你在网络上以接近原生的速度运行 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 Emscripten version, which remains unchanged in patch releases. Qt's binary packages are built using the target Emscripten version. Applications should use the same version since Emscripten does not guarantee ABI compatibility between versions.
Qt 的每个次版本都以特定的 Emscripten 版本为目标,该版本在补丁发布时保持不变。Qt 的二进制包使用目标 Emscripten 版本构建。应用程序应使用相同的版本,因为 Emscripten 并不保证不同版本之间的 ABI 兼容性。

The Emscripten versions are:
Emscripten 版本如下

  • Qt 6.2: 2.0.14
  • Qt 6.3: 3.0.0
  • Qt 6.4: 3.1.14
  • Qt 6.5: 3.1.25
  • Qt 6.6: 3.1.37
  • Qt 6.7: 3.1.50 Qt 6.73.1.50

Use emsdk to install specific Emscripten versions. For example, to install it for Qt 6.7 enter:
使用 emsdk 安装特定的 Emscripten 版本。例如,要为 Qt 6.7 安装,请输入

  • ./emsdk install 3.1.50
  • ./emsdk activate 3.1.50 ./emsdk 激活 3.1.50

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

You can build Qt from source if you require more flexibility when selecting the Emscripten version. In this case the versions above are minimum versions. Later versions are expected to work but may introduce behavior changes which require making changes to Qt.
如果在选择 Emscripten 版本时需要更大的灵活性,可以从源代码构建 Qt。在这种情况下,上述版本是最低版本。以后的版本预计也能正常运行,但可能会引入一些行为变化,需要对 Qt 进行修改。

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 come in single-threaded and multi-threaded versions. Non-standard features such as Wasm SIMD and Wasm exceptions are not supported by the binary builds.
二进制版本旨在运行在尽可能多的浏览器上,有单线程和多线程版本。二进制版本不支持 Wasm SIMDWasm exceptions 等非标准功能。

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 , 配置选项启用线程支持。不支持共享库编译。

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 configure 参数中指定该路径。

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 SDK 附带的 Emscripten.cmake 工具链文件。这可以通过设置环境变量 CMAKE_TOOLCHAIN_FILE 或向 configure 传递 CMAKE_TOOLCHAIN_FILE=/path/to/Emscripten.cmake 来实现。

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

Note: configure always uses the Ninja generator and build tool if a ninja executable is available. Ninja is cross-platform, feature-rich, performant, and recommended on all platforms. The use of other generators might work but is not officially supported.
注意:如果有 ninja 可执行文件,configure 总是使用 Ninja 生成器和构建工具。Ninja 跨平台、功能丰富、性能卓越,建议在所有平台上使用。使用其他生成器可能可行,但未获官方支持。

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 和 make 或 CMake 与 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.
构建应用程序会生成多个输出文件,包括一个包含应用程序和 Qt 代码(静态链接)的 .wasm 文件、一个可在浏览器中打开以运行应用程序的 .html 文件。

Note: Emscripten produces relatively large .wasm files at the "-g" debug level. Consider linking with "-g2" for debug builds.
注意:在"-g "调试级别下,Emscripten 生成的 .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.
运行应用程序需要网络服务器。构建输出文件都是静态内容,因此任何网络服务器都可以使用。某些用例可能需要特殊的服务器配置,例如提供 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 可以启动网络服务器、启动浏览器,还可以捕获并转发 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:
另一种方法是启动开发网络服务器,然后单独启动网络浏览器。最简单的选择之一就是 Python 中的 http.server:

python -m http.server

Note that this is only a simple webserver and does not support SharedArrayBuffer required for threading, as the required COOP and COED headers mentioned below are not sent.
请注意,这只是一个简单的网络服务器,不支持线程所需的 SharedArrayBuffer,因为下面提到的 COOP 和 COED 头信息不会被发送。

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 提供了一个开发者网络服务器,它使用 mkcert 生成 https 证书。这样就可以测试需要安全环境的网络功能。请注意,通过 http://localhost 传输也被认为是安全的,不需要证书。

The web server also sets the COOP and COEP headers to values which enables support for SharedArrayBuffer and multi-threading.
网络服务器还会将 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
在网络上部署应用程序

Building an application generates several files (substitute "app" with the application name in the following table).
构建应用程序会生成多个文件(在下表中用应用程序名称代替 "app")。

Generated file 生成文件Brief Description 简要说明
app.htmlHTML container HTML 容器
qtloader.jsJavaScript API for loading Qt applications
用于加载 Qt 应用程序的 JavaScript API
app.jsJavaScript runtime generated by Emscripten
由 Emscripten 生成的 JavaScript 运行时
app.wasmapp binary 应用程序二进制

You can deploy app.html as-is, or discard it in 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。

Compress the Wasm file using either gzip or brotli before deploying, as they offer better compression ratio than the other tools. See Minimizing the size of binaries for more information.
部署前使用 gzipbrotli 压缩 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 并不提供这样做的任何功能。

Using qtloader 使用 qtloader

Qt provides a JavaScript API for downloading, compiling, and instantiating Qt for WebAssembly applications. This loading API wraps loading functionality provided by Emscripten, and provides additional features useful for Qt-based applications. It is implemented in the qtloader.js file. A copy of this file is written to the build directoty at build time.
Qt 为下载、编译和实例化 Qt for WebAssembly 应用程序提供了 JavaScript API。该加载 API 封装了 Emscripten 提供的加载功能,并为基于 Qt 的应用程序提供了更多有用的功能。它在 qtloader.js 文件中实现。该文件的副本会在构建时写入构建目录。

Typical usage looks like the following:
典型用法如下

const app_container_element = ...;
const instance = await qtLoad({
    qt: {
        containerElements: [ app_container_element ],
        onLoaded: () => { /* handle application load completed */  },
        onExit: () => {  /* handle application exit */ },
    }
});

The code calls the qtLoad() loader function with a configuration object. This configuration object can contain any emscripten configuration options, as well as a special "qt" configuration object. The qt configuration object supports the following properties:
代码会调用带有配置对象的 qtLoad() 加载器函数。该配置对象可包含任何 emscripten 配置选项,以及一个特殊的 "qt "配置对象。qt 配置对象支持以下属性:

Property 物业Brief Description 简要说明
containerElements 容器元素Array of HTML container elements. The application sees these as QScreens.
HTML 容器元素数组。应用程序将其视为 QScreens。
onLoaded 加载时Callback for when the application has completed loading.
应用程序加载完成后的回调。
onExitCallback for when the applicataion exits.
应用程序退出时的回调。

The containerElements array is the main interface between Qt and the web page, where the html elements in this array (typically <div> elements) specify the location of the application content on the web page.
containerElements 数组是 Qt 与网页之间的主要接口,数组中的 html 元素(通常是 <div> 元素)指定了应用程序内容在网页上的位置。</div>

The application sees each container element as a QScreen instance, and can place application windows on the screen instances as usual. Windows with the Qt::WindowFullScreen state set use the entire screen area, while non-"fullscreen" windows get window decorations.
应用程序将每个容器元素视为一个 QScreen 实例,并可像往常一样在屏幕实例上放置应用程序窗口。设置了 Qt::WindowFullScreen 状态的窗口会使用整个屏幕区域,而非 "全屏 "窗口则会获得窗口装饰。

The qtLoad() function returns a promise, which yelds an Emscripten instance when awaited. The instance provides access to Embind exported functions. Qt exports several such functions, and these functions make up the instance API.
qtLoad() 函数会返回一个承诺,在等待时会生成一个 Emscripten 实例。该实例提供对 Embind 导出函数的访问。Qt 导出了多个此类函数,这些函数构成了实例 API。

Using the Qt instance API
使用 Qt 实例 API

Qt provides several instance functions. Currently, these support adding and removing container elements at runtime.
Qt 提供了多个实例函数。目前,这些函数支持在运行时添加和删除容器元素。

Property 物业Brief Description 简要说明
qtAddContainerElementAdd a container element. Adding an element will add a new QScreen.
添加容器元素添加一个元素将添加一个新的 QScreen。
qtRemoveContainerElementRemove a container element, and its corresponding screen.
移除容器元素及其对应的屏幕。
qtSetContainerElementsSets all container elements
设置所有容器元素
qtResizeContainerElementMake Qt pick up changes to container element size.
使 Qt 能捕捉容器元素大小的变化。

Porting to the Qt 6.6 qtloader
移植到 Qt 6.6 qtloader

Qt 6.6 includes a new qtloader with a simplified implementation and a smaller scope. This includes API changes which may require porting application JavaScript code. Qt provides a compatibility API to ease the transition. Depending use case there are several ways forward:
Qt 6.6 包含一个新的 qtloader,其实现经过简化,范围更小。这包括可能需要移植应用程序 JavaScript 代码的 API 变化。Qt 提供了一个兼容性 API 来简化过渡。根据不同的使用情况,有几种前进方式:

  • If you are using the generated app.html file directly then this file will be updated as well at build time. No action is needed.
    如果直接使用生成的 app.html 文件,则该文件也将在构建时更新。无需任何操作。
  • If you are using the basic qtloader feature set then you may use the compatibility API included in Qt 6.6 as a temporary maesure. This API will be removed in a future release; you should plan on updating to use the new qtloader. Porting step 1 below is needed.
    如果您使用的是基本的 qtloader 功能集,那么您可以使用 Qt 6.6 中包含的兼容性 API 作为临时措施。该 API 将在未来的版本中移除;您应计划更新以使用新的 qtloader。需要移植下面的步骤 1。
  • If you are using advanced features (such as adding container elements at runtime), then porting to the new loader or instance API required. Porting steps 1 and 2 below are needed.
    如果要使用高级功能(如在运行时添加容器元素),则需要移植到新的加载器或实例 API。移植步骤 1 和 2 如下。

Porting steps 移植步骤

  1. Include the app.js (JavaScript runtime generated by Emscripten) from the loading html file.
    在加载的 html 文件中加入 app.js (由 Emscripten 生成的 JavaScript 运行时)。
    <script src="app.js"></script>

    Before Qt 6.6, qtloader would load and evaluate this JavaScript file. This is no longer done, and the file must be included using a <script> tag.
    在 Qt 6.6 之前,qtloader 会加载并评估 JavaScript 文件。现在不再这样做了,必须使用

  2. Port to using the new JavaScript and instance API.
    移植到使用新的 JavaScript 和实例 API。

See documentation sections above.
参见上文的文件章节。

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 提供了检查 WebGL 是否可用的 API。

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 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 平台端口不完整的额外限制。更多信息,请参阅 WebAssembly 的 Qt 开发。

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 技术预览版的模块和功能。这些功能可能需要重新配置和构建 Qt。它们可能包含在浏览器或 Emscripten 中仍处于试验阶段的功能。

Developing with Qt for WebAssembly
使用 Qt 开发 WebAssembly

Building with CMake 使用 CMake 构建

If there is a need for Emscripten-specific configuration in CMake, the following code can be utilized:
如果需要在 CMake 中对 Emscripten 进行特定配置,可以使用以下代码:

if(EMSCRIPTEN)
    # WebAssembly specific code
else()
    # other platforms
endif()

This code allows for the accommodation of Emscripten-specific configurations while ensuring compatibility with other platforms.
该代码允许使用 Emscripten 特有的配置,同时确保与其他平台兼容。

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,版本映射如下:

OpenGLWebGL
OpengL ES 2WebGL 1
OpengL ES 3WebGL 2

OpenGL ES 2 and OpenGL ES 3 are enabled by default, and can be selected through the QSurfaceFormat::setMajorVersion() function.
OpenGL ES 2 和 OpenGL ES 3 默认已启用,可通过 QSurfaceFormat::setMajorVersion() 函数进行选择。

Web and Desktop OpenGL differences are documented in WebGL and OpenGL Differences. There are additional differences between WebGL 1.0 and WebGL 2.0, documented in the WebGL 2.0 Specification.
WebGL 和 OpenGL 差异中记录了 Web 和桌面 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
默认情况下使用的是 ES2(和 ES3)的 WebGL 友好子集。如果需要使用不带绑定缓冲区的 glDrawArraysglDrawElements ,可以通过添加

target_link_options(<your target> PRIVATE -s FULL_ES2=1)

and/or full ES3 emulation by adding
和/或通过添加

target_link_options(<your target> PRIVATE -s FULL_ES3=1)

to your project's CMakeLists.txt.
到项目的 CMakeLists.txt .

Multithreading 多线程

Qt for WebAssembly supports multithreading using Emscripten's Pthreads support, where each thread is backed by a web worker. Enable multithreading by installing the "WebAssembly (multi-threaded)" component from Qt Maintenance Tool, or by building Qt from source and passing the "-feature-thread" flag to configure.
Qt for WebAssembly 使用 Emscripten 的 Pthreads 支持多线程,其中每个线程都由一个 Web Worker 支持。从 Qt 维护工具中安装 "WebAssembly(多线程)"组件,或从源代码构建 Qt 并在配置时传递"-feature-thread "标志,即可启用多线程。

Existing threading code can generally be reused, but may need to be modified to work around specifics of the pthread implementation. Some Emscripten and Qt features are not supported, this includes the thread proxying feature and the Qt Quick threaded render loop.
现有的线程代码一般可以重复使用,但可能需要修改以适应 pthread 实现的特殊性。不支持 Emscripten 和 Qt 的某些功能,包括线程代理功能和 Qt Quick 线程渲染循环。

Be aware that it is especially important to not block the main thread on Qt for WebAssembly, since the main thread might be required to service requests from secondary threads. For example, all timers in Qt are scheduled on the main thread, and will not fire if the main thread is blocked. Another example is that creating a new web worker (for a thread) can only be done from the main thread.
请注意,不要阻塞 WebAssembly Qt 的主线程尤为重要,因为主线程可能需要处理次线程的请求。例如,Qt 中的所有定时器都是在主线程上调度的,如果主线程被阻塞,定时器就不会启动。另一个例子是,(为线程)创建一个新的 Web Worker 只能在主线程中完成。

Emscripten provides some mitigations for this. Short-term waits such as acquiring a mutex lock is supported by busy-waiting and processing events while waiting for the lock. Longer waits on the main thread should be avoided. In particular, the common practice of calling QThread::wait() or pthread_join() to wait for a secondary thread will not work, unless the application can guarantee that the thread (and web worker) has already been started, and will be able to complete without assistance from the main thread at the time that the wait() or join() call is made.
Emscripten 对此提供了一些缓解措施。短期等待(如获取互斥锁)可通过忙碌等待和在等待锁时处理事件来实现。应避免在主线程上进行较长时间的等待。特别是,调用 QThread::wait() 或 pthread_join() 来等待辅助线程的常见做法是行不通的,除非应用程序能保证该线程(和网络工作者)已经启动,并且在调用 wait() 或 join() 时无需主线程协助即可完成。

The multithreading feature requires browser support for the SharedArrayBuffer API. (Normally, Emscripten stores the heap in an ArrayBuffer object. For multithreading, the heap must be shared with web workers and a SharedArrayBuffer is needed) This API is generally available in all modern browsers, but may be disabled if certain security requirements are not met. WebAssembly binaries with thread support enabled will then fail to run, also if the binary does not actually start a thread.
多线程功能需要浏览器支持 SharedArrayBuffer API。(通常,Emscripten 将堆存储在 ArrayBuffer 对象中。对于多线程,堆必须与 Web Worker 共享,因此需要一个 SharedArrayBuffer)所有现代浏览器一般都支持该 API,但如果不满足某些安全要求,则可能会禁用。启用了线程支持的 WebAssembly 二进制程序将无法运行,如果二进制程序实际上没有启动线程也是如此。

Enabling SharedArrayBuffer requires a secure browsing context (where the page is served over https:// or http://localhost), and that the page is in cross-origin isolated mode. The latter can be done by setting the so called COOP and COEP headers on the web server:
启用 SharedArrayBuffer 需要一个安全的浏览环境(页面通过 https:// 或 http://localhost 提供),并且页面处于跨源隔离模式。后者可以通过在网络服务器上设置所谓的 COOP 和 COEP 标头来实现:

  • Cross-Origin-Opener-Policy: same-origin
    跨源生成策略:同源
  • Cross-Origin-Embedder-Policy: require-corp
    跨源代理政策: require-corp

SIMD

Emscripten supports WebAssembly SIMD, which provides 128-bit SIMD types and operations for WebAssembly.
Emscripten 支持 WebAssembly SIMD,为 WebAssembly 提供 128 位 SIMD 类型和操作。

Build Qt from source and configure with the -feature-wasm-simd128 flag to enable; this will pass the -msimd128 flag at compile and link time. Note that Qt does not contain wasm-simd optimized code paths at this point, however enabling wasm-simd will enable compiler auto-vectorization where the compiler can use the SIMD instructions.
从源代码编译 Qt 并配置 -feature-wasm-simd128 标志为启用;这将在编译和链接时传递 -msimd128 标志。请注意,此时 Qt 并不包含 wasm-simd 优化代码路径,但启用 wasm-simd 将启用编译器自动矢量化,编译器可以使用 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. Qt does not use this emulation, as the use of SSE SIMD instructions that have no native Wasm SIMD equivalent may cause reduced performance.
此外,Emscripten 还支持将 x86 SSE 指令模拟/转换为 Wasm SIMD 指令。Qt 不使用这种模拟,因为使用没有本地 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 代码路径也是如此。可能需要在浏览器的高级配置(如 "about:config "或 "chrome:flags")中启用 SIMD 支持。

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 提供有限的网络支持。一般来说,网络上已经使用的网络协议也可以通过 Qt 使用,而其他网络协议由于网络沙盒的原因不能直接使用。

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 协议进行网络套接字连接。
  • Emulated POSIX TCP Sockets over WebSockets, using functionality provided by Emscripten. Note that this requires running a forwarding server which handles socket translation.
    通过 WebSockets 仿真 POSIX TCP 套接字,使用 Emscripten 提供的功能。请注意,这需要运行一个处理套接字转换的转发服务器。

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.
文件系统访问在网络上是沙箱式的,这对应用程序如何处理文件有影响。网络平台提供了在用户控制下访问本地文件系统的应用程序接口,以及访问持久存储的应用程序接口。Emscripten 和 Qt 封装了这些功能,并提供了更易于从基于 C++ 和 Qt 的应用程序中使用的 API。

The web platform provides features for accessing local files and persistent storage:
网络平台提供访问本地文件和持久存储的功能:

  • <input type="file"> for showing a native open-file dialog where the user can pick a file.
    <input></input> 用于显示用户可以选择文件的本地打开文件对话框。
  • IndexedDB provides persistent local storage (not accessible outside the browser)
    索引数据库提供持久性本地存储(浏览器外部无法访问)

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 支持将文本复制和粘贴到系统剪贴板,但由于网络沙盒的原因会有一些差异。一般来说,剪贴板访问需要用户许可,可以通过处理输入事件(如 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)提供,而且某些浏览器可能需要更改配置标志。

  • Chrome version 66 and Safari version 13.1 support the Clipboard API
    Chrome 浏览器 66 版和 Safari 13.1 版支持剪贴板 API
  • Firefox version 90 supports the Clipboard API if you enable the following flags in 'about:config':
    如果在 "about:config "中启用以下标志,Firefox 90 版本将支持剪贴板 API:
    dom.events.asyncClipboard.read
    dom.events.asyncClipboard.clipboardItem

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 Resource System(与通常桌面应用程序的工作方式相同)获取字体。

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 对象并调用执行函数:

int main(int argc, char **argv)
{
    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() 调用通常会阻塞并处理事件,直到应用程序关闭。遗憾的是,这在网络平台上是不可能的,因为网络平台不允许阻塞主线程。相反,必须在处理完每个事件后将控制权返回给浏览器的事件循环。

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 **argv)
{
    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.
由于网络平台的限制,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 的 asyncify 功能允许同步调用(如 QEventLoop::exec() 和 QDialog::exec())让位于事件循环,从而解除了这些限制。不支持嵌套调用,因此 asyncify 不用于顶级 QApplication::exec() 调用。

Features that require asyncify are:
需要 asyncify 的功能有

  • QDialogs, QMessageBoxes with return values.
    带有返回值的 QDialogs、QMessageBoxes。
  • Drag and drop (specifically drag).
    拖放(特别是拖动)。
  • Nested/secondary event loops exec().
    嵌套/二级事件循环 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 开始,二进制软件包已启用 Asyncify 支持,但应用程序需要在链接器选项中添加 -sASYNCIFY -Os:

CMake: CMake:

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

qmake: 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.
启用 asyncify 会以增加二进制文件大小和 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(打印套接字、网络数据传输)

CMake: CMake:

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

qmake: qmake:

QMAKE_LFLAGS_DEBUG += -s LIBRARY_DEBUG=1

Optimizing 优化

Qt for WebAssembly uses the Emscripten toolchain to generate binaries, and there are many flags that may impact performance and the size of binaries. See Emscripten: Optimizing Code for more information.
Qt for WebAssembly 使用 Emscripten 工具链生成二进制文件,有许多标记可能会影响性能和二进制文件的大小。请参阅 Emscripten:优化代码》了解更多信息。

You can pass linker and compiler flags just as for normal C++ applications:
与普通 C++ 应用程序一样,您可以传递链接器和编译器标志:

target_compile_options(<your target> PRIVATE -oz -flto)
target_link_options(<your target> PRIVATE -flto)
QMAKE_CXXFLAGS += -oz -flto
QMAKE_LFLAGS += -flto

Minimizing the size of binaries
最小化二进制文件的大小

In order to provide a seamless user experience, it's important to reduce the time to download and load WebAssembly applications. Smaller application binary is one of the important aspects that enable faster download. Use the following alternatives to reduce the binary size:
为了提供无缝的用户体验,缩短下载和加载 WebAssembly 应用程序的时间非常重要。更小的应用程序二进制文件是加快下载速度的重要因素之一。使用以下替代方法可减小二进制文件的大小:

  • Make sure to distribute release builds. Debug builds contain debug symbols and are much bigger.
    确保发布发布版。调试版本包含调试符号,体积更大。
  • Enable compression on a server. The most common algorithms like gzip and Brotli work well on Wasm binaries and can drastically reduce their size.
    在服务器上启用压缩。最常见的算法如 gzip 和 Brotli 在 Wasm 二进制文件上运行良好,可大幅减少文件大小。
  • Try compiler and linker flags that may results in generating smaller binaries (i.e. '-os', '-oz'). Results will vary depending on the particular application.
    尝试使用可生成较小二进制文件的编译器和链接器标志(如"-os"、"-oz")。具体结果视具体应用而定。
  • Disable unsued features when compiling Qt for WebAssembly from source (see below).
    从源代码编译 Qt for WebAssembly 时禁用不需要的功能(见下文)。
Opting out of features
退出功能

A WebAssembly application by default links statically to the Qt libraries, enabling the compiler to eliminate dead code. However, due to Qt's dynamic nature it's not always possible for the compiler to perform such optimizations.
默认情况下,WebAssembly 应用程序会静态链接到 Qt 库,这样编译器就能消除死代码。然而,由于 Qt 的动态特性,编译器并不总是能进行这样的优化。

If you build Qt for WebAssembly from source, you can disable features to reduce the size of Qt binaries, and — as a result — the size of .wasm binaries. Qt disables some features by default for the WebAssembly platform, but you can also disable features that your application does not use. See disabled features for more information.
如果你从源代码构建 Qt for WebAssembly,你可以禁用一些功能来减小 Qt 二进制文件的大小,从而减小 .wasm 二进制文件的大小。对于 WebAssembly 平台,Qt 默认禁用某些功能,但你也可以禁用应用程序不使用的功能。更多信息,请参阅禁用的功能。

You can disable the following features to reduce binary size (usually by 10-15%):
您可以禁用以下功能来减少二进制文件的大小(通常减少 10-15%):

Configure Argument 配置参数Brief Description 简要说明
-no-feature-cssparser -无特征-CSS 解析器Parser for Cascading Style Sheets.
层叠样式表解析器
-no-feature-datetimeedit -无功能-日期时间编辑Editing dates and times (depends on datetimeparser).
编辑日期和时间(取决于 datetimeparser)。
-no-feature-datetimeparser
-无功能数据时间解析器
Parsing date-time texts. 解析日期时间文本
-no-feature-dockwidget -无功能小工具Docking widgets inside a QMainWindow or floating them as top-level windows on the desktop.
在 QMainWindow 中停靠窗口部件,或将它们作为顶层窗口浮动到桌面上。
-no-feature-gestures -无特征手势Framework for gestures. 手势框架。
-no-feature-mimetype -无特征-mimetypeMimetype handling. Mimetype 处理。
-no-feature-qml-network -无功能-qml-网络Network transparency. 网络透明度。
-no-feature-qml-list-model
-无功能-qml-列表-模型
ListModel QML type. ListModel QML 类型。
-no-feature-qml-table-model
-无特征-qml-表模型
TableModel QML type. TableModel QML 类型。
-no-feature-quick-canvas -无快速画布功能Canvas item. 帆布项目。
-no-feature-quick-path -无功能快速路径Path elements. 路径要素。
-no-feature-quick-pathview
-无快速路径视图功能
PathView item. PathView 项目。
-no-feature-quick-treeview
-无功能快速评论
TreeView item. 树形视图项目。
-no-feature-style-stylesheet
-无特色样式表
Widget style which is configurable via CSS.
可通过 CSS 配置的小工具样式。
-no-feature-tableview -无功能表观Default model/view implementation of a table view.
表格视图的默认模型/视图实现。
-no-feature-texthtmlparser
-无特性-texthtml 解析器
Parser for HTML. HTML 解析器
-no-feature-textmarkdownreader
-无文本标记阅读器功能
Markdown (CommonMark and GitHub) reader.
Markdown(CommonMark 和 GitHub)阅读器。
-no-feature-textodfwriter
-无功能文本写入器
ODF writer. ODF 编写者。

Wasm Exceptions Wasm 例外

Qt is built without exception support by default, where throwing an exception will abort the program. WebAssembly exceptions can be enabled by building from source and passing the -feature-wasm-exceptions flag to Qt configure. This will pass the -fwasm-exceptions flag to the compiler at compile and link time. Qt does not support enabling Emscripten's support for the earlier JavaScript-based exception implementation.
Qt 在构建时默认不支持异常,抛出异常会中止程序。要启用 WebAssembly 异常,可从源代码编译并向 Qt configure 传递 -feature-wasm-exceptions 标志。这将在编译和链接时将 -fwasm-exceptions 标志传递给编译器。Qt 不支持启用 Emscripten 对早期基于 JavaScript 的异常实现的支持。

Note that calling QApplication::exec() is not supported when exceptions are enabled, due to internal implementation details. Instead, write main() in the form where it returns early and does not call exec(), as described in Application Startup and the Event Loop.
请注意,由于内部实现细节的原因,启用异常时不支持调用 QApplication::exec()。相反,请按照应用程序启动和事件循环中的描述,以提前返回且不调用 exec() 的形式编写 main()。

Shared Libraries and Dynamic Linking Developer Preview
共享库和动态链接开发人员预览版

Qt for WebAssembly uses static linking by default, where the application is deployed as a single WebAssembly file which contains the Qt libraries and application code. Dynamic linking is an alternative build mode where each library and plugin is distributed individually.
Qt for WebAssembly 默认使用静态链接,即应用程序部署为包含 Qt 库和应用程序代码的单个 WebAssembly 文件。动态链接是另一种构建模式,其中每个库和插件都是单独发布的。

For instance, an application which uses Qt Quick may make use of the following libraries and plugins:
例如,使用 Qt Quick 的应用程序可以使用以下库和插件:

  • <qtpath>/lib/libQt6Core.so
  • <qtpath>/lib/libQt6Gui.so
  • <qtpath>/lib/libQt6Qml.so
  • <qtpath>/lib/libQt6Quick.so
  • <qtpath>/plugins/imageformats/libqjpeg.so
  • <qtpath>/plugins/imageformats/libqjgif.so
  • <qtpath>/qml/QtQuick/Window/libquickwindowplugin.so

Dynamic linking support is currently in developer preview. The implementation is suitable for prototyping and evaluation, but is not suitable for production use. Current limitations and restrictions include:
动态链接支持目前处于开发人员预览阶段。该实现适合原型开发和评估,但不适合生产使用。目前的限制和约束包括

  • The Emscripten SDK must be patched. Use emsdk 3.1.37, and apply this patch.
    必须修补 Emscripten SDK。请使用 emsdk 3.1.37 并打上此补丁。
  • The Chrome browser is not supported, due it not supporting synchronous loading of wasm files larger than 4K.
    不支持 Chrome 浏览器,因为它不支持同步加载大于 4K 的 wasm 文件。
  • Multithreading is not supported.
    不支持多线程。
  • Asyncify is not supported.
    不支持 Asyncify。

Quick Start 快速入门

The build and deployment procedure is slightly different than that from static wasm and shared desktop builds. Consider starting with a small example before progressing to a full application build.
构建和部署程序与静态 wism 和共享桌面构建略有不同。在进行完整的应用程序构建之前,可以考虑先从一个小示例开始。

  1. Build Qt from source, pass the “-shared” option to the Qt configure script.
    从源代码构建 Qt,向 Qt 配置脚本传递"-shared "选项。
  2. Build your application using Qt from step 1.
    使用步骤 1 中的 Qt 创建应用程序。
  3. Deploy the Qt installation by copying or linking to a directory named "qt" in the application directory
    通过复制或链接到应用程序目录中名为 "qt "的目录,部署 Qt 安装程序
    • ln -s <qtpath> qt
    • cp -r <qtpath> qt
  4. Create plugin preloading lists by running deployment scripts.
    通过运行部署脚本创建插件预加载列表。
    • <qtpath>/qtbase/util/wasm/preload/deploy_qt_plugins.py <qtpath>
    • <qtpath>/qtbase/util/wasm/preload/deploy_qml_imports.py <qthostpath> <qtpath>

Shared Libraries Deployment in Depth
共享库深度部署

The shared libraries build of Qt is deployed in two stages, where the first stage makes the Qt and application build available for download from the web server, and the second stage downloads required Qt plugins and Qt Quick imports at application startup.
Qt 的共享库构建分两个阶段部署,第一阶段从 Web 服务器下载 Qt 和应用程序构建,第二阶段在应用程序启动时下载所需的 Qt 插件和 Qt Quick 导入。

In the first step, make the Qt installation available for download from the web server. Depending on the specifics of the web server setup there may be different ways to accomplish this. In common is that the Qt loader expects to find the Qt libraries and plugins in a directory name "qt", relative to the html file which loads the application.
第一步,从网络服务器下载 Qt 安装。根据网络服务器设置的具体情况,可能会有不同的方法来实现这一点。常见的情况是,Qt 加载器希望在加载应用程序的 html 文件相对应的名为 "qt "的目录中找到 Qt 库和插件。

If you are already copying the application to the web server as a part of deployment, then copying Qt as well is a possible option. If you are serving the application directly from its build directroy - often the case during development phases - then creating a symlink to Qt can work well.
如果作为部署的一部分,您已将应用程序复制到网络服务器,那么复制 Qt 也是一种可能的选择。如果您直接从应用程序的构建目录为其提供服务(通常是在开发阶段),那么创建一个指向 Qt 的符号链接也是不错的选择。

Prepare for the second step by creating preload lists for Qt components such as plugins and Qt Quick imports. Preloading ensures that all required Qt components are availabe at application startup. Delayed loading, where components are dowloaded on demand, is also possbile but is not covered here.
为第二步做准备,为插件和 Qt Quick 导入等 Qt 组件创建预加载列表。预加载可确保应用程序启动时可使用所有需要的 Qt 组件。延迟加载,即按需下载组件,也是可行的,但这里不涉及。

Preloading is implemented by the Qt JavaScript loader, which downloads files from the web server to the in-memory file system provided by Emscripten. Which files to download is specified using json-formatted download lists. Qt provides two scripts for generating preload lists, see Quick Start section above.
预加载由 Qt JavaScript 加载器实现,它将文件从网络服务器下载到 Emscripten 提供的内存文件系统中。使用 json 格式的下载列表可指定要下载的文件。Qt 提供了两个用于生成预加载列表的脚本,请参见上文的快速入门部分。

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。可使用实验功能 Asyncify。
  • Printing is not supported
    不支持打印
  • QDnsLookup lookups, QTcpSocket, QSsl do not work and are not supported due to the web sandbox
    由于网络沙盒的原因,QDnsLookup 查找、QTcpSocket 和 QSsl 不工作,也不受支持。
  • 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 CMakeLists.txt: set_target_properties(<target> PROPERTIES QT_WASM_INITIAL_MEMORY "150MB")
    链接时间错误,如 "wasm-ld: error: initial memory too small"(wasm-ld:错误:初始内存太小),需要调整初始内存大小。使用 QT_WASM_INITIAL_MEMORY 设置初始内存大小,单位为 kb,必须是 64KB 的倍数(65536)。默认值为 50 MB。在 CMakeLists.txt 中: set_target_properties( PROPERTIES QT_WASM_INITIAL_MEMORY "150MB")
  • add_executable in CMakeLists.txt does not produce <target>.html or copy qtloader.js. Use qt_add_executable instead.
    CMakeLists.txt 中的 add_executable 不会生成 .html 或复制 qtloader.js。请使用 qt_add_executable。
  • QWebSocket connections are supported by Emscripten only on the main thread.
    Emscripten 仅在主线程上支持 QWebSocket 连接。
  • QWebSockets for WebAssembly does not support sending ping or pong frames, as the API available to web pages and browsers does not expose this functionality.
    QWebSockets for WebAssembly 不支持发送 ping 或 pong 框架,因为网页和浏览器可用的应用程序接口(API)不提供这种功能。
  • Runtime error such as "RangeError: Out of memory" can be worked around by setting MAXIMUM_MEMORY to a value the device supports, for example
    诸如 "RangeError:内存不足 "等运行时错误,可以通过将 MAXIMUM_MEMORY 设置为设备支持的值来解决,例如
    target_link_options(<your target> PRIVATE -s MAXIMUM_MEMORY=1GB)
  • To use QtWebsockets, the subprotocol might need to be set to 'mqtt' for using QtMqtt. Use QWebSocketHandshakeOptions when you open the QWebSocket.
    要使用 QtWebsockets,可能需要将使用 QtMqtt 的子协议设置为 "mqtt"。打开 QWebSocket 时,请使用 QWebSocketHandshakeOptions。

Other Topics 其他主题

Qt Configure Options Reference
Qt 配置选项参考

The following configure options are relevant when building Qt for WebAssembly from source.
以下配置选项与从源代码构建 Qt for WebAssembly 相关。

Configure Argument 配置参数Brief Description 简要说明
-feature-thread -特色主题Multi-threaded Wasm. 多线程 Wasm。
-feature-wasm-simd128Enables WebAssembly SIMD support.
启用 WebAssembly SIMD 支持。
-feature-wasm-exceptions -feature-wasm-exceptions(例外情况Enables WebAssembly exceptions support.
启用 WebAssembly 异常支持。
-feature-opengles3Use opengles3 in addition to the default opengles2.
除默认的 opengles2 外,请使用 opengles3。
-device-option QT_EMSCRIPTEN_ASYNCIFY=1Use asyncify. 使用 asyncify。

Qt disables some features by default for the WebAssembly platform, to reduce the binary size. You can explicitly enable a feature when you configure Qt for WebAssembly:
Qt 默认禁用 WebAssembly 平台的某些功能,以减小二进制文件的大小。在为 WebAssembly 配置 Qt 时,可以明确启用某项功能:

Configure Argument 配置参数Brief Description 简要说明
-feature-topleveldomain -feature-topleveldomain(特征-opleveldomainProvides support for checking if a domain is a top-level domain.
为检查域名是否为顶级域提供支持。

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.8M2.1M
wiggly widget (QtCore + QtGui + QtWidgets)4.3M3.2M
SensorTag (QtCore + QtGui + QtWidgets + QtQuick + QtCharts)8.6M6.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.
压缩通常在网络服务器端进行,使用标准压缩功能:服务器自动压缩或拾取文件的预压缩版本。通常不需要对 Wasm 文件进行特殊处理。

For more information, see Minimizing the size of binaries.
更多信息,请参阅最小化二进制文件大小。

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 可在 The Qt Company 的商业许可下使用。此外,它还受 GNU 通用公共许可证第 3 版的保护。更多详情,请参阅 Qt Licensing。

© 2024 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.
© 2024 The Qt Company Ltd. 版权所有。此处包含的文档贡献的版权归其各自所有者所有。此处提供的文档根据自由软件基金会发布的 GNU Free Documentation License 1.3 版本的条款授权。Qt 及相关徽标是 Qt 有限公司在芬兰和/或世界其他国家的商标。所有其他商标均为其各自所有者的财产。