Qt5 cross-compilation environment for Raspberry Pi
This post is a brief extract of a wonderfully detailed video made by Ulas Dikme. Many thanks to Ulas for sharing his experiences, it saved me several days of work setting up the cross-compilation environment.
Ulas was using an Ubuntu 20 Virtual Box machine for building a sysroot and qt base. While it's not the best solution performance-wise, it's certainly very convenient in terms of being portable across the host machines. My Qt5 build system resides on a USB hard drive.
VM installation
The first part of the video covers a Virtual Box ubuntu installation and set up. Please don't forget to allocate a sufficient amount of RAM and VCPU resources. 4 to 6 VCPU might be adequate for make -j 6
I would refer to ubuntu VM as to a host system. Once the host system is up and running, we need to install some prerequisite development packages.
apt-get install gawk wget git-core diffstat unzip \
texinfo gcc-multilib build-essential chrpath socat \
libsdl1.2-dev xterm
apt-get install build-essential make gawk curl git \
git-lfs diffstat unzip texinfo build-essential \
chrpath libsdl1.2-dev xterm gperf bison gcc-multilib \
g++-multilib
Target (Raspbery Pi) system setup
Download the official Raspberry Pi OS and flash the image.
download rpi
wget --content-disposition --retry-connrefused \
--waitretry=2 https://downloads.raspberrypi.org/raspios_armhf_latest
flash the image
unzip 2020-05-27-raspios-buster-armhf.zip
lsblk will show your block devices, choose a correct one and rewrite the entire device with an image. Some sources advise to reduce the write block size (bs) down to 1M, which makes it slower. I've been using bs=4M with no issues.
dd if=2020-05-27-raspios-buster-armhf.img of=/dev/mmcblk0 bs=4M conv=fsync
Once the image is copied to a micro sd card, insert it into the slot and power up the board.
Please login into the target system and update /etc/apt/sources.list
Line below must be uncommented:
deb-src http://raspbian.raspberrypi.org/raspbian/ buster main contrib non-free rpi
Update the packages:
apt-get update
apt-get upgrade
run firmware update and accept changes
rpi-update
*** Updating firmware
*** Updating kernel modules
*** depmod 5.4.51+
*** depmod 5.4.51-v7l+
*** depmod 5.4.51-v8+
*** depmod 5.4.51-v7+
*** Updaating VideoCore libraries
*** Using HardFP libraries
*** Updating SDK
*** Running ldconfig
*** Storing current firmware revision
*** Deleting downloaded files
*** Syncing changes to disk
*** If no errors appeared, your firmware was successfully updated to **70598414a73afab7f8e521c358a7cfd5ffb65d3e**
*** A reboot is needed to activate the new firmware
In his video Ulas urges us to note the firmware revision for later. Current revision is accessible via /boot/.firmware_revision
root@raspberrypi:/home/pi# cat /boot/.firmware_revision
70598414a73afab7f8e521c358a7cfd5ffb65d3e
It would allow us to reproduce the working environment and keep track of the updates.
To install a specific firmware version use rpi-update:
rpi-update <revision number here>
Please be warned that Raspberry Pi may not boot after the firmware update. Mine was not booting up until I've disconnected the 5V jumper line between a touch screen and raspberry pi GPIO header and powered the screen with a separate USB PSU.
it's a good idea to enable ssh before the Raspberry Pi reboot and check if it starts.
Enable ssh server on a target
systemctl enable ssh
systemctl daemon-reload
systemctl start ssh
check the status
systemctl status ssh
Installation of qt & dependencies on a target system
Login as root and install all of the prerequisites.
I was logging in via ssh from the host machine for convenience.
apt-get build-dep qt5-qmake
apt-get build-dep libqt5webengine-data
apt-get install libboost1.58-all-dev libudev-dev libinput-dev \
libts-dev libmtdev-dev libjpeg-dev libfontconfig1-dev
apt-get install libssl-dev libdbus-1-dev libglib2.0-dev libxkbcommon-dev \
libegl1-mesa-dev libgbm-dev libgles2-mesa-dev mesa-common-dev
apt-get install libasound2-dev libpulse-dev gstreamer1.0-omx \
libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev gstreamer1.0-alsa
apt-get install libvpx-dev libsrtp0-dev libsnappy-dev libnss3-dev
apt-get install "^libxcb.*"
apt-get install libfreetype6-dev libicu-dev libsqlite3-dev libxslt1-dev \
libavcodec-dev libavformat-dev libswscale-dev
apt-get install libgstreamer0.10-dev gstreamer-tools libraspberrypi-dev \
libx11-dev libglib2.0-dev
apt-get install freetds-dev libsqlite0-dev libpq-dev libiodbc2-dev firebird \
-dev libjpeg9-dev libgst-dev libxext-dev libxcb1 libxcb1-dev libx11-xcb1
apt-get install libxcb-sync1 libxcb-sync-dev libxcb-render-util0 \
libxcb-render-util0-dev libxcb-xfixes0-dev libxrender-dev libxcb-shape0 libxcb-randr0-dev
apt-get install libxcb-glx0-dev libxi-dev libdrm-dev libssl-dev \
libxcb-xinerama0 libxcb-xinerama0-dev
apt-get install libatspi-dev libssl-dev libxcursor-dev libxcomposite-dev \
libxdamage-dev libfontconfig1-dev
apt-get install libxss-dev libxtst-dev libpci-dev libcap-dev libsrtp0-dev \
libxrandr-dev libnss3-dev libdirectfb-dev libaudio-dev
Create directory for qt5
mkdir /usr/local/qt5pi
chown pi:pi /usr/local/qt5pi
Compilation of Qt in ubuntu vm
when the vm is ready, apt-get update, upgrade & install dependencies:
apt-get install gcc git bison python gperf pkg-config
apt-get install libclang-dev
mkdir /opt/qt5pi
chown dev:dev /opt/qt5pi
Latest qt versions are reliably cross-compiled with a linaro toolchain, so let's get linaro.
Download Linaro cross-compiler
cd /opt/qt5pi
wget https://releases.linaro.org/components/toolchain/binaries/latest-7/arm-linux-gnueabihf/gcc-linaro-7.5.0-2019.12-x86_64_arm-linux-gnueabihf.tar.xz
untar it:
tar xf gcc-linaro-7.5.0-2019.12-x86_64_arm-linux-gnueabihf.tar.xz
add the tool chain path to a .bashrc
export PATH=$PATH:/opt/qt5pi/gcc-linaro-7.5.0-2019.12-x86_64_arm-linux-gnueabihf/bin
and export it in a current session
Download the latest qt (an original version in video was 5.14.x)
http://download.qt.io/official_releases/qt/5.15/5.15.0/single/qt-everywhere-src-5.15.0.tar.xz
and untar it under /opt/qt5pi/
Create sysroot on a host machine
Create sysroot on a host device
Rsync target files into a host for cross compilation
rsync -avz root@10.0.0.7:/lib sysroot
rsync -avz root@10.0.0.7:/usr/include sysroot/usr
rsync -avz root@10.0.0.7:/usr/lib sysroot/usr
rsync -avz root@10.0.0.7:/opt/vc sysroot/opt
make a backup of libEGL
mv sysroot/usr/lib/arm-linux-gnueabihf/libEGL.so.1.1.0 \
sysroot/usr/lib/arm-linux-gnueabihf/bak_orig_libEGL.so.1.1.0
mv sysroot/usr/lib/arm-linux-gnueabihf/libGLESv2.so.2.1.0 \
sysroot/usr/lib/arm-linux-gnueabihf/backup_orig_libGLESv2.so.2.1.0
create symlinks
ln -s sysroot/opt/vc/lib/libEGL.so \
sysroot/usr/lib/arm-linux-gnueabihf/libEGL.so.1.1.0
ln -s sysroot/opt/vc/lib/libGLESv2.so \
sysroot/usr/lib/arm-linux-gnueabihf/libGLESv2.so.2.1.0
ln -s sysroot/opt/vc/lib/libEGL.so \
sysroot/opt/vc/lib/libEGL.so.1
ln -s sysroot/opt/vc/lib/libGLESv2.so \
sysroot/opt/vc/lib/libGLESv2.so.2
fix absolute link names in sysroot
Download ./sysroot-relativelinks.py script and run it on a sysroot. This python script will process all of the symlinks in sysyroot and make them relative.
wget https://raw.githubusercontent.com/riscv/riscv-poky/master/scripts/sysroot-relativelinks.py
root@ubuntu-qt:/opt/qt5pi# chmod 755 sysroot-relativelinks.py
root@ubuntu-qt:/opt/qt5pi# ./sysroot-relativelinks.py sysroot
create a build directory, configure the build and start it:
root@ubuntu-qt:/opt/qt5pi# mkdir qt5build
root@ubuntu-qt:/opt/qt5pi# cd qt5build/
root@ubuntu-qt:/opt/qt5pi/qt5build#
Run configure script
../qt-everywhere-src-5.15.0/configure -opengl es2 -device linux-rasp-pi4-v3d-g++ \
-device-option CROSS_COMPILE=arm-linux-gnueabihf- -sysroot /opt/qt5pi/sysroot -gcc-sysroot \
-prefix /usr/local/qt5pi -opensource -confirm-license -skip qtscript -skip qtwayland \
-skip qtdatavis3d -nomake examples -make libs -pkg-config -no-use-gold-linker -v
Once everything is built, you must run 'make install'. Qt will be installed into '/opt/qt5pi/sysroot/usr/local/qt5pi'.
This will take a while to complete:
make -j 6
make install
Copy cross compiled qt into a target (10.0.0.7 is my Raspberry Pi):
cd /opt/qt5pi/
dev@ubuntu-qt:/opt/qt5pi$ rsync -avz sysroot/usr/local/qt5pi root@10.0.0.7:/usr/local
Install and configure Qt creator
dev@ubuntu-qt:/opt/qt5pi$ apt-cache showpkg qtcreator
Package: qtcreator
Versions:
4.11.0
dev@ubuntu-qt:/opt/qt5pi$ sudo apt-get install qtcreator
Configure Qt Creator embedded device kit
Navitage to QT Creator's "Options" -> "Kits"
Add new kit as a generic linux device
Navigate to "Qt Versions" tab and select the manual, then add "/opt/qt5pi/sysroot/usr/local/qt5pi/bin/qmake"
Go to "Compilers" tab
click "Add" -> "GCC" -> "C", add the linaro cross compiler's path there : /opt/qt5pi/gcc-linaro-7.5.0-2019.12-x8664arm-linux-gnueabihf/bin/arm-linux-gnueabihf-gcc and name it
change "ABI" to custom, it will change to arm linux generic elf 32bit
click "Apply" / "Ok"
click "Add" -> "GCC" -> "C++", add the linaro cross compiler's path there : /opt/qt5pi/gcc-linaro-7.5.0-2019.12-x8664arm-linux-gnueabihf/bin/arm-linux-gnueabihf-g++ and name it
change "ABI" to custom, it will change to arm linux generic elf 32bit
click "Apply" / "Ok"
now go back to the "kits" tab, select your kit and change the C / C++ compilers to the ones you've just added.
change the qt version as well to qt5pi and apply changes
Click on "devices" entry in a navigation list Click "Add" and select a generic linux device, then supply an ip address, login and a private key to log in
Add ssh key to allow an automated deployment into a target system.
Go back to kits, your new device shall be selecteds under devices
Your cross-compilation environment is now ready. Create a new project with a qt5-rpi4 environment, build it and copy to the target device. You should be able to run the cross-compiled executable.
Tags: embedded, qt, linux, raspberry-pi