前言
网上有一堆Qt移植到嵌入式linux的教程,但是目标机器基本都是32bit的较老的机型(ARM9/ARM11/CortexA8/A9)。现在目标机器跑的是64bit的Linux(飞思卡尔(已经被NXP收购)i.MX8M:4*Cortex-A53 + 1*Cortex-M4)。我原本以为就算它是64bit的linux系统应该是可以兼容32bit的应用程序的,然不,我也成功编译出32bit的Qt,移植到arm-linux上,但在运行可执行程序(ELF)的时候无法识别这是一个可执行程序。所以需要编译一个64bit的Qt出来。以下对该过程的进行做个笔记和记录各种坑该怎么填。
开发环境
操作系统:Ubuntu16.04
交叉编译器:aarch64-linux-gnu-gcc(aarch64-linux-gnu-gcc是由 Linaro 公司基于GCC推出的的ARM交叉编译工具。可用于交叉编译ARMv8 64位目标中的裸机程序、u-boot、Linux kernel、filesystem和App应用程序。aarch64-linux-gnu-gcc交叉编译器必须安装在64为主机上,才能编译目标代码。->
官网地址)。或者
参考这篇文章下载。不能使用传统的arm-linux-交叉编译工具链,那些编译出来的都是32bit。
Qt版本:Qt560。为什么选择Qt560?Qt4.x有点古老,不符合ARMv8的身份(最新的能装逼)!!!,那为啥不用Qt5.7,5.8,现在最新的Qt是5.10,最新的不稳定(实际上装逼失败···)!实际上我最初用的是Qt5.8,但是configure的时候老是报错···,Qt5.7也试过了,和5.8报一样的错,如下图(先把Qt5.6搞成功再回来研究),无奈之下选择了Qt5.6(附
Qt下载地址)。
开始移植
下载交叉编译器
见上面提供的参考地址。
安装交叉编译器
解压交叉编译器
tar -zxvf gcc-linaro-aarch64-linux-gnu-4.9-2014.07_linux.tar
添加环境变量
vim /etc/profile
在最后一行添加:export PATH=$PATH:***/bin(***表示交叉编译器的根目录)
source /etc/profile
制作编译器工具链接文件
为什么要制作链接文件,因为编译第三方库的时候(比如:tslib,libiconv)需要指定--host=arm-linux,我试过--host=aarch64-linux-gnu,在configure的时候会无法识别。所以需要制作arm-linux开头的链接文件,在编译器根目录下新建MkLinks.sh,输入脚本如下然后运行脚本:
#!/bin/sh
ln -s aarch64-linux-gnu-addr2line arm-linux-addr2line
ln -s aarch64-linux-gnu-ar arm-linux-ar
ln -s aarch64-linux-gnu-as arm-linux-as
ln -s aarch64-linux-gnu-c++ arm-linux-c++
ln -s aarch64-linux-gnu-c++filt arm-linux-c++filt
ln -s aarch64-linux-gnu-cpp arm-linux-cpp
ln -s aarch64-linux-gnu-elfedit arm-linux-elfedit
ln -s aarch64-linux-gnu-ct-ng.config arm-linux-ct-ng.config
ln -s aarch64-linux-gnu-g++ arm-linux-g++
ln -s aarch64-linux-gnu-gcc arm-linux-gcc
ln -s aarch64-linux-gnu-gcc-ar arm-linux-gcc-ar
ln -s aarch64-linux-gnu-gcc-nm arm-linux-gcc-nm
ln -s aarch64-linux-gnu-gcc-ranlib arm-linux-gcc-ranlib
ln -s aarch64-linux-gnu-gcov arm-linux-gcov
ln -s aarch64-linux-gnu-gdb arm-linux-gdb
ln -s aarch64-linux-gnu-gfortran arm-linux-gfortran
ln -s aarch64-linux-gnu-gprof arm-linux-gprof
ln -s aarch64-linux-gnu-ld arm-linux-ld
ln -s aarch64-linux-gnu-ldd arm-linux-ldd
ln -s aarch64-linux-gnu-nm arm-linux-nm
ln -s aarch64-linux-gnu-objcopy arm-linux-objcopy
ln -s aarch64-linux-gnu-objdump arm-linux-objdump
ln -s aarch64-linux-gnu-pkg-config arm-linux-pkg-config
ln -s aarch64-linux-gnu-pkg-config-real arm-linux-pkg-config-real
ln -s aarch64-linux-gnu-ranlib arm-linux-ranlib
ln -s aarch64-linux-gnu-readelf arm-linux-readelf
ln -s aarch64-linux-gnu-size arm-linux-size
ln -s aarch64-linux-gnu-strings arm-linux-strings
ln -s aarch64-linux-gnu-strip arm-linux-strip
解压Qt560源码
tar -zxvf qt-everywhere-opensource-src-5.6.0.tar.gz
配置qmake.conf
进入Qt560源码根目录下的qtbase/mkspecs/linux-arm-gnueabi-g++/,打开qmake.conf进行修改
cd qtbase/mkspecs/linux-arm-gnueabi-g++/
vim qmake.conf
原来的qmake.conf
#
# qmake configuration for building with arm-linux-gnueabi-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)
# modifications to g++.conf
QMAKE_CC = arm-linux-gnueabi-gcc
QMAKE_CXX = arm-linux-gnueabi-g++
QMAKE_LINK = arm-linux-gnueabi-g++
QMAKE_LINK_SHLIB = arm-linux-gnueabi-g++
# modifications to linux.conf
QMAKE_AR = arm-linux-gnueabi-ar cqs
QMAKE_OBJCOPY = arm-linux-gnueabi-objcopy
QMAKE_NM = arm-linux-gnueabi-nm -P
QMAKE_STRIP = arm-linux-gnueabi-strip
load(qt_config)
修改后的qmake.conf
#
# qmake configuration for building with arm-linux-gnueabi-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)
# modifications to g++.conf
QMAKE_CC = aarch64-linux-gnu-gcc
QMAKE_CXX = aarch64-linux-gnu-g++
QMAKE_LINK = aarch64-linux-gnu-g++
QMAKE_LINK_SHLIB = aarch64-linux-gnu-g++
# modifications to linux.conf
QMAKE_AR = aarch64-linux-gnu-ar cqs
QMAKE_OBJCOPY = aarch64-linux-gnu-objcopy
QMAKE_NM = aarch64-linux-gnu-nm -P
QMAKE_STRIP = aarch64-linux-gnu-strip
load(qt_config)
制作Qt编译配置脚本
进入Qt根目录下,新建qt_compile_conf.sh,输入以下脚本(先不要急着输入,因为这样编译会出错,不是最终版本,或者你想试错也行),或者根据自己的需要进行配置(Qt的各个配置项目含义参考
这篇文章)(暂时不想支持tslib,后面用到在补上):
#!/bin/sh
./configure -prefix /opt/arm/qt560_64/qt_sdk #qt的安装路径
-opensource
-release
-pch #预编译头
-confirm-license
-xplatform linux-arm-gnueabi-g++
-shared
-qt-zlib
-iconv
-no-gif
-no-nis
-qt-libjpeg
-no-opengl
-no-cups
-no-glib
-no-dbus
-no-rpath
-no-sse2 -no-sse3 -no-ssse3 -no-sse4.1 -no-sse4.2
-no-avx
-no-openssl
-nomake tools
-qreal float
-qt-libpng
-make examples
执行qt_compile_conf.sh,不出意外是成功的。然后生成Makefile,执行make -j4,make过程中会出错(
undefined reference to `_ZN18QRegularExpressionD4Ev')如下图:
解决方法:将qt_compile_conf.sh脚本中的-pch改成-no-pch,禁止掉预编译头,再次./qt_compile_conf.sh,make -j4就可以编译通过了。然后make install就输出产物到/opt/arm/qt560_64/qt_sdk了。
验证移植效果
将/opt/arm/qt560_64/qt_sdk拷贝到嵌入式linux下的/usr/local(位置随意),然后配置Qt的运行时环境,打开/etc/profile,在最后一行输入一下内容:
export QTDIR=/usr/local/qt_sdk #qtsdk在系统上的路径
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 QT_QPA_PLATFORM=linuxfb:fb=/dev/fb0 #framebuffer驱动
export QWS_MOUSE_PROTO=/dev/input/event0
然后进入qt_sdk根目录下的example目录,随便选择一个例子运行。这时候可能出现错误
QIconvCodec::convertToUnicode: using Latin-1 for conversion, iconv_open failed和
QIconvCodec::convertFromUnicode: using Latin-1 for conversion, iconv_open failed,如下图。解决方法有两种:
1、在编译配置脚本中将-iconv改成-no-iconv去掉iconv模块,再次编译。
2、
下载libiconv,解压,配置,编译,安装。
cd libiconv
./configure -prefix=$PWD/install -host=arm-linux
make && make install
但是,在make的时候可能会出现错误
error: 'gets' ubdeclared here (not in a function),如下图:
解决方法是打开srclib目录下的stdio.in.h,大概在699行上下,做以下修改,如下图:
/* It is very rare that the developer ever has full control of stdin,
so any use of gets warrants an unconditional warning. Assume it is
always declared, since it is required by C89. */
// 注释掉下面这一行
// _GL_WARN_ON_USE (gets, "gets is a security hole - use fgets instead");
// 新添加以下三行
#if defined(__GLIBC__) && !defined(__UCLIBC__) && !__GLIBC_PREREQ(2, 16)
_GL_WARN_ON_USE (gets, "gets is a security hole - use fgets instead");
#endif
现在可以make过了,安装后将install/lib下的preloadable_libiconv.so拷贝到嵌入式linux系统的/lib目录下即可。
再次运行qt_sdk/example下的例子就成功了。
技术交流
图像处理-深度学习技术交流群:qq群:
247270428
如果文章对您有帮助,打赏一包辣条吧,DaLao们。
附录
附上最终的Qt编译配置脚本
#!/bin/sh
./configure -prefix /opt/arm/qt560_64/qt_sdk
-opensource
-release
-no-pch
-confirm-license
-xplatform linux-arm-gnueabi-g++
-shared
-qt-zlib
-no-iconv
-no-gif
-no-nis
-qt-libjpeg
-no-opengl
-no-cups
-no-glib
-no-dbus
-no-rpath
-no-sse2 -no-sse3 -no-ssse3 -no-sse4.1 -no-sse4.2
-no-avx
-no-openssl
-nomake tools
-qreal float
-qt-libpng
-make examples