Raspberry Pi Logo

Building Qt 5 on Raspberry Pi

By ICS Development Team

This is a HOW TO guide for building Qt 5 for the Raspberry Pi, and building and deploying Qt 5 apps using Qt Creator. This guide will be using Raspbian "Wheezy", a Debian based distro designed for the Raspberry Pi. This guide also assumes the use of Linux or UNIX on the workstation side.

Note: Throughout this guide the symbol "$" denotes a command prompt on the host workstation, and "pi$" denotes a command prompt on the target Raspberry Pi.

Getting started

Downloads

You will need the following downloads:

Please note the user and login for the Linux image. Currently this is user "pi" and password "raspberry", but this could change in the future.

Learn more about Programming with Qt for Embedded Devices with ICS Training

Install a Toolchain

To build on the Raspberry Pi we need a cross-compile toolchain. The toolchain will contain compilers, linkers and other tools that run on the host workstation but create executables for the target Raspberry Pi.

For embedded development, one normally uses a vendor-supplied toolchain, but in the case of the Raspberry Pi, there is no official vendor supplied toolchain. There are several generic ARM toolchains that will suffice, however, we have chosen to use the same one the bakeqtpi script uses. This is a Linaro based toolchain for the ARMv6 platform with hard floating-point support. Alternatively, we could have built our own toolchain.

We will create a working directory to use named "raspberry". Our first step is to get and install a cross compiling toolchain.

$ mkdir ~/raspberry
$ cd ~/raspberry
$ wget http://swap.tsmt.eu/gcc-4.7-linaro-rpi-gnueabihf.tbz
$ tar xfj gcc-4.7-linaro-rpi-gnueabihf.tbz

Since this toolchain is built for 32-bit systems, you will need a set of 32-bit libraries installed if you are on a 64-bit system. On Ubuntu systems, this can be accomplished by installing the ia32-libs package. Unfortunately, this is a deprecated transitional package, with no replacement.

$ sudo apt-get install ia32-libs

Development Script

As a convenience, you can create a setdevenv.sh script in ~/raspberry that can be sourced to set up necessary environment variables.

#!/bin/sh
WORKINGDIRECTORY=$HOME/raspberry
TOOLCHAIN=gcc-4.7-linaro-rpi-gnueabihf
MOUNTPOINT=/mnt/raspberry-rootfs
export PATH=$PATH:$WORKINGDIRECTORY/$TOOLCHAIN/bin

Prepare the Image

Burn and Boot

Before we can do anything, we need to be able to boot up the Raspberry Pi to a working Raspbian "Wheezy" Linux. We do this by burning a Raspbian image to an SD Card.

  • Extract and rename the image previously downloaded. We rename it to keep track of the image we are working on.
    $ unzip 2013-02-09-wheezy-raspbian.zip
      ...
    $ mv 2013-02-09-wheezy-raspbian.img raspberry-working-image.img
    
  • Determine what device the SD card reader is. There are various ways to do this, but I prefer looking at the last few lines of dmesg output after inserting the card. In the following case, the device is sdb. Make sure you know the correct device to use with the subsequent dd command, or you could lose all your data.

    Repeat: Make sure you know the correct device to use with the subsequent dd command, or you could lose all your data.

    $ dmesg
    ...
    [ 2838.088974] sd 7:0:0:0: [sdb] No Caching mode page present
    [ 2838.088981] sd 7:0:0:0: [sdb] Assuming drive cache: write through
    [ 2838.088986] sd 7:0:0:0: [sdb] Attached SCSI removable disk
    
  • Burn the image. It is advisable to use a smaller card rather than a larger card for this purpose. The minimum size is 2Gig however. Correct for any path and device differences in the following command.
    $ sudo dd bs=4M if=raspberry-working-image.img of=/dev/sdb
    462+1 records in
    462+1 records out
    1939865600 bytes (1.9 GB) copied, 404.52 s, 4.8 MB/s
    
  • Remove the SD card and insert it into the Raspberry Pi. Boot the Raspberry Pi. Verify that it boots correctly to the Raspi-config screen.
  • Turn on ssh while you are in this screen, as well as any other options you might desire (keyboard layout, timezone, etc).
  • Exit the Raspi-config screen to a command prompt. Run ifconfig to determine the Raspberry's network address.
    pi$ ifconfig
    eth0 Link encap:Ethernet HWaddr xx:xx:xx:xx:xx:xx  
         inet addr:10.0.0.3 Bcast:10.0.0.255  Mask:255.255.255.0
    ...
    
  • Back on your workstation, ssh into the Raspberry Pi.
    $ ssh pi@10.0.0.3
    pi@10.0.0.3's password:raspberry
    pi$
    

