Auf dieser Seite

Qt für WebAssembly

Mit Qt für WebAssembly können Sie Qt-Anwendungen im Web ausführen.

WebAssembly (abgekürzt Wasm) ist ein binäres Befehlsformat, das für die Ausführung in einer virtuellen Maschine, beispielsweise in einem Webbrowser, vorgesehen ist.

Mit Qt für WebAssembly können Sie Ihre Anwendung als Webanwendung bereitstellen, die in einer Browser-Sandbox ausgeführt wird. Dieser Ansatz eignet sich für webbasierte Anwendungen, die keinen vollständigen Zugriff auf die Funktionen des Host-Geräts benötigen.

Hinweis: Qt for WebAssembly ist eine unterstützte Plattform, jedoch werden einige Module noch nicht unterstützt oder befinden sich in der Tech Preview. Siehe „Unterstützte Qt-Module“.

Erste Schritte mit Qt für WebAssembly

Das Erstellen von Qt-Anwendungen für WebAssembly ähnelt dem Erstellen von Qt für andere Plattformen. Sie müssen ein SDK (Emscripten) installieren, Qt installieren (oder Qt aus dem Quellcode kompilieren) und schließlich die Anwendung erstellen. Es gibt einige Unterschiede: Beispielsweise unterstützt Qt für WebAssembly weniger Module und Funktionen als andere Qt-Builds.

Emscripten installieren

Emscripten ist eine Toolchain zum Kompilieren für WebAssembly. Damit können Sie Qt im Web mit nahezu nativer Geschwindigkeit ohne Browser-Plugins ausführen.

Jede Nebenversion von Qt ist auf eine bestimmte Emscripten-Version ausgerichtet, die in Patch-Veröffentlichungen unverändert bleibt. Die Binärpakete von Qt werden unter Verwendung der Zielversion von Emscripten erstellt. Anwendungen sollten dieselbe Version verwenden, da Emscripten keine ABI-Kompatibilität zwischen den Versionen garantiert.

Die unterstützte Emscripten-Version für 6.12.0 ist Emscripten 5.0.5.

Weitere Informationen zur Installation des Emscripten-SDK finden Sie in der Emscripten-Dokumentation.

Verwenden Sie „ emsdk “, um bestimmte Versionen von „ Emscripten “ zu installieren. Um es beispielsweise für 6.12.0 zu installieren, geben Sie Folgendes ein:

  • ./emsdk install 5.0.5
  • ./emsdk activate 5.0.5

Nach der Installation sollte der Emscripten-Compiler in Ihrem Pfad enthalten sein. Überprüfen Sie dies mit dem folgenden Befehl:

em++ --version

Unter Windows ist Emscripten nach der Installation bereits in Ihrem Pfad enthalten. Unter macOS oder Linux müssen Sie es wie folgt zu Ihrem Pfad hinzufügen:

source /path/to/emsdk/emsdk_env.sh

Überprüfen Sie dies mit dem folgenden Befehl:

em++ --version

Sie können Qt aus dem Quellcode kompilieren, wenn Sie bei der Auswahl der Emscripten-Version mehr Flexibilität benötigen. In diesem Fall stellen die oben genannten Versionen die Mindestanforderungen dar. Neuere Versionen sollten zwar funktionieren, können jedoch zu Verhaltensänderungen führen, die Anpassungen an Qt erfordern.

Installation von Qt

Laden Sie Qt im Bereich „Downloads“ Ihres Qt-Kontos herunter. Wir stellen Builds für Linux, macOS und Windows als Entwicklungsplattformen zur Verfügung.

Die Binärversionen sind so konzipiert, dass sie auf möglichst vielen Browsern laufen, und sind in Single-Thread- und Multi-Thread-Versionen erhältlich. Nicht standardmäßige Funktionen wie „ Wasm SIMD “ und „ Wasm exceptions “ werden von den Binärversionen nicht unterstützt.

Qt aus dem Quellcode kompilieren

Beim Kompilieren aus dem Quellcode können Sie Qt-Konfigurationsoptionen wie Thread-Unterstützung, OpenGL ES-Level oder SIMD-Unterstützung festlegen. Laden Sie die Qt-Quellcodes im Bereich „Downloads“ Ihres Qt-Kontos herunter.

Konfigurieren Sie Qt als Cross-Compile-Build für die Plattform „ wasm-emscripten “. Dadurch werden die Konfigurationsoptionen „ -static “, „ -no-feature-thread “ und „ -no-make examples “ gesetzt. Sie können die Thread-Unterstützung mit der Konfigurationsoption „ -feature-thread “ aktivieren. Der Build von gemeinsam genutzten Bibliotheken wird nicht unterstützt.

Sie benötigen eine Host-Version derselben Qt-Version. Legen Sie außerdem den Pfad zur Host-Version in der CMake-Variablen ` QT_HOST_PATH ` oder mithilfe des Konfigurationsarguments ` -qt-host-path ` fest.

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

Hinweis: „configure“ verwendet immer den Ninja-Generator und das Ninja-Build-Tool, sofern eine ausführbare Datei namens „ ninja “ verfügbar ist. Ninja ist plattformübergreifend, funktionsreich, leistungsstark und wird auf allen Plattformen empfohlen. Die Verwendung anderer Generatoren funktioniert möglicherweise, wird jedoch nicht offiziell unterstützt.

Stellen Sie unter Windows sicher, dass sich „Mingw-w64“ in Ihrem „ PATH “ befindet, und führen Sie „configure“ mit folgenden Optionen aus:

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

Erstellen Sie anschließend die erforderlichen Module:

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

Anwendungen über die Befehlszeile erstellen

Qt für WebAssembly unterstützt das Erstellen von Anwendungen mit CMake unter Verwendung von Ninja oder Make.

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

Hinweis: Bei Verwendung von „ CMake “ (im Gegensatz zu „ qt-cmake “ unter Linux oder „ qt-cmake.bat “ unter Windows) denken Sie daran, wie bei jedem anderen plattformübergreifenden Build eine Toolchain-Datei mit „-DCMAKE_TOOLCHAIN_FILE“ anzugeben. Weitere Informationen finden Sie hier: Erste Schritte mit CMake.

Beim Erstellen der Anwendung werden mehrere Ausgabedateien generiert, darunter eine .wasm-Datei, die den Anwendungs- und Qt-Code (statisch verknüpft) enthält, sowie eine .html-Datei, die im Browser geöffnet werden kann, um die Anwendung auszuführen.

Hinweis: Emscripten erzeugt auf der Debug-Stufe „-g“ relativ große .wasm-Dateien. Erwägen Sie für Debug-Builds die Verwendung von „-g2“.

Ausführen von Anwendungen

Zum Ausführen der Anwendung ist ein Webserver erforderlich. Bei den erzeugten Dateien handelt es sich ausschließlich um statische Inhalte, sodass jeder Webserver geeignet ist. In einigen Anwendungsfällen sind möglicherweise spezielle Serverkonfigurationen erforderlich, wie beispielsweise die Bereitstellung von HTTPS-Zertifikaten oder die Einstellung von HTTP-Headern, die für die Multithreading-Unterstützung notwendig sind.

