移植Qt5.12.9

编程入门 行业动态 更新时间:2024-10-24 02:02:18

移植Qt5.12.9

移植Qt5.12.9

  • 参考正点原子的Qt移植教程,整理自己实际的应用步骤
  • 同样的步骤测试Qt5.9.5也适用

一、安装虚拟机环境

  • 当前使用版本:Ubuntu16.04.7
$ lsb_release -a	# 查看当前系统信息

二、安装交叉编译器

2.1 下载交叉编译器

  • 下载地址:Linaro Releases
  • 交叉编译器版本:4.9.4
    • 【TIPS】不推荐选择过高版本,建议采用实测版本
    • 根据芯片类型选择,不带
  • 根据当前系统版本选择对应的文件
$ uname -a 
Linux ubuntu 4.15.0-112-generic #113~16.04.1-Ubuntu SMP Fri Jul 10 04:37:08 UTC 2020 x86_64 x86_64 x86_64 GNU/Linux# x86_64: 当前系统为64位系统,选择x86_64版本的交叉编译器

2.2 安装交叉编译器

  • 新建arm文件
$ sudo mkdir /usr/local/arm
  • 解压交叉编译器压缩包到arm路径下
$ sudo tar -xvf gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabi.tar.xz## 建议重新修改名称
$ mv gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabi /usr/local/arm/linaro-4.9.4
  • 配置环境变量
$ sudo vim /etc/profile
## 将下行内容添加到文件末尾
export PATH=$PATH:/usr/local/arm/linaro-4.9.4/bin## /etc/profile 开机加载;通过source指令立即生效
$ source /etc/profile

2.3 验证交叉编译器

## 使用该交叉编译器前,需要在Ubuntu安装一些库 【必要!】
$ sudo apt-get install lsb-core lib32stdc++6	## 验证交叉编译器,有版本信息输出则配置完成
$ arm-linux-gnueabi-gcc -v
...
gcc version 4.9.4 (Linaro GCC 4.9-2017.01)

三、获取和编译tslib

  • Qt支持触摸屏,还需要编译tslib,以产生相关插件

3.1 下载tslib

  • 下载地址:tslib
  • 项目页面的右侧,在release中选择1.21版本

3.2 编译tslib

  • 安装辅助软件
$ sudo apt-get update
$ sudo apt-get install autoconf automake libtool
  • 调用脚本
$ tar -xvf tslib-1.21	## 解压
$ cd tslib-1.21
$ ./autogen.sh	# 软件文件夹自带脚本
  • 执行configure指令
$ ./configure \
--host=arm-linux-gnueabi \ # 指定编译器
ac_cv_func_malloc_0_nonnull=yes \
--cache-file=arm-linux.cache \
-prefix=${PWD}/arm-tslib # 指定编译输出路径;根据自己的实际路径设置
  • 编译
$ make 			
$ make install 

3.3 验证编译生成文件

$ file /arm-tslib/bin/ts_calibrate	# 查看编译生成文件的类型; 32-bit  ARM 即为正确
bin/ts_calibrate: ELF 32-bit LSB executable, ARM, EABI5 version 1 (SYSV),
dynamically linked, interpreter /lib/ld-linux.so.3, for GNU/Linux 2.6.31,
BuildID[sha1]=235a90a36a321ae53ee3f6f63f44d7aed8e83e64, not stripped

四、编译Qt5.12.9源码

4.1 下载源码

  • 下载地址:Qt5.12.9

  • 解压源码
$ tar -xvf qt-everywhere-src-5.12.9.tar.xz## 建议修改文件名
$ mv qt-everywhere-src-5.12.9 qt-5.12.9
$ cd qt-5.12.9

4.2 修改qmake.conf

$ gedit qtbase/mkspecs/linux-arm-gnueabi-g++/qmake.conf## 添加下列内容;位置在 include(../common/linux.conf) 之前
QT_QPA_PLATFORM = linuxfb:fb=/dev/fb0
QMAKE_CFLAGS_RELEASE += -O2 -march=armv7-a
QMAKE_CXXFLAGS_RELEASE += -O2 -march=armv7-a

4.3 修改qlinuxfbscreen

  • 在嵌入式中运行,Qt4采用QWS系统,Qt5采用QPA方案
  • 在Qt4中可设置QWS_DISPLAY旋转软件
  • 在Qt5中只能通过修改qlinuxfbscreen源码处理【通过QGraphicsScene的方案,事件无法往子控件传递】
