介绍
本文记录了QT交叉编译并移植到开发板的过程,并在虚拟机上用QTcreater 开发程序,到开发板上运行。其中重点解决了一些过程中的BUG和坑。
准备工作
1、一个ubuntu系统的电脑(或虚拟机)
2、arm64位开发板
3、QT源代码软件包 qt-everywhere-opensource-src-5.9.6.tar.xz
4、linaro交叉编译器
5、tslib
6、sqlite3
7、开发板根文件系统,其中包含了OpenGL ES3的库文件和头文件。
步骤
一、交叉编译环境搭建
直接参考文章linux_ubuntu_gcc-linaro-7.4.1交叉编译器安装
其中建议安装aarch64最新版交叉编译器
二、tslib和sqlite3的交叉编译与移植
直接参考文章
ARM40之TSLIB移植
移植SQLite3到ARM40-A5
三、交叉编译QT
1、首先解压qt开源源码后,编辑相关的qmake.conf文件,由于我用的是arm64位的开发板,所以编译的是linux-aarch64-gnu-g++这个 目录下的qmake.conf
vim ~/qt-everywhere-opensource-src-5.9.6/qtbase/mkspecs/linux-aarch64-gnu-g++/qmake.conf
参考以下代码
#
# qmake configuration for building with aarch64-linux-gnu-g++
#
MAKEFILE_GENERATOR = UNIX
CONFIG += incremental
QMAKE_INCREMENTAL_STYLE = sublib
QMAKE_CFLAGS_RELEASE += -O2 -march=armv8-a -mtune=cortex-a53 #指定处理器架构
QMAKE_CXXFLAGS_RELEASE += -O2 -march=armv8-a -mtune=cortex-a53
include(../common/linux.conf)
include(../common/gcc-base-unix.conf)
include(../common/g++-unix.conf)
QMAKE_INCDIR = KaTeX parse error: Expected 'EOF', got '#' at position 204: … #̲指定sysroot头文件 QM…[QT_SYSROOT]/usr/lib #指定sysroot库文件
QMAKE_LIBDIR += KaTeX parse error: Expected 'EOF', got '#' at position 311: …u #̲指定sysroot库文件 QM…[QT_SYSROOT]/lib #指定sysroot库文件
QMAKE_INCDIR += /opt/tslib/include /opt/sqlite3/include #指定tslib和sqlite头文件,需预编译
QMAKE_LIBDIR += /opt/tslib/lib /opt/sqlite3/lib #指定tslib和sqlite库文件,需预编译
QMAKE_CXXFLAGS += -ludev -lffi #链接选项
QMAKE_LFLAGS += -Wl,-rpath-link,KaTeX parse error: Expected 'EOF', got '#' at position 191: … #̲链接sysroot库文件 QM…[QT_SYSROOT]/usr/lib/aarch64-linux-gnu #链接sysroot库文件
QMAKE_LFLAGS += -Wl,-rpath-link $$[QT_SYSROOT]/lib #链接sysroot库文件
QMAKE_INCDIR_OPENGL[_ES2] +=
<
s
p
a
n
c
l
a
s
s
=
"
t
o
k
e
n
p
u
n
c
t
u
a
t
i
o
n
"
>
[
<
/
s
p
a
n
>
Q
T
S
Y
S
R
O
O
T
<
s
p
a
n
c
l
a
s
s
=
"
t
o
k
e
n
p
u
n
c
t
u
a
t
i
o
n
"
>
]
<
/
s
p
a
n
>
<
s
p
a
n
c
l
a
s
s
=
"
t
o
k
e
n
o
p
e
r
a
t
o
r
"
>
/
<
/
s
p
a
n
>
u
s
r
<
s
p
a
n
c
l
a
s
s
=
"
t
o
k
e
n
o
p
e
r
a
t
o
r
"
>
/
<
/
s
p
a
n
>
i
n
c
l
u
d
e
<span class="token punctuation">[</span>QT_SYSROOT<span class="token punctuation">]</span><span class="token operator">/</span>usr<span class="token operator">/</span>include \
<spanclass="tokenpunctuation">[</span>QTSYSROOT<spanclass="tokenpunctuation">]</span><spanclass="tokenoperator">/</span>usr<spanclass="tokenoperator">/</span>include [QT_SYSROOT]/usr/include/EGL
<
s
p
a
n
c
l
a
s
s
=
"
t
o
k
e
n
p
u
n
c
t
u
a
t
i
o
n
"
>
[
<
/
s
p
a
n
>
Q
T
S
Y
S
R
O
O
T
<
s
p
a
n
c
l
a
s
s
=
"
t
o
k
e
n
p
u
n
c
t
u
a
t
i
o
n
"
>
]
<
/
s
p
a
n
>
<
s
p
a
n
c
l
a
s
s
=
"
t
o
k
e
n
o
p
e
r
a
t
o
r
"
>
/
<
/
s
p
a
n
>
u
s
r
<
s
p
a
n
c
l
a
s
s
=
"
t
o
k
e
n
o
p
e
r
a
t
o
r
"
>
/
<
/
s
p
a
n
>
i
n
c
l
u
d
e
<
s
p
a
n
c
l
a
s
s
=
"
t
o
k
e
n
o
p
e
r
a
t
o
r
"
>
/
<
/
s
p
a
n
>
G
L
E
S
2
<span class="token punctuation">[</span>QT_SYSROOT<span class="token punctuation">]</span><span class="token operator">/</span>usr<span class="token operator">/</span>include<span class="token operator">/</span>GLES2 \
<spanclass="tokenpunctuation">[</span>QTSYSROOT<spanclass="tokenpunctuation">]</span><spanclass="tokenoperator">/</span>usr<spanclass="tokenoperator">/</span>include<spanclass="tokenoperator">/</span>GLES2 [QT_SYSROOT]/usr/include/GLES3
<
s
p
a
n
c
l
a
s
s
=
"
t
o
k
e
n
p
u
n
c
t
u
a
t
i
o
n
"
>
[
<
/
s
p
a
n
>
Q
T
S
Y
S
R
O
O
T
<
s
p
a
n
c
l
a
s
s
=
"
t
o
k
e
n
p
u
n
c
t
u
a
t
i
o
n
"
>
]
<
/
s
p
a
n
>
<
s
p
a
n
c
l
a
s
s
=
"
t
o
k
e
n
o
p
e
r
a
t
o
r
"
>
/
<
/
s
p
a
n
>
u
s
r
<
s
p
a
n
c
l
a
s
s
=
"
t
o
k
e
n
o
p
e
r
a
t
o
r
"
>
/
<
/
s
p
a
n
>
i
n
c
l
u
d
e
<
s
p
a
n
c
l
a
s
s
=
"
t
o
k
e
n
o
p
e
r
a
t
o
r
"
>
/
<
/
s
p
a
n
>
K
H
R
Q
M
A
K
E
L
I
B
D
I
R
O
P
E
N
G
L
<
s
p
a
n
c
l
a
s
s
=
"
t
o
k
e
n
p
u
n
c
t
u
a
t
i
o
n
"
>
[
<
/
s
p
a
n
>
E
S
2
<
s
p
a
n
c
l
a
s
s
=
"
t
o
k
e
n
p
u
n
c
t
u
a
t
i
o
n
"
>
]
<
/
s
p
a
n
>
<
s
p
a
n
c
l
a
s
s
=
"
t
o
k
e
n
o
p
e
r
a
t
o
r
"
>
+
=
<
/
s
p
a
n
>
<span class="token punctuation">[</span>QT_SYSROOT<span class="token punctuation">]</span><span class="token operator">/</span>usr<span class="token operator">/</span>include<span class="token operator">/</span>KHR QMAKE_LIBDIR_OPENGL<span class="token punctuation">[</span>_ES2<span class="token punctuation">]</span> <span class="token operator">+=</span> \
<spanclass="tokenpunctuation">[</span>QTSYSROOT<spanclass="tokenpunctuation">]</span><spanclass="tokenoperator">/</span>usr<spanclass="tokenoperator">/</span>include<spanclass="tokenoperator">/</span>KHRQMAKELIBDIROPENGL<spanclass="tokenpunctuation">[</span>ES2<spanclass="tokenpunctuation">]</span><spanclass="tokenoperator">+=</span> [QT_SYSROOT]/usr/lib
QMAKE_INCDIR_EGL += Q M A K E I N C D I R O P E N G L < s p a n c l a s s = " t o k e n p u n c t u a t i o n " > [ < / s p a n > E S 2 < s p a n c l a s s = " t o k e n p u n c t u a t i o n " > ] < / s p a n > Q M A K E L I B D I R E G L < s p a n c l a s s = " t o k e n o p e r a t o r " > + = < / s p a n > QMAKE_INCDIR_OPENGL<span class="token punctuation">[</span>_ES2<span class="token punctuation">]</span> QMAKE_LIBDIR_EGL <span class="token operator">+=</span> QMAKEINCDIROPENGL<spanclass="tokenpunctuation">[</span>ES2<spanclass="tokenpunctuation">]</span>QMAKELIBDIREGL<spanclass="tokenoperator">+=</span>QMAKE_LIBDIR_OPENGL[_ES2]
QMAKE_INCDIR_OPENVG +=
Q
M
A
K
E
I
N
C
D
I
R
O
P
E
N
G
L
<
s
p
a
n
c
l
a
s
s
=
"
t
o
k
e
n
p
u
n
c
t
u
a
t
i
o
n
"
>
[
<
/
s
p
a
n
>
E
S
2
<
s
p
a
n
c
l
a
s
s
=
"
t
o
k
e
n
p
u
n
c
t
u
a
t
i
o
n
"
>
]
<
/
s
p
a
n
>
Q
M
A
K
E
L
I
B
D
I
R
O
P
E
N
V
G
<
s
p
a
n
c
l
a
s
s
=
"
t
o
k
e
n
o
p
e
r
a
t
o
r
"
>
+
=
<
/
s
p
a
n
>
QMAKE_INCDIR_OPENGL<span class="token punctuation">[</span>_ES2<span class="token punctuation">]</span> QMAKE_LIBDIR_OPENVG <span class="token operator">+=</span>
QMAKEINCDIROPENGL<spanclass="tokenpunctuation">[</span>ES2<spanclass="tokenpunctuation">]</span>QMAKELIBDIROPENVG<spanclass="tokenoperator">+=</span>QMAKE_LIBDIR_OPENGL[_ES2]
# QMAKE_LIBS_OPENGL[_ES2] += -lEGL -lGLESv2
QMAKE_LIBS_EGL = -lEGL -lGLESv2
QMAKE_LIBS_OPENGL[_ES2] = -lglapi -lGLESv2 -lEGL
#QMAKE_LIBS_OPENGL[_ES2] += -lbrcmEGL -lbrcmGLESv2
# modifications to g++.conf
QMAKE_CC = /opt/gcc-arm-10.2-2020.11-x86_64-aarch64-none-linux-gnu/bin/aarch64-none-linux-gnu-gcc
QMAKE_CXX = /opt/gcc-arm-10.2-2020.11-x86_64-aarch64-none-linux-gnu/bin/aarch64-none-linux-gnu-g++
QMAKE_LINK = /opt/gcc-arm-10.2-2020.11-x86_64-aarch64-none-linux-gnu/bin/aarch64-none-linux-gnu-g++
QMAKE_LINK_SHLIB = /opt/gcc-arm-10.2-2020.11-x86_64-aarch64-none-linux-gnu/bin/aarch64-none-linux-gnu-g++
# modifications to linux.conf
QMAKE_AR = /opt/gcc-arm-10.2-2020.11-x86_64-aarch64-none-linux-gnu/bin/aarch64-none-linux-gnu-ar cqs
QMAKE_OBJCOPY = /opt/gcc-arm-10.2-2020.11-x86_64-aarch64-none-linux-gnu/bin/aarch64-none-linux-gnu-objcopy
QMAKE_NM = /opt/gcc-arm-10.2-2020.11-x86_64-aarch64-none-linux-gnu/bin/aarch64-none-linux-gnu-nm -P
QMAKE_STRIP = /opt/gcc-arm-10.2-2020.11-x86_64-aarch64-none-linux-gnu/bin/aarch64-none-linux-gnu-strip
load(qt_config)
上述代码主要注意以下几点
(1)、QT_SYSROOT为你开发板的根文件系统,你可以拷贝到电脑上或者挂载到电脑上。下面./configure时会指定这个目录。
(2)、配置sysroot,tslib,sqlite。opengl es2的头文件,库文件,以及编译时的符号和库文件。
(3)、指定交叉编译器路径
2、在qt-everywhere-opensource-src-5.9.6下面新建autoconf.sh文件,保存编译选项
#!/bin/sh
./configure \
-v \
-confirm-license \
-prefix /opt/qt5.9.6 \
-release \
-opensource \
-accessibility \
-make libs \
-xplatform linux-aarch64-gnu-g++ \
-pch \
-tslib \
-sqlite \
-qt-libjpeg \
-qt-libpng \
-qt-zlib \
-qt-freetype \
-opengl es2 \
-nomake examples -nomake tools \
-sysroot ~/sysroot \ //sysroot为开发板的根文件系统
-I ~/sysroot/usr/include \
-L ~/sysroot/usr/lib \
-L ~/sysroot/usr/lib/aarch64-linux-gnu \
-L ~/sysroot/lib
之后sudo chmod a+x autoconf.sh,使其可执行。
3、交叉编译QT
这部分是最恶心的部分,bug尤其多
(1)执行./autoconf.sh,进行编译。
这部分一般不会出错
(2)make -j4
这部分会有问题,会出现.h或者.so缺失问题,举例:如下所示:
In file included from /home/wadexu/debian_buster_renesas_OpenGL_for_QT_15.1/usr/include/sys/stat.h:446,
from ../../mkspecs/linux-aarch64-gnu-g++/../linux-g++/qplatformdefs.h:75,
from ../../mkspecs/linux-aarch64-gnu-g++/qplatformdefs.h:40,
from global/qmalloc.cpp:40:
/opt/gcc-arm-10.2-2020.11-x86_64-aarch64-none-linux-gnu/lib/gcc/aarch64-none-linux-gnu/10.2.1/include-fixed/bits/statx.h:48:10: fatal error: bits/statx-generic.h: 没有那个文件或目录
48 | #include <bits/statx-generic.h>
| ^~~~~~~~~~~~~~~~~~~~~~
compilation terminated.
编译过程中报错,缺少<bits/statx-generic.h>。其实这个头文件是在sysroot中的,但是由于交叉编译器在搜索头文件路径时,会优先从自己的目录中搜索,导致引用的文件缺失。所以你需要在sysroot中,用find指令找到对应的头文件,并拷贝到/opt/gcc-arm-10.2-2020.11-x86_64-aarch64-none-linux-gnu/lib/gcc/aarch64-none-linux-gnu/10.2.1/include-fixed/bits这个报错的目录中去。
这种情况大约会出现几十次,都以这种方式处理即可。
之后make执行完成,没有错误再出现(警告不用管)
(3)sudo make install
执行完成后,qt会安装到你~/sysroot/opt/qt5.9.6下面。把qt5.9.6拷贝到你开发板的/opt/下面即可。
四、开发QT程序
参考文章
linux下如何利用QtCreator编译ARM版本的Qt程序
注意以下几点
1、交叉编译QT程序,需要按照上述链接,指定构建环境、配置为交叉编译器,交叉编译后的gdb、交叉编译后的qt。
2、交叉编译的QT程序,选择为release模式,编译无报错即可。点击运行是运行不了的,因为你的电脑是X86的,引用arm64下面相关的.so会报错。
五、在开发板上运行QT程序
1、首先将电脑上交叉编译的qt5.9.6拷贝到开发板上,目录为/opt/qt5.9.6
2、配置开发板环境变量
sudo vim /etc/profile
export QTDIR=/opt/qt5.9.6
export QT_QPA_FONTDIR=$QTDIR/lib/fonts
export QT_QPA_PLATFORM_PLUGIN_PATH=$QTDIR/plugins
export LD_LIBRARY_PATH=$QTDIR/lib:$LD_LIBRARY_PATH
export PATH=$QTDIR/bin:$PATH
export PKG_CONFIG_PATH=$QTDIR/lib/pkgconfig/$PKG_CONFIG_PATH
source /etc/profile 使其生效
3、链接缺失的fonts文件到qt下面
ln -snf /usr/share/fonts/truetype/dejavu /opt/qt5.9.6/lib/fonts
4、将电脑上编译好的release文件夹拷贝到开发板上,以root身份执行可执行文件。
我的QT程序叫QtDemo,我将其拷贝到开发板上后,如下图所示:
执行./QtDemo即可在显示屏上出现自己的QT界面。
简单聊聊
想要在开发板上显示界面,你需要安装一个显示服务器,X11或者wayland这种都可以。如果想要用opengl es,需要开发板上包含gpu,并且有gpu厂家提供的opengl es 库文件以及头文件。这些在上述安装过程中,是已经安装好了的。