4. 交叉编译Qt库(Qt5)

前面讲解了如何编译Qt程序,接下来这几章将讲解下个人如何搭建qt交叉编译环境,交叉编译Qt并进行部署测试。

交叉编译可能有很多问题,我们仓库提供了一些已经交叉编译好的库, 具体库文件到 网盘 下载, 使用方式参考下教程 Qt程序编译

提示

接下来这两章的Qt编译的默认测试环境:板卡系统Debian10、PC虚拟机系统ubuntu20.04、交叉编译GCC是8.3.0、Qt源码版本是5.15.8/6.2.4。

4.1. 交叉编译Qt

提示

虚拟机ubuntu20.04建议配置至少4个cpu核,内存要4G以上(如果一次性交叉编译Qt所有模块,建议内存24G以上)。

本教程选择的交叉编译器版本和Qt库版本:

鲁班猫板卡系统

PC主机系统

交叉编译工具链

Qt库版本

Ubuntu20.04

Ubuntu20.04

aarch64-linux-gnu-gcc 9.4.0

Qt 5.15.8/Qt6.2.4

Debian10

Ubuntu20.04

aarch64-linux-gnu-gcc 8.3.0

Qt 5.15.8/Qt 6.2.4

后面章节主要介绍为Debian10系统的鲁班猫板卡,Ubuntu20.04的主机系统,交叉编译Qt 5.15.8/Qt 6.2.4。

4.1.1. Lubancat板卡环境(Debian10)

LubanCat板卡使用extboot镜像,系统是Debian10或者ubuntu20.04、ubuntu22.04, 镜像的烧录和获取查看下 《LubanCat-RK系列板卡快速使用手册》

测试主要使用Debian10, 建议使用相同的环境,为了交叉编译Qt,我们需要安装需要的库和工具:

# 安装一些库和工具等,按自己需要安装
sudo apt update

# x11相关
sudo apt-get install -y libx11-dev freetds-dev libxcb-xinput-dev libpq-dev libiodbc2-dev firebird-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

# gst相关
sudo apt-get install -y libgstreamer1.0-0 gstreamer1.0-plugins-base \
   gstreamer1.0-plugins-good gstreamer1.0-plugins-bad gstreamer1.0-plugins-ugly \
   gstreamer1.0-libav gstreamer1.0-doc gstreamer1.0-tools libunwind-dev

# opengl相关
sudo apt-get install -y  libegl1-mesa-dev libgbm-dev libgles2-mesa-dev libgles2-mesa

# 其他等等
sudo apt-get install -y libfreetype6-dev libicu-dev libsqlite3-dev libasound2-dev libnss3-dev \
   libxss-dev libxtst-dev libpci-dev libcap-dev libsrtp0-dev libxrandr-dev libdirectfb-dev libaudio-dev \
   libavcodec-dev libavformat-dev libswscale-dev libts-dev libfontconfig1-dev

sudo apt-get install -y libssl-dev libdbus-1-dev libglib2-dev  rsyslog  libjpeg-dev
# 安装可能需要相关工具
sudo apt-get install gcc g++ gdbserver rsync

4.1.2. PC主机环境(ubuntu20.04)

4.1.2.1. 安装环境

安装Qt Creator可以参考下前面章节,然后使用下面命令安装相关工具或者库:

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

4.1.2.2. 创建sysroot目录

我们交叉编译的程序是部署到板卡环境运行,需要构建和板卡一样的库环境,我们需要创建一个sysroot目录, 在编译时指定了 -sysroot=dir 该逻辑目录,编译过程中需要引用的库,头文件,就到 dir/xx 目录下去找。 创建sysroot目录下面提供了几种方法:

1 、 直接复制文件到sysroot

我们将sysroot文件夹与鲁班猫中的系统文件同步,sysroot文件夹将拥有运行系统所需的所有文件。 简单的我们就直接复制镜像的文件系统的到该目录下,我们网盘将会提供完整的包:

# 下载网盘的sysroot_debian10.tar.gz复制到虚拟机中,解压到用户目录下:
tar -xzf  sysroot_debian10.tar.gz ~

2、 rsync同步文件到sysroot

我们连接板卡和PC在一个局域网下,使用rsync目录同步文件,rsync将只复制更改的文件,对后面部署会节省大量时间。

# 在虚拟机上,创建sysroot目录
mkdir -p ~/sysroot/usr
mkdir -p ~/sysroot/lib
cd ~
rsync -avz --rsync-path="sudo rsync" --delete cat@192.168.103.102:/lib sysroot/lib
rsync -avz --rsync-path="sudo rsync" --delete cat@192.168.103.102:/usr/include sysroot/usr
rsync -avz --rsync-path="sudo rsync" --delete cat@192.168.103.102:/usr/lib sysroot/usr

# 根据实际板卡ip,修改上面的192.168.103.102

3、 nfs挂载文件到sysroot

通过挂载网络文件系统,也是一个很好的选择,nfs环境搭建参考下 挂载NFS网络文件系统

