|||
前面我用arm-linux-gnueabihf-readelf -d qtdemo已经检查过,程序已经包含使用libts.so共享库,但是运行qtdemo时点击触摸屏没有响应。
在qt的网站上看都通过设置QT_PLUGIN_PATH来加载共享库,但是设置后没有解决问题。
后来上网查到,能够设置qt的运行环境变量export QT_DEBUG_PLUGINS=1,来在运行qt程序时,在超级终端打印输出信息。
1、知道qt程序是通过qt5.4.1开发包中的libqtslibplugin.so(generic plugin库的一种)和libts.so通信的,首先确认arm的nfs系统中是否存在需要的这些库,并路径设置是否正确。
2、发现库都对,并路径设置也是对的。
3、添加QT_DEBUG_PLUGINS后,启动qtdmeo时,查看minicom超级终端上的打印信息,发现只laod了linuxfb库,没有加载libqtslibplugin库,但是库的版本,路经设定都是对的,所以决定检查qt5.4.1运行库加载共享库的过程。
4、基于gui的qt程序启动时,需要初始化gui类,在gui的初始化过程中,会在init_platform函数中加载platform库,在init_plugins函数中加载generic plugins库,并最终是通过source/qtbase/src/corelib/plugin/qfactorylaoder.cpp来加载共享库:
void QFactoryLoader::update()
{
#ifdef QT_SHARED
Q_D(QFactoryLoader);
QStringList paths =QCoreApplication::libraryPaths();
for (int i = 0; i < paths.count(); ++i) {
const QString &pluginDir = paths.at(i);
// Already loaded, skip it...
if (d->loadedPaths.contains(pluginDir)) continue;
d->loadedPaths << pluginDir;
QString path = pluginDir + d->suffix;
qDebug()<<"load at directory:"<<path; //增加这行代码,将加载插件时的搜索路径打印出来
if(qt_debug_component())
qDebug() <<"QFactoryLoader::QFactoryLoader() checking directory path" <<path << "...";
if(!QDir(path).exists(QLatin1String(".")))
continue;
QStringList plugins = QDir(path).entryList(QDir::Files);
QLibraryPrivate *library = 0;
进入到./source/qtbase/src/corelib目录下,执行make编译corelib,结束后,将./source/qtbase/lib目录下新的libQt5Core相关6个文件拷贝到arm的nfs文件系统中的opt/qt541arm/lib目录下,覆盖原来的core库文件。
重新运行qtdemo,发现超级终端打印出信息,在加载generic plugins共享库时,是在/qt541arm/plugins/platforms/generic目录下寻找库文件的,这显然是错误的。在Qt5.4.1默认的make install安装中,generic plugins库的目录是:/qt541arm/plugins/generic。(在这里,考虑将generic目录以及文件直接拷贝到/platforms目录下,不过我还没有这样尝试)
由于在QT的官网上查到的设置QT_PLUGIN_PATH环境变量的方法没有解决问题,所以决定自己改qt5.4.1的源程序。
不过这里不能修改corelib的qfactoryloader.cpp,由于generic plugins是由gui加载的,所以我们需要找到gui的源程序中加载generic
plugins库的代码。gui是在qguiapplication.cpp中调用qgenericpluginfactory.cpp的QGenericPluginFactory::create来加载generic plugins共享库,在./source/qtbase/src/gui目录下打开qgenericpluginfactory.cpp:
Q_GLOBAL_STATIC_WITH_ARGS(QFactoryLoader,loader,(QGenericPluginFactoryInterface_iid,QLatin1String("/generic"), Qt::CaseInsensitive))
上面的宏将corelib中的QFactoryLoader映射到loader,然后QGenericPluginFactory::createQObject *QGenericPluginFactory::create(const QString& key, const
QString &specification)
{
const QString driver = key.toLower();
#if !defined(Q_OS_WIN32) || defined(QT_SHARED)
#ifndef QT_NO_LIBRARY
if (QObject *object = qLoadPlugin1<QObject, QGenericPlugin>(loader(), driver, specification))
return object;
#endif
#endif
return 0;
}
在QGenericPluginFactory::create中,调用corelib的loader(QFactoryLoader),查找key指定的共享库,并加载。
显然路径是上面的宏传递到core去的:QLatin1String("/generic")。而在corelib的qfactoryloader中,是将这个路径直接加到corelib默认路径上的。
由于在gui初始化时,先调用platform的库加载函数,然后再调用generic plugins库的加载函数,导致core默认的路径是由QT_QPA_PLATFORM_PLGUIN_PATH来设置,所以这里gui加载generic plugins的路径就变成了QT_QPA_PLATFORM_PLGUIN_PATH/generic,这显然是错误的。
修改上面的宏:
Q_GLOBAL_STATIC_WITH_ARGS(QFactoryLoader,loader,(QGenericPluginFactoryInterface_iid,QLatin1String("/../generic"), Qt::CaseInsensitive))
将QLatin1String("/generic")修改为QLatin1String("/../generic")。
然后进入到./source/qtbase/src/gui目录中,执行make重新编译gui库。结束后,将./source/qtbase/lib目录下的libQt5Gui相关的6个文件拷贝到arm的nfs文件系统中的qt541arm/lib目录中。
然后重新启动qtdemo程序,这时发现minicom超级终端显示出找到Tslib和TslibRaw插件,并加载Tslib插件。程序最终加载2个共享库文件:libqlinuxfb和libqtslibplugin。屏幕上显示出qtdemo的对话框,点击触摸屏,发现qtdemo相应的执行了动作。
到此,就完成了Qt5.4.1和tslib移植到am335x的linux kernel 3.2.0的工作。
不过现在qt还有一个bug,就是在启动qt应用程序前,或者运行中,usb触摸屏设备故障后又自动恢复,qt应用程序时不能再次响应触摸屏事件。必须要退出qt应用程序,再次重新启动qt应用程序,才能够再次响应触摸屏事件。这对于工业控制的应用,就是一个很大的问题。下一篇笔记将讲述这个问题的解决过程。
(原创文章,转载请注明出处)
(未经本人同意,不得用于商业用途)