Thursday, August 15, 2019

QMqtt & QWebAssembly

Qt for WebAssembly is an exciting new platform for Qt. It means that Qt applications can run in a web browser. This means that deploying a Qt application is as easy as copying the files to your properly configured web server and handing out the url, for your users to run in their web browser.

Mqtt is a machine to machine communication protocol, which is used for messaging in IoT. Websocket is a two way communication protocol between a web browser and a web server.

QtMqtt has been ported to run on the WebAssembly platform, using QtWebSockets as it's transport. There is a catch to getting it working, however. That catch is that you need to use the WebSocketIODevice class that is in the QtMqtt websocketsubscription example app. WebSocketIODevice depends on the QtWebSocket module.

You need to copy websocketiodevice.h and websocketiodevice.cpp into your project, using the WebSocketIODevice as QMqttClient's transport.

In a nutshell, at a minimum,  code such as this:

QMqttClient m_client
WebSocketIODevice m_device;
m_device.setUrl(m_url);
connect(&m_device, &WebSocketIODevice::socketConnected, this, [this]() {
    m_client.setTransport(&m_device, QMqttClient::IODevice);
}

Then you can use the QMqttClient as normal.

You can read more about Qt for WebAssembly, QtMqtt and QtWebSockets in the book Hands-On Mobile and Embedded Development with Qt 5

Tuesday, July 2, 2019

[Update] Faster link time for Qt WebAssembly

The guys working on Emscripten have begun integrating the new llvm wasm backend into mainstream emscripten. Although it is still not the default, it is now heaps easier to install and use, as you no longer need to build llvm yourself.

https://v8.dev/blog/emscripten-llvm-wasm

The jist of it is:

emsdk install latest-upstream
emsdk activate latest-upstream

According to the linked blog, there are code size benefits as well as link time speed-ups.

The faster link time mostly affects application builds.

Of course, you will need to recompile Qt for WebAssembly to use this, and need to configure it with the Qt WebAssembly specific option:

-device-option WASM_OBJECT_FILES=1

After that, you just need to run qmake as normal.

One note: You will need to remove the line
 -s \"BINARYEN_TRAP_MODE=\'clamp\'\"

from the mkspecs/wasm-emscripten/qmake.conf, as upstream llvm webassembly backend does it's own overflow clamping and does not support BINARYEN_TRAP_MODE argument.

Friday, June 7, 2019

Faster link time for Qt WebAssembly

I have built Qt and various apps using emscripten so many times over the last couple of years, it isn't even funny.

One detractor with building Qt applications for the web using Qt for WebAssembly, is the time it takes to build the client application. Especially during linking, it takes a huge amount of time to produce a binary for Qt WebAssembly.
This is caused by all the magic that the linker in emscripten is doing.

Luckily, llvm can now produce wasm binaries directly so emscripten does not have to go through any additional steps to output wasm. Emscripten and Qt can utilize this feature to reduce the length of time it takes to link and emit a .wasm binary.

YAY! \0/

I did some very non scientific measurements on build time. Using my development machine with make -j8:

Qt (not including configure)textedit
default configure Qt for WebAssemblyuser 20m3.706suser 2m46.678s
using -device-option WASM_OBJECT_FILES=1user 23m30.230suser 0m29.435s

The result is that building Qt takes a tad longer, but building the client application is significantly faster. Which means development iterations will be much faster. In this instance, I used the textedit example in Qt. The build time went from 2 minutes and 46 seconds for a default non object files build, to 29 seconds! Zip! Zoom! Zang! Dang! that's fast (for wasm)

Unfortunately, this is not currently done by default by either Qt, emscripten or llvm. There is a way to do this which involves building llvm from upstream and telling emscripten to use that.

For the emscripten and binaryen version, I tested the current 1.38.32

From this bug report https://bugreports.qt.io/browse/QTBUG-72537
Morten has fleshed out a method for doing this.

------------------------------------------------------------

Getting started:

(Note: this is "how-I-did-it", not necessarily "how-it-should-be-done".)
1. Clone the following repositories:

2. Check out the version you want to use 
  • emscripten and binaryen have matching emsdk version tags, for example "1.38.23".
  • llvm has its own version numbers, and must be synced up manually. Currently:
    • emscripten <= 1.38.23 : llvm 8.0 (8.0.0-rc2 branch)
    • emscripten > 1.38.23 : llvm 9.0 (master branch)
      (em++/emcc will complain if you have the incorrect llvm version)

3. Build
  • emscripten is all python, no build needed.
  • binaryen: "cmake -GNinja && ninja"
  • llvm:
    cmake -GNinja
    ../path/to/llvmcheckout
    -DLLVM_ENABLE_PROJECTS="clang;libcxx;libcxxabi;lld"
    -DCMAKE_BUILD_TYPE=Release
    -DLLVM_TARGETS_TO_BUILD=WebAssembly
    -DLLVM_EXPERIMENTAL_TARGETS_TO_BUILD=WebAssembly
    
    (one of the WebAssembly targets may be redundant)

4. Configure Environment
I use the following:
export EMSDK="/Users/msorvig/dev/emsdks/emscripten-1.38.23"
export PATH="$EMSDK:$PATH"
export LLVM="/Users/msorvig/dev/emsdks/llvm-8.0.0-build/bin"
export BINARYEN="/Users/msorvig/dev/emsdks/binaryen-1.38.23"
export EM_CONFIG="/Users/msorvig/dev/emsdks/.emscripten-vanillallvm-1.38.23"
export EM_CACHE="/Users/msorvig/dev/emsdks/.emscripten-vanillallvm-cache-1.38.23"
Where .emscripten-vanillallvm-1.38.23 is a copy of the .emscripten config file that emsdk generates.

------------------------------------------------------------

You will need to adjust the various paths to your system, of course. 
Then to configure and build Qt, add -device-option WASM_OBJECT_FILES=1 to the normal Qt for WebAssembly configure line.

The one I normally use is:

configure -xplatform wasm-emscripten -developer-build -nomake tests -nomake examples -opensource -confirm-license -verbose -compile-examples -no-warnings-are-errors -release  -device-option WASM_OBJECT_FILES=1


Works like a charm for the Qt 5.13 and the 5.13.0 branches of the Qt source code repo. I tried this with the 5.13.0 beta4 WebAssembly binaries, but got:

wasm-ld: warning: function signature mismatch:
so a complete rebuild is required.

There is a chapter regarding Qt for WebAssembly in the book, Hands-On Mobile and Embedded Development with Qt 5


Wednesday, May 22, 2019

exec on Qt WebAssembly

When porting applications to Qt for WebAssembly, there are a few issues to keep in mind.

One big issue is that you do not have a full operating system underneath for you to utilize.
What you get is the same sandbox in which javascript lives. In some aspects, it is somewhat similar to a single-threaded microcontroller where there is just one thread in which to operate, limited filesystem access and limited resources.

One of the unusual and tricky bits about using Qt for WebAssembly, is that the exec loop is not typical. The Emscripten main loop is co-operative, after each event has a turn to run, control is then returned to the browser. Any blocking of the event loop will mean the web page in which your application runs will become unresponsive.

This is all fine and dandy for simple applications that use one main loop, but gets complicated when you try to exec a secondary loop. To stop the execution of an event loop, emscripten throws an exception, which leads to all kinds of fun. It also means it never returns to the same place that you expect it. So any modal dialog that uses exec() will not return values. Less than ideal.

Take for instance QColorDialog. Typical use is as such:


    QColorDialog dlg(parent);
    dlg.exec();
    QColor color = dlg.selectedColor();






Which is basically what QColorDialog::getColor does.

... and does not work with Qt WebAssembly, because exec() does not return to the same place as you expect! The call to selectedColor will never get called.

What you can do is use a non-modal dialog with the show() or in the case of QColorDialog open() function and use Qt's signal/slot API to retrieve the selected QColor.

 QColorDialog *dlg = new QColorDialog(this);

    connect(
        dlg, &QColorDialog::colorSelected,
        [=](const QColor &selectedColor) {
        qDebug() << Q_FUNC_INFO << selectedColor;
    });
    dlg->open();

You can read more about the Emscripten execution environment at
https://emscripten.org/docs/api_reference/emscripten.h.html#browser-execution-environment

You can also learn more about Qt for WebAssembly and other things in the book I wrote:
Hands on Mobile and Embedded Development with Qt 5

Friday, May 3, 2019

Mobile and Embedded Development with Qt

At times it was a bit painful juggling writing a book, doing my day job and running around doing the things that life throws. It's done and dusted now, you too can buy my book titled Hands-On Mobile and Embedded Development with Qt 5! It has a nice image of glacier ice on the cover, which I thought was appropriate for a technology founded in Norway and then continued in Finland.



https://www.packtpub.com/application-development/hands-mobile-and-embedded-development-qt-5

A big thanks to the co-founder of Trolltech, Eirik Chambe-Eng, who was gracious enough to write the forward at the last second. Tons of thanks to all the editors who also worked on this book.

One of the things I learned writing this book is that Qt is big. I already knew that, but now it's plainly apparent just how big it has grown. Not only are there major companies developing products with Qt, but it has a lot of different functionality and is not just about desktop widgets. There are a huge number of classes to cover.

You can check out the table of contents if you want to see what is covered and included. One area that I did not include is OpenGL ES. This is a huge topic and easily a book on it's own. It's something I would like to know more about, which is why I did not feel qualified to cover it. You need to know OpenGL Shader Language (GLSL), and I did not have the time to discover that to any real depth.

I hope that I covered topics that are relevant for mobile, embedded and IoT developers. From QtWidgets, QtQuick, QtSensors (of course) to In-app purchasing and building an embedded system with Qt Company's Boot To Qt and Yocto. I also explore Qt's newest platform - Qt for WebAssembly, which allows you to serve Qt applications from a web server to run in a web browser.


Enjoy!

Wednesday, November 22, 2017

Qt for WebAssembly update

The project Qt 5 emscripten that Intopalo (who are doing tons of amazing stuff with some awesome talent) started as research for a client, has moved git repos. The new main git repo has been moved to a branch in Qt proper! and a new name - Qt for WebAssembly.

git://code.qt.io/qt/qtbase.git in the 'wip/webassembly' branch, and can be downloaded here:
git clone -b wip/webassembly git://code.qt.io/qt/qtbase.git

which is also here at github:
https://github.com/qt/qtbase/tree/wip/webassembly

Along with the move comes expanded requirements, like targeting non QtWidgets based apps, including QtDeclarative.

As well, it now builds only for wasm and does not bother with the asmjs fallback, This means your web browser will need to specifically support wasm. Pure wasm builds in emscripten have performance optimizations that do not happen when also building the asmjs fallback.

That said....

*NOTE* Qt for WebAssembly is still very alpha and buggy! Some of which I will cover in the next blog post.

I have managed to conjole Qt Creator to use the emscripten built Qt for apps. Here are the steps to do so, if you are so inclined.

Build Qt for web assembly.

1) Download and build emsdk (you may also try to pre built binary version)