Emrun

Emscripten stellt das Dienstprogramm „emrun“ zum Testen von Anwendungen bereit. Emrun startet einen Webserver, öffnet einen Browser und erfasst sowie leitet stdout/stderr weiter (die normalerweise an die JavaScript-Konsole gesendet werden).

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

Python http.server

Eine weitere Möglichkeit besteht darin, einen Entwicklungs-Webserver zu starten und anschließend den Webbrowser separat zu öffnen. Eine der einfachsten Optionen ist „http.server“ aus Python:

python -m http.server

Beachten Sie, dass es sich hierbei nur um einen einfachen Webserver handelt, der SharedArrayBuffer, das für Threading erforderlich ist, nicht unterstützt, da die unten erwähnten erforderlichen COOP- (Cross-Origin-Opener-Policy) und COEP- (Cross-Origin-Embedder-Policy) Header nicht gesendet werden.

qtwasmserver

Qt stellt einen Entwickler-Webserver bereit, der mkcert zur Generierung von HTTPS-Zertifikaten verwendet. Dies ermöglicht das Testen von Webfunktionen, die einen sicheren Kontext erfordern. Beachten Sie, dass die Bereitstellung über http://localhost ebenfalls als sicher gilt, ohne dass ein Zertifikat erforderlich ist.

Der Webserver setzt außerdem die Header „COOP“ und „COEP“ auf Werte, die die Unterstützung von „SharedArrayBuffer“ und Multithreading ermöglichen.

Das Skript „qtwasmserver“ startet einen Server, der standardmäßig an „localhost“ gebunden ist. Sie können mit dem Befehlszeilenargument „-a“ weitere Adressen hinzufügen oder mit „ --all “ eine Bindung an alle verfügbaren Adressen herstellen.

Das Skript „qtwasmserver“ befindet sich in den Quelldateien unter

qtbase/util/wasm/qtwasmserver/qtwasmserver.py

oder kann mit pip installiert werden:

pip install qtwasmserver

Weitere Informationen zu qtwasmserver finden Sie unter qtwasmserver

Verwendung von qtwasmserver:

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

Erstellen von Anwendungen mit Qt Creator

Qt Creator: Erstellen Sie Anwendungen für das Web.

Bereitstellung von Anwendungen im Web

Beim Erstellen einer Anwendung werden mehrere Dateien generiert (ersetzen Sie „app“ in der folgenden Tabelle durch den Namen der Anwendung).

Erzeugte DateiKurzbeschreibung
app.htmlHTML-Container
qtloader.jsJavaScript-API zum Laden von Qt-Anwendungen
app.jsVon Emscripten generierte JavaScript-Laufzeitumgebung
app.wasmApp-Binärdatei

Sie können app.html unverändert bereitstellen oder zugunsten einer benutzerdefinierten HTML-Datei verwerfen. Kleinere Anpassungen, wie beispielsweise das Ersetzen des Bildes auf dem Begrüßungsbildschirm vom Qt-Logo durch das App-Logo, sind ebenfalls möglich. In beiden Fällen stellt qtloader.js eine JavaScript-API zum Laden der Anwendung bereit.

Komprimieren Sie die WASM-Datei vor der Bereitstellung entweder mit gzip oder brotli, da diese Tools eine bessere Komprimierungsrate bieten als andere. Weitere Informationen finden Sie unter „Größe von Binärdateien minimieren “.

Das Aktivieren bestimmter Funktionen, wie z. B. Multithreading und SIMD, führt zu .wasm-Binärdateien, die mit Browsern inkompatibel sind, die die aktivierte Funktion nicht unterstützen. Es ist möglich, diese Einschränkung zu umgehen, indem mehrere .wasm-Dateien erstellt werden und anschließend mithilfe der JavaScript-Funktionserkennung die richtige ausgewählt wird. Beachten Sie jedoch, dass Qt hierfür keine Funktionen bereitstellt.

Verwendung von qtloader

Qt stellt eine JavaScript-API zum Herunterladen, Kompilieren und Instanziieren von Qt-for-WebAssembly-Anwendungen bereit. Diese Lade-API verpackt die von Emscripten bereitgestellten Ladefunktionen und bietet zusätzliche Funktionen, die für Qt-basierte Anwendungen nützlich sind. Sie ist in der Datei „qtloader.js“ implementiert. Eine Kopie dieser Datei wird beim Erstellen in das Build-Verzeichnis geschrieben.

Eine typische Verwendung sieht wie folgt aus:

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

Der Code ruft die Loader-Funktion `qtLoad()` mit einem Konfigurationsobjekt auf. Dieses Konfigurationsobjekt kann beliebige emscripten-Konfigurationsoptionen sowie ein spezielles „qt“-Konfigurationsobjekt enthalten. Das „qt“-Konfigurationsobjekt unterstützt die folgenden Eigenschaften:

EigenschaftKurzbeschreibung
containerElementsArray von HTML-Container-Elementen. Die Anwendung betrachtet diese als QScreens.
onLoadedCallback, der aufgerufen wird, sobald die Anwendung vollständig geladen ist.
onExitCallback, der aufgerufen wird, wenn die Anwendung beendet wird.

Das Array „containerElements“ ist die Hauptschnittstelle zwischen Qt und der Webseite, wobei die HTML-Elemente in diesem Array (in der Regel <DIV>-Elemente) die Position des Anwendungsinhalts auf der Webseite festlegen.

Die Anwendung betrachtet jedes Containerelement als eine Instanz von ` QScreen ` und kann Anwendungsfenster wie gewohnt auf den Bildschirminstanzen platzieren. Fenster, bei denen der Status „ Qt::WindowFullScreen “ gesetzt ist, nutzen den gesamten Bildschirmbereich, während Fenster, die nicht im Vollbildmodus sind, Fensterdekorationen erhalten.

Die Funktion `qtLoad()` gibt ein Promise zurück, das bei der Abfrage eine Emscripten-Instanz liefert. Die Instanz ermöglicht den Zugriff auf die von Embind exportierten Funktionen. Qt exportiert mehrere solcher Funktionen, die zusammen die Instanz-API bilden.

Verwendung der Qt-Instanz-API

Qt stellt mehrere Instanzfunktionen zur Verfügung. Derzeit unterstützen diese das Hinzufügen und Entfernen von Containerelementen zur Laufzeit.

EigenschaftKurzbeschreibung
qtAddContainerElementFügt ein Containerelement hinzu. Durch das Hinzufügen eines Elements wird ein neues ` QScreen` erstellt.
qtRemoveContainerElementEin Containerelement und den dazugehörigen Bildschirm entfernen.
qtSetContainerElementsLegt alle Containerelemente fest
qtResizeContainerElementLässt Qt Änderungen an der Größe des Containerelements übernehmen.

Portierung auf den Qt 6.6 qtloader

