Cross-Compile Qt 6 for Raspberry Pi

From Qt Wiki
Revision as of 14:09, 20 June 2022 by Uraihan (talk | contribs) (Continuing the page (Qt Wiki editor is freaking out sometimes on my end...))
Jump to navigation Jump to search

Introduction

This is a step-by-step guide to cross-compile Qt6 for Raspberry Pi OS. The end result of this guide allows you to compile Qt6 applications on a host machine and deploy it on the Raspberry Pi running a Raspberry Pi OS image. The instructions in this guide are targeted for beginners while also allowing a more advanced user to follow through. It was tested on Ubuntu 20.04 targeting Raspberry Pi OS, but should work with any Debian-based OS.

For an older guide, check this Qt Wiki guide or this one.

Getting Started: Planning Phase

Before we get our hands dirty and mess around with the configurations, let's familiarise ourselves with essential components needed to cross-compile Qt and decide which directory names we want to use to store these components. This way, we can easily track the location of these important components when we are typing commands in the terminal.

At its most basic setup, we need at least the following components in a host machine to cross-compile Qt:

  • Sysroot, which basically is the scaled down version of our target's filesystem inside our host machine. For this example, we will store it on
    ~/rpi-sysroot
    
  • A cross-compiler. To make it as straightforward as possible, for this guide we will use the cross-compiler for Aarch64 from the Ubuntu repository.
  • Qt source code with its submodules, at least the qtbase submodule. For this guide, we will download Qt source code from Qt official GitHub repository. By default, it will be stored in
    ~/qt5
    
    .
  • CMake toolchain. CMake is the recommended build generator for Qt6. Inside this toolchain file, we will specify in detail about the exact specifications of our cross-compiled Qt build. We will store this
    toolchain.cmake
    
    file on our
    $HOME
    
    directory.

We also have to decide the locations of our Qt builds, one for host machine and one for our Raspberry Pi in our PC before we transfer it to the Raspberry Pi.

  • We will store a build of Qt6 for host machine on
    ~/qt-host
    
    . This is necessary because when building a Qt for our Raspberry Pi target, we will refer to this build of Qt.
  • Finally, our Qt6 build for Raspberry Pi will be stored on
    ~/qt-raspi
    
    in the host machine temporarily before we move it to a location in our Raspberry Pi (for example,
    /usr/local/qt6
    
    ).

Following the best practices of building C/C++ applications, we also want to make sure that our final build directories are clean from all build configuration files that CMake will create during the configuration phase. For that, we will store build configuration files on

~/qthost-build

for configuration files of Qt for our host machine and

~/qtpi-build

for configuration files of Qt for Raspberry Pi.

After we decided these locations, let's create them all!

On host machine,

cd ~
mkdir rpi-sysroot rpi-sysroot/usr rpi-sysroot/opt
mkdir qt-host qt-raspi qthost-build qtpi-build

The second line will create the sysroot directory with its necessary subfolder, while the third line will create the directory for the rest of locations defined previously.

Installing Raspberry Pi OS

Let's now install an image of Raspberry Pi OS. You can download the latest Raspberry Pi Imager from https://www.raspberrypi.com/software/, and then flash an image of Raspberry Pi OS to your microSD card with only a few clicks on the Imager's GUI. This one should be straightforward.

Setup Raspberry Pi

After successfully flashing an image of Raspberry Pi OS to a microSD card, insert it into the microSD card reader of our Raspberry Pi, connect a keyboard and monitor to the device and boot it up. The system will ask for a basic first-time setup. Please follow the setup according to the instruction.

After successfully setting up the device, the system will reboot to the home desktop. From here, open Terminal. We want to install a few packages needed by Qt6.

Install Dependencies

Update and upgrade to the newest version.

sudo apt update
sudo apt full-upgrade
sudo reboot

Next, install the package dependencies.

sudo apt-get install libboost-all-dev libudev-dev libinput-dev libts-dev libmtdev-dev libjpeg-dev libfontconfig1-dev libssl-dev libdbus-1-dev libglib2.0-dev libxkbcommon-dev libegl1-mesa-dev libgbm-dev libgles2-mesa-dev mesa-common-dev libasound2-dev libpulse-dev gstreamer1.0-omx libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev  gstreamer1.0-alsa libvpx-dev libsrtp2-dev libsnappy-dev libnss3-dev "^libxcb.*" flex bison libxslt-dev ruby gperf libbz2-dev libcups2-dev libatkmm-1.6-dev libxi6 libxcomposite1 libfreetype6-dev libicu-dev libsqlite3-dev libxslt1-dev

