qt源码编译方法-Qt嵌入式解决方案(Qt5.14

当我需要在嵌入式arm linux平台上运行Qt应用程序时,我了解到两种解决方案:

Qt for Device Creation + Boot to Qt,这个技术还是蛮让人着迷的,虽然只能使用商业版的Qt,但是用了这么久的开源版Qt,付费也未尝不可它; 但是当我在Qt的官方网站上了解到该公司需要留下信息来协商商业Qt的价格后,我就放弃了这个想法(其实我后来买了一些许可证...),因为这是充满了未知数,没有人知道他们要如何定价。 在Qt的官网上还有一个颇具讽刺意味的广告:

交叉编译Qt源代码并将其移植到arm linux。 网上的资料大部分都是老版本的Qt,这个过程会伴随很多问题,特别是需要添加opengl模块的时候。 自我否定,那我们就只能用这个办法了。 当然,我们选择了一个比较新的Qt版本:5.14.2(2021年编写),浮夸又时尚。 以下是我交叉编译并移植到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)选择使用Nvidia提供的文件系统模拟工具,选择适合Nano的版本,下载链接

(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 

其实只要把这两个Nvidia提供的gl动态库重命名一下,不同设备厂商提供的支持库的名字可能会不一样;

5.同步Jetson Nano的文件系统

确保Nano设备和自己的开发机在同一个局域网内,使用ifconfig命令查看Nano设备的IP地址; 同步 /usr/include 和 /usr/lib 下的所有文件:

sudo rsync -e ssh -avz root@192.168.10.201:/usr/include  . 
sudo rsync -e ssh -avz root@192.168.10.201:/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

在这一步中,您可能会遇到各种问题qt源码编译方法,例如编译套件损坏、构建套件无法使用等。 请检查是否忘记设置环境变量等,不要错过细节,一一解决问题;

(1)遇到c++11相关错误,在源代码目录下输入qtbase/mkspecs/common/gcc-base.conf,将QMAKE_CFLAGS_ISYSTEM = -isystem修改为QMAKE_CFLAGS_ISYSTEM = -I(大写i),然后使用当前的qmake将QMAKE_CXXFLAGS += -std=gnu++11和QMAKE_CFLAGS_ISYSTEM=-I添加到.conf中;

(2)注意qmake.conf中的注释

在openg es2头文件的情况下,configure可以正确识别es2,正确加载依赖库并编译成功;

由于直接使用文件系统,所以不考虑注释中提到的libm.a错误;

如果编译时仍然出现奇怪的链接错误,请检查依赖库的软链接是否正常,包括但不限于libm.so、libz.so、libc.so、libdl.so等;

(3)如果autoconfig执行过程中出现错误,建议复制一份源代码,改完错误后执行,否则可能会导致更新错误,缓存文件会一直报错;

(四)预期结果

执行configure时不应出现错误,相关项应为yes:

8.编译源码

(1)上一步正常执行后,会生成Makefile,执行命令:

sudo make -j16 

“-j16”参数指定并行编译,根据个人开发机器的核心线程数适当设置可以提升编译速度;

(2) 在“-j16”的情况下,编译大约需要20分钟或更长时间。 如果这期间出现错误,请仔细检查链接和依赖关系。 编译成功后,执行:

sudo make install

大约1-2分钟安装完成;

(3)如果编译出现错误,建议复制一份源代码,改完错误后重新操作,不要寄希望于“make clean”;

(4)以上编译安装正确后,交叉编译的Qt就会安装在autoconfig中指定的路径下,如图:

预计大小会超过200Mb,如果太小,请考虑编译的正确性;

9. 在开发机上构建交叉编译套件

(1)打开QtCreator,进入Tools -> Options -> Kits(不同版本的QtCreator可能略有不同)

(2)选择编译器选项卡,点击“添加”qt源码编译方法,在“gcc”项中分别添加gcc和g++,并分别从交叉口的安装目录安装aarch64-linux-gnu-gcc和aarch64-linux-gnu-g++ compiler 将路径添加到编译器路径中,然后点击Apply; 如图所示:

(3)切换到Qt Versions页面,点击Add按钮,进入交叉编译库所在目录/tools(由autoconfig指定),选择qmake添加,修改Versions Name,如:Qt -for-arm5.14.2,点击Apply Changes,如图:

(4)切换到Kits页面,点击Add按钮,添加一个kit,修改一个可识别的kit名称,如:5.14.2 arm 64,修改该kit的“Compiler”为第2步添加的编译器当前条目,修改“Qt版本”为步骤3中添加的Qt版本,点击Apply按钮应用,如图:

10.交叉编译套件测试

(1)创建一个空白的Qt工程,通用类型为QWidget,选择第9项添加的套件作为创建套件,在pro文件中引入opengl模块:

QT += 核心 gui sql opengl

编译工程时,如果报错提示找不到opengl模块,则证明交叉编译错误,请回溯编译步骤;

(2)将测试项改为QOPenglWidget窗口,测试opengl功能的完整性,在ui中添加一个按钮设置英文文本,直接转入槽位,测试Qt基本功能的完整性,如如图所示:

(3)本测试项目的功能是使用opengl绘制一个蓝色背景的窗口,按钮为英文文本,测试英文字符。 点击按钮,弹出一个简单的对话框来编译项目。 如果出现opengl相关类型或函数错误报告,则证明编译不完整,请回溯编译步骤;

11.将Qt库移植到嵌入式linux并运行测试项目

(1)使用硬盘或网络将交叉编译的Qt库(如Qt-for-arm5.14.2)文件夹和测试测试项目生成的可执行文件复制到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 将导致 Qt5 从 qt-default 和 qtchooser 链接。 9.5;

如果以上测试功能正确,则证明Qt的交叉编译配置和移植已经成功完成。

附件:auticonfig.sh、qmake.conf、测试用例

自动配置文件

qmake.conf

测试.zip