Raspberry PI Cross Compiling QT GUI Application in Ubuntu

Learn raspberry pi cross compiling qt gui application in ubuntu with practical examples, diagrams, and best practices. Covers ubuntu, gcc, raspberry-pi development techniques with visual explanations.

Cross-Compiling Qt GUI Applications for Raspberry Pi on Ubuntu

Raspberry Pi board connected to a monitor, with a Qt logo overlay, symbolizing cross-compilation.

Learn how to set up a cross-compilation environment on Ubuntu to build Qt GUI applications for your Raspberry Pi, streamlining your development workflow.

Developing graphical user interface (GUI) applications for the Raspberry Pi often involves building directly on the device. While feasible for small projects, this approach can be slow and resource-intensive, especially for larger Qt applications. Cross-compilation offers a more efficient alternative, allowing you to build your applications on a powerful Ubuntu development machine and then deploy them to your Raspberry Pi. This article will guide you through setting up a robust cross-compilation environment for Qt GUI applications targeting Raspbian.

Understanding Cross-Compilation for Raspberry Pi

Cross-compilation is the process of compiling code on one type of computer (the host) for execution on another type of computer (the target). In our case, the host is an x86-64 Ubuntu machine, and the target is an ARM-based Raspberry Pi running Raspbian (or Raspberry Pi OS). This requires a specific toolchain that can generate ARM executables from your source code. Additionally, Qt applications depend on various libraries, so we'll need to ensure that the cross-compilation environment can link against the correct ARM versions of these libraries.

flowchart TD
    A[Ubuntu Host Machine] --> B{Cross-Compilation Toolchain}
    B --> C[Qt Source Code]
    C --> D[Cross-Compiled Qt Libraries]
    D --> E[Your Qt Application Source]
    E --> F{Cross-Compilation Process}
    F --> G[ARM Executable/Libraries]
    G --> H[Raspberry Pi Target]
    H --> I[Run Qt Application]

    subgraph Host Setup
        A
        B
        C
        D
        E
        F
    end

    subgraph Target Deployment
        G
        H
        I
    end

Overview of the Raspberry Pi Qt Cross-Compilation Workflow

Prerequisites and Initial Setup

Before we begin, ensure you have the following:

  • Ubuntu Development Machine: A working Ubuntu installation (e.g., 20.04 LTS or newer).
  • Raspberry Pi: A Raspberry Pi (e.g., Pi 3, 4, or 5) with Raspbian (or Raspberry Pi OS) installed and configured for SSH access.
  • Internet Connection: Both your Ubuntu machine and Raspberry Pi need internet access for downloading packages.
  • Sufficient Disk Space: Cross-compiling Qt can consume several gigabytes of disk space.

We'll start by installing necessary tools on Ubuntu and preparing the Raspberry Pi for synchronization.

1. Install Essential Build Tools on Ubuntu

Open a terminal on your Ubuntu machine and install the required development tools and libraries:

2. Prepare Raspberry Pi for Synchronization

On your Raspberry Pi, ensure SSH is enabled and install rsync. We'll use rsync to copy system libraries from the Pi to your Ubuntu machine.

3. Create a Cross-Compilation Directory

On your Ubuntu machine, create a dedicated directory for your cross-compilation environment. This helps keep things organized.

sudo apt update
sudo apt install build-essential git rsync crossbuild-essential-armhf libgl-dev libegl-dev libgles-dev

# For Qt 6, you might also need:
sudo apt install libxcb-xinerama0-dev libxcb-xinput-dev libxkbcommon-dev libxkbcommon-x11-dev

# On Raspberry Pi:
sudo apt update
sudo apt install rsync openssh-server

# On Ubuntu:
mkdir ~/rpi-cross-compile
cd ~/rpi-cross-compile

Installing prerequisites and setting up directories

Synchronizing Raspberry Pi System Libraries

To successfully cross-compile, your Ubuntu machine needs access to the Raspberry Pi's system libraries. We'll use rsync to copy these libraries into our cross-compilation directory. This step is crucial for the linker to find the correct ARM versions of libraries like libc, libstdc++, and various graphics libraries.

PI_USER="pi" # Your Raspberry Pi username
PI_IP="192.168.1.100" # Your Raspberry Pi's IP address

mkdir sysroot
mkdir sysroot/usr
mkdir sysroot/opt

rsync -avz --rsync-path="sudo rsync" ${PI_USER}@${PI_IP}:/lib sysroot
rsync -avz --rsync-path="sudo rsync" ${PI_USER}@${PI_IP}:/usr/include sysroot/usr
rsync -avz --rsync-path="sudo rsync" ${PI_USER}@${PI_IP}:/usr/lib sysroot/usr
rsync -avz --rsync-path="sudo rsync" ${PI_USER}@${PI_IP}:/opt/vc sysroot/opt

# Fix symlinks in sysroot
sudo chown -R $(whoami):$(whoami) sysroot

# Script to fix symlinks (save as fix_symlinks.sh and run)
cat <<EOF > fix_symlinks.sh
#!/bin/bash
SYSROOT="$(pwd)/sysroot"

