Arm-Linux嵌入式QT/E环境的建立(qt/e 3.x系列)

时间:2023-01-04 20:23:23
Arm-Linux嵌入式QT/E环境的建立(qt/e 3.x系列)
 
 
QT/E 3.x系列比QT/E 2.x系列有非常大的改进,大大提高了开发进度,不再使用tmake,安装也更简单。但目前在网上关于QT/E 3.x系列的介绍还是比较少,所以本文介绍一下QT/E 3.x系列的安装。

一、建立ARM交叉编译工具链

       在安装QT/E之前,应确保ARM-Linux交叉编译工具链已经建立,如果还没有可以参考以下步骤建立。

     1、下载交叉编译工具cross-2.95.3.tar.bz2(或其他版本如:cross-3.4.4.tar.bz2),这是已经制作好的ARM交叉编译工具链,只需解压及建交环境变量即可使用。

     2、把文件cross-2.95.3.tar.bz2拷贝到一个文件夹,这里我用:/usr/local/ARM这个目录。 注意后面建立环境变量时要与之对应。

      3、解压 tar   -xjvf    cross-2.95.3.tar.bz2

      4、建立环境变量 export    PATH=/usr/local/ARM/2.95.3/bin:$PATH

或者也可以写进文件 ~/.bashrc中,这样就不用每次开机都export啦。

             vi     ~/.bashrc

             在后面加上 export    PATH=/usr/local/ARM/2.95.3/bin:$PATH

     到此ARM-Linux交叉编译工具链就已经建好了。

二、编译QT

        1、QT/E*版可到官网ftp下载。网址是:ftp://ftp.trolltech.com/qt/source/ 。可自己选择一个版本下载,个人认为QT/E 3.x系列比较好用,不过QT/E 2.x系列在网上的资料比较多。但建议不用qt/e 3.3.x 的版本,因为在本人开发的过程当中试用过qt/e 3.3.4和qt/e3.3.8,发现它们在ARM开发板上占CPU的资源特高,一直占cpu 98%左右,现在我还没找到原因,不知道有没有哪位朋友也遇到这个问题。推荐用qt/e 3.1.0版本,我正在用,没遇到什么问题。

(注:问题已经得到解决,原来是键盘接口没做好,等有空与大家分享一下移植键盘接口的过程)

         2、在这里,本人假设用的是 qt-embedded-free-3.1.0.tar.bz2

         3、把文件qt-embedded-free-3.1.0.tar.bz2 拷贝到一个文件夹,这里我用:/usr/local/ARM这个目录。 注意后面建立环境变量时要与之对应。

         4、解压 tar   -xjvf   qt-embedded-free-3.1.0.tar.bz2  

             把解压后的文件夹qt-embedded-free-3.1.0改为qte。(可以不改,这里是为了方便,注意后面建立环境变量时要与之对应)   

                        mv     qt-embedded-free-3.1.0     qte

         5、建立环境变量

                       vi     ~/.bashrc

               在后面加上

                       export QTDIR=/usr/local/ARM/qte
                       export QTEDIR=$QTDIR
                       export PATH=$QTDIR/bin:$PATH
                       export LD_LIBRARY_PATH=$QTDIR/lib:$LD_LIBRARY_PATH

              (请重新登陆,以使得环境变量生效)

          6、配置QT

            进入QT/E目录:     cd    $QTDIR

              输入:   ./configure  -embedded  ARM   -thread  -no-cups -qvfb -depths 4,8,16,32


            上述选项: -embedded  ARM 指目标平台为ARM; -thread 表示支持qt线程,本人开发当中用到; -qvfb 表示支持虚拟缓冲帧工具qvfb;-depths 4,8,16,32 表示支持4,8,16,32 位的显示颜色深度。还有很多选项就不一一列举,请查看 ./configure  -help。

         此外还有一个选项我没用的是 -qconfig  local,你可以把一些开关变量写到一个文件qconfig-local.h 中,并把它放到$QTDIR/src/tools下。可参考这个目录下的qconfig-small.h、qconfig-medium.h 、qconfig-large.h等文件,直接使用它们也行,如:  -qconfig  small 。通过这些开关变量,可以把一些开发当中用不着的构件去掉,减少qt库的大小。这里要对QT比较熟练,初学者可先不理。


            (本人在家里编译到这里曾出现编译 $QTDIR/include/qvaluestack.h 这个文件的时候出错,后来把qt3.3.8对应的文件拷贝过来覆盖便通过了,估计是与gcc的版本不兼容的问题,我在公司里没出现过这种问题)

         7、编译

            make sub-src      // 指定按精简方式编译开发包,也就是说有些Qt 类未被编