Install Packages

Additional packages will be needed on the Raspberry Pi in order to build Qt 5 and run Qt 5 applications.

The first step is to update and upgrade the existing packages.

pi$ sudo apt-get update
pi$ sudo apt-get upgrade

Here is a list of the basic packages needed for building and running Qt 5. These are Ubuntu package names, but there should be similar packages on all Linux distros.

  • libfontconfig1-dev
  • libdbus-1-dev
  • libfreetype6-dev
  • libudev-dev
pi$ sudo apt-get install libfontconfig1-dev ...
Setting up libfontconfig1-dev (2.9.0-7.1) ...
...

If you plan on building QWebKit, you'll need the following additional packages.

  • libicu-dev
  • libsqlite3-dev
  • libxslt1-dev
  • libssl-dev

For multimedia you will need the following optional packages.

  • libasound2-dev
  • libavcodec-dev
  • libavformat-dev
  • libswscale-dev
  • libgstreamer0.10-dev
  • libgstreamer-plugins-base0.10-dev
  • gstreamer-tools
  • gstreamer0.10-plugins-good
  • gstreamer0.10-plugins-bad

Back to the Workstation

Building software on the Raspberry Pi will be too slow, thus we will need to return to our workstation and use our cross-compile toolchain to perform the remainder of the work.

A traditional method of cross-platform development is to create a chroot or jail environment to build against. However, since we have a working image of the Raspberry Pi, we can use that instead and it will be much easier. There are also minor fixes we need to make to the image.

  • First, cleanly shutdown the Raspberry Pi.
    pi$ sudo shutdown -h now
    
  • Insert the SD card in the host workstation and copy the card contents back to our working image file. Note that this will create an image the size of the SD card, so make sure you have enough room. Correct for any path and device differences in the following command.
    $ sudo dd if=/dev/sdb of=raspberry-working-image.img
    7761920+0 records in
    7761920+0 records out
    3974103040 bytes (4.0 GB) copied, 253.641 s, 15.7 MB/s
    
  • You will need the offset for the Linux image to mount it. If it's not otherwise provided with the download, you can determine it using losetup. There are 512 bytes per sector, so in the example below the offset is 122880 * 512 = 62914560.
    $ sudo /sbin/losetup /dev/loop0 raspberry-working-image.img
    $ sudo /sbin/fdisk -l /dev/loop0
    ...
          Device Boot      Start         End      Blocks   Id  System
    /dev/loop0p1            8192      122879       57344    c  W95 FAT32 
    /dev/loop0p2         122880     3788799     1832960   83  Linux
    ...
    $ sudo /sbin/losetup -d /dev/loop0
    
  • Now create a mount point and mount the image:
    $ sudo mkdir /mnt/raspberry-rootfs
    $ sudo mount -o loop,offset=62914560 \
      raspberry-working-image.img /mnt/raspberry-rootfs
    $ ls /mnt/raspberry-rootfs
    bin   dev  home  lost+found  mnt  proc  run   selinux  sys  usr
    boot  etc  lib   media       opt  root  sbin  srv      tmp  var
    
    For convenience our setdevenv.sh script sets a mountpoint variable for us, so we can use $MOUNTPOINT instead of the full path.
  • Clone the cross-compile-tools repo. This contains some useful scripts, including the important fixQualifiedLibraryPaths script.
    $ git clone git://gitorious.org/cross-compile-tools/cross-compile-tools.git
    $ cd cross-compile-tools
    
  • Apply the fixQualifiedLibraryPaths script. This fixes the symlinks in the mounted image to be relative instead of absolute. The command is: fixQualifiedLibraryPaths target-rootfs path-to-target-toolchain-compiler
    $ sudo ./fixQualifiedLibraryPaths $MOUNTPOINT \
      ~/raspberry/gcc-4.7-linaro-rpi-gnueabihf/bin/arm-linux-gnueabihf-gcc
    
  • Finally we need to make some miscellaneous fixes.
    $ sudo ln -s \
      $MOUNTPOINT/opt/vc/include/interface/vmcs_host/linux/vchost_config.h \
      $MOUNTPOINT/opt/vc/include/interface/vmcs_host/vchost_config.h
    

