Qt嵌入式解决方案(Qt5.14.2 + opengl 交叉编译移植至Jetson Nano 详细步骤)

在我需要将Qt应用程序运行到嵌入式arm linux平台上时,我了解到了两种方案:
Qt for Device Creation + Boot to Qt,这项技术相当诱人,虽然只有商业版Qt能够使用,但用了这么久的开源版本Qt,为其适当的付费也未尝不可;但是当我在Qt的官网上了解到公司商用Qt需要留下资料协商定价后,我就打消了这个念头,因为这充满了未知,谁也不知道他们想要如何定价,在Qt的官网上还有着相当嘲讽的广告:

Qt嵌入式解决方案(Qt5.14.2 + opengl 交叉编译移植至Jetson Nano 详细步骤)_第1张图片

交叉编译Qt源码,移植至arm linux,网上大部分资料都是较为老的Qt版本,而且这个过程还会伴随大量问题,尤其是需要附加opengl模块的时候更是灾难,但既然第一个方案被自我否决,那就只能使用这个方案了,当然,浮夸又时尚的我们选择一个较为新颖的Qt版本:5.14.2,以下是我交叉编译并移植至Jetson Nano的过程。

首先我们要明确目的:在x86_64架构的PC上,使用arm交叉编译器构建Qt源码,将编译出的Qt运行支持库部署至目标设备嵌入式linux,开发机使用同版本号Qt编写代码并运行测试,需打包发布应用程序时依赖开发机的性能,使用交叉编译套件生成可执行文件。

1.获取Qt源码
建议以下两种方式获取:
(1)如安装Qt的时候勾选了 Source 选项,可从Qt安装目录下的版本号文件夹下获取Src目录使用(如 5.14.2);

(2)Qt官方网站获取,Qt5.14.2源码地址,务必选
择tar.xz后缀的源码包,zip包可能在windows下编辑过,直接使用可能会报字符集的错误,解决起来较为耗时;

2.安装交叉编译器
安装交叉编译器的方式分为两种,推荐第二种方式,速度较快:
(1)官网下载交叉编译器下载地址;

(2)apt-get指令获取

sudo apt-get install gcc-aarch64-linux-gnu #安装一个适配当前系统版本的编译器  

加入环境变量:

sudo vim /etc/profile  

底部加入:

export PATH="/usr/bin:$PATH"  

重启或执行source /etc/profile 生效;

3.安装Jetson Nano文件系统
(1)选择使用英伟达提供的文件系统仿真工具,选择适用于Nano的版本,下载地址
Qt嵌入式解决方案(Qt5.14.2 + opengl 交叉编译移植至Jetson Nano 详细步骤)_第2张图片

(2)得到 Jetson-210_Linux_R32.6.1_aarch64.tbz2 和 Tegra_Linux_Sample-Root-Filesystem_R32.6.1_aarch64.tbz2 文件;(文件名或许会根据版本而变动)

(3)创建文件夹安置文件系统

mkdir JetsonNano
cd JetsonNano  
sudo tar xpf Jetson-210_Linux_R32.6.1_aarch64.tbz2  
cd Linux_for_Tegra/rootfs/ 
sudo tar xpf ../../Tegra_Linux_Sample-Root-Filesystem_R32.6.1_aarch64.tbz2  
sudo ../apply_binaries.sh  

4.Jetson Nano上链接库的准备
(1)安装Qt依赖库

sudo apt-get install '.*libxcb.*' libxrender-dev libxi-dev libfontconfig1-dev libudev-dev 

(2)软连接opengl es库
进入 Jetson Nano 的 /usr/lib/aarch64-linux-gnu/tegra-egl 目录,执行:

sudo ln -s libGLESv2_nvidia.so.2 libGLESv2.so  
sudo ln -s libEGL_nvidia.so.0 libEGL.so 

实际上只是将这两个英伟达提供的 gl 动态库重命名,不同的设备厂商提供的支持库名字可能会有差异;

5.同步Jetson Nano的文件系统
保证 Nano 设备和自己的开发机在同一局域网下,使用 ifconfig 指令查看 Nano 设备的ip地址;同步 /usr/include 和 /usr/lib 下的所有文件:

sudo rsync -e ssh -avz [email protected]:/usr/include  . 
sudo rsync -e ssh -avz [email protected]:/usr/lib  . 

root为Nano上的用户名,ip地址为Nano的ip,这个过程时间较长;
如果遇到指令无法正确执行,确认用户名、密码及ip地址;
如遇连接被拒绝,可能需要修改Nano的ssh配置文件,自行查阅资料;