$ gedit qtbase/src/plugins/platforms/linuxfb/qlinuxfbscreen.h	# 修改头文件
$ gedit qtbase/src/plugins/platforms/linuxfb/qlinuxfbscreen.cpp # 修改源文件
class QLinuxFbScreen : public QFbScreen
{Q_OBJECT
public:QLinuxFbScreen(const QStringList &args);~QLinuxFbScreen();bool initialize() override;QPixmap grabWindow(WId wid, int x, int y, int width, int height) const override;QRegion doRedraw() override;private:QStringList mArgs;int mFbFd;int mTtyFd;// add by immortal startint mRotation;// add by immortal endQImage mFbScreenImage;int mBytesPerLine;int mOldTtyMode;struct {uchar *data;int offset, size;} mMmap;QPainter *mBlitter;
};
QLinuxFbScreen::QLinuxFbScreen(const QStringList &args)//   : mArgs(args), mFbFd(-1), mTtyFd(-1), mBlitter(0)  // modify by immortal: mArgs(args), mFbFd(-1), mTtyFd(-1), mBlitter(0),mRotation(0)
{mMmap.data = 0;
}QLinuxFbScreen::~QLinuxFbScreen()
{if (mFbFd != -1) {if (mMmap.data)munmap(mMmap.data - mMmap.offset, mMmap.size);close(mFbFd);}if (mTtyFd != -1)resetTty(mTtyFd, mOldTtyMode);delete mBlitter;
}bool QLinuxFbScreen::initialize()
{QRegularExpression ttyRx(QLatin1String("tty=(.*)"));QRegularExpression fbRx(QLatin1String("fb=(.*)"));QRegularExpression mmSizeRx(QLatin1String("mmsize=(\\d+)x(\\d+)"));QRegularExpression sizeRx(QLatin1String("size=(\\d+)x(\\d+)"));QRegularExpression offsetRx(QLatin1String("offset=(\\d+)x(\\d+)"));// add by immorta startQRegularExpression rotationRx(QLatin1String("rotation=(0|90|180|270)"))// add by immorta endQString fbDevice, ttyDevice;QSize userMmSize;QRect userGeometry;bool doSwitchToGraphicsMode = true;// Parse argumentsforeach (const QString &arg, mArgs) {QRegularExpressionMatch match;if (arg == QLatin1String("nographicsmodeswitch"))doSwitchToGraphicsMode = false;else if (arg.contains(mmSizeRx, &match))userMmSize = QSize(match.captured(1).toInt(), match.captured(2).toInt());else if (arg.contains(sizeRx, &match))userGeometry.setSize(QSize(match.captured(1).toInt(), match.captured(2).toInt()));else if (arg.contains(offsetRx, &match))userGeometry.setTopLeft(QPoint(match.captured(1).toInt(), match.captured(2).toInt()));else if (arg.contains(ttyRx, &match))ttyDevice = match.captured(1);else if (arg.contains(fbRx, &match))fbDevice = match.captured(1);// add by immortal startelse if (arg.contains(rotationRx, &match))mRotation = match.captured(1).toInt();// add by immortal end}if (fbDevice.isEmpty()) {fbDevice = QLatin1String("/dev/fb0");if (!QFile::exists(fbDevice))fbDevice = QLatin1String("/dev/graphics/fb0");if (!QFile::exists(fbDevice)) {qWarning("Unable to figure out framebuffer device. Specify it manually.");return false;}}// Open the devicemFbFd = openFramebufferDevice(fbDevice);if (mFbFd == -1) {qErrnoWarning(errno, "Failed to open framebuffer %s", qPrintable(fbDevice));return false;}// Read the fixed and variable screen informationfb_fix_screeninfo finfo;fb_var_screeninfo vinfo;memset(&vinfo, 0, sizeof(vinfo));memset(&finfo, 0, sizeof(finfo));if (ioctl(mFbFd, FBIOGET_FSCREENINFO, &finfo) != 0) {qErrnoWarning(errno, "Error reading fixed information");return false;}if (ioctl(mFbFd, FBIOGET_VSCREENINFO, &vinfo)) {qErrnoWarning(errno, "Error reading variable information");return false;}mDepth = determineDepth(vinfo);mBytesPerLine = finfo.line_length;QRect geometry = determineGeometry(vinfo, userGeometry);// add by immortal startQRect originalGeometry = geometry;if( 90 == mRotation  || 270 == mRotation ){int tmp = geometry.width();geometry.setWidth(geometry.height());geometry.setHeight(tmp);}// add by immortal endmGeometry = QRect(QPoint(0, 0), geometry.size());mFormat = determineFormat(vinfo, mDepth);// modify by immortal start//   mPhysicalSize = determinePhysicalSize(vinfo, userMmSize, geometry.size());mPhysicalSize = determinePhysicalSize(vinfo, userMmSize, originalGeometry.size());// modify by immortal end// mmap the framebuffermMmap.size = finfo.smem_len;uchar *data = (unsigned char *)mmap(0, mMmap.size, PROT_READ | PROT_WRITE, MAP_SHARED, mFbFd, 0);if ((long)data == -1) {qErrnoWarning(errno, "Failed to mmap framebuffer");return false;}// modify by immortal start
//   mMmap.offset = geometry.y() * mBytesPerLine + geometry.x() * mDepth / 8;mMmap.offset = originalGeometry.y() * mBytesPerLine + originalGeometry.x() * mDepth / 8;// modify by immortal endmMmap.data = data + mMmap.offset;QFbScreen::initializeCompositor();// modify by immortal start// mFbScreenImage = QImage(mMmap.data, geometry.width(), geometry.height(), mBytesPerLine, mFormat);mFbScreenImage = QImage(mMmap.data, originalGeometry.width(), originalGeometry.height(), mBytesPerLine, mFormat);// modify by immortal endmCursor = new QFbCursor(this);mTtyFd = openTtyDevice(ttyDevice);if (mTtyFd == -1)qErrnoWarning(errno, "Failed to open tty");switchToGraphicsMode(mTtyFd, doSwitchToGraphicsMode, &mOldTtyMode);blankScreen(mFbFd, false);return true;
}QRegion QLinuxFbScreen::doRedraw()
{QRegion touched = QFbScreen::doRedraw();if (touched.isEmpty())return touched;if (!mBlitter)mBlitter = new QPainter(&mFbScreenImage);const QVector<QRect> rects = touched.rects();mBlitter->setCompositionMode(QPainter::CompositionMode_Source);for (int i = 0; i < rects.size(); ++i) 	// add by immortal start		{if( 90 == mRotation || 270 == mRotation ){mBlitter->translate(mGeometry.height()/2, mGeometry.width()/2);}else if( 180 == mRotation ){mBlitter->translate(mGeometry.width()/2, mGeometry.height()/2);}if( mRotation != 0 ){mBlitter->rotate(mRotation);mBlitter->translate(-mGeometry.width()/2, -mGeometry.height()/2);}// add by immortal end	mBlitter->drawImage(rects[i], *mScreenImage, rects[i]);// add by immortal startmBlitter->resetTransform();// add by immortal end}return touched;
}// grabWindow() grabs "from the screen" not from the backingstores.
// In linuxfb's case it will also include the mouse cursor.
QPixmap QLinuxFbScreen::grabWindow(WId wid, int x, int y, int width, int height) const
{if (!wid) {if (width < 0)width = mFbScreenImage.width() - x;if (height < 0)height = mFbScreenImage.height() - y;return QPixmap::fromImage(mFbScreenImage).copy(x, y, width, height);}QFbWindow *window = windowForId(wid);if (window) {const QRect geom = window->geometry();if (width < 0)width = geom.width() - x;if (height < 0)height = geom.height() - y;QRect rect(geom.topLeft() + QPoint(x, y), QSize(width, height));rect &= window->geometry();return QPixmap::fromImage(mFbScreenImage).copy(rect);}return QPixmap();
}

