Qt on RPi

I love Qt for any project that needs a UI and I love Raspberry Pi’s, so why not use the two together? There are a number of tutorials around showing how to do that but most of them are old and out of date. I’ve written-up the method I have used to do this below to get Qt 5.12.2 running on a Raspberry Pi 3 Model B+ running Raspbian Stretch (November 2018). No doubt you will be using something different, so here’s some good background reading to understand the process and what you may need to do to update the following for your environment.

https://doc.qt.io/qt-5/supported-platforms.html - work out which version of  GCC you need
https://wiki.qt.io/Building_Qt_5_from_Git
http://doc.qt.io/qt-5/build-sources.html
https://wiki.qt.io/Building_a_static_Qt_for_Windows_using_MinGW
https://wiki.qt.io/MinGW
https://wiki.qt.io/Mingw-64-bit
http://doc.qt.io/qt-5/windows-requirements.html#gcc-mingw-builds
http://doc.qt.io/qt-5/supported-platforms-and-configurations.html
http://doc.qt.io/qt-5/windows-building.html
https://wiki.qt.io/Building_Qt_Desktop_for_Windows_with_MinGW

I want to run the Qt apps on Pi to write directly to the screen rather than a desktop-style windowed Qt app running under X11. That means cross-compiling to use hardware accelerated OpenGL with eglfs.

I’m assuming that the Pi is up and running with Stretch. In overview the things we need to do from here are to :

  • Setup the RPI with all the required libraries and development files and then sync those to the PC.
  • Cross-compile the chosen version of Qt on the PC to run on the RPi.
  • Set-up Qt on the PC to cross-compile applications for the RPi.

*Simple! OK lets get started.