Qt 6.6 enthält einen neuen qtloader mit einer vereinfachten Implementierung und einem geringeren Funktionsumfang. Dies beinhaltet API-Änderungen, die möglicherweise eine Portierung des JavaScript-Codes der Anwendung erfordern. Qt stellt eine Kompatibilitäts-API bereit, um den Übergang zu erleichtern. Je nach Anwendungsfall gibt es mehrere Möglichkeiten:

  • Wenn Sie die generierte Datei „ app.html “ direkt verwenden, wird diese Datei beim Erstellen ebenfalls aktualisiert. Es sind keine Maßnahmen erforderlich.
  • Wenn Sie den grundlegenden Funktionsumfang des „qtloader“ nutzen, können Sie die in Qt 6.6 enthaltene Kompatibilitäts-API als vorübergehende Maßnahme verwenden. Diese API wird in einer zukünftigen Version entfernt; Sie sollten daher ein Update planen, um den neuen „qtloader“ zu verwenden. Dazu ist der unten beschriebene Portierungsschritt 1 erforderlich.
  • Wenn Sie erweiterte Funktionen nutzen (z. B. das Hinzufügen von Container-Elementen zur Laufzeit), ist eine Portierung auf den neuen Loader oder die neue Instanz-API erforderlich. Die folgenden Portierungsschritte 1 und 2 sind erforderlich.

Portierungsschritte

  1. Binden Sie die „ app.js “ (von Emscripten generierte JavaScript-Laufzeitumgebung) aus der HTML-Ladungsdatei ein.
    <script src="app.js"></script>

    Vor Qt 6.6 hat „qtloader“ diese JavaScript-Datei geladen und ausgewertet. Dies ist nun nicht mehr der Fall, und die Datei muss mithilfe eines <script>-Tags eingebunden werden.

  2. Portieren Sie das Programm auf die neue JavaScript- und Instanz-API.

Siehe die obigen Abschnitte der Dokumentation.

Unterstützte Browser

Desktop

Qt für WebAssembly wird auf den folgenden Browsern entwickelt und getestet:

  • Chrome
  • Firefox
  • Safari
  • Edge

Qt sollte funktionieren, wenn der Browser WebAssembly unterstützt. Browser, die WebAssembly unterstützen, unterstützen oft auch WebGL, obwohl einige Browser ältere oder nicht unterstützte GPUs auf eine Sperrliste setzen.s/qtloader.js stellt APIs zur Verfügung, um zu prüfen, ob WebGL verfügbar ist.

Qt nutzt Betriebssystemfunktionen nicht direkt, und es spielt keine Rolle, ob beispielsweise Firefox unter Windows oder macOS läuft. Qt nutzt jedoch einige Betriebssystemanpassungen, zum Beispiel für die Behandlung der Strg-/Cmd-Taste unter macOS.

Mobilgeräte

Qt für WebAssembly-Anwendungen läuft auf mobilen Browsern wie dem mobilen Safari und Android Chrome.

Unterstützte Qt-Module

Qt für WebAssembly unterstützt eine Teilmenge der Qt-Module und -Funktionen. Die getesteten Module sind unten aufgeführt; andere Module funktionieren möglicherweise oder auch nicht.

Die folgenden Module befinden sich in der Technology Preview. Sie weisen möglicherweise eingeschränkte Funktionalität auf oder können sich in zukünftigen Versionen erheblich ändern.

In jedem Fall ist die Unterstützung der Module möglicherweise noch nicht vollständig, und es können zusätzliche Einschränkungen bestehen, die entweder auf die Browser-Sandbox oder auf die Unvollständigkeit der Qt-Plattformportierung zurückzuführen sind. Weitere Informationen finden Sie unter „Entwickeln mit Qt für WebAssembly “.

Entwickeln mit Qt für WebAssembly

Erstellen mit CMake

Falls in CMake eine Emscripten-spezifische Konfiguration erforderlich ist, kann der folgende Code verwendet werden:

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

Dieser Code ermöglicht die Berücksichtigung von Emscripten-spezifischen Konfigurationen und gewährleistet gleichzeitig die Kompatibilität mit anderen Plattformen.

OpenGL und WebGL

Qt für WebAssembly unterstützt hardwarebeschleunigtes Rendering mithilfe von https://developer.mozilla.org/en-US/docs/Web/API/WebGL_API WebGL.

WebGL entspricht weitgehend OpenGL ES, wobei folgende Versionszuordnung gilt:

OpenGLWebGL
OpenGL ES 2.0WebGL 1
OpenGL ES 3.0WebGL 2

Qt verwendet die höchste verfügbare WebGL-Version. Bei heutigen Browsern ist dies in der Regel WebGL 2, bei Hardwareeinschränkungen kann es jedoch auch WebGL 1 sein. Wir empfehlen, mit Qt für WebAssembly Geräte anzusprechen, die WebGL 2 unterstützen.

Die Unterschiede zwischen Web- und Desktop-OpenGL sind unter „Unterschiede zwischen WebGL und OpenGL“ dokumentiert. Es gibt weitere Unterschiede zwischen WebGL 1.0 und WebGL 2.0, die in der WebGL-2.0-Spezifikation dokumentiert sind.

Standardmäßig wird eine WebGL-kompatible Teilmenge von ES2 (und ES3) verwendet. Wenn Sie „ glDrawArrays “ und „ glDrawElements “ ohne gebundene Puffer verwenden müssen, können Sie die vollständige ES2-Unterstützung aktivieren, indem Sie Folgendes hinzufügen:

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

und/oder die vollständige ES3-Emulation durch Hinzufügen von

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

in die Datei „ CMakeLists.txt “ Ihres Projekts ein.

Weitere Informationen zur OpenGL-Unterstützung von Emscripten finden Sie unter https://emscripten.org/docs/porting/multimedia_and_graphics/OpenGL-support.html

Einschränkungen des OpenGL-Kontexts

WebGL unterstützt keine mehreren Kontexte pro Oberfläche. Dies hat Auswirkungen auf Anwendungen, die ` QOpenGLContext ` entweder direkt oder indirekt über andere Klassen wie ` QOpenGLWidget` verwenden.

Jede ` QOpenGLContext `-Instanz sollte nur mit einer einzigen Oberfläche verwendet werden. In der Praxis wird der Kontext beim ersten Aufruf von `makeCurrent()` mit der Oberfläche verknüpft. Ein späterer Aufruf von `makeCurrent()` für eine andere Oberfläche oder von einem anderen ` QOpenGLContext ` mit derselben Oberfläche wird nicht unterstützt.

Die gemeinsame Nutzung von OpenGL-Kontexten wird nicht unterstützt. Der Aufruf von ` QOpenGLContext::setShareContext()` hat keine Wirkung, und ` QOpenGLContext::shareContext()` gibt immer `nullptr` zurück.

Das Löschen einer Oberfläche (z. B. eines ` QWindow`) führt zum Verlust des zugehörigen Kontexts. Die Anwendung sollte dies durch das erneute Erstellen des Kontexts behandeln.

