Qt toolchain交叉编译以及SDK制作流程

Qt toolchain交叉编译流程

交叉编译工具gcc/g++安装

apt-cache search aarch64
apt-get install ggc-9-aarch64-linux-gnu
apt-get install g++-9-aarch64-linux-gnu
apt-get install ggc-aarch64-linux-gnu
apt-get install g++-aarch64-linux-gnu

Qt源码下载

建议直接在Qt官网下载,可按需查找对应版本Qt version

编译步骤

详细编译步骤可以参考该篇博客

4. Qt交叉编译(Qt5) — [野火]嵌入式Qt应用开发实战指南—基于LubanCat-RK开发板 文档

制作mkspec文件

首先,进入源码目录中,进行配置Qt,重新拷贝一份 qtbase/mkspecs/devices/linux-arm-generic-g++的配置, 并且命名为 linux-aarch64-g++,重新配置qmake.conf,需要注意以下几个参数的使用,其中

QMAKE_INCDIR_POST +=
QMAKE_LIBDIR_POST +=
以上两个参数用于指定项目的系统库搜索路径列表

QMAKE_CFLAGS += -B xxxx
QMAKE_CXXFLAGS += -B xxxx
以上-B是一种编译器选项,用于指预处理器的搜索路径

QMAKE_RPATHLINKDIR_POST += 
用于指定项目运行时的库搜索路径
QMAKE_LFLAGS += -B xxxx 
用于指定项目链接过程中的选项,包含了库搜索路径等链接器特定的选项

如果使用QMAKE_LIBDIR_POST的话,--sysroot仍然需要在QMAKE_CFLAGS、QMAKE_CXXFLAGS以及QMAKE_LFLAGS中定义

qmake.conf配置举例如下:

在配置linux-aarch64-g++/qmake.conf时,注意QMAKE_LIBDIR_POST以及QMAKE_CFLAGS的使用,遇到的情况总结如下:

#!/bin/sh

CROSS_COMPILE   = aarch64-linux-gnu-
DISTRO_OPTS     += aarch64

SYSROOT_FLAGS   = --sysroot=$$[QT_SYSROOT] -B $$[QT_SYSROOT]/lib/ \
                  -B $$[QT_SYSROOT]/usr/lib/ \
                  -B $$[QT_SYSROOT]/lib/aarch64-linux-gnu/ \
                  -B $$[QT_SYSROOT]/usr/lib/aarch64-linux-gnu/
QMAKE_CFLAGS    += $$SYSROOT_FLAGS
QMAKE_CXXFLAGS  += $$SYSROOT_FLAGS
QMAKE_LFLAGS    += $$SYSROOT_FLAGS

include(../linux-arm-generic-g++/qmake.conf)

参考上述QMAKE_RPATHLINKDIR_POST和QMAKE_CFLAGS的联系,可将上述qmake.conf修改为:

#!/bin/sh

CROSS_COMPILE   = aarch64-linux-gnu-
DISTRO_OPTS     += aarch64

SYSROOT_FLAGS   = --sysroot=$$[QT_SYSROOT] 

QMAKE_LIBDIR_POST += $$[QT_SYSROOT]/lib/ \
                      $$[QT_SYSROOT]/usr/lib/ \
                       $$[QT_SYSROOT]/lib/aarch64-linux-gnu/ \
                       $$[QT_SYSROOT]/usr/lib/aarch64-linux-gnu/

QMAKE_CFLAGS    += $$SYSROOT_FLAGS
QMAKE_CXXFLAGS  += $$SYSROOT_FLAGS
QMAKE_LFLAGS    += $$SYSROOT_FLAGS

include(../linux-arm-generic-g++/qmake.conf)

 参考上述修改方法,mkspecs中的linux-aarch64-rockchip-gnu-g++也可进行如下修改,测试通过

root@ning-QiTianM620-N000:/opt/toolchain_Qt_V5.12.8/rk3588/sysroot/usr/lib/aarch64-linux-gnu/qt5/mkspecs/linux-aarch64-rockchip-gnu-g++# cat qmake.conf 
#
# qmake configuration for building with aarch64-linux-gnu-g++
#