# 在板卡上搭建nfs服务
sudo apt install nfs-kernel-server

# 切换到root用户
echo "/usr 192.168.103.0/24(rw,sync,all_squash,anonuid=1000,anongid=1000,no_subtree_check)" >> /etc/exports
echo "/lib 192.168.103.0/24(rw,sync,all_squash,anonuid=1000,anongid=1000,no_subtree_check)" >> /etc/exports

sudo exportfs -arv

# 在虚拟机创建sysroot目录,安装nfs客户端,挂载
mkdir -p ~/sysroot/usr
mkdir -p ~/sysroot/lib

sudo apt install nfs-common -y

sudo mount -t nfs 192.168.103.102:/usr ~/sysroot/usr
sudo mount -t nfs 192.168.103.102:/lib ~/sysroot/lib

重要

nfs挂载和rsync同步文件,有些软连接库是使用绝对路径,交叉编译Qt源码时会出错。我们可以使用symlinks修改绝对路径为相对路径,安装命令: sudo apt-get install symlinks 使用命令: symlinks -rc ~/sysroot

4.1.2.3. 获取交叉编译器

X86架构是微处理器执行的计算机语言指令集,指一个intel通用计算机系列的标准编号缩写,也标识一套通用的计算机指令集合。 我们常用的PC,笔记本就属于X86架构的计算机。这种架构的计算机上又通常运行着三种操作系统,即是Windows、Linux和macOS。

ARM64架构是一个64位精简指令集(RISC)处理器架构,其广泛地使用在许多嵌入式系统中。 LubanCat Rk系列板卡就是基于ARM64架构的计算机。

由于x86和ARM64架构最底层的指令集不同,所以两个平台的程序不能通用,需要分开编译,编译的工具链是不一样。

第一章节有介绍到GNU工具链,这套工具链就分别提供X86和ARM64的编译工具。 由于我们日常的开发习惯,ARM架构的计算机资源等等因素,我们通常会在X86架构的平台上编写代码并编译然后放到ARM上运行。 所以就需要搭建交叉编译环境。

什么是交叉编译环境呢?简单点说就是在一个架构的处理器上能编译在另一个架构上运行的程序的环境。 再简单点来说,就是在X86架构下安装ARM的编译工具。

关于编译器的选择,建议使用和文件系统相同的编译器。 Debian10的默认的编译器是8.3.0版本,我们这里选择使用相同版本:aarch64-linux-gnu 8.3.0,为避免较多问题尽量使用相同版本,当然其他的版本也行。

野火提供 build-gcc.sh 脚本一键下载 gcc-aarch64-linux-gnu 8.3.0版本交叉编译器

build-gcc.sh 脚本内容如下:

#!/bin/sh

HOST=aarch64-linux-gnu
SCRIPT_PATH=$(pwd)

#修改源码包解压后的名称
MAJOR_NAME=gcc-aarch64-linux-gnu

#修改需要下载的源码版本前缀和后缀
OPENSRC_VER_PREFIX=8.3
OPENSRC_VER_SUFFIX=.0

PACKAGE_NAME=${MAJOR_NAME}-${OPENSRC_VER_PREFIX}${OPENSRC_VER_SUFFIX}

#定义压缩包名称
COMPRESS_PACKAGE=gcc-arm-8.3-2019.03-x86_64-aarch64-linux-gnu.tar.xz

#定义编译后安装--生成的文件,文件夹位置路径,可以根据实际修改到普通用户目录下,需和后面交叉编译qt源码脚本保持一致
INSTALL_PATH=/opt/${PACKAGE_NAME}

#无需修改--下载地址
DOWNLOAD_LINK=https://armkeil.blob.core.windows.net/developer/Files/downloads/gnu-a/8.3-2019.03/binrel/${COMPRESS_PACKAGE}

#下载源码包
do_download_src () {
   echo "\033[1;33mstart download ${COMPRESS_PACKAGE}...\033[0m"
   if [ ! -f "${COMPRESS_PACKAGE}" ];then
      if [ ! -d "${PACKAGE_NAME}" ];then
      wget -c ${DOWNLOAD_LINK}
      fi
   fi
   echo "\033[1;33mdone...\033[0m"
}

#解压源码包
do_tar_package () {
   echo "\033[1;33mstart unpacking the ${PACKAGE_NAME} package ...\033[0m"

   mkdir -p ${INSTALL_PATH}

   if [ ! -d "${PACKAGE_NAME}" ];then
      tar -xf ${COMPRESS_PACKAGE} -C ${INSTALL_PATH} --strip-components=1
   fi
   echo "\033[1;33mdone...\033[0m"
}

#删除下载的文件
do_delete_file () {
   cd ${SCRIPT_PATH}
   if [ -f "${PACKAGE_NAME}" ];then
      sudo rm -f ${PACKAGE_NAME}
   fi
}

do_download_src
do_tar_package
# do_delete_file

exit $?

