Remote Qt development

Let´s take a look how you can develop and cross compile Qt applications for your Raspberry Pi.

If you want to develop a graphical user interface for the Raspberry Pi, in most cases you end up with a solution that is realized with Qt. This is a universal C ++ library for creating graphical interfaces for various operating systems, such as B. Windows, Linux or Android.

Unfortunately, a Raspberry Pi does not offer a lot of computing power, which is why the development of graphical interfaces on the Raspberry Pi is rather unattractive. A much more elegant way would be if the program was developed on a host PC and then copied and executed on the Raspberry Pi via remote connection.

And that's exactly what this guide should be about. I will show how the Raspberry Pi and an Ubuntu host system can be used to develop Qt applications for the Raspberry Pi on the host system, which are then run remotely on the Raspberry Pi.

Prepare the Raspberry Pi

For a smooth process, the operating system (here Raspbian) on the Raspberry Pi must be updated. To do this, the file /etc/apt/sources.list must first be adjusted and Debian source packages must be permitted. Add this to the file:

deb-src http://raspbian.raspberrypi.org/raspbian/ buster main contrib non-free rpi

Then the package list, the packages and the operating system of the Raspberry Pi are updated:

$ sudo apt-get update
$ sudo apt-get dist-upgrade
$ sudo reboot
$ sudo rpi-update
$ sudo reboot

Then the missing packages are installed:

$ sudo apt-get build-dep qt5-qmake
$ sudo apt-get build-dep libqt5gui5
$ sudo apt-get build-dep libqt5webengine-data
$ sudo apt-get build-dep libqt5webkit5
$ sudo apt-get install libudev-dev libinput-dev libts-dev libxcb-xinerama0-dev libxcb-xinerama0 gdbserver

And finally, a folder for the Qt installation and some additional symlinks are created:

$ sudo mkdir /usr/local/RaspberryQt
$ sudo chown -R pi:pi /usr/local/RaspberryQt
$ ln -s /opt/RaspberryQt/sysroot/opt/vc/lib/libEGL.so /opt/RaspberryQt/sysroot/usr/lib/arm-linux-gnueabihf/libEGL.so.1.0.0 
$ ln -s /opt/RaspberryQt/sysroot/opt/vc/lib/libGLESv2.so /opt/RaspberryQt/sysroot/usr/lib/arm-linux-gnueabihf/libGLESv2.so.2.0.0 
$ ln -s /opt/RaspberryQt/sysroot/opt/vc/lib/libEGL.so /opt/RaspberryQt/sysroot/opt/vc/lib/libEGL.so.1 
$ ln -s /opt/RaspberryQt/sysroot/opt/vc/lib/libGLESv2.so /opt/RaspberryQt/sysroot/opt/vc/lib/libGLESv2.so.2 

The configuration of the Raspberry Pi is now complete. It continues with the host ...

Compile Qt for the Raspberry Pi

For the host system I used an Ubuntu 18.04 LTS in a virtual machine.

Here, too, the package sources and packages must first be updated and a few additional packages installed.

$ sudo add-apt-repository "deb http://security.ubuntu.com/ubuntu xenial-security main"
$ sudo apt update
$ sudo apt install libjasper-dev
$ sudo apt-get install -y git cmake build-essential pkg-config libjpeg-dev libtiff5-dev libpng-dev libavcodec-dev libavformat-dev libswscale-dev libv4l-dev libxvidcore-dev libx264-dev libatlas-base-dev gfortran wget unzip libz-dev zlib1g-dev gcc g++ git bison python gperf gdb-multiarch qt5-default texinfo make python3-dev

Then the working directories are created and the rights configured accordingly:

$ sudo mkdir /opt/RaspberryQt
$ sudo mkdir /opt/RaspberryQt/build
$ sudo mkdir /opt/RaspberryQt/sysroot /opt/RaspberryQt/sysroot/usr /opt/RaspberryQt/sysroot/opt
$ sudo chown -R 1000:1000 /opt/RaspberryQt

An SSH key for the Raspberry Pi is then created for easier work, which avoids annoying password entries when copying the data.

$ ssh-keygen -t rsa -C root@<IP Raspberry Pi> -P "" -f ~/.ssh/rpi_root_id_rsa
$ ssh-keygen -t rsa -C pi@<IP Raspberry Pi> -P "" -f ~/.ssh/rpi_pi_id_rsa
$ cat ~/.ssh/rpi_root_id_rsa.pub | ssh root@<IP Raspberry Pi> 'cat >> .ssh/authorized_keys && chmod 640 .ssh/authorized_keys'
$ cat ~/.ssh/rpi_pi_id_rsa.pub | ssh pi@<IP Raspberry Pi> 'cat >> .ssh/authorized_keys && chmod 640 .ssh/authorized_keys'

The necessary files can then be downloaded.

