qt5.15.2 交叉编译总结

最近项目需要,qt源码需要交叉编译,以前对这块不是很熟悉,从开始的一脸懵逼到最终成功编译出qt源码库,还是有了很多收获,分享给大家,希望对大家有所帮助。

交叉编译详解

还是先说交叉编译的思想。这里我以为我的项目经历为例给大家讲解。

说到交叉编译,这里要给大家普及两个概念。

  • 构建机平台,这个意思是说要在那台机器进行交叉编译,我自己的项目中的构建平台是x86_64+银河麒麟v10。
  • 目标平台,这个更好理解了,就是编译出来的动态库要运行在哪个平台上,我自己项目中的目标平台是aarch64+银河麒麟v10。

通过上面的介绍,大家应该基本理解了这两个概念,下面就开始说说交叉交叉编译的思想,交叉编译顾名思义就是在构建机平台上编译出目标机平台的应用程序或者动态库/静态库。很多朋友会问为什么会存在交叉编译呢?因为有这样的场景,很多嵌入式平台因性能不足无法进行大规模软件编译的情况,也存在很多其它的情况,大家可以百度一下能够得到很多理由。

好了上面对交叉编译做了基本的介绍,下面先从本机编译开始说起,本机编译,顾名思义就是本机编译的程序或者动态在本机上运行(也可以在同平台的机器上运行,这里不做过多赘述),这个很好理解,要编译的程序或者动态库依赖的一些头文件或者库文件就在本机系统上,或在默认目录(以linux为例,/usr/include /usr/lib等),另外也可以通过人工指定的方式(例如qt中可以通过LIBS关键字或者INCLUDEPATH等指定库文件路径和头文件路径等)指明依赖的头文件和库文件位置。这个很好理解,对于程序源来说这是很基本的概念。

上面已经详细介绍了本机编译的情况,本机介绍交叉编译,交叉编译的思想与本机编译的思想类似,但是有一些区别,下面一一列出。

  • 必须选择交叉编译器,以arm为例,可以到arm官网:Arm GNU Toolchain Downloads – Arm Developer下载包含符合自己构建平台和目标平台的交交叉编译器,这里是提供的是版本比较新的交叉编译器。如果需要查找历史版本则可以从这两个路径去查找:GNU toolchain releases for Embedded processors (discontinued)和GNU toolchain releases for A-profile processors (discontinued),这二者的区别是一个是嵌入式处理器的交叉编译工具,另外一个是移动设备或者计算能力强的处理的交叉编译工具,如有感兴趣的朋友可以自己查找资料,这里仅简单描述。用户需要根据自己的需求下载对应的交叉编译工具,上面的连接中提供了多种不同的构建和目标平台的交叉编译版本,例如x86_64 Linux hosted cross toolchains表示该编译器是运行在x86_64架构上的;AArch64 GNU/Linux target表示是编译出的目标程序是运行在aarch64架构上且依赖的是linux操作系统的。也有一部分是与操作系统无关,我自己的理解是编译器中的没有依赖操作系统相关的接口。
  • 交叉编译过程中依赖的头文件和库需要从目标机上安装,下载到构建机使用,不能使用本机的头文件和库文件,因为构建机的库文件与目标机的库文件由于架构不同,往往不能通用。头文件在不同的平台下接口名称可能也不一样,为了保险起见,最好编译程序所依赖的头文件和库文件最好从平台拉取到本地,然后手动指定头文件和库文件的路径进行编译。这里我在交叉编译qt5.15.2的源码时,是通过sysroot关键字来制出依赖的头文件和库文件路径,下面会详细介绍,这里仅介绍方法。需要注意的是交叉编译过程中依赖的头文件和库文件需要在目标机上安装,然后下载到本地,直接在构建机上安装是不对的

上面涉及的两个步骤都做完后就可以开始交叉编译了,下面以qt5.15.2为例,详细介绍下是如何完成交叉编译的。

Qt 5.15.2交叉编译实例