QOpenGLWidget und andere Klassen, die intern die gemeinsame Nutzung von Kontexten nutzen, werden nicht unterstützt.

Multithreading

Qt für WebAssembly unterstützt Multithreading mithilfe der Pthreads-Unterstützung von Emscripten, wobei jeder Thread von einem Web Worker unterstützt wird. Aktivieren Sie Multithreading, indem Sie die Komponente „WebAssembly (multi-threaded)“ von Qt Maintenance Tool installieren oder indem Sie Qt aus dem Quellcode kompilieren und dabei das Flag „-feature-thread“ an `configure` übergeben.

Bestehender Threading-Code kann in der Regel wiederverwendet werden, muss jedoch möglicherweise angepasst werden, um Besonderheiten der pthread-Implementierung zu berücksichtigen. Einige Funktionen von Emscripten und Qt werden nicht unterstützt, darunter die Thread-Proxying-Funktion und die Qt Quick -Threaded-Render-Loop.

Beachten Sie, dass es bei Qt für WebAssembly besonders wichtig ist, den Hauptthread nicht zu blockieren, da dieser möglicherweise Anfragen von sekundären Threads bearbeiten muss. Beispielsweise werden alle Timer in Qt auf dem Hauptthread geplant und werden nicht ausgelöst, wenn der Hauptthread blockiert ist. Ein weiteres Beispiel ist, dass das Erstellen eines neuen WebWorkers (für einen Thread) nur vom Hauptthread aus erfolgen kann.

Emscripten bietet hierfür einige Abhilfemaßnahmen. Kurzfristige Wartezeiten, wie beispielsweise das Erlangen einer Mutex-Sperre, werden durch „Busy-Waiting“ und die Verarbeitung von Ereignissen während des Wartens auf die Sperre unterstützt. Längere Wartezeiten im Hauptthread sollten vermieden werden. Insbesondere funktioniert die gängige Vorgehensweise, ` QThread::wait()` oder `pthread_join()` aufzurufen, um auf einen sekundären Thread zu warten, nicht, es sei denn, die Anwendung kann garantieren, dass der Thread (und der Web Worker) bereits gestartet wurde und zum Zeitpunkt des Aufrufs von `wait()` oder `join()` ohne Unterstützung durch den Hauptthread abgeschlossen werden kann.

Die Multithreading-Funktion erfordert Browserunterstützung für die SharedArrayBuffer- API. (Normalerweise speichert Emscripten den Heap in einem ArrayBuffer-Objekt. Für Multithreading muss der Heap mit WebWorkern geteilt werden, wofür ein `SharedArrayBuffer` erforderlich ist.) Diese API ist in der Regel in allen modernen Browsern verfügbar, kann jedoch deaktiviert sein, wenn bestimmte Sicherheitsanforderungen nicht erfüllt sind. WebAssembly-Binärdateien mit aktivierter Thread-Unterstützung lassen sich dann nicht ausführen, auch wenn die Binärdatei tatsächlich keinen Thread startet.

