Qt for Native Client (and emscripten)

Qt for Native client has been in development for a while, and I'm pleased to announce that the project again has reached working status: running Qt applications (Qt Widgets and Qt Quick) sandboxed in the Chrome browser. In this post I'll talk about the background of native code on the web and how to get started with Qt.

Qt for Native Client is available as an unsupported tech preview. Get the source code form code.qt.io:


git clone https://code.qt.io/qt/qtbase.git .
git checkout wip/nacl

The above "git clone" will give you qtbase only - If you are interested in using Qt Quick then you probably want a complete Qt checkout with the wip/nacl branch for QtBase.

See the presentation at the the Qt World Summit
Qt for Native Client will be presented at the Qt World Summit. Register today!

A brief history of Native Code on the Web

Native Client (NaCl) is a sandbox for native x86 code, first published back in 2009, and later extended to support x86_64 and ARM. Portable Native Client (PNaCl) is built on top of NaCl and defines an intermediate architecture-independent format for distribution. PNaCl binaries are translated to NaCl binaries on first load by the browser. Chrome runs PNaCl binaries from the Web, NaCl binaries from the Chrome App store or if enabled in browser settings. Other browser vendors have showed little interest in this line of technology.

Emscripten compiles native code to JavaScript which can run on all browsers. Later versions of Emscripten improves performance (on cooperating browsers) by using the ASM JS subset of JavaScript.

WebAssembly is a joint effort between some of the larger browser vendors, which target “is to promote early-stage cross-browser collaboration on a new, portable, size- and load-time-efficient format suitable for compilation to the web.” Compatibility for non-WebAssembly browsers is provided in the form of a WebAssembly loader implemented in JavaScript.

The Native Client SDK

The Native Client SDK is versioned along with Chrome and follows the same 6-week release cycle. The SDK contains an update script which fetches new versions and updates ‘canary'.


$ ls nacl_sdk/
	pepper_40
	pepper_41
	pepper_canary

'pepper_NN/toolchain' then contains PNaCl and NaCl toolchains. The “mac” in the names is the host, produced binaries are OS independent. The Qt tech preview currently supports the 'pnacl' and 'newlib' toolchains, using static builds.


$ ls nacl_sdk/pepper_41/toolchain
	mac_arm_newlib
	mac_pnacl
	mac_x86_glibc
	mac_x86_newlib

Finally we find the compiler binaries and conclude we are dealing with a cross-compiler:


$ ./nacl_sdk/pepper_41/toolchain/mac_pnacl/bin/i686-nacl-clang++ hello.cpp -o hello.nexe
$ file hello.nexe
hello.nexe: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked, not stripped
$ ./hello
-bash: ./hello.nexe: cannot execute binary file

Emscripten

Emscripten is typically distributed by your platforms package manager. On OS X:


	brew install emscripten

This gives you the ‘em++’ compiler and friends - there are no versions or toolchain variants. em++ can produce “executable” .js files:


$em++ hello.cpp -o hello.js
node hello.js
“Hello World”

API and Platform

Programs that want to do something more interesting than printing to standard out need an API to interface against. In Qt, this is the domain of the QPA platform plugin. Native Client provides PPAPI (’Pepper’) which provides a C and C++ API for the features covered by the HTML (5) specification. For example, Pepper gives access to mouse and keyboard events, and provides 2D or 3D graphics contexts.

Emscripten also has a similar API. Qt could have used it but instead uses pepper.js, which is a re-implementation of the Pepper API on top of Html, which allows us to re-use the exiting pepper platform plugin. (It could be said that adding this level of indirection is in the spirit of compiling C++ to JavaScript). Emscripten support is still very expermental: QtCore and QtGui runs with raster graphics, the OpenGL, QtWidgets and QtQuick modules are largely untested.

Setting up Qt

The workflow is similar to using Qt for any other platform:
1. Configure and build Qt.
2. Build the application.
3. Deploy. (nacldeployqt)

The following is a simplified overview, complete getting started instructions are available at qtbase/README.md.

1. Use the provided configure script, select a NaCl toolchain or emscripten (We treat emscripten as a nacl variant.)


./nacl-configure mac_pnacl release

Build Qt:


make qtmodule-qtbase (or qtmodule-qtdeclarative)

2. Build the application


/path/to/qmake && make

3. Run nacldeployqt


/path/to/nacldeployqt application.nexe

This creates supporting files for the application: a html file, the qtloader.js script, manifest files.

In addition, nacldeployqt provides some convenience:


   -—run: Start Chrome, run the application
   -—debug: Start Chrome and nacl-gdb, run the applicatjon with attached debugger

Finally it runs:
nacl-controls-gallery

Questions? Interested in contributing to the development of Qt for Native Client? Contact us here or on #qt-labs on irc (freenode).


Blog Topics:

Comments