Morten Johan Sørvig

Getting Started With Qt for WebAssembly

Published Monday November 19th, 2018
54 Comments on Getting Started With Qt for WebAssembly
Posted in Dev Loop | Tags:

We’ve previously blogged about some of the features of Qt for WebAssembly. In this blog post we’ll take a look at how to get started: building Qt, building your application, and finally deploying the application.

If you would like to know more about this topic, then please join me for the Qt for WebAssembly webinar on November 27th.

Emscripten

The first step is installing emscripten. Please refer to the emscripten documentation for how to do so, and also note that Qt requires a unix host system: GNU/linux, macOS, or Windows subsystem for Linux. When done you should have a working em++ compiler in the path:

$ em++ --version
emcc (Emscripten gcc/clang-like replacement) 1.38.16 (commit 7a0e27441eda6cb0e3f1210e6837cae4b080ab4c)

Qt for WebAssembly applications are also Emscripten-based applications. Qt makes use of many of its features and so can application code.

Qt

Next, install the Qt 5.12 sources, for example using the online installer:

qtmaintenancetoolsources

Build Qt from source and specify that we are cross-compiling for wasm using emscripten:

$ ~/Qt/5.12.0/Src/configure -xplatform wasm-emscripten -nomake examples -prefix $PWD/qtbase
$ make module-qtbase module-qtdeclarative [other modules]

This Qt build is different from standard desktop builds in two additional ways: It is a static build, and does not support threads. Depending on how your application is structured and which features you use this may pose a problem. One way to find out is to make a separate “-static -no-feature-thread” desktop Qt build, and then debug/fix any issues there. The reason this may be preferable is that the build-debug cycle is usually faster on desktop, and you have a working debugger.

Your Application

Finally, build the application. Qmake is the currently supported build system.

$ /path/to/qt-wasm/qtbase/bin/qmake
$ make

This will produce several output files:

Name Producer Purpose
app.html Qt HTML container
qtloader.js Qt JS API for loading Qt apps
app.js emscripten app runtime and JS API
app.wasm emscripten app binary

Here, the app.wasm contains the majority (if not all) of the application and Qt code, while the .js files provide loading and run-time support.

The .html file provides the html page structure which contains the application as a <canvas> element. The default version of this file displays a Qt logo during the loading and compile stage and contains a simple HTML page structure which makes the application use the entire browser viewport. You will probably want to replace this with application-specific branding and perhaps integrate with existing html content.

For qtloader.js our intention is to have a public and stable API for loading Qt-based applications, but we are not there yet and the API in that file is subject so change.

The files are plain data files and can be served from any http server; there is no requirement for any special active server component or plugin. Note that loading from the file system is not supported by current browsers. I use Python http.server for development, which works well.

When deploying applications we do recommend using a server that supports compression. The following table gives an indication of what the expected file sizes (for the main .wasm file) are:

Qt Modules gzip brotli
Core Gui 2.8MB 2.1MB
Core Gui Widgets 4.3MB 3.2MB
Core Gui Widgets Quick Charts 8.6MB 6.3MB

gzip is a good default choice as compressor and is supported by most web servers. brotli provides a nice compression gain and is supported by all wasm-enabled browsers.

Slate

The final result of all this should be your application running in a web browser, here represented by the Slate app created by my colleague Mitch. Slate is a Qt Quick Controls 2 based image editor.

slate-wasm

A live version is available as well. If you’ve looked at this demo before the news is that it should be actually usable now: local file access is possible and there are few or none visual glitches.

For those that are attending Qt World Summit in Berlin next month: I look forward to seeing you there. If you a are not going then let me link to the webinar once again.

edit: Modified configure string in build instructions to include -nomake examples, since it will currently fail on the threading examples as some have noted in the comments. This will be fixed in Qt 5.12.1.

Do you like this? Share it
Share on LinkedInGoogle+Share on FacebookTweet about this on Twitter

Posted in Dev Loop | Tags:

54 comments

Stephen Morris says:

Does the fact that the Qt framework must be compiled statically, mean that this capability can only be used with a commercial licence? Or perhaps with GPL but not LGPL? I’ve always underdstood that the use of the dynamic Qt libraries is the best way to ensure compliance with the LGPL.

dtech says:

LGPL doesn’t mandate dynamic linking. It mandates that you must provide your work in a relinkable form. Which can be satisfied if you provide a link to your object files in the case of closed source applications. For open source it is a non-issue.

Morten Johan Sørvig Morten Johan Sørvig says:

Also, please note that the open source license for Qt for WebAssambly is GPL. The configure script should prompt you to accept/reject it.

dtech says:

