文章

Qt6.2 编译WebAssembly

演示通过cmake将Qt6项目编译为WebAssembly,并加载自定义中文字体

首先在官网注册并下载安装Qt。安装时需要勾选WebAssembly选项。截止目前本文所采用的Qt 6.2版本中,WebAssembly还是作为技术预览版出现,不太适合用于生产环境。

直接上代码

// main.cpp #include <QGuiApplication> #include <QQmlApplicationEngine> #include <QQmlContext> #include <QFontDatabase> int main(int argc, char *argv[]) { QGuiApplication app(argc, argv); // 设置全局字体,用于解决Qt for WebAssembly中文显示异常问题 // fileName 参数不用带qrc前缀 int fontId = QFontDatabase::addApplicationFont(":/qtwasm/qrc/ZhiMangXing-Regular.ttf"); QStringList fontFamilies = QFontDatabase::applicationFontFamilies(fontId); qDebug()<<"fontfamilies:"<<fontFamilies; if (fontFamilies.size() > 0) { QFont font; auto fontFamilie = fontFamilies[0]; font.setFamily(fontFamilie);//设置全局字体 app.setFont(font); } QQmlApplicationEngine engine; const QUrl url(QStringLiteral("qrc:/qtwasm/qrc/Main.qml")); engine.load(url); if (engine.rootObjects().isEmpty()) return -1; return app.exec(); }

通过QFontDatabase类加载自定义字体。其实fileName不需要加qrc前缀,不然加载不出来。

QML文件内容如下:

// Main.qml import QtQuick import QtQuick.Controls import QtQuick.Layouts Window { visible: true width: 800 height: 600 title: qsTr("Hello World") App{ } } // App.qml import QtQuick import QtQuick.Controls import QtQuick.Layouts ColumnLayout { Layout.fillHeight: true Layout.fillWidth: true RowLayout { height: 40 Text { text: "Hello中文😯" font.pointSize: 20 } } RowLayout { Layout.preferredHeight: 80 TextEdit { text: "Please Input 请输入内容" selectByMouse: true font.pointSize: 20 } } }

qml内容比较简单,只是演示目的 CMakeLists.txt文件内容如下:

cmake_minimum_required(VERSION 3.15) project(qt-wasm VERSION 0.1 LANGUAGES CXX) set(CMAKE_VERBOSE_MAKEFILE ON) set(CMAKE_INCLUDE_CURRENT_DIR ON) set(CMAKE_AUTOUIC ON) set(CMAKE_AUTOMOC ON) set(CMAKE_AUTORCC ON) set(CMAKE_CXX_STANDARD 20) set(CMAKE_CXX_STANDARD_REQUIRED ON) find_package(Qt6 COMPONENTS Core Gui Quick REQUIRED) set(PROJECT_SOURCES main.cpp) qt_add_executable(qt-wasm MANUAL_FINALIZATION ${PROJECT_SOURCES}) target_link_libraries(qt-wasm PRIVATE Qt6::Core Qt6::Gui Qt6::Quick) # 当编译WebAssembly时修改链接参数,否则会报初始内存太小错误 if(EMSCRIPTEN) target_link_options(qt-wasm PRIVATE -s TOTAL_MEMORY=32MB) endif() qt_import_qml_plugins(qt-wasm) qt_finalize_executable(qt-wasm) qt_add_qml_module(qt-wasm URI qtwasm VERSION 1.0 QML_FILES qrc/Main.qml qrc/App.qml RESOURCES qrc/ZhiMangXing-Regular.ttf)

其中qt_add_qml_module为qt 6.2新增的cmake api 在编译wasm时遇到了初始内存大小超出限制的错误,经过搜索需要加上TOTAL_MEMORY链接参数。在以上cmake文件内容中,通过判断是WebAssembly平台即加上该参数。 中文字体可以在网上下载或本机系统目录中拷贝。

在项目目录执行以下命令构建wasm文件:

mkdir build cd build cmake -DCMAKE_PREFIX_PATH=~/Qt/6.2.0/macos/lib/cmake -DCMAKE_TOOLCHAIN_FILE:PATH=~/Qt/6.2.0/wasm_32/lib/cmake/Qt6/qt.toolchain.cmake .. make

需要把qt的文件目录,和wasm工具链的路径参数传递给cmake命令。 注意需要提前安装Emscripten编译环境,参考官方链接安装:Download and install — Emscripten 3.1.4-git (dev) documentation 执行make构建完成后,会在build目录生成以下文件:

qt-wasm.html qt-wasm.js qt-wasm.wasm qtloader.js

其中qt-wasm是我们在CMakeLists.txt文件中设置的可执行文件名称 如果想看构建完wasm文件之后的运行效果,可以在build目录启动一个简单的http服务器,在浏览器访问相应端口即可。 这里采用node的http-server来运行:

npm i -g http-server # 安装工具,需要node环境 http-sever # 下build目录执行该命令

执行完http-server命令后,即可在浏览器中访问127.0.0.1:8080来查看编译后的效果。 qt通过网页中的canvas来绘制qml文件中描述的内容。

目前可以显示中文了,但是对中文输入法的支持很不好,无法正常输入。同时生成的wasm文件大约有20M,即使gzip压缩后也有7M左右,是不太适合直接应用到网站项目中的。希望后续会有所改善。

本文由作者按照 CC BY 4.0 进行授权