qt编译 能在wayland上运行的版本
1.编译环境
系统:ubuntu 20
qt版本:5.12.2
交叉编译工具链:通过yocto生成的交叉编译工具链,在进行编译前需要使用“source poky/oe-init-build-env”配置环境,若是其他工具链需要根据自己进行相关配置
2.修改相关文件
2.1 修改qmake.conf 文件
修改 qtbase/mkspecs/linux-aarch64-gnu-g++/qmake.conf 文件(也可以改其他文件,但后面的-xplatform 要指定对应的文件)
#
# 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_CXXFLAGS += -I/opt/poky/3.1.14/sysroots/aarch64-poky-linux/usr/include/drm -I/opt/poky/3.1.14/sysroots/aarch64-poky-linux/usr/include
QMAKE_CFLAGS += -I/opt/poky/3.1.14/sysroots/aarch64-poky-linux/usr/include/drm
# modifications to g++.conf
QMAKE_CC = aarch64-poky-linux-gcc
QMAKE_CXX = aarch64-poky-linux-g++
QMAKE_LINK = aarch64-poky-linux-g++
QMAKE_LINK_SHLIB = aarch64-poky-linux-g++
# modifications to linux.conf
QMAKE_AR = aarch64-poky-linux-ar cqs
QMAKE_OBJCOPY = aarch64-poky-linux-objcopy
QMAKE_NM = aarch64-poky-linux-nm -P
QMAKE_STRIP = aarch64-poky-linux-strip
# QMAKE_INCDIR_OPENGL_ES2 = /opt/poky/3.1.14/sysroots/aarch64-poky-linux/usr/include
# QMAKE_LIBDIR_OPENGL_ES2 = /opt/poky/3.1.14/sysroots/aarch64-poky-linux/usr/lib64
# QMAKE_INCDIR_EGL = /opt/poky/3.1.14/sysroots/aarch64-poky-linux/usr/include
# QMAKE_LIBDIR_EGL = /opt/poky/3.1.14/sysroots/aarch64-poky-linux/usr/lib64
# QMAKE_LIBS_EGL += -lmali
# QMAKE_LIBS_OPENGL_ES2 += -lmali
load(qt_config)
- 这里的交叉编译工具我用相对路径是因为前面的脚本配置好了环境变量,需要根据自己的情况进行配置
- 我还添加QMAKE_CXXFLAGS和QMAKE_CFLAGS,这里主要是处理头文件找不到的情况,我这里主要是drm找不到,加了后就解决bug了,如果有头文件找不到的问题都可以用试试
- 后面还有一些注释掉的东西,例如:QMAKE_LIBS_OPENGL_ES2 ,这里加了反而会出问题,编译出来的qt在运行时会去找mali库,而且还是在pc的路径动态库路径去找,而不是在运行的机器的动态库路径找。这个的添加是参考另外一位用瑞芯微的博主加的,好像有部分opengles的实现依赖mali所以必须添加,我这没这个问题。
2.2 添加run.sh脚本
在源码目录中添加qmake.conf 文件,用于保存configure编译的相关配置
#!/bin/sh
#PREFIX=/用户目录/qt5.12.2_aarch64_linux/
SYSROOT=/opt/poky/3.1.14/sysroots/aarch64-poky-linux
# export LD_LIBRARY_PATH=${SYSROOT}/usr/lib64:$LD_LIBRARY_PATH
export PKG_CONFIG_SYSROOT_DIR=${SYSROOT}
export PKG_CONFIG_LIBDIR=${SYSROOT}/usr/lib/pkgconfig:${SYSROOT}/usr/lib/aarch64-linux-gnu/pkgconfig:${SYSROOT}/lib/aarch64-linux-gnu/pkgconfig:${SYSROOT}/usr/share/pkgconfig
export PKG_CONFIG_PATH=${PKG_CONFIG_LIBDIR}
# export STAGING_DIR=${STAGING_DIR}:${SYSROOT}
# export CPLUS_INCLUDE_PATH=/opt/poky/3.1.14/sysroots/aarch64-poky-linux/usr/include/c++/8.3.0:$CPLUS_INCLUDE_PATH
./configure -extprefix /home/cwf/qt-sdk \
-xplatform linux-aarch64-gnu-g++ \
-sysroot /opt/poky/3.1.14/sysroots/aarch64-poky-linux \
-R /usr/lib64 \
-opensource \
-release \
-shared \
-opengl es2 \
-confirm-license \
-qt-zlib \
-qt-libpng \
-qt-libjpeg \
-qt-pcre \
-pkg-config \
-nomake examples \
-nomake tests \
-no-pch \
-recheck-all
-
PKG_CONFIG相关的环境变量,执行configure后会去检查各种东西,如果没配PKG_CONFIG相关变量会有警告,我这考虑到pkg-config能帮忙自动找很多包,加上能减少出错的可能性。
-
configure 相关配置
(1)extprefix :设置输出的SDK目录,prefix也可以设,但会加上sysroot,交叉编译时还是用extprefix 比较方便
(2)sysroot :交叉编译工具链的根目录,不设置大概报错,qt的依赖基本从这找
(3)R /usr/lib64 \:指定运行时动态库搜索路径,理论可以不加,一般都找得到,我这里时处理前面找mali库得bug,但没起作用。
(4)opensource :使用qt开源版本
(5)release :使用qt发布版本
(6)shared :编译出动态库
(7)opengl es2:编译Opengles ,要注意别再后面添加-no-opengl, 会屏蔽opengles的
(8)-confirm-license: 自动确认许可。
(9)-qt-zlib -qt-libpng -qt-libjpeg -qt-pcre:我超的一些组件,这种按需加,理论上讲但你知道你缺什么组件,就会加了。
(10)pkg-config:启动pkg-config,一般交叉编译工具链都带pkg-config,加上能自动找包,减少bug
(11)-nomake examples -nomake tests :例子和测试,sdk弄好后配qt create,然后编译例子,再传到板子,这样其实也挺快的
(12)-no-pch :好像和一些预编译相关,我遇到个bug和这个选项有点关系,加着一般不碍事
(13)recheck-all:丢弃所有缓存的配置测试结果。加着一般不碍事 -
到这为止会发现好像没有wayland的配置项,不过好像configure也没有wayland的配置项,但运行时会自动检测wayland,成功检测到wayland会有以下输出。(可能不同的工具链会有些区别,我这个只作为能在wayland上运行的一种参考配置。另外,一般用wayland的都支持opengl,所以opengles的选项一般都要加上)
Qt Wayland Drivers:
EGL .................................... yes
Raspberry Pi ........................... no
XComposite EGL ......................... no
XComposite GLX ......................... no
DRM EGL ................................ yes
libhybris EGL .......................... no
Shm emulation server buffer integration . yes
Qt Wayland Client ........................ yes
Qt Wayland Compositor .................... yes
- 运行成功后会出现以下输出
Qt is now configured for building. Just run 'make'.
Once everything is built, you must run 'make install'.
Qt will be installed into '/home/cwf/qt-sdk'.
3. qt运行环境配置
export PATH=$PATH:/qt-sdk/bin
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/ota:/qt-sdk/lib
export QT_PLUGIN_PATH=/qt-sdk/plugins/
export QT_QPA_PLATFORM=wayland
export QML_IMPORT_PATH=/qt-sdk/qml
export QML2_IMPORT_PATH=/qt-sdk/qml
- PATH 加上qt的执行文件目录
- LD_LIBRARY_PATH 加上qt库的目录
- QT_PLUGIN_PATH 设置插件目录,这里的插件主要是各个平台的插件例如wayland插件,x11插件,linuxfb插件
- QT_QPA_PLATFORM 要设置运行环境,这里是跑在wayland下,所以设置wayland
- QML_IMPORT_PATH和QML2_IMPORT_PATH 我用上了qml,所以要配置qml
4.编译时的一些错误
4.1 重编建议
编译时有时会出现非常多奇怪的错误,如果发现错误一环扣一环,建议删掉现在的源码,重新复制一份新的来编译,这样很多莫名其妙的错误都会消失。我用make clean,make distclean都是清理不干净的
4.2 头文件找不到
前面讲qmake.conf有提到如何处理
4.3 特殊bug,# include_next 报错
以下是报错logo
linux/usr/include/c++/8.3.0/algorithm:62,
from ../../include/QtCore/../../src/corelib/global/qglobal.h:142,
from ../../include/QtCore/qglobal.h:1,
from ../../include/QtGui/../../src/gui/kernel/qtguiglobal.h:43,
from ../../include/QtGui/qtguiglobal.h:1,
from accessible/qaccessible.h:40,
from accessible/qaccessible.cpp:40:
/opt/poky/3.1.14/sysroots/aarch64-poky-linux/usr/include/c++/8.3.0/cstdlib:75:15: fatal error: stdlib.h: No such file or directory
#include_next <stdlib.h>
报错位置是交叉编译工具链的源码,而非qt源码,我是没找到一些官方推荐的修改办法,我的修改方法应该可以让qt正常编译下去,仅作为一种修改参考
cstdlib源码
// Need to ensure this finds the C library's <stdlib.h> not a libstdc++
// wrapper that might already be installed later in the include search path.
#define _GLIBCXX_INCLUDE_NEXT_C_HEADERS
#include_next <stdlib.h>
#undef _GLIBCXX_INCLUDE_NEXT_C_HEADERS
#include <bits/std_abs.h>
修改后
// Need to ensure this finds the C library's <stdlib.h> not a libstdc++
// wrapper that might already be installed later in the include search path.
#define _GLIBCXX_INCLUDE_NEXT_C_HEADERS
//#include_next <stdlib.h>
#include <stdlib.h>
#undef _GLIBCXX_INCLUDE_NEXT_C_HEADERS
#include <bits/std_abs.h>
还有另外一种修改方法
fenv.h源码
#include <bits/c++config.h>
#if _GLIBCXX_HAVE_FENV_H
# include_next <fenv.h>
#endif
修改后
#include <bits/c++config.h>
#if _GLIBCXX_HAVE_FENV_H
//# include_next <fenv.h>
# include "../../fenv.h"
#endif
从cstdlib源码注释可以看出用# include_next是希望去找c相关的头文件而不是C++的(stdlib.h,c
++的头文件路径下有份,c下也有份)。我这里报错感觉是# include_next没起作用,没有在排除当前的目录的情况下去寻找c对应的文件。
话虽然是这样说,但改#include <stdlib.h>又不能像# include "…/…/fenv.h"这样指向c的文件,这里#include <stdlib.h>找的还是当前目录下的stdlib.h,如果有遇到类似问题可以试试我的这样的修改,至少能编下去,也能在板子上运行