Best practices for building Qt applications with OpenEmbedded

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.