继上面给BananaPro编译好GPU的驱动后,已经迫不及待地要把Qt移植到开发板上看看效果。但是过程并不省心,主要还是一些概念没有弄清楚,导致了各种奇葩的错误。所以在做一件事情之前一定要阅读大量的文档,尤其是官方的文档,这样不仅能够减少走的弯路,更是最快的捷径。在这里是通过交叉编译的方式移植最新版的Qt5.6.0到BananaPro,这也是继Qt4.8之后的Qt5的首个LTS版。
- 像上面说的一样,首先需要做的阅读大量的文档,尤其是官方的文档。在这里例举几个:
- 在阅读完这些文档之后确保你已经对下面的这些概念已经熟悉了:
- QPA/QWS:QPA是Qt5提出的新的概念用于代替Qt4的QWS,利用的是平台抽象的概念,与之前的QWS的C/S架构不同的是QPA是可以直接和底层的硬件驱动进行通信的,而不需要通过Server。因此也抽象出了一些平台的插件,比如说EGLFS、LinuxFB、、KMS、 DirectFB、Wayland等
- device的概念。与之前用(平台/架构/编译器/操作系统)区分编译不同的,在Qt的嵌入式平台的移植中,Qt允许开发者指定自己的device,在这个device中定义自己的一些参数和变量,然后进行编译,官方的device中有树莓派等device,而开发者完全可以自己新建一device然后对device的一些配置进行自定义。
- sysroot的概念。这是至关重要的一个概念,sysroot的提出事非常perfect的。通过制定sysroot也就是device的rootfs,可以使用完全适合目标device的一些库,而不需要在交叉编译的宿主机上进行安装。之前就是没有理解清楚这个概念导致花了很多时间还遇到很多的问题。
- 开始交叉编译Qt5.6.0的准备工作。在开始之前,我们需要以下内容:
- 一台安装有检查编译工具的宿主机(我用的是Ubuntu 14.04 LTS 系统),最好CPU要快一些。
- 一张存有开发板的系统镜像的TF卡(不清楚直接使用镜像挂载行不行,原理上不行因为IMG都是只读,而安装时要进行写的)。
- 下载好的Qt源码包:
qt-everywhere-opensource-src-5.6.0.tar.gz
- 装有各种dev套件的镜像(如果需要比较全的功能的Qt的话)。
- 开始设置编译Qt的选项。
- 首先解压
tar -xvf qt-everywhere-opensource-src-5.6.0.tar.gz
,这个解压貌似也是有坑的,就是删除原来的旧代码重新解压的时候解压不完全就是有的文件没有解压出来,这种情况可以吧v选项去掉,再者就是确保当前要删除的目录没有被其他的进程所占用。 - 然后把tf卡中的rootfs挂载到/mnt/bananapro
- 新建一个配置文件,在
./qt-everywhere-opensource-src-5.6.0/qtbase/mkspecs/devices
目录下可以看到很多的device,比如linux-rasp-pi2-g++
我们copy该文件夹一份并且重命名为bananapro
,这个文件夹里面包含了编译的各种配置变量。下面就可以修改该配置文件以适合我们的要求,打开该文件夹可以看到两个文件:qplatformdefs.h
中包含了Qt的宿主机平台有关的基本配置,可以看到里面就一行#include "../../linux-g++/qplatformdefs.h"
,我们再打开该文件可以看到里面就是包含了各种宿主机头文件。- qmake.conf 中便是主要的配置选项。
- 可以看到开头的
include(../common/linux_device_pre.conf)
这个文件里面有以下配置:QT_QPA_DEFAULT_PLATFORM = eglfs
配置默认的平台插件MAKEFILE_GENERATOR = UNIX
配置makefile生成的平台CONFIG += incremental
配置使用增量链接然后又包含了三个文件:
include(../../common/linux.conf)这个文件主要是配置编译时编译器,链接器以及一些库的选项,比如
QMAKE_LIBS_OPENGL_ES2 = -lGLESv2
include(../../common/g++-unix.conf)主要用于配置G++
接着
QMAKE_CC = $${CROSS_COMPILE}gcc
等配置重新设置了交叉编译的编译工具。
- 接着在qmake.conf中有以下至关重要的内容:
DEFAULT_INCDIRS += /usr/include/c++/4.8/
添加宿主机默认的库QMAKE_INCDIR += /mnt/bananapro/usr/include/c++/4.8
添加目标主机的库QMAKE_LFLAGS += -Wl,-rpath-link,$$[QT_SYSROOT]/usr/lib
LFLAGS选项可以设置自定义的可执行程序库文件查找路径QMAKE_LIBDIR_OPENGL_ES2 += /mnt/bananapro/usr/lib
设置GPU的驱动的库QMAKE_LIBDIR_OPENGL_ES2 += /mnt/bananapro/usr/local/lib
同上QMAKE_LIBDIR_OPENGL_ES2 += /mnt/bananapro/usr/lib/arm-linux-gnueabihf
设置OPENGL的驱动的头文件QMAKE_LIBDIR_OPENGL_ES2 += /mnt/bananapro/lib/arm-linux-gnueabihf
同上QMAKE_INCDIR_EGL += /mnt/bananapro/usr/include
设置EGL的驱动的头文件QMAKE_INCDIR_EGL += /mnt/bananapro/usr/include/drm
同上QMAKE_INCDIR_OPENGL_ES2 = $${QMAKE_INCDIR_EGL}
QMAKE_LIBS_EGL = -lEGL -lGLESv2
设置OPENGL的驱动的库文件QMAKE_CFLAGS += -march=armv7-a -marm -mthumb-interwork -mfpu=neon-vfpv4 -mtune=cortex-a7 -mabi=aapcs-linux
设置编译目标机器的平台及处理器相关的信息QMAKE_CXXFLAGS = $$QMAKE_CFLAGS
DISTRO_OPTS += hard-float
硬件支持浮点运算DISTRO_OPTS += deb-multi-arch
- 可以看到开头的
- 上面一定要设置好不然的话就会在编译过程多次中断遇到各种问题然后郁闷,如果设置好一般都是编译从头到尾一点问题都没有相当爽。上面设置好了之后就要开始生成编译要用的Makefile了,输入下面命令
./configure -release --opensource -confirm-license -device bananapro -device-option CROSS_COMPILE=arm-linux-gnueabihf- -prefix /opt/Qt5.6.0/armv7-a -sysroot /mnt/bananapro -v -hostprefix /opt/Qt5.6.0/host -opengl es2 -libinput
以配置Qt的Makefile,其中可选的选项如qt5_6_0_configure_options.txt所示。我们用到的各个选项的含义如下:
- -release 指定版本,也可以指定debug
- –opensource 开放源代码
- -confirm-license 确定使用的开源协议
- -device 指定设备
- CROSS_COMPILE 指定交叉编译工具链
- -prefix 指定Qt安装的目录
- -sysroot 指定目标设备的rootfs
- -v 把配置过程输出
- -hostprefix 指定宿主机文件输出的目录,里面会构建一些编译用到的qmake等内容。
- -opengl es2 指定使用的opengl版本。
整个编译过程你可能会看到这样的内容(视具体的需求情况而定):qt_5_6_0_configure_result.txt,另外还需要明确的是,这里的对应的东西是指你编译时包含或者不包含该模块,这样只会影响在你的目标机器进行编程时能/不能使用该模块。
- 生成makefile后就可以直接输入make进行编译,在这里有的可能会使用-j4的选项,但是这需要电脑的CPU靠谱,不然的话可能会出现编译的顺序错乱而导致一些难以预料的错误,所以这里建议使用单个线程进行编译。
- 如果幸运女神眷顾你的话那就不会出现任何的错误然后一路编译到尾,最后只需make install就可以安装了。另外我不建议使用类似这样的
-I/usr/arm-linux-gnueabihf/include/c++/4.8.2/
方式来引入包含文件,而是应该在device配置里面配置好。
但是绝大多数的人是得不到幸运女神的眷顾的,所以你可能会遇到下面这些令人疑惑的问题:
- C++版本问题,一定要对应。也就是说你的目标机的库的C++的版本和你的交叉编译工具的C++版本一定要对应在一起,如果版本不对应就会出现找不到某些库,或者某些头文件里面使用了没有定义的数据类型之类的错误。比如我在宿主机上使用了gcc的4.8.4的套件,那么你在你的目标机器上应该
apt-get install gcc-4.8 g++-4.8
来安装对应的版本的C++的库。 - 缺乏某个头文件。确定你的对应的宿主机里面安装了对应版本的dev库,这里强烈不建议通过将一些头文件移动到宿主机的方法来是的编译通过,因为即使编译通过也是无法在宿主机使用对应的库进行编码的。还有就是你安装了对应的dev库,但是它安装的目录和你配置里面的目录不同一个地方,这是你就需要添加包含的头文件库了。比如
c++11.cpp:40:19: fatal error: utility:没有那个文件或目录
的错误时可以通过添加QMAKE_INCDIR += /mnt/bananapro/usr/include/c++/5
来解决的。 - 缺乏某些链接库。这种情况一般要怀疑是不是链接库的软连接损坏了,比如找不到libudev.so你就可以
file libudev.so
来查看对应的库的信息,如果出现libudev.so: broken symbolic link to /lib/arm-linux-gnueabihf/libudev.so.1.6.4'
那么就是你的软链接出错了,这个时候你就需要重新建立软链接:sudo rm libudev.so
然后sudo ln ../../../lib/arm-linux-gnueabihf/libudev.so.1.6.4 libudev.so``file libudev.so
来查看链接建立好没有,如果出现libudev.so: ELF 32-bit LSB shared object, ARM, EABI5 version 1 (SYSV), dynamically linked, BuildID[sha1]=fbe533be2929994d59590d221823685df824caec, stripped
则说明已经修复好了。 - 缺乏某个模块。比如
fatal error: xcb/xcb_icccm.h: 没有那个文件或目录
这种错误就是缺乏某个某块导致的,这个可以在对应的模块的README中找到解决办法,一般是需要安装对应的依赖:sudo apt-get install 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-sync libxcb-sync0-dev libxcb-xfixes0-dev libxrender-dev libxcb-shape0-dev libxcb-randr0-dev libxcb-render-util0 libxcb-render-util0-dev libxcb-glx0-dev libxcb-xinerama0-dev
这个视不同的某块不同而解决的方法不同。