Die Aktivierung von SharedArrayBuffer erfordert einen sicheren Browsing-Kontext (d. h., die Seite wird über https:// oder http://localhost bereitgestellt) und dass sich die Seite im Cross-Origin-Isolated-Modus befindet. Letzteres kann durch das Setzen der sogenannten COOP- und COEP-Header auf dem Webserver erreicht werden:

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

SIMD

Emscripten unterstützt WebAssembly SIMD, das 128-Bit-SIMD-Typen und -Operationen für WebAssembly bereitstellt.

Kompilieren Sie Qt aus dem Quellcode und konfigurieren Sie es mit dem Flag -feature-wasm-simd128, um diese Funktion zu aktivieren; dadurch wird das Flag -msimd128 bei der Kompilierung und beim Verknüpfen übergeben. Beachten Sie, dass Qt derzeit keine für wasm-simd optimierten Codepfade enthält; die Aktivierung von wasm-simd ermöglicht jedoch die automatische Vektorisierung durch den Compiler, bei der dieser die SIMD-Befehle nutzen kann.

Sie können WebAssembly-SIMD direkt ansprechen, indem Sie entweder die GCC/Clang-SIMD-Vektor-Erweiterungen oder die WASM-SIMD128-Intrinsics verwenden. Weitere Informationen finden Sie in der Emscripten -SIMD-Dokumentation.

Darüber hinaus unterstützt Emscripten die Emulation bzw. Übersetzung von x86-SSE-Befehlen in Wasm-SIMD-Befehle. Qt nutzt diese Emulation nicht, da die Verwendung von SSE-SIMD-Befehlen, für die es kein natives Wasm-SIMD-Äquivalent gibt, zu Leistungseinbußen führen kann.

Beachten Sie, dass SIMD-fähige Binärdateien mit Browsern inkompatibel sind, die WebAssembly-SIMD nicht unterstützen, auch wenn die SIMD-Codepfade zur Laufzeit nicht aufgerufen werden. Die SIMD-Unterstützung muss möglicherweise in den erweiterten Einstellungen des Browsers aktiviert werden, z. B. unter „about:config“ oder „chrome:flags“.

Netzwerk

Qt bietet eine eingeschränkte Unterstützung für Netzwerkfunktionen. Im Allgemeinen können Netzwerkprotokolle, die bereits im Web verwendet werden, auch von Qt aus genutzt werden, während andere aufgrund der Web-Sandbox nicht direkt verfügbar sind.

Die folgenden Protokolle werden unterstützt:

  • QNetworkAccessManager HTTP-Anfragen an den Ursprungsserver der Webseite oder an einen Server, der CORS unterstützt. Dazu gehört auch XMLHttpRequest aus QML.
  • QWebSocket Verbindungen zu beliebigen Hosts. Beachten Sie, dass Webseiten, die über das sichere HTTPS-Protokoll bereitgestellt werden, WebSocket-Verbindungen nur über das sichere WSS-Protokoll zulassen.
  • Emulierte POSIX-TCP-Sockets über WebSockets unter Verwendung der von Emscripten bereitgestellten Funktionen. Beachten Sie, dass hierfür ein Weiterleitungsserver erforderlich ist, der die Socket-Übersetzung übernimmt.

Alle anderen Netzwerkprotokolle werden nicht unterstützt.

Hinweis: „ QWebSocketServer “ wird aufgrund von Browser-Einschränkungen nicht unterstützt. Browser schränken serverseitige Socket-Funktionen ein, um die Sicherheit innerhalb der Web-Sandbox zu gewährleisten. Folglich können Funktionen, die auf „ QWebSocketServer “ zur Annahme eingehender Netzwerkverbindungen beruhen, innerhalb der Webumgebung nicht genutzt werden.

Hinweis: Qt MQTT Die Module „ QtRemoteObjects “ können mit „ QtWebSockets “ als Transportprotokolle verwendet werden. Sie werden nicht offiziell unterstützt und funktionieren möglicherweise nicht oder weisen fehlende Funktionen auf. Siehe QMqttClient::connectToHostWebSocket und das Beispiel „QtRemoteObjects WebSockets Applications “.

Cross-Origin Resource Sharing (CORS) und Policy (CORP)

WebAssembly-Anwendungen, die Netzwerkfunktionen nutzen, erfordern möglicherweise, dass der Server die Antwort-Header „Cross-Origin Resource Sharing“ (CORS) und „Cross-Origin Resource Policy“ (CORP) setzt. Diese schränken HTTP-Anfragen ein, die von anderen Domänen stammen und ein Sicherheitsrisiko darstellen.

Unter Verwendung von QHttpServer finden Sie im Folgenden ein Beispiel für die Einstellung dieser Header:

auto headers = response.headers();
headers.append("Access-Control-Allow-Origin", "*");
headers.append("Access-Control-Allow-Origin", "localhost");
headers.append("Access-Control-Allow-Methods", "POST, GET, OPTIONS");

headers.append("Cross-Origin-Opener-Policy", "same-origin");
headers.append("Cross-Origin-Embedder-Policy", "require-corp");
headers.append("Cross-Origin-Resource-Policy", "cross-origin");

Andere bekannte Server verfügen über eigene Methoden zur Konfiguration des Versands dieser Header.

Die Verwendung eines Platzhalters „*“ für „Access-Control-Allow-Origin“ führt zu einem Fehler, wenn dieser zusammen mit „Access-Control-Allow-Credentials“ verwendet wird.

Das mitgelieferte Dienstprogramm-Skript „qtwasmserver.py“ setzt diese Header, wenn die Option „ --cross-origin-isolation “ verwendet wird.

Lokaler Dateizugriff

Der Zugriff auf das Dateisystem erfolgt im Web in einer Sandbox, was Auswirkungen darauf hat, wie die Anwendung mit Dateien umgeht. Die Webplattform stellt APIs für den Zugriff auf das lokale Dateisystem bereit, der unter der Kontrolle des Benutzers steht, sowie APIs für den Zugriff auf persistenten Speicher. Emscripten und Qt verpacken diese Funktionen und stellen APIs bereit, die sich aus C++- und Qt-basierten Anwendungen heraus einfacher nutzen lassen.

Die Webplattform bietet Funktionen für den Zugriff auf lokale Dateien und persistenten Speicher:

  • <input type="file"> zum Anzeigen eines nativen Dateiauswahldialogs, in dem der Benutzer eine Datei auswählen kann.
  • IndexedDB bietet persistenten lokalen Speicher (außerhalb des Browsers nicht zugänglich)

Emscripten stellt mehrere Dateisysteme mit einer POSIX-ähnlichen API bereit. Dazu gehören:

  • das temporäre Dateisystem MEMFS, das Dateien im Arbeitsspeicher speichert
  • das persistente IDBFS-Dateisystem, das Dateien mithilfe von IndexedDB speichert

Emscripten bindet beim Start der Anwendung ein temporäres MEMFS-Dateisystem unter „/“ ein. Das bedeutet, dass „ QFile “ verwendet werden kann und Dateien standardmäßig im Arbeitsspeicher gelesen und geschrieben werden. Diese werden beim Neuladen des Browsers nicht beibehalten.

Da Webseiten keinen direkten Zugriff auf das lokale Dateisystem haben, stellt Qt eine „ QFileDialog “-API zur Verwendung mit Qt für WebAssembly bereit.

Zugriff auf die Zwischenablage

Qt unterstützt das Kopieren und Einfügen von Text, URLs, bekannten Dateitypen und Bildern über die System-Zwischenablage, wobei es aufgrund der Web-Sandbox einige Unterschiede gibt. Beliebige binäre Daten vom Typ „application/octet-stream“ werden nicht unterstützt. Im Allgemeinen erfordert der Zugriff auf die Zwischenablage die Erlaubnis des Benutzers, die durch die Behandlung eines Eingabeereignisses (z. B. STRG+C) oder durch die Verwendung der Zwischenablage-API eingeholt werden kann.

Schriftarten

Das Qt-WASM-Modul enthält drei eingebettete Schriftarten: „Bitstream Vera Sans“ (Fallback-Schriftart), „DejaVu Sans“ und „DejaVu Sans Mono“.

Diese Schriftarten bieten einen begrenzten Zeichensatz. Qt bietet mehrere Möglichkeiten, zusätzliche Schriftarten hinzuzufügen:

Eine Möglichkeit ist die Verwendung von ` FontLoader ` in QML, womit eine Schriftart entweder über eine URL oder über das Qt-Ressourcensystem abgerufen werden kann (genauso wie bei herkömmlichen Desktop-Anwendungen).

Die andere Möglichkeit, eine Schriftart zu verwenden, besteht darin, sie über ` QFontDatabase::addApplicationFontFromData` hinzuzufügen.

Barrierefreiheit und Bildschirmleseprogramme

Qt für WebAssembly bietet grundlegende Unterstützung für Bildschirmleseprogramme. Einfache UI-Elemente wie Schaltflächen und Kontrollkästchen funktionieren, während bei komplexeren UI-Elementen wie Tabellen- oder Baumansichten möglicherweise noch Unterstützung fehlt. Sowohl Qt Widgets als auch Qt Quick werden unterstützt.

Die folgenden Konfigurationen von Bildschirmleseprogrammen und Browsern wurden getestet und funktionieren nachweislich. Andere Browser und Bildschirmleseprogramme funktionieren möglicherweise ebenfalls.

  • VoiceOver mit Safari unter macOS
  • VoiceOver mit Chrome unter macOS

Die Barrierefreiheitsimplementierung funktioniert durch die Erstellung von „Shadow“-HTML-Elementen, die die Barrierefreiheitsinformationen für die Qt-UI-Elemente bereitstellen. Diese Funktion ist standardmäßig deaktiviert. Der Endnutzer kann sie aktivieren, indem er mithilfe des Screenreaders die Schaltfläche „Screenreader aktivieren“ auswählt. Nach der Aktivierung wird die Webseite mit Barrierefreiheitselementen versehen.

Ziehen und Ablegen

  • Das Ablegen wird unterstützt (Dateien und vom Browser unterstützte MIME-Typen).
  • Das anwendungsinterne Drag-and-Drop wird unterstützt.
  • Das Ziehen aus der Anwendung heraus wird nicht unterstützt.

Anwendungsstart und die Ereignisschleife

Qt für WebAssembly unterstützt den standardmäßigen Qt-Startansatz, bei dem die Anwendung ein ` QApplication `-Objekt erstellt und die Funktion `exec` aufruft:

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

    QWindow appWindow;

    return app.exec();
}

Der obige Aufruf von `exec()` blockiert normalerweise und verarbeitet Ereignisse bis zum Beenden der Anwendung. Leider ist dies auf der Webplattform nicht möglich, da das Blockieren des Hauptthreads dort nicht erlaubt ist. Stattdessen muss die Kontrolle nach der Verarbeitung jedes Ereignisses an die Ereignisschleife des Browsers zurückgegeben werden.

