Cross-Compiling-Qt-for-Raspberry-Pi-4 - 为 Raspberry Pi 4 Model B 交叉编译 Qt 5.15.0 的指南

Created at: 2020-07-12 21:10:26
Language:

为 Raspberry Pi 4 交叉编译 Qt 5.15.0

过去,我经常遇到为 Raspberry Pi 编译 Qt 的问题。随着软件和硬件的每次更新,为旧版本编写的说明似乎在新版本中略有损坏。直接在 Pi 上编译源代码时,由于 CPU 速度较慢,可能需要很长时间才能意识到问题的发生甚至发生。

在尝试在新的 Raspberry Pi 4 上进行本地编译失败​​后,我决定专注于让交叉编译器工作。这意味着我可以直接在我的 PC 上完成所有 CPU 密集型工作,而且我也可以更快地失败,加快我发现和解决问题的能力。

本指南记录了我为 Raspberry Pi 4B 编译 Qt 5.15.0 所遵循的步骤。希望它对其他想要实现类似目标的人有用。如果你发现任何错误或多余/不必要的步骤,请告诉我。

设置为测试:

硬件
主机:Ryzen 5 3600 + 16 GB RAM + RTX 2070 超级
目标:Raspberry Pi 4 Model B Rev 1.2(2020 生产年份)

软件
主机:Ubuntu 20.04 LTS 64 位(在 Windows 10 中的 VMWare Player 中运行)
目标:Raspberry Pi OS(32 位)发布:2020-05-27
交叉编译器:gcc-linaro-7.4.1-2019.02-x86_64_arm- linux-gnueabihf

其他注意事项
虚拟机:VMWare Player 配置有 4 个 CPU 内核 + 8GB RAM + 禁用 CPU 的虚拟化引擎
WSL:这些指令已经在 Windows 子系统 Linux (WSL) 上进行了测试,并且运行良好 (Ubuntu 20.04)。这可能比处理 VM
存储要求更快:一旦整个过程完成,Ubuntu 中的构建目录大约为 8.1 GB
网络:你的 Raspberry Pi 需要访问互联网才能遵循这些说明。它还需要与主机 PC 位于同一网络上

致谢

本指南主要基于 INTERELECTRONIX 的 Walter Prechtl 为 Qt 14.1 发布的指南:https : //www.interelectronix.com/de/qt-auf-dem-raspberry-pi-4.html(在谷歌翻译)

我还使用了以下指南作为参考:

非常感谢Oliver Wilkins的指导和支持!

第 1 步:下载 Raspberry Pi OS 映像

我下载了映像并在我的 Windows 机器上准备了 SD 卡。这里有几个步骤:

1.1 设置WiFi

将 SD 卡连接到你的计算机,

wpa_supplicant.conf

在 /boot/ 分区上创建一个名为的新文件

该文件应具有以下内容:

country=GB
ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev
update_config=1

network={
	ssid="NETWORK-NAME"
	psk="NETWORK-PASSWORD"
	priority=2
}

network={
	ssid="SECOND-NETWORK-NAME"
	psk="SECOND-NETWORK-PASSWORD"
	priority=1
}	

修改网络块的内容以匹配你的 WiFi 连接的内容。如果你希望设备能够自动连接到多个网络之一,你可以添加任意数量的网络块。我离开了模板以允许两个网络。
如果多个网络可见,则使用优先级值选择 RPi 应优先考虑的网络。更高的数字 = 更高的优先级

1.2 设置SSH

我希望能够立即通过 SSH 连接到 Pi。要启用 ssh,只需

ssh
在 /boot/ 分区中创建一个名为的空文件

在我的桌面上,我使用

kitty
(一个流行的分支
putty
)通过 SSH 连接到 RPi。如果你在虚拟机中执行此操作,你还可以直接从任何终端使用 Ubuntu 的内置 SSH 功能。

现在可以将 SD 卡插入 RPi。