整个脚本的核心就是使用wget命令将gcc-aarch64-linux-gnu的文件下载到本地, 然后通过tar解压到指定的安装目录(/opt/${PACKAGE_NAME},实际上就是/opt/gcc-aarch64-linux-gnu-8.3.0目录下)。

我们直接运行脚本即可下载并安装gcc-aarch64-linux-gnu-8.3.0版本的交叉编译器,后续的编译都是要该编译器进行。

执行脚本的过程:

# 使用命令执行脚本,下载到普通用户目录就不加sudo
sudo ./build-gcc.sh

start download gcc-arm-8.3-2019.03-x86_64-aarch64-linux-gnu.tar.xz...
--2023-03-27 16:02:38--  https://armkeil.blob.core.windows.net/developer/Files/downloads/gnu-a/8.3-2019.03/binrel/gcc-arm-8.3-2019.03-x86_64-aarch64-linux-gnu.tar.xz
正在解析主机 armkeil.blob.core.windows.net (armkeil.blob.core.windows.net)... 52.239.137.100
正在连接 armkeil.blob.core.windows.net (armkeil.blob.core.windows.net)|52.239.137.100|:443... 已连接。
已发出 HTTP 请求,正在等待回应... 200 OK
长度: 272029648 (259M) [application/octet-stream]
正在保存至: “gcc-arm-8.3-2019.03-x86_64-aarch64-linux-gnu.tar.xz”

6_64-aarch64-linux-gnu.tar.xz
99%[=======================================================================================> ] 259.38M   498KB/s    剩余 0s    Segmentation fault (core dumped)
done...
start unpacking the gcc-aarch64-linux-gnu-8.3.0 package ...
done...

提示

下载速度可能很慢,可以到 网盘 下载, 然后放到脚本同级目录下,执行命令解压。

安装完成之后,/opt/目录下就会存在gcc-aarch64-linux-gnu-8.3.0目录,下面是测试查看解压的交叉编译器:

# 查看解压的交叉编译器
ls /opt
 gcc-aarch64-linux-gnu-8.3.0

# 查看版本:
/opt/gcc-aarch64-linux-gnu-8.3.0/bin/aarch64-linux-gnu-gcc -v

使用内建 specs。
COLLECT_GCC=/opt/gcc-aarch64-linux-gnu-8.3.0/bin/aarch64-linux-gnu-gcc
COLLECT_LTO_WRAPPER=/opt/gcc-aarch64-linux-gnu-8.3.0/bin/../libexec/gcc/aarch64-linux-gnu/8.3.0/lto-wrapper
目标:aarch64-linux-gnu
配置为:/tmp/dgboter/bbs/rhev-vm8--rhe6x86_64/buildbot/rhe6x86_64--aarch64-linux-gnu/build/src/gcc/configure --target=aarch64-linux-gnu --prefix= --with-sysroot=/aarch64-linux-gnu/libc
--with-build-sysroot=/tmp/dgboter/bbs/rhev-vm8--rhe6x86_64/buildbot/rhe6x86_64--aarch64-linux-gnu/build/build-aarch64-linux-gnu/install//aarch64-linux-gnu/libc
--with-bugurl=https://bugs.linaro.org/ --enable-gnu-indirect-function --enable-shared --disable-libssp --disable-libmudflap --enable-checking=release --enable-languages=c,c++,fortran
--with-gmp=/tmp/dgboter/bbs/rhev-vm8--rhe6x86_64/buildbot/rhe6x86_64--aarch64-linux-gnu/build/build-aarch64-linux-gnu/host-tools
--with-mpfr=/tmp/dgboter/bbs/rhev-vm8--rhe6x86_64/buildbot/rhe6x86_64--aarch64-linux-gnu/build/build-aarch64-linux-gnu/host-tools
--with-mpc=/tmp/dgboter/bbs/rhev-vm8--rhe6x86_64/buildbot/rhe6x86_64--aarch64-linux-gnu/build/build-aarch64-linux-gnu/host-tools
--with-isl=/tmp/dgboter/bbs/rhev-vm8--rhe6x86_64/buildbot/rhe6x86_64--aarch64-linux-gnu/build/build-aarch64-linux-gnu/host-tools
--enable-fix-cortex-a53-843419 --with-pkgversion='GNU Toolchain for the A-profile Architecture 8.3-2019.03 (arm-rel-8.36)'
线程模型:posix
gcc 版本 8.3.0 (GNU Toolchain for the A-profile Architecture 8.3-2019.03 (arm-rel-8.36))

提示

如果是为鲁班猫ubuntu20.04系统交叉编译Qt,获取交叉编译器,建议使用apt默认安装交叉编译(aarch64-linux-gnu-gcc 9.4.0)。

4.1.3. 交叉编译Qt源码

提示

下面交叉编译Qt源码,会交叉编译很多模块,如果你需要快速编译使用,可以仅仅只编译Qt base模块,然后使用编译出的qmake单独编译和安装其他需要的Qt模块,但是需要注意其他模块的依赖等等。