sudo apt-get install libavcodec-dev libavformat-dev libswscale-dev libx11-dev freetds-dev libsqlite3-dev libpq-dev libiodbc2-dev firebird-dev libgst-dev libxext-dev libxcb1 libxcb1-dev libx11-xcb1 libx11-xcb-dev libxcb-keysyms1 libxcb-keysyms1-dev libxcb-image0 libxcb-image0-dev libxcb-shm0 libxcb-shm0-dev libxcb-icccm4 libxcb-icccm4-dev libxcb-sync1 libxcb-sync-dev libxcb-render-util0 libxcb-render-util0-dev libxcb-xfixes0-dev libxrender-dev libxcb-shape0-dev libxcb-randr0-dev libxcb-glx0-dev libxi-dev libdrm-dev libxcb-xinerama0 libxcb-xinerama0-dev libatspi2.0-dev libxcursor-dev libxcomposite-dev libxdamage-dev libxss-dev libxtst-dev libpci-dev libcap-dev libxrandr-dev libdirectfb-dev libaudio-dev libxkbcommon-x11-dev

This will install a bunch of libraries from the Debian repository that Qt needed to deploy various kinds of applications on Raspberry Pi.

We also will make a directory that will hold Qt binaries for Raspberry Pi, as specified in the previous section. Actually this can be done at every time before transferring Qt6 build from host machine to the Raspberry Pi, but in this guide we will create it at this stage

sudo mkdir /usr/local/qt6

Setting SSH

We also want to setup an SSH connection between Raspberry Pi and a host machine. This is needed to transfer data between both devices. It is disabled by default, so we need to enable it. For this example, we will use an Ethernet cable to connect both devices. You can also setup an SSH connection via Wi-Fi, and there is a lot of guides on how to set that up on the internet so I will not talk about that here.

Go to Preferences > Raspberry Pi Configuration. Inside the configuration window, switch to Interfaces tab, then toggle SSH on. Click OK, then check whether the SSH service is already enabled by executing

systemctl status ssh.service

in the terminal. Make sure it outputs

Active: active (running)

in one of the output lines.

Next, connect an Ethernet cable to your Raspberry Pi on one end and to a host machine on the other end.

Setup Host Machine

Let's configure our Ubuntu/Debian host machine. First, let's update our packages to the latest version.

sudo apt update
sudo apt upgrade

Next, let's get our cross-compiler. For this guide, we will install it from the Ubuntu/Debian package repository as this is the easiest way to get an ARM64 cross-compiler.

sudo apt install gcc-aarch64-linux-gnu g++-aarch64-linux-gnu

You can also download the cross-compiler from somewhere on the internet. If you want to do so, my recommendation is to check the ARM official download page and choose which one fits your purpose.

Next, we will install some more package dependencies. Some of these packages are build tools needed to compile Qt6 that you might or might not have.

sudo apt-get install make build-essential libclang-dev ninja-build gcc git bison python3 gperf pkg-config libfontconfig1-dev libfreetype6-dev libx11-dev libx11-xcb-dev libxext-dev libxfixes-dev libxi-dev libxrender-dev libxcb1-dev libxcb-glx0-dev libxcb-keysyms1-dev libxcb-image0-dev libxcb-shm0-dev libxcb-icccm4-dev libxcb-sync-dev libxcb-xfixes0-dev libxcb-shape0-dev libxcb-randr0-dev libxcb-render-util0-dev libxcb-util-dev libxcb-xinerama0-dev libxcb-xkb-dev libxkbcommon-dev libxkbcommon-x11-dev libatspi2.0-dev libgl1-mesa-dev libglu1-mesa-dev freeglut3-dev

To wrap this section up, we will build a Sysroot from our own Raspberry Pi device. To do this, we will copy and paste a few directories from Raspberry Pi using rsync through SSH. If rsync is not installed yet in your host machine, simply install it by executing

sudo apt install rsync

. After the host machine and Raspberry Pi is connected,

rsync -avz --rsync-path="sudo rsync" --delete pi@169.254.187.77:/lib sysroot && rsync -avz --rsync-path="sudo rsync" --delete pi@169.254.187.77:/usr/include sysroot/usr && rsync -avz --rsync-path="sudo rsync" --delete pi@169.254.187.77:/usr/lib sysroot/usr && rsync -avz --rsync-path="sudo rsync" --delete pi@169.254.187.77:/opt/vc sysroot/opt