MAKEFILE_GENERATOR      = UNIX
CONFIG                 += incremental
QMAKE_INCREMENTAL_STYLE = sublib

include(../common/linux.conf)
include(../common/gcc-base-unix.conf)
include(../common/g++-unix.conf)

QMAKE_INCDIR_POST += \
    $$[QT_SYSROOT]/usr/include \
    $$[QT_SYSROOT]/usr/include/aarch64-linux-gnu

QMAKE_LIBDIR_POST += \
    $$[QT_SYSROOT]/usr/lib \
    $$[QT_SYSROOT]/lib/aarch64-linux-gnu \
    $$[QT_SYSROOT]/usr/lib/aarch64-linux-gnu

QMAKE_RPATHLINKDIR_POST += \
    $$[QT_SYSROOT]/usr/lib \
    $$[QT_SYSROOT]/usr/lib/aarch64-linux-gnu \
    $$[QT_SYSROOT]/lib/aarch64-linux-gnu

QMAKE_CFLAGS   += --sysroot=$$[QT_SYSROOT]
QMAKE_CXXFLAGS += --sysroot=$$[QT_SYSROOT]
QMAKE_LFLAGS   += --sysroot=$$[QT_SYSROOT] 

# modifications to g++.conf
QMAKE_CC                = aarch64-linux-gnu-gcc
QMAKE_CXX               = aarch64-linux-gnu-g++
QMAKE_LINK              = aarch64-linux-gnu-g++
QMAKE_LINK_SHLIB        = aarch64-linux-gnu-g++

# modifications to linux.conf
QMAKE_AR                = aarch64-linux-gnu-ar cqs
QMAKE_OBJCOPY           = aarch64-linux-gnu-objcopy
QMAKE_NM                = aarch64-linux-gnu-nm -P
QMAKE_STRIP             = aarch64-linux-gnu-strip
configure配置

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

root@20d93c971bd1:/home/adv/qt-everywhere-src-5.12.8# cat build-qt.sh 
#!/bin/sh

SYSROOT_PATH=/opt/toolchain_Qt_V5.12.8/rk3588/sysroot
DEVICE=linux-aarch64-g++
CROSS_CHAIN_PREFIX=/usr/bin/aarch64-linux-gnu-

INSTALL_COMMON_DIR=/usr/lib/aarch64-linux-gnu/qt5
INSTALL_HEADER_DIR=/usr/include/aarch64-linux-gnu/qt5
INSTALL_LIB_DIR=/usr/lib/aarch64-linux-gnu
INSTALL_BIN_DIR=/usr/lib/qt5/bin
INSTALL_DATA_DIR=/usr/share/qt5
INSTALL_DOC_DIR=/usr/share/qt5/doc
INSTALL_TRANSLATION_DIR=/usr/share/qt5/translations

HOST_DATA_DIR=/usr/lib/x86_64-linux-gnu/qt5
HOST_LIB_DIR=/usr/lib/x86_64-linux-gnu

do_configure () {
     echo "\033[1;33mstart configure ...\033[0m"
     ./configure \
     -device $DEVICE \
     -device-option CROSS_COMPILE=${CROSS_CHAIN_PREFIX} \
     -sysconfdir /etc/xdg \
     -prefix /usr \
     -hostprefix /usr \
     -sysroot ${SYSROOT_PATH}  \
     -bindir ${INSTALL_BIN_DIR} \
     -headerdir ${INSTALL_HEADER_DIR} \
     -libdir ${INSTALL_LIB_DIR} \
     -archdatadir ${INSTALL_COMMON_DIR} \
     -qmldir ${INSTALL_COMMON_DIR}/qml \
     -importdir ${INSTALL_COMMON_DIR}/imports \
     -plugindir ${INSTALL_COMMON_DIR}/plugins \
     -examplesdir ${INSTALL_COMMON_DIR}/examples \
     -libexecdir ${INSTALL_COMMON_DIR}/libexec \
     -datadir ${INSTALL_DATA_DIR} \
     -hostbindir ${INSTALL_BIN_DIR} \
     -hostlibdir ${HOST_LIB_DIR} \
     -hostdatadir ${HOST_DATA_DIR} \
     -release \
     -opensource \
     -confirm-license \
     -no-opengl \
     -no-openssl \
     -no-xcb \
     -no-eglfs \
     -no-compile-examples \
     -no-pkg-config \
     -no-iconv \
     -no-glib \
     -skip qtscript \
     -skip qtwebengine  \
     -no-use-gold-linker  \
     -v \
     -recheck-all
     echo "\033[1;33mdone...\033[0m"
}