如果你不打算连接显示器和键盘,则可以使用网络路由器的接口来确定 RPi 的 IP 地址。

步骤2:配置Raspberry Pi

对于我们的构建,我们需要启用 SSH 和 GL(FAKE KMS)。这些都可以通过

raspi-config
实用程序完成。
如果你按照上述说明进行操作,则 SSH 应该已经启用。如果没有,我在下面详细说明了如何做:

在 Raspberry Pi 终端上,键入:

sudo raspi-config

你的终端上应该会弹出一个菜单

2.1启用SSH

要启用 SSH,请转到:

Interfacing Options -> P2 SSH -> Yes

按 Enter/Return 以启用它

2.2 启用GL(FAKE KMS)

要启用 Fake KMS,请从根

raspi-config
菜单转到:

Advanced Options -> A8 GL Driver -> G2 GL (Fake KMS)

那应该启用 KMS。如果你使用的是最小版本,系统可能会提示你在此选项可用之前下载一些更新。如果被问到,就这样做。

这就是我们需要配置的全部内容

raspi-config

2.3 启用开发源

你需要编辑源列表以启用开发源。为此,请在终端中输入以下内容

sudo nano /etc/apt/sources.list

在 nano 文本编辑器中,通过删除

#
字符来取消注释以下行(该行应该已经存在,如果不存在则添加它):

deb-src http://raspbian.raspberrypi.org/raspbian/ buster main contrib non-free rpi

现在按

Ctrl+X
退出。系统会询问你是否要保存更改。按
y
是,然后按
Enter
保持相同的文件名。

2.4 更新系统

在终端中运行以下命令以更新系统并重新启动

sudo apt-get update
sudo apt-get dist-upgrade
sudo reboot

2.5 使用提升的权限启用 rsync

在本指南的后面,我们将使用该

rsync
命令在 PC 和 RPi 之间同步文件。对于其中一些文件,需要 root 权限(即 sudo)。
在这一步中,我们将更改设置以允许这样做。

首先,使用以下命令找到 rsync 的路径:

which rsync

在我的 RPi 上,它在这里:

/usr/bin/rsync

现在我们需要编辑 sudoers 文件。你可以通过在终端中键入以下内容来编辑它:

sudo visudo

现在 sudoers 文件应该用 nano 打开。你需要使用以下结构在末尾添加一个条目:

<username> ALL=NOPASSWD:<path to rsync>

在我的情况下(以及其他大多数人),它是:

pi ALL=NOPASSWD:/usr/bin/rsync

就是这样。现在,如果需要,应该将 rsync 设置为与 sudo 一起运行。

2.6 安装需要的开发包

在终端中运行以下命令以安装所需的包

sudo apt-get build-dep qt5-qmake
sudo apt-get build-dep libqt5gui5
sudo apt-get build-dep libqt5webengine-data
sudo apt-get build-dep libqt5webkit5
sudo apt-get install libudev-dev libinput-dev libts-dev libxcb-xinerama0-dev libxcb-xinerama0 gdbserver

在这个阶段,我使用了我的 SD 卡映像的备份,

Win32DiskImager
以便我可以轻松地恢复到这种状态,如果以后有什么东西破坏了安装。

2.7多媒体的可选软件包(也可以在以后完成)

如果你需要多媒体或蓝牙功能,你可以安装这些软件包。

我建议现在跳过这一步,稍后再完成。我已经指定了何时安装这些库以及我在下面的第 4.5 节中遵循的过程。

应该注意的是,我最初在配置安装了这些包的 Qt 构建时遇到了问题。最初我一次性安装了所有这些库,但后来遇到了麻烦。然后,我通过反复试验以特定的顺序逐一安装了它们,这似乎可以解决问题。这是我安装它们的顺序:

sudo apt-get install gstreamer1.0-plugins*
sudo apt-get install libgstreamer1.0-dev  libgstreamer-plugins-base1.0-dev libopenal-data libsndio7.0 libopenal1 libopenal-dev pulseaudio
sudo apt-get install bluez-tools
sudo apt-get install libbluetooth-dev