交叉编译Qt 5.15.8源码,可以直接使用野火提供 build-qt.sh脚本,根据自己需要修改配置, build-qt.sh 脚本内容如下:

lubancat_qt_tutorial_code/Env/build-qt.sh
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
#!/bin/sh
# set -v

DEVICE=linux-lubancat-g++
SCRIPT_PATH=$(pwd)

#源码包名称,5.15版本使用qt-everywhere-opensource-src,其他的是qt-everywhere-src
MAJOR_NAME=qt-everywhere-src
MAJOR_NAME_1=qt-everywhere-opensource-src

#修改需要下载源码版本的前缀和后缀,我们默认使用5.15.8
OPENSRC_VER_PREFIX=5.15
OPENSRC_VER_SUFFIX=.8

#无需修改--自动组合下载版本
OPENSRC_VER=${OPENSRC_VER_PREFIX}${OPENSRC_VER_SUFFIX}

#修改源码包解压后的名称
PACKAGE_NAME=${MAJOR_NAME}-${OPENSRC_VER_PREFIX}${OPENSRC_VER_SUFFIX}

#定义编译后安装--生成的文件,文件夹位置路径
INSTALL_PATH_EXT=/opt/${PACKAGE_NAME}/ext
INSTALL_PATH_HOST=/opt/${PACKAGE_NAME}/host

#定义sysroot目录,需根据自己实际放的位置确认,这个默认设置在~/sysroot下
SYSROOT_PATH=~/sysroot

#添加交叉编译工具链路径,根据前面交叉编译器安装的路径设置
CROSS_CHAIN_PREFIX=/opt/gcc-aarch64-linux-gnu-8.3.0/bin/aarch64-linux-gnu-

#定义压缩包名称
COMPRESS_PACKAGE=${MAJOR_NAME}-${OPENSRC_VER_PREFIX}${OPENSRC_VER_SUFFIX}.tar.xz
COMPRESS_PACKAGE_1=${MAJOR_NAME_1}-${OPENSRC_VER_PREFIX}${OPENSRC_VER_SUFFIX}.tar.xz

#自动组合下载地址
case ${OPENSRC_VER_PREFIX} in
   5.15)
      DOWNLOAD_LINK=http://download.qt.io/official_releases/qt/${OPENSRC_VER_PREFIX}/${OPENSRC_VER}/single/${COMPRESS_PACKAGE_1}
      ;;
   *)
      DOWNLOAD_LINK=http://download.qt.io/archive/qt/${OPENSRC_VER_PREFIX}/${OPENSRC_VER}/single/${COMPRESS_PACKAGE}
      ;;
esac

#无需修改--自动组合平台路径
CONFIG_PATH=${SCRIPT_PATH}/${PACKAGE_NAME}/qtbase/mkspecs/devices/${DEVICE}

#无需修改--自动组合配置平台路径文件
CONFIG_FILE=${CONFIG_PATH}/qmake.conf

#下载源码包
do_download_src () {
     echo "\033[1;33mstart download ${PACKAGE_NAME}...\033[0m"

     if [ ! -f "${COMPRESS_PACKAGE}" ];then
         if [ ! -d "${PACKAGE_NAME}" ];then
             wget -c ${DOWNLOAD_LINK}
         fi
     fi

     echo "\033[1;33mdone...\033[0m"
}

#解压源码包
do_tar_package () {
     echo "\033[1;33mstart unpacking the ${PACKAGE_NAME} package ...\033[0m"
     if [ ! -d "${PACKAGE_NAME}" ];then
         tar -xf ${COMPRESS_PACKAGE}
     fi
     echo "\033[1;33mdone...\033[0m"
}

