Building Qt for Embedded Linux

From Qt Wiki
Jump to: navigation, search
This article is for Qt 4 only. For Qt 5, see Qt documentation on embedded linux

Introduction

To get a reasonable Qt for Embedded Linux development environment setup it is necessary to build Qt twice:

  1. For the host system (your own workstation) where the development will be done. We will refer to this as the host build.
  2. For the target system (the embedded board) where we will deploy the applications. We will refer to this as the target build.

The host system configuration is not so very different from a standard Qt/X11 installation and uses your normal tool chain so we will describe this configuration first.

The target build configuration however is a little different. We must build in on the host machine but in such a way that the applications generated with it are able to execute on the embedded platform being targeted. This requires us to use our cross-compiling toolchain so a little more effort is required here - although not much so don't worry. :-)

Pre-requisites

Before we begin please make sure that you have a working cross-compiling toolchain. This will either be supplied with your device's SDK or you can build your own.

If you are using a commercial license then please also ensure that a valid license file is located at $HOME/.qt-license

The Host Build

Configuring the Host Build

Firstly you need the latest and greatest version of the Qt source, so go and download the Qt-everywhere package from the Nokia website (or from your customer portal if you are a commercial customer). Once you have the tarball, extract it somewhere convenient for your normal user e.g. $HOME/development/qt-4.7.2, say. Change into the Qt source directory and configure Qt for an embedded host build with something along the lines of:

./configure -prefix /usr/local/qt-embedded-4.7.2
      -embedded -qt-gfx-linuxfb -qt-gfx-qvfb
      -qt-gfx-vnc -no-largefile-exceptions -no-accessibility \
      -no-qt3support -qt-zlib -no-gif -no-libtiff \
      -qt-libpng -no-libmng -qt-libjpeg \
      -openssl -no-nis -no-cups -depths 8,16,18,32 \  
      -qt-kbd-tty -qt-kbd-qvfb -qt-kbd-linuxinput \
      -qt-mouse-linuxinput -qt-mouse-qvfb -qt-mouse-pc \  
      -commercial -confirm-license -silent

The above configure line tells Qt to configure itself for an embedded build using your normal system tool chain. However, some of these options warrant further explanation.

  • -prefix <path>- The host build of Qt-Embedded will be installed under this prefix. Please make sure that this is something different than your system Qt install prefix so that we do not clobber anything from that!
  • -embedded- Enable support for the embedded options. This includes the QWS window system into the build and enables so other embedded related options.
  • -qt-gfx-linuxfb- Enable the linux framebuffer driver so that the app can be tested full screen on the host (outside of X11)
  • -qt-gfx-qvfb- Enable support for testing applications in the qvfb (virtual framebuffer application which is part of Qt/X11)
  • -qt-gfx-vnc- Enabled support for exporting application display over VNC
  • -depths 8,16,18,32- Include support for these colour depths. These are just some common options. Please refer to your board's documentation to see what it actually supports. Setting the same option here will allow you to see an accurate representation of your app even when running it on the host machine.
  • -qt-kdb-tty- Enable support for the tty keyboard driver
  • -qt-kbd-qvfb- Enable keyboard support with qvfb
  • -qt-kbd-linuxinput- Enable a keyboard linux input in the QtGui library.
  • -qt-mouse-linuxinput- Enable a mouse linux input in the QtGui library.
  • -qt-mouse-qvfb- Enable mouse support with qvfb
  • -confirm-license- Lazy option to save agreeing to license agreement during configure process (you can go drink tea instead)

The other options should be fairly self-explanatory, but see ./configure —help for more detail. You can of course specify additional options to configure or remove some of the ones listed in the above example depending upon your requirements.

The configure process can take a few minutes as it must first compile the qmake application and some other supporting utilities.

The build itself

This bit is simple. Just issue the command make -j<no of parallel jobs>. The argument to give to the -j flag is down to personal choice. A good general guide is to use the number of available CPU cores + 1. So on a single core machine you might use:

make -j2

or on a quad-core machine:

make -j5

If you wish to leave some CPU cores free for other taks whilst building then reduce the number.

Depending upon the speed and load of your machine the build can take of the order of a few tens of minutes on a modern PC. This is a good time to get yourself a cup of tea and a biscuit or do something else

