最近项目需要,qt源码需要交叉编译,以前对这块不是很熟悉,从开始的一脸懵逼到最终成功编译出qt源码库,还是有了很多收获,分享给大家,希望对大家有所帮助。
还是先说交叉编译的思想。这里我以为我的项目经历为例给大家讲解。
说到交叉编译,这里要给大家普及两个概念。
通过上面的介绍,大家应该基本理解了这两个概念,下面就开始说说交叉交叉编译的思想,交叉编译顾名思义就是在构建机平台上编译出目标机平台的应用程序或者动态库/静态库。很多朋友会问为什么会存在交叉编译呢?因为有这样的场景,很多嵌入式平台因性能不足无法进行大规模软件编译的情况,也存在很多其它的情况,大家可以百度一下能够得到很多理由。
好了上面对交叉编译做了基本的介绍,下面先从本机编译开始说起,本机编译,顾名思义就是本机编译的程序或者动态在本机上运行(也可以在同平台的机器上运行,这里不做过多赘述),这个很好理解,要编译的程序或者动态库依赖的一些头文件或者库文件就在本机系统上,或在默认目录(以linux为例,/usr/include /usr/lib等),另外也可以通过人工指定的方式(例如qt中可以通过LIBS关键字或者INCLUDEPATH等指定库文件路径和头文件路径等)指明依赖的头文件和库文件位置。这个很好理解,对于程序源来说这是很基本的概念。
上面已经详细介绍了本机编译的情况,本机介绍交叉编译,交叉编译的思想与本机编译的思想类似,但是有一些区别,下面一一列出。
上面涉及的两个步骤都做完后就可以开始交叉编译了,下面以qt5.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
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++等工具,别找错目录了
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
#!/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
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。
按照上面的步骤操作能够避免绝大多数问题,但是还是不可避免的遇到了一些问题,下面将他们一一列出,希望能够给朋友们一些帮助。
错误信息:编译的过程中提示缺少libdl.so 和librt.so等动态库,提示这些动态库的下符号找不到,例如dlOpen等。
修改方法:打开报错目录的makefile文件,手动在LIBS关键字中添加对应的so,缺少哪个就添加哪个,例如-ldl -lrt 如果名字不标准的,直接添加路径+so名称即可。
错误信息: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);
其它报相同的问题按照相同方式修改即可。
错误信息:错误: '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博客