do_configure

配置完成后,qt.conf内容如下:

[EffectivePaths]
Prefix=..
[DevicePaths]
Prefix=/usr
Documentation=share/qt5/doc
Headers=include/aarch64-linux-gnu/qt5
Libraries=lib/aarch64-linux-gnu
LibraryExecutables=lib/aarch64-linux-gnu/qt5/libexec
Binaries=lib/qt5/bin
Plugins=lib/aarch64-linux-gnu/qt5/plugins
Imports=lib/aarch64-linux-gnu/qt5/imports
Qml2Imports=lib/aarch64-linux-gnu/qt5/qml
ArchData=lib/aarch64-linux-gnu/qt5
Data=share/qt5
Translations=share/qt5/translations
Examples=lib/aarch64-linux-gnu/qt5/examples
[Paths]
Prefix=/usr
Documentation=share/qt5/doc
Headers=include/aarch64-linux-gnu/qt5
Libraries=lib/aarch64-linux-gnu
LibraryExecutables=lib/aarch64-linux-gnu/qt5/libexec
Binaries=lib/qt5/bin
Plugins=lib/aarch64-linux-gnu/qt5/plugins
Imports=lib/aarch64-linux-gnu/qt5/imports
Qml2Imports=lib/aarch64-linux-gnu/qt5/qml
ArchData=lib/aarch64-linux-gnu/qt5
Data=share/qt5
Translations=share/qt5/translations
Examples=lib/aarch64-linux-gnu/qt5/examples
HostPrefix=/usr
HostBinaries=lib/qt5/bin
HostLibraries=lib/x86_64-linux-gnu
HostData=lib/x86_64-linux-gnu/qt5
Sysroot=/opt/toolchain_Qt_V5.12.8/rk3588/sysroot
SysrootifyPrefix=true
TargetSpec=devices/linux-aarch64-g++
HostSpec=linux-g++

qt.conf中重要信息包括以下:
Sysroot和prefix指定了库的查找路径,最终的库文件安装路径为$Sysroot$prefix,TargetSpec指定了spec文件。
 

Qt SDK制作

Qt SDK制作的背景

下面这篇文章详细讲解了如何适配将QT的SDK可以放到任何目录用来编译Qt应用,主要和qt.conf文件Sysroot、Prefix以及HostData配置参数有关系。原因是由于Qt在编译的时候将安装路径写死在库文件中,当使用qmake xxxx.pro生成的Makefile会使用库文件中写死的SDK安装路径,这导致必须将SDK安装到特定的路径下不然找不到编译好的Qt库。而写死的SDK安装路径就是由Sysroot和Prefix配置参数定义的。幸运的是,在Qt4中引入了一个新的机制: qt.conf,于是,这个问题得以解决。在使用qmake 时引用参数-qtconf指定用户自定义的qt.conf文件即可。
qmake (.pro) SDK放在任意目录使用

Qt SDK制作步骤

创建sysroot目录

使用rsync同步设备上的/usr和/include目录,如果没有rsync命令的话,使用apt-get install rsync进行安装

mkdir /opt/toolchain_Qt_V5.12.8/rk3588/sysroot
cd  /opt/toolchain_Qt_V5.12.8/rk3588/sysroot
mkdir -p usr/share

rsync -rl --delete-after --safe-links root@172.21.84.58:/lib ./
rsync -rl --delete-after --safe-links root@172.21.84.58:/{usr/include,usr/lib} ./usr
rsync -rl --delete-after --safe-links root@172.21.84.58:/{usr/share/qt5,usr/share/qtchooser} ./usr/share