构建平台: x86_64+银河麒麟v10

目标机平台:aarch64+银河麒麟v10

按照第一节讲解的步骤下载了9.2版本(gcc-arm-9.2-2019.12-x86_64-aarch64-none-linux-gnu)的交叉编译器,同时将目标机的头文件和库文件下载到构建机。

步骤一

qt源码安装依赖很多库,需要提前在目标机(aarch64+银河麒麟V10)上安装,依赖库如下:

sudo apt install build-essential cmake unzip pkg-config gfortran
sudo apt build-dep qt5-qmake libqt5gui5 libqt5webengine-data libqt5webkit5 libudev-dev libinput-dev libts-dev libxcb-xinerama0-dev libxcb-xinerama0 gdbserver
sudo apt install libxcb-randr0-dev libxcb-xtest0-dev libxcb-shape0-dev libxcb-xkb-dev

附加包如下所示,根据需要安装即可。

# additional (multimedia) packages
sudo apt install libjpeg-dev libpng-dev libtiff-dev
sudo apt install libavcodec-dev libavformat-dev libswscale-dev libv4l-dev
sudo apt install libxvidcore-dev libx264-dev openjdk-8-jre-headless
# audio packages
sudo apt install libopenal-data libsndio7.0 libopenal1 libopenal-dev pulseaudio
# bluetooth packages
sudo apt install bluez-tools
sudo apt install libbluetooth-dev
# gstreamer (multimedia) packages
sudo apt install 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 gstreamer1.0-x gstreamer1.0-alsa gstreamer1.0-gl gstreamer1.0-gtk3 gstreamer1.0-qt5 gstreamer1.0-pulseaudio
sudo apt install libgstreamer1.0-dev  libgstreamer-plugins-base1.0-dev

步骤二

设置符号连接,这里我自己的理解是交叉编译工具需要一些特定的符号链接用于在编译过程中使用。需要下载SSymlinkerbash 脚本,这个脚本我从一[参考链接]中看到,但是按照他的方法没有下载下来,这里我把这个脚本上传到这里,供大家下载。脚本下载地址请在文章顶部提供的链接下载。下载脚本后执行如下操作,通过这些操作你能大概明白他的含义:

sudo chmod +x SSymlinker
./SSymlinker -s /usr/include/arm-linux-gnueabihf/asm -d /usr/include
./SSymlinker -s /usr/include/arm-linux-gnueabihf/gnu -d /usr/include
./SSymlinker -s /usr/include/arm-linux-gnueabihf/bits -d /usr/include
./SSymlinker -s /usr/include/arm-linux-gnueabihf/sys -d /usr/include
./SSymlinker -s /usr/include/arm-linux-gnueabihf/openssl -d /usr/include
./SSymlinker -s /usr/lib/arm-linux-gnueabihf/crtn.o -d /usr/lib/crtn.o
./SSymlinker -s /usr/lib/arm-linux-gnueabihf/crt1.o -d /usr/lib/crt1.o
./SSymlinker -s /usr/lib/arm-linux-gnueabihf/crti.o -d /usr/lib/crti.o

至此目标机(aarch64+银河麒麟V10)已经设置完成。

步骤三(配置构建机)

  • 构建机也需要安装一些基础软件包,安装的软件包如下所示:

sudo apt update
sudo apt dist-upgrade
sudo apt install build-essential cmake unzip gfortran
sudo apt install gcc git bison python gperf pkg-config gdb-multiarch wget
sudo apt-get -y install gcc g++ gperf flex texinfo gawk bison openssl pigz libncurses-dev autoconf automake tar figlet

设置目录结构,这个目录结构用来存放从目标机下载的库文件和头文件,供交叉编译器使用。

命令如下:

sudo mkdir ~/rk-qt
sudo mkdir ~/rk-qt/build
sudo mkdir ~/rk-qt/tools
sudo mkdir ~/rk-qt/sysroot
sudo mkdir ~/rk-qt/sysroot/usr
sudo mkdir ~/rk-qt/sysroot/opt
sudo chown -R consys:consys ~/rk-qt
cd ~/rk-qt

  •  接下来下载qt5.15.2源码到构建机,并解压缩到本地,目录自己指定即可。另外从arm官网下载的交叉编译工具也解压缩到本地。
  • 上述步骤完成,将交叉编译工具的bin目录添加到环境变量PATH中,方法如下:

vim .bashrc

在文件末尾添加export PATH=交叉编译工具bin目录:$PATH(以我的项目为例:/home/consys/tool/gcc-linaro-11.3.1-2022.06-x86_64_aarch64-linux-gnu/bin:$PATH)

source .bashrc 或者直接关闭该终端,再重新打开终端执行export命令查看PATH环境变量是否添加成功。

需要注意的是交叉编译工具bin目录下存放的是aarch64-linux-gnu-gcc。xxxxxxx-g++等工具,别找错目录了

  • 修改/home/consys/tool/qt-everywhere-src-5.15.2/qtbase/mkspecs目录下的qmake配置文件,我因为是要交叉编译aarhch+银河麒麟v10的程序,所以我选择的是修改linux-aarch64-gnu-g++目录下的qmake.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

修改为:

QMAKE_CC                = aarch64-none-linux-gnu-gcc   //注意这里的名字与交叉编译工具bin目录下的名字一致
QMAKE_CXX               = aarch64-none-linux-gnu-g++  //注意这里的名字与交叉编译工具bin目录下的名字一致
QMAKE_LINK              = aarch64-none-linux-gnu-g++  //注意这里的名字与交叉编译工具bin目录下的名字一致
QMAKE_LINK_SHLIB        = aarch64-none-linux-gnu-g++  //注意这里的名字与交叉编译工具bin目录下的名字一致

# modifications to linux.conf

QMAKE_AR                = aarch64-none-linux-gnu-ar cqs //注意这里的名字与交叉编译工具bin目录下的名字一致
QMAKE_OBJCOPY           = aarch64-none-linux-gnu-objcopy  //注意这里的名字与交叉编译工具bin目录下的名字一致
QMAKE_NM                = aarch64-none-linux-gnu-nm -P  //注意这里的名字与交叉编译工具bin目录下的名字一致
QMAKE_STRIP             =aarch64-none-linux-gnu-strip  //注意这里的名字与交叉编译工具bin目录下的名字一致

  •  从目标平台下载依赖的头文件、库文件和配置文件等。命令如下所示:

cd ~/rk-qt

 rsync -avz --rsync-path="sudo rsync" --delete [email protected]:/lib sysroot
 rsync -avz --rsync-path="sudo rsync" --delete [email protected]:/usr/include sysroot/usr
 rsync -avz --rsync-path="sudo rsync" --delete [email protected]:/usr/lib sysroot/usr
 rsync -avz --rsync-path="sudo rsync" --delete [email protected]:/opt/vc sysroot/opt

注意:rsync命令研究一下,只要从目标机下载到本机即可

将交叉编译依赖的文件下载到本地后执行下面命令,恢复链接

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

  • 编译qt源码需要先执行configure脚本,然后执行make 和make install命令,但是在交叉编译过程中有一项千万要在执行configure脚本之前执行,即配置PKG_CONFIG_PATH环境变量,这个环境变量指明一些后缀为pc的文件,这些pc文件指令了依赖库的路径,是非常重要的一个步骤,我很长时间编译出错就是因为在执行configure后,才添加的这个环境变量,但是configure执行过程中如果不配置该环境变量,qt就认为一些依赖库不存在,但是其实依赖库是存在的,因为configure执行过程中会根据该环境变量,影响一些生成的文件中的内容,造成报错或者编译跳过问题。我遇到的问题是编译qwebegine模块时一直提示nns模块不存在,但是从目标机下载头文件和库文件中nss已经存在,被折腾了好久。
  • 到这里已经基本配置完成了,但是还是要啰嗦一下,就是最好写一个autoconfigre.sh脚本放到qt5.15.2的目录下,与configure脚本同级即可,这个就自己研究参数把,我把自己使用的autoconfigure.sh脚本放在下面,供参考使用。