git the emsdk source repo:
git clone https://github.com/juj/emsdk.git
(to update: git pull; ./emsdk update-tags )

Follow these instructions to build emsdk:
http://kripken.github.io/emscripten-site/docs/getting_started/downloads.html#installation-instructions

I usually use 'incoming' instead of 'latest', as it has more recent features.

/path/to/emsdk install sdk-master-64bit binaryen-master-64bit

2) Download Qt for emsdk

git clone -b wip/webassembly https://code.qt.io/qt/qtbase.git

3) Build Qt

source /path/to/emsdk/emsdk_env.sh

$QT_DIR/configure -xplatform emscripten -confirm-license -opensource -nomake tests -nomake examples -developer-build -no-dbus -no-headersclean -release -no-thread  -no-feature-networkinterface

(non developer builds should work too)

4) Add emscripten compiler to Creator

  • Tools->Options->Build & Run -> Compilers->Add->Custom
  • add emcc as C, and emc++ as C++
  • 'emscripten' as Qt mkspecs.
  • ABI: x86, linux (or whatever platform you build on), unknown, elf, 64bit

5) Add emscripten built Qt

  • Tools->Options->Build & Run ->Qt Versions->Add
    • add the qmake from your emscripten Qt build.
6) Add emscripten kit

  • Tools->Options->Build & Run ->Kits->Add
    • add emcc and emc++ as Compilers
    • If you use cmake, you can also add to CMake configuration:
      • CMAKE_TOOLCHAIN_FILE=/path/to/emsdk/emscripten/incoming/cmake/Modules/Platform/Emscripten.cmake