Building Qt 5

Building Qt 5 will now proceed normally in much the same way as building Qt 5 for the desktop. There are a few minor differences however, such as applying a few patches and providing the appropriate configure options.

Patching Qt 5

  • Untar the Qt5 distribution into a build directory.
    $ tar xvfz qt-everywhere-opensource-src-5.0.2.tar.gz
    ....
    
  • Qt 5 needs to have some patches applied. Unfortunately, it can be hard to know what patches are needed for what version. There is no authoritative repository of good patches for the Raspberry Pi. What works here might not work with the next incremental release of Qt. I am taking these patches from the bakeqtpi repo. YMMV.
    $ git clone git://gitorious.org/bakeqtpi/bakeqtpi.git
    Cloning into 'bakeqtpi'...
    $ cd bakeqtpi
    $ cp 0001-Adjusts-to-build-qtbase-with-support-to-openvg.patch \
      ../qt-everywhere-opensource-src-5.0.2/qtbase
    $ cp 0001-V8-Add-support-for-using-armv6-vfp2-instructions.patch \
      ../qt-everywhere-opensource-src-5.0.2/qtjsbackend
    $ cd ../qt-everywhere-opensource-src-5.0.2/qtbase
    $ patch -p1 < 0001-Adjusts-to-build-qtbase-with-support-to-openvg.patch
    $ cd ../qtjsbackend
    $ patch -p1 < 0001-V8-Add-support-for-using-armv6-vfp2-instructions.patch
    

Building Qt 5 Base

  • Configure Qt 5. Several options are necessary for the Raspberry Pi. The -sysroot option is very important as it tells the build to use the libraries in our mounted image.
    $ cd qt-everywhere-opensource-src-5.0.2/qtbase
    $ ./configure \
      -release \
      -opengl es2 \
      -optimized-qmake \
      -no-pch \
      -make libs \
      -make tools \
      -reduce-relocations \
      -reduce-exports \
      -sysroot /mnt/raspberry-rootfs \
      -device linux-rasp-pi-g++ \
      -device-option CROSS_COMPILE=~/raspberry/gcc-4.7-linaro-rpi-gnueabihf/bin/arm-linux-gnueabihf- \
      -prefix /usr/local/Qt-5.0.2-raspberry
    
  • Double check the configure output to make sure everything looks fine. Then build and install Qt Base. The install target will install to both the host workstation and the mounted image, although it installs different components to each. We manually copy over the mkspecs because the cross-compile build will not do this for us.
    $ make
    $ sudo make install
    $ sudo cp -r /usr/local/Qt-5.0.2-raspberry/mkspecs \
      $MOUNTPOINT/usr/local/Qt-5.0.2-raspberry
    

Qt 5 base will now be installed to /usr/local/Qt-5.0.2-raspberry on both the workstation and the mounted image.

Building Qt 5 Modules

Repeat the following steps for each additional Qt module you wish to use: qtimageformats, qtjsbackend, qtsvg, qtxmlpatterns, qtdeclarative, qtgraphicaleffects, qtmultimedia, qtscript, qtwebkit. Note, the order of each build is important, as some modules are dependent on others.

For each module:

$ cd qt-everywhere-opensource-src-5.0.2/<module>
$ /usr/local/Qt-5.0.2-raspberry/bin/qmake
$ make
$ sudo make install

Alternatively, for a short mini-script to build and install them all:

$ cd qt-everywhere-opensource-src-5.0.2
$ for module in qtimageformats qtjsbackend qtsvg qtxmlpatterns qtdeclarative \
  qtgraphicaleffects qtmultimedia qtquick1 qtscript qtwebkit; do
> cd ../$module
> /usr/local/Qt-5.0.2-raspberry/bin/qmake
> make
> sudo make install
> done

Burn the New Image

Now that Qt has been successfully built and installed, we need to burn this image back to an SD card to use on the Raspberry Pi.

$ sync
$ sudo umount /mnt/raspberry-rootfs
$ sudo dd bs=4M if=raspberry-working-image.img of=/dev/sdb
947+1 records in
947+1 records out
3974103040 bytes (4.0 GB) copied, 672.988 s, 5.9 MB/s