Qt umgeht dies, indem „exec()“ die Kontrolle über den Hauptthread an den Browser zurückgibt, dabei aber den Stack beibehält. Aus Sicht des Anwendungscodes wird die Funktion „exec()“ aufgerufen und die Ereignisverarbeitung läuft wie gewohnt ab. Der Aufruf von „exec()“ kehrt jedoch niemals zurück, auch nicht beim Beenden der Anwendung.

Dieses Verhalten ist in der Regel akzeptabel, da der Browser den Anwendungsspeicher beim Beenden der Anwendung freigibt. Es bedeutet jedoch, dass der Beendigungscode nicht ausgeführt wird, da das Anwendungsobjekt nicht freigegeben wird und sein Destruktor nicht ausgeführt wird.

Sie können dies vermeiden, indem Sie `main()` so umschreiben, dass es asynchron läuft, was möglich ist, da Emscripten die Laufzeitumgebung nicht beendet, wenn `main()` zurückkehrt. Der Anwendungscode verzichtet dann auf den Aufruf von `exec()` und kann Qt sauber beenden, indem er das Fenster der obersten Ebene sowie die Anwendungsobjekte löscht.

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;
}

Hinweis: Dies gilt, wenn Asyncify oder JSPI nicht verwendet werden. Bei Verwendung von Asyncify oder JSPI ist der Aufruf von `exec()` in `main()` erforderlich.

Asyncify und JSPI

Die Standard-Qt-Build-Version für WebAssembly unterstützt das Wiedereintreten in die Ereignisschleife – beispielsweise durch den Aufruf von ` QEventLoop::exec()` oder ` QDialog::exec()` – nicht, da Einschränkungen der Webplattform verhindern, dass synchroner C++-Code asynchrone JavaScript-APIs aufruft.

Zu den Funktionen, die asyncify/JSPI erfordern, gehören:

  • QDialogs, QMessageBoxes mit Rückgabewerten.
  • Drag & Drop (insbesondere Drag).
  • Verschachtelte/sekundäre Ereignisschleifen exec().

Emscripten bietet Unterstützung, um diese Einschränkungen mithilfe der Asyncify -Funktion zu umgehen. Diese Funktion ist in zwei Versionen verfügbar:

  • „Asyncify“, implementiert über einen Nachbearbeitungsschritt für WebAssembly-Code.
  • JSPI, implementiert mithilfe der WebAssembly-Funktion „JS Promise Integration “.

In den folgenden Abschnitten finden Sie Details dazu, wie Sie die einzelnen Optionen aktivieren können und welche Vor- und Nachteile damit verbunden sind. Kurz gesagt: Asyncify ist bereits heute verfügbar, verursacht jedoch einen Mehraufwand in Form von längeren Build-Zeiten, größeren Binärdateigrößen und Leistungseinbußen zur Laufzeit. JSPI verursacht nur minimalen oder gar keinen Mehraufwand, wird jedoch noch nicht von allen Browsern unterstützt.

Hinweis: Der Aufruf von `application.exec()` in `main()` war in früheren Versionen von Qt für WebAssembly optional, ist nun aber bei Verwendung von „Asyncify“ oder „JSPI“ erforderlich.

Asyncify

Aktivieren Sie Asyncify, indem Sie die Flags „-sASYNCIFY -Os“ zu den Linker-Optionen hinzufügen:

CMake:

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

qmake:

QMAKE_LFLAGS += -sASYNCIFY -Os

Das Aktivieren von „asyncify“ verursacht einen Mehraufwand in Form größerer Binärdateien und einer höheren CPU-Auslastung. Führen Sie den Build mit aktivierten Optimierungen durch, um diesen Mehraufwand zu minimieren.

JSPI (JS Promise Integration)

Im Gegensatz zu „Asyncify“ erfordert die Verwendung von JSPI, dass Qt aus dem Quellcode kompiliert wird. Übergeben Sie die Flags „-feature-wasm-jspi“ und „-feature-wasm-exceptions“ an das Qt-Konfigurationsskript, um es zu aktivieren. (JSPI ist nicht mit den standardmäßigen, von Emscripten emulierten Ausnahmen kompatibel.)

Aktivieren Sie anschließend JSPI für Ihre Anwendung, indem Sie das Flag -sJSPI zu den Linker-Optionen hinzufügen:

CMake:

target_link_options(<your target> PUBLIC -sJSPI)

qmake:

QMAKE_LFLAGS += -sJSPI

Debugging und Profiling

Das Debuggen von Wasm erfolgt über die JavaScript-Konsole des Browsers. Es ist nicht möglich, Wasm-Anwendungen direkt in „ Qt Creator “ zu debuggen.

Sie können die Ausführlichkeit erhöhen, um das Debuggen mithilfe der Emscripten-Linker-Argumente zu erleichtern:

  • -s LIBRARY_DEBUG=1 (Bibliotheksaufrufe ausgeben)
  • -s SYSCALL_DEBUG=1 (Systemaufrufe ausgeben)
  • -s FS_LOG=1 (Dateisystemoperationen ausgeben)
  • -s SOCKET_DEBUG (Socket- und Netzwerkdatenübertragungen ausgeben)

CMake:

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

qmake:

QMAKE_LFLAGS_DEBUG += -s LIBRARY_DEBUG=1

Optimierung

Die Optimierung von Qt für WebAssembly erfolgt mithilfe der Emscripten-Toolchain zur Erzeugung von Binärdateien, wobei zahlreiche Optionen die Leistung und die Größe der Binärdateien beeinflussen können. Weitere Informationen finden Sie unter „Emscripten: Code optimieren “.

Sie können Linker- und Compiler-Optionen genau wie bei normalen C++-Anwendungen übergeben:

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

Minimierung der Größe von Binärdateien

Um eine nahtlose Benutzererfahrung zu gewährleisten, ist es wichtig, die Zeit für das Herunterladen und Laden von WebAssembly-Anwendungen zu verkürzen. Eine kleinere Anwendungsdatei ist einer der wichtigsten Aspekte, die ein schnelleres Herunterladen ermöglichen. Nutzen Sie die folgenden Möglichkeiten, um die Größe der Binärdatei zu reduzieren:

  • Achten Sie darauf, Release-Builds zu verteilen. Debug-Builds enthalten Debug-Symbole und sind deutlich größer.
  • Aktivieren Sie die Komprimierung auf dem Server. Die gängigsten Algorithmen wie „ gzip “ und „Brotli“ eignen sich gut für Wasm-Binärdateien und können deren Größe drastisch reduzieren.
  • Probieren Sie Compiler- und Linker-Flags aus, die zur Erstellung kleinerer Binärdateien führen können (z. B. „-os“, „-oz“). Die Ergebnisse variieren je nach der jeweiligen Anwendung.
  • Deaktivieren Sie nicht verwendete Funktionen, wenn Sie Qt für WebAssembly aus dem Quellcode kompilieren (siehe unten).
Deaktivieren von Funktionen