使用rsync同步完sysroot之后,需要在usr/lib/aarch64-linux-gnu/qt5/mkspecs目录下创建linux-aarch64-g++或linux-aarch64-rockchip-gnu-g++,区别在于linux-aarch64-g++位于devices子目录下,linux-aarch64-rockchip-gnu-g++位于当前目录下,交叉编译.configure时两者的差异,前者是使用-device xx指定,后者是使用-xplatform xx指定。

在使用rsync同步sysroot目录后发现,/usr/lib/aarch64-linux-gnu/libpthread.so文件不存在,分析执行rsync -rl --delete-after --safe-links root@172.21.84.58:/{usr/include,usr/lib} ./usr时,/usr/lib/aarch64-linux-gnu/libpthread.so的源文件
/lib/aarch64-linux-gnu/libpthread.so.0为SRC目录树以外的链接指令,而--safe-links 选项忽略了指向SRC路径目录树以外的链接,因此在rsync同步的sysroot目录下,需要手动创建软链接。

意外发现

使用rsync拷贝sysroot不使用--safe-links选项时
libpthread.so -> /lib/aarch64-linux-gnu/libpthread.so.0
libpthread.so应该是存在的,只是指向的源路径需要从绝对路径修改为相对路径

那么刚好执行symlinks -rc ./sysroot可以帮忙解决该问题
其中 , -c选项将使用绝对路径的符号链接转换为相对路径
             -r选项用于检查所有子目录中的符号链接
测试的话,可以使用-c选项和-t选项一起使用,会显示如何将绝对路径的符号链接转换为相对路径,但不会实际转换。

qmake环境安装

首先,需要安装x86环境的qmake指令,使用qmake -query可查看qmake是否安装成功

apt-get install qt5-qmake
apt-get install qt5-default

其次,在/opt/toolchain_Qt_V5.12.8/rk3588/sysroot目录下创建qmake以及qt.conf文件,内容如下

root@ning-QiTianM620-N000:/opt/toolchain_Qt_V5.12.8/rk3588/sysroot# cat qmake 
#!/bin/sh
qmake "$@" -before -qtconf "/opt/toolchain_Qt_V5.12.8/rk3588/sysroot/qt.conf"

以上qmake的二进制脚本中调用的qmake指令,是/usr/bin/qmake,是通过apt-get install qt5-qmake安装的x86平台的qmake,其中$@代表命令行中传递的所有参数列表,-qtconf指定使用的qt.conf文件。

$@的使用比如执行/opt/toolchain_Qt_V5.12.8/rk3588/sysroot/qt5/qmake -query时,-query就在$@中传递

qmake "$@" -qtconf /opt/toolchain_Qt_V5.12.8/rk3588/sysroot/qt5/qt.conf

具体执行内容为:

/usr/bin/qmake -query -qtconf /opt/toolchain_Qt_V5.12.8/rk3588/sysroot/qt5/qt.conf

qt.conf的内容如下:

root@ning-QiTianM620-N000:/opt/toolchain_Qt_V5.12.8/rk3588/sysroot# cat qt.conf 
[Paths]
# Target paths (see /usr/lib/aarch64-linux-gnu/qt5/qt.conf)
Sysroot=/opt/toolchain_Qt_V5.12.8/rk3588/sysroot
SysrootifyPrefix=true
Prefix=/usr
ArchData=lib/aarch64-linux-gnu/qt5
Binaries=lib/qt5/bin
Data=share/qt5
Documentation=share/qt5/doc
Examples=lib/aarch64-linux-gnu/qt5/examples
Headers=include/aarch64-linux-gnu/qt5
Imports=lib/aarch64-linux-gnu/qt5/imports
Libraries=lib/aarch64-linux-gnu
LibraryExecutables=lib/aarch64-linux-gnu/qt5/libexec
Plugins=lib/aarch64-linux-gnu/qt5/plugins
Qml2Imports=lib/aarch64-linux-gnu/qt5/qml
Settings=/etc/xdg
Translations=share/qt5/translations

# Host paths
HostPrefix=/usr
HostData=lib/x86_64-linux-gnu/qt5
HostBinaries=lib/qt5/bin
HostLibraries=lib/x86_64-linux-gnu