#创建和修改配置平台
do_config_before () {
     echo "\033[1;33mstart configure platform...\033[0m"
     cd ${PACKAGE_NAME}

     if [ ! -d "${CONFIG_PATH}" ];then
         cp -a ${SCRIPT_PATH}/${PACKAGE_NAME}/qtbase/mkspecs/devices/linux-generic-g++ ${CONFIG_PATH}
     fi

     echo "#" > ${CONFIG_FILE}
     echo "# qmake configuration for the LubanCat running Linux for debian10 " >> ${CONFIG_FILE}
     echo "#" >> ${CONFIG_FILE}
     echo "" >> ${CONFIG_FILE}
     echo "include(../common/linux_device_pre.conf)" >> ${CONFIG_FILE}
     echo "" >> ${CONFIG_FILE}
     echo "QMAKE_LIBS_EGL         += -lEGL -lmali" >> ${CONFIG_FILE}
     echo "QMAKE_LIBS_OPENGL_ES2  += -lGLESv2 -lEGL -lmali" >> ${CONFIG_FILE}
     echo "QMAKE_CFLAGS            = -march=armv8-a" >> ${CONFIG_FILE}
     echo "QMAKE_CXXFLAGS          = \$\$QMAKE_CFLAGS" >> ${CONFIG_FILE}
     echo "QMAKE_LFLAGS += -static-libstdc++" >> ${CONFIG_FILE}
     echo "" >> ${CONFIG_FILE}

     echo "QMAKE_INCDIR_POST += \
         \$\$[QT_SYSROOT]/usr/include \
         \$\$[QT_SYSROOT]/usr/include/\$\${GCC_MACHINE_DUMP} " >> ${CONFIG_FILE}

     echo "QMAKE_LIBDIR_POST += \
         \$\$[QT_SYSROOT]/usr/lib \
         \$\$[QT_SYSROOT]/lib/\$\${GCC_MACHINE_DUMP} \
         \$\$[QT_SYSROOT]/usr/lib/\$\${GCC_MACHINE_DUMP} " >> ${CONFIG_FILE}

     echo "QMAKE_RPATHLINKDIR_POST += \
         \$\$[QT_SYSROOT]/usr/lib \
         \$\$[QT_SYSROOT]/usr/lib/\$\${GCC_MACHINE_DUMP} \
         \$\$[QT_SYSROOT]/lib/\$\${GCC_MACHINE_DUMP} " >> ${CONFIG_FILE}

     echo "" >> ${CONFIG_FILE}
     echo "DISTRO_OPTS += aarch64" >> ${CONFIG_FILE}
     echo "DISTRO_OPTS += deb-multi-arch" >> ${CONFIG_FILE}
     echo "" >> ${CONFIG_FILE}
     echo "include(../common/linux_arm_device_post.conf)" >> ${CONFIG_FILE}
     echo "load(qt_config)" >> ${CONFIG_FILE}

     cat ${CONFIG_FILE}
     echo "\033[1;33mdone...\033[0m"
}

#配置选项
do_configure () {
     echo "\033[1;33mstart configure ${PACKAGE_NAME}...\033[0m"
     ./configure \
     -sysroot ${SYSROOT_PATH}  \
     -hostprefix ${INSTALL_PATH_HOST} \
     -extprefix ${INSTALL_PATH_EXT} \
     -device ${DEVICE} \
     -device-option CROSS_COMPILE=${CROSS_CHAIN_PREFIX} \
     -release \
     -opensource \
     -confirm-license \
     -nomake tests  \
     -make libs \
     -opengl es2 \
     -eglfs \
     -xcb \
     -dbus \
     -syslog \
     -sqlite \
     -tslib \
     -fontconfig \
     -pkg-config \
     -skip qtscript \
     -skip qtwebengine  \
     -no-use-gold-linker  \
     -v \
     -recheck-all
     echo "\033[1;33mdone...\033[0m"
}

#编译并且安装
do_make_install () {
     echo "\033[1;33mstart make and install ${PACKAGE_NAME} ...\033[0m"

     if [ ! -d "${CONFIG_PATH}" ];then
         cd ${PACKAGE_NAME}
     fi
     make -j4 && make install
     echo "\033[1;33mdone...\033[0m"
}

#删除下载的文件
do_delete_file () {
     cd ${SCRIPT_PATH}
     if [ -f "${COMPRESS_PACKAGE}" ];then
         sudo rm -f ${COMPRESS_PACKAGE}
     fi
}

# 下载源码包,如果你手动下载,并放在该脚本同级目录下,可以注释掉。
#do_download_src

# 解压源码包,如果你手动解压了,并放在该脚本同级目录下,可以注释掉。
#do_tar_package

# 配置文件
do_config_before

# 配置qt编译
do_configure

# 编译,安装qt
#do_make_install

# 删除文件
#do_delete_file

exit $?

简单介绍一下脚本的内容:

  1. 脚本使用wget命令下载Qt源码(也可以使用git获取,国内很慢不建议)。

    建议直接手动到 官网 ,获取5.15.8版本的Qt源码:

    qt_cross_compiling003.png

    如果网站访问很慢,也可以到 清华大学开源软件镜像网站 获取。

  2. 解压下载完的源码包。

  3. 进入源码目录中,进行配置Qt,这重新拷贝一份 qtbase/mkspecs/devices/linux-generic-g++ 中的配置, 并且命名为 linux-lubancat-g++,里面设置链接的库路径,头文件路径,pkg-config等等, 最后配置的qmake.conf文件的内容:

qt_cross_compiling005.png
  1. 配置Qt编译,这里我们使用 -device 指定我们的平台设备(linux-lubancat-g++)、 在 -device-option CROSS_COMPILE= 后指定交叉编译器路径 、 -sysroot 指定编译时根文件系位置,交叉编译的库和依赖到这个目录下查找、 -hostprefix 指定存放主机相关文件的路径、 -extprefix 指定安装路径, 上面测试时脚本指定了hostprefix和extprefix,实际使用指定 -prefix``也行。 配置编译的模块,个人根据自己的使用修改,使用命令 ``./configure -help 查看关闭相关模块。

