Cross Compiling Qt6 (64bit) - LLdaniel/StellwerkQt GitHub Wiki

Updated instructions for cross compiling Qt for RaspberryPi (armhf)

Last test with Qt6.5 on Raspberry Pi 3B+ and PiOS Bullseye or Bookworm (64bit). Host system was Debian Bullseye or Bookworm. Adapted from Qt Wiki Cross-Compile Qt6

1. [Pi] Installation prequesites

sudo apt update
sudo apt full-upgrade
sudo reboot

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

# libgst-dev not available on Debian Bookworm, not an issue here
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

# get egl libraries with a firmware update, they will be saved in /opt/vc
sudo rpi-update

# here goes the qt Pi installation
sudo mkdir /usr/local/qt6

2. [Host] Installation prequesites

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

sudo apt update
sudo apt upgrade

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

# install cross compiler
sudo apt install gcc-aarch64-linux-gnu g++-aarch64-linux-gnu

3. [Host] Build sysroot

cd ~/raspi
rsync -avz --rsync-path="sudo rsync" --delete fdl@estw:/lib sysroot; rsync -avz --rsync-path="sudo rsync" --delete fdl@estw:/usr/include sysroot/usr; rsync -avz --rsync-path="sudo rsync" --delete fdl@estw:/usr/lib sysroot/usr; rsync -avz --rsync-path="sudo rsync" --delete fdl@estw:/opt/vc sysroot/opt

4. [Host] Change absolute links to relative ones (needed later)

sudo apt install symlinks
symlinks -rc sysroot

5. [Host] Get Qt6

cd ~/raspi
git clone "https://codereview.qt-project.org/qt/qt5"
cd qt5/
git checkout 6.5
perl init-repository --module-subset=qtbase,qtsvg,qtqa -f
cd ../qt-hostbuild
qt-hostbuild
# dbus failed, therefore left out
cmake ../qt5/ -GNinja -DCMAKE_BUILD_TYPE=Release -DQT_BUILD_EXAMPLES=OFF -DQT_BUILD_TESTS=OFF -DCMAKE_INSTALL_PREFIX=$HOME/raspi/qt-host -DFEATURE_dbus=OFF 
cmake --build . --parallel 8
cmake --install .

6. [Host] Create a toolchain file 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/daniel/raspi/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})

# if you use other version of gcc and g++ than gcc/g++ 9, you must change the following variables
# bookworm
set(CMAKE_C_COMPILER /usr/bin/aarch64-linux-gnu-gcc-12)
set(CMAKE_CXX_COMPILER /usr/bin/aarch64-linux-gnu-g++-12)
# bullseye
#set(CMAKE_C_COMPILER /usr/bin/aarch64-linux-gnu-gcc-10)
#set(CMAKE_CXX_COMPILER /usr/bin/aarch64-linux-gnu-g++-10)

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 -ldbus-1")

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)

7. [Host] Configure Qt Essentials in a new directory

cd ../qtpi-build/
../qt5/configure -release -opengl es2 -nomake examples -nomake tests -qt-host-path $HOME/raspi/qt-host -extprefix $HOME/raspi/qt-raspi -prefix /usr/local/qt6 -device linux-rasp-pi4-aarch64 -device-option CROSS_COMPILE=aarch64-linux-gnu- -- -DCMAKE_TOOLCHAIN_FILE=$HOME/raspi/toolchain.cmake -DQT_FEATURE_xcb=ON -DFEATURE_xcb_xlib=ON -DQT_FEATURE_xlib=ON -DFEATURE_dbus=OFF

cmake --build . --parallel 8
cmake --install .

8. [Host] Build submodules

cd ~/raspi/qtpi-build/
./qt-raspi/bin/qt-cmake ../qt5/qtsvg/CMakeLists.txt
cmake --build . --parallel 8
cmake --install ../qt5/qtsvg/

cd ~/raspi/qtpi-build/
./qt-raspi/bin/qt-cmake ../qt5/qtqa/CMakeLists.txt
cmake --build . --parallel 8
cmake --install ../qt5/qtqa

9. [Pi] Build wiringPi

Building wiringPi on armhf to get libwiringPi.so.2.70.

file raspi/sysroot/usr/lib/libwiringPi.so.2.70 
raspi/sysroot/usr/lib/libwiringPi.so.2.70: ELF 64-bit LSB shared object, ARM aarch64, version 1 (SYSV), dynamically linked, BuildID[sha1]=783b6e05735e298b44504c49623cc2e7b5c301d5, not stripped

10. [Host] Replace symlinks for wiringPi (maybe a problem due to wiringPi build call on amd64 laptop)

cd /usr/local/lib/
scp fdl@estw:/usr/local/lib/libwiringPi.so.2.70 fdl@estw:/usr/local/lib/libwiringPiDev.so.2.70 .
chown daniel:daniel libwiringPi.so.2.70

11. [Host] Fix missing header files form wiringPi: wiringPi.h, mcp23017.h, sr595.h

Compiler errors finding no header files. Currently fixed with a copy in source code directory.

cd ~/Documents/StellwerkQt
cp WiringPi/wiringPi/sr595.h .
cp WiringPi/wiringPi/mcp23017.h .
cp WiringPi/wiringPi/sr595.h .

12. [Host] Change StellwerkQt.pro file to CMakeLists.txt

Due to the usage of cmake in Qt6 we need a CMakeLists.txt. Initially it was generated from StellwerkQt.pro with the provided script. See qmake2cmake

cd ~/Documents/StellwerkQt/
~/raspi/qt-raspi/bin/qt-cmake CMakeLists.txt
cmake --build . --parallel 8
cmake --install .

13. [Host] Sync back Qt6 for Pi

rsync -avz --rsync-path="sudo rsync" qt-raspi/* fdl@estw:/usr/local/qt6

14. [Pi] OpenGL parameter

Adding this to ~/.bashrc

export QT_QPA_EGLFS_PHYSICAL_WIDTH=<width> #in [mm]
export QT_QPA_EGLFS_PHYSICAL_HEIGHT=<height> #in [mm]
export QT_QPA_FONT_DIR=/usr/share/fonts/truetype/dejavu
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/qt6/lib/
⚠️ **GitHub.com Fallback** ⚠️