4.4 配置编译选项

## 配置选项保存为脚本文件
$ gedit autoconfigure.sh
$ sudo chmod a+x autoconfigure.sh	# 添加执行权限
$ ./autoconfigure.sh
...
Qt is now configure for building, Just run 'make' # 看到此条信息,可直接编译
...
## autoconfigure.sh文件内容
#!/bin/bash./configure -prefix ${PWD}/arm-qt \
-opensource \
-confirm-license \
-release \
-strip \
-shared \
-xplatform linux-arm-gnueabi-g++ \
-optimized-qmake \
-c++std c++11 \
--rpath=no \
-pch \
-make libs \
-nomake examples -nomake tools \
-nomake tests \
-gui \
-widgets \
-dbus-runtime \
--glib=no \
--iconv=no \
--pcre=qt \
--zlib=qt \
-no-openssl \
-no-opengl \
--freetype=qt \
--harfbuzz=qt \
-linuxfb \
--xcb=no \
-tslib \
--libpng=qt \
--libjpeg=qt \
--sqlite=qt \
-plugin-sql-sqlite \
-I/usr/local/arm/arm-tslib/include \	# 设定为实际路径
-L/usr/local/arm/arm-tslib/lib \		# 设置为实际路径
-recheck-all

4.5 编译Qt源码