Eine WebAssembly-Anwendung wird standardmäßig statisch mit den Qt-Bibliotheken verknüpft, wodurch der Compiler toten Code entfernen kann. Aufgrund des dynamischen Charakters von Qt ist es dem Compiler jedoch nicht immer möglich, solche Optimierungen durchzuführen.

Wenn Sie Qt für WebAssembly aus dem Quellcode kompilieren, können Sie Funktionen deaktivieren, um die Größe der Qt-Binärdateien und damit auch die Größe der .wasm-Binärdateien zu reduzieren. Qt deaktiviert standardmäßig einige Funktionen für die WebAssembly-Plattform, Sie können jedoch auch Funktionen deaktivieren, die Ihre Anwendung nicht nutzt. Weitere Informationen finden Sie unter „Deaktivierte Funktionen “.

Sie können die folgenden Funktionen deaktivieren, um die Binärdateigröße zu reduzieren (in der Regel um 10–15 %):

KonfigurationsargumentKurzbeschreibung
-no-feature-cssparserParser für Cascading Style Sheets.
-no-feature-datetimeeditBearbeitung von Datums- und Zeitangaben (abhängig von „datetimeparser“).
-no-feature-datetimeparserParsen von Datums- und Zeitangaben.
-no-feature-dockwidgetWidgets in einem „ QMainWindow “ andocken oder als Fenster auf oberster Ebene auf dem Desktop anzeigen.
-no-feature-gesturesFramework für Gesten.
-no-feature-mimetypeVerarbeitung von MIME-Typen.
-no-feature-qml-networkNetzwerktransparenz.
-no-feature-qml-list-modelListModel QML-Typ.
-no-feature-qml-table-modelTableModel QML-Typ.
-no-feature-quick-canvasCanvas-Element.
-no-feature-quick-pathPfadelemente.
-no-feature-quick-pathviewPathView Element.
-no-feature-quick-treeviewTreeView Element.
-no-feature-style-stylesheetWidget-Stil, der über CSS konfigurierbar ist.
-no-feature-tableviewStandard-Modell/Ansicht-Implementierung einer Tabellenansicht.
-no-feature-texthtmlparserParser für HTML.
-no-feature-textmarkdownreaderMarkdown-Reader (CommonMark und GitHub).
-no-feature-textodfwriterODF-Writer.

Wasm-Ausnahmen

Qt wird standardmäßig ohne Ausnahmeunterstützung kompiliert, sodass das Auslösen einer Ausnahme zum Abbruch des Programms führt. WebAssembly-Ausnahmen können aktiviert werden, indem man aus dem Quellcode kompiliert und das Flag -feature-wasm-exceptions an Qt configure übergibt. Dadurch wird das Flag -fwasm-exceptions beim Kompilieren und Verknüpfen an den Compiler übergeben. Qt unterstützt die Aktivierung der Emscripten-Unterstützung für die frühere JavaScript-basierte Ausnahmebehandlung nicht.

Beachten Sie, dass der Aufruf von ` QApplication::exec()` bei aktivierten Ausnahmen aufgrund interner Implementierungsdetails nicht unterstützt wird. Schreiben Sie stattdessen die Funktion `main()` so, dass sie vorzeitig zurückkehrt und `exec()` nicht aufruft, wie unter „Anwendungsstart und die Ereignisschleife“ beschrieben.

Gemeinsam genutzte Bibliotheken und dynamische Verknüpfung (Technologievorschau)

Qt für WebAssembly verwendet standardmäßig statische Verknüpfung, bei der die Anwendung als einzelne WebAssembly-Datei bereitgestellt wird, die die Qt-Bibliotheken und den Anwendungscode enthält. Die dynamische Verknüpfung ist ein alternativer Build-Modus, bei dem jede Bibliothek und jedes Plugin einzeln verteilt wird.

Beispielsweise kann eine Anwendung, die „ Qt Quick “ verwendet, auf die folgenden Bibliotheken und Plugins zurückgreifen:

  • <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

Die Unterstützung für dynamische Verknüpfungen in Version 6.12 befindet sich in der Technology Preview. Die Implementierung eignet sich für die Prototypenentwicklung und Evaluierung, ist jedoch nicht für den produktiven Einsatz geeignet. Zu den aktuellen Einschränkungen und Beschränkungen gehören:

  • Multithreading wird nicht unterstützt.
  • „Asyncify“ wird nicht unterstützt.

Qt-Anwendungen, die mit dynamischer Verknüpfung erstellt wurden, erfordern, dass neben den Binärdateien zwei zusätzliche Dateien vorhanden sind: „qt_plugins.json“ und „qt_qml_imports.json“. Diese Dateien enthalten eine Liste der gemeinsam genutzten Bibliotheken, die beim Start der Anwendung geladen werden. Zur Erstellung dieser Dateien steht ein Hilfsprogramm zur Verfügung: wasmdeployqt. Um die Verwendung dieses Tools zu veranschaulichen, können Sie es mit dem Flag „ --help “ ausführen, um einen Überblick über die zur Ausführung des Tools erforderlichen Flags sowie ein Anwendungsbeispiel zu erhalten.

Auf dem Webserver, auf dem die Anwendung gehostet wird, müssen die Qt-Shared-Libraries verfügbar sein. Dies kann erreicht werden, indem der Inhalt des Qt-Installationsordners auf den Webserver kopiert wird oder indem ein Dateisystem-Link erstellt wird.

Schnellstart

Das Verfahren zum Erstellen und Bereitstellen unterscheidet sich geringfügig von dem bei statischen WASM- und Shared-Desktop-Builds. Beginnen Sie am besten mit einem kleinen Beispiel, bevor Sie zur Erstellung einer vollständigen Anwendung übergehen.

  1. Erstellen Sie Qt aus dem Quellcode und übergeben Sie die Option „ -shared “ an das Qt-Konfigurationsskript. Verwenden Sie die Option „-prefix“, um das Installationsverzeichnis festzulegen.
  2. Erstellen Sie Ihre Anwendung mit Qt aus Schritt 1.
  3. Erstellen Sie Listen zum Vorladen von Plugins, indem Sie das Bereitstellungstool aus dem Build-Verzeichnis Ihrer Anwendung ausführen.
    • <qtpath>/qtbase/bin/wasmdeployqt --qt-wasm-dir=<Path to the Qt for WebAssembly directory> --qml-root-path=<Root directory for QML files> --qt-host-dir=<Path to the Qt host directory>

Die Bereitstellung von gemeinsam genutzten Bibliotheken im Detail

Die Bereitstellung der gemeinsam genutzten Bibliotheken von Qt erfolgt in zwei Schritten: Im ersten Schritt werden der Qt-Build und der Anwendungs-Build zum Download vom Webserver bereitgestellt, und im zweiten Schritt werden beim Start der Anwendung die erforderlichen Qt-Plugins und „ Qt Quick “-Importe heruntergeladen.

Im ersten Schritt stellen Sie die Qt-Installation auf dem Webserver zum Download bereit. Je nach den Besonderheiten der Webserver-Konfiguration gibt es hierfür verschiedene Möglichkeiten. Gemeinsam ist allen, dass der Qt-Loader erwartet, die Qt-Bibliotheken und -Plugins in einem Verzeichnis namens „qt“ zu finden, relativ zur HTML-Datei, die die Anwendung lädt.