for file in 
$(find "$SYSROOT" -type l);
do
  target="$(readlink "$file")"
  if [[ "$target" == /* ]]; then
    # Absolute symlink
    sudo rm "$file"
    sudo ln -s "$SYSROOT/$target" "$file"
  fi
done
EOF

chmod +x fix_symlinks.sh
./fix_symlinks.sh

Synchronizing Raspberry Pi libraries and fixing symlinks

Downloading and Configuring Qt Source

Next, we need to download the Qt source code. It's generally best to use a version of Qt that is compatible with the version available on your Raspberry Pi, or a slightly newer one if you plan to deploy the necessary Qt runtime libraries. We'll then configure Qt for cross-compilation.

1. Download Qt Source Code

Navigate to your cross-compilation directory and download the Qt source. For this example, we'll use Qt 5.15.2, a common and stable version for Raspberry Pi. You can find other versions on the official Qt archives.

2. Configure Qt for Cross-Compilation

Create a build directory and run the configure script. This step tells Qt how to build itself for the ARM target, specifying the sysroot, toolchain, and features.

cd ~/rpi-cross-compile

# Download Qt 5.15.2 source
wget https://download.qt.io/archive/qt/5.15/5.15.2/single/qt-everywhere-src-5.15.2.tar.xz
tar -xf qt-everywhere-src-5.15.2.tar.xz

mkdir qt5.15.2-build
cd qt5.15.2-build

../qt-everywhere-src-5.15.2/configure \
    -prefix /usr/local/qt5pi \
    -extprefix ~/rpi-cross-compile/qt5pi \
    -hostprefix ~/rpi-cross-compile/qt5pi-host \
    -release -opengl es2 \
    -device linux-rasp-pi4-g++ \
    -device-option CROSS_COMPILE=/usr/bin/arm-linux-gnueabihf- \
    -sysroot ~/rpi-cross-compile/sysroot \
    -opensource -confirm-license \
    -make libs -nomake examples -nomake tests \
    -skip qtwebengine -skip qtwayland -skip qtlocation -skip qtmultimedia \
    -no-use-gold-linker -v

Downloading Qt source and configuring for Raspberry Pi 4

Building and Installing Qt

After successful configuration, the next step is to build Qt. This process can take a significant amount of time, depending on your host machine's performance. Once built, we'll install the cross-compiled Qt libraries into our designated extprefix directory.

cd ~/rpi-cross-compile/qt5.15.2-build

make -j$(nproc) # Use all available CPU cores for faster compilation

make install

Building and installing cross-compiled Qt libraries

Compiling Your Qt Application

With Qt successfully cross-compiled and installed, you can now compile your own Qt GUI applications. We'll use the qmake or cmake from our cross-compiled Qt installation to generate makefiles and then build the application.

// main.cpp
#include <QApplication>
#include <QLabel>

int main(int argc, char *argv[]) {
    QApplication a(argc, argv);
    QLabel label("Hello, Raspberry Pi Qt!");
    label.setAlignment(Qt::AlignCenter);
    label.resize(300, 100);
    label.show();
    return a.exec();
}

Example Qt GUI application (main.cpp)

# example.pro
QT += widgets

SOURCES += main.cpp

TARGET = my_rpi_app
CONFIG += console

# Deploy to Raspberry Pi
# This is a simple example, for complex deployments, consider qmake's deploy features or custom scripts
# For manual deployment, you'd copy the executable and required Qt libraries.

QMake project file (example.pro)

1. Set up Environment Variables

Before compiling your application, ensure your environment variables point to the cross-compiled Qt installation.

2. Build Your Application

Navigate to your application's source directory and use the cross-compiled qmake to generate the Makefile, then make to build.

export PATH=~/rpi-cross-compile/qt5pi-host/bin:$PATH

# Assuming your application source is in ~/my_qt_app
mkdir ~/my_qt_app_build
cd ~/my_qt_app_build

qmake ~/my_qt_app/example.pro
make -j$(nproc)

Building your Qt application using the cross-compiled Qt

Deploying and Running on Raspberry Pi

Once your application is compiled, you need to deploy it along with the necessary Qt runtime libraries to your Raspberry Pi. The qt5pi directory created during the make install step contains all the libraries required for your application to run on the target.

1. Copy Qt Libraries to Raspberry Pi

Use rsync to copy the entire cross-compiled Qt installation to your Raspberry Pi. This ensures all dependencies are present.

2. Copy Your Application to Raspberry Pi

Transfer your compiled application executable to the Raspberry Pi.

3. Run Your Application on Raspberry Pi

SSH into your Raspberry Pi and set the LD_LIBRARY_PATH to include the deployed Qt libraries, then execute your application.

PI_USER="pi"
PI_IP="192.168.1.100"

# Copy Qt libraries
rsync -avz ~/rpi-cross-compile/qt5pi ${PI_USER}@${PI_IP}:/usr/local/

# Copy your application
rsync -avz ~/my_qt_app_build/my_rpi_app ${PI_USER}@${PI_IP}:/home/${PI_USER}/

# On Raspberry Pi (via SSH):
ssh ${PI_USER}@${PI_IP}

export LD_LIBRARY_PATH=/usr/local/qt5pi/lib:$LD_LIBRARY_PATH
./my_rpi_app

Deploying and running the Qt application on Raspberry Pi