[The following includes material copied from other recipes on the web, mostly from https://wiki.qt.io/RaspberryPi2EGLFS and https://visualgdb.com/tutorials/raspberry/qt/embedded/. If any of the authors of those object, let me know and I will change it].

First we need to do some work on the RPi to get it ready.

  1. [on RPi] Make sure that your distribution is up to date:
    sudo rpi-update
    sudo reboot
    sudo apt-get update
    sudo apt-get upgrade
    sudo reboot
  2. [on RPi] Install a bunch of development files (for simplicity we use build-dep, not everything is really needed, but it is easier this way).
    Edit sources list in /etc/apt/sources.list with use of your favorite editor (nano / vi) and uncomment the deb-src line:
    sudo nano /etc/apt/sources.list

    Update your system and install required libraries:

    sudo apt-get update
    sudo apt-get build-dep qt4-x11
    sudo apt-get build-dep libqt5gui5
    sudo apt-get install libudev-dev libinput-dev libts-dev libxcb-xinerama0-dev libxcb-xinerama0

Now move over to the PC and do the following steps there.

  1. Download and install a cross compile toolchain appropriate for your level of Raspbian from here : http://gnutoolchains.com/raspberry/. For Raspbian Stretch I used raspberry-gcc6.3.0-r4.exe (534 MB), however this appears to include some older levels of some of the header files, which screws up the build. These can be removed from the search path by renaming the two offending folders:
    CD to C:\SysGCC\Raspberry\arm-linux-gnueabihf\include
    Rename the “bits” and “sys” folders to something else. I used “bits.old” and “sys.old” respectively.
  2. Download and install a MinGW64 toolchain from here : https://sourceforge.net/projects/mingw-w64/. You’ll need to pick the right level for your version of Qt. For Qt 5.12.2 I used version 7.3.0
  3. Download and install Python 2.7 for Windows .
  4. Download and install Perl for Windows.
  5. Download the latest version of Qt from here : https://www.qt.io/download. You will need the source code, so tick the “Sources” box if using the Qt Online Installer for Windows.
  6. Before we can build the Qt for Raspberry Pi, we need to resynchronize the sysroot with the toolchain to ensure that the toolchain has all the headers and libraries from your Raspberry Pi. Start the UpdateSysroot.bat file from the c:\SysGCC\Raspberry\TOOLS folder:03-syncYou need to synchronize at least the /opt folder, as it contains OpenGL headers that are not included in the toolchain. If you have installed additional packages on your Raspberry Pi, resynchronize other suggested directories as well. Do not resynchronize the /etc folder. Otherwise it will overwrite the /etc/ld.so.conf file with a version from the device that contains “include” statements unsupported by the Windows compiler. If you did overwrite it, expand the statements manually or revert to the ld.so.conf file shipped with the original toolchain.
    TIP: use <ctrl> <Return> to add a new line to the list of directories to synchronise
    TIP2: this process can take a long time, so time to make a cup of tea.
    TIP3: this crashed halfway through for me (at the end of the /usr/lib section). So I ran it again without the folders that had already been synced.
  7. Create a folder to contain your Qt build. I used c:/temp/qt-build, referred to as <qt-build> in the following.
  8. We are going to use a Windows command shell to run the compilations. To do that, it is easiest to use a script to setup the environment.
    CD to <qt-build> and create the file qt5vars.cmd, containing the following:
    @echo off

    REM Edit this location to point to the source code of Qt
    SET _ROOT=C:\Qt\5.12.2\Src

    SET PATH=%_ROOT%\qtbase\bin;%_ROOT%\gnuwin32\bin;%PATH%

    REM Uncomment the below line when using a git checkout of the source repository
    REM SET PATH=%_ROOT%\qtrepotools\bin;%PATH%

    REM Uncomment the below line when building with OpenSSL enabled. If so, make sure the directory points
    REM to the correct location (binaries for OpenSSL).
    REM SET PATH=C:\OpenSSL-Win32\bin;%PATH%

    REM When compiling with ICU, uncomment the lines below and change <icupath> appropriately:
    REM Note that -I <icupath>\include and -L <icupath>\lib need to be passed to
    REM configure separately (that works for MSVC as well).
    REM SET PATH=<icupath>\lib;%PATH%

    REM Contrary to earlier recommendations, do NOT set QMAKESPEC.

    SET _ROOT=

    REM Keeps the command line open when this script is run.
    REM cmd /k
  9. Run qt5vars to create a command shell and use that for the following steps.
  10. Check that Python and Perl are installed on the path correctly.
    1. Typing “python” should take you into the python shell (ctrl-Z, return to exit). Check that it is V2.7.x.
    2. Typing “perl -v” should tell you what version of Perl is installed. I’m not sure it matters what level you have. I had v5.22.2.
  11. Ensure that we are running the correct versions of the MinGW gcc compiler and the Raspberry Pi cross-compiler.
    1. “where gcc” should return C:\SysGCC\mingw64\bin\gcc.exe
    2. “where arm-linux-gnueabihf-gcc” should return C:\SysGCC\raspberry\bin\arm-linux-gnueabihf-gcc.exe
  12. Open the C:\Qt\5.12.2\Src\qtbase\mkspecs\linux-arm-gnueabi-g++\qmake.conf  file and replace all occurences of arm-linux-gnueabi- with arm-linux-gnueabihf- [Not sure if this step is still needed]
  13. The Raspberry Pi 3 qmake.conf file needs to be fixed up. The shipped version uses “=” in the paths to indicate sysroot, but that seems to screw up “configure”. The fix is to change the “=” if there is one at the start of any path to $$[QT_SYSROOT]. In C:\Qt\5.12.2\Src\qtbase\mkspecs\devices\linux-rasp-pi3-g++\gmake.conf, change:
    VC_LIBRARY_PATH = /opt/vc/lib
    VC_INCLUDE_PATH = =/opt/vc/include
    VC_LINK_LINE = -L=${VC_LIBRARY_PATH}
    QMAKE_LIBDIR_OPENGL_ES2 = =${VC_LIBRARY_PATH}

    To:

    VC_LIBRARY_PATH = $[QT_SYSROOT]/opt/vc/lib
    VC_INCLUDE_PATH = $[QT_SYSROOT]/opt/vc/include
    VC_LINK_LINE = -L${VC_LIBRARY_PATH}
    QMAKE_LIBDIR_OPENGL_ES2 = ${VC_LIBRARY_PATH}
  14. Now we are ready to build Qt. Due to a bug in the Qmake build script, we will need to build it in 2 steps: first we will build a Qmake for Windows and then we’ll build the actual Qt binaries.
  15. First to build the Windows tools, make sure that you are in the <qt-build> directory and run the following configuration script from there (all one line) (note the “-opengl es2” option that configures Qt to use the Raspberry Pi framebuffer directly instead of the X11 system):
    c:\Qt\5.12.2\Src\configure -platform win32-g++ -xplatform linux-arm-gnueabi-g++ -release -opengl es2 -sysroot C:/SysGCC/Raspberry/arm-linux-gnueabihf/sysroot -prefix /usr/local/qt5 -nomake examples
  16. This build may fail eventually, but as long as it has got past building qmake.exe we are OK. Check this by making sure that you can run “qtbase\bin\qmake -v”.
  17. Now we can build the rest of the Qt framework. First of all open the c:\Qt\5.12.2\Src\configure file and insert the condition before the “Creating qmake line” with this one and add a matching fi at the end of the block:
    if [ '!' -f "$outpath/bin/qmake.exe" ]; then

    10-configure

  18. We now need to run the configure script again with a few more parameters. Configure has loads of parameters (try configure -h to see them all) and you may need to try different combinations to get the results you want. To make that easier, you may want to put the command inside a command file (I use “qt5unix.cmd”) to make it easier to tweak. The combination that worked for me is (again, all one line):
    c:\Qt\5.12.2\Src\configure -platform win32-g++ -device linux-rasp-pi3-g++ -release -opengl es2 -sysroot C:/SysGCC/Raspberry/arm-linux-gnueabihf/sysroot -prefix /usr/local/qt5 -nomake examples -device-option CROSS_COMPILE=C:/SysGCC/Raspberry/bin/arm-linux-gnueabihf- -qt-xcb -opensource -confirm-license
  19. The -device-option is required when using the device specification, however if you specify it while building Qmake, the Qt build system will try to use the cross-compiler to build the Windows Qmake executable that will obviously fail.

    If you get errors while configuring Qt, please check that:

    • Your <toolchain>\sysroot\etc\ld.so.conf file contains the following lines:
    • Your toolchain sysroot directory contains the /opt/vc directory

    If nothing helps, run the configure script with the -verbose argument and direct its output to a file by appending “>log.txt 2>&1” to the command line. This should provide more information on what exactly is causing the problem.

  20. Once the configure script reports that the configuration is complete, run the “mingw32-make && mingw32-make install” command to build the entire Qt framework and install it into the cross-compiler directory. The framework is huge, so the build process might take several hours to complete, even on a fast machine.12-builddoneWarning: do not run “make install” before “make” succeeds as it would fail leaving the build directory in a partially built state failing further builds until the entire directory is deleted and re-created.
  21. Open SmarTTY (a portable version can be found in <SysGCC>\Raspberry\TOOLS\PortableSmartty) and connect to your Raspberry Pi. Then run the following commands to create the /usr/local/qt5 folder and make it writable to the current user:

    Then select SCP->Upload directory:13-mkdir

  22. Select the <sysroot>\usr\local\qt5 directory and upload it to /usr/local/qt5:14-upload
  23. Wait for the upload to complete. The built Qt framework is relatively large and would take several minutes to upload:15-progr
  24. Once the upload is complete, you can test out the framework. Go to the /usr/local/qt5/examples/opengl/qopenglwidget directory and launch ./qopenglwidget:16-widget
  25. To get this working I had to fix-up a few things :
    To get fonts working I did:
    export QT_QPA_FONTDIR=/usr/share/fonts/truetype/dejavu
    I also needed to set the following environment variables
    export QT_QPA_PLATFORM=eglfs
    export QT_QPA_PLATFORM_PLUGIN_PATH=/usr/local/qt5/plugins/platforms
    export LD_LIBRARY_PATH=/usr/local/qt5/lib
  26. Look at the screen connected to the HDMI port of the Raspberry Pi. You will see a rotating Qt logo animation:17-screenshotIf the screen does not show anything, shut down your Raspberry Pi and re-plug the power connector. As long as the screen is connected when the device is powered on, Raspberry Pi should recognize it.