Setting up LLVM/clang, emscripten, and emscripten-qt

Updated 7 years ago

Introduction

From llvm.org, "the LLVM Project is a collection of modular and reusable compiler and toolchain technologies." It is used for the optimization of programs written in arbitrary programming languages. Clang is a C/C++ front-end for LLVM. Emscripten uses these technologies to convert C++ code into Javascript. Emscripten-qt adds support for Qt in Emscripten.

This guide will go through the process of setting up these tools, designed for a Linux environment, although many of the links have instructions for other operating systems as well.

Versions

Versions of software used:

  • Linux:
    • linuxmint-13-xfce-64
  • llvm:
    • LLVM (http://llvm.org/):
      LLVM version 3.2svn
      Optimized build with assertions.
      Built Apr 15 2013 (11:06:21).
      Default target: x86_64-unknown-linux-gnu
      Host CPU: corei7
  • CLANG:
    • clang version 3.2 (tags/RELEASE_32/final)
      Target: x86_64-unknown-linux-gnu
      Thread model: posix
  • emcc (emscripten):
    • emcc (Emscripten GCC-like replacement) 1.4.9 (commit 0ad87244178badf26cd5c8e0ed88116e87026472)
  • node:
    • v0.10.0
  • qmake (emscripten-qt) :
    • QMake version 2.01a
      Using Qt version 4.8.4

LLVM and Clang

To get LLVM set-up, simply follow the steps provided on LLVM: Getting Started. Be sure that you meet all of the requirements listed on the requirements section, and then follow the steps outlined on getting started a summary.

After llvm/clang are finished compiling, add the directory where the binaries are to your path. Should be something like "/home/user/somewhereInHome/llvm/Release+Asserts/bin" then try these examples to make sure everything is working:
(the parts in [] are notes, don't type them)

clang --help
clang file.c -fsyntax-only             [check for correctness]
clang file.c -S -emit-llvm -o -        [print out unoptimized llvm code]
clang file.c -S -emit-llvm -o - -O3
clang file.c -S -O3 -o -               [output native machine code]

if everything ran successfully, then clang and LLVM are configured correctly and you can move on to the next step.

Emscripten and Emscripten-qt

For emscripten and emscripten-qt, just follow the instructions on the emscripten-qt wiki the section "how do I use it." The instructions are fairly detailed, and I will summarize them here:

Create a directory (probably somewhere in your home directory) for emscripten and emscripten-qt. For the sake of this guide, that directory will be referred to as "/home/user/emscriptenqt/", make sure to replace all instances of that directory with what your's actually is.
Enter the following commands, replacing /home/user/emscriptenqt

mkdir build-emscripten-qt
cd build-emscripten-qt
export EMSCRIPTEN_ROOT_PATH=/home/user/emscriptenqt/emscripten/
../emscripten-qt/configure -xplatform qws/emscripten-clang  -embedded emscripten -static -opensource -debug  -no-qt3support -no-opengl -no-openssl   -system-zlib -no-gif -qt-zlib -qt-libpng -no-libmng -no-libtiff -qt-libjpeg -no-accessibility -dbus -script -no-fpu -no-mmx -no-3dnow -no-sse -no-sse2 -no-sse3 -no-ssse3 -no-sse4.1 -no-sse4.2 -no-icu -no-rpath  -confirm-license -no-webkit -no-phonon -no-freetype -nomake demos -nomake examples -little-endian -no-feature-socket  -no-feature-codecs -no-feature-textcodecplugin -no-feature-systemlocale  -no-feature-qws_multiprocess -no-feature-sound    -no-feature-printpreviewwidget  -no-feature-printpreviewdialog  -no-feature-systemsemaphore -no-feature-sharedmemory -no-feature-localeventloop -feature-qws_clientblit -feature-qws_cursor  -depths 32 -make tools  --prefix=$(pwd)/install
make sub-tools-bootstrap && make install_qmake sub-moc-install_subtargets sub-uic-install_subtargets sub-rcc-install_subtargets && make  sub-corelib-install_subtargets sub-gui-install_subtargets install_mkspecs

Now you should have emscripten and emscripten-qt. You may wish to add /home/user/emscriptenqt/emscripten to your PATH, but it is not necessary. Next, we will run an example Qt app to make sure that everything is working correctly.

cd ..
mkdir qtdemos
cd qtdemos
export PATH=/home/user/emscriptenqt/build-emscripten-qt/install/bin/:$PATH
export QMAKESPEC=/home/user/emscriptenqt/build-emscripten-qt/install/mkspecs/qws/emscripten-clang
cp -R ../emscripten-qt/demos/chip .
cd chip
patch main.cpp < ../../emscripten-qt/emscripten-stuff/chip-emscripten-qt-patch.patch 
cd ..
mkdir build
cd build
qmake ../chip/chip.pro
make
mkdir -p qt-fonts && cp ../../build-emscripten-qt/install/lib/fonts/helvetica_*.qpf ../../build-emscripten-qt/install/lib/fonts/fixed_*.qpf qt-fonts/
cp ../../build-emscripten-qt/install/lib/QtGui.a QtGui.so
cp ../../build-emscripten-qt/install/lib/QtCore.a QtCore.so
../../emscripten/emcc \
  chip.bc \
  QtGui.so QtCore.so \
  -O2 \
  --closure 0 \
  --jcache \
  --pre-js ../../emscripten-qt/emscripten-stuff/pre-qt.js \
  --js-library ../../emscripten-qt/emscripten-stuff/pre-qt-library.js \
  --embed-file qt-fonts \
  -s EXPORTED_FUNCTIONS="['_main', '_EMSCRIPTENQT_resetTimerCallback', '_EMSCRIPTENQT_timerCallback', '_EMSCRIPTENQT_timerCallback_springboard', '_EMSCRIPTEN_canvas_width_pixels', '_EMSCRIPTEN_canvas_height_pixels', '_EMSCRIPTENQT_mouseCanvasPosChanged', '_EMSCRIPTENQT_mouseCanvasButtonChanged']" \
  -s TOTAL_MEMORY=67108864 \
  -s INLINING_LIMIT=50 \
  -o chip.html 

The emscripten-qt wiki goes into more detail about what all of the parameters and commands mean.

If all completes as it should, you should now have a chip.html file in that directory. Open it with a supported browser, and the chip's demo page will load. If so, then emscripten-qt is working as it should, and you're finished!

NOTE: you might notice that the generated canvas isn't large enough to display all of the chip's demo. Apparently emscripten-qt does not yet support dynamically resizing of the canvas, and the canvas must be set manually to the correct size. On about line 23 of the generated html file, you should find:

<canvas class="emscripten" id="canvas" oncontextmenu="event.preventDefault()"></canvas>

change it to something like:

<canvas width="800px" height="600px" class="emscripten" id="canvas" oncontextmenu="event.preventDefault()"></canvas>