$ cd /opt/RaspberryQt
$ git clone https://github.com/raspberrypi/tools
$ wget https://download.qt.io/archive/qt/5.12/5.12.8/single/qt-everywhere-src-5.12.8.tar.xz
$ wget https://raw.githubusercontent.com/riscv/riscv-poky/master/scripts/sysroot-relativelinks.py

The files are a cross compiler for the Raspberry Pi, the Qt version used (here 5.12.8) and a Python script to replace symbolic links of files with relative links (will be needed later).

Then the Qt version is unpacked and the name of the compiler used (here arm-linux-gnueabihf) is adjusted in the Qt configuration file.

$ tar xf qt-everywhere-src-5.12.8.tar.xz
$ cp -R qt-everywhere-src-5.12.8/qtbase/mkspecs/linux-arm-gnueabi-g++ qt-everywhere-src-5.10.1/qtbase/mkspecs/linux-arm-gnueabihf-g++
$ sed -i -e 's/arm-linux-gnueabi-/arm-linux-gnueabihf-/g' qt-everywhere-src-5.12.8/qtbase/mkspecs/linux-arm-gnueabihf-g++/qmake.conf

Now the libraries used by the target (here the Raspberry Pi) Pi are still required. These can be downloaded from the Raspberry Pi using rsync.

$ rsync -avz root@<IP vom Raspberry Pi>:/lib sysroot
$ rsync -avz root@<IP vom Raspberry Pi>:/usr/include sysroot/usr
$ rsync -avz root@<IP vom Raspberry Pi>:/usr/lib sysroot/usr
$ rsync -avz root@<IP vom Raspberry Pi>:/opt/vc sysroot/opt

It may take a few minutes to download. These files will later be required for the Qt build process, since Qt requires some standard libraries from the target system (here the Raspberry Pi).

Before the files can be used, the symbolic links that still point to the file system of the Raspberry Pi must be replaced by relative links from the new sysroot directory.

/opt/RaspberryQt/sysroot-relativelinks.py /opt/RaspberryQt/sysroot

Finally, Qt is configured.

$ cd /opt/RaspberryQt/build
$ ../qt-everywhere-src-5.12.8/configure -opengl es2 -device linux-rasp-pi3-g++ -device-option CROSS_COMPILE=/opt/RaspberryQt/tools/arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian-x64/bin/arm-linux-gnueabihf- -sysroot /opt/RaspberryQt/sysroot -prefix /usr/local/RaspberryQt -opensource -confirm-license -no-gbm -skip qtscript -nomake tests -nomake examples -make libs -pkg-config -no-use-gold-linker -v

During configuration, the type of the target must be specified via the parameter of the argument -device. The following table applies to the parameters.

Once the configuration is complete, Qt can be compiled and installed.

$ make -j4
$ make install

The number of cores used is specified via parameter -j4, which can speed up the process. With a core, the entire process takes a good 3-4 hours (depending on the system). The fully compiled Qt libraries are then copied to the Raspberry Pi using rsync.

$ cd /opt/RaspberryQt
$ rsync -avz sysroot/usr/local/RaspberryQt root@<IP des Raspberry Pi>:/usr/local

The Qt libraries and the Raspberry Pi are now ready for use. Qt applications can now be created, compiled and executed on the Raspberry Pi. The next step is to create a new GDB, because the GDB from the Raspberry Pi Toolchain does not have any support for the Python programming language and therefore cannot be used in the Qt Creator.

Compiling GDB

Before GDB can be compiled, a few additional packages must be installed:

$ sudo apt-get update
$ sudo apt-get upgrade
$ sudo apt-get install texinfo gcc gcc-c++ make python3-devel wget

The sources for GDB can be downloaded directly from the FTP server of the GNU project by using the wget command:

$ wget https://ftp.gnu.org/gnu/gdb/gdb-9.1.tar.xz
$ tar xf gdb-9.1.tar.xz
$ mkdir gdb-9.1/build

The installed Python version and the corresponding Python libraries are required to create GDB:

$ export PYTHON=python3
$ export PYTHON_LIBDIR=$("${PYTHON}" -c "import sysconfig; print(sysconfig.get_config_var('LIBDIR'))")

GDB can now be configured and created:

$ cd gdb-9.1/build
$ ../configure --prefix=/home/kampi/GDB/bin --target=arm-linux-gnueabihf --with-python=${PYTHON} LDFLAGS="-L${PYTHON_LIBDIR}"
$ make -j4
$ make -C gdb install

The GDB version created is saved in the bin/ directory at the end of the compilation process.

This would complete the tools. I'll show you in the next step how you can set up the Qt Creator.

Configure Qt Creator for the host system

The Qt Creator is best suited for the development of Qt applications. Since the installation via the official Ubuntu package sources didn't work for me and the Qt Creator always throw some errors me, I downloaded and ran the Qt installer directly from the website.

$ cd ~/Downloads
$ sudo chmod +x qt-unified-linux-x64-3.0.6-online.run
$ ./qt-unified-linux-x64-3.0.6-online.run

