Next Previous Contents

12. Example program development

This chapter is made out of my "LinuxEmbeddeJournal" article, written a in December 2001. It contains three example programs, which describe, howto develop for the iPaq.

12.1 "Hello World" for the teminal

Until now, there were only boring preparations. Now we come to the goal of this article, your first iPAQ program.

Create a directory for your new project which name is ipaq1. Enter this directory and edit a small main.cpp.

        #include <stdio.h>
        int main( int argc, char* argv[] )
        {
          printf ("Hello nice iPAQ World\n" );
          exit(0);
        }
        

Compile it for X to try it out. A "gcc -o ipaq1 main.cpp" will create an executable. Start it to check, if it works.

To create the iPAQ binary enter "qtarm" and type "arm-linux-gcc -o ipaq1a main.cpp". Transfer the result to the iPAQ using "ssh ipaq1a root@ipaq:/root", login to the iPAQ as root and start "./ipaq1a". Congratulations, your first program is running.

12.2 Example "Hello World" for QPE/OPIE

To generate a QPE (or OPIE) program, you have to do a little bit more. We want to create an application showing a textline with a "HelloWorld" text and a quit-button.

You can start as usual with QT. You need a main.cpp creating the QT-Application, a hwedit.cpp (and.h) as the center class and a hweditdlg.ui file generated using QT-Designer as a user-interface (choose a widget as the template).

The main.cpp will be written for X11 and embedded use. Line 2 includes qpeapplication.h which is used for QT-Embedded, while line 4 is used for X11 use. The precompiler switch "QWS" is set as a compiler-switch. Line 7 includes the MainWidget class hwedit.h. In line 11-15 a QT application is created (dependent on QWS). Line 17 creates the central Widget, which is declared as the MainWidget in line 18 and shown in line 19. Line 21 hands over the program control to the eventqueue of the program.

        1 #ifdef QWS
        2 #include <qpeapplication.h>
        3 #else
        4 #include <qapplication.h>
        5 #endif
        6
        7 #include "hwedit.h"
        8
        9 int main(int argc, char *argv[])
        10 {
        11 #ifdef QWS
        12   QPEApplication a ( argc, argv );
        13 #else
        14   QApplication a ( argc, argv );
        15 #endif
        16
        17   HWEdit *hwedit = new HWEdit();
        18   a.setMainWidget(hwedit);
        19   hwedit->show();
        20
        21   return a.exec();
        22 }
        

The hwedit.h defines the main class HWEdit. This class inherits the QT-Designer dialog (headerfile hweditdlg.h, Class HWEditDlg) (line 9 + 11). Line 18 defines the slot, that is called, when the button is pressed.

        1 #ifndef HWEDIT_H
        2 #define HWEDIT_H
        3
        4 #ifdef QWS
        5 #include <qpeapplication.h>
        6 #else
        7 #include <qapplication.h>
        8 #endif
        9 #include <hweditdlg.h>
        10
        11 class HWEdit : public HWEditDlg
        12 {
        13   Q_OBJECT
        14   public:
        15     HWEdit( QWidget* parent=0, const char *name=0 );
        16    ~HWEdit();
        17  private slots:
        18     void slotQuit();
        19 };
        20 #endif
        

The hwedit.cpp is the constructor for the class HWEdit. The slot "slotQuit()" only calls the function qApp->quit(), which quits the program (qApp is a global pointer and points to the running application). Line 5 sets our text into the LineEdit (which is called "LineEdit" in the QT-Designer file). Line 7 and 8 sets the applications size, when QWS is defined. On the iPAQ you should not use larger applications, than the screen. Also the virtual keyboard has to be calculated to use some size.

        0 #include "qlineedit.h"
        1 #include "hwedit.h"
        2
        3 HWEdit::HWEdit(QWidget *parent, const char *name) : HWEditDlg(parent, name)
        4 {
        5    LineEdit->setText( "Hello nice iPAQ world" );
        6 #ifdef QWS
        7   setMaximumSize( 240, 280 );
        8   showMaximized();
        9 #endif
        10 }
        11
        12 HWEdit::~HWEdit()
        13 {
        14 }
        15
        16 void HWEdit::slotQuit()
        17 {
        18    qApp->quit();
        19 }
        

Now you can start the QT-Designer and prepare a Widget with the Button and the LineEdit class. Connect the Button to slotQuit() and save the program. Name the MainWidget "HWEditDlg" (the class-name) and the LineEdit field just "LineEdit". The button is labeled "&Quit()" which causes the "Q" to be an acceleration key. Of course the program should not extend the iPAQs maximum screen size (320x240 Pixel). You can resize it inside of the HWEdit class-definition later.