交叉编译Qt源码时,需要先运行配置文件,检测下是否缺少库, 打开上面脚本的do_config_before和do_configure函数的注释,然后执行脚本编译配置, 之后我们查看config.summary文件:

Building on: linux-g++ (x86_64, CPU features: mmx sse sse2)
Building for: devices/linux-lubancat-g++ (arm64, CPU features: neon)
Target compiler: gcc 8.3.0
Configuration: cross_compile compile_examples enable_new_dtags largefile neon precompile_header shared shared rpath release c++11 c++14 c++17 c++1z concurrent dbus reduce_exports stl
Build options:
Mode ................................... release
Optimize release build for size ........ no
Building shared libraries .............. yes
Using C standard ....................... C11
Using C++ standard ..................... C++17
Using ccache ........................... no
Using new DTAGS ........................ yes
Relocatable ............................ yes
Using precompiled headers .............. yes
Using LTCG ............................. no
Target compiler supports:
   NEON ................................. yes
Build parts ............................ libs
Qt modules and options:
Qt Concurrent .......................... yes
Qt D-Bus ............................... yes
Qt D-Bus directly linked to libdbus .... no
Qt Gui ................................. yes
Qt Network ............................. yes
Qt Sql ................................. yes
Qt Testlib ............................. yes
Qt Widgets ............................. yes
Qt Xml ................................. yes
Support enabled for:
Using pkg-config ....................... yes
udev ................................... yes
Using system zlib ...................... yes
Zstandard support ...................... yes
Qt Core:
DoubleConversion ....................... yes
   Using system DoubleConversion ........ yes
GLib ................................... yes
iconv .................................. no
ICU .................................... yes
Built-in copy of the MIME database ..... yes
Tracing backend ........................ <none>
Logging backends:
   journald ............................. no
   syslog ............................... yes
   slog2 ................................ no
PCRE2 .................................. yes
   Using system PCRE2 ................... yes
Qt Network:
getifaddrs() ........................... yes
IPv6 ifname ............................ yes
libproxy ............................... no
Linux AF_NETLINK ....................... yes
OpenSSL ................................ yes
   Qt directly linked to OpenSSL ........ no
OpenSSL 1.1 ............................ yes
DTLS ................................... yes
OCSP-stapling .......................... yes
SCTP ................................... no
Use system proxies ..................... yes
GSSAPI ................................. yes
Qt Gui:
Accessibility .......................... yes
FreeType ............................... yes
   Using system FreeType ................ yes
HarfBuzz ............................... yes
   Using system HarfBuzz ................ yes
Fontconfig ............................. yes
Image formats:
   GIF .................................. yes
   ICO .................................. yes
   JPEG ................................. yes
      Using system libjpeg ............... yes
   PNG .................................. yes
      Using system libpng ................ yes
Text formats:
   HtmlParser ........................... yes
   CssParser ............................ yes
   OdfWriter ............................ yes
   MarkdownReader ....................... yes
      Using system libmd4c ............... no
   MarkdownWriter ....................... yes
EGL .................................... yes
OpenVG ................................. no
OpenGL:
   Desktop OpenGL ....................... no
   OpenGL ES 2.0 ........................ yes
   OpenGL ES 3.0 ........................ yes
   OpenGL ES 3.1 ........................ yes
   OpenGL ES 3.2 ........................ yes
Vulkan ................................. yes
Session Management ..................... yes
Features used by QPA backends:
evdev .................................. yes
libinput ............................... yes
INTEGRITY HID .......................... no
mtdev .................................. yes
tslib .................................. yes
xkbcommon .............................. yes
X11 specific:
   XLib ................................. yes
   XCB Xlib ............................. yes
   EGL on X11 ........................... yes
   xkbcommon-x11 ........................ yes
QPA backends:
DirectFB ............................... no
EGLFS .................................. yes
EGLFS details:
   EGLFS OpenWFD ........................ no
   EGLFS i.Mx6 .......................... no
   EGLFS i.Mx6 Wayland .................. no
   EGLFS RCAR ........................... no
   EGLFS EGLDevice ...................... yes
   EGLFS GBM ............................ yes
   EGLFS VSP2 ........................... no
   EGLFS Mali ........................... yes
   EGLFS Raspberry Pi ................... no
   EGLFS X11 ............................ yes
LinuxFB ................................ yes
VNC .................................... yes
XCB:
   Using system-provided xcb-xinput ..... no
   Native painting (experimental) ....... no
   GL integrations:
      GLX Plugin ......................... no
      EGL-X11 Plugin ..................... yes
Qt Sql:
SQL item models ........................ yes
Qt Widgets:

/*...........中间省略.......................*/

Qt Attributions Scanner ................ yes
qtdiag ................................. yes
qtpaths ................................ yes
qtplugininfo ........................... yes
Windows deployment tool ................ no
WinRT Runner Tool ...................... no
Qt Tools:
QDoc ................................... yes

Note: Also available for Linux: linux-clang linux-icc