In my installation, I skipped this step and did it at a later stage. The exact steps I happened to follow which worked for me are documented below.

2.8 Create a directory for the Qt install

This is where the built Qt sources will be deployed to on the Rasberry Pi. Run the following to create the directory:

sudo mkdir /usr/local/qt5.15
sudo chown -R pi:pi /usr/local/qt5.15

Step 3: Configure PC

This guide assumes that you have Ubuntu 20.04 already installed on your machine, either natively or running within a virtual machine.

3.1 Update the PC

Run the following to update your system and install some needed dependancies:

sudo apt-get update
sudo apt-get upgrade
sudo apt-get install gcc git bison python gperf pkg-config gdb-multiarch
sudo apt install build-essential

3.2 Set up SSH keys to speed up connecting with the Raspberry Pi

Normally, everytime you connect from your PC to the RPi, you will need to provide the login credentials. We can use SSH keys to avoid this and speed up the process.

Detailed instructions on how to do this are provided in the Raspberry Pi documentation here: https://www.raspberrypi.org/documentation/remote-access/ssh/passwordless.md

For simplicity, I opted not to use a passphrase when generating the key.

3.3 Set up the directory structure

I chose to create a directory called "rpi" to use as my workspace for the cross-compiler on the PC. Use these commands to create the directory structure:

sudo mkdir ~/rpi
sudo mkdir ~/rpi/build
sudo mkdir ~/rpi/tools
sudo mkdir ~/rpi/sysroot
sudo mkdir ~/rpi/sysroot/usr
sudo mkdir ~/rpi/sysroot/opt
sudo chown -R 1000:1000 ~/rpi
cd ~/rpi

The second to last line makes the first user of the computer (hopefully you) the owner of that folder. You can replace the

1000
with your user name if you want to be sure.

最后一个命令应该将你的当前目录更改为 ~/rpi。如果没有,请运行最后一行以确保你在里面,

~/rpi
因为接下来的步骤假设你正在从该目录运行你的命令。

第 4 步:构建准备和构建

4.1 下载Qt源码

现在我们可以下载 Qt 的源文件了。如前所述,本指南适用于 Qt 5.15.0,这是运行时可用的最新版本。它也是最新的 LTS 版本。

运行以下行以下载源文件:

sudo wget http://download.qt.io/archive/qt/5.15/5.15.0/single/qt-everywhere-src-5.15.0.tar.xz

使用以下命令解压下载的 tar 文件:

sudo tar xfv qt-everywhere-src-5.15.0.tar.xz 

我们需要稍微修改源文件中的 mkspec 文件,以允许我们使用我们的交叉编译器。我们将复制源文件中的现有目录,并修改目录名称和该目录中 qmake.conf 文件的内容,以遵循我们编译器的名称。

为此,请运行以下两个命令:

cp -R qt-everywhere-src-5.15.0/qtbase/mkspecs/linux-arm-gnueabi-g++ qt-everywhere-src-5.15.0/qtbase/mkspecs/linux-arm-gnueabihf-g++

sed -i -e 's/arm-linux-gnueabi-/arm-linux-gnueabihf-/g' qt-everywhere-src-5.15.0/qtbase/mkspecs/linux-arm-gnueabihf-g++/qmake.conf

4.2下载交叉编译器

大多数 Raspberry Pi 的交叉编译指南将使用 Raspberry Foundation 自己提供的工具,但这在这里不起作用,因为这些文件中的 gcc 版本太旧。我们将下载更新的 linaro 编译器。我使用了 7.4.1 版的编译器。较新的版本也可能适用。我们将把它下载到工具文件夹中。让我们首先使用以下命令切换到该目录:

cd ~/rpi/tools

运行以下命令下载编译器:

sudo wget https://releases.linaro.org/components/toolchain/binaries/7.4-2019.02/arm-linux-gnueabihf/gcc-linaro-7.4.1-2019.02-x86_64_arm-linux-gnueabihf.tar.xz