$ make # 等 1-2 h完成,也可以使用 make -j n;全速编译
make[1]: Leaving directory ...$ make install

五、移植Qt到示教器

5.1 移植tslib

## 压缩编译输出文件
$ tar -zcvf arm-tslib.tar.gz arm-tslib
  • 通过scp、sftp或U盘将文件传送到示教器中
$ tar -zxvf arm-tslib.tar.gz	# 解压文件
  • 配置环境变量
## 示教器使用 vim.tiny;显示有时有问题,改用nano编辑
$ nano /etc/bash.bashrc
## 将之间的配置信息注释
# export T_ROOT=/usr/local/tslib
# export TSLIB_CONFFILE=$T_ROOT/etc/ts.conf
# export TSLIB_TSEVENTTYPE=H3600
# export TSLIB_CONSOLEDEVICE=none
# export TSLIB_FBDEVICE=/dev/fb0
# export TSLIB_PLUGINDIR=$T_ROOT/lib/ts
# export TSLIB_CALIBFILE=/etc/pointercal## 修改环境变量
export TSLIB_ROOT=/usr/local/arm/tslib-1.21 # 实际存放路径
export TSLIB_CONSOLEDEVICE=none
export TSLIB_FBDEVICE=/dev/fb0
export TSLIB_CONFFILE=$TSLIB_ROOT/etc/ts.conf
export TSLIB_PLUGINDIR=$TSLIB_ROOT/lib/ts
export TSLIB_CALIBFILE=/etc/pointercal
export LD_PRELOAD=$TSLIB_ROOT/lib/libts.so
if [ -e /dev/input/mouse1 ]; then
export TSLIB_TSDEVICE=/dev/input/event2
else
export TSLIB_TSDEVICE=/dev/input/event1
rm -f /dev/input/mouse0
fi
  • 测试tslib
$ source /etc/bash.bashrc
$ /usr/local/arm/tslib-1.21/bin/ts_test # 运行ts_test测试触摸屏是否正常

5.2 移植Qt

## 压缩编译输出文件
$ tar -zcvf arm-qt.tar.gz arm-qt
  • 传输方式同上即可
$ tar -zxvf arm-qt.tar.gz
  • 配置环境变量
$ nano /etc/bash.bashrc
## Qt5 使用 QPA 环境变量;Qt4 使用 QWS 环境变量
export QT_ROOT=/usr/local/arm/qt-5.12 # 实际路径
export QT_QPA_GENERIC_PLUGINS=tslib:/dev/input/event1
export QT_QPA_FONTDIR=/usr/share/fonts # 如果没有,找到系统自带的;指定为实际路径
export QT_QPA_PLATFORM_PIUGIN_PATH=$QT_ROOT/plugins
export QT_QPA_PLATFORM=linuxfb:fb=/dev/fb0:rotation=90 # 指定旋转度数
export QT_PLUGIN_PATH=$QT_ROOT/plugins
export LD_LIBRARY_PATH=$QT_ROOT/lib:$QT_ROOT/plugins/platforms
export QML2_IMPORT_PATH=$QT_ROOT/qml
export QT_QPA_FB_TSLIB=1
  • 测试Qt运行
$ source /etc/bash.bashrc
## 由于编译Qt源码跳过了examples 和 tests,无现成的测试应用;需要新建工程测试,结合下一节实现

六、搭建ARM平台的Qt Creator环境

6.1 安装Qt Creator

  • 下载地址:Qt5.12.9

  • 下载完成,在虚拟机环境双击安装

6.2 配置Qt Creator Kit

  • 打开选项

  • 配置qmake:找到编译生成arm-qt下的qmake

  • 配置gcc编译器:安装的linaro

  • 配置Kits:以实际版本名称,或自定义命名

6.3 编译程序

  • 选择Arm Kit编译Qt工程

七、运行程序

  • 将文件传输到示教器
  • 添加可执行权限
  • 直接执行

7.1 旋转tslib

  • 软件旋转后,触摸的坐标系没有匹配;导致点击屏幕的位置不对
$ /usr/local/arm/tslib-1.21/bin/ts_calibrate -h	# 查看帮助信息
$ ts_calibrate -r 1	# 旋转90°,调出屏幕校准;文字阅读方向即为当前正方向

  • 校准屏幕后直接运行程序
$ ./Icon	# 直接运行即可

更多推荐

移植Qt5.12.9

本文发布于:2024-03-04 02:02:54,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1707964.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!