TargetSpec=devices/linux-aarch64-g++

[EffectivePaths]
# Use target mkspecs
HostData=/opt/toolchain_Qt_V5.12.8/rk3588/sysroot/usr/lib/aarch64-linux-gnu/qt5

# Dup host paths
HostPrefix=/usr
HostBinaries=lib/qt5/bin
HostLibraries=lib/x86_64-linux-gnu

# Dup target paths
Prefix=/usr
ArchData=lib/aarch64-linux-gnu/qt5
Binaries=lib/qt5/bin
Data=share/qt5
Documentation=share/qt5/doc
Examples=lib/aarch64-linux-gnu/qt5/examples
Headers=include/aarch64-linux-gnu/qt5
Imports=lib/aarch64-linux-gnu/qt5/imports
Libraries=lib/aarch64-linux-gnu
LibraryExecutables=lib/aarch64-linux-gnu/qt5/libexec
Plugins=lib/aarch64-linux-gnu/qt5/plugins
Qml2Imports=lib/aarch64-linux-gnu/qt5/qml
Settings=/etc/xdg
Translations=share/qt5/translations

在qt.conf中定义了qt库文件的安装路径以及Hostdata参数,使用Hostdata参数可找到自定义的mkspecs文件,如linux-aarch64-g++和linux-aarch64-rockchip-gnu-g++。如果修改了以上qt.conf中EffectivePaths中的HostData,会导致qmake在构建项目时报错,
提示Could not find qmake configuration file devices/linux-aarch64-g++
所以说,EffectivePaths中的HostData和Qt项目构建时查找mkspecs文件有关系。

对比分析qt.conf

分析对比此处的qt.conf文件和交叉编译Qt configure之后生成的qt.conf,差异就在于[EffectivePaths]中Hostdata的值不同,如果将交叉编译过程Qt configure生成的qt.conf,修改[EffectivePaths]中Hostdata为/opt/toolchain_Qt_V5.12.8/rk3588/sysroot/usr/lib/aarch64-linux-gnu/qt5后,使用交叉编译生成的qt.conf也可成功制作SDK。

通过上述分析,可能会有以下的疑问:Paths和EffectivePaths中定义的HostData有什么差异?

答:在Qt的配置文件qt.conf中,Paths和EffectivePaths都是用来指定一些路径信息的配置项,而其中的HostData字段通常是指主机的数据路径。

在使用qmake构建.pro项目时,Paths和EffectivePaths中的hostdata字段的差异在于:
Paths中的hostdata字段通常用于指定Qt应用程序运行时需要查找和加载的主机数据文件的路径。
这些数据文件可以是与Qt应用程序相关的配置文件、数据文件或其他资源文件。
EffectivePaths中的hostdata字段则是在构建过程中使用的路径,它通常是由Qt构建系统根据主机环境和构建选项自动确定的。
这个路径通常包含构建输出文件(例如可执行文件、库文件等)的主机数据相关的文件或目录。
总结来说,Paths中的HostData字段是在Qt应用程序运行时使用的路径,用于查找和加载主机数据文件,而EffectivePaths中的HostData字段是在Qt构建过程中使用的路径,由构建系统根据构建选项自动确定。

openGL库引用方式差异

使用/opt/toolchain_Qt_V5.12.8/rk3588/sysroot/qmake构建项目,在生成的Makefile中关于libGL.so库的引用发现存在问题,库文件的路径为/usr/lib/aarch64-linux-gnu/libGL.so,需要修改为/opt/toolchain_Qt_V5.12.8/rk3588/sysroot/usr/lib/aarch64-linux-gnu/libGL.so.。

通过与Debian系统中Qt SDK对比发现,在ubuntu20.04 Qt SDK中/usr/lib/aarch64-linux-gnu/qt5/mkspecs/modules目录下的一些.pri文件中有关于QMAKE_LIBDIR_OPENGL参数的设置,区别于Debain Qt SDK的差异在于前者赋值为usr/lib/aarch64-linux-gnu/libGL.so,后者赋值为-lGL,修改前者为-lGL后问题得以解决。

