RaspberryPiWithQt6WebEngine: Difference between revisions
(add note) |
Ariacorrente (talk | contribs) m (Install libnss3-dev in the target system before exiting the chroot) |
||
(23 intermediate revisions by one other user not shown) | |||
Line 21: | Line 21: | ||
In this guide we are going to cross compile Qt 6.5 with WebEngine coming from Qt 6.7 | In this guide we are going to cross compile Qt 6.5 with WebEngine coming from Qt 6.7 | ||
{{note | As shown [[Cross-Compile_Qt_6_for_Raspberry_Pi | here]], we could do a top level build of Qt6, but we are going to do prefix module | {{note | As shown [[Cross-Compile_Qt_6_for_Raspberry_Pi | here]], we could do a 'top level build' of Qt6, but we are going to do 'prefix module build' just to show an alternative way of building Qt6.}} | ||
We need fours repositories to have Qt 6WebEngine up and running: qtbase, shadertools, qtdeclarative and qtwebengine. | We need fours repositories to have Qt 6WebEngine up and running: qtbase, shadertools, qtdeclarative and qtwebengine. | ||
* Let's create our workspace:<syntaxhighlight> | * Let's create our workspace:<syntaxhighlight lang="bash"> | ||
mkdir -p ~/workspaces/rpi/ | mkdir -p ~/workspaces/rpi/toolchain/sysroot | ||
mkdir -p ~/workspaces/rpi/host | mkdir -p ~/workspaces/rpi/toolchain/qt/build/host | ||
mkdir -p ~/workspaces/rpi/ | mkdir -p ~/workspaces/rpi/toolchain/qt/build/target | ||
mkdir -p ~/workspaces/rpi/target | mkdir -p ~/workspaces/rpi/target | ||
mkdir -p ~/workspaces/rpi/image | mkdir -p ~/workspaces/rpi/image | ||
</syntaxhighlight> | </syntaxhighlight> | ||
* Let's checkout qt source code and select branches:<syntaxhighlight> | * Let's checkout qt source code and select branches:<syntaxhighlight lang="bash"> | ||
cd ~/workspaces/rpi/ | cd ~/workspaces/rpi/toolchain/qt | ||
git clone git://code.qt.io/qt/qtbase.git | git clone git://code.qt.io/qt/qtbase.git | ||
cd qtbase | cd qtbase | ||
git checkout origin/6.5.3 | |||
cd .. | cd .. | ||
Line 51: | Line 51: | ||
git clone git://code.qt.io/qt/qtwebengine.git | git clone git://code.qt.io/qt/qtwebengine.git | ||
cd qtwebengine | |||
git checkout origin/6.7 | git checkout origin/6.7 | ||
git submodule init | |||
git submodule update | git submodule update | ||
cd .. | cd .. | ||
Line 65: | Line 67: | ||
{{note|We do need a local copy of 'libs' and 'headers' from the image, as we want to adjust the symlinks.}} | {{note|We do need a local copy of 'libs' and 'headers' from the image, as we want to adjust the symlinks.}} | ||
* Let's now download Raspberry Pi OS:<syntaxhighlight> | * Let's now download Raspberry Pi OS:<syntaxhighlight lang="bash"> | ||
cd ~/workspaces/rpi/image | cd ~/workspaces/rpi/image | ||
wget https://downloads.raspberrypi.com/raspios_arm64/images/raspios_arm64-2023-12-06/2023-12-05-raspios-bookworm-arm64.img.xz | wget https://downloads.raspberrypi.com/raspios_arm64/images/raspios_arm64-2023-12-06/2023-12-05-raspios-bookworm-arm64.img.xz | ||
</syntaxhighlight> | </syntaxhighlight> | ||
* Let's extract the image:<syntaxhighlight> | * Let's extract the image:<syntaxhighlight lang="bash"> | ||
unxz --keep 2023-12-05-raspios-bookworm-arm64.img.xz | unxz --keep 2023-12-05-raspios-bookworm-arm64.img.xz | ||
</syntaxhighlight> | </syntaxhighlight> | ||
* We need add at least 2G space to the image to be able to fit qt build with debug info [[ResizeRaspberryPiImage| (see here instructions) ]] | * We need add at least 2G space to the image to be able to fit qt build with debug info [[ResizeRaspberryPiImage| (see here instructions) ]] | ||
* Make loop devices for the image:<syntaxhighlight> | * Make loop devices for the image:<syntaxhighlight lang="bash"> | ||
losetup -fP 2023-12-05-raspios-bookworm-arm64.img | losetup -fP 2023-12-05-raspios-bookworm-arm64.img | ||
losetup -a | losetup -a | ||
Line 81: | Line 83: | ||
</syntaxhighlight> | </syntaxhighlight> | ||
* Mount the root partition:<syntaxhighlight> | * Mount the root partition:<syntaxhighlight lang="bash"> | ||
mount /dev/loop0p2 -t ext4 ~/workspaces/rpi/target | mount /dev/loop0p2 -t ext4 ~/workspaces/rpi/target | ||
mount -t proc /proc ~/workspaces/rpi/target/proc | mount -t proc /proc ~/workspaces/rpi/target/proc | ||
mount -t sysfs /sys ~/workspaces/rpi/target/sys | mount -t sysfs /sys ~/workspaces/rpi/target/sys | ||
mount --bind /dev ~/workspaces/rpi/target/dev | mount --bind /dev ~/workspaces/rpi/target/dev | ||
mount --bind /dev/pts ~/workspaces/rpi/target/pts | mount --bind /dev/pts ~/workspaces/rpi/target/dev/pts | ||
</syntaxhighlight> | </syntaxhighlight> | ||
* We need qemu on the image to able to execute command, therefore copy static qemu binary to image.<syntaxhighlight> | * We need qemu on the image to able to execute command, therefore copy static qemu binary to image.<syntaxhighlight lang="bash"> | ||
cp /usr/bin/qemu- | cp /usr/bin/qemu-aarch64-static ~/workspaces/rpi/target/usr/bin/ | ||
</syntaxhighlight> | </syntaxhighlight> | ||
{{note| Setup of qemu static interpreter is distribution specific. Please refer to your Linux distribution documentation.}} | {{note| Setup of qemu static interpreter is distribution specific. Please refer to your Linux distribution documentation.}} | ||
* Chroot to arm64 target:<syntaxhighlight> | * Chroot to arm64 target:<syntaxhighlight lang="bash"> | ||
cd ~/workspaces/rpi/target | cd ~/workspaces/rpi/target | ||
chroot . | chroot . | ||
</syntaxhighlight> | </syntaxhighlight> | ||
* Let's | * Let's upgrade the image (optional) and install Qt6 build dependencies:<syntaxhighlight lang="bash"> | ||
vi /etc/apt/sources.list | vi /etc/apt/sources.list | ||
# uncomment the deb-src | # uncomment the deb-src lines | ||
apt update | apt update | ||
apt build-dep | apt upgrade | ||
apt build-dep libqt6gui6 | |||
</syntaxhighlight> | |||
* Let's install build dependencies for QtWebEngine:<syntaxhighlight lang="bash"> | |||
apt install libnss3-dev | |||
exit | exit | ||
</syntaxhighlight> | </syntaxhighlight> | ||
* rsync the parts that we need:<syntaxhighlight> | * rsync the parts that we need:<syntaxhighlight lang="bash"> | ||
cd ~/workspaces/rpi/ | cd ~/workspaces/rpi/toolchain | ||
rsync -av ~/workspaces/rpi/target/lib sysroot | rsync -av ~/workspaces/rpi/target/lib sysroot | ||
rsync -av ~/workspaces/rpi/target/usr/include sysroot/usr | rsync -av ~/workspaces/rpi/target/usr/include sysroot/usr | ||
rsync -av ~/workspaces/rpi/target/usr/lib sysroot/usr | rsync -av ~/workspaces/rpi/target/usr/lib sysroot/usr | ||
rsync -av ~/workspaces/rpi/target/usr/share/pkgconfig sysroot/usr/share | |||
</syntaxhighlight> | </syntaxhighlight> | ||
* Adjust symlinks to be relative:<syntaxhighlight> | * Adjust symlinks to be relative:<syntaxhighlight lang="bash"> | ||
wget https://raw.githubusercontent.com/Kukkimonsuta/rpi-buildqt/master/scripts/utils/sysroot-relativelinks.py | wget https://raw.githubusercontent.com/Kukkimonsuta/rpi-buildqt/master/scripts/utils/sysroot-relativelinks.py | ||
chmod +x sysroot-relativelinks.py | chmod +x sysroot-relativelinks.py | ||
Line 122: | Line 130: | ||
{{note| Command-line tool called [https://linux.die.net/man/8/symlinks symlinks] should not be used instead as it creates dangling links.}} | {{note| Command-line tool called [https://linux.die.net/man/8/symlinks symlinks] should not be used instead as it creates dangling links.}} | ||
* Umount no longer needed mounts:<syntaxhighlight> | * Umount no longer needed mounts:<syntaxhighlight lang="bash"> | ||
umount ~/workspaces/rpi/target/sys ~/workspaces/rpi/target/proc | umount ~/workspaces/rpi/target/sys ~/workspaces/rpi/target/proc | ||
umount ~/workspaces/rpi/target/dev/pts ~/workspaces/rpi/target/dev | umount ~/workspaces/rpi/target/dev/pts ~/workspaces/rpi/target/dev | ||
</syntaxhighlight> | </syntaxhighlight> | ||
* Detach loop device:<syntaxhighlight> | * Detach loop device:<syntaxhighlight lang="bash"> | ||
losetup -d /dev/loop0 | losetup -d /dev/loop0 | ||
</syntaxhighlight> | </syntaxhighlight> | ||
Line 133: | Line 141: | ||
==Toolchain== | ==Toolchain== | ||
To cross-compile Qt, we need a cross-compiler toolchain. There are many excellent tools to compile a toolchain, such as crosstool-ng | To cross-compile Qt, we need a cross-compiler toolchain. There are many excellent tools to compile a toolchain, such as [https://crosstool-ng.github.io crosstool-ng]. We could also simply download ready 3dparty toolchain form the internet. However, this guide will use the official gcc cross compiler, which is shipped with Debian distribution, same as the one shipped with Raspberry Pi OS. | ||
We could also simply download ready 3dparty toolchain form the internet. However, this guide will use the official gcc cross compiler, which is | |||
shipped with Debian distribution, same as the one shipped with Raspberry Pi OS. | |||
In time of writing this quide latest Raspberry Pi OS is called 'Bookworm' and it is shipped with gcc 12.2 and Qt 6.4. Therefore we will use the gnu gcc cross compiler from Bookworm release. | In time of writing this quide latest Raspberry Pi OS is called 'Bookworm' and it is shipped with gcc 12.2 and Qt 6.4. Therefore we will use the gnu gcc cross compiler from Bookworm release. | ||
To setup the cross-compiler toolchain will use 'debootstrap' which is a very convenient tool to install Debian base system into a subdirectory | To setup the cross-compiler toolchain will use 'debootstrap' which is a very convenient tool to install Debian base system into a subdirectory | ||
Line 142: | Line 148: | ||
{{note | The other approach could be for example installing Debian distribution on VM.}} | {{note | The other approach could be for example installing Debian distribution on VM.}} | ||
* To setup Bookworm Debian release on your machine execute:<syntaxhighlight> | * To setup Bookworm Debian release on your machine execute:<syntaxhighlight lang="bash"> | ||
debootstrap --arch amd64 bookworm ~/workspaces/rpi/toolchain http://ftp.uk.debian.org/debian | |||
debootstrap --arch amd64 bookworm ~/ | |||
</syntaxhighlight> | </syntaxhighlight> | ||
* Let's mount and chroot into newly created installation:<syntaxhighlight> | * Let's mount and chroot into newly created installation:<syntaxhighlight lang="bash"> | ||
mount -t proc /proc ~/workspaces/rpi/ | mount -t proc /proc ~/workspaces/rpi/toolchain/proc | ||
mount -t sysfs /sys ~/workspaces/rpi/ | mount -t sysfs /sys ~/workspaces/rpi/toolchain/sys | ||
mount --bind /dev ~/workspaces/rpi/ | mount --bind /dev ~/workspaces/rpi/toolchain/dev | ||
mount --bind /dev/pts ~/workspaces/rpi/ | mount --bind /dev/pts ~/workspaces/rpi/toolchain/dev/pts | ||
chroot ~/workspaces/rpi/ | chroot ~/workspaces/rpi/toolchain /bin/bash | ||
</syntaxhighlight> | </syntaxhighlight> | ||
* Let's install host and cross compiler:<syntaxhighlight> | * Let's install host and cross compiler:<syntaxhighlight lang="bash"> | ||
apt update | |||
apt install build-essential crossbuild-essential-arm64 | apt install build-essential crossbuild-essential-arm64 | ||
</syntaxhighlight> | </syntaxhighlight> | ||
Line 162: | Line 168: | ||
==Qt6 Host Build== | ==Qt6 Host Build== | ||
We need Qt6 host build as cross-compilation requires all host compiled tools like for example 'moc'. | |||
We will do here qt 'module' build in separate build directory. | |||
* Let's install dependencies for build using know dependencies for Qt 6.4:<syntaxhighlight> | {{note | For more information about build options see [[QtWebEngine/Qt6Build| here]].}} | ||
{{note | After toolchain setup, we should be still chrooted into our host Debian root (~/workspaces/rpi/toolchain).}} | |||
* Add source packages repository for 'apt' by following line to '/etc/apt/sources.list' file:<syntaxhighlight lang="bash"> | |||
deb-src http://deb.debian.org/debian bookworm main | |||
</syntaxhighlight> | |||
* Let's install dependencies for Qt host build using know dependencies for Qt 6.4:<syntaxhighlight lang="bash"> | |||
apt update | apt update | ||
apt build-dep | apt build-dep libqt6gui6 | ||
</syntaxhighlight> | |||
* Let's install build dependencies for QtWebEngine:<syntaxhighlight lang="bash"> | |||
apt install nodejs gperf bison flex python3-html5lib libnss3-dev | |||
</syntaxhighlight> | |||
* Let's configure host build for Qt6 qtbase, build it and install into ~/workspaces/rpi/toolchain/opt/qt/host:<syntaxhighlight lang="bash"> | |||
cd /qt/build/host | |||
mkdir qtbase | |||
cd qtbase | |||
/qt/qtbase/configure -release -nomake tests -nomake examples -linker lld -prefix /opt/qt/host | |||
cmake --build . --parallel | |||
cmake --install . | |||
</syntaxhighlight> | |||
{{note | The path /qt/qtbase in chroot is really ~/workspaces/rpi/toolchain/qt/qtbase on the build machine.}} | |||
* Let's configure and build remaining modules:<syntaxhighlight lang="bash"> | |||
cd /qt/build/host | |||
mkdir qtshadertools qtdeclarative qtwebengine | |||
cd qtshadertools | |||
/opt/qt/host/bin/qt-configure-module ../../../qtshadertools | |||
cmake --build . --parallel | |||
cmake --install . | |||
cd .. | |||
cd qtdeclarative | |||
/opt/qt/host/bin/qt-configure-module ../../../qtdeclarative | |||
cmake --build . --parallel | |||
cmake --install . | |||
cd .. | |||
cd qtwebengine | |||
/opt/qt/host/bin/qt-configure-module ../../../qtwebengine | |||
cmake --build . --parallel | |||
cmake --install . | |||
cd .. | |||
</syntaxhighlight> | </syntaxhighlight> | ||
* Let's configure | ==Qt6 Target Cross Build== | ||
cd /qt/build | |||
We should have by now Qt6 host build, target arm64 sysroot and cross compilation toolchain. To setup now cmake build we still need to create [https://cmake.org/cmake/help/latest/manual/cmake-toolchains.7.html cmake toolchain file] 'rpi.toolchain.cmake', which will provide information to cmake about our toolchian and sysroot setup. | |||
{{note | After toolchain setup, we should be still chrooted into our host Debian root (~/workspaces/rpi/toolchain).}} | |||
* Let's create toolchain file:<syntaxhighlight lang="bash"> | |||
vi /qt/rpi.toolchain.cmake | |||
cmake_minimum_required(VERSION 3.18) | |||
include_guard(GLOBAL) | |||
set(CMAKE_SYSTEM_NAME Linux) | |||
set(CMAKE_SYSTEM_PROCESSOR arm) | |||
set(CMAKE_SYSROOT /sysroot) | |||
set(CMAKE_C_COMPILER /usr/bin/aarch64-linux-gnu-gcc-12) | |||
set(CMAKE_CXX_COMPILER /usr/bin/aarch64-linux-gnu-g++-12) | |||
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(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") | |||
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() | |||
# See output of 'pkg-config --variable pc_path pkg-config' command. | |||
set(ENV{PKG_CONFIG_PATH} "") | |||
set(ENV{PKG_CONFIG_LIBDIR} ${CMAKE_SYSROOT}/usr/lib/aarch64-linux-gnu/pkgconfig:${CMAKE_SYSROOT}/usr/lib/pkgconfig:${CMAKE_SYSROOT}/usr/share/pkgconfig) | |||
set(ENV{PKG_CONFIG_SYSROOT_DIR} ${CMAKE_SYSROOT}) | |||
</syntaxhighlight> | |||
{{note | If you wonder why we overload 'cmake_initialize_per_config_variable' see [https://www.qt.io/blog/standalone-boot2qt-/-yocto-sdk-cmake-toolchain this] blog post.}} | |||
{{note | The pkg-config exports could be set in build shell instead of toolchain.}} | |||
* Let's configure target build for Qt6 qtbase, build it and install into ~/workspaces/rpi/toolchain/opt/qt/target:<syntaxhighlight lang="bash"> | |||
cd /qt/build/target | |||
mkdir qtbase | mkdir qtbase | ||
cd qtbase | cd qtbase | ||
/ | ../../../qtbase/configure -release -opengl es2 -nomake examples -nomake tests -qt-host-path /opt/qt/host -extprefix /opt/qt/target -prefix /usr/local/qt6 -- -DCMAKE_TOOLCHAIN_FILE=/qt/rpi.toolchain.cmake | ||
cmake --build . --parallel | |||
cmake --install . | |||
</syntaxhighlight> | |||
* Let's configure and build remaining modules:<syntaxhighlight lang="bash"> | |||
cd /qt/build/target | |||
mkdir qtshadertools qtdeclarative qtwebengine | |||
cd qtshadertools | |||
/opt/qt/target/bin/qt-configure-module ../../../qtshadertools | |||
cmake --build . --parallel | |||
cmake --install . | |||
cd .. | |||
cd qtdeclarative | |||
/opt/qt/target/bin/qt-configure-module ../../../qtdeclarative | |||
cmake --build . --parallel | cmake --build . --parallel | ||
cmake --install | cmake --install . | ||
cd .. | |||
cd qtwebengine | |||
/opt/qt/target/bin/qt-configure-module ../../../qtwebengine | |||
cmake --build . --parallel | |||
cmake --install . | |||
cd .. | |||
</syntaxhighlight> | </syntaxhighlight> | ||
{{note | /qt/ | ==Deploy== | ||
We need to deploy compiled sources to sdcard. We can use RasberryPi OS image from sysroot step, mount it and rsync the content. | |||
{{note | We are not any longer in the chrooted enviroment, however target image is still mounted.}} | |||
* Deploy with rsync: <syntaxhighlight lang="bash"> | |||
rsync -av ~/workspaces/rpi/toolchain/opt/qt/target/ ~/workspaces/rpi/target/usr/local/qt6/ | |||
</syntaxhighlight> | |||
{{note| If you wnat to rsync sysroot over the network, just replace the rsync steps below with the equivalent network location of your Rasberry Pi board.}} | |||
* Umount the image and detach loop device:<syntaxhighlight lang="bash"> | |||
umount ~/workspaces/rpi/target/dev/pts ~/workspaces/rpi/target/dev | |||
umount ~/workspaces/rpi/target/proc ~/workspaces/rpi/target/sys | |||
umount ~/workspaces/rpi/target | |||
losetup -d /dev/loop0 | |||
</syntaxhighlight> | |||
* Copy the image to the SD card (replace sdX with the device on your machine):<syntaxhighlight lang="bash"> | |||
cd ~/workspaces/rpi/image | |||
dd if=2023-12-05-raspios-bookworm-arm64.img of=/dev/sdX bs=4M | |||
</syntaxhighlight> |
Latest revision as of 16:04, 2 March 2024
Introduction
This page describes how to set up self-compiled Qt6 with WebEngine on Raspberry Pi 4 running Raspberry Pi OS.
To see other guides visit:
- Qt5 WebEngine cross compilation guide for Raspbian
- Qt6 general cross compilation guide for Raspberry Pi OS
- Qt6 WebEngine general compilation quide for all platforms
Setup
To be able to cross compile Qt6 for Raspberry Pi OS, we need three things:
Qt6 uses cmake therefore to cross-compile we need to have actually two builds of Qt. One Qt6 host build, which is later used to cross-compile the arm64 Qt build.
In this guide we are going to cross compile Qt 6.5 with WebEngine coming from Qt 6.7
Note: As shown here, we could do a 'top level build' of Qt6, but we are going to do 'prefix module build' just to show an alternative way of building Qt6.
We need fours repositories to have Qt 6WebEngine up and running: qtbase, shadertools, qtdeclarative and qtwebengine.
- Let's create our workspace:
mkdir -p ~/workspaces/rpi/toolchain/sysroot mkdir -p ~/workspaces/rpi/toolchain/qt/build/host mkdir -p ~/workspaces/rpi/toolchain/qt/build/target mkdir -p ~/workspaces/rpi/target mkdir -p ~/workspaces/rpi/image
- Let's checkout qt source code and select branches:
cd ~/workspaces/rpi/toolchain/qt git clone git://code.qt.io/qt/qtbase.git cd qtbase git checkout origin/6.5.3 cd .. git clone git://code.qt.io/qt/qtshadertools.git cd qtshadertools git checkout origin/6.5.3 cd .. git clone git://code.qt.io/qt/qtdeclarative.git cd qtdeclarative git checkout origin/6.5.3 cd .. git clone git://code.qt.io/qt/qtwebengine.git cd qtwebengine git checkout origin/6.7 git submodule init git submodule update cd ..
Note: QtWebEngine needs initialization of the submodule.
Sysroot
To be able to cross-compile, we need a part of arm64 target sysroot to be present on our build machine. As shown here, you could simply start your Rasberry Pi OS on the board and then rsync the required libs and includes to the host machine with SSH connection. However, in this guide we will mount the Raspberry Pi OS image via a loop device, use qemu to install build dependencies and than make a local copy.
Note: We do need a local copy of 'libs' and 'headers' from the image, as we want to adjust the symlinks.
- Let's now download Raspberry Pi OS:
cd ~/workspaces/rpi/image wget https://downloads.raspberrypi.com/raspios_arm64/images/raspios_arm64-2023-12-06/2023-12-05-raspios-bookworm-arm64.img.xz
- Let's extract the image:
unxz --keep 2023-12-05-raspios-bookworm-arm64.img.xz
- We need add at least 2G space to the image to be able to fit qt build with debug info (see here instructions)
- Make loop devices for the image:
losetup -fP 2023-12-05-raspios-bookworm-arm64.img losetup -a /dev/loop0: [66306]:2363198 (~/workspaces/rpi/image/2023-12-05-raspios-bookworm-arm64.img)
- Mount the root partition:
mount /dev/loop0p2 -t ext4 ~/workspaces/rpi/target mount -t proc /proc ~/workspaces/rpi/target/proc mount -t sysfs /sys ~/workspaces/rpi/target/sys mount --bind /dev ~/workspaces/rpi/target/dev mount --bind /dev/pts ~/workspaces/rpi/target/dev/pts
- We need qemu on the image to able to execute command, therefore copy static qemu binary to image.
cp /usr/bin/qemu-aarch64-static ~/workspaces/rpi/target/usr/bin/
Note: Setup of qemu static interpreter is distribution specific. Please refer to your Linux distribution documentation.
- Chroot to arm64 target:
cd ~/workspaces/rpi/target chroot .
- Let's upgrade the image (optional) and install Qt6 build dependencies:
vi /etc/apt/sources.list # uncomment the deb-src lines apt update apt upgrade apt build-dep libqt6gui6
- Let's install build dependencies for QtWebEngine:
apt install libnss3-dev exit
- rsync the parts that we need:
cd ~/workspaces/rpi/toolchain rsync -av ~/workspaces/rpi/target/lib sysroot rsync -av ~/workspaces/rpi/target/usr/include sysroot/usr rsync -av ~/workspaces/rpi/target/usr/lib sysroot/usr rsync -av ~/workspaces/rpi/target/usr/share/pkgconfig sysroot/usr/share
- Adjust symlinks to be relative:
wget https://raw.githubusercontent.com/Kukkimonsuta/rpi-buildqt/master/scripts/utils/sysroot-relativelinks.py chmod +x sysroot-relativelinks.py ./sysroot-relativelinks.py sysroot
Note: Command-line tool called symlinks should not be used instead as it creates dangling links.
- Umount no longer needed mounts:
umount ~/workspaces/rpi/target/sys ~/workspaces/rpi/target/proc umount ~/workspaces/rpi/target/dev/pts ~/workspaces/rpi/target/dev
- Detach loop device:
losetup -d /dev/loop0
Toolchain
To cross-compile Qt, we need a cross-compiler toolchain. There are many excellent tools to compile a toolchain, such as crosstool-ng. We could also simply download ready 3dparty toolchain form the internet. However, this guide will use the official gcc cross compiler, which is shipped with Debian distribution, same as the one shipped with Raspberry Pi OS. In time of writing this quide latest Raspberry Pi OS is called 'Bookworm' and it is shipped with gcc 12.2 and Qt 6.4. Therefore we will use the gnu gcc cross compiler from Bookworm release. To setup the cross-compiler toolchain will use 'debootstrap' which is a very convenient tool to install Debian base system into a subdirectory of any other running Linux system. Most of distributions ship this tool therefore it was selected as most generic approach.
Note: The other approach could be for example installing Debian distribution on VM.
- To setup Bookworm Debian release on your machine execute:
debootstrap --arch amd64 bookworm ~/workspaces/rpi/toolchain http://ftp.uk.debian.org/debian
- Let's mount and chroot into newly created installation:
mount -t proc /proc ~/workspaces/rpi/toolchain/proc mount -t sysfs /sys ~/workspaces/rpi/toolchain/sys mount --bind /dev ~/workspaces/rpi/toolchain/dev mount --bind /dev/pts ~/workspaces/rpi/toolchain/dev/pts chroot ~/workspaces/rpi/toolchain /bin/bash
- Let's install host and cross compiler:
apt update apt install build-essential crossbuild-essential-arm64
Qt6 Host Build
We need Qt6 host build as cross-compilation requires all host compiled tools like for example 'moc'. We will do here qt 'module' build in separate build directory.
Note: For more information about build options see here.
Note: After toolchain setup, we should be still chrooted into our host Debian root (~/workspaces/rpi/toolchain).
- Add source packages repository for 'apt' by following line to '/etc/apt/sources.list' file:
deb-src http://deb.debian.org/debian bookworm main
- Let's install dependencies for Qt host build using know dependencies for Qt 6.4:
apt update apt build-dep libqt6gui6
- Let's install build dependencies for QtWebEngine:
apt install nodejs gperf bison flex python3-html5lib libnss3-dev
- Let's configure host build for Qt6 qtbase, build it and install into ~/workspaces/rpi/toolchain/opt/qt/host:
cd /qt/build/host mkdir qtbase cd qtbase /qt/qtbase/configure -release -nomake tests -nomake examples -linker lld -prefix /opt/qt/host cmake --build . --parallel cmake --install .
Note: The path /qt/qtbase in chroot is really ~/workspaces/rpi/toolchain/qt/qtbase on the build machine.
- Let's configure and build remaining modules:
cd /qt/build/host mkdir qtshadertools qtdeclarative qtwebengine cd qtshadertools /opt/qt/host/bin/qt-configure-module ../../../qtshadertools cmake --build . --parallel cmake --install . cd .. cd qtdeclarative /opt/qt/host/bin/qt-configure-module ../../../qtdeclarative cmake --build . --parallel cmake --install . cd .. cd qtwebengine /opt/qt/host/bin/qt-configure-module ../../../qtwebengine cmake --build . --parallel cmake --install . cd ..
Qt6 Target Cross Build
We should have by now Qt6 host build, target arm64 sysroot and cross compilation toolchain. To setup now cmake build we still need to create cmake toolchain file 'rpi.toolchain.cmake', which will provide information to cmake about our toolchian and sysroot setup.
Note: After toolchain setup, we should be still chrooted into our host Debian root (~/workspaces/rpi/toolchain).
- Let's create toolchain file:
vi /qt/rpi.toolchain.cmake cmake_minimum_required(VERSION 3.18) include_guard(GLOBAL) set(CMAKE_SYSTEM_NAME Linux) set(CMAKE_SYSTEM_PROCESSOR arm) set(CMAKE_SYSROOT /sysroot) set(CMAKE_C_COMPILER /usr/bin/aarch64-linux-gnu-gcc-12) set(CMAKE_CXX_COMPILER /usr/bin/aarch64-linux-gnu-g++-12) 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(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") 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() # See output of 'pkg-config --variable pc_path pkg-config' command. set(ENV{PKG_CONFIG_PATH} "") set(ENV{PKG_CONFIG_LIBDIR} ${CMAKE_SYSROOT}/usr/lib/aarch64-linux-gnu/pkgconfig:${CMAKE_SYSROOT}/usr/lib/pkgconfig:${CMAKE_SYSROOT}/usr/share/pkgconfig) set(ENV{PKG_CONFIG_SYSROOT_DIR} ${CMAKE_SYSROOT})
Note: If you wonder why we overload 'cmake_initialize_per_config_variable' see this blog post.
Note: The pkg-config exports could be set in build shell instead of toolchain.
- Let's configure target build for Qt6 qtbase, build it and install into ~/workspaces/rpi/toolchain/opt/qt/target:
cd /qt/build/target mkdir qtbase cd qtbase ../../../qtbase/configure -release -opengl es2 -nomake examples -nomake tests -qt-host-path /opt/qt/host -extprefix /opt/qt/target -prefix /usr/local/qt6 -- -DCMAKE_TOOLCHAIN_FILE=/qt/rpi.toolchain.cmake cmake --build . --parallel cmake --install .
- Let's configure and build remaining modules:
cd /qt/build/target mkdir qtshadertools qtdeclarative qtwebengine cd qtshadertools /opt/qt/target/bin/qt-configure-module ../../../qtshadertools cmake --build . --parallel cmake --install . cd .. cd qtdeclarative /opt/qt/target/bin/qt-configure-module ../../../qtdeclarative cmake --build . --parallel cmake --install . cd .. cd qtwebengine /opt/qt/target/bin/qt-configure-module ../../../qtwebengine cmake --build . --parallel cmake --install . cd ..
Deploy
We need to deploy compiled sources to sdcard. We can use RasberryPi OS image from sysroot step, mount it and rsync the content.
Note: We are not any longer in the chrooted enviroment, however target image is still mounted.
- Deploy with rsync:
rsync -av ~/workspaces/rpi/toolchain/opt/qt/target/ ~/workspaces/rpi/target/usr/local/qt6/
Note: If you wnat to rsync sysroot over the network, just replace the rsync steps below with the equivalent network location of your Rasberry Pi board.
- Umount the image and detach loop device:
umount ~/workspaces/rpi/target/dev/pts ~/workspaces/rpi/target/dev umount ~/workspaces/rpi/target/proc ~/workspaces/rpi/target/sys umount ~/workspaces/rpi/target losetup -d /dev/loop0
- Copy the image to the SD card (replace sdX with the device on your machine):
cd ~/workspaces/rpi/image dd if=2023-12-05-raspios-bookworm-arm64.img of=/dev/sdX bs=4M