Donald Carr
OpenGL
Embedded
Build system
Posted by Donald Carr
 in OpenGL, Embedded, Build system
 on Friday, February 05, 2010 @ 10:49

Requirements

1) Tegra 2 platform
2) The latest Nvidia Tegra2 SDK (11.0074_devlite_eula_Beta-RC.zip at this time)

Board bring up

Nvidia have done a pretty good job in documenting bring up and I will not
paraphrase them. I personally used their dev environment exactly as
intended (answering every question posed during installation with an
affirmative), so my dev machine became a DHCP/NFS server serving out on a
secondary network interface. Be sure to select an X enabled SDK during installation as we
currently don’t work out of the box with their OpenKode drivers.

Their supplied documentation (in chm format) is thorough and documents
flashing the latest bootloader to the device (amongst other things) which I would
recommended on every update, to ensure targetfs/bootloader compatibility.

Initial rootfs adjustment/configuration

Once you have installed both packages included in
11.0074_devlite_eula_Beta-RC.zip you should have 2 dirs:

emPower-devlite-p1138
toolchains

Go into:

./emPower-devlite-p1138

cp -r include/* targetfs/usr/include
cp -r lib-target/* targetfs/usr/lib

your targetfs is now primed for GL compilation. You will need to boot your
target prior to proceeding though, as on first boot a host of packages
are installed into the targetfs including all the X11 headers required to
compile Qt/X11.

Additional headers (dbus, glib, freetype, gstreamer) might be
required for a full featured Qt build, but the packages installed on first
boot will suffice for a OpenGL ES 2 enabled Qt/X11 build with all of Qt’s
core functionality.

Go to town with apt-get according to your needs
(apt-get build-dep libqt4-gui unfortunately fails due to unmet
dependencies) and please be aware of the fact that the chm documentation
covers forwarding net traffic between your Tegra2 target and the external
world via your host machine.

Once this is done, we are ready to build qt.

Configuring build environment

I use Scratchbox 2 for reasons qualified in the appendix.

1) Change to your targetfs directory (cd $NV_ROOT/emPower-devlite-p1138/targetfs)

2) Run:

sb2-init -c /usr/bin/qemu-arm $SB2-TARGETNAME $NV_ROOT/toolchains/tegra2-4.3.2-nv/bin/arm-none-linux-gnueabi-gcc

within this directory, where:

$SB2-TARGETNAME is a suitable name for your target’s scratchbox environment
$NV_ROOT is where you unpacked the archive

You now have a sane scratchbox 2 env when you can compile Qt/X11. If you
were to enter the scratchbox env and build Qt now, it would get through
every module up until QtOpenGL was reached, at which point you would
witness spaghetti breakage referencing the inclusion of the qdebug/text
streaming classes.

This is because

targetfs/usr/include/EGL/eglplatform.h

includes several X11 headers:

Xlib.h
Xutil.h

as it explicitly references native X11 types. I initially tried to move
these headers out of this header file, but the path of least resistance
ended up being the undefining of conflicting defines at the end of the
eglplatform.h header file.

I introduced the following 4 lines:

#undef None
#undef Status
#undef Unsorted
#undef GrayScale

immediately prior to the final #endif in this file. I know this is dirty,
but it circumvents the point of breakage and resolves all remaining build failures.

Having done this, we are ready to build Qt/X11.

Building Qt

1) Enter scratchbox 2 with: sb2 -t $SB2-TARGETNAME
2) Enter your Qt directory
3) Configure Qt with (at a minimum):
./configure -xplatform linux-g++ -platform linux-host-g++ -opengl es2 -force-pkg-config ..
(The utilized mkspecs are discussed in the Appendix)
4) Check the output of configure to verify OpenGL ES2 (and any other
functionality you wish to build) has been correctly detected and enabled by
the configure tests.
5) run “make” (Qt should build through to completion)
6) “make install” Qt to its prefix path on the host (if necessary)
7) Use Qt to compile any appropriate Qt applications within the
scratchbox env
8 ) Deploy Qt to its prefix path (on the target) with any desired
applications

When you boot your Tegra2 platform, start X and launch your
OpenGL ES2 enabled Qt application (Either GLES2 content directly
in QGLWidget ala hellogl_es2, a QGLWidget fronted QGraphicsView
or via explicit use of the OpenGL ES2 graphics system), everything
should simply work to a greater or lesser extent and work at pace
at that.

We have not done any profiling of Qt on the Tegra2
hardware in order to quantify where we are today, nor any
dedicated integration in order to be maximize our use of the
underlying hardware but the baseline performance is very solid.

Appendix

mkspec information

linux-g++

the generic linux X11 mkspec, which behind the curtains of scratchbox
is mapped to the (environment creation time) specified cross compiler.

linux-host-g++

a modification of the generic linux X11 mkspec, which maps to the host machines compiler. This
mkspec is already present in the Qt maemo5 branch on our git repository. This
mkspec is basically a modification of linux-g++, with “host-” prefixed on
all the compiler variables. (included from ../common/g++.conf) The only
noteworthy thing about this mkspec is that instead of including
“../common/g++.conf” and modifying select variables accordingly, the
complete include is inlined. This is due to a known issue where overriding
QMAKE_CXX variables in not respected during the qmake boot strapping
process.

The linux-host-g++ mkspec looks roughly like this:

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

#
# qmake configuration for linux-g++
#

MAKEFILE_GENERATOR = UNIX
TEMPLATE = app
CONFIG += qt warn_on release incremental link_prl
QT += core gui
QMAKE_INCREMENTAL_STYLE = sublib

#
# qmake configuration for common gcc
#

#inlined ../common/g++.conf follows

QMAKE_CC = host-gcc
QMAKE_CFLAGS += -pipe
QMAKE_CFLAGS_DEPS += -M
QMAKE_CFLAGS_WARN_ON += -Wall -W
QMAKE_CFLAGS_WARN_OFF += -w
QMAKE_CFLAGS_RELEASE += -O2
QMAKE_CFLAGS_DEBUG += -g
QMAKE_CFLAGS_SHLIB += -fPIC
QMAKE_CFLAGS_STATIC_LIB += -fPIC
QMAKE_CFLAGS_YACC += -Wno-unused -Wno-parentheses
QMAKE_CFLAGS_HIDESYMS += -fvisibility=hidden
QMAKE_CFLAGS_PRECOMPILE += -x c-header -c ${QMAKE_PCH_INPUT} -o ${QMAKE_PCH_OUTPUT}
QMAKE_CFLAGS_USE_PRECOMPILE += -include ${QMAKE_PCH_OUTPUT_BASE}

QMAKE_CXX = host-g++
QMAKE_CXXFLAGS += $$QMAKE_CFLAGS
QMAKE_CXXFLAGS_DEPS += $$QMAKE_CFLAGS_DEPS
QMAKE_CXXFLAGS_WARN_ON += $$QMAKE_CFLAGS_WARN_ON
QMAKE_CXXFLAGS_WARN_OFF += $$QMAKE_CFLAGS_WARN_OFF
QMAKE_CXXFLAGS_RELEASE += $$QMAKE_CFLAGS_RELEASE
QMAKE_CXXFLAGS_DEBUG += $$QMAKE_CFLAGS_DEBUG
QMAKE_CXXFLAGS_SHLIB += $$QMAKE_CFLAGS_SHLIB
QMAKE_CXXFLAGS_STATIC_LIB += $$QMAKE_CFLAGS_STATIC_LIB
QMAKE_CXXFLAGS_YACC += $$QMAKE_CFLAGS_YACC
QMAKE_CXXFLAGS_HIDESYMS += $$QMAKE_CFLAGS_HIDESYMS -fvisibility-inlines-hidden
QMAKE_CXXFLAGS_PRECOMPILE += -x c++-header -c ${QMAKE_PCH_INPUT} -o ${QMAKE_PCH_OUTPUT}
QMAKE_CXXFLAGS_USE_PRECOMPILE = $$QMAKE_CFLAGS_USE_PRECOMPILE

QMAKE_LINK = host-g++
QMAKE_LINK_SHLIB = host-g++
QMAKE_LINK_C = host-gcc
QMAKE_LINK_C_SHLIB = host-gcc
QMAKE_LFLAGS +=
QMAKE_LFLAGS_RELEASE += -Wl,-O1
QMAKE_LFLAGS_DEBUG +=
QMAKE_LFLAGS_APP +=
QMAKE_LFLAGS_SHLIB += -shared
QMAKE_LFLAGS_PLUGIN += $$QMAKE_LFLAGS_SHLIB
QMAKE_LFLAGS_SONAME += -Wl,-soname,
QMAKE_LFLAGS_THREAD +=
QMAKE_LFLAGS_NOUNDEF += -Wl,–no-undefined
QMAKE_RPATH = -Wl,-rpath,

QMAKE_PCH_OUTPUT_EXT = .gch

# -Bsymbolic-functions (ld) support
QMAKE_LFLAGS_BSYMBOLIC_FUNC = -Wl,-Bsymbolic-functions
QMAKE_LFLAGS_DYNAMIC_LIST = -Wl,–dynamic-list,

include(../common/linux.conf)

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

Scratchbox

I personally use Scratchbox 2 rather than Scratchbox 1 since I use a 64 bit
distro, and Scratchbox 2 exists in the Ubuntu repositories.

http://packages.ubuntu.com/search?keywords=scratchbox&searchon=names&suite=karmic&section=all

You might get equally good mileage with Scratchbox 1, or entirely without
Scratchbox. I personally opt for the path of least resistance, and this blog is a cart
following that path.

Arguments in favour of Scratchbox

1) pkg-config in Ubuntu 9.10 does not support prefixes (sysroot) correctly,
so you have to directly modify the .pc files or build pkg-config yourself
2) The Nvidia targetfs/usr/lib entries often have fully qualified symlinks which link
into your host machines libs without a chroot safety net
3) There were some toolchain/targetfs anomalies which simply vanished when adopting this build approach

Known issues

1)The aforementioned qmake bootstrapping issue preventing QMAKE_CXX being over ridden in linux-host-g++
2) 16 bit X is the only environment tested and known to work. Qt GLES2 applications currently segfault
on launch under a 24 bit X session. I am busy investigating this issue. Please ensure that your xorg.conf file is using
16 bit as the default/selected color depth if you intend to run Qt apps.
3) libEGL.so prints a spurious error message:

“”Couldn’t load implementation for OpenGL_ES”

due to the absence of an libGLES(1).so which, it appears, can be safely ignored

Donald Carr
Qt
Graphics View
Painting
OpenGL
Performance
Embedded
Build system
Posted by Donald Carr
 in Qt, Graphics View, Painting, OpenGL, Performance, Embedded, Build system
 on Friday, November 20, 2009 @ 00:53

Introduction

Texas Instruments has a wiki which documents what is required to bring Qt
up on the Beagle board with full OpenGL ES (1/2) support:

http://www.tiexpressdsp.com/index.php/Building_Qt

and I would like to thank one of their engineers, Varun, for his quick turn
around times in addressing any questions I raised.

This blog entry is intended to serve a similar purpose, but is more verbose regarding
Qt considerations and the initial beagle board bring up. It attempts to serve
as a comprehensive independent source of information on getting Qt built
for the Beagle board with full OpenGL ES 2 support.

These instructions are intended for use with Qt 4.6 (and beyond), so grab
the release candidate or check Qt 4.6 out from the public git repository prior
to proceeding.

You can choose to use either Qt/Embedded or Qt/X11, both can
be successfully integrated with the Beagle board’s SGX GPU and the only
point of divergence in these instructions will be at (Qt) configure time
and the client side system (run time) configuration. Both implementations
offer window management, via QWS and X11 respectively, and operate at
around 27fps and 22fps respectively when running our hellogl_es2 example.
(16bit color depth at 1280×720)

I personally deploy Ångström on my Beagle board, it handles a large amount
of the logistics surrounding cross compilation and is generally very
agreeable, and these instructions are therefore going to be bolted to
Ångström for completeness. Feel free to establish an environment capable of
showing the OpenGL ES examples TI provide, then following the Qt level
considerations (Configuring Qt) accordingly.

For those holding a dormant Beagle board who are open to the author’s
distribution preferences:

Building the Ångström rootfs

Open Embedded is manifested in a git repository: in this posting we are
working within origin/stable/2009. Please follow the instructions give
here, they are comprehensive and got me completely off the ground.

http://www.angstrom-distribution.org/building-angstrom

These instructions end in you running:

bitbake base-image ; bitbake console-image ; bitbake x11-image

which actually builds an X11 angstrom image for your Beagle board. Please
note, you will need to build the X11-image if you want to build and deploy
the SGX packages (we will do this in the next section) via Ångström as opkg considers
X11 to be a required dependency of libgles-omap3_3.00.00.09. This is due
to one of the encapsulated windowing system libraries being X11 centric:

libpvrPVR2D_X11WSEGL.so

Regardless of the indicated X11 dependency, this package will bestow the required
kernel module on you for general OpenGL ES usage (console or X11). We will be
building our own QWS centric (libpvrPVR2D_X11WSEGL.so equivalent) library
behind the scenes for QWS in the Qt/Embedded instructions given later.

Ångström SGX integration

You now need to integrate the SGX drivers on your Ångström system.

You need to get your paws on:

OMAP35x_Graphics_SDK_setuplinux_3_00_00_09.bin

with the following MD5 checksum:

e15147ad76ddbe7c5aec682f5455b774

Getting this involves following the above link and going through the required registration/request process.
Once you have this file, you drop it in:

$OETREE/openembedded/recipes/powervr-drivers/libgles-omap3

and then run:

bitbake libgles-omap3-3.00.00.09

which generates the following packages:

libgles-omap3_3.00.00.09-r1.1_armv7a.ipk
libgles-omap3-dbg_3.00.00.09-r1.1_armv7a.ipk
libgles-omap3-demos_3.00.00.09-r1.1_armv7a.ipk
libgles-omap3-dev_3.00.00.09-r1.1_armv7a.ipk
libgles-omap3-tests_3.00.00.09-r1.1_armv7a.ipk

Deploy the x11-image to an sd-card, and copy these packages to the sd-card
for deployment on the target. If your beagle board does not have internet
access you will probably also require:

*  devmem2
*  libx11-6 (Only if you insisted on using a console build!)

as opkg will not be able to automatically install the required dependencies
from its repositories and you would hit the following error at deployment:

———————————————-
root@beagleboard:/opt/deploy# opkg install ./libgles-omap3_3.00.00.09-r1.1_armv7 a.ipk
Installing libgles-omap3 (3.00.00.09-r1.1) to root…
libgles-omap3: unsatisfied recommendation for libgles-omap3-tests
Collected errors:
* ERROR: Cannot satisfy the following dependencies for libgles-omap3:
*  devmem2 *  libx11-6 (>= 1.1.5) *
———————————————-

Once you have installed all the above packages, please reboot the board.

Your bootargs in U-Boot should look something like:

console=ttyS0,115200n8=noinitrd ip=dhcp rw root=/dev/mmcblk0p2 omapfb.mode=dvi:1280×720MR-16@60

assuming you want to output via DVI and are running a similar kernel
version (2.6.29-omap1 on my beagle) which accepts the same kernel
arguments indicated in the bootargs variable above.

Please note that we are specifying a 16 bit color depth which is intentional
and discussed in the “color depth considerations” section in the appendix

Please run the powervr demos (under X11) to establish that your drivers are
successfully installed and usable.

Configuring Qt

In order to build Qt now, all that is required for each target is an
appropriate mkspec:

For Qt/X11

You would fork your mkspec off the linux-g++ mkspec, the resulting mkspec’s
qmake.conf would resemble:

==================================================================
………….
include(../common/linux.conf)

# modifications to g++.conf
# These release optimization flags are TI supplied
# and a little more aggressive than Qt standard (gentoo types rejoice!)
QMAKE_CFLAGS_RELEASE     = -O3 -march=armv7-a -mtune=cortex-a8 -mfpu=neon -mfloat-abi=softfp
QMAKE_CXXFLAGS_RELEASE     = $$QMAKE_CFLAGS_RELEASE

QMAKE_CC         = $FULLY_QUALIFIED_COMPILER_PREFIX-gcc
QMAKE_CXX         = $FULLY_QUALIFIED_COMPILER_PREFIX-g++
QMAKE_LINK         = $FULLY_QUALIFIED_COMPILER_PREFIX-g++
QMAKE_LINK_SHLIB     = $FULLY_QUALIFIED_COMPILER_PREFIX-g++

# modifications to linux.conf
QMAKE_LIBS_EGL         = -lEGL -lIMGegl -lsrv_um
QMAKE_LIBS_OPENGL_QT     = -lEGL -lGLESv2 -lGLES_CM -lIMGegl -lsrv_um
QMAKE_LIBS_OPENVG     = -lEGL -lGLESv2 -lGLES_CM -lIMGegl -lsrv_um -lOpenVG -lOpenVGU

QMAKE_INCDIR         = $TARGET_STAGING_PATH/usr/include
QMAKE_LIBDIR         = $TARGET_STAGING_PATH/usr/lib

QMAKE_AR         = $FULLY_QUALIFIED_COMPILER_PREFIX-ar cqs
QMAKE_OBJCOPY         = $FULLY_QUALIFIED_COMPILER_PREFIX-objcopy
QMAKE_STRIP         = $FULLY_QUALIFIED_COMPILER_PREFIX-strip

load(qt_config)
==================================================================

and you would configure Qt with:

configure -arch arm -xplatform linux-omap3-g++ -opengl es2 -openvg

all that remains is to adjust /etc/powervr.ini on the target to be:

[default]
WindowSystem=libpvrPVR2D_FLIPWSEGL.so

Now compile an example, eg:

./examples/opengl/hellogl_es2

deploy it and Qt to the target and enjoy.

For Qt/Embedded

Since we don’t have the X11 abstraction, we have to interface with the
underlying hardware/interfaces with Qt/Embedded’s gfx abstraction layer. We
are going to be making some heavy use of the powervr driver resident under:

$QTSRCTREE/src/plugins/gfxdrivers/powervr

there is a README file in the powervr directory that is definitely
recommend reading, and lends some serious insight into our powervr driver
and Qt/Embedded in general. The same driver is used for MBX/SGX targets and
hence sees a fair amount of usage on a variety of target devices.

You would fork your mkspec off the qws/linux-arm-g++ mkspec, the resulting mkspec’s
qmake.conf would resemble:

==================================================================
…………….
include(../../common/qws.conf)

# modifications to g++.conf
QMAKE_CFLAGS_RELEASE     = -O3 -march=armv7-a -mtune=cortex-a8 -mfpu=neon -mfloat-abi=softfp
QMAKE_CXXFLAGS_RELEASE     = $$QMAKE_CFLAGS_RELEASE

QMAKE_CC         = $FULLY_QUALIFIED_COMPILER_PREFIX-gcc
QMAKE_CXX         = $FULLY_QUALIFIED_COMPILER_PREFIX-g++
QMAKE_LINK         = $FULLY_QUALIFIED_COMPILER_PREFIX-g++
QMAKE_LINK_SHLIB     = $FULLY_QUALIFIED_COMPILER_PREFIX-g++

# modifications to linux.conf
QMAKE_INCDIR         = $TARGET_STAGING_PATH/usr/include
QMAKE_LIBDIR         = $TARGET_STAGING_PATH/usr/lib

QMAKE_LIBS_EGL         = -lEGL -lIMGegl -lsrv_um
QMAKE_LIBS_OPENGL_QT     = -lEGL -lGLESv2 -lGLES_CM -lIMGegl -lsrv_um
QMAKE_LIBS_OPENVG     = -lEGL -lGLESv2 -lGLES_CM -lIMGegl -lsrv_um -lOpenVG -lOpenVGU

QMAKE_AR         = $FULLY_QUALIFIED_COMPILER_PREFIX-ar cqs
QMAKE_OBJCOPY         = $FULLY_QUALIFIED_COMPILER_PREFIX-objcopy
QMAKE_STRIP         = $FULLY_QUALIFIED_COMPILER_PREFIX-strip

#These defines are documented in the powervr README, please read it
DEFINES += QT_QWS_CLIENTBLIT QT_NO_QWS_CURSOR

load(qt_config)
==================================================================

and you would configure Qt with:

/opt/dev/source/qt-beagle-4.6/configure -embedded arm -little-endian -xplatform qws/linux-omap3-g++ -opengl es2 -openvg -plugin-gfx-powervr

all that remains is to adjust /etc/powervr.ini on the target to be:

[default]
WindowSystem=libpvrQWSWSEGL.so

Now compile an example, eg:

./examples/opengl/hellogl_es2

deploy it and Qt to your board, and after shutting down X, run the example with
the following arguments:

./hellogl_es2 -qws -display powervr

-qws - starts the application as the QWS server with exclusive access to the
system hardware which manages all subsequent Qt “client” applications

-display powervr - indicates that Qt should use the powervr driver we
compiled earlier

Summary

I hope that this posting encourages people to go forward and experiment
with a fully accelerated Qt 4.6 on the beagle board. Offloading the
painting work onto the GPU drastically reduces the load on the CPU and
broadens the range of applications which can feasibly be run on this
broadly available (cheap!) embedded hardware. The Beagle board has
really nice hardware, and it would be infinitely useful for us to have external
people using our powervr driver and getting it as broadly used/refined as
possible.

Appendix

Additional Benefits to OpenGL ES acceleration

If you take any Qt Graphics View based example and set a QGLWidget as its
viewport, a large amount of work will be offloaded on the GPU leaving your
CPU free to frolic. To put this in perspective, a modified version of:

./examples/animation/animatedtiles

which continually transitions runs smoothly at 720p on the beagle board
when using software, but consumes 100% CPU time according to top (99.3% to
be fair). It is therefore CPU bound and you are not going to be doing
anything else in the background.

When backed by a QGLWidget, the CPU usage drops to 20% on the exact same
example in the exact same conditions (720p, at 16bit color depth). The
frame rate suffers slightly, but at least this is mandated by the GPU

Minor clipping issue evident in hellogl_es2

The bubbles are evidently clipped on the right hand side, I will hopefully
beat you to reporting this at: http://bugreports.qt.nokia.com/secure/Dashboard.jspa

I have not seen any other artifacts, please file any additional bugs you
may encounter at the above URL.

Are these instructions applicable to OMAP3 targets in general

Yes. There is no theoretical reason these instructions would not suffice
for any OMAP3 based target, although I have not personally verified them
outside of Beagle board usage. Caveat emptor.

No Scratchbox2 usage when cross compiling

The more astute of your would recognize that I bypassed Scratchbox2 when
configuring Qt/X11 this time around. I payed dearly for it, and this X11
build has no fontconfig, dbus or glib support even though the Ångström
subsystem I am building against has support for all of them. If you want a
full fledged X11 build with decent font support and OpenGL ES support,
please either:

1) Invest your time in physically adjusting your MKSPEC (and/or wrestling
pkg-config) to get all desired dependencies detected and built against

-Or-

2) Take the easy road, refer to my previous blog posting “Cross compiling
Qt/X11″ and merge the above mkspec changes into the:

./mkspecs/unsupported/linux-scratchbox2-g++

mkspec in your Qt 4.6 source tree.

The same goes for Qt/Embedded which is more self sufficient, but which will
be built without dbus, glib, etc and additional external dependency support
without additional mkspec/environment modification or the use of Scratchbox2
to abstract this away.

Color depth considerations

1) The powervr implementation we are relying on does not support
PVRSRV_PIXEL_FORMAT_RGB888 (24bit color depths), it does however support
PVRSRV_PIXEL_FORMAT_RGB565 and PVRSRV_PIXEL_FORMAT_ARGB8888

2) Ångström is busybox based, and the fbset command you will need to set 32
bit color depths on the console will not work with the default fbset
busybox symlink. You will therefore have to install and use fbset(.real)
in order to get 32bit color depths, which is a simple opkg install away for
the connected Beagle board and a bitbake away for the stranded.

Please note the color depth specified in the boot arguments

console=ttyS0,115200n8=noinitrd ip=dhcp rw root=/dev/mmcblk0p2 omapfb.mode=dvi:1280×720MR-16@60

if you want 32 bit color depth, use:

console=ttyS0,115200n8=noinitrd ip=dhcp rw root=/dev/mmcblk0p2 omapfb.mode=dvi:1280×720MR-24@60

followed by:

/usr/sbin/fbset.real -depth 32 -rgba 8/16,8/8,8/0,8/24

after your Linux kernel drops you in userspace with a kiss on the cheek. A
brave man once tried leaving the color depth at 16 in his boot args, and
jumping all the way to 32bit with fbset so he could change between the more
performant 16 bit color space and the hardware compositing ARGB offering.
Running the dedicated fbset command halved his vertical resolution
regardless of any other parameters he tried to pass fbset and he eventually
ran off to fight another day.

There is a clear performance hit of 7 fps when running hellogl_es2 in
32bit rather than 16bit, taking you down to 20 fps. This hit is even more
pronounced when setting a QGLWidget on the viewport of a QGraphicsView. I
am not sure who is responsible for this, and will be personally
investigating it in the future. Any conjecture/feedback/research performed
by the reader would be greatly appreciated.

*Edited: Introduce rudimentary formatting to make the blog look less Vim forged

kamlie
Qt
Git
S60
Symbian
Build system
Posted by kamlie
 in Qt, Git, S60, Symbian, Build system
 on Wednesday, October 28, 2009 @ 16:31

One day I was sitting at my computer, waiting for my build of S60 to finish. I had run my usual round of build commands and custom scripts to speed up the build if but a little, and was expecting to wait for at least 10-12 min. At this point it occurred to me (well, it had occurred to me before): The Symbian build system is really overkill. What could it be doing that’s taking so long, for something that should be relatively simple: compile and link?

Symbian and Tux

So I thought to myself that this can definitely be improved, and that’s how I started the work on a Symbian make specification that is based entirely on qmake and make (no Symbian build chain stuff, although it uses the tools from there), and runs on Linux.

Then you might say “What about the Raptor build system that is supposed to improve things?”. It is true that Raptor improves a lot of the deficiencies of good ol’ abld, but I still felt that the huge Raptor build system is sooo overkill for something really simple. I like to obey the KISS principle. Call it a personal itch!

With this in mind I have two design goals:

  1. Ditch all unnecessary file types. This includes bld.inf and MMP files.
  2. Be fast!

Whether I’ll be able to fulfill them in the end, time will show, but that’s what I’m aiming for at least.

But let’s get into the gory details. Be reminded that the build system is still in the very early stages, and is not ready for for the end user yet, but if you like to tinker with the latest and greatest, read on. Here’s what works currently:

  1. Running configure.
  2. Building QtCore.dll with RVCT.
  3. Running QtCore.dll
  4. Building user applications with RVCT.
  5. Running user applications.

Here’s a few things that don’t work yet, but I plan to get them working:

  1. Building the host tools automatically (this needs to be done manually ATM).
  2. Building QtCore.dll with GCCE (this doesn’t work with the official port either, but as soon as it works there, it should work here as well).
  3. Other Qt dlls. QtGui.dll should probably be easy to get compiling, but it needs a few header fixes first.
  4. Building user applications with GCCE.
  5. Making the process of building a package automatic.

Here’s one thing that will probably never work:

  1. Building for the emulator. The emulator won’t run under Wine, so there’s no point in building for it. If the build system gets ported to Windows maybe it’ll be supported, but not before then.

The procedure for getting the system up and running is subject to change as the project goes forward, so instead of posting it here, I have put it in the README.s60-mkspec in the Git repository. To get it, go to http://qt.gitorious.org/+qt-developers/qt/s60-linux-mkspec, and clone the repository from there. Then check out the “working” branch. This branch is often rebased based on the latest work in the topic branches. “master” should not ever be rebased, but many things are missing from there at the time of writing.

Here’s a few short term goals for the project in the following weeks:

  1. Get the other modules compiling.
  2. Get the process to be more streamlined (e.g. more like the other platforms)
  3. Move from ABIv1 to ABIv2. The former is the old way of linking binaries on Symbian. Since this is being superseded by ABIv2, which is binary compatible at run time, but not compile time, it makes sense to only support that.
Marius
Build system
Posted by Marius
 in Build system
 on Wednesday, October 14, 2009 @ 07:38

The previous blog entry yesterday spawned so many sizable comments, that I felt they couldn’t be simply replied to in comments. So, here are some replies and comments to your comments, which you may comment on again :-)

Many: “Have you considered the <insert favorite here> build system?”

Yes, we have.
Any Java-based system is automatically /ignored due to the vast overhead of running such a system, and the fact that we would then need a Java VM running on all the systems we support. A build system needs to be fast, and fairly lean.

We’re not really considering the autotools.

Max: “CMake gets a lot of “wow! it’s great!” comments, but I could write several blog posts about how it is in fact merely mediocre. I guess you guys agree since you are not considering it.”

This is incorrect. We have not said nor implied that we are disregarding CMake. CMake might not current fulfill our complete wishlist, but we are of course still considering it. In fact, we initiated discussions with KitWare (the guys behind CMake) weeks before this blog post, to see if our wishes are unitable with their plans for CMake. These discussions are still ongoing. In fact, Bill Hoffman (CTO & Vice President of KitWare) is currently at DevDays in Munich, where these discussions will continue.

nathan: “I think the idea of using JavaScript has all the many advantages”
Sylvain: “Javascript + JSON is really good, please go for it…”
Damien Arthur: “a build tool based on json would be sweet!”
Adam Higerd: “I like the idea of using ECMAScript / JSON notation. It’s simple and not overly verbose, but expressive enough to handle non-trivial setups.”
mariuz: “I would choose javascript or minimal python (waf like)”
spinynorman: “Please don’t base any replacement on JavaScript.”…”your core audience is developers familiar with desktop rather than web languages. I’d much rather have it Python based than JavaScript.”
Tim: “I think IDE integration is the most important factor to consider, and one that you can’t do right if your build file is a script.”

After having thought about build systems a lot, we tend to like the idea of JavaScript as the build language. The reasons are several:
1) Javascript lets you use both an imperative language, and a subset declarative syntax (JSON).
This is great for supporting IDEs, since you can say that a project is primarily defined in the declarative syntax, while still support more complex builds using a full imperative language. The IDE would then only support modifying the JSON of the project, so support changing compiler flags, defines, adding and removing files on various platforms etc, and for the non-declarative parts it could drop you out in a tab-completed syntax-highlighted editor with easy access to documentation ;)
2) No need to rely on 3rd party
JavaScriptCore can be bootstrapped into the product, so there’s no need for a 3rd party distribution. That also enables us more to structure the language usage, as you wouldn’t expose a boat load of libraries by default, which you would have with for example Python.
3) Native speed on many platforms
JavaScriptCore will compile the scripts into native code on many platforms, and increasing, so the script execution is fast.
4) Good debugging tools for JavaScript
JavaScript has plenty of debuggers readily available for it, so you can debug the whole build process from within the IDE, for example.
5) Solid user base, and growing
The World Wide Web usage of JavaScript is growing at tremendous pace. QMLs scripting language is JavaScript. So, on a team there will always be someone who already knows the language. This makes build system maintenance easier for both us and our users.

Peter: “It isn’t too hard to use CMake with QtScript, see http://sourceforge.net/projects/cmakescript/
A hello world looks like this:

project("hello")

// this starts the debugger
// Qt 4.5 needed
debugger

var name = "Hello";

add_library (name, "hello.cxx")

This is a very neat proof of concept, and I could definitely consider CMake with a JavaScript language. However, unless you also start changing some of the internals to make use of the language more effectively, then all you have a new language used in the same way as before, like the add_library() function call above. If the internals were modified to allow for the the JSON construct of the project, then we’re talking! This project is great, but at the current state, not much more than what we had with QMake + JavaScript, which we had before. (And I’m not sure KitWare would want to integrate the whole QtScript module into CMake ;-) )

DAVIDB: “Cmake - its good enough for KDE which handles like a billion lines of code in hundreds if not thousands of projects. It’s been around a while and has proven to be a very good cross platform configuration tool.”

Several features needed implementation before the KDE project could use CMake; and several more would be needed to properly support Qt. It’s not just about the missing features, but also about language. We like how easy QMake projects are for medium projects, although it can get ugly when you get into the medium-to-complicated projects. It’s also very quick to get started with. Often you can just run qmake -project in your project directory, and you have a .pro file which gets you most of the way, if not all.
You also have to consider all the customers that Qt has, and will have as the various phone ports move along. What we decide on will ultimately push them to switch at some point, although we will of course maintain QMake for some time.

Coder: “Why not take an existing Open Source cross-platform build system and contribute to it.”

If we find a project which maps nicely with wishlist and requirements we have, of course this is what we will do. We don’t want re-invent a wheel, if we can avoid it. However, we do have strong reasons for not just jumping on any of the ones discussed in their current state; and that’s also why we’re reaching out, to see what ya’ll think about the various tools out there, and QMake of course.

spinynorman: “whatever you do please provide a painless upgrade path - a way to import QMake .pro files into the new system”

The users are always our primary concern, and we would of course do everything we can to assist in the transition. Just like Qt 4 has the Qt3Support, maybe the new tool would have a QMake front-end alternative? It’s not impossible.

spinynorman: “please don’t have any hidden behaviors like special include or library paths (such as the libary paths that QMake itself decides to add to Makefiles).”

I fear you might be using QMake in the incorrect way if it’s adding library paths which you don’t want into the Makefiles.
For example, if you wish to use QMake on non-Qt projects, you should do CONFIG-=qt.

spinynorman + many: “Can’t QMake be fixed rather than replaced?”

Possibly. However, it would take considerable efforts to switch out the internals while keeping backwards compatibility, and at the current state of the QMake autotests I wouldn’t dare it. Though, I guess it would be doable if enough people consider it a much better alternative than something new. One thing is then, how do we fix up the language mistakes without destroying too many projects? Bring the QtScript module back into QMake?

Holger Schurig: “If you consider using your own tool, make it a library. So that it’s easyly integratable into some IDE.”

If we decide on writing our own, that would be the idea, yes. The library would contain the whole DAG, have functions to manipulate the project JSONs, and the IDE could walk the invalidated DAG nodes, both to compile them, and to update the code completer.

Holger Schurig: “QMake currently has several generators, e.g. unix (make) or windows (nmake). Maybe it can gain a qbuilder (or whatever the new name will be) generator. That would allow you to use qmake to convert a qmake-project into a qbuilder-project.”

That’s a novel idea. Only problem is that much of the project is “lost in translation”. Once the front-end parses it, much of the information is thrown away (system checks, conditions, loops etc), so the information the back-end sees is only valid for that one particular configuration.

Reed: “Jam (Boost Jam or Perforce) are pretty good”

Read this article: http://gamesfromwithin.com/the-quest-for-the-perfect-build-system-part-2

Cliff: “Ecmascript-Syntax is better than any strange language but it won’t fully fix the problem for IDEs in my eyes. Should the IDE evaluate the code?”

As mentioned above, if the build system was libified, the IDE would contain the whole build system logic, parser and DAG. So, it easily could reparse the project file if need be, and replace that project branch in the DAG. The DAG walkers would then take care to only rebuild the invalid nodes.

Craig Ringer: “CMake looks nice … at first. Like most build systems, it turns out to have some huge, ugly warts.”

Any build system will in someones eyes have these “ugly warts”. QMake certainly has a few of them. How we deal with them (reporting/complaining, sending patches) and how the team maintaining the tool handles them is key. It’s OK if a tool has some warts as long as a) you have possible work arounds, b) you can live it the issue, and/or c) the team is actively trying to fix these issues. I’m certain KitWare doesn’t like warts in their products, and are actively trying to fix them. :-)

Craig Ringer: (about CMake): “I’ve had to copy almost every standard Find module I use into my source tree and modify it to handle one or more basic issues - improper caching of negative results, failure to handle debug library linkage on win32, failure to handle spaces in paths, etc.”

..And I assume you’ve contributed these patches back to KitWare, right?

Craig Scott: “Cross-compiling: I much prefer to compile on the platform itself. Once you have to integrate third party packages that need to be installed to supply bits of the build (eg libraries, headers, etc.), trying to set up cross-compiling gets too hard.”

Unfortunately, this is a reality which we (Qt) have to live with, increasingly. When we start targeting even more embedded systems, phones etc, we often have to do mixed cross-compilation. It’s good that not too many have to do this though :-)

Uwe: “For me it would be more important to see a better documentation of the existing qmake, than a new build environment.”
Florian: “I strongly vote for rewritting QMake and for staying backward compatible (!). That mainly means that you need to write a good unit test for the existing QMake functionality and keep that running while refactoring.”…”In our company we have thousands of QMake profiles and it would really be a bad decision for us if you stop QMake!”

QMake certainly has a lot of undocumented features, and should be better documented. However, our organization is hitting the limits of its capabilities and maintainability, so we find it hard to continue at the current state. Either we seriously renovate QMake, by fixing its internals and shape up the language, or we move over to another tool and try to shape up that one. I guess most QMake users today would want us to do the former, but the question is then, would it require too many resources to get there; and in what time perspective?

Per: “Allow the easy and familiar ./configure interface to switches with integrated documentation.”

This has been one of the topics of discussion with KitWare, yes.

Chris: “How about a XML-based approach, like Ant?”

XML is too verbose, and impossible to maintain by hand. Yes, many of our users don’t use a GUI for development, and would hate to maintain XML files for building.

cartman:http://code.google.com/p/gyp/ might be the answer to all your problems”

It’s got the JSON part, yes, but a bit young and feature-lacking of a project if we decide to go with something established.

Sebastian: “Long ago, I looked at QMake and I believe at that time it wasn’t able to create full-blown VS project files that allowed to tune all usual settings from within the IDE, but some crippled wrapper projects that just called nmake and lacked the usual settings.”

Just had to respond to this one, since I wrote the whole vcproj/sln generator: QMake never ever created a nmake wrapper for VS project files. The first iteration of the vcproj generator parsed all known options at the time, and placed them mostly correctly in the vcproj format.

QtFan: “I’m curious, when you are talking about changing/replacing QMake, are there any thoughts about changing/extending MOC !?”

Moc is a different discussion altogether. And no, we’re not planning to change Moc. Extending it, maybe. Give us a detailed use-case, and we’ll talk about it.

Florian: “I think if you would create a new tool, we would NOT use it in our company and change to CMake instead, because CMake will never go away.”

There’s no reason why QMake should go away either. It’s Open-Source after all.

gwright: “Personally, I think qmake is great. However, there is one huge flaw with it which is a showstopper for at least me”…”he makefile generator backends for qmake are paired with specific linker versions”

Yes, this is somewhat true. However, it’s not impossible to fix, and we have a developer internally which is trying to cross-compile Qt for Windows on his Linux box using MinGW, and run that result directly from his VMWare image. The applications now run, but missing some graphics :)

Ok, that was some of my comments to your comments. Keep the comment flowing, we need to know your opinions!

Thanks!

Marius
Build system
Posted by Marius
 in Build system
 on Monday, October 12, 2009 @ 14:25
QMake is one of those crucial tools which just has to work, or it totally ruins your day; that is, if your project is using qmake, of course.

Before QMake came around, there was TMake. TMake was a perl script which did a good job for what it was designed for at the time. The inner workings of QMake was based upon TMake, and a gazillion features and hacks later, QMake has ended up as a very-hard-to-maintain-without-breaking-anything-esoteric beast. The question is, what are we going to do about it?

There have been plenty of internal discussions going on for years, if we should scrap QMake and make a new, go for one of the existing build systems, or to spend extra resources trying to fix up qmake (and not break compatibility). A few projects began, but never finished. One project (QBuild) was even released with Qtopia, but not completed and further developed.
Given the non-uniform set of developers at Qt, the discussions have be fierce, and opinions as plentiful as the number of developers. There’s really no tool out there which satisfies our complete wish list, and we have looked into many of them. Either the language is broken, it’s lacking features, it’s too hard to mold to do trivial things, the language is too verbose for trivial projects (XML for example), the language is not limiting enough (Python with all its libs, for exampe), too slow, doesn’t parallelize well, doesn’t see all dependencies or takes forever to process them, it’s trigger (fork) happy, and the list goes on and on.

So, in order to make the decision even harder, we seek your opinion on the matter. :-)

I’ll present some opinions for a potential new build system, and how to potentially tackle them.

1) “Proprietary” language
As we have already experienced with QMake, maintaining an own language is sub-optimal. You actively have to work on both developing the language to support new features, and on the internals/usage of the language. You might end up ‘designing yourself’ into bad constructs which hinders new development, and doesn’t make as much sense as perhaps other possible language constructs. It can make the language hard to learn for new users. One example of this in QMake can be seen in the file

    QTDIR/mkspecs/features/exclusive_builds.prf

Another problem with a proprietary language is that it creates an additional hurdle for new users to overcome before being able to use the system, as they cannot relate any previous language skills.

It would therefor be great if the language of this new build system was a language which most people can relate to, for example JavaScript, which is getting more and more widespread (http://www.langpop.com/). By using a language which is already defined, we could focus entirely on how to use the language most efficiently and cleanly, rather than also creating a language.
We should probably also steer away from 3rd party scripting languages, as they usually come with a plethora of utility libraries, making it very hard to enforce a structure of the build system, allowing for too much customization. People going that route should probably rather use a custom script for their builds (and any build system could run that, if need be).

2) IDE integration
The build system needs to integrate well into IDEs.
We have created our own IDE, and that IDE needs to interact properly with the build process of Qt, and Qt-based projects. This means that the IDE must be able to show all the files for all different platforms at the same time, and also know which ones are built on the host and target (mixed cross-platform build) platforms, to ensure that Intellisense/code completion works as expected. It also must be able to alter the build process, like adding/modifying/removing compiler/linker options and files, which is then reflected in the build system project files.

This is not as easy as simply creating a separate file which specifies the sources needed for a build, since we need to list platform specific files, and also change settings depending on platform.

The problem then is of course conditions in the language, as these are evaluated on parse time, and thus normally not known by the IDE which needs to parse the project language.

One possible solution we’ve found to this issue would be to ensure that the settings are visible after the parsing, and easy to evaluate. In JavaScript we could define targets like this:

    var corelib = new Object()
    corelib.target = "QtCore"
    corelib.defines                 = ["QT_BUILD_CORE_LIB",
                                       "QT_NO_USING_NAMESPACE"]
    corelib.defines["mac && bundle"]= ["QT_NO_DEBUG_PLUGIN_CHECK"];
    corelib.sources                 = ["Foo.cpp", "Bar.cpp"]
    corelib.sources["windows"]      = ["Foo_win.cpp", "Bar_win.cpp"]
    corelib.sources["unix && !mac"] = ["Foo_x11.cpp", "Bar_x11.cpp"]

or, even more optimal for an IDE, as JSON:

    var corelib = {
        "target" : "QtCore",
        "defines" : { "all"           : ["QT_BUILD_CORE_LIB",
                                         "QT_NO_USING_NAMESPACE"],
                      "mac && bundle" : ["QT_NO_DEBUG_PLUGIN_CHECK"] },
        "sources" : { "all"           : ["Foo.cpp", "Bar.cpp"],
                      "windows"       : ["Foo_win.cpp", "Bar_win.cpp"],
                      "unix && !mac"  : ["Foo_x11.cpp", "Bar_x11.cpp"] }
        }

(Note that the “all” entry in the array would equal the normal array in the non-JSON code)
So, the IDE would be able to see all the possible sources, and know which configuration they belong to. Then the backends would evaluate the final sources based on the current configuration, when adding the target “corelib” to the DAG (Directed Acyclic Graph), or project dependency tree, if you will.

3) Build directly from tool
Since the tool itself has the whole DAG tree, it should be able to build all the targets directly, without going through another build system. CMake, for example, relies on the Makefile generator, and creates Makefiles which in turn calls back into CMake to do the build. This solution is not only fork-heavy, but also limiting, since you can only parallelize as well as the backend generator allows you to. So, unless the output Makefile is one single huge Makefile, you’ll run into limitations. Scons will build directly, but is too slow at parsing dependencies, so each build you do takes forever to start. Waf is better in this respect, but both lack a proper set of backends for project generations (Vcproj, XCode, Makefiles etc). They are also based on Python, which adds a dependency of a 3rd party library, which we want to avoid due to both the multitude of platforms Qt supports, and because of all the utility libraries.

4) Integration towards distributed build systems
We internally use several distributed build system, depending on which platforms we’re on (Teambuilder on Linux, Distributed Network Builds on Mac and IncrediBuild on Windows), and they all have the same limitation when we use Makefiles: They fork off more processes than what is necessary/useful on the system.

Say you have a build farm with 20 open slots. You fire off ‘make -j20′ in good faith to fill the farm. However, at the same time someone else does the same, and you both get only 10 slots each. You’ll now have 10 ’sleeping’ processes, all which are just waiting for their slot in the farm, when those resources would be better spent elsewhere.

The building backend should be able to interface with the various tools to see how much resources is available at any given time. That way it scale up or down the number of parallel jobs to the optimum. Also, the distributed build system probably knows better, as it might NOT be optimal to run 1 local compile and 20 remote ones, while your machine is linking on the other core; maybe 0 local and 10 remote is better for *your* machine, even if there are 20 open slots in the farm?

The build tool shouldn’t have to know this, and the developer shouldn’t have to think about how parallel he wants to be. This is why such an interface is important, so that it’s possible for the distributed systems to add these algorithms to the build tool.

5) Cross-compiling
In large mixed cross-compiled (were you compile projects for both host and target systems at the same time) projects, most of the sub-projects normally compile for the target system, while only a few (supporting) projects are intended for the host. This means that projects should easily and automatically pick up the target platform, while a bit more attention should be required for host platform projects only.

The project shouldn’t have to worry too much about which platform, nor how to manipulate the project file to achieve the result. Ideally they would only have to mark that a project is intended for the host platform, like for example:

    var moc = {
        "target" : "moc",
        "platform": "Host",
        "defines" : { "all"           : ["QT_MOC"]},
        ...
        }

As the configure process has already figured out which parameters are needed for the host and target platform, the build system would know which defaults to apply to each project type in the cross-compiling setup; so the project developer need not do anything else to the project, unless he/she needs to override the cross-compiling defaults.

6) pkg-config support
The build system needs to both be able to use pkg-config information, and to output the pkg-config files for a built project. Individual projects should not need to maintain a separate .pc file with replacement variables.

7) Deployment
The build system should be able to create deployment files for the various popular platforms, like .msi, .deb, .rpm, .dmg. Of course it could do this by creating scripts which are run with common platform specific tools to create these deployment files.

8 ) Configuration
The tool should handle the configuration of projects. That way we only need to maintain one set of configuration rules on all platforms, and extending with new options would be uniform. Ideally the system should also automatically generate the -h/–help documentation, based on the configuration script, so we don’t need to maintain a separate doc file together with the configuration script.
This is the same reason why we keep as much documentation together with the Qt source code, to make the maintenance of the documentation as easy and coupled as possible.

So, these are some of the things we’ve been thinking about, however, there’s a lot more to a build system than just these 8 items. Also, it’s worth mentioning that nothing is set in stone yet. We’re at the thinking stage. No matter what we decide, QMake will still around for a long time.

So, what’s your opinion?

Donald Carr
Qt
Embedded
Build system
Posted by Donald Carr
 in Qt, Embedded, Build system
 on Thursday, September 10, 2009 @ 00:49

Overview

Cross compiling Qt Embedded is relatively trivial since it is so self
contained, but as the number of external dependencies increases (DirectFB,
D-Bus, GStreamer, OpenGL ES) adjusting your custom mkspec to individually
account for the location of dependencies on the host machine becomes
increasingly tedious/untidy. This complexity culminates in cross compiling
Qt/X11 which adds the additional dependency of fontconfig/FreeType/X11 to
the fray.

This blog is intended as a general overview of the cross
compilation of Qt/X11 for embedded Linux targets. The wide availability of
the BeagleBoard and the proliferation of embedded Linux platforms gives us
the rare opportunity (and impetus) to walk people through the cross
compilation of Qt for an X11 target and get it up and running on a
reference embedded device.

These steps can be summed up as:

  1. Build a reference Linux image and toolchain (Ångström)
  2. Create an appropriate Scratchbox 2 target
  3. Build Qt against this reference image
  4. Reap the whirlwind

This walk through will introduce you to 2 separate tools intended to
simplify cross compilation for embedded targets:

OpenEmbedded (used to build the reference Linux system (Ångström) and toolchain)
Scratchbox 2 (used to build Qt/X11 against the reference system)

They both have their strengths and their particular uses, and if I offend
your sensibilities by using them in conjunction be sure to express yourself
with vigour in the comments section below. Neither tool is required to
achieve this goal, both tools expedite achieving the desired goal.

Building Ångström

I have personally chosen to use Ångström as a reference platform as the
Open Embedded development environment is relatively straightforwards to
setup in a standard (K)Ubuntu Jaunty environment, supports both x86 and
x86_64 host machines, and because it provides a fairly minimalist Linux image
possessing everything required to build a full fledged version of Qt/X11
(X11, D-Bus, GStreamer, Glib, fontconfig, FreeType). Anyone from a Gentoo
background will also enjoy the reassuring quality of 9000 build steps
constructing your eventual Linux system from source.

I followed the instructions given here:

http://www.angstrom-distribution.org/building-ångström

which culminate in the following build step.

bitbake base-image ; bitbake console-image ; bitbake x11-image

I would personally recommend rather running:

bitbake beagleboard-demo-image

which builds an appealing E17 image and which meets all Qt/X11’s needs.

The resulting Linux images are immediately deployable and you will have
acquired a very recent (by cross compiler standards) gcc toolchain to use in
the next step

Creating an appropriate Scratchbox2 target

Scratchbox enables you to abstract away the host machine when cross
compiling for a target. Rather than having to correct for host paths, you
can simply execute certain commands in a chrooted environment which
directly resembles the desired targets layout with the targets headers/libs
in their anticipated locations. With Scratchbox 2, you simply prefix
toolchain calls with sb2, and they are run within the specified
realm/sandbox.

Firstly, install Scratchbox 2 using your distributions package manager, or
via whatever mechanism you prefer. Next, you will need to create a suitable
Scratchbox 2 target. This involves executing “sb2-init” (from within the
staging/root directory containing the target’s /usr/include and /usr/lib)
with the following arguments:

  1. an appropriate cpu transparency command (normally qemu-$arch)
  2. the desired name of the target
  3. the fully qualified path of the gcc compiler

My sb2-init line looked like this:

sb2-init -c /usr/bin/qemu-arm angstrom-beagle /OE/angstrom-dev/cross/armv7a/bin/arm-angstrom-linux-gnueabi-gcc

and was run within:

/OE/angstrom-dev/staging/armv7a-angstrom-linux-gnueabi;

(Tip: The targets you have created and associated parameters are helpfully
revealed in subsequent calls to sb2-init)

Prior to running sb2-init as shown above, I personally had to modify:

/usr/bin/sb2-build-libtool

by explicitly adding “–host=x86_64″ to the configure line in order to get
libtool to compile successfully. The required diff would look something
like this (depending on your host):

- ./configure –prefix=$HOME/.scratchbox2/$TARGET –build=$(uname -m)-unknown-linux-gnu
+ ./configure –host=x86_64 –prefix=$HOME/.scratchbox2/$TARGET –build=$(uname -m)-unknown-linux-gnu

Cross compiling Qt/X11

Whenever you cross compile Qt you should create a custom mkspec based off
an appropriate reference mkspec, mkspecs/linux-g++ in this case. The
required modifications involve hijacking the qmake variables responsible
for defining all the target toolchain commands (gcc, g++, ar,
objcopy, strip) and prefixing each command with sb2.

My qmake.conf in my target mkspec looks like this:

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

#
# qmake configuration for linux-g++
#

MAKEFILE_GENERATOR = UNIX
TEMPLATE = app
CONFIG += qt warn_on release incremental link_prl
QT += core gui
QMAKE_INCREMENTAL_STYLE = sublib

include(../../common/g++.conf)
include(../../common/linux.conf)

# modifications to g++.conf
QMAKE_CC = sb2 gcc
QMAKE_CXX = sb2 g++
QMAKE_LINK = sb2 g++
QMAKE_LINK_SHLIB = sb2 g++

# modifications to linux.conf
QMAKE_AR = sb2 ar cqs
QMAKE_OBJCOPY = sb2 objcopy
QMAKE_STRIP = sb2 strip

load(qt_config)

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

Once you have modified this mkspec to address any additional considerations
you might have, you can export PKG_CONFIG_PATH to point to your targets
pkg-config (.pc) files, which are normally in a pkg-config directory under
the targets lib directory:

$targetPathOnHost/usr/lib/pkgconfig. Please note this path must be fully
qualified relative to the host)

Qt’s configure script currently does not employ pkg-config when
establishing FreeType library metainformation when testing for fontconfig
support, instead opting for heuristics which are explicitly excluded when
cross compiling. This rough little (unsupported) patch will resolve this,
and will result in the correct detection and compilation of Qt with
fontconfig/FreeType support.

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

diff –git a/configure b/configure
index 3f3e55a..54de96b 100755
— a/configure
+++ b/configure
@@ -5115,6 +5115,10 @@ if [ “$PLATFORM_X11″ = “yes” ]; then
if [ -n “$PKG_CONFIG” ] && $PKG_CONFIG –exists fontconfig 2>/dev/null; then
QT_CFLAGS_FONTCONFIG=`$PKG_CONFIG –cflags fontconfig 2>/dev/null`
QT_LIBS_FONTCONFIG=`$PKG_CONFIG –libs fontconfig 2>/dev/null`
+ if $PKG_CONFIG –exists freetype2 2>/dev/null; then
+ QT_CFLAGS_FONTCONFIG=”$QT_CFLAGS_FONTCONFIG `$PKG_CONFIG –cflags freetype2 2>/dev/null`”
+ QT_LIBS_FONTCONFIG=”$QT_LIBS_FONTCONFIG `$PKG_CONFIG –libs freetype2 2>/dev/null`”
+ fi
else
QT_CFLAGS_FONTCONFIG=
QT_LIBS_FONTCONFIG=”-lfreetype -lfontconfig”

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

then kick off the configure with:

./configure -arch arm -xplatform $customMkspecDirName -force-pkg-config

configure, make and pkg-config are being run directly on the host,
pkg-config is using the targets .pc files, the core tools (qmake, uic, moc)
are being built for the host, the config.tests are being correctly built
against the targets mkspecs and the cross compiler is used for all target
specific compilation. With any luck you with see a large number of the
configure tests pass, and see Qt configured to be built with full
fontconfig/GStreamer/D-Bus support. You can now build Qt by simple running
“make” (You are using the host machines Make, and please note that you
never actually need to prefix sb2 on the commands you run, the qmake
generated Makefile will contain sb2 calls where applicable)

Reap the whirlwind

Cross compiling Qt applications now simply involves running the freshly
built qmake against the desired project .pro file, and running make as per
usual. (You are using Qt tools built for the host, and the host system’s
make and pkg-config applications amongst other things). Running make
therefore results in the host system’s “make” proceeding through all
the build steps using the correctly prefixed build tools.

Assuming your build is dynamic, your libraries and plugins have to be
deployed to the prefix path you either implicitly or explicitly specified
at configure time)

(Disclaimer: I realize that there is no implicit dependence on Linux when
discussing X11, and there is nothing Linux centric in my instructions other
than that it is the reference (and host) platform. I am building a standard
Qt X11 build in a controlled environment advertising my headers/libs in
their canonical paths (via Scratchbox) and making use of qmake’s cross
compiling infrastructure. If you have a suitable root filesystem,
associated toolchain (cross compiler), and if both Qt/X11 and Scratchbox 2
support your target platform, you should be set (although officially
thoroughly unsupported) to walk down the yellow brick road with these
instructions.)

****Note:  As of Qt 4.6 the above mentioned scratchbox2 approach is redundant on systems with a fully functioning pkg-config and is only recommended as a fall back. Build the Ångström sub-system, export PKG_CONFIG_PATH and PKG_CONFIG_SYSROOT appropriately and configure should correctly establish the capabilities of the sub-system.



© 2008 Nokia Corporation and/or its subsidiaries. Nokia, Qt and their respective logos are trademarks of Nokia Corporation in Finland and/or other countries worldwide.
All other trademarks are property of their respective owners.