Note: Your Raspberry Pi might not have a directory named

/opt/vc

, and it is fine. Usually this directory contains proprietary Broadcom libraries, but during the testing the author did not find an issue with the lack of this directory. After building our own sysroot, we need to fix absolute symbolic links that were broken during the syncing process by converting them to relative symlinks. The easiest, fastest way to do this is to use a command-line tool called

symlinks

, which is available from the Ubuntu official repository. Check the symlinks documentation to learn more.

sudo apt install symlinks
cd ~
symlinks -rc rpi-sysroot

Building Qt 6

After all the setup process, finally we can start building Qt 6! This will be divided into two parts: Building Qt 6 for host machine, and building Qt 6 for our target device (i.e. the Raspberry Pi).

Building Qt 6 for Host Machine

For the detailed step-by-steps of this process, I will refer to this great wiki article that explained the whole process in detail. One thing to remember is that we will install Qt on

~/qt-host

, and we want to store all build configuration files on

~/qt-hostbuild

.

The rest of the guide is quite straightforward, so I will leave you to read the article.

Building Qt 6 for Target Device

This is the interesting part. We will compile Qt 6 on a host machine, store it temporarily in the host machine, and send it to the Raspberry Pi. The instruction for configuring and building are similar to building Qt 6 for host machine, but there are some things we need to tweak to get the intended results.

First, we want to create our own CMake toolchain file. This is important to link the right compilers and libraries so that CMake can produces the suitable Qt build for Raspberry Pi. For this guide, we will use the following CMake code to a text editor and save it as

toolchain.cmake

.

cmake_minimum_required(VERSION 3.18)
include_guard(GLOBAL)

set(CMAKE_SYSTEM_NAME Linux)
set(CMAKE_SYSTEM_PROCESSOR arm)

set(TARGET_SYSROOT /home/uraihan/rpi-sysroot)
set(CMAKE_SYSROOT ${TARGET_SYSROOT})

set(ENV{PKG_CONFIG_PATH} $PKG_CONFIG_PATH:/usr/lib/aarch64-linux-gnu/pkgconfig)
set(ENV{PKG_CONFIG_LIBDIR} /usr/lib/pkgconfig:/usr/share/pkgconfig/:${TARGET_SYSROOT}/usr/lib/aarch64-linux-gnu/pkgconfig:${TARGET_SYSROOT}/usr/lib/pkgconfig)
set(ENV{PKG_CONFIG_SYSROOT_DIR} ${CMAKE_SYSROOT})

set(CMAKE_C_COMPILER /usr/bin/aarch64-linux-gnu-gcc-9)
set(CMAKE_CXX_COMPILER /usr/bin/aarch64-linux-gnu-g++-9)

set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -I${TARGET_SYSROOT}/usr/include")
set(CMAKE_CXX_FLAGS "${CMAKE_C_FLAGS}")

set(QT_COMPILER_FLAGS "-march=armv8-a")
set(QT_COMPILER_FLAGS_RELEASE "-O2 -pipe")
set(QT_LINKER_FLAGS "-Wl,-O1 -Wl,--hash-style=gnu -Wl,--as-needed")

set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)
set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE)
set(CMAKE_BUILD_RPATH ${TARGET_SYSROOT})


include(CMakeInitializeConfigs)

function(cmake_initialize_per_config_variable _PREFIX _DOCSTRING)
    if (_PREFIX MATCHES "CMAKE_(C|CXX|ASM)_FLAGS")
        set(CMAKE_${CMAKE_MATCH_1}_FLAGS_INIT "${QT_COMPILER_FLAGS}")
        
        foreach (config DEBUG RELEASE MINSIZEREL RELWITHDEBINFO)
            if (DEFINED QT_COMPILER_FLAGS_${config})
                set(CMAKE_${CMAKE_MATCH_1}_FLAGS_${config}_INIT "${QT_COMPILER_FLAGS_${config}}")
            endif()
        endforeach()
    endif()


    if (_PREFIX MATCHES "CMAKE_(SHARED|MODULE|EXE)_LINKER_FLAGS")
        foreach (config SHARED MODULE EXE)
            set(CMAKE_${config}_LINKER_FLAGS_INIT "${QT_LINKER_FLAGS}")
        endforeach()
    endif()

    _cmake_initialize_per_config_variable(${ARGV})
