Best practices for building Qt applications with OpenEmbedded

Posted by Cliff Brake on 2009-08-06 | 16 Comments to Read

This article describes how to cross compile a Qt application (named qt_tutorial) with OpenEmbedded, and several best practices you should consider.  OpenEmbedded currently includes fairly good support for building Qt — both Qt Embedded and Qt X11.   OE also includes a number of qt classes that make building Qt applications easy.  One of the main considerations with embedded Linux application development is that you keep the build system flexible so that you can easily build on a PC or for your embedded hardware.  This means that hand crafted Makefiles with hardcoded paths to cross compilers do not quality.

Put Your Application in a SCM system

No matter what type of application you are building, it is a good idea to put your source in a SCM or revision control system and fetch it directly using OE.  OpenEmbedded supports fetching sources from a number of revision control systems including Subversion, Git, Bazaar, Mercurial, CVS, etc.   The not so obvious reason we do this is so you can easily check out the source code and build it on a PC as well as your target system in OE.  In this example we fetch the application source from a SVN repository:

SRC_URI = "svn://dev.bec-systems.com/svn/pub;module=qt_tutorial;proto=http"

For the above repository, the direct URI to the source would be: http://dev.bec-systems.com/svn/pub/qt_tutorial/

Put the Install logic in the Application Source

Most Linux applications support “make install”, and this is the case with autotools, and qmake (Qt’s build tool).  We could put logic in the OE recipe to install the application something like the following:

do_install() {
	install -d ${D}/${bindir}
	install -m 0755  ${S}/qt_tutorial ${D}/${bindir}
}

But, the problem with this approach is you can’t install the application in other environments (like a native x86 PC build) unless you are building with OE.  So a better approach is to put the logic to install the application in the application source, so that in can be installed in both your PC environment, and your OpenEmbedded build.  To accomplish this, you can set up the project as follows

application qmake project file (qt_tutorial.pro):

TEMPLATE = app
TARGET = qt_tutorial
DEPENDPATH += .
INCLUDEPATH += .

# Input
HEADERS += lcdrange.h
SOURCES += lcdrange.cpp main.cpp

target.path = /usr/bin
INSTALLS += target

OpenEmbedded recipe (qt-tutorial_svn.bb):

inherit qt4e

SRCREV = "${AUTOREV}"
PV = "1.0+svnr${SRCREV}"
PR = "r1"

SRC_URI = "svn://dev.bec-systems.com/svn/pub;module=qt_tutorial;proto=http"

S = ${WORKDIR}/qt_tutorial

FILES_${PN}-dbg += "${bindir}/.debug"

do_install() {
	export INSTALL_ROOT=${D}
	make install
}

Now, the same mechanism is used to install the application on both a PC native build, as well an OpenEmbedded build.  If you look in the Makefile generated by qmake, you see the following:

install_target: first FORCE
	@$(CHK_DIR_EXISTS) $(INSTALL_ROOT)/usr/bin/ || $(MKDIR) $(INSTALL_ROOT)/usr/bin/
	-$(INSTALL_PROGRAM) "$(QMAKE_TARGET)" "$(INSTALL_ROOT)/usr/bin/$(QMAKE_TARGET)"

install:  install_target  FORCE