Once the build has completed it is time to install Qt. You may need to su to root to do this part depending upon what prefix you configured the build with above. As the appropriate user do:

make install

Congratulations you should now have a working Qt for Embedded Linux host build. We'll see how to use it shortly, but first we need to build a version of Qt for our target device.

The Target Build

Cleaning the Previous Build

We already have a Qt build directory from the above Host System steps. We can re-use this for our target build. We just need to remove the previous configuration. As your normal user once more, cd into the Qt build directory and issue:

make confclean

This will remove all build files and the previous configuration.

Preparing a mkspec

Before we can redo the configuration for the target system, we will need a new set of mkspecs that tells qmake which tool chain it should reference when it creates the makefiles. The contents of the mkspecs files will vary depending upon the architecture and other details of your target device. Qt ships with some example mkspecs that you can either use directly or as inspiration for your own. Take a look in the mkspecs/qws directory under your Qt source directory. If you are able to use one of these then great make a note of its name. If not then we need to roll our own custom mkspec.

If you need to make your own custom mkspec file then make a copy of the closest match from the existing mkspecs form the mkspec/qws sub-directory and name it something appropriate. In this example we will create a mkspec to go along with the cross-compiling toolchain that we made earlier.

The mkspec consists of 2 files:

  1. qmake.conf- This is a list of qmake variable assignments that tells qmake what flags to pass through to the compiler, which compiler to use etc.
  2. qplatformdefs.h - This is a header file with various platform-specific #includes and #defines. Often this just refers to an existing qplatformdefs.h file from another generic mkspec.

For our example we are using our 486-based toolchain. A typical qmake.conf file for this may looki like this:

#
# qmake configuration for linux-g++ modified to use 486 compliant compiler
#

MAKEFILE_GENERATOR = UNIX
TEMPLATE = app
CONFIG ''= qt warn_on release link_prl
QT''= core gui network
QMAKE_INCREMENTAL_STYLE = sublib

QMAKE_CC = i486-pc-linux-gnu-gcc
QMAKE_LEX = flex
QMAKE_LEXFLAGS =
QMAKE_YACC = yacc
QMAKE_YACCFLAGS = -d
QMAKE_CFLAGS = -pipe
QMAKE_CFLAGS_WARN_ON = -Wall -W
QMAKE_CFLAGS_WARN_OFF =
QMAKE_CFLAGS_RELEASE = -O2
QMAKE_CFLAGS_DEBUG = -g
QMAKE_CFLAGS_SHLIB = -fPIC
QMAKE_CFLAGS_YACC = -Wno-unused -Wno-parentheses
QMAKE_CFLAGS_THREAD = -D_REENTRANT
QMAKE_CFLAGS_HIDESYMS = -fvisibility=hidden

QMAKE_CXX = i486-pc-linux-gnu-g++
QMAKE_CXXFLAGS = $$QMAKE_CFLAGS
QMAKE_CXXFLAGS_WARN_ON = $$QMAKE_CFLAGS_WARN_ON
QMAKE_CXXFLAGS_WARN_OFF = $$QMAKE_CFLAGS_WARN_OFF
QMAKE_CXXFLAGS_RELEASE = $$QMAKE_CFLAGS_RELEASE
QMAKE_CXXFLAGS_DEBUG = $$QMAKE_CFLAGS_DEBUG
QMAKE_CXXFLAGS_SHLIB = $$QMAKE_CFLAGS_SHLIB
QMAKE_CXXFLAGS_YACC = $$QMAKE_CFLAGS_YACC
QMAKE_CXXFLAGS_THREAD = $$QMAKE_CFLAGS_THREAD
QMAKE_CXXFLAGS_HIDESYMS = $$QMAKE_CFLAGS_HIDESYMS -fvisibility-inlines-hidden

QMAKE_INCDIR = /usr/i486-pc-linux-gnu/usr/include
QMAKE_LIBDIR = /usr/i486-pc-linux-gnu/usr/lib
QMAKE_INCDIR_X11 =
QMAKE_LIBDIR_X11 =
QMAKE_INCDIR_QT = $$[QT_INSTALL_HEADERS]
QMAKE_LIBDIR_QT = $$[QT_INSTALL_LIBS]
QMAKE_INCDIR_OPENGL =
QMAKE_LIBDIR_OPENGL =
QMAKE_INCDIR_QTOPIA = $(QPEDIR)/include
QMAKE_LIBDIR_QTOPIA = $(QPEDIR)/lib