Wenn Sie die Anwendung im Rahmen der Bereitstellung bereits auf den Webserver kopieren, ist es eine mögliche Option, auch Qt mitzukopieren. Wenn Sie die Anwendung direkt aus ihrem Build-Verzeichnis bereitstellen – was in der Entwicklungsphase häufig der Fall ist –, kann das Erstellen eines Symlinks zu Qt eine gute Lösung sein.

Bereiten Sie den zweiten Schritt vor, indem Sie Vorladelisten für Qt-Komponenten wie Plugins und „ Qt Quick “-Importe erstellen. Das Vorladen stellt sicher, dass alle erforderlichen Qt-Komponenten beim Start der Anwendung verfügbar sind. Ein verzögertes Laden, bei dem Komponenten bei Bedarf heruntergeladen werden, ist ebenfalls möglich, wird hier jedoch nicht behandelt.

Das Vorladen wird durch den Qt-JavaScript-Loader implementiert, der Dateien vom Webserver in das von Emscripten bereitgestellte Dateisystem im Arbeitsspeicher herunterlädt. Welche Dateien heruntergeladen werden sollen, wird mithilfe von Download-Listen im JSON-Format festgelegt. Qt stellt ein Tool zur Erstellung von Vorladelisten bereit; siehe Abschnitt „Schnellstart“ weiter oben.

Bekannte Probleme

  • Verschachtelte Ereignisschleifen werden nur bei Verwendung der experimentellen Funktionen „Asyncify“ oder „JSPI“ unterstützt.
  • Das Drucken wird nicht unterstützt.
  • QDnsLookup Lookups und „ QSsl “ funktionieren nicht und werden aufgrund der Web-Sandbox nicht unterstützt. Der Browser übernimmt DNS-Lookups und SSL-Zertifikate. Anwendungen, die DNS-Lookups benötigen, können „DNS over HTTP“ verwenden.
  • QTcpSockets können verwendet werden, jedoch werden nicht alle POSIX-Socket-Funktionen weitergeleitet. Es muss ein WebSockets-Server-Proxy wie Websockify verwendet werden.
  • Alle Q*Server-Klassen werden von der Plattform nicht unterstützt.
  • QWebSocket Verbindungen werden von Emscripten nur im Hauptthread unterstützt.
  • QWebSockets für WebAssembly unterstützt das Senden von Ping- oder Pong-Frames nicht, da die für Webseiten und Browser verfügbare API diese Funktionalität nicht bereitstellt.
  • Um QtWebSockets zu verwenden, muss das Subprotokoll möglicherweise auf „mqtt“ gesetzt werden, um QtMqtt zu nutzen. Verwenden Sie QWebSocketHandshakeOptions, wenn Sie QWebSocket öffnen.
  • Schriftarten: Die Wasm-Sandbox erlaubt keinen Zugriff auf Systemschriftarten. Schriftartdateien müssen mit der Anwendung verteilt werden, beispielsweise in Qt-Ressourcen oder als Download. Qt für WebAssembly selbst bettet eine solche Schriftart ein.
  • Bei einigen Qt Quick Controls -2-Komponenten, wie z. B. Kontrollkästchen, können Artefakte durch nicht initialisierten Grafikspeicher auftreten. Dies ist manchmal auf High-DPI-Bildschirmen zu beobachten.
  • Native Stile für Windows und macOS werden nicht unterstützt, da die Wasm-Plattform diese Funktion nicht bereitstellt.
  • Linkfehler wie „wasm-ld: error: initial memory too small“ erfordern eine Anpassung der anfänglichen Speichergröße. Verwenden Sie QT_WASM_INITIAL_MEMORY, um die anfängliche Größe in KB festzulegen; diese muss ein Vielfaches von 64 KB (65536) sein. Der Standardwert beträgt 50 MB. In CMakeLists.txt: set_target_properties(<target> PROPERTIES QT_WASM_INITIAL_MEMORY "150MB")
  • „add_executable“ in der Datei „CMakeLists.txt“ erzeugt weder eine <target>.html-Datei noch kopiert es „qtloader.js“. Verwenden Sie stattdessen „qt_add_executable“.

Weitere Themen

Referenz zu den Qt-Konfigurationsoptionen

Die folgenden Konfigurationsoptionen sind relevant, wenn Qt für WebAssembly aus dem Quellcode kompiliert wird.

„configure“-ArgumentKurzbeschreibung
-feature-threadMultithread-Wasm.
-feature-wasm-simd128WebAssembly-SIMD-Unterstützung aktivieren.
-feature-wasm-exceptionsWebAssembly-Ausnahmen aktivieren.
-device-option QT_EMSCRIPTEN_ASYNCIFY=1Aktiviert die Unterstützung für „asyncify“.
-device-option QT_EMSCRIPTEN_ASYNCIFY=2Aktiviert die Unterstützung für „asyncify“ (JSPI).

Qt deaktiviert standardmäßig einige Funktionen für die WebAssembly-Plattform, um die Größe der Binärdatei zu reduzieren. Sie können eine Funktion explizit aktivieren, wenn Sie Qt für WebAssembly konfigurieren:

KonfigurationsargumentKurzbeschreibung
-feature-topleveldomainBietet Unterstützung für die Überprüfung, ob es sich bei einer Domain um eine Top-Level-Domain handelt.

Typische Download-Größen

Erwartete Speicherbelegung (Downloadgröße): Vom Compiler erzeugte Wasm-Module können groß sein, lassen sich jedoch gut komprimieren:

Beispielgzipbrotli
helloglwindow (QtCore + QtGui)2,8 Mio.2,1 M
wiggly widget (QtCore + QtGui + QtWidgets)4,3 Mio.3,2 Mio.
SensorTag (QtCore + QtGui + QtWidgets + QtQuick + QtCharts)8,6 Mio.6,3 Mio.

Die Komprimierung erfolgt in der Regel auf der Webserver-Seite unter Verwendung von Standard-Komprimierungsfunktionen: Der Server komprimiert die Dateien automatisch oder greift auf bereits komprimierte Versionen der Dateien zurück. Eine spezielle Behandlung von WASM-Dateien ist in der Regel nicht erforderlich.

Weitere Informationen finden Sie unter „Minimieren der Größe von Binärdateien“.

Beispiele

Beispiele und Demos von Qt-Anwendungen, die in einem Webbrowser ausgeführt werden: Qt-Demos

Externe Ressourcen

Lizenz

Qt für WebAssembly ist unter kommerziellen Lizenzen von The Qt Company erhältlich. Darüber hinaus steht es unter der GNU General Public License, Version 3, zur Verfügung. Weitere Informationen finden Sie unter „Qt-Lizenzierung “.

Siehe auch „https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS“ und „https://developer.mozilla.org/en-US/docs/Web/HTTP/Cross-Origin_Resource_Policy“.

© 2026 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.