100ASK-IMX6ULL开发板_QT移植全过程

环境及开发包介绍:
主机:ubuntu18.04(百问网提供)
交叉编译器:gcc-linaro-6.2.1-2016.11-x86_64_arm-linux-gnueabihf(百问网提供的bsp包)
QT5.6.0:qt-everywhere-opensource-src-5.6.0(链接:https://pan.baidu.com/s/1hiDQEDYWCq8FQYirw9yedg 密码:gvd7)
tslib:tslib-1.6(git clone https://github.com/kergoth/tslib.git)
Busybox:Busybox_1.30.0(百问网提供的bsp包)
Linux:Linux-4.9.88(百问网提供的bsp包)

注意:本文章的所有命令涉及到的 路径 需根据自身实际所创建的改变

一. Ubuntu安装QT软件

详细QT软件安装编译环境配置可参考链接

使用QT执行编译时,应选择QT软件Tools/Options选项新增QT编译器选项,导入对应版本qmake(qt-everywhere-opensource-src-5.6.0配置编译安装目录的bin目录中),配置ARM板QT编译器,编译时选中新生成的配置选项

100ASK-IMX6ULL开发板_QT移植全过程_linux

100ASK-IMX6ULL开发板_QT移植全过程_linux_02


100ASK-IMX6ULL开发板_QT移植全过程_qt移植_03

注意:选用新增的QT编译器选项生成的可执行文件(文件位于工程目录下build-xxx-xxx_toolchain-Debug文件中)不能在QT软件中Debug,需移植ARM进行功能测试。可用file命令查看文件运行环境:

100ASK-IMX6ULL开发板_QT移植全过程_linux_04

二. 使用busybox构建根文件系统

参考链接

  1. 解压busybox-1.30.0.tar.bz2:
tar -vxjf busybox-1.30.0.tar.bz2
  1. 修改Makefile(如果已设置全局交叉编译环境可忽略以下两条),添加编译器,打开busybox的根目录中的Makefile,将164行修改为:
CROSS_COMPILE ?= /home/book/share/100ask_imx6ull-sdk/ToolChain/gcc-linaro-6.2.1-2016.11-x86_64_arm-linux-gnueabihf/bin/arm-linux-gnueabihf-

将路径修改为自己的交叉编译工具的绝对路径,将190行修改为:

ARCH ?= arm
  1. 配置busybox,busybox有三种配置选项:
  • defconfig,默认配置
  • allyesconfig,全选配置,使能busybox中的所有功能
  • allnoconfig,最小配置
    使用默认配置,执行:
make defconfig

然后打开图形配置界面,执行:

make menuconfig

分别配置下面的路径:

Location:
  -> Settings
	-> Build static binary (no shared libs) //取消选中,动态编译,不然编译出来的根文件系统很大
Location:
  -> Settings
	-> vi-style line editing commands  //选中
Location:
  -> Linux Module Utilities
	-> Simplified modutils   //取消选中
Location:
  -> Linux System Utilities
	-> mdev (16 kb) //确保下面的全部选中,默认都是选中的
  1. 配置完busybox就可以编译了,执行:
make install CONFIG_PREFIX=/home/book/nfs_rootfs/blogrootfs

CONFIG_PREFIX指定输出路径,指向nfs服务器的路径即可。编译完成后可以查看rootfs路径下的文件:

100ASK-IMX6ULL开发板_QT移植全过程_imx6ull_05

  1. 向根文件系统添加lib
    在rootfs下创建lib文件夹,在usr下创建lib文件夹。
  • 进入交叉编译器存放的目录,将arm-linuxgnueabihf/libc/lib下的so和***.a拷贝到rootfs/lib下:
cp *so* *.a ~/nfs_rootfs/blogrootfs/lib/ -d

后面的“-d”表示拷贝符号链接。在rootfs中lib执行ls ld-linux-armhf.so.3 -l,可以看到ld-linux-armhf.so.3是一个软链接,所以需要重新复制一下。先删除rootfs/lib下的ld-linux-armhf.so.3,然后进入arm-linuxgnueabihf/libc/lib执行:

cp ld-linux-armhf.so.3 ~/nfs_rootfs/blogrootfs/lib/

再次查看rootfs/lib下的ld-linux-armhf.so.3,已经不是软链接了。

  • 进入交叉编译器存放的目录,将arm-linuxgnueabihf/lib下的so和***.a拷贝到rootfs/lib下:
cp *so* *.a ~/nfs_rootfs/blogrootfs/lib/ -d
  • 进入交叉编译器存放的目录,将arm-linuxgnueabihf/libc/usr/lib下的so和***.a拷贝到rootfs/usr/lib下:
cp *so* *.a ~/nfs_rootfs/blogrootfs/usr/lib/ -d

可能会有警告,不用管。

  1. 创建其它文件夹
    在rootfs根目录下创建文件夹:dev、 proc、 mnt、 sys、 tmp、root,创建完后如下图示:
  2. 100ASK-IMX6ULL开发板_QT移植全过程_imx6ull_06

  3. 测试根文件系统
    测试根文件系统一般都使用NFS,在内核启动时指定使用的nfs服务器以及路径,设置好后保存环境变量,然后使用tftp加载内核和设备树并启动:
  4. 配置TFTP环境
    3.1. Ubuntu 安装 TFTP 服务
    注意:使用 VMware NAT 网络或 Docker 时,不需要在 Ubuntu 中安装 TFTP 服务,而是在 Windows 运行
    tftpd64 程序。
    在 Ubuntu 中执行以下命令安装 TFTP 服务:
book@100ask:~$ sudo apt-get install tftp-hpa tftpd-hpa

然后,创建 TFTP 服务器工作目录,并打开 TFTP 服务配置文件,如下:

book@100ask:~$ mkdir -p /home/book/tftpboot
book@100ask:~$ sudo chmod 777 /home/book/tftpboot
book@100ask:~$ sudo vim /etc/default/tftpd-hpa

在配置文件/etc/default/tftpd-hpa 中,添加以下字段:

TFTP_DIRECTORY="/home/book/tftpboot"
TFTP_OPTIONS="-l -c -s"

最后,重启 TFTP 服务:

book@100ask:~$ sudo service tftpd-hpa restart

查看 tftp 服务是否在运行,运行如下命令,即可查看是否在后台运行。

book@100ask:~$ ps –aux | grep “tftp”

100ASK-IMX6ULL开发板_QT移植全过程_qt_07

3.2. 准备工作

使用NFS根文件系统时,涉及3个文件:zImage 、 设备树(比如100ask_imx6ull-14x14.dtb)、

rootfs.tar.bz2(解压到Ubuntu某个目录,比如/home/book/nfs_rootfs)。 这里我们使用之前所构建根文件的对应目录

在U-Boot中通过tftpboot命令从Ubuntu/Windows中下载内核文件zImagen、100ask_imx6ull-14x14.dtb,

设置Uboot启动参数使用Ubuntu的某个目录(比如/home/book/nfs_rootfs)作为根文件系统。

1) 拷贝内核和设备树文件到 tftp 目录:

如果使用 VMware 桥接网络,将出厂镜像或者自行编译的 zImage 和设备树文件 100ask_imx6ull-

14x14.dtb,拷贝到 Ubuntu 的 /home/book/tftpboot 目录。

2) 把制作好的最小根文件系统压缩包拷贝到 NFS 目录:

3) 确认客户机与服务端互通:

先在 u-boot 中设置开发板 IP 为 192.168.1.112,然后在 u-boot 中使用 ping 命令测试开发板与 Ubuntu

系统是否连通(出现“alive”就表示联通):命令如下:

=> setenv ipaddr 192.168.1.112
=> ping 192.168.1.224

3.3. 配置选项,网络启动内核

先在 Ubuntu 的 TFTP 目录中放入 zImage 和设备树文件,再在/home/book/nfs_rootfs 目录下拷贝配置好的根文件系统。

然后在 U-Boot 控制台执行以下命令启动单板,假设 Ubuntu IP 是 192.168.1.224:

=> setenv serverip 192.168.***.*** //设置服务器的 IP 地址,这里指的是 Ubuntu 主机 IP
=> setenv ipaddr 192.168.***.*** //设置开发板的 IP 地址。
=> setenv nfsroot /home/book/nfs_rootfs/*** //设置文件系统所在目录。
=> run netboot //设置完成后,运行网络启动系统命令

3.4. 启动流程

U-boot通过tftp从服务端tftp指定目录下下载到内核设备树加载入内存,从而启动内核,最终挂载根文件系统

100ASK-IMX6ULL开发板_QT移植全过程_qt移植_08

启动完成后如下图:

100ASK-IMX6ULL开发板_QT移植全过程_qt移植_09


可以执行基本的命令了,但是提示没有/etc/init.d/rcS文件,所以需要完善一下文件系统。

3. 完善根文件系统

3.1 创建/etc/init.d/rcS文件

linux启动后需要运行一些服务,而 /etc/init.d/rcS文件就是规定启动哪些服务,创建该文件并添加如下内容:

#!/bin/sh
PATH=/sbin:/bin:/usr/sbin:/usr/bin:$PATH
#往PATH里面新增一个~/bin的路径,如果不加:$PATH的话,就表示直接把PATH赋值为~/bin,这样你其他的老路径就丢失了。
LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/lib:/usr/lib
export PATH LD_LIBRARY_PATH
mount -a
mkdir /dev/pts
mount -t devpts devpts /dev/pts
echo /sbin/mdev > /proc/sys/kernel/hotplug #通过这两行,linux内核就可以在/dev目录下自动创建设备节点
mdev -s
mount -a
exec /etc/rc.local

将rcS添加可执行权限chmod 777 rcS

创建/etc/rc.local,创建该文件并添加如下内容:

\#!/bin/sh
. /etc/profile #注意.后边有个空格!

创建/etc/profile,暂且不添加内容.

3.2 创建/etc/fstab文件

fstab 在 Linux 开机以后自动配置哪些需要自动挂载的分区,创建该文件并添加如下内容:

#<file system> <mount point> <type> <options> <dump> <pass>
proc           /proc         proc    defaults   0      0
tmpfs          /tmp          tmpfs   defaults   0      0
tmpfs          /dev          tmpfs   defaults   0      0
sysfs          /sys          sysfs   defaults   0      0

3.3 创建/etc/inittab文件

init 程序会读取/etc/inittab这个文件, inittab 由若干条指令组成,创建该文件并添加如下内容:

::sysinit:/etc/init.d/rcS
console::askfirst:-/bin/sh
::restart:/sbin/init
::ctrlaltdel:/sbin/reboot
::shutdown:/sbin/umount -a -r
::shutdown:/sbin/swapoff -a

3.4 创建/etc/resolv.conf文件

/etc/resolv.conf文件用于配置域名服务器,没有域名服务器就不能将网址转换成ip地址,创建该文件并添加如下内容:

nameserver 114.114.114.114
nameserver 192.168.101.1

创建完以上三个文件后,重启linux,发现没有错误提示了。ping一下百度也可以ping通,网络也可以使用了,此时可以通过交叉编译器来编译可以在100ASK开发板上运行的linux程序了。

3.5 构建 /dev 目录

mkdir -p ~/nfs_rootfs/blogrootfs/dev
cd ~/nfs_rootfs/blogrootfs/dev
sudo mknod console c 5 1
sudo mknod null   c 1 3

三.编译QT_arm源码与tslib

一. 安装tslib

tar xzf tslib-1.4.tar.gz
cd tslib
mkdir -p generated_tslib_ok/tslib
echo "ac_cv_func_malloc_0_nonnull=yes" >arm-linux.cache

./configure --host=arm-linux ac_cv_func_malloc_0_nonnull=yes CC=arm-linux-gnueabihf-gcc \
-prefix=$(pwd)/generated_tslib_ok/tslib

make&sudo make install

tslib安装在/generated_tslib_ok/tslib目录下:

100ASK-IMX6ULL开发板_QT移植全过程_qt_10

二. 安装qt-everywhere-opensource-src-5.6.0

tar -xf qt-everywhere-opensource-src-5.6.0.tar.gz
cd qt-everywhere-opensource-src-5.6.0

vi qtbase/mkspecs/linux-arm-gnueabi-g++/qmake.conf

原配置文件:

修改配置文件:(注意以下选项:QMAKE_INCDIR QMAKE_LIBDIR对应tslib安装目录)

#
# qmake configuration for building with arm-linux-gnueabi-g++
#
MAKEFILE_GENERATOR      = UNIX
CONFIG                 += incremental
QMAKE_INCREMENTAL_STYLE = sublib
QT_QPA_DEFAULT_PLATFORM  = linuxfb
QMAKE_CFLAGS_RELEASE    += -O2 -march=armv7-a
QMAKE_CXXFLAGS_RELEASE  += -O2 -march=armv7-a
QMAKE_INCDIR +=/home/book/QT_imx6ull/tslib/generated_tslib_ok/tslib/include
QMAKE_LIBDIR +=/home/book/QT_imx6ull/tslib/generated_tslib_ok/tslib/lib
include(../common/linux.conf)
include(../common/gcc-base-unix.conf)
include(../common/g++-unix.conf)
# modifications to g++.conf
QMAKE_CC                = arm-linux-gnueabihf-gcc
QMAKE_CXX               = arm-linux-gnueabihf-g++
QMAKE_LINK              = arm-linux-gnueabihf-g++
QMAKE_LINK_SHLIB        = arm-linux-gnueabihf-g++
# modifications to linux.conf
QMAKE_AR                = arm-linux-gnueabihf-ar cqs
QMAKE_OBJCOPY           = arm-linux-gnueabihf-objcopy
QMAKE_NM                = arm-linux-gnueabihf-nm -P
QMAKE_STRIP             = arm-linux-gnueabihf-strip
load(qt_config)

配置选项:

./configure -v -prefix /opt/qt-5.6.0 -release \
-opensource -no-accessibility \
-make libs -xplatform linux-arm-gnueabi-g++ -optimized-qmake \
-pch \
-qt-sql-sqlite \
-qt-zlib \
-tslib \
-no-opengl \
-no-sse2 \
-no-openssl \
-no-nis \
-no-cups \
-no-glib \
-no-pkg-config \
-no-separate-debug-info \
-I /home/book/QT_imx6ull/tslib/generated_tslib_ok/tslib/include \
-L /home/book/QT_imx6ull/tslib/generated_tslib_ok/tslib/lib

执行安装:

make
sudo make install

最终生成文件:

100ASK-IMX6ULL开发板_QT移植全过程_qt_11

四. QT与tslib移植

cp /opt/qt-5.6.0 /home/book/nfs_rootfs/blogrootfs/
cp /home/book/QT_imx6ull/tslib/generated_tslib_ok/tslib/ /home/book/nfs_rootfs/blogrootfs/

修改最小根文件系统配置文件,增加以下内容 /etc/profile

export T_ROOT=/tslib 
export LD_LIBRARY_PATH=/tslib/lib:$LD_LIBRARY_PATH
export TSLIB_CONSOLEDEVICE=none
export TSLIB_FBDEVICE=/dev/fb0
export TSLIB_TSDEVICE=/dev/input/event1 #注意:该设备为板子触摸屏文件
export TSLIB_PLUGINDIR=$T_ROOT/lib/ts
export TSLIB_CONFFILE=$T_ROOT/etc/ts.conf
export POINTERCAL_FILE=/etc/pointercal
export TSLIB_CALIBFILE=/etc/pointercal
export QTEDIR=/qt-5.6.0
export LD_LIBRARY_PATH=lib:$LD_LIBRARY_PATH
export QT_QPA_GENERIC_PLUGINS=tslib
export QT_QPA_FONTDIR=/lib/fonts
export QT_QPA_PLATFORM_PLUGIN_PATH=plugins 
export QT_QPA_PLATFORM=linuxfb:fb=/dev/fb0:size=480x640:mmSize=1280x720:offset=0x0:tty=/dev/ttymxc0
export TSLIB_TSDEVICE=/dev/input/event1 #注意:该设备为板子触摸屏文件

移植后执行QT应用文件,可能会出现以下问题:

QIconvCodec::convertToUnicode: using Latin-1 for conversion, iconv_open failed
QIconvCodec::convertFromUnicode: using Latin-1 for conversion, iconv_open failed

下载 http://ftp.gnu.org/gnu/libiconv/libiconv-1.14.tar.gz 解压后,执行以下命令:

./configure -prefix=$PWD/_install -host=arm-linux-gnueabihf  
wget -c http://www.itkb.ro/userfiles/file/libiconv-glibc-2.16.patch.gz
gzip -d libiconv-glibc-2.16.patch.gz 
cp libiconv-glibc-2.16.patch libiconv-1.14/srclib #将补丁考到 libiconv-1.14/srclib 目录
cd libiconv-1.14/srclib
patch -p1 <libiconv-glibc-2.16.patch
cd libiconv-1.14 #返回
make
make install 
#把_install/lib 下的preloadable_libiconv.so 拷到最小根文件系统的/lib 下, 
#/etc/profile添加
export LD_PRELOAD=/lib/preloadable_libiconv.so

不打补丁会出现以下问题:
make[2]: [progname.o] Error 1
make[2]: Waiting for unfinished jobs…
make[2]: Leaving directory /opt/sources/libiconv-1.14/srclib
make[1]: [all] Error 2
make[1]: Leaving directory /opt/sources/libiconv-1.14/srclib

make: *** [all] Error 2

参考链接:

此刻,兼容QT5.6.0的最小根文件制作完成

四.使用genimage制作可烧录运行镜像

在制作完最小根文件系统后,需配置系统内核模块以及固件:
重新挂载rootfs.ext4,在根文件系统下创建/boot目录,
拷贝编译好的内核镜像和设备树文件到 arm 架构 ubuntu 根文件系统的 boot 目录下。

安装内核模块到arm架构的ubuntu文件系统内,如下命令所示,

book@100ask:~/100ask_imx6ull-sdk/Linux-4.9.88$ sudo make ARCH=arm INSTALL_MOD_PATH=/home/book/nfs_rootfs/roofs_ext4_touch/rootfs_mount modules_install

INSTALL_MOD_PATH后面的目录地址为 arm 架构 ubuntu 文件系统所在绝对路径(模块安装前需要先编译模块make moudle)。

安装完内上述文件后,即可进行镜像生成操作如下命令所示,需要先生成一个大小为 2GB 的 rootfs.ext4 镜像文件,让后格式化镜像为 ext4 格式,之后通过挂载镜像方式把制作好的镜像文件拷贝到文件系统内。

book@100ask:~$ dd if=/dev/zero of=rootfs.ext4 bs=1M count=512
book@100ask:~$ sudo mkfs.ext4 -F rootfs.ext4

100ASK-IMX6ULL开发板_QT移植全过程_arm_12

如下命令所示,创建一个 rootfs-mount 目录,并挂载 rootfs.ext4 镜像到该目录下,之后拷贝制作好的文件系统内所有文件到此挂载目录,紧接着使用 sync 命令同步数据缓存保证拷贝完成,完成后可以使用 sudo umount rootfs-mount/卸载当前挂载的镜像。

book@100ask:~$ mkdir rootfs-mount
book@100ask:~$ sudo mount rootfs.ext4 rootfs_mount/
book@100ask:~$ sudo cp -rvfp min_blogrootfs/* rootfs_mount/
book@100ask:~$ sync
book@100ask:~$ sudo umount rootfs_mount/

100ASK-IMX6ULL开发板_QT移植全过程_linux_13

只制作好 ext4 格式的文件系统并不能直接烧录到开发板启动,此时我们需要使用一个 buildroot 下的一个镜像生成工具 genimage 来制作。首先把编译好生成的 genimage 可执行程序拷贝到家目录下,同时把编译好的 uboot 镜像文件 u-boot-dtb.imx 文件也拷贝到当前目录下。

此时需要在家目录下新建一个名为 root-genimage.cfg 的分区配置文件,里面写入如下信息。

image 100ask_imx6ull.img {
        hdimage {
}
partition u-boot {
        in-partition-table = "no"
        image = "u-boot-dtb.imx"
        offset = 1024
}
partition arduino {
        partition-type = 0xC
        size = 50M
        offset = 10M
}
partition rootfs {
        partition-type = 0x83
        image = "rootfs.ext4"
        size = 512M
}

此时目录下有如下 4 个文件,分别是 rootfs-genimage.cfg rootfs.ext4 u-boot-dtb.imx genimage

100ASK-IMX6ULL开发板_QT移植全过程_imx6ull_14

此时我们可以执行如下命令来生成 ubuntu-16.04-armhf_100ask_imx6ull.img 系统镜像文件。

book@100ask:~$ mkdir root
book@100ask:~$ sudo ./genimage --inputpath ./ --outputpath ./ --config ./rootfs-genimage.cfg

执行命令完成在当前路径下生成空白文件目录与镜像文件100ask_imx6ull.img。

100ASK-IMX6ULL开发板_QT移植全过程_linux_15

使用FileZilla软件将镜像文件拷贝到PC机修改正确的文件目录名称,使用100ask_imx6ull_flashing_tool即可烧录运行测试

五. 功能演示

  1. 测试tslib,并校准屏幕:

100ASK-IMX6ULL开发板_QT移植全过程_qt_16


100ASK-IMX6ULL开发板_QT移植全过程_qt移植_17

  1. 自己编写的QT测试程序,编译执行:

100ASK-IMX6ULL开发板_QT移植全过程_qt_18


100ASK-IMX6ULL开发板_QT移植全过程_qt_19

PS:根文件系统没有一次制作完成得多次挂载移植文件有点繁琐,不过当作练习命令敲写:!,过程还有很多地方得学习改进…