Quick Sanity Check

Let's make sure everything is working. Insert the SD card in the Raspberry Pi and boot it up.

$ ssh pi@10.0.0.3
pi@10.0.0.3's password:

Then write a quick hello world.

pi$ cat > test.qml
import QtQuick 2.0
Rectangle {
  color: "lightgray"
  Text {
    text: "Hello world!"
    anchors.centerIn: parent
  }
}
^D
pi$ /usr/local/Qt-5.0.2-raspberry/bin/qmlscene test.qml

Setting Up Qt Creator

You do not need a special build of Qt Creator to build for the Raspberry Pi. Qt Creator uses Kits to select build configurations.

  • Make sure your development environment is set, and the raspberry working image is mounted.
  • Start Qt Creator.
  • Bring up the options dialog using Tools -> Options....
  • Select the Devices page on the left.
    • Click Add... and add an entry for the Raspberry Pi.
    • Select Generic Linux Device and click Start Wizard.
    • Enter Raspberry Pi for the name of the device.
    • Enter the IP address for the Raspberry Pi.
    • Enter "pi" for the username.
    • Enter "raspberry" for the password.
  • Select the Build & Run page on the left.
  • Select the Compilers tab.
    • Using the Add button, add a GCC compiler.
    • Name the compiler "Raspberry Pi Toolchain".
    • Set the path to the toolchain, ~/raspberry/gcc-4.7-linaro-rpi-gnueabihf/bin/arm-linux-gnueabihf-g++
  • Select the Qt Versions tab.
    • Using Add... add a new Qt version.
    • Select the path to the appropriate qmake: "/usr/local/Qt-5.0.2-raspberry/bin/qmake".
  • Select the Kits tab.
    • Click Add button to add a kit for the Raspberry Pi.
    • Enter "Qt 5.0 Raspberry Pi" for name.
    • Select Generic Linux Device and Raspberry Pi for device type and device.
    • Enter "/mnt/raspberry-rootfs" for the sysroot
    • Select Raspberry Pi Toolchain for the compiler.
    • Browse to ~/raspberry/gcc-4.7-linaro-rpi-gnueabihf/bin/arm-linux-gnueabihf-gdb for the debugger.
    • Select Qt-5.0.2-raspberry for the Qt Version.
  • Click OK to finalize the configuration.

Typical Development Workflow

Here's a typical development workflow using Qt Creator to build for the Raspberry Pi.

  • Mount the working image. The toolchain needs this for the libraries.
    $ sudo mount -o loop,offset=62914560 \
      raspberry-working-image.img /mnt/raspberry-rootfs
    
  • Start Qt Creator
  • Start a new project
    • File -> New File or Project...
    • Select Qt Console Application
    • Name the project. I chose "raspberrytest"
    • Check Qt 5.0 Raspberry Pi as a project type and uncheck all other types.
  • Develop a Qt application as you normally would. In my case, I used the following files (borrowed from a Raspberry Qt example).
    • main.cpp
      #include <QGuiApplication>
      #include <QtQml>
      #include <QQuickView>
      
      int main(int argc, char *argv[])
      {
              QGuiApplication a(argc, argv);
      
              QQuickView v;
              v.setResizeMode(QQuickView::SizeRootObjectToView);
              v.setSource(QUrl("qrc:///main.qml"));
              v.showFullScreen();
      
              return a.exec();
      }
      
    • main.qml
      import QtQuick 2.0
      
      Rectangle
      {
          color: "green"
      }
      
    • main.qrc
      <RCC>
          <qresource prefix="/">
              <file>main.qml</file>
          </qresource>
      </RCC>
      
  • Set up raspberrytest.pro to correctly deploy.
    • Change the QT variable to be "core gui qml quick"
    • Add an install target
      target.path = /home/pi
      INSTALLS += target
      
  • Build the application by selecting Build -> Build All (or click on the hammer icon)
  • Deploy and run on the Raspberry Pi by selecting Debug -> Start Debugging (or click the debug icon)
  • Stop the app by selecting Debug -> Stop Debugger (or click on red stop icon in debugging bar)
  • For final deployment, select Build -> Deploy All

Unmount!

Don't forget to unmount the working image when you are through with it!

References

Learn more about Programming with Qt for Embedded Devices with ICS Training