下载后,我们可以使用以下命令提取它:

tar xfv gcc-linaro-7.4.1-2019.02-x86_64_arm-linux-gnueabihf.tar.xz

让我们根据需要返回到 rpi 文件夹以进行下一部分:

cd ~/rpi

4.3 同步我们的 sysroot

我们现在需要将 sysroot 文件夹与来自 Raspberry Pi 的系统文件同步。sysroot 文件夹将包含运行系统所需的所有文件,因此也可以为该系统进行编译。rsync 可以让我们将在 Raspberry Pi 上所做的任何更改与我们的 PC 同步,反之亦然。这很方便,因为如果你稍后对 RPi 进行更改并希望更新主机上的 sysroot 文件夹,rsync 只会复制更改,从而可能节省大量时间。

现在,我们希望同步(即复制)来自 RPi 的所有相关文件。为此,请输入以下命令 [使用 RPi 的 IP 地址更改192.168.1.7 ]:

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

注意:在执行上述每个命令后仔细检查所有文件是否已复制。如果有任何问题,将会出现一条信息消息。如果你想检查所有文件是否已被复制,你可以根据需要再次运行这些行中的任何一行。rsync仅在进行任何更改后才复制文件。

--rsync-path="sudo rsync"
选项允许我们访问目标系统 (RPi) 上可能需要提升权限的文件。我们对 RPi 本身所做的 rsync 配置更改允许我们使用此标志。

--delete
选项将从我们的主机系统中删除任何文件,如果它们也已在 RPi 上被删除。你可能可以省略这一点,但我在对 RPi 上的库安装问题进行故障排除时使用了它。

4.4 修复符号链接

我们在上一步中复制的文件仍然具有指向 Raspberry Pi 上文件系统的符号链接。我们需要改变它,使它们成为来自主机上新 sysroot 目录的相对链接。我们可以使用可下载的 python 脚本来做到这一点。要下载它,请输入以下内容:

wget https://raw.githubusercontent.com/riscv/riscv-poky/master/scripts/sysroot-relativelinks.py

下载后,你只需要使用以下命令使其可执行并运行它:

sudo chmod +x sysroot-relativelinks.py
./sysroot-relativelinks.py sysroot

4.5如果你需要Qt多媒体(可选)