Note: PKG_CONFIG_LIBDIR automatically set to /home/llh/sysroot/usr/lib/pkgconfig:/home/llh/sysroot/usr/share/pkgconfig:/home/llh/sysroot/usr/lib/aarch64-linux-gnu/pkgconfig

Note: PKG_CONFIG_SYSROOT_DIR automatically set to /home/llh/sysroot

Note: journald, syslog or slog2 integration is enabled.
If your users intend to develop applications against this build,
ensure that the IDEs they use either set QT_FORCE_STDERR_LOGGING to 1
or are able to read the logged output from journald, syslog or slog2.

前面配置我们开启了-opengl es2,我们关注EGLFS和openGL ES系列是否是yes, 如果都是no或者编译测试显示错误,说明没有找到库,或者有其他问题,需要具体查看下config.log和config.cache文件。

最后如果没有问题最终会输出提示,让我们执行make和make install 编译和安装:

qt_cross_compiling01.png

我们修改脚本,取消脚本中do_make_install的注释,执行脚本进行编译、安装,如果没有问题最后会显示:

qt_cross_compiling01.png

编译安装结束,切换到/opt/qt-everywhere-src-5.15.8/ext/lib下查看我们编译的库:

llh@llh-VirtualBox:/opt/qt-everywhere-src-5.15.8/ext/lib$ file libQt5Core.so.5.15.8
libQt5Core.so.5.15.8: ELF 64-bit LSB shared object, ARM aarch64, version 1 (GNU/Linux), dynamically linked, for GNU/Linux 3.17.0, stripped

将交叉编译出的库同步到板卡上(可选):

# 复制库到板卡上
llh@llh-VirtualBox:/opt/$ scp -r qt-everywhere-src-5.15.8 root@192.168.103.129:/opt/

# 添加到搜索库路径
cat@lubancat:~$ echo /opt/qt-everywhere-src-5.15.8/ext/lib | sudo tee /etc/ld.so.conf.d/LubancatQt5.conf
cat@lubancat:~$ sudo ldconfig

4.1.4. PC主机上配置交叉编译编译套件

前面章节的Qt Creator是安装在x86平台的,编译出来的程序,只能在该PC上工作。 要想我们的程序能在LubanCat执行,就必须使用我们这一章交叉编译的Qt库来编译程序。

Qt Creator 是Qt官方的IDE,那我们就在这个IDE中将交叉编译的Qt库和交叉编译工具链配置成 lubancat_rk 构建套件(Kits)。

选择 【工具】 -> 【外部】 -> 【配置】

qt_cross_compiling03.png

在弹出来的选项配置界面中选择【Kits】->【编译器】, 点击【添加】按钮选择添加【GCC】 ->【C++】类型,自己定义一个名字(这里是名称为 g++-aarch64-linux-gnu-8.3.0), 然后将我们之前安装的 aarch64-linux-gnu-8.3.0 版本的交叉编译器添加进来, 注意要选择 /opt/gcc-aarch64-linux-gnu-8.3.0/bin/aarch64-linux-gnu-g++ , 点击【Apply】完成应用。

qt_cross_compiling03.png

同理将 /opt/gcc-aarch64-linux-gnu-8.3.0/bin/aarch64-linux-gnu-gcc 编译器添加进来,名称为 gcc-aarch64-linux-gnu-8.3.0

qt_cross_compiling03.png

然后选择Qt的版本,我们在前面已经交叉编译并安装了Qt5.15.8版本,那么在这里只需要将qmake添加进来即可, 具体操作如下:在选项配置界面中选择【Kits】->【Qt Versions】,然后点击【添加】按钮,在Qt的安装目录 下选择qmake: /opt/qt-everywhere-src-5.15.8/host/bin/qmake ,然后添加完成后点击【Apply】完成应用。

qt_cross_compiling05.png

最后要添加构建套件,在选项配置界面中选择 【Kits】->【构建套件(Kit)】,然后点击【添加】,然后设置名称,此处我的名称设置为 lubancat_rk , 接着选择设备的类型,选择 通用的Linux设备(Generic Linux Device)

因为这是为开发板构建的环境,选择的编译器是我们刚刚添加的交叉编译工具,sysroot目录是我们前面交叉编译指定的sysroot目录, 最后选择Qt的版本,此处也是选择我们刚刚添加的交叉编译安装的版本,最后点击【Apply】完成应用。

qt_cross_compiling05.png

4.1.5. 交叉编译Qt程序

打开Qt Creator界面的analogclock例程, 然后点击例程的项目配置,选择使用交叉编译环境编译,选择构建套件为刚刚添加的交叉编译套件 lubancat_rk ,在编译时可以根据自己需求决定选择Debug或者Release版本:

qt_cross_compiling07.png
qt_cross_compiling05.png

点击“锤子”符号,构建编译应用程序:

qt_cross_compiling05.png

在构建完成后,可以在 Examples/Qt-5.15.2/gui/build-analogclock-lubancat_rk-Debug 目录下看到对应的可执行文件analogclock:

qt_cross_compiling05.png