endfunction()

set(XCB_PATH_VARIABLE ${TARGET_SYSROOT})

set(GL_INC_DIR ${TARGET_SYSROOT}/usr/include)
set(GL_LIB_DIR ${TARGET_SYSROOT}:${TARGET_SYSROOT}/usr/lib/aarch64-linux-gnu/:${TARGET_SYSROOT}/usr:${TARGET_SYSROOT}/usr/lib)

set(EGL_INCLUDE_DIR ${GL_INC_DIR})
set(EGL_LIBRARY ${XCB_PATH_VARIABLE}/usr/lib/aarch64-linux-gnu/libEGL.so)

set(OPENGL_INCLUDE_DIR ${GL_INC_DIR})
set(OPENGL_opengl_LIBRARY ${XCB_PATH_VARIABLE}/usr/lib/aarch64-linux-gnu/libOpenGL.so)

set(GLESv2_INCLUDE_DIR ${GL_INC_DIR})
set(GLIB_LIBRARY ${XCB_PATH_VARIABLE}/usr/lib/aarch64-linux-gnu/libGLESv2.so)

set(GLESv2_INCLUDE_DIR ${GL_INC_DIR})
set(GLESv2_LIBRARY ${XCB_PATH_VARIABLE}/usr/lib/aarch64-linux-gnu/libGLESv2.so)

set(gbm_INCLUDE_DIR ${GL_INC_DIR})
set(gbm_LIBRARY ${XCB_PATH_VARIABLE}/usr/lib/aarch64-linux-gnu/libgbm.so)

set(Libdrm_INCLUDE_DIR ${GL_INC_DIR})
set(Libdrm_LIBRARY ${XCB_PATH_VARIABLE}/usr/lib/aarch64-linux-gnu/libdrm.so)

set(XCB_XCB_INCLUDE_DIR ${GL_INC_DIR})
set(XCB_XCB_LIBRARY ${XCB_PATH_VARIABLE}/usr/lib/aarch64-linux-gnu/libxcb.so)

set(XCB_RENDER_INCLUDE_DIR ${GL_INC_DIR})
set(XCB_RENDER_LIBRARY ${XCB_PATH_VARIABLE}/usr/lib/aarch64-linux-gnu/libxcb-render.so)

set(XCB_SHAPE_INCLUDE_DIR ${GL_INC_DIR})
set(XCB_SHAPE_LIBRARY ${XCB_PATH_VARIABLE}/usr/lib/aarch64-linux-gnu/libxcb-shape.so)

set(XCB_XFIXES_INCLUDE_DIR ${GL_INC_DIR})
set(XCB_XFIXES_LIBRARY ${XCB_PATH_VARIABLE}/usr/lib/aarch64-linux-gnu/libxcb-xfixes.so)

set(XCB_SHM_INCLUDE_DIR ${GL_INC_DIR})
set(XCB_SHM_LIBRARY ${XCB_PATH_VARIABLE}/usr/lib/aarch64-linux-gnu/libxcb-shm.so)

set(XCB_COMPOSITE_INCLUDE_DIR ${GL_INC_DIR})
set(XCB_COMPOSITE_LIBRARY ${XCB_PATH_VARIABLE}/usr/lib/aarch64-linux-gnu/libxcb-composite.so)

set(XCB_CURSOR_INCLUDE_DIR ${GL_INC_DIR})
set(XCB_CURSOR_LIBRARY ${XCB_PATH_VARIABLE}/usr/lib/aarch64-linux-gnu/libxcb-cursor.so)

set(XCB_DAMAGE_INCLUDE_DIR ${GL_INC_DIR})
set(XCB_DAMAGE_LIBRARY ${XCB_PATH_VARIABLE}/usr/lib/aarch64-linux-gnu/libxcb-damage.so)

set(XCB_DPMS_INCLUDE_DIR ${GL_INC_DIR})
set(XCB_DPMS_LIBRARY ${XCB_PATH_VARIABLE}/usr/lib/aarch64-linux-gnu/libxcb-dpms.so)

set(XCB_GLX_INCLUDE_DIR ${GL_INC_DIR})
set(XCB_GLX_LIBRARY ${XCB_PATH_VARIABLE}/usr/lib/aarch64-linux-gnu/libxcb-glx.so)

set(XCB_ICCCM_INCLUDE_DIR ${GL_INC_DIR})
set(XCB_ICCCM_LIBRARY ${XCB_PATH_VARIABLE}/usr/lib/aarch64-linux-gnu/libxcb-icccm.so)