QMAKE_LINK = i486-pc-linux-gnu-g++
QMAKE_LINK_SHLIB = i486-pc-linux-gnu-g++
QMAKE_LFLAGS =
QMAKE_LFLAGS_RELEASE =
QMAKE_LFLAGS_DEBUG =
QMAKE_LFLAGS_SHLIB = -shared
QMAKE_LFLAGS_PLUGIN = $$QMAKE_LFLAGS_SHLIB
QMAKE_LFLAGS_SONAME = -Wl,-soname,
QMAKE_LFLAGS_THREAD =
QMAKE_RPATH = -Wl,-rpath,

QMAKE_LIBS =
QMAKE_LIBS_DYNLOAD = -ldl
QMAKE_LIBS_X11 =
QMAKE_LIBS_X11SM =
QMAKE_LIBS_QT = -lqte
QMAKE_LIBS_QT_THREAD = -lqte-mt
QMAKE_LIBS_QT_OPENGL = -lqgl
QMAKE_LIBS_QTOPIA = -lqpe -lqtopia
QMAKE_LIBS_THREAD = -lpthread
QMAKE_LIBS_OPENGL =

QMAKE_MOC = $$[QT_INSTALL_BINS]/moc
QMAKE_UIC = $$[QT_INSTALL_BINS]/uic

QMAKE_AR = i486-pc-linux-gnu-ar cqs
QMAKE_RANLIB =

QMAKE_TAR = tar -cf
QMAKE_GZIP = gzip 9f

QMAKE_COPY = cp -f
QMAKE_MOVE = mv -f
QMAKE_DEL_FILE = rm -f
QMAKE_DEL_DIR = rmdir
QMAKE_CHK_DIR_EXISTS = test -d
QMAKE_MKDIR = mkdir -p
include(../../common/unix.conf)
load(qt_config)

The corresponding qplatformdefs.h file is much simpler and just refers to an existing generic one:

#include "../../linux-g+''/qplatformdefs.h"

To complete this custom mkspec, place the above files into a directory called linux-i486-g+ within the mkspecs/qws directory.

Configuring the target build

We are now ready to configure Qt to use our mkspec and hence use our cross-compiling toolchain. We do so with the following command:

 ./configure -xplatform qws/linux-i486-g++ -embedded x86 
        -prefix /usr/i486-pc-linux-gnu/usr/local/qt-embedded
        -qt-gfx-linuxfb -qt-gfx-vnc
        -no-largefile -exceptions -no-accessibility -no-qt3support -no-sse2 -qt-zlib -no-gif -no-libtiff
        -qt-libpng -no-libmng -qt-libjpeg -openssl -no-nis -no-cups -depths 16
        -qt-kbd-linuxinput -nomake demos -nomake examples
        -qt-mouse-linuxinput -qt-mouse-tslib
        -confirm-license

We have some different options here now compared to the earlier host configuration. Notably all references to the qvfb support are gone. This is because the virtual framebuffer application is purely a development and testing tool. It is not designed with security in mind so you should never deploy it on the target.

Here is some information on the other new options that appear:

  • -xplatform <mkspec files to use>- Cross compile for the target platform using the environment specified in the mkspec files
  • -embedded <target CPU architecture>- The CPU architecture of the target platform
  • -prefix <path>- The path to install the cross-compiled Qt to. This should be within your sysroot on your host machine to make things easier.
  • -qt-mouse-tslib- Enable touch screen support via the generic tslib touch screen library
  • -I<path>- Extra include directory to search (in this case for tslib headers)
  • -L<path>- Extra library directory to search (in this case for tslib headers)

Building and installing

To build and then install the cross-compiled target version of Qt, you can follow the same instructions as for the host build. In short:

make -j<number of jobs>
su- (if you need root access to be able to install)
make install

And that's it! You now have everything needed to start writing, testing and running Qt applications for embedded devices on both your development machien and on the device itself (after a suitable deployment).

Summary

In this tutorial you have learned how to:

  • Configure, build and install Qt for Embedded Linux as a host build
  • Prepare custom mkspecs suitable for your target device