7) Build your app
  • Use 'release' mode build, as 'debug' will result in a runtime error: "failed to asynchronously prepare wasm: CompileError: wasm validation error: at offset 14762: too many functions"
8) Run your app

  • add custom executable: Projects->(qt5-wasm) Run
    • specify /path/to/emsdk/emscripten/incoming/emrun
      • arguments: .html
        • I also use --browser firefox (I use nightly)
Hopefully some things will actually work! This is all still in the development phase. Your kilometerage will vary. 

Good luck! You can join the fun, we are in #qt-webassembly at https://qtmob.slack.com and on freenode.


Monday, June 5, 2017

Qt for web (assembly)

So ya, I have been doing work for the up and coming Finnish company Intopalo getting Qt5 for WebAssembly using emscripten up and running. This is the 3rd Finnish company I have done work for, and the 4th Nordic company (Trolltech, Nokia, Jolla, Intopalo)

This is very much a work in progress.

Background:

There was a Qt4 version, emscripten-qt and a related Qt5 for Native Client which do similar things, and we have taken inspiration from both these projects. Thanks!

The gist of it:

We use emscripten to cross compile Qt5 into javascript and/or webassembly. We use 'incoming' from emscripten's git repo. Details how to build emsdk are here.

My working Qt5 repo is here, (the wm branch contains multi window and window decorations) while there is also an outdated WIP gerrit MR  which will get updated at some point.

This is how I configure Qt for emscripten:
 . ~/emsdk/emsdk_env.sh (to get em compiler in path)

~/depot/qt/qt5/qtbase/configure -xplatform emscripten -confirm-license -opensource -nomake tests  -nomake examples -developer-build -no-dbus -no-thread

 (no-thread is a new feature I added for this, as threading in javascript is basically non existent)

and then, use that qmake to compile a Qt app!

To run the app, in the firefox browser
emrun --browser firefox path/to/app.html

This is all bleeding edge from the emscripten compiler to the web assembly support in the browser, so your mileage may vary.

With the 'wm' branch of my github repo, multi windows and window decorations are kind of working. As well as compiling into webassembly and not just javascript asmjs.
Compiling into wasm brings much smaller download sizes, but you need to have a browser that supports it.

There is still heaps of work to do to bring it up to release state. So for now, it is still a research and WIP project, and a lot of things may or may not work. But it can run some Qt widget based apps in your (firefox) browser!

The future:

Currently there is no support for qml/qt quick. That just means we haven't tried it as our focus is currently on widgets and opengl.

Personally, I would like to see location and some sensor events, but that is for the future.