Now we have to create a makefile. You will find some of the Environment variables used in the makefile. This helps to use the same makefile for different compilation targets. Line 1-14 define the different used parameters. Line 18-20 define the linking process, while line 22-40 define the compilation of the different modules. Line 42-46 do the uic compilation as well as the moc compilation. UIC builds a header and a cpp file out of the QT-Designer file (*.ui). The lines 57-59 strip the resulting program.

        1 CC = $(CCX)            # Compiler
        2 CFLAGS = -c -Wall -fPIC $(OPTIONS)
        3 LD = $(CXXX)           # Linker
        4 LDFLAGS = -L$(QTDIR)/lib -L$(KERNEL_PATH)/lib
        5 MOCC = $(QTDIR)/bin/moc
        6 UICC = $(QTDIR)/bin/uic
        7
        8 IPATH    = -I $(PWD) \
        9       -I $(KERNEL_PATH)/include \
        10      -I $(QTDIR)/include $(EXTRAINC)
        11
        12 XTRALIB  = $(XT_LIB)
        13
        14 STRIP = $(STRIP_PROG)
        15
        16 all : hwedit
        17
        18 hwedit : main.o      hwedit.o domoc hwedit_moc.o hweditdlg_moc.o hweditdlg.o
        19      @echo "linking hwedit ..."
        20      ${LD} ${LDFLAGS} ${XTRALIB} -o hwedit main.o hwedit.o hwedit_moc.o hweditdlg_moc.o hweditdlg.o
        21
        22 main.o : main.cpp
        23      @echo "compiling main"
        24      ${CC} -posix ${IPATH} ${CFLAGS} main.cpp
        25
        26 hwedit.o : hwedit.cpp
        27      @echo "compiling hwedit"
        28      ${CC} -posix ${IPATH} ${CFLAGS} hwedit.cpp
        29
        30 hwedit_moc.o : hwedit_moc.cpp
        31      @echo "compiling hwedit_moc"
        32      ${CC} -posix ${IPATH} ${CFLAGS} hwedit_moc.cpp
        33
        34 hweditdlg_moc.o : hweditdlg_moc.cpp
        35      @echo "compiling hweditdlg_moc"
        36      ${CC} -posix ${IPATH} ${CFLAGS} hweditdlg_moc.cpp
        37
        38 hweditdlg.o : hweditdlg.cpp
        39      @echo "compiling hweditdlg"
        40      ${CC} -posix ${IPATH} ${CFLAGS} hweditdlg.cpp
        41
        42 domoc :
        43      ${UICC} -o hweditdlg.h hweditdlg.ui
        44      ${UICC} -i hweditdlg.h hweditdlg.ui > hweditdlg.cpp
        45      ${MOCC} -o hweditdlg_moc.cpp hweditdlg.h
        46      ${MOCC} -o hwedit_moc.cpp hwedit.h
        47
        48 clean :
        49      @echo "Loesche folgende Dateien"
        50      @echo "  " *.o
        51      /bin/rm -f *.o
        52      /bin/rm -f *.so
        53      /bin/rm -f *_moc*
        54      /bin/rm -f *dlg.h
        55      /bin/rm -f *dlg.cpp
        56
        57 strip :
        58      @echo "Stripping hwedit"
        59      ${STRIP} hwedit
        

To build a X11 version enter "qtx11" and type "make clean all". The result is a program running under X11. You will see a Widget containing a LineEdit with the text "Hello nice iPAQ World" and a button "Quit". By pressing the button, the application quits.

To build an embedded version just enter "qtemb" and do a "make clean all". If you start your QVFB (/usr/lib/qt2/tools/qvfb/qvfb -depth 16 &), a call to "./hwedit" will show the result in the frambuffer window.

To build an iPAQ version just enter "qtarm" and do a "make clean all strip". Transfer the result to the iPAQ (scp hwedit root@iPAQ:/root). Login the iPAQ as root and enter "hwedit". The program will start on the iPAQ.

Congratulations!! Your first iPAQ program is working.

12.3 Using kdevelop

Manual makefile definitions maybe very boring, especially when developing more complex programs. It makes sense to use an integrated development kit also for the QPE development.

Since kdevelop 1.4 (I use kde as my standard desktop) there is a patch available for the admin dir to use the development kit also for QT-embedded programs (incl. crosscompilation). This patch still needs some manual manipulations, but works fine :) and makes programmers live easy.

The patchfile can be downloaded from my homepage (admin.tar.gz). The tarball includes either a patch-script for the m4 file in the admin dir as well as the comlete (patched) admin dir of kdevelop 1.4.