This step installs the complete Qt libraries, etc. on the host system and not just the Qt Creator.

After installation, the Qt Creator must still be configured for the Raspberry Pi. To do this, the Creator is started and the menu ToolsSettings is opened. Then the Devices submenu is opened and click on Add... to add a new Generic Linux device.

The Start Wizard button confirms the selection and creates a new device. The key file already created can be used for the SSH connection. The setup of the new device is completed with NextComplete. The Qt Creator then tests the settings and tries to connect to the device.

If the test was successful, the window can be closed. The new device is now listed in the device list.

The kit, i.e. the compiler, debugger and source collection, is then created. The Settings menu is opened again via Tools and the Kits item is selected. In the Compiler tab, the Add button adds an entry for a C and a C ++ compiler (both can be found under GCC).

The entries are then confirmed by clicking Apply.

Next, the Qt version for the Raspberry Pi is created. To do this, the Qt Versions tab is opened and the Add button is used to create a new entry. A file browser opens with which the path of the created qmake is selected.

The entry is confirmed by clicking the Apply button.

In the last step, a new debugger is created. To do this, the Debugger tab is opened and a new entry is created using the Add button and filled in with the path of the debugger created.

Now the kit can be created. The Kits tab is opened and a new kit is created using the Add button. The mask is now filled in according to the screenshot.

Here too, the entry is confirmed by clicking on Apply. The window can then be closed with OK.

Create the first application

Now that all tools are together, a sample project should be developed on the Ubuntu host system and executed remotely on the Raspberry Pi. Via FileNew... a new Qt-Widgets project is created. The individual entries are confirmed with Next. When selecting the kit, the Raspberry Pi Kit that has just been created is selected as the kit.

All other entries can be confirmed directly with Next and the wizard can then be closed with Close.

Next, the deployment rule must be adjusted in the project file, since the user pi is not allowed to access the default directory /opt by default. Therefore the path in /home/pi is changed.

target.path = /home/pi/$${TARGET}/bin
INSTALLS += target

In the created project, two environment variables must then be set for the target, i.e. the Raspberry Pi. To do this, the Projects tab is opened and the item Execute the current kit is selected. The variables DISPLAY =: 0 and XAUTHORITY = /home/pi/.Xauthority are created and set in the submenu Execution Environment.

In addition, the command line parameters must be set to -platform xcb.

In the standard configuration, Qt for Embedded Linux uses eglfs to render the windows, which means that no display server such as X11 or Wayland is required.

Therefore, the applications always start in full screen mode and cannot be minimized or pushed into the background. If egl is to be used, the size of the screen has to be defined. This is done using the environment variables QT_QPA_EGLFS_PHYSICAL_WIDTH, QT_QPA_EGLFS_PHYSICAL_HEIGHT, QT_QPA_EGLFS_HEIGHT and QT_QPA_EGLFS_WIDTH.

In the case of the official Raspberry Pi screen, the size of the screen can be found in the official drawing. The entered values ​​correspond to the size of the screen in millimeters and pixels! For other screens, the values ​​must be adjusted accordingly.

In addition, two paths need to be adjusted on the Raspberry Pi:

$ cd /opt/vc/lib $ sudo ln -s libbrcmEGL.so libEGL.so.1 $ sudo ln -s libbrcmGLESv2.so libGLESv2.so.2 $ echo "export LD_LIBRARY_PATH=/opt/vc/lib" >> ~/.bashrc

This means that the setup is ready for use and nothing stands in the way of developing graphic applications on the PC for the Raspberry Pi. With a click on the green arrow in the side bar or with the key combination Ctrl + R the project is created and the application is started a few seconds later on the Raspberry Pi.

Add additional modules

The installation carried out is a minimal installation, in which not all modules are present (e.g. the Qt charts are missing). These modules can be installed later by downloading the sources of the respective module from the submodules directory of the respective Qt version (hereinafter carried out for Qt charts):

$ wget http://download.qt.io/official_releases/qt/5.12/5.12.8/submodules/qtcharts-everywhere-src-5.12.8.tar.xz
$ tar xf qtcharts-everywhere-src-5.12.8.tar.xz

After unpacking, you change to the directory and start the installation. The path of the created qmake is required for this:

$ cd qtcharts-everywhere-src-5.12.8
$ /opt/RaspberryQt/sysroot/usr/local/RaspberryQt/bin/qmake
$ make
$ make install

The created libraries must then be copied to the Raspberry Pi using rsync.

$ rsync -avz /opt/RaspberryQt/sysroot/usr/local/RaspberryQt root@$<IP des Raspberry Pi>:/usr/local

And the additional module is ready for use.

I have created some bash scripts that contain the complete installation procedure (both for the Raspberry Pi and for the host system). You can download both scripts and the sample project can be found in my GitLab repository.

Last updated