Setting up LLVM/clang, emscripten, and emscripten-qt
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
- LLVM (http://llvm.org/):
- CLANG:
- clang version 3.2 (tags/RELEASE_32/final)
Target: x86_64-unknown-linux-gnu
Thread model: posix
- clang version 3.2 (tags/RELEASE_32/final)
- 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
- QMake version 2.01a
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>