参考文章:
《https://blog.csdn.net/understand125/article/details/87968043》
《https://blog.csdn.net/zcshoucsdn/article/details/76037463》
《https://www.cnblogs.com/oloroso/p/5407779.html》等
当前最新的QT版本是5.13,但QT5.9是长期维护的版本,这里选用了5.9.8版本。
到http://download.qt.io/archive/qt/官网下载qt-everywhere-opensource-src-5.9.8.tar.xz
我们要编译一个支持Hi3536 gpu的QT库,这里假设Hi3536的sdk安装路径为/home/default/work/Hi3536_SDK_V2.0.6.0
# 解压
xz -d qt-everywhere-opensource-src-5.9.8.tar.xz
tar -xf qt-everywhere-opensource-src-5.9.8.tar
解压好后,我们需要修改编译链相关的文件,以便make能找到相应的平台及其交叉编译工具链:
# 进入平台配置目录
cd qt-everywhere-opensource-src-5.9.8/qtbase/mkspecs
# 复制linux-arm-gnueabi-g++目录为linux-hi3536-g++
cp -dr linux-arm-gnueabi-g++ linux-hi3536-g++
# 修改 qmake.conf,配置如下
#
# qmake configuration for building with arm-linux-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)
DEFINES += EGL_FBDEV
# gpu 注意路径为Hi3536的SDK目录
QMAKE_INCDIR_EGL += /home/default/work/Hi3536_SDK_V2.0.6.0/mpp_master/component/gpu/release/include
QMAKE_LIBDIR_EGL += /home/default/work/Hi3536_SDK_V2.0.6.0/mpp_master/component/gpu/release/lib
QMAKE_LIBS_EGL += -lmali
QMAKE_INCDIR_OPENGL_ES2 += /home/default/work/Hi3536_SDK_V2.0.6.0/mpp_master/component/gpu/release/include
QMAKE_LIBDIR_OPENGL_ES2 += /home/default/work/Hi3536_SDK_V2.0.6.0/mpp_master/component/gpu/release/lib
QMAKE_LIBS_OPENGL_ES2 += -lmali
EGLFS_DEVICE_INTEGRATION = eglfs_mali
# modifications to g++.conf
#或者加入海思的一些编译选项 -march=armv7-a -mfloat-abi=softfp -mfpu=neon-vfpv4 -mno-unaligned-access -fno-aggressive-loop-optimizations
QMAKE_CC = arm-hisiv400-linux-gcc
QMAKE_CXX = arm-hisiv400-linux-g++
QMAKE_LINK = arm-hisiv400-linux-g++
QMAKE_LINK_SHLIB = arm-hisiv400-linux-g++
# modifications to linux.conf
QMAKE_AR = arm-hisiv400-linux-ar cqs
QMAKE_OBJCOPY = arm-hisiv400-linux-objcopy
QMAKE_NM = arm-hisiv400-linux-nm -P
QMAKE_STRIP = arm-hisiv400-linux-strip
load(qt_config)
修改好交叉编译工具链后,就可以生成可用的makefile了
./configure -prefix /home/default/work/other/qt_source/qt598_hi3536 -opensource -confirm-license -release \
-strip -eglfs -linuxfb -qt-zlib -no-gif -qt-libpng -qt-libjpeg -qt-freetype \
-no-rpath -no-pch -no-avx -no-openssl -no-cups -no-dbus -no-pkg-config \
-no-glib -no-iconv -xplatform linux-hi3536-g++ -make libs -opengl es2 \
-nomake examples -nomake tools -qt-sqlite
成功编译后发现生成的库太大了,其实可以裁剪一下,可改为:
./configure -prefix /home/default/work/other/qt_source/qt598_hi3536 -opensource -confirm-license -release \
-strip -eglfs -linuxfb -qt-zlib -no-gif -qt-libpng -qt-libjpeg -qt-freetype \
-no-rpath -no-pch -no-avx -no-openssl -no-cups -no-dbus -no-pkg-config \
-no-glib -no-iconv -xplatform linux-hi3536-g++ -make libs -opengl es2 \
-nomake examples -nomake tools -qt-sqlite \
-skip qtgamepad \
-skip qtandroidextras \
-skip qtmacextras \
-skip qtx11extras \
-skip qtsensors \
-skip qtserialbus \
-skip qtserialport \
-skip qtwebengine \
-skip qtwebchannel \
-skip qtwebsockets \
-skip qtlocation \
-skip qtquickcontrols \
-skip qtpurchasing \
-skip qtconnectivity \
-skip qtscxml \
-skip qtxmlpatterns \
-skip qtnetworkauth \
-skip qtspeech \
-skip qtscript \
-skip qtremoteobjects \
-skip qtcharts \
-skip qtdatavis3d \
-skip qtwebview
当然,如果编译不出错的话,建议使用第一个configure,其实可以在写qt程序时,
根据用到什么库就拷贝什么库进海思的文件系统/lib/内,这样体积也会比较小!没必要通过configure裁剪
其中-no-iconv是为了防止运行板内程序后,iconv无法格式转换的报错。
如果使用虚拟机来编译QT,那么虚拟机必须要开启swap,否则会出现gcc报错:
g++: internal compiler error: Killed (program cc1plus)
Please submit a full bug report
至少4GB交换内存:
sudo dd if=/dev/zero of=/swapfile bs=64M count=64
sudo mkswap /swapfile
sudo swapon /swapfile
make时尽量不要开多个任务进行编译,形如:make -j20等,怀疑多个任务先后顺序不确定会导致一些编译错误,例如:
编译3D相关内容时会出现:
IFCLoader.cpp:(.text+0x963c): undefined reference to `Assimp::IFC::GetSchema(Assimp::STEP::EXPRESS::ConversionSchema&)'
我们使用最简单的make即可
make
make install
此时,/home/default/work/other/qt_source/qt598_hi3536安装好了QT
我们编写qt程序用于测试编译出来的库。qt程序的编写超出本博客范围,不作介绍。
安装目录qt598_hi3536/bin/qmake工具用于生成Makefile,嵌入式惯用make编译代码。当然也可以使用QT Creator进行IDE开发(最好使用版本一致的IDE,防止在pc上能编译,使用3536的qmake编译不了,还生成奇怪的Makefile.test),需要指定交叉编译工具链、qmake路径。
到这一步,假设已经编译出“demo”,可以放进Hi3536板子(以下简称目标板)运行了。
运行前,目标板需搭建好QT的运行环境:
1,将安装文件夹qt598_hi3536下的lib、plugins、和qml拷贝到目标板的/lib/Qt文件夹下(使用“cp -dr”把符号链接也拷贝过去),在该QT目录下创建fonts目录,并拷贝simsun.ttf新宋体字库进去。如果文件系统空间有限,lib就只拷贝用到的so库即可。譬如,注意到目标板只会用到动态链接库*.so*,不会用到*.a的,除非你在目标板内编译代码。也用不到*.la/*.prl/cmake/pkgconfig这些文件,为了节省目标板flash空间,这些都可以删掉,qml文件夹也用不到的话可以删掉。
下面是一些可以删除的库和文件,仅供参考:
cd QT/
rm lib/*.a
rm lib/*.la
rm lib/*.prl
rm lib/*3D*
rm lib/*Quick*
rm lib/*Positioning*
rm lib/*Purchasing*
rm lib/*PrintSupport*
rm lib/*Nfc*
rm lib/*Bluetooth*
rm lib/*Charts*
rm lib/*Script*
rm lib/*DataVisualization*
rm lib/*Serial*
rm lib/*Scxml*
rm lib/*Speech*
rm lib/*NetworkAuth*
rm lib/*XmlPatterns*
rm lib/*Sensors*
rm lib/*Gamepad*
rm lib/*Web*
rm lib/*Location*
rm lib/*Test*
rm -fr lib/cmake
rm -fr lib/pkgconfig
rm -fr plugins/gamepads
rm -fr plugins/sensorgestures
rm -fr plugins/sensors
rm -fr plugins/position
rm -fr plugins/canbus
注意不要删除你编译出来的qt598_hi3536内的东西,毕竟qt598_hi3536里面的库可能在其他项目中会用到,删了这些项目就因缺库编译不通过了
2,将udev相关so动态库放入/usr/lib下,libQT5xxx.so.xxx依赖该库
default@default:~/work/other/qt_source/depend$ ls -l
total 1312
-rw-r--r-- 1 default default 777008 8月 29 00:26 libudev.a
-rwxr-xr-x 1 default default 964 8月 29 00:26 libudev.la
lrwxrwxrwx 1 default default 16 8月 29 00:26 libudev.so -> libudev.so.1.6.3
lrwxrwxrwx 1 default default 16 8月 29 00:26 libudev.so.1 -> libudev.so.1.6.3
-rwxr-xr-x 1 default default 560071 8月 29 00:26 libudev.so.1.6.3
arm-hisiv400-linux-没有安装udev库,需手动编译,移步《https://blog.csdn.net/litao31415/article/details/95897821》编译eudev源码。
3,安装海思GPU库和驱动。Hi3536的GPU驱动和动态链接库在Hi3536_SDK_V2.0.6.0/mpp_master/component/gpu/release下面,将release目录拷贝到目标板的/lib下,并重命名为“gpu”。
4,设置环境变量 ,保存为qt_env.sh
#! /bin/sh
export GPU_LIB_PATH=/lib/gpu/lib
export QT_ROOT=/lib/QT/
export QT_QPA_FONTDIR=$QT_ROOT/fonts
export QT_QPA_PLATFORM=eglfs
export QT_QPA_EGLFS_FB=/dev/fb0
export QT_QPA_PLATFORM_PLUGIN_PATH=$QT_ROOT/plugins
export QT_QPA_EGLFS_WIDTH=1920
export QT_QPA_EGLFS_HEIGHT=1080
export QT_QPA_EGLFS_PHYSICAL_WIDTH=320
export QT_QPA_EGLFS_PHYSICAL_HEIGHT=240
export QT_QPA_EGLFS_DEPTH=16
export QT_QPA_EGLFS_INTEGRATION=eglfs_mali
export QT_QPA_EGLFS_ALWAYS_SET_MODE=1
export QML_IMPORT_PATH=$QT_ROOT/qml
export QML2_IMPORT_PATH=$QT_ROOT/qml
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$GPU_LIB_PATH:/$QT_ROOT/lib
# for debug
#export QT_QPA_EGLFS_DEBUG=1
#export QT_LOGGING_RULES=qt.qpa.*=true
5,导出环境变量: “. qt_env.sh”,本质上是“source qt_env.sh”
6,安装gpu驱动:
使用" sh /lib/gpu/ko/loadgpu -i "加载以下GPU驱动:
kds.ko
hi_dbe.ko
mali_kbase.ko
这时应该就可以运行eglfs平台的qt程序了(你就想!!)。
其实是不行的,因为/dev/fb0还没准备好。至少要初始化VO后才能显示,这里使用HDMI输出,使用sample下面的vo、vdec、hifb都可以。
但由于/dev/fb0默认使用1280x720的分辨率,同时我们设置QT宽高环境变量为1920x1080,所以demo会运行出错:EGL Error : Could not create the egl surface: error = 0x300b的错误。
可以修改环境变量,设置小一点的分辨率,如:
export QT_QPA_EGLFS_WIDTH=1280
export QT_QPA_EGLFS_HEIGHT=720
export QT_QPA_EGLFS_PHYSICAL_WIDTH=216
export QT_QPA_EGLFS_PHYSICAL_HEIGHT=135
其中,带PHYSICAL这个是物理宽高,可以拿尺子进行测量得到,单位毫米。
这种虽能显示,但我要的是1920x1080或者更大的分辨率输出啊!还是没能解决问题!!
QT与fb是独立配置的,我们可以尝试一下先配置好GPU和/dev/fb0,再运行qt程序。参考源文件Hi3536_SDK_V2.0.6.0/mpp_master/sample/gpu/common/egl/src/hi_egl.c,它封装成hi_egl_setup()接口了,简单修改一下就可以按分辨率初始化GPU和/dev/fb0了。我们写一个小程序,调用该接口,配置GPU为1920x1080、ARGB8888等属性。并且把QT环境变量改回来1920和1080,再一次运行demo,发现能正常运行qt程序了!
当然,/dev/fb0还有很多可配置的属性,诸如RGB1555,Colorkey,Alpha透明等拓展功能,具体参考HiFb相关文档,已超出本博客范围。
另外,注意Hi3536默认的fb缓冲区是不够4K的,如果QT要输出3840x2160分辨率的话需要修改ko/load3536脚本否则通过hi_egl.c设置HiFB时会报错:
譬如只用到G0和鼠标层G3这两个图形层则
insmod hifb.ko video="hifb:vram0_size:32400,vram1_size:8100,vram2_size:2160,vram3_size:128,vram4_size:128" softcursor="off"
改为:
insmod hifb.ko video="hifb:vram0_size:64800,vram3_size:128" softcursor="off"
最后,谈一下上述编译出来的QT库重命名、拷贝到其他PC上的情况
把qt安装目录拷贝到另外一台电脑时,qmake报错,无法生成Makefile,需要做以下步骤:
1、qmake -v
QMake version 3.1
Using Qt version 5.9.8 in ....../lib
查看原本编译时用的lib路径
在安装路径bin文件夹下(即qmake所在路径)创建一个qt.conf文件,重新定义安装路径:
[Paths]
Prefix=/home/default/work/other/qt_source/hi3539_qt598
2、还要注意安装目录下mkspecs/linux-hi3536-g++的qmake.conf文件内的QMAKE_INCDIR_EGL
等使用了Hi3536 GPU相关的绝对路径,拷贝到第二台电脑时,也需要更改这些路径。因为make目标板的qt程序时,需要用到这些路径找so库。
漏了一点,很重要,键鼠热插拔问题!
export QT_QPA_GENERIC_PLUGINS=evdevmouse:/dev/input/event0,evdevkeyboard:/dev/input/event1
这个环境变量指定了键鼠的设备。但弱点很明显,必须先知道键盘一定是/dev/input/event1,而鼠标一定是/dev/input/event0才行。同时必须要先配好QT_QPA_GENERIC_PLUGINS后运行QT程序才能控制,当你拔掉键鼠后,重新插入,就无法操控QT。假设设备号没有变,要kill掉QT程序,再一次运行才行。如果重新插入后,设备都改变了,譬如鼠标变成了/dev/input/ecent1了,这时,你还需要先重新配置QT_QPA_GENERIC_PLUGINS,再重启QT程序。
我是怎么解决掉这个问题的呢?请听下回分解。