In the Raspberry Pi configuration steps (step 2.7), I mentioned a list of libraries required for QtMultimedia, and also how I had issues when I installed them. I suggested skipping installing them in that section. Instead this is what I suggest you do:

  1. Continue to the configuration section 4.6 below (i.e. don't install any of the multimedia libraries yet)
  2. Follow the instructions given to configure the build
  3. Wait for configuration to finish
  4. Hopefully there won't be any issues with it. If there are, then you have a problem elsewhere. Let's assume there were no problems.
  5. Now go on the Raspberry Pi and install the first library running the following command:
    • sudo apt-get install gstreamer1.0-plugins*
  6. Now run the commands given above again to sync the sysroot and fix symbolic links (section 4.3 & 4.4). Ensure you are running them from the ~/rpi directory (and not the build directory)
  7. Go to the next section below and run the configure command
  8. Check that there aren't any issues in the configuration output. Let's assume that everything is okay
  9. Now repeat steps 5-8 again but everytime you do step 5, change the library being installed appropriately. Do them in the following order (as that's what I happened to do and worked for me):
    1. sudo apt-get install gstreamer1.0-plugins*
      [ALREADY COMPLETED ABOVE]
    2. sudo apt-get install libgstreamer1.0-dev  libgstreamer-plugins-base1.0-dev libopenal-data libsndio7.0 libopenal1 libopenal-dev pulseaudio
    3. sudo apt-get install bluez-tools
    4. sudo apt-get install libbluetooth-dev
    5. [any other libraries you might need for your specific use case]
  10. If after installing any of the above libraries you face issues with the configure step below, then that means that library installation was interfering with something in your sysroot.
    That would be a library specific issues most likely, and resolving that is out of the scope of this guide.

4.6 Configure Qt Build

Now most of the work we need to set things up has been completed. We can now configure our Qt build.

Let's move into the build directory that we created earlier inside the rpi folder:

cd ~/rpi/build

现在我们需要运行配置脚本来配置我们的构建。这个配置脚本实际上位于 qt 源目录中。我们不想在那个源目录中构建,因为它会变得混乱,所以我们将从这个构建目录中访问它。这是你需要运行以配置构建的命令,包括所有必要的选项:

../qt-everywhere-src-5.15.0/configure -release -opengl es2  -eglfs -device linux-rasp-pi4-v3d-g++ -device-option CROSS_COMPILE=~/rpi/tools/gcc-linaro-7.4.1-2019.02-x86_64_arm-linux-gnueabihf/bin/arm-linux-gnueabihf- -sysroot ~/rpi/sysroot -prefix /usr/local/qt5.15 -extprefix ~/rpi/qt5.15 -opensource -confirm-license -skip qtscript -skip qtwayland -skip qtwebengine -nomake tests -make libs -pkg-config -no-use-gold-linker -v -recheck

配置脚本可能需要几分钟才能完成。完成后,你应该获得已配置内容的摘要。确保出现以下选项:

QPA backends:
  DirectFB ............................... no
  EGLFS .................................. yes	[SHOULD BE YES]
  EGLFS details:
    EGLFS OpenWFD ........................ no
    EGLFS i.Mx6 .......................... no
    EGLFS i.Mx6 Wayland .................. no
    EGLFS RCAR ........................... no
    EGLFS EGLDevice ...................... yes	[SHOULD BE YES]
    EGLFS GBM ............................ yes
    EGLFS VSP2 ........................... no
    EGLFS Mali ........................... no
    EGLFS Raspberry Pi ................... no	[SHOULD BE NO]
    EGLFS X11 ............................ yes
  LinuxFB ................................ yes
  VNC .................................... yes

如果你的配置摘要没有将 EGLFS 功能设置为上面显示的内容,则可能出现问题。你可以查看构建目录中的 config.log 文件以尝试诊断可能是什么问题。如果你在配置摘要底部看到“EGLFS 已启用但是....”行的错误,这也可能表明出现问题。查看 config.log 文件以尝试诊断错误。
你可能会收到有关未编译 QDoc 的警告。除非你特别需要,否则可以安全地忽略它。

如果你有任何问题,请在再次运行 configure 之前,使用以下命令删除当前内容(如果需要,请先保存 config.log 的副本):

rm -rf *

我上面提供的配置命令跳过了 QtWebEngine,因为这似乎有一些额外的依赖。如果需要,可以稍后尝试单独编译该模块。我也跳过了对 Wayland 的支持,但如果你需要它,你可以从提供的配置命令中删除该选项。我跳过了 QtScripts,因为这个库正在被弃用,最好避免使用它。

如果你正在构建 QtMultimedia 并按照我在上一节中的步骤进行操作,那么这就是你返回并在 RPi 上安装你需要的下一个库的地方。那是假设配置摘要看起来没问题并且没有表明任何问题。
安装库时,你应该能够在多媒体和蓝牙下的配置摘要中看到不同的功能已启用(设置为“是”)。

如果一切看起来都不错并且你需要的所有库都已安装,我们可以继续下一节

4.7 构建 Qt

我们的构建现在已经配置好了,是时候真正构建源文件了。确保你仍在构建目录中,然后运行以下命令:

make -j4

-j4 选项指示作业应分散到 4 个线程并并行运行。我为我的 Ubuntu 虚拟机分配了 4 个 CPU 内核,所以我认为系统会利用它并在 4 个内核之间分配工作负载。

这个过程需要一些时间

完成后,我们可以使用以下命令安装构建的包:

make install

这应该将文件安装在正确的目录中

4.8 将 Qt 部署到我们的树莓派

我们现在可以将 Qt 部署到我们的 RPi。我们将再次使用 rsync 命令。首先使用以下命令移回 rpi 文件夹:

cd ~/rpi

你现在应该在这里看到一个名为“qt5.15”的新文件夹。使用以下命令将其复制到 raspberry pi [用你的 RPi 的 IP 地址替换 192.168.1.7]:

rsync -avz --rsync-path="sudo rsync" qt5.15 pi@192.168.1.7:/usr/local

第 5 步:更新 Raspberry Pi 上的链接器

(我不完全确定是否需要这一步)

输入以下命令更新设备,让链接器找到新的 Qt 库文件:

echo /usr/local/qt5.15/lib | sudo tee /etc/ld.so.conf.d/qt5.15.conf
sudo ldconfig

用于在 Raspberry Pi 2 上安装的 Qt wiki 建议如下:

If you're facing issues with running the example, 
try to use 00-qt5pi.conf instead of qt5pi.conf, to introduce proper order.

如果你在运行项目时遇到问题,可以尝试一些方法。

应该是这样!你现在(希望)已经在 Raspberry Pi 4B 上成功安装了 Qt 5.15。

在下一步中,我们将构建一个示例应用程序,以检查一切是否正常。

第 6 步:构建示例应用程序

在 PC 上,运行以下命令以构建与 Qt 捆绑在一起的示例 OpenGL 项目之一,并将其​​部署到 Raspberry Pi:

要复制示例项目,请运行以下命令:

cp -r ~/rpi/qt-everywhere-src-5.15.0/qtbase/examples/opengl/qopenglwidget ~/rpi/

进入该新文件夹并使用以下命令构建源文件:

cd ~/rpi/qopenglwidget
../qt5.15/bin/qmake
make

使用以下命令将构建的二进制文件复制到 Rasberry Pi [将 IP 地址更改为你的 RPi 的]:

scp qopenglwidget pi@192.168.1.7:/home/pi

现在切换到 Raspberry Pi并导航到主目录:

cd ~

现在运行我们从主机复制的编译后的可执行文件:

./qopenglwidget

该演示应在连接到Raspberry Pi的显示器上开始运行。

第 6 步:窗口与全屏模式

在我之前在 Raspberry Pi 上使用的 Qt 版本中,我开发的应用程序直接在帧缓冲区上运行,绕过了 X 窗口管理器。这也意味着应用程序总是全屏运行。我发现此 Qt 版本并非如此。

如果我启动进入桌面模式并启动该应用程序,它将在窗口模式下运行。这确实具有能够将 VNC 连接到 Raspberry Pi 并查看结果的好处。

但是,如果你希望它绕过 X Window Manager,到目前为止我找到的唯一解决方案是将 RPi 直接引导到 CLI。这样 X Window Manager 就不会运行,并且应用程序在启动时会全屏运行。

Pablojr 指出,即使在命令行模式下,通过

-platform vnc
在启动时添加标志,你也可以通过 VNC 访问该应用程序,如下所示:

./qopenglwidget -platform vnc

为此,你首先需要通过 禁用 Raspberry Pi 的内置 VNC 服务器

raspi-config
。我确实遇到了使用 OpenGL 组件(例如上面的示例)的应用程序的问题,其中 OpenGL 图形无法呈现。

第 7 步:配置 Qt Creator

目前,我在Windows机器上开发Qt应用程序。因此它不能直接访问交叉编译器。我只需将我的项目源文件从我的 Windows 环境复制到虚拟机内的 Ubuntu 环境,然后运行

qmake
make
编译代码。我尚未在 Ubuntu 中配置 Qt Creator 以自动交叉编译并部署到我的 Raspberry Pi。

但是,如果你想这样做,可以在网上找到指南,包括在我开头提供的链接之一中作为参考:https : //mechatronicsblog.com/cross-compile-and-deploy-qt-5-树莓派12 /