What mandates that? WA is in no way directly utilized in the Qt application itself, it is a part of the underlying platform. Linux is GPL too, but you can run LGPL software on top of it.

Qt modules that are avialable under LGPL should remain avaiable even after including WA in the software stack, otherwise it severely limits applicability.

Morten Johan Sørvig Morten Johan Sørvig says:

Specifically, the wasm platform plugin is GPL licensed (in addition to the commercial license). See for example http://code.qt.io/cgit/qt/qtbase.git/tree/src/plugins/platforms/wasm/main.cpp?h=5.12.

So this is actually a part of Qt. You can use LGPL modules, but you then have to comply with the terms of both the LGPL and GPL.

dtech says:

Well that’s too bad then. At any rate, not that much of a loss, considering the apparently significant overhead.

Luca says:

The web app is very slow on a Fedora 29 (core i3 4th generation), and I cannot draw on the image 🙁

Morten Johan Sørvig Morten Johan Sørvig says:

That sounds not-right. A good control test would be to run some WebGL examples of varying complexity and/or the WebAssembly Tanks! demo (at https://webassembly.org/demo/Tanks/) to see if all WebGL is slow for you or if it’s Qt only.

dtech says:

Would you mind running those QML performance benchmarks that were recently posted to showcase 5.12 improvements? I am curious how it will perform with an additional platform abstraction layer.

Morten Johan Sørvig Morten Johan Sørvig says:

Agreed, this would be a very interesting comparison. I think some of the benchmark runners may require some porting work, so this is a topic for a future blog post.

Tham says:

Thanks for the nice blog, biggest issues remain are threads support(Someone say WA need several years to support native thread) and file system?

Lorn Potter Lorn Potter says:

thread support was enabled for chrome browser, so we can continue and develop the threaded option

Vladislav Navrocky says:

Cannot build Qt. I get such error while building:

5.12.0/Src/qtbase/examples/corelib/threads/semaphores/semaphores.cpp:62:1: error: unknown type name ‘QSemaphore’
QSemaphore freeBytes(BufferSize);
^

Whats wrong?

Jinming Chen says:

That’s because Qt for WebAssembly does not support threads, so it actually does not compile the thread-related classes. Just pass `-nomake examples` to configure to prevent from building thread-related examples.

Lorn Potter Lorn Potter says:

You can either configure with -nomake examples, or apply this patch
https://codereview.qt-project.org/#/c/246149/

Vladislav Navrocky says:

Hello, I am getting such error while building Qt with ~/Qt/5.12.0/Src/configure -xplatform wasm-emscripten && make

https://pastebin.com/5ifyS6FU

What I doing wrong?

Cajus Pollmeier says:

I had this error, too. Looks to me like the description is incomplete. Here’s a transcript of what I did to make it compile. Hope it helps:

https://gist.github.com/cajus/689eca85be257997019065979799e2f6

Vladislav Navrocky says:

I solved this error with additional configuring options:

-nomake examples -skip qtwebengine

And Qt was built successfully, but now on stage of building my app i get such error:

vlad@vladwork:~/prog/loan-calculator/web-build> ~/tmp/qt-wasm/qtbase/bin/qmake ..
Info: creating stash file /home/vlad/prog/loan-calculator/web-build/.qmake.stash
Project ERROR: Unknown module(s) in QT: qml quick

In qt-wasm/config.summary I see that QML and QUICK modules enabled:

Qt QML:
QML network support ……………….. yes
QML debugging and profiling support …. yes
QML sequence object ……………….. yes
QML list model ……………………. yes
QML XML http request ………………. yes
QML Locale ……………………….. yes
QML delegate model ………………… yes
Qt Quick:
Direct3D 12 ………………………. no
AnimatedImage item ………………… yes
Canvas item ………………………. yes
Support for Qt Quick Designer ………. yes
Flipable item …………………….. yes
GridView item …………………….. yes
ListView item …………………….. yes
TableView item ……………………. yes
Path support ……………………… yes
PathView item …………………….. yes
Positioner items ………………….. yes
Repeater item …………………….. yes
ShaderEffect item …………………. yes
Sprite item ………………………. yes

Shantanu Tushar says:

Same here –

“`
$ ~/dev/wasm/qtbase/bin/qmake
Project ERROR: Unknown module(s) in QT: quick
“`

Morten Johan Sørvig Morten Johan Sørvig says:

Hi, could you try running “make module-qtdeclarative”? That should make sure Qt Quick is built.

Shantanu Tushar says:

Hi,

I tried that in a fresh build, still no luck, see https://pastebin.com/raw/EVNgBYen

(I have removed parts of the output that are compiler invocations)

Morten Johan Sørvig Morten Johan Sørvig says:

Looks like the trick here is to either run “make install” (as the configure output suggests), or configure with “-prefix $PWD/qtbase”. I’ve updated the instructions to suggest the latter.

Georgy Shepelev says:

Hi!

I was able to build qt for WA with the following parameters:
../qt-everywhere-src-5.12.0-beta4/configure -xplatform wasm-emscripten -nomake examples -no-compile-examples -skip qt3d -skip qtcanvas3d -skip qtcharts -skip qtconnectivity -skip qtdatavis3d -skip qtwayland -skip qtwebchannel -skip qtwebengine -skip qtwebview -skip qttools -qtlibinfix Emscripten -static -no-feature-thread -no-dbus -no-ssl |& tee log-configure.txt

If qttools is not skipped then error “could not determine clang version at /path/to/emsdk/clang” arise.

Mike Inman says:

Is there support for modules such as QProcess? In other words, can the WebAssembly app use QProcess to launch system commands?

Morten Johan Sørvig Morten Johan Sørvig says:

This won’t be supported. If it was possible, then any webpage could run any command on your system, which would be less than ideal 🙂

Within a web page, each Qt app is a WebAssembly Instance, which has some similarities to a process. So maybe QProcess could gain support for managing WebAssembly instances.

Lorn Potter Lorn Potter says:

Webassembly lives in the same sandbox that javascript lives in, so there is no access to the local filesystem.

Tham says:

But I can access local file by the live version, do it use some non Qt api to make it work?If so, could you tell me which parts of the source codes I should check? Thanks

Morten Johan Sørvig Morten Johan Sørvig says:

Yes, please take a look at https://codereview.qt-project.org/#/c/228599, which provides a Qt API for loading and saving files.

Morten Johan Sørvig Morten Johan Sørvig says:

Hi, thanks everyone for being patient while we get our build instructions sorted out.

We’ll make sure that plain “make” will work. In the mean time it’s probably best to limit which modules are built, either by checking out a subset like Cajus suggests above, or by building a subset using “make module-foo”. I’ve updated the instructions to give an example of this usage.

Vladislav Navrocky says:

It will be great to quick start if you make a docker image with prebuilt Qt and Emscripten. At this moment building of Qt is a hard challenge.

Morten Johan Sørvig Morten Johan Sørvig says:

That’s a good idea. We aim to provide binaries via the Qt installer for the 5.13 release.

benstrap says:

Works already really fine.

QtQuick 2 application are working perfectly, “configure” reports:
Qt Quick:
Path support ……………………… yes
PathView item …………………….. yes

However I’ve not been able to import module “QtQuick.Shapes” from QML (console error message: “”QtQuick.Shapes is not installed”), do you actually have had some successful tests with this module (with WebGL backend?) ?

Did you

Fabio says:

Hi!

I am very excited to try Qt for Webassembly.

Is there any plan to have it to work in windows without the linux subsystem (basically “natively”)?

Since Qt Webassembly is GPL as far as I understood, does that means that we have to pay for the commercial license if we put ads in the page where the application runs? Also do we have to pay for the commercial license if we something like a “premium” section (or feature) of the application that users need to pay to access?

Thanks and keep the great work!

Tham says:

I think we could reference to Wt, it use the same license as the Qt WA plugin.

Their words

If you wish to use the library using the GNU General Public License (GPL) , you may build a web application with Wt and deploy it, but per the terms of the GPL, you are obliged to make the source code available to anyone you give the application to install on their own server. This also applies to redistribution of the Wt library, in original or modified form.

This is the link–https://www.webtoolkit.eu/wt/download or google by “Wt commerical use”

Tham says:

I think we could reference to the license of Wt(a c++ website development library, gpl too). Their website–https://www.webtoolkit.eu/wt/download

Their comments :

If you wish to use the library using the GNU General Public License (GPL) , you may build a web application with Wt and deploy it, but per the terms of the GPL, you are obliged to make the source code available to anyone you give the application to install on their own server. This also applies to redistribution of the Wt library, in original or modified form.

My opinion :

We are safe to use Qt5 to develop our commercial websites by GPL license, unless your customers ask you to give them the app to install on their own server,
else it is safe for you or your company to keep the source codes close.

Fabio says:

Thanks. I guess we could also implement the “premium” sections part server logic in a non GPL server software, so we could distribute just the source for the interface for the “premium” sections not the actual server logic.

Something like Qt Webassembly for the interface and asp.net core or just standard C++ for the server logic.

Fabio says:

It would be nice if a license for individuals could also be released. Which would be way cheaper than the companies license.

m][sko says:

How can I compile qt with threads? as chrome allow threads in webassembly now.

Are there any change to add debugging support?

Morten Johan Sørvig Morten Johan Sørvig says:

Threads are not supported right now but in the works for Qt 5.13.

I’ve briefly looked at the new wasm debugging support in Chrome (version 71?). It looks like we should get source maps support going for Qt so that Qt and application sources can be viewed in the debugger.

Albert says:

Is there any chance to get an example mixing ssl + web assembly?

Morten Johan Sørvig Morten Johan Sørvig says:

I don’t think we have any wasm-spesific examples. In general the best way to approach this is to let the browser handle SSL, for example by using secure websockets.

Lars says:

I tried it with the “Application Example” and the “Editable Tree Model Example”. FireFox Nightly displays “TypeError: currentScript is null; can’t access its “src” property”, Chrome “TypeError: Cannot read property ‘src’ of null”

Morten Johan Sørvig Morten Johan Sørvig says:

This is strange: it is expected that document.currentScript will be null due to how qtloader.js loads the app.js file, but all usages should be guarded by a null object check.

So the questions are: what does the javascript code that accesses currentScript look like, and which version of Emscripten are you using? You may upload the entire example build output (perhaps without the wasm file) to a QTBUG if you want to.

Lars says:

I made a fresh install of emscripten, downloaded Qt 5.12 RC and compiled it. Now the “Application Example” is running.

Andrew says:

You need to do something with event handling loop in Qt for WebAssembly because the cpu core usage rises to 100% when I simply move mouse across Slate app window. It’ll make Qt uncompetitive in web world.

Tham says:

>because the cpu core usage rises to 100% when I simply move mouse across Slate app window.

Not as bad as you, but I noticed my cpu usage raise a lot when I try to draw something, from less than 10% raise to over 40%.

Although, current version is almost useable(waiting for thread support of WA and performance fix of Qt), unless it could save lots of development times.

Morten Johan Sørvig Morten Johan Sørvig says:

Note that Slate is actually doing work in this case: updating the coordinate display in the lower left corner. This causes a full WebGL canvas flush at 60 fps. So I’m inclined to let the event loop implementation off the hook and hook and blame WebGL canvas overhead.

But this does not help you if you’re seeing 100% CPU usage. Are you able to run other WebGL examples, like for example the aquarium demo at https://webglsamples.org/aquarium/aquarium.html ?

Sai says:

slate example is using qbs , run qmake in this project show “Cannot read /home/sai/code/git/slate: file to open is a directory”

how to build this slate?

Morten Johan Sørvig Morten Johan Sørvig says:

Use the the version at https://github.com/msorvig/slate, branch wasmhackery 🙂

Bob says:

I tried out the QmlOscilloscope example. It compiles fine but when loading the example I just get a gray screen with the debug output:

mount persistent directory as IDBFS qtloader.js:342:17
Warning: qrc:/qml/qmloscilloscope/main.qml:30:1: module “QtQuick” is not installed (qrc:/qml/qmloscilloscope/main.qml:30, (null))
qtloader.js line 409 > eval:1:266934
Warning: QWasmWindow 0x134a4f0: 0x3afcb4 0x1
((null):0, (null))
qtloader.js line 409 > eval:1:266934
end persisted to mem file sync..

Am I missing something in the linking-stage? The linking against “libQt5Quick.so.5.11.1.wasm” seems to work. I’ve built Qt with the modules: module-qtbase module-qtdeclarative module-qtquickcontrols2 module-qtwebsockets module-qtmqtt module-qtsvg module-qtcharts. Do I also need module-qtquick1 and module-qtquickcontrols1?

Bob says:

My fault! Needed to build the modules statically by executing the configure-script with the additional parameter “-static” (why the wiki is not specific about that?). Now the “QtQuick” module can be found, however, there is still something wrong with my qtcharts-module. When I run any of the qtcharts examples the only thing that is displayed is a small blue rectangle (see the link):

https://imgur.com/a/hAutR3D

Bob says:

Building the Qt 5.12.0-rc sources from the installer as described above (no need for the “-static” configure-parameter) and using emscripten version 1.38.16 does the trick:

git clone https://github.com/juj/emsdk.git
cd emsdk
./emsdk install sdk-1.38.1-64bit
./emsdk activate –global sdk-1.38.1-64bit
source ./emsdk_env.sh

Morten Johan Sørvig Morten Johan Sørvig says:

Are you sure you are up to date with your 5.12(.0) branch? There was a recent change to the configure system to make it default to static for wasm builds.

cemal demir says:

I think you should full tutorial for compilation or installation for Qt WebAssembly module.

Commenting closed.

Get started today with Qt Download now