set(XCB_IMAGE_INCLUDE_DIR ${GL_INC_DIR})
set(XCB_IMAGE_LIBRARY ${XCB_PATH_VARIABLE}/usr/lib/aarch64-linux-gnu/libxcb-image.so)

set(XCB_KEYSYMS_INCLUDE_DIR ${GL_INC_DIR})
set(XCB_KEYSYMS_LIBRARY ${XCB_PATH_VARIABLE}/usr/lib/aarch64-linux-gnu/libxcb-keysyms.so)

set(XCB_PRESENT_INCLUDE_DIR ${GL_INC_DIR})
set(XCB_PRESENT_LIBRARY ${XCB_PATH_VARIABLE}/usr/lib/aarch64-linux-gnu/libxcb-present.so)

set(XCB_RANDR_INCLUDE_DIR ${GL_INC_DIR})
set(XCB_RANDR_LIBRARY ${XCB_PATH_VARIABLE}/usr/lib/aarch64-linux-gnu/libxcb-randr.so)

set(XCB_RECORD_INCLUDE_DIR ${GL_INC_DIR})
set(XCB_RECORD_LIBRARY ${XCB_PATH_VARIABLE}/usr/lib/aarch64-linux-gnu/libxcb-record.so)

set(XCB_RENDERUTIL_INCLUDE_DIR ${GL_INC_DIR})
set(XCB_RENDERUTIL_LIBRARY ${XCB_PATH_VARIABLE}/usr/lib/aarch64-linux-gnu/libxcb-render-util.so)

set(XCB_RES_INCLUDE_DIR ${GL_INC_DIR})
set(XCB_RES_LIBRARY ${XCB_PATH_VARIABLE}/usr/lib/aarch64-linux-gnu/libxcb-res.so)

set(XCB_SCREENSAVER_INCLUDE_DIR ${GL_INC_DIR})
set(XCB_SCREENSAVER_LIBRARY ${XCB_PATH_VARIABLE}/usr/lib/aarch64-linux-gnu/libxcb-screensaver.so)

set(XCB_SYNC_INCLUDE_DIR ${GL_INC_DIR})
set(XCB_SYNC_LIBRARY ${XCB_PATH_VARIABLE}/usr/lib/aarch64-linux-gnu/libxcb-sync.so)

set(XCB_UTIL_INCLUDE_DIR ${GL_INC_DIR})
set(XCB_UTIL_LIBRARY ${XCB_PATH_VARIABLE}/usr/lib/aarch64-linux-gnu/libxcb-util.so)

set(XCB_XF86DRI_INCLUDE_DIR ${GL_INC_DIR})
set(XCB_XF86DRI_LIBRARY ${XCB_PATH_VARIABLE}/usr/lib/aarch64-linux-gnu/libxcb-xf86dri.so)

set(XCB_XKB_INCLUDE_DIR ${GL_INC_DIR})
set(XCB_XKB_LIBRARY ${XCB_PATH_VARIABLE}/usr/lib/aarch64-linux-gnu/libxcb-xkb.so)

set(XCB_XTEST_INCLUDE_DIR ${GL_INC_DIR})
set(XCB_XTEST_LIBRARY ${XCB_PATH_VARIABLE}/usr/lib/aarch64-linux-gnu/libxcb-xtest.so)

set(XCB_XV_INCLUDE_DIR ${GL_INC_DIR})
set(XCB_XV_LIBRARY ${XCB_PATH_VARIABLE}/usr/lib/aarch64-linux-gnu/libxcb-xv.so)

set(XCB_XVMC_INCLUDE_DIR ${GL_INC_DIR})
set(XCB_XVMC_LIBRARY ${XCB_PATH_VARIABLE}/usr/lib/aarch64-linux-gnu/libxcb-xvmc.so)

set(XCB_XINPUT_INCLUDE_DIR ${GL_INC_DIR})
set(XCB_XINPUT_LIBRARY ${XCB_PATH_VARIABLE}/usr/lib/aarch64-linux-gnu/libxcb-xinput.so)

set(XKB_INCLUDE_DIR ${GL_INC_DIR})
set(XKB_LIBRARY ${XCB_PATH_VARIABLE}/usr/lib/aarch64-linux-gnu/libxkbcommon.so)