INSTALL_ROOT can be set to force the entire system to be installed in a subdirectory.  This is required for build systems that generate packages, like OpenEmbedded.  To build this example, put the qt-tutorial_svn.bb file in your OE recipes tree, and run: bitbake qt-tutorial.  This will fetch the source code and build a package.  To run the tutorial, install the package on a system that includes Qt Embedded, and then run: qt_tutorial -qws.

  • zecke said,

    Great!

  • Caner said,

    Hi,
    Good tutorial. However, I missed the steps of qmake and make. I mean, considering this recipe, where and how does bitbake run qmake and make?
    As the final question, what are the differences in the case of Qt3?

    Thanks for the tutorial.
    Regards,

  • Cliff Brake said,

    “inherit qt4e” causes qmake and make to run automatically.

    I started with Qt4, so I’m not sure about Qt3.

  • Caner said,

    Hi Cliff,
    Thanks for the answer. Though I couldn’t yet succeed, I’m newbie at OE.
    When I run bitbake qt_tutorial, I get this error:

    ERROR: Nothing PROVIDES ‘qt_tutorial’

    I’ve tried to access the svn server with TortoiseSVN to be sure whether there’s no problem at the connection. But the server did not respond.
    Then I’ve set SRC_URI as:
    SRC_URI = “http://dev.bec-systems.com/svn/pub/qt_tutorial/;proto=http”
    and as another case I tried:
    SRC_URI = “http://dev.bec-systems.com/svn/pub/qt_tutorial/;module=qt_tutorial;proto=http”
    Both cases have come up with the same error given above.
    Finally, I created a “files/” directory and put all the source with .pro file inside. I’ve changed SRC_URI as:
    SRC_URI = ” \
    file://cannonfield.h \
    file://cannonfield.cpp \
    file://gameboard.h \
    file://gameboard.cpp \
    file://lcdrange.h \
    file://lcdrange.cpp \
    file://main.cpp \
    file://qt_tutorial.pro \

    I’ve also excluded SRCREV and PV lines to get rid of a parse error. And again, I’ve got the same error.

    Any suggest would be highly appreciated.
    Thanks again.

  • Cliff Brake said,

    The tortoisesvn URI would be: http://dev.bec-systems.com/svn/pub/qt_tutorial

    try it in a web browser to make sure it works.

    The problem with your recipe is the name. The ‘_’ is used to separate PN (package name) from PV (package version). Try the recipe name: qt-tutorial_svn.bb, and it will work.

  • Caner said,

    Hi Cliff,
    It worked. Well, since this is the first qt4 application I compiled on OE, first qt-embedded libraries are compiled.
    After the compilation, I transferred the package to target machine which is BeagleBoard. Now the problem is that the qt-tutorial requires qt libraries of version 4.4.3, but in the target machine libraries of version 4.4.1 are installed. Anyway, thanks for all helps. And again, great tutorial.

    Regards,

  • favor said,

    nice tutorial, and it’s helpful ;)

    thanks

  • favor said,

    hi, Cliff

    thank for your tutorial.
    I remain to have one question about this tutorial. what’s the difference between this:
    do_install() {
    install -d ${D}/${bindir}
    install -m 0755 ${S}/qt_tutorial ${D}/${bindir}
    }
    and this:
    do_install() {
    export INSTALL_ROOT=${D}
    make install
    }

    don’t they both set the installed directory as $(D)?

  • Cliff Brake said,

    From an OE perspective you are correct. The advantage of the INSTALL_ROOT mechanism is the application has knowledge of how to install itself, so if you were to package the application using Debian, or Suse, then the install part would be mostly done. For a simple application this is not a big deal, but for complex applications that install dozens of files, you don’t really want to code the install logic in every distribution build system. For many embedded applications this does not really matter, but I think its always a good idea to use best practices where possible as projects often grow beyond the original scope.

    I think it might eventually make sense to put the do_install logic in the qt4e class as it should be common with most Qt apps (similar to the autotools class), but I’ve not looked into this yet.

  • Best practices for building Gtk+ applications with OpenEmbedded » BEC Systems said,

    [...] recently wrote an article about best practices building Qt applications with OpenEmbedded, and it occured to me that I should write an equivalent article for Gtk+ applications.  The same [...]

  • Erik said,

    This is a lot of good information, but it seems I am having a bit of a problem here. Here is what I have:
    I have a quadrobot directory that contains my quadrobot_0.1.bb file and a source directory. Within the source directory are my source files.

    The BB is as follows:
    inherit qt4e
    DESCRIPTION = “My Program”
    PR = “r1″
    S = “${WORKDIR}/${P}”

    SRC_URI=”\source://mainwindow.h \source://mainwindow.cpp \source://main.cpp \source://QuadrobotV0.pro;proto=file”

    do_install () {
    export INSTALL_ROOT=${D}
    make install
    }

  • Cliff Brake said,

    Hello Erik, you are probably better off using the srctree mechanism if you want to build a source code tree in place with OE. See http://cgit.bec-systems.com/cgit.cgi/qt-overo-palo-gpio/tree/ as an example of using this mechanism.

  • Ivan Jäger said,

    Great. It worked excellent!

    Fetching the project from my own svn-server was the easiest way.

    I only had to change proto=http to proto=svn

    Thank you very much.

  • Sean_h said,

    Hi Cliff

    Thanks for sharing your knowledge, again. Your guides really help.

    Thanks
    Sean

  • Donald Poole said,

    Hi Cliff

    Great bit of information on building Qt application with openembedded. I’m doing something similar, but instead of and application I’m creating a library. My recipe successfully bakes, but I noticed that there are not any files deployed under my tmp/work/armv7a-angstrom-linux-gnueabi//packages-split packages directory. Here is my recipe (I had to remove the repository location and name for non-disclosure reasons):

    inherit qt4e

    MODULE = “MyMercurialRepoModule”

    REF_VER ?= “1.1″
    SRCREV ?= “default”

    PV = “${REF_VER}+${PR}+hg${SRCREV}”
    PR = “r0″

    S = “${WORKDIR}/${MODULE}”

    do_fetch() {
    cd ${WORKDIR}
    if [ ! -e ${MODULE} ]; then
    hg clone https://mymercurialrepo.org/hg/${MODULE}
    fi
    }

    do_install() {
    # Install the libary into the destination
    export INSTALL_ROOT=${D}
    make ${PARALLEL_MAKE} install

    # Install the headers into staging
    install -m 0755 -d ${STAGING_INCDIR}/VICTORY
    install -m 0644 ${INSTALL_ROOT}${prefix}/local/include/VICTORY/* ${STAGING_INCDIR}/VICTORY

    # Install the libraries into staging
    oe_libinstall -so lib${MODULE} ${STAGING_LIBDIR}
    oe_libinstall -so lib${MODULE}_debug ${STAGING_LIBDIR}
    }

    FILES_${PN} += “${libdir}/lib${MODULE}.so.*”
    FILES_${PN}-dbg += “${libdir}/lib{MODULE}_debug.so.*”
    FILES_${PN}-dev += “${includedir}/*”

    Could you give any insight as to why this recipe wouldn’t populate the packages folders?

    Thanks,
    Donald

  • Suman Gupta said,

    Hi Cliff,
    Thanks for the valuable info you have provided.I was working with the qt4-embedded_4.7.2.bb recipe file.More interested in changing the configuration in such a way that few libraries and executables do not get added in the root file system.These are the list of libraries and executables(in the format of .ipk files) :

    Libs:

    libphonone4_4.7.2-r34.14-arago8.6_armv7a.ipk
    libqtclucenee4_4.7.2-r34.14-arago8.6_armv7a.ipk
    libqtdesignercomponentse4_4.7.2-r34.14-arago8.6_armv7a.ipk
    libqtdesignere4_4.7.2-r34.14-arago8.6_armv7a.ipk
    libqthelpe4_4.7.2-r34.14-arago8.6_armv7a.ipk
    libqtteste4_4.7.2-r34.14-arago8.6_armv7a.ipk
    libqtwebkite4_4.7.2-r34.14-arago8.6_armv7a.ipk

    executables:

    qt4-embedded-assistant_4.7.2-r34.14-arago8.6_armv7a.ipk
    qt4-embedded-demos_4.7.2-r34.14-arago8.6_armv7a.ipk
    qt4-embedded-designer_4.7.2-r34.14-arago8.6_armv7a.ipk
    qt4-embedded-pixeltool_4.7.2-r34.14-arago8.6_armv7a.ipk
    qt4-embedded-plugin-phonon-backend-gstreamer_4.7.2-r34.14-arago8.6_armv7a.ipk
    qt4-embedded-qmlimports-webkit_4.7.2-r34.14-arago8.6_armv7a.ipk
    qt4-embedded-qt3to4_4.7.2-r34.14-arago8.6_armv7a.ipk
    qt4-embedded-tools_4.7.2-r34.14-arago8.6_armv7a.ipk

    I am not that much familiar with the bitbake recipe.I was not able to configure where to make changes in the qt4-embedded_4.7.2.bb(which internally calls qt4-embedded.inc & qt4.inc) so that the above lists don’t get included into the root file system.Any suggestion from your side would be helpful.

    with regards,
    Suman