译。

          8、测试

                  至此编译工作完成,最后测试一下是否能正常使用。我们可以用QT自带的例子来测试,如:

                  cd  $QTDIR/examples/aclock      //或你自己新建一个QT工程也行

                  make clean                              //把原来的清掉

                   rm    *.pro      Makefile                       //删掉,重新建立工程文件

                   qmake   -project

                    qmake   -spec  $QTDIR/mkspecs/qws/Linux-ARM-g++   -o  Makefile           

                -spec指定目标板的配置文件,这里我做的是Linux ARM平台,注意在这里,$QTDIR/mkspecs/qws/Linux-ARM-g++ 它不是编译器,是一个配置文件,而编译时用的编译器是我们在第一步建立的ARM交叉编译工具链里面的编译器。 

                   make                      

             如果没出错就表示你的QT/E环境已经成功建立。如果提示说cannot   find   -lqte,那么你试一下修改Makefile文件,找到-lqte ,把它改为-lqte-mt再make一次一般就行了。这是因为如果用到QT线程或其它一些原因,它生成的库不再是libqte.so.3.1.0,而是 libqte-mt.so.3.1.0,所以它便找不到了。

三、移植到开发板(以下都是在目标机环境下)

        1、新建一个目录,如:/qt/lib。进入此目录 cd   /qt/lib

        2、通过 ftp  把上面生成的qt库文件libqte-mt.so.3.1.0下载到开发板/qt/lib/目录下。(注意:不要用wget 下载,会破坏库文件,从而出现  ld.so: dynamic-link.h: 62: elf_get_dynamic_info: Assertion `! "bad dynamic tag"'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' failed!.这种错误

        3、创建qt库连接:

                ln   -s   libqte-mt.so.3.1.0     libqte-mt.so

                ln   -s   libqte-mt.so.3.1.0     libqte-mt.so.3

                ln   -s   libqte-mt.so.3.1.0     libqte-mt.so.3.1

        4、建立环境变量

                       vi     ~/.bashrc

               在后面加上

                       export QTDIR=/qt
                       export QTEDIR=$QTDIR
                       export LD_LIBRARY_PATH=$QTDIR/lib:$LD_LIBRARY_PATH

           4、到此目标板的环境已经建好。现在可以把上面的例子aclock下载到目标板上试一下能不能跑起来!

             在开发板控制台下输入:  ./aclock  -qws 

             如果能跑起来但是键盘用不了,那是正常的情况,因为键盘、鼠标等设备的接口还没加进QT/E的原因,而这个不是一两句话能说清的,所以留到以后再另外补充!

补充一点:如果有类似这样的提示:  "./aclock: error while loading shared libraries: libstdc++.so.6: cannot load shared object file: No such file or directory." 你可以从我们第一步建立的 ARM交叉编译工具链里的/usr/local/ ARM/2.95.3/ ARM- Linux/lib/目录下找到相应的库文件下载到开发板的 /lib 目录下即可。


===============================================

嵌入式linux下QT3/Embedded的输入设备驱动接口

[日期:2008-04-30] 来源:中嵌网  作者:admin [字体: ]

一、Qt3/Embedded的输入设备的驱动接口实现原理分析

       1Qt3/Embedded把与底层硬件相关的源文件统一放在src/embedded目录下,所以我们最好也把自己的设备驱动接口文件放到此目录。

 

2Qt/Embedded中的输入设备分为鼠标类与键盘类。在3.x版本系列中,鼠标设备的抽象基类为QWSMouseHandler,在src/embedded/qmouse_qws.h中定义,键盘设备的抽象基类为QWSKeyboardHandler,在src/embedded/qkbd_qws.h中定义。对于具体的输入设备我们则从这两个基类重新派生出它的实现类。

 

3、系统加载过程分析。Qt/Embedded在体系上为C/S结构,任何一个Qt/Embedded程序都可以作为系统中唯一的一个GUI Server存在。当应用程序首次以系统GUI Server的方式加载时,将建立QWSServer实体。在系统加载构造QWSServer时,将会调用QWSServer::openMouseQWSServer::openKeyboard函数 (建立QWSServer实体的源文件是src/kernel/qwindowsystem_qws.cpp)。这两个函数分别调用QMouseDriverFactory::create()QKbdDriverFactory::create()函数,它们分别是在src/embedded/qmousedriverfactory_qws.hsrc/embedded/qkbddriverfactory_qws.h中定义。这时会根据嵌入式Linux系统的环境变量QWS_MOUSE_PROTOQWS_KEYBOARD获得鼠标类设备和键盘类设备的设备类型和设备节点。打开相应设备并返回相应设备的基类句柄指针给系统,系统通过将该基类指令强制转换为对应的具体子类设备指针,获得对具体鼠标类设备和键盘类设备的调用操作。也就是说,我们只要把自己的设备类放在create()函数中即可。调用关系如下:

QWSServer::openMouse() à QMouseDriverFactory::create() à MyMouseHandler  QWSMouseHandler

鼠标接口的加载过程

QWSServer::openKeyboard() à QKbdDriverFactory::create() à MyKeyboarddHandler QWSKeyboardHandler

键盘接口的加载过程

 

二、在QTE中实现自己的设备驱动接口

    经过上面的分析可以发现,要在QTE中实现自己的设备接口其实是很容易的事情。下面以键盘接口的实现为例,简单介绍一下具体的实现过程,鼠标接口也是差不多的。

QTE中实现自己的键盘接口只需要三步:

1、从抽象基类QWSKeyboardHandler派生出具体类,如MyKbdHandler。为此我们在QTE的子目录src/embedded中新建两个文件mykbd_qws.hmykbd_qws.cpp,内容如下:

(1) mykbd_qws.h的内容:

#ifndef MYKBD_QWS_H

#define MYKBD_QWS_H

 

#include "qkbd_qws.h"  //QT定义抽象基类QWSKeyboardHandler

 

#ifndef QT_NO_MYKBD   //编译时可以通过定义这个变量从而不编译这个模块

 

class MyKbdPrivate;   //我们的键盘设备私有类,实现具体的键盘设备操作,如打开键盘、读键盘数据,解析按键等等。

 

class MyKbdHandler : public QWSKeyboardHandler //供系统调用的键盘句柄

{

public:

    MyKbdHandler(const QString&);

    virtual ~MyKbdHandler();

private:

    MyKbdPrivate *d;

};

 

#endif // QT_NO_MYKBD

#endif // MYKBD_QWS_H

 

(2)mykbd_qws.cpp的内容:

#include "mykbd_qws.h"

 

#ifndef QT_NO_MYKBD

 

#include sys/types.h

#include sys/stat.h

#include sys/ioctl.h

#include fcntl.h

#include termios.h

#include unistd.h

#include errno.h

 

#include qsocketnotifier.h

 

class MyKbdPrivate : public QObject

{

    Q_OBJECT

public:

    MyKbdPrivate( MyKbdHandler *h, const QString& );

    virtual ~MyKbdPrivate();

 

    bool isOpen() { return buttonFD > 0; }

 

private slots:

    void readKeyboardData();

 

private:

    QString terminalName;

    int buttonFD;

    int kbdIdx;

    int kbdBufferLen;

    unsigned char *kbdBuffer;

    QSocketNotifier *notifier;

    MyKbdHandler *handler;

};

 

MyKbdPrivate::MyKbdPrivate(MyKbdHandler *h, const QString &device ) : handler(h)

{

    terminalName = device.isEmpty()?"/dev/mykeyboard":device.latin1();

    buttonFD = -1;

    notifier = 0;

 

    if ((buttonFD = open(terminalName, O_RDWR | O_NDELAY, 0)) < 0)

    {

        qWarning("Cannot open %s/n", terminalName.latin1());

    }

 

    if ( buttonFD >= 0 ) {

        notifier = new QSocketNotifier( buttonFD, QSocketNotifier::Read, this );

        connect( notifier, SIGNAL(activated(int)),this,

           SLOT(readKeyboardData()) );

    }

 

    kbdBufferLen = 80;

    kbdBuffer = new unsigned char [kbdBufferLen];

    kbdIdx = 0;

}

 

MyKbdPrivate::~ MyKbdPrivate()

{

    if ( buttonFD > 0 ) {

        ::close( buttonFD );

        buttonFD = -1;

    }

    delete notifier;

    notifier = 0;

    delete [] kbdBuffer;

}

 

void MyKbdPrivate::readKeyboardData()

{

int n = 0;

int idx = 0;

    n  = read(buttonFD, kbdBuffer+kbdIdx, 4);

 

    unsigned char *next = kbdBuffer + idx;

    int *code = (int *)next;

    int keycode = Qt::Key_unknown;

 

    switch ( (*code) & 0xff ) {

        case 11:

        keycode = Qt::Key_Backtab;

        break;

        case 12:

        keycode = Qt::Key_Return;

        break;

        case 13:

        keycode = Qt::Key_Tab;

        break;

        case 14:

        keycode = Qt::Key_Up;

        break;

        case 15:

        keycode = Qt::Key_Down;

        break;

 

        default:

qDebug("Unrecognised key code %d", *code );

    }

 

        handler->processKeyEvent( 0, keycode, 0, TRUE, FALSE );

          

}

 

MyKbdHandler::MyKbdHandler(const QString &device)

{

    d = new MyKbdPrivate( this, device );

}

 

MyKbdHandler::~MyKbdHandler()

{

    delete d;

}

 

#include "mykbd_qws.moc"

 

#endif // QT_NO_MYKBD

 

2、把MyKbdHandler加入QkbdDriverFactory::create()函数中。在src/embedded/qkbddriverfactory_qws.cpp文件中加入头文件:

#include “mykbd_qws.h”

然后找到QkbdDriverFactory::create()这个函数,在”Qstring  driver = key.lower();”这一行的后面加上以下几行:

#ifndef QT_NO_MYKBD

      if ( driver == “mykbd” || driver.isEmpty() )

            return new MyKbdHandler( device );

#endif

3、重新编译QT/Embedded并把生成的qt库文件下载到开发板上,然后在目标板上设置系统变量,输入命令:export  QWS_KEYBOARD=’MYKBD:/dev/mykeyboard’

至此 QT3/Embedded 的键盘设备接口已经完成。