set(XCB_DRI2_INCLUDE_DIR ${GL_INC_DIR})
set(XCB_DRI2_LIBRARY ${XCB_PATH_VARIABLE}/usr/lib/aarch64-linux-gnu/libxcb-dri2.so)

set(XCB_DRI3_INCLUDE_DIR ${GL_INC_DIR})
set(XCB_DRI3_LIBRARY ${XCB_PATH_VARIABLE}/usr/lib/aarch64-linux-gnu/libxcb-dri3.so)

set(X11_XCB_INCLUDE_DIR ${GL_INC_DIR})
set(X11_XCB_LIBRARY ${XCB_PATH_VARIABLE}/usr/lib/aarch64-linux-gnu/libX11-xcb.so)

set(X11_X11_INCLUDE_PATH ${GL_INC_DIR})
set(X11_X11_LIB ${XCB_PATH_VARIABLE}/usr/lib/aarch64-linux-gnu/libX11.so)

Now that we have our toolchain, as well as the cross compiler and sysroot, we can continue with configuring and building Qt for our Raspberry Pi! As decided in the planning process, we will put all build configuration files on

qtpi-build

, so let's

cd

into that directory:

cd ~/qtpi-build

Now, we can run the configuration command inside this directory.

../qt5/configure -release -opengl es2 -nomake examples -nomake tests -qt-host-path $HOME/qt-host -extprefix $HOME/qt-raspi -prefix /usr/local/qt6 -- -DCMAKE_TOOLCHAIN_FILE=$HOME/toolchain.cmake -DQT_FEATURE_brotli=OFF -DQT_FEATURE_libudev=OFF -DQT_QMAKE_TARGET_MKSPEC=devices/linux-rasp-pi4-v3d-g++ -DQT_FEATURE_xcb=ON -DFEATURE_xcb_xlib=ON -DQT_FEATURE_xlib=ON -DFEATURE_dbus=OFF

Command above will run the configuration file that came with the Qt source code and complementing it with the toolchain that we just created. This is equivalent to this CMake command:

cmake ../qt5/ -GNinja -DCMAKE_BUILD_TYPE=Release -DINPUT_opengl=es2 -DQT_BUILD_EXAMPLES=OFF -DQT_BUILD_TESTS=OFF -DQT_HOST_PATH=$HOME/qt-host -DCMAKE_STAGING_PREFIX=$HOME/qt-raspi -DCMAKE_INSTALL_PREFIX=/usr/local/qt6 -DCMAKE_TOOLCHAIN_FILE=$HOME/toolchain.cmake -DQT_FEATURE_brotli=OFF -DQT_FEATURE_libudev=OFF -DQT_QMAKE_TARGET_MKSPEC=devices/linux-rasp-pi4-v3d-g++ -DQT_FEATURE_xcb=ON -DFEATURE_xcb_xlib=ON -DQT_FEATURE_xlib=ON -DFEATURE_dbus=OFF

Note: During the testing process, it was found that the DBus installation inside our sysroot was broken, so it was decided to exclude this feature from the build, hence the

-DFEATURE_dbus=OFF

flag. Your mileage may vary, and we will try to update this page once we found out why. These commands will configure Qt to be installed on

qt-raspi

folder on the host machine, with expectation that it will populate

usr/local/qt6

on the Raspberry Pi. The Qt installation from this build will be configured to run on the ARM64 architecture. You can make sure by running

file ~/qt-raspi/bin/qt-cmake

on terminal after installing. Then proceeds with building and installing.

cmake --build . --parallel 4
cmake --install .

After Qt is successfully installed on

~/qt-raspi

, we will then send this Qt installation back to the Raspberry Pi. To do this, we can use

rsync

as we did when building sysroot, or

scp

. Both will accomplish the same thing, and there should be no significant difference between both of them. To use

rsync

:

rsync -avz --rsync-path="sudo rsync" /home/uraihan/qt-raspi pi@169.254.187.77:/usr/local/qt6

To use

scp

:

cd ~/qt-raspi
scp -r * pi@169.254.187.77:/usr/local/qt6

Final Configuration on Raspberry Pi

To ensure our Qt 6 installation can be run on Raspberry Pi, we need to setup a few environment variables. All of this can be done on the host device via SSH.

ssh pi@169.254.187.77
## enter your raspberry pi user password, if prompted
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/qt6/lib/

This is the most important environment variable that we need to set. If you intend to run the application through SSH from your host machine and see the application running on a monitor that is connected to the Raspberry Pi, you need to execute

export DISPLAY=:0

in addition to the commands above.