同步完毕后,进入Linux_for_Tegra文件夹 ,新建脚本文件 link.sh,复制以下内容:

#!/bin/bash
if [ "$#" -ne 1 ]; then
    echo "usage ./cmd rootfs_path"
    exit -1
fi
ROOTFS=$(readlink -f $1)
cd $ROOTFS/usr/lib/aarch64-linux-gnu
find . -maxdepth 1 -type l | while read i;
do qualifies=$(readlink $i | grep '^\(/usr\)\?/lib')
   if [ -n "$qualifies" ]; then
       newPath=$(readlink $i | grep '^\(/usr\)\?/lib' | xargs echo $ROOTFS | sed -e s/\\s//g)
       echo $i
       echo $newPath;
       rm $i;
       ln -s $newPath $i;
   fi
done

保存并退出文件,运行指令:

sudo ./link.sh ./rootfs/

修复因为同步而损坏的链接文件,注意这一步,因为软连接的失效导致编译出错耽误了不少时间;

6.准备编译配置
(1)在第三步准备好的文件系统下的/home目录创建任意一个用户文件夹,如 user, 复制一份准备好的源码到此目录作为工作目录,在自己的用户工作目录创建空文件夹,预期将交叉编译的Qt安装到此处,如:Qt-for-arm5.14.2;

(2)进入源码目录,创建 autoconfig.sh 文件,编辑内容:

./configure \ 
-v \
-opensource \
-confirm-license \
-device-option CROSS_COMPILE=/usr/bin/aarch64-linux-gnu- \  
-device linux-jetson-tx1-g++ \
-prefix /home/你的用户目录/Qt-for-arm5.14.2 \
-extprefix /home/你的用户目录/Qt-for-arm5.14.2  \
-hostprefix /home/你的用户目录/Qt-for-arm5.14.2/tools \  
-nomake examples \  
-nomake tests \  
-nomake tools \  
-opengl es2 \
-sysroot /home/你的用户目录/jetsonNano/Linux_for_Tegra/rootfs

这个sh文件指示了执行configure指令的参数,其中有几个需要关注的参数:

//指示了交叉编译器,编译时-后会自动连接到gcc/g++,
//查看自己对应目录下是否有aarch64-linux-gnu-gcc/g++  
-device-option CROSS_COMPILE=/usr/bin/aarch64-linux-gnu- \  
 
//指示了使用源码目录下 qtbase/mkspecs/devices/ 下的某个文件下的qmake.conf,
//由于没有 Nano 文件夹,我们使用相似的linux-jetson-tx1-g++下的qmake.conf,
//文件夹名不重要,规则是qmake.conf中的内容,我们将会修改qmake.conf;  
-device linux-jetson-tx1-g++ \ 

//编译后执行make install指令安装的目标路径,这个文件夹预先创建
-extprefix /home/你的用户目录/Qt-for-arm5.14.2 \ 

//存放开发机上使用交叉编译库所需的工具,如关键的 qmake
-hostprefix /home/你的用户目录/Qt-for-arm5.14.2/tools \  

//不编译Qt样例 
-nomake examples \  

//不编译 test 文件  
-nomake tests \ 

//不编译自带工具,如creator等     
-nomake tools \ 

//编译opengl es2   
-opengl es2 \      

//指示文件系统路径,在qmake.conf中我们会用到   
-sysroot /home/你的用户目录/jetsonNano/Linux_for_Tegra/rootfs

(3)编辑qmake.conf
进入我们在configure阶段指定的将要使用的qmake.conf路径,编辑qmake.conf文件:

include(../common/linux_device_pre.conf)  
                                         
QMAKE_INCDIR_POST += \  
    $$[QT_SYSROOT]/usr/include \  
    $$[QT_SYSROOT]/usr/include/aarch64-linux-gnu   
                                          
QMAKE_LIBDIR_POST += \ 
    $$[QT_SYSROOT]/usr/lib \  
    $$[QT_SYSROOT]/lib/aarch64-linux-gnu \  
    $$[QT_SYSROOT]/usr/lib/aarch64-linux-gnu  
                                        
QMAKE_RPATHLINKDIR_POST += \ 
    $$[QT_SYSROOT]/usr/lib \  
    $$[QT_SYSROOT]/usr/lib/aarch64-linux-gnu \  
    $$[QT_SYSROOT]/usr/lib/aarch64-linux-gnu/tegra \ 
    $$[QT_SYSROOT]/lib/aarch64-linux-gnu  
                                       
QMAKE_INCDIR_OPENGL[_ES2] += \ 
    $$[QT_SYSROOT]/include \ 
    $$[QT_SYSROOT]/include/EGL \ 
    $$[QT_SYSROOT]/include/GLES2 \ 
    $$[QT_SYSROOT]/include/GLES3 \  
    $$[QT_SYSROOT]/include/KHR \  
    $$[QT_SYSROOT]/usr/include \ 
    $$[QT_SYSROOT]/usr/include/EGL \ 
    $$[QT_SYSROOT]/usr/include/GLES2 \ 
    $$[QT_SYSROOT]/usr/include/GLES3 \ 
    $$[QT_SYSROOT]/usr/include/KHR 
                                       
QMAKE_LIBDIR_OPENGL[_ES2] += \
    $$[QT_SYSROOT]/lib/aarch64-linux-gnu/tegra \ 
    $$[QT_SYSROOT]/lib/aarch64-linux-gnu/tegra-egl \ 
    $$[QT_SYSROOT]/lib/aarch64-linux-gnu \ 
    $$[QT_SYSROOT]/usr/lib/aarch64-linux-gnu/tegra \  
    $$[QT_SYSROOT]/usr/lib/aarch64-linux-gnu/tegra-egl \ 
    $$[QT_SYSROOT]/usr/lib/aarch64-linux-gnu
                                         
QMAKE_LIBS_OPENGL[_ES2] += -lEGL -lGLESv2 
                                         
DISTRO_OPTS += aarch64 
COMPILER_FLAGS += -mtune=cortex-a57.cortex-a53 -march=armv8-a 
                                          
EGLFS_DEVICE_INTEGRATION = eglfs_x11  
#EGLFS_DEVICE_INTEGRATION = eglfs_kms_egldevice  
                                        
include(../common/linux_arm_device_post.conf)
load(qt_config)`  

7.执行 sudo ./autoconfig
在这一步,可能会遇到各种问题,如编译套件损坏、无法使用构建套件请检查是否忘记设置环境变量等,不要遗漏细节,一个个解决问题;
(1)如遇 c++11 相关报错,进入源码目录下 qtbase/mkspecs/common/gcc-base.conf,将QMAKE_CFLAGS_ISYSTEM = -isystem 改为 QMAKE_CFLAGS_ISYSTEM = -I (capital i),然后在当前使用的qmake.conf中加入QMAKE_CXXFLAGS += -std=gnu++11QMAKE_CFLAGS_ISYSTEM=-I

(2)注意qmake.conf中的注释
Qt嵌入式解决方案(Qt5.14.2 + opengl 交叉编译移植至Jetson Nano 详细步骤)_第3张图片

在拥有openg es2头文件的情况下,configure才能正确识别es2,正确加载依赖库才能编译成功;
由于直接使用了文件系统,所以不考虑注释中所提到的libm.a报错;
如果编译时仍出现奇怪的链接错误,请检查依赖库的软链接是否正常,包括但不限定于 libm.so,libz.so,libc.so,libdl.so等;

(3)执行autoconfig 出现任何错误都建议重新拷贝一份源码修改错误后执行,否则可能导致更新错误后,缓存文件导致仍然报错;

(4)预期的结果
执行 confogure 应无 error,且所关注的条目应为 yes:
Qt嵌入式解决方案(Qt5.14.2 + opengl 交叉编译移植至Jetson Nano 详细步骤)_第4张图片
Qt嵌入式解决方案(Qt5.14.2 + opengl 交叉编译移植至Jetson Nano 详细步骤)_第5张图片

8.编译源码
(1)上一步正常执行后将会生成 Makefile 文件,执行指令:

sudo make -j16 

“-j16”参数指定了并行编译,按个人开发机的核心线程数适量设置可加快编译速度;

(2)“-j16” 情况下约编译二十分钟以上,期间出现错误请仔细检查链接和依赖,成功编译后执行:

sudo make install

约1-2分钟安装完毕;

(3)编译出现任何错误都建议重新拷贝一份源码修改错误后重新操作,不要寄希望于 “make clean”;

(4)以上执行编译安装无误后,将在autoconfig中指定的路径中安装交叉编译的Qt,如图:
Qt嵌入式解决方案(Qt5.14.2 + opengl 交叉编译移植至Jetson Nano 详细步骤)_第6张图片

预期大小将是 200Mb 以上,过小请考虑编译的正确性;

9.开发机搭建交叉编译套件
(1)打开QtCreator,进入 工具->选项->Kits (不同版本QtCreator可能会略有不同)

(2)选择编译器分页,点击 “添加”,在“gcc”条目中分别添加 gcc 和 g++,从交叉编译器的安装目录中分别将 aarch64-linux-gnu-gcc 和 aarch64-linux-gnu-g++ 路径添加入编译器路径,并点击 Apply 应用;如图:
Qt嵌入式解决方案(Qt5.14.2 + opengl 交叉编译移植至Jetson Nano 详细步骤)_第7张图片
Qt嵌入式解决方案(Qt5.14.2 + opengl 交叉编译移植至Jetson Nano 详细步骤)_第8张图片

Qt嵌入式解决方案(Qt5.14.2 + opengl 交叉编译移植至Jetson Nano 详细步骤)_第9张图片

(3)切换至 Qt Versions 分页,点击添加按钮,进入交叉编译库所在的目录/tools(autoconfig指定),选中qmake将其添加,修改该Versions的 Name,如:Qt-for-arm5.14.2,点击 Apply 应用修改,如图:
Qt嵌入式解决方案(Qt5.14.2 + opengl 交叉编译移植至Jetson Nano 详细步骤)_第10张图片

(4)切换至Kits分页,点击 Add 按钮,添加套件,修改一个有辨识度的套件名,如:5.14.2 arm 64,修改该套件的"Compiler"为当前条目步骤2添加的编译器,修改“Qt version”为步骤3添加的 Qt Versions,点击Apply 按钮应用,如图:
Qt嵌入式解决方案(Qt5.14.2 + opengl 交叉编译移植至Jetson Nano 详细步骤)_第11张图片
Qt嵌入式解决方案(Qt5.14.2 + opengl 交叉编译移植至Jetson Nano 详细步骤)_第12张图片

10.交叉编译套件测试
(1)创建一个空白的以QWidget为基类的Qt项目,选择条目9中添加的套件为构建套件, pro文件中引入 opengl 模块:

QT += core gui sql opengl

编译项目,如报错提示找不到opengl模块,则证明交叉编译有误,请回溯编译步骤;

(2)将测试项目修改为QOPenglWidget窗口,测试opengl功能完整性,ui中加入一个按钮设置中文文本,直接转到槽,测试Qt基础功能完备性,如图:
Qt嵌入式解决方案(Qt5.14.2 + opengl 交叉编译移植至Jetson Nano 详细步骤)_第13张图片

Qt嵌入式解决方案(Qt5.14.2 + opengl 交叉编译移植至Jetson Nano 详细步骤)_第14张图片

Qt嵌入式解决方案(Qt5.14.2 + opengl 交叉编译移植至Jetson Nano 详细步骤)_第15张图片

(3)该测试项目功能为使用opengl画出一个背景为黄色的窗口,按钮为中文文本用以测试中文字符,点击按钮弹出一个简单对话框,编译该工程,如出现opengl相关类型或函数报错,则证明编译不完整,请回溯编译步骤;

11.Qt库移植至嵌入式linux并运行测试工程
(1)使用U盘或网络将交叉编译Qt库(如Qt-for-arm5.14.2)文件夹和test测试工程生成的可执行文件复制到 Nano,将交叉编译Qt库移动到 Nano的 /usr/lib 下,测试工程放在任意位置(如Downloads或主目录);

(2)修改环境变量:

sudo gedit /etc/profile 

末尾加入:

export QTDIR=/usr/lib/Qt-for-arm5.14.2
export LD_LIBRARY_PATH=/usr/lib/Qt-for-arm5.14.2/lib:$LD_LIBRARY_PATH
export QT_QPA_PLATFORM_PLUGIN_PATH=$QTDIR/plugins
export QT_QPA_PLATFORM=eglfs

保存并退出,执行 source /etc/profile 或重启Nano使其生效;

(3)运行测试样例
进入测试样例所在文件,执行./test(test为用例文件名),默认以环境变量中的 eglfs 启动,独占整个屏幕,执行
./test -platform xcb将以普通桌面应用方式启动,注意此处不能以 sudo 方式运行程序,由于 Nano 自带了Qt5.9.5,使用sudo会导致从 qt-default和qtchooser中链接所指向的Qt5.9.5;

以上测试功能无误则证明成功完成Qt的交叉编译配置和移植。
附:auticonfig.sh、qmake.conf、test测试用例
autoconfig.sh
qmake.conf
test.zip

你可能感兴趣的:(Qt,qt,arm开发,开发语言,交叉编译)