#!/bin/sh

./configure -release   -qt-libjpeg -qt-libpng -qt-zlib -qt-pcre -xplatform linux-aarch64-gnu-g++ -sysroot ~/rk-qt/sysroot -prefix /home/consys/tool/aarch64-qt-output  -opensource -confirm-license -skip qtscript -skip qtwayland  -nomake tests  -skip qtlocation -skip qt3d  -no-opengl -skip qtcanvas3d -skip qtpurchasing -make libs -pkg-config  -v -recheck -L$HOME/rk-qt/sysroot/usr/lib/aarch64-linux-gnu -I$HOME/rk-qt/sysroot/usr/include/aarch64-linux-gnu

  •  最后赋予autoconfigure.sh脚本执行权限,执行该脚本就可以了

sudo chmod +x autoconfigure.sh

./autoconfiure.sh

make

make install

注意1:交叉编译qt5.15.2时会消耗大量的内存,我开始使用的笔记本交叉编译(配置为8G内存+9G交换空间),在上面的配置中依然内存不够,造成编译不通过,最后找了一台内存超大的机器后菜编译通过。

注意2:autoconfigure.sh中指定了prefix(/home/consys/tool/aarch64-qt-output),这个目录需要注意并不是绝对路径,如果指定了sysroot,那么生成路径就是在sysroot指定的路径下创建prefix路径,即最终的动态库生成路径是(/home/consys/rk-qt/sysroot/home/consys/tool/aarch64-qt-output),这一点不要搞混了。sysroot的作用是提供一个逻辑地址,configure指定该参数后,编译依赖的头文件和库文件会以sysroot指定的路径作为基地址,即交叉编译原本依赖的头文件路径是/usr/include,指定sysroot后,则变成/home/consys/sysroot/usr/include。

交叉编译过程中遇到的问题

按照上面的步骤操作能够避免绝大多数问题,但是还是不可避免的遇到了一些问题,下面将他们一一列出,希望能够给朋友们一些帮助。

问题1

错误信息:编译的过程中提示缺少libdl.so 和librt.so等动态库,提示这些动态库的下符号找不到,例如dlOpen等。

修改方法:打开报错目录的makefile文件,手动在LIBS关键字中添加对应的so,缺少哪个就添加哪个,例如-ldl -lrt 如果名字不标准的,直接添加路径+so名称即可。

问题2

错误信息:jidctfst-neon.c:88:29: 错误: 用'int64x1_t'初始化'int_64' {或称‘long int’}时类型不兼容

int64_t left_ac_bitmap = vreinterpret_s64_s16(bitmap))

修改方法:此处是代码问题,需要修改代码,=号量表类型不一致,问题代码为:

int64_t left_ac_bitmap = vreinterpret_s64_s16(vget_low_s16(bitmap));

修改为

int64_t left_ac_bitmap = vget_lane_s64(vreinterpret_s64_s16(vget_low_s16(bitmap)),0);

其它报相同的问题按照相同方式修改即可。

问题3

错误信息:错误: 'vaddq_s8'的第2个实参类型不兼容

修改方法:代码问题,需要修改代码,实参类型与虚参类型不一致,问题代码为:

vaddq_s8(cols_01_s8,  vdupq_n_u8(CENTERJSAMPLE)));

修改为

vaddq_s8(cols_01_s8,  vreinterpretq_s8_u8(vdupq_n_u8(CENTERJSAMPLE))));

使用方法

交叉编译完成后,到生成的目录中将文件上传到目标平台,然后在目标平台执行如下命令:

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

最后运行程序即可。

参考链接:

树莓派4B——ubuntu20.04交叉编译QT5.15.2,_交叉编译qt 5.15_Li丶Chong的博客-CSDN博客

你可能感兴趣的:(Qt,qt,开发语言)