最终将ubuntu 20.04 Qt SDK中/usr/lib/aarch64-linux-gnu/qt5/mkspecs/modules中QMAKE_LIBDIR_XX=usr/lib/aarch64-linux-gnu/libx.so的部分,全部搜索进行修改,确保Makefile中对于.so的引用路径均对应到sysroot目录下。

Qt SDK发布流程

目录结构如下

root@ning-QiTianM620-N000:/opt/work/rk3568/qt5/createbin# ls -ll
total 1526624
-rwxr-xr-x 1 ning ning       419 11月 21 13:56 createbin.sh
-rwxr-xr-x 1 ning ning       407 11月 21 14:08 installbin.sh
-rwxr-xr-x 1 root root 781620700 11月 21 14:08 rk3588_aarch64_ubuntu20.04_toolchain_Qt_V5.12.8.run
-rw-r--r-- 1 root root 781620246 11月 21 13:52 rk3588_aarch64_ubuntu20.04_toolchain_Qt_V5.12.8.tar.gz

压缩sysroot

rk3588_aarch64_ubuntu20.04_toolchain_Qt_V5.12.8.tar.gz的制作,在 /opt/toolchain_Qt_V5.12.8/rk3588/目录下,压缩sysroot目录

cd  /opt/toolchain_Qt_V5.12.8/rk3588
tar zcf rk3588_aarch64_ubuntu20.04_toolchain_Qt_V5.12.8.tar.gz ./sysroot/

生成安装脚本

Qt SDK生成脚本creatbin.sh内容如下:

root@ning-QiTianM620-N000:/opt/work/rk3568/qt5/createbin# cat createbin.sh 
#!/bin/bash
if [ "$1" = "" ];then
   echo "please input The data source"
   echo "eg. ./createbin.sh rk3588_*_toolchain_Qt_V5.12.8_*.tar.gz"
   exit 1;
fi
BSP=$1
INSTALLSH=installbin.sh
BASE=$(basename $BSP .tar.gz)

cat $INSTALLSH | sed -e s/OUTNAME/$BSP/ > linux_license_new.bin
dos2unix -k -q linux_license_new.bin
cat linux_license_new.bin $BSP > ${BASE}.run
rm -rf linux_license_new.bin
sudo chmod a+x ${BASE}.run

Qt SDK安装脚本installbin.sh内容如下:

root@ning-QiTianM620-N000:/opt/work/rk3568/qt5/createbin# cat installbin.sh 
#!/bin/bash
localinstall=/opt/toolchain_Qt_V5.12.8/rk3588/
if [ -d "$localinstall" ] ; then
	rm -rf $localinstall
fi

/bin/mkdir -p $localinstall
outname=$localinstall/OUTNAME

echo "Unpacking..."
sed -n -e '1,/^exit 0$/!p' $0 > $outname

echo "Install aarch64-ubuntu20.04 Qt V5.12.8 Cross Compiler, May be few minutes, please wait..."
tar -zxf $outname -C $localinstall
rm -rf $outname
echo "Done."
exit 0

installbin.sh脚本中OUTNAME的值在creatbin.sh中使用sed语法将其替换为rk3588_aarch64_ubuntu20.04_toolchain_Qt_V5.12.8.tar.gz,installbin.sh脚本中sed语法的使用sed -n -e '1,/^exit 0$/!p' $0 > $outname用于将creatbin.sh脚本中cat合并的两个文件installbin.sh和rk3588_aarch64_ubuntu20.04_toolchain_Qt_V5.12.8.tar.gz重新分开。具体来说,就是将.run文件中除了第一行和 exit 0 所在行中间的部分,也就是exit 0后面的内容,输出到$outname
$0 是当前脚本的名,也就是 rk3588_aarch64_ubuntu20.04_toolchain_Qt_V5.12.8.run
exit 0 在这里可以看作一个分割标志,可以使用其他字符串代替。

最终,执行rk3588_aarch64_ubuntu20.04_toolchain_Qt_V5.12.8.run即可成功安装Qt toolchain到/opt/toolchain_Qt_V5.12.8/rk3588/sysroot目录下

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值