具备交叉编译工具
电脑上原先已经包含了交叉编译工具 arm-bulidroot-linux-gnueabihf-gcc
移植tslib
qt库需要支持触摸屏需要先移植tslib
https://github.com/libts/tslib?tab=readme-ov-file
下载后,放到linux上进行解压
unzip tslib-master.zip
解压后,文件夹里面并没有Makefile文件,无法进行编译,需要自动生成Makefile
先安装一些需要的库
sudo apt-get install autoconf automake libtool
再按照如下命令一一运行进行编译
执行此文件进行自动生成
./auto-gen.sh
执行此命令进行configure
CC是编译,在交叉编译工具加上-gcc,必须跟工具完全一样
--host为交叉工具,必须跟工具完全一样
--prefix是编译后安装的文件路径,编译后的产物
CC=arm-buildroot-linux-gnueabihf-gcc ./configure --host=arm-buildroot-linux-gnueabihf ac_cv_func_malloc_0_nonnull=yes --cache-file=arm-linux.cache -prefix=/home/book/qt-work/tslib-master/qt-tslib
编译
make -j4
编译后安装
make install
然后,就能在文件路径下的,arm-tslib看到
重要:如果CC=arm-buildroot-linux-gnueabihf-gcc 和 --host=arm-buildroot-linux-gnueabihf 没有严格使用交叉编译,那么编译QT时,使用tslib,就会报错如下,因为交叉编辑工具链不一致
Feature 'tslib' was enabled, but the pre-condition 'libs.tslib' failed.
QT编译
1. 首先,下载qt,可以使用国内镜像
阿里云镜像:https://mirrors.aliyun.com/qt/
路径是:/archive/qt/5.15/5.15.13/single/
qt-everywhere-opensource-src-5.15.13.tar.xz
下载完,放到linux,进行解压
tar -xvf qt-everywhere-src-5.15.13.tar.xz
2.修改qmake.conf
进入路径如下,修改qmake.conf
qt-everywhere-src-5.15.13/qtbase/mkspecs/linux-arm-gnueabi-g++/qmake.conf
注意:
1. QT_QPA_DEFAULT_PLATFORM,QMAKE_CFLAGS,AMAKE_CXXFLAGS为新增,请保持一致,对应imx6ull
2. 所有的arm-buildroot-linux-gnueabihf 换成自己的编译工具链,否则编译不会通过
#
# 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)
QT_QPA_DEFAULT_PLATFORM = linuxfb
QMAKE_CFLAGS += -O2 -march=armv7-a -mtune=cortex-a7 -mfpu=neon -mfloat-abi=hard
AMAKE_CXXFLAGS += -O2 -march=armv7-a -mtune=cortex-a7 -mfpu=neon -mfloat-abi=hard
# modifications to g++.conf
QMAKE_CC = arm-buildroot-linux-gnueabihf-gcc
QMAKE_CXX = arm-buildroot-linux-gnueabihf-g++
QMAKE_LINK = arm-buildroot-linux-gnueabihf-g++
QMAKE_LINK_SHLIB = arm-buildroot-linux-gnueabihf-g++
# modifications to linux.conf
QMAKE_AR = arm-buildroot-linux-gnueabihf-ar cqs
QMAKE_OBJCOPY = arm-buildroot-linux-gnueabihf-objcopy
QMAKE_NM = arm-buildroot-linux-gnueabihf-nm -P
QMAKE_STRIP = arm-buildroot-linux-gnueabihf-strip
load(qt_config)
3. 在qt-everywhere-src-5.15.13目录下,新增autoconfigure.sh,根据自己的路径进行配置
需要修改的
-prefix /home/book/qt-work/qt-everywhere-src-5.15.13/arm-qt 为编译后输出的目录,改为自己要的路径
以下改为前面编译后tslib的路径
-I/home/book/qt-work/tslib/arm-tslib/include
-L/home/book/qt-work/tslib/arm-tslib/lib
./configure -prefix /home/book/qt-work/qt-everywhere-src-5.15.13/arm-qt \
-opensource \
-confirm-license \
-release \
-strip \
-shared \
-xplatform linux-arm-gnueabi-g++ \
-optimized-qmake \
-c++std c++11 \
--rpath=no \
-pch \
-skip qt3d \
-skip qtactiveqt \
-skip qtandroidextras \
-skip qtcanvas3d \
-skip qtconnectivity \
-skip qtdatavis3d \
-skip qtdoc \
-skip qtgamepad \
-skip qtlocation \
-skip qtmacextras \
-skip qtnetworkauth \
-skip qtpurchasing \
-skip qtremoteobjects \
-skip qtscript \
-skip qtscxml \
-skip qtsensors \
-skip qtspeech \
-skip qtsvg \
-skip qttools \
-skip qttranslations \
-skip qtwayland \
-skip qtwebengine \
-skip qtwebview \
-skip qtwinextras \
-skip qtx11extras \
-skip qtxmlpatterns \
-make libs \
-make examples \
-nomake tools -nomake tests \
-gui \
-widgets \
-dbus-runtime \
--glib=no \
--iconv=no \
--pcre=qt \
--zlib=qt \
-no-openssl \
--freetype=qt \
--harfbuzz=qt \
-no-opengl \
-linuxfb \
--xcb=no \
-tslib \
--libpng=qt \
--libjpeg=qt \
--sqlite=qt \
-plugin-sql-sqlite \
-I/home/book/qt-work/tslib/arm-tslib/include \
-L/home/book/qt-work/tslib/arm-tslib/lib \
-recheck-all
4. 编译,安装
autoconfigure.sh 如果报错,请严格确认前面的配置文件是否正确
make需要时间比较久,且过程中,如果发现编译报错,请自行网络搜索,并更正,一般都能找到答案
Chmod +x autoconfigure.sh
./autoconfigure.sh
make
make install
放到板上进行验证
编译得到的qt和tslib,放到板上
设置开发版的环境,编辑/etc/profile,在后面加入tslib和qt的配置
注意修改为自己的路径
export TSLIB_ROOT=/root/arm-tslib
export QT_ROOT=/root/arm-qt
接着source /etc/profile 使得配置文件生效
export TSLIB_ROOT=/root/arm-tslib
export TSLIB_CONSOLEDEVICE=none
export TSLIB_FBDEVICE=/dev/fb0
export TSLIB_TSDEVICE=/dev/input/event1
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
export QT_ROOT=/root/arm-qt
export QT_QPA_GENERIC_PLUGINS=tslib:/dev/input/event1
export QT_QPA_FONTDIR=/usr/share/fonts
export QT_QPA_PLATFORM_PLUGIN_PATH=$QT_ROOT/plugins
export QT_QPA_PLATFORM=linuxfb:tty=/dev/fb0
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的例子进行确认
进入/root/arm-qt/examples/widgets/animation/animatedtiles/
执行 ./animatedtiles
其他知识点:
Qt调用硬件使用的是插件,目前使用的是linuxfb,摘取initialize函数,包含打开设备以及获取fb_fix_screeninfo和fb_var_screeninfo,最后mmap了framebuffer
qt-everywhere-src-5.15.13/qtbase/src/plugins/platforms/linuxfb/qlinuxfbscreen.cpp
bool QLinuxFbScreen::initialize()
{
//省略参数获取,具体看原档
QString fbDevice, ttyDevice;
QSize userMmSize;
QRect userGeometry;
bool doSwitchToGraphicsMode = true;
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 device
mFbFd = openFramebufferDevice(fbDevice);
if (mFbFd == -1) {
qErrnoWarning(errno, "Failed to open framebuffer %s", qPrintable(fbDevice));
return false;
}
// Read the fixed and variable screen information
fb_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);
mGeometry = QRect(QPoint(0, 0), geometry.size());
mFormat = determineFormat(vinfo, mDepth);
mPhysicalSize = determinePhysicalSize(vinfo, userMmSize, geometry.size());
// mmap the framebuffer
mMmap.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;
}
mMmap.offset = geometry.y() * mBytesPerLine + geometry.x() * mDepth / 8;
mMmap.data = data + mMmap.offset;
QFbScreen::initializeCompositor();
mFbScreenImage = QImage(mMmap.data, geometry.width(), geometry.height(), mBytesPerLine, mFormat);
mCursor = new QFbCursor(this);
mTtyFd = openTtyDevice(ttyDevice);
if (mTtyFd == -1)
qErrnoWarning(errno, "Failed to open tty");
switchToGraphicsMode(mTtyFd, doSwitchToGraphicsMode, &mOldTtyMode);
blankScreen(mFbFd, false);
return true;
}