In kdevelop 2.0 it is also working well until you use the right autoconf program. For future versions of kdevelop, the crosscompilation possiblilty will be integrated into the kdevelop user interface, so the "manual" manipulations will not any more necessary.

Create a new project using kdevelop. Choose the kde-mini template not to make a too large application. Name it "hwedit". The project creates three files in its source directory. This files are named main.cpp, hwedit.h and hwedit.cpp. Delete all infos from the created source and header files and copy the code form the above example into the files.

Create a new "hweditdlg.ui" file using QT-Designer (choose "file->new file" and the ".ui" extension). or just add the existing one to your project using "project->add existing Files".

Enter the menu "project->options" and disable the extra libraries kdeui and kdecore. Edit the Makefile.am in your source dir and add a line at the end containing "KDE_OPTIONS=qtonly" Install the admin-patch. Either patch your admin dir or just remove it and extract the admin.tar.gz archive in your project directory. Choose (one after the other) "build->distclean", "build->automake", "build->configure" to create new makefiles.

Compile and start your program for X11 use pressing "F9".

Now its time to prepare the crosscompilation. Start a terminal and enter your project directory. Create the directories "x11", "emb", "arm" and create a file called "mkcfg.rc" in each of this directories containing the following lines.

For x11 ...

        #!/bin/sh
        ../configure --with-qt-dir=$QTDIR
        

For embedded ...

        #!/bin/sh
        ../configure --with-qt-dir=$QTDIR --prefix=$QPEDIR \
        --with-extra-includes=$QPEDIR/library --enable-embedded
        

For arm ...

        #!/bin/sh
        ../configure --with-qt-dir=$QTDIR --prefix=$QPEDIR \
        --with-extra-includes=$QPEDIR/library \
        --enable-embedded --target=arm-linux
        For x11 ...
        #!/bin/sh
        ../configure --with-qt-dir=$QTDIR
        

Change the accessability using chmod 555 mk*rc.

Enter the directory x11 and enter "qtx11" followed by "./mkcfg.rc;make clean all" to recreate your x11-Version. You find the result in <project>/x11/hwedit. Leave the x11 environment with "exit".

Copy the Makefile.am of your source directory to Makefile.am.x11 for x11 compilations. Change the Makefile.am again. Search the line starting with "hwedit_LDADD". Copy that line and comment the original. Append "-lqpe" to the line. Search the line starting with INCLUDES. Copy that line and comment the original. Append "-I$(QPEDIR)/library" to the line. Copy that modified Makefile.am to Makefile.am.emb for emb/arm compilations.

In your project directory enter "make distclean; make -f Makefile.dist". Enter the directory emb and type "qtemb" followed by "./mkcfg.rc;make clean all" to create your first embedded-version. You find the result in <project>/emb/hwedit. Leave the env environment with "exit".

Enter the directory arm and type "qtarm" followed by "./mkcfg.rc;make clean all" to create your arm-version. You find the result in <project>/arm/hwedit. Leave the env environment with "exit".

To work with your new project, you can use kdevelop for editing the files. To compile the emb- and arm-versions you have to save all files, enter the emb/arm directory change into the qtemb- or qtarm-mode and just call "make all". The system will compile the changed sources for the required platform.

Unfortunatly, the QPE requires the extra QPE library (and includes). For this you created the two "Makefile.am" in your source directory. In case of switching back to x11, you have to copy the "Makefile.am.x11" back to "Makefile.am", before compilation. Do the same with the "Makefile.am" when switching to emb/arm.

If there are new files to be added, do that first using the integrated kdevelop tools. After rearranging everything, you may have to edit the "Makefile.am" again. In this case follow the steps described above.

Multiple congratulations!! You managed it to create an iPAQ program using an integrated development tool.

Nothing is in the way any more to get your program ideas included into the QPE desktop. Do it and share it with all the other iPAQ users running Linux.

12.4 Program integration into QPE/OPIE

The final step to do is to integrate your new program into the QPE desktop.

To do this, just copy your binary into the "/opt/QtPalmtop/bin" dir on your handheld. Add a related pixmap into the "/opt/QtPalmtop/pics" dir and create a "/opt/QtPalmtop/apps/Applications/hwedit.desktop" file (just copy and modify) like this.

        [Desktop Entry]
        Comment=A test program for QPE development
        Exec=hwedit
        Icon=HwEdit
        Type=Application
        MimeType=text/*
        Name=Hello World
        

Restart either your QPE-Server or your handheld. You should find the programs icon on your applications page. Select it with the stylus and it will start.


Next Previous Contents