Introduction
What is Wt ?
In their introduction on the Wt main page they write:
“…Wt (pronounced as witty) is a C++ library for developing web applications…”
The idea of writing web apps in C++ sounds a bit weird at first, but I found Wt the ideal solution for me and the following project:
I wanted to use a Raspberry Pi as a mini server which periodically logs into a Fritzbox, reads out the phone caller list and displays this on a small LCD
Wt being the main service behind and an easy way to configure this and be able to query more detailed information.
Paths
Of course you can use any path for the work directory. And I could have used a $VAR_XX
to specify the path. But – I used plain absolute paths in this documentation. I used /home/user
as the work directory where I used subdirs like linaro
, wt
and so on.
So please replace this with your actual home or work path. I was very careful that the setup did not write outside this directory. You do not need to be root if you have enough rights inside this directory.
License
Wt is dual licensed, more information can be found on the download page
It can be either used under GPL or a commercial license (with fair pricing).
Build yourself, or ready-made ?
Sure, everything pre-built is nice. But see we-do-it-all-for-you scripts for potential problems.
In this post, I describe everything how I did it from scratch. If you are satiesfied with an “old-if-you-read-this version”, you can skip some parts of the description.
I tell you which.
Install Qt creator and other tools
We assume Ubuntu 14.04 here as the host environment. There is no strict requirement for Qt creator, but see below.
sudo apt-get install g++ sudo apt-get install qtcreator sudo apt-get install cmake
If you want to build everything youself, you can continue here. You can also download most of the needed stuff prebuilt from my site. In this case, go straight to “Build Template application (make)”
Downloading and building Wt
On the download page one can find different versions. I downloaded the tarball version 3.3.3
♦ Unpack:
tar xzf wt-3.3.3.tar.gz
The challenge for me was to cross compile this for the Raspberry Pi. On my post Cross compiling under Raspbian with Linaro toolchain I wrote about setting up a cross compile toolchain for the Raspberry Pi.
We assume here:
- Target device is Raspberry Pi with Raspbian (2014-06-20-wheezy-raspbian)
- Host environment is Ubuntu 14.04
- We install everything under the home dir of user user (
/home/user
) - Cross compiler is installed and usable (
/home/user/linaro/bin/arm-linux-gnueabihf-gcc
)
Download boost
Boost is the universal C++ library and is used by Wt.
♦ Go to Sourecforge download page and download boost_1_55_0.tar.gz
Note: This is no longer the newest version. I assume newer versions will also do it, but I have not tested it.
♦ Unpack:
tar xzf boost_1_55_0.tar.gz
Download Qt
Qt should be well-known as the cross platform UI “and more” library.
Even if Wt is (from the programming model) a bit similar to Qt, it does not depend on it. One purpose of downloading and building Qt is to be able to use Qt creator as the IDE for the further development of Raspi apps.
Why build Qt from source, and not just use the Qt package from Ubuntu ?
Yes, this was my first idea. I thought I would be able to use Qt creator only as the IDE. But qmake needs a Qt installation built for the target platform to work properly. I searched the web a lot for this and even tried many suggestions. In the end I found out that the way described here will be the one to go. In addition, Qt can be used together with Qt, and I thought it would be of good value to be able to use some of the Qt non-GUI libs for my development.
♦ Go to Qt download page and download qt-everywhere-opensource-src-5.2.1.tar.gz
♦ Unpack:
tar xzf qt-everywhere-opensource-src-5.2.1.tar.gz
Download TinyMCE
♦ Go to TinyMCE download page and download TinyMCE 3.5.11
♦ Unpack:
unzip tinymce_3.5.11.zip
Download zlib
♦ Go to zlib page and download zlib source code, version 1.2.8, tar.gz format
♦ Unpack:
tar xzf zlib-1.2.8.tar.gz
Download bzip2
♦ Go to bzip download page and download 1.0.6 source tarball.
♦ Unpack:
tar xzf bzip2-1.0.6.tar.gz
Build zlib for ARM / Raspbian
cd zlib-1.2.8 mkdir build_rpi cd build_rpi cmake -D CMAKE_C_COMPILER=/home/user/linaro/bin/arm-linux-gnueabihf-gcc -D CMAKE_INSTALL_PREFIX=/home/user/zlib_rpi .. make make install
Build boost for ARM / Raspbian
cd boost_1_55_0 ./bootstrap.sh --prefix=/home/user/boost_rpi --without-libraries=python
♦ Edit project-config.jam
, add two lines at the end:
using gcc : arm : /home/user/linaro/bin/arm-linux-gnueabihf-g++ ; using zlib : 1.2.8 : /home/user/zlib_rpi/include /home/user/zlib_rpi/lib ;
./b2 install toolset=gcc-arm -s BZIP2_SOURCE=/home/user/bzip2-1.0.6
Build Wt for ARM / Raspbian
cd wt-3.3.3 mkdir build_rpi cd build_rpi cmake -D CMAKE_C_COMPILER=/home/user/linaro/bin/arm-linux-gnueabihf-gcc -D CMAKE_CXX_COMPILER=/home/user/linaro/bin/arm-linux-gnueabihf-g++ -D BOOST_ROOT:PATHNAME=/home/user/boost_rpi -D ZLIB_PREFIX=/home/user/zlib_rpi -D ZLIB_INCLUDE=/home/user/zlib_rpi/include -D CMAKE_LIBRARY_PATH=/home/user/linaro/arm-linux-gnueabihf/libc/usr/lib/arm-linux-gnueabihf -D WT_CPP_11_MODE=-std=c++0x -D CMAKE_INSTALL_PREFIX=/home/user/wt_rpi -D CONFIGDIR=/home/user/wt_rpi/etc -D RUNDIR=/home/user/wt_rpi/run -D WEBUSER=user -D WEBGROUP=user .. make make install
Build Qt for ARM / Raspbian
cd qt-everywhere-opensource-src-5.2.1 ./configure -v -extprefix /home/user/qt_rpi -opensource -confirm-license -no-pkg-config -qt-zlib -qt-libjpeg -qt-freetype -qt-pcre -no-cups -no-glib -no-pch -no-nis -nomake examples -nomake tests -no-gui -no-widgets -device linux-rasp-pi-g++ -device-option CROSS_COMPILE=/home/user/linaro/bin/arm-linux-gnueabihf- -skip qtlocation make make install
Create runtime environment for Raspbery Pi
Here we create a runtime environment for the execution of wt applications
on the Raspberry Pi
mkdir /home/user/Template_run mkdir /home/user/Template_run/lib cd /home/user/Template_run/lib cp /home/user/boost_rpi/lib/libboost_*.so.1.55.0 . cp -P /home/user/boost_rpi/lib/libboost_*.so . cp -P /home/user/wt_rpi/lib/libwtdbo*.so* . cp -P /home/user/wt_rpi/lib/libwt.so* . cp -P /home/user/wt_rpi/lib/libwthttp.so* . cp /home/user/qt_rpi/lib/libQt5Concurrent.so.5 . cp /home/user/qt_rpi/lib/libQt5Core.so.5 . cp /home/user/qt_rpi/lib/libQt5Network.so.5 . cp /home/user/qt_rpi/lib/libQt5Script.so.5 . cp /home/user/qt_rpi/lib/libQt5Xml.so.5 . /home/user/linaro/bin/arm-linux-gnueabihf-strip -s lib*.so.3.3.3 /home/user/linaro/bin/arm-linux-gnueabihf-strip -s lib*.so.1.55.0 cd /home/user/Template_run cp -R /home/user/wt_rpi/share/Wt/resources . cp -R /home/user/tinymce/jscripts/tiny_mce resources
We should have this directory structure now:
Template_run/ lib/ libboost_* libQt* libwt* resources/ ajax-loading.gif ... font-awesome/ jPlayer/ themes/ tiny_mce/ tiny_mce.js ... ...
♦ Pack the runtime (in /home/user/Template_run
):
tar czf ../runtime_rpi.tar.gz *
Pack all created packages
For archiving purposes, we pack the created files:
tar czf boost_rpi.tar.gz boost_rpi tar czf wt_rpi.tar.gz wt_rpi tar czf qt_rpi.tar.gz qt_rpi tar czf zlib_rpi.tar.gz zlib_rpi
This can be helpful if we rebuild our whole system and don’t want to create
everything from scratch.
Build Template application (make)
Ok, you are here either from the step by step instructions and you built everything yourself, or you just want to dowload the pre-built libraries.
In the former case, go straight to “Download this sample:”
In the latter case, download these files:
MD5: 1fb6bfb00b5e0c169302536e8f969917
SHA-1: 3ca61e13b7ae5ded8b649108a72f59bd93d84179
MD5: 5160d40552fbf77b8fb2e20ea7281dd1
SHA-1: db5a26d5d24f1e494aac623d54b29082491f3674
MD5: be32fce064f6b5689e0fafccc26ceb5a
SHA-1: da9566db409c40330ecb0fc9fd1ba2b5f8b64a22
MD5: b913c9efeeac4d85b6a3e22222f82003
SHA-1: 144d51ee122d03bddb3d5ebbdb15a2ccf79ef8f6
MD5: 1db8d928de8e99a4f4cbab82d8126466
SHA-1: 8ab7f17375f8478c28590d8ddbb5da36fb22b230
Unpack all files (in the work directory we assume /home/user
here):
tar xzf xxxxxx.tar.gz
Build template app
Now, everything is on the right place. Now we can build our first sample web application.
Download this sample:
MD5: 016318e9823fb84b8838ac80ea48bb17
SHA-1: a687cbb9daecc2ccabeb856af57a28f33188b49c
Unpack:
tar xzf Template.tar.gz
♦ Edit Makefile to match your paths. Ok, I could have used some better way of writing this Makefile and didn’t use hardcoded absolute paths … but it is how it is.
make
Everything should build. You end with an ARM executable named “Template”
Install runtime on the Raspbery Pi
♦ Copy the previously built runtime to the raspi.
scp runtime_rpi.tar.gz root@name-or-ip-of-raspi:/tmp
♦ Login (as root in our example) into the raspi
cd /opt mkdir wt cd wt mkdir Template cd Template
tar xzf /tmp/runtime_rpi.tar.gz
(this tar extraction creates the two dirs (lib and resources) directly in the current directory !)
♦ Copy the previously built Template executable to the raspi.
scp Template root@name-or-ip-of-raspi:/opt/wt/Template
♦ Start the Template on the raspi (in /opt/wt/Template):
./Template --docroot . --http-address 0.0.0.0
♦ Start a web browser and navigate to the name / ip of the raspi
Using Qt Creator
♦ Tools → Options → Devices
♦ Add…
♦ Generic Linux Device → Start Wizard
The name to identify this configuration: Raspi
The device’s host name or IP address: name-or-ip-of-raspi
The user name to log into the device: root
The authentication type: Password
The user’password: root-password
♦ Next → Finish
♦ Apply
♦ Tools → Options → Build & Run → Compilers
♦ Add → GCC
Name: GCC_RPI
Compiler path: /home/user/linaro/bin/arm-linux-gnueabihf-g++
♦ Apply
♦ Tools → Options → Build & Run → Qt Versions
♦ Add…
open /home/user/qt_rpi/bin/qmake
♦ Tools → Options → Build & Run → Kits
♦ Add
Name: RPI
Device type: Generic Linux Device
Device: Raspi
Compiler: GCC_RPI
Debugger: None
Qt version: Qt 5.21 (qt_rpi)
I have created a custom project template.
Download it from here:
MD5: 39142ffaa733717f209f107cd664ca41
SHA-1: ad0c992e29c80257419b7c5e7d5b7e3238db8275
In home directory:
tar xzf custom_wizard.tar.gz
This will extract these files:
/home/user/.config/QtProject/qtcreator/templates/wizards/rpiwt/ main.cpp main.h project.pro rpi.png wizard.xml /home/user/.config/QtProject/qtcreator/templates/wizards/rpiwtqt/ main.cpp main.h project.pro rpi.png wizard.xml QtObjectSend.cpp QtObjectSend.h QtObjectReceive.cpp QtObjectReceive.h DispatchThread.cpp DispatchThread.h WQApplication.cpp WQApplication.h
♦ Now, in Qt Creator:
♦ New Project → Custom Projects → RaspiWt → Choose…
Name: -enter name for sample project-
In the “Kit Selection”:
♦ uncheck Desktop
♦ check RPI
♦ Next
♦ The checkbox “Add optional boost libs” adds some additional boost libaries not needed for Wt itself, but which may be used by your program
♦ In “lib + include path for boost and Wt” enter the path under which boost_rpi und wt_rpi are located
♦ In “run path on Raspberry Pi” enter the path where the wt runtime project will be located
♦ Next → Finish
♦ Projects → RPI → Run
♦ Under Run → Arguments enter:
--docroot /opt/wt/ --http-address 0.0.0.0
♦ Replace the path for docroot with your path on the Raspi where the executable will be deployed.
♦ Make sure that “lib
” and “resources
” subdirectories are located under this directory
♦ Build
♦ Press the green right arrow.
→
The built executable will be copied (with scp) to the Raspberry and the web application will be started directly on the Raspi.
In the “Application Output” pane the output will be displayed.
This should look similar to:
stdin: is not a tty [2014-Jun-01 13:08:28.588074] 2374 - [info] "WServer/wthttp: initializing built-in wthttpd" [2014-Jun-01 13:08:28.598015] 2374 - [info] "wthttp: started server: http://0.0.0.0:80"
♦ To stop the running application, press the red square button under the “Application Output” pane
Further information
Cross compiler toolchain
See my post Cross compiling under Raspbian with Linaro toolchain.
boost
This was rather easy. We have to set the installation directory with
--prefix=/home/user/boost_rpi
and name the cross compiler to use.
Wt
This needs some further explanations:
-D CMAKE_LIBRARY_PATH=/home/user/linaro/arm-linux-gnueabihf/libc/usr/lib/arm-linux-gnueabihf
If this is omitted, we get some linker errors complaining about missing references:
[ 94%] Built target wtdbosqlite3 Linking CXX executable test.sqlite3 ../src/Wt/Dbo/backend/libwtdbosqlite3.so.3.3.2: undefined reference to `dlopen' ../src/Wt/Dbo/backend/libwtdbosqlite3.so.3.3.2: undefined reference to `dlclose' ../src/Wt/Dbo/backend/libwtdbosqlite3.so.3.3.2: undefined reference to `dlerror' ../src/Wt/Dbo/backend/libwtdbosqlite3.so.3.3.2: undefined reference to `dlsym'
The cause is in src/Wt/Dbo/backend/CMakeLists.txt
:
IF(NOT WIN32) FIND_LIBRARY(DL_LIB NAMES dl ) IF(DL_LIB) TARGET_LINK_LIBRARIES(wtdbosqlite3 ${DL_LIB}) ENDIF(DL_LIB) ENDIF(NOT WIN32)
The problem is here that FIND_LIBRARY
does not find our ARM libaries. So we help with giving the complete path. Luckily, setting CMAKE_LIBRARY_PATH
to this special subdirectory does not have any side effects.
-D CONFIGDIR=/home/user/wt_rpi/etc
Path for configuration files (default is /etc/wt/
)
During build, the wt directory will be created. To prevent this, we set the path relative to our home directory.
-D RUNDIR=/home/user/wt_rpi/run
Default path for wt session management (only used by FCGI connector; not relative to CMAKE_INSTALL_PREFIX). Similar to CONFIGDIR
-D WEBUSER=user -D WEBGROUP=user ..
During build, the run dir will be chown-ed to apache:apache
if not explicitly set. So we just set our own user / group here.
Qt
Qt Creator is very good in cross building. We could use cmake, but using QMake has some advantages. We need a qmake command which is a i386 executable, but especially prepared for the target architecture.
In my tests, Qt creator 2.5 (e.g. from Debian 7) did not work. I had to use 3.x