我们可以使用file查看文件的类型,可以发现它是64位的可执行文件,ARM aarch64平台。

~$ file analogclock
analogclock: ELF 64-bit LSB executable, ARM aarch64, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux-aarch64.so.1, \
for GNU/Linux 3.7.0, with debug_info, not stripped

4.1.6. 板卡上运行测试

拷贝库文件到板卡

复制前面交叉编译的库到板卡上(如果前面以及同步,就不用下面这步操作):

# 板卡上创建目录
sudo mkdir /opt/qt-everywhere-src-5.15.8

# 虚拟机上,使用rsync复制库文件到板卡,使用scp、sftp也行
cd /opt/qt-everywhere-src-5.15.8
rsync -avz --rsync-path="sudo rsync" ext cat@192.168.103.102:/opt/qt-everywhere-src-5.15.8

设置下板卡环境(系统是Debian10 带桌面):

# 板卡上创建目录
sudo mkdir /opt/qt-everywhere-src-5.15.8

# 虚拟机上,使用rsync复制库文件到板卡,使用scp、sftp也行。
cd /opt/qt-everywhere-src-5.15.8
rsync -avz --rsync-path="sudo rsync" ext cat@192.168.103.102:/opt/qt-everywhere-src-5.15.8

提示

rsync命令中是 ext,表示同步ext文件夹到板卡的/opt,如果是 ext/,将会同步ext文件夹下的文件到板卡的/opt。

测试运行

传输前面交叉编译的可执行程序到板卡:

# 复制程序到板卡
scp analogclock cat@192.168.103.102:/home/cat

检查下前面板卡配置的环境:

# 在板卡执行程序
cat@lubancat:~$ ls
Desktop  analogclock
cat@lubancat:~$ ldd analogclock
   linux-vdso.so.1 (0x0000007f9a935000)
   libQt5Gui.so.5 => /usr/lib/aarch64-linux-gnu/libQt5Gui.so.5 (0x0000007f9a36f000)
   libQt5Core.so.5 => /usr/lib/aarch64-linux-gnu/libQt5Core.so.5 (0x0000007f99e5b000)
   libGLESv2.so.2 => /usr/lib/aarch64-linux-gnu/mali/libGLESv2.so.2 (0x0000007f99e49000)
   libpthread.so.0 => /lib/aarch64-linux-gnu/libpthread.so.0 (0x0000007f99e1a000)
   libm.so.6 => /lib/aarch64-linux-gnu/libm.so.6 (0x0000007f99d5d000)
   libgcc_s.so.1 => /lib/aarch64-linux-gnu/libgcc_s.so.1 (0x0000007f99d39000)
   libc.so.6 => /lib/aarch64-linux-gnu/libc.so.6 (0x0000007f99bc8000)
   libGL.so.1 => /usr/lib/aarch64-linux-gnu/libGL.so.1 (0x0000007f99ac5000)
   libpng16.so.16 => /usr/lib/aarch64-linux-gnu/libpng16.so.16 (0x0000007f99a80000)
   libharfbuzz.so.0 => /usr/lib/aarch64-linux-gnu/libharfbuzz.so.0 (0x0000007f99982000)
   libz.so.1 => /lib/aarch64-linux-gnu/libz.so.1 (0x0000007f99958000)
   libstdc++.so.6 => /usr/lib/aarch64-linux-gnu/libstdc++.so.6 (0x0000007f997cd000)
   /lib/ld-linux-aarch64.so.1 (0x0000007f9a907000)
   libicui18n.so.63 => /usr/lib/aarch64-linux-gnu/libicui18n.so.63 (0x0000007f994fa000)
   libicuuc.so.63 => /usr/lib/aarch64-linux-gnu/libicuuc.so.63 (0x0000007f9931f000)
   ......
# 后面省略

从上面可以看到,查找的库都是Debian10系统默认安装的qt5,直接运行程序就会出现:

relocation error: ./analogclock: symbol _ZTVN10__cxxabiv120__si_class_type_infoE version Qt_5 not defined....

简单的解决办法:我们就在执行程序前指定下链接库,并指定下平台插件(测试系统是Debian10 带桌面):

# 测试时使用xcb插件
LD_LIBRARY_PATH=/opt/qt-everywhere-src-5.15.8/ext/lib ./analogclock -platform xcb
qt_cross_compiling12.png

交叉编译时支持了eglfs、LinuxFB、xcb等,以上只是简单的测试,详细配置板卡环境,可以参考下后面 部署章节, 关于远程连接部署参考下 远程连接部署

以上是为鲁班猫Debian10系统交叉编译Qt,如果是为鲁班猫ubuntu20.04系统交叉编译Qt,建议在PC ubuntu20.04系统上, 使用apt默认安装交叉编译(aarch64-linux-gnu-gcc 9.4.0)编译,安装命令是 sudo apt install gcc-aarch64-linux-gnu g++-aarch64-linux-gnu, 其他相关库和编译脚本参考配套例程。