Building Necessitas Qt framework using NDK-r5b and Cygwin — not fun, but mostly possible

I’ve been following the Necessitas project (formerly “Android Lighthouse”) for a while now. It’s a port of the Qt GUI framework to Android. Last year I managed to get it to build on Windows by following the instructions at android-lighthouse google code ticket 11 and this very helpful post by Damien Buhl (in French, Chrome will translate it for you). Those links are still super helpful, but some things have changed since then — Necessitas has undergone significant structural change, and Google have released a new Android NDK r5b.

This post documents the steps I took to get the Necessitas Qt framework to compile with Cygwin and the official Android NDK r5b (the latest version as of this writing). So far I’ve only got the libraries to compile. I havn’t built Qt Creator (the GUI IDE that Necessitas now offers) and nothing is running on my device yet — that’s a matter for more research. I thought I’d post the info now because I seem to have got it to build, and well, there’s more than enough info here for a blog post.

*Disclaimer:* If you follow these instructions you will have built Qt libraries for Android with Cygwin, nothing more. I don’t tell you how to use them or how to load them onto the device, nor do I tell you how to get Necessitas Qt Creator running on Windows.

Cygwin vs. mingw

Windows gcc development can be done with the Cygwin POSIX emulation layer, or with mingw — a light weight minimalist gcc distribution. So far Android NDK development on Windows requires the Cygwin environment. However Google is in the process of dropping support/dependency on Cygwin from the Windows Android NDK. This is good and bad news. Good because NDK builds with Cygwin are slow, and installing Cygwin just to build NDK code is a lot of overhead. Bad news is that the native Qt build and configuration system doesn’t support cross-compiling Qt on Windows without Cygwin, and using the new NDK in combination with Cygwin-based Qt builds is non-trivial.

I tried to build Qt Necessitas with both mingw and Cygwin. I made progress with both but in the end I succeeded with Cygwin first, so that’s what this post is about. In the long term I think cross-compiling Qt using mingw on Windows is most likely a better solution but it will require substantial work on Qt’s configuration system before it is possible. I just learnt that mingw.android is working on it.

Preliminary steps

The official Necessitas instructions for compiling the Qt framework describe how to build Qt frameworks for Android on Linux. There are a few extra steps to make this process work on Windows under Cygwin.

You need to have Cygwin installed, with the development tools  (binutils, gcc-core, gcc-g++, make, patchutils) and Cygwin git. It’s all easy to install using cygwin’s package installer. You may need a few other Cygwin packages. You’ll soon know about it if you try to run a command that isn’t installed.

Also have the Windows Android NDK r5b downloaded and unzipped.

Clone the Qt source code from the android-lighthouse repository using git (it’s about 400MB and might take a while):

git clone git://gitorious.org/~taipan/qt/android-lighthouse.git

A few points here:

  • Make sure you’re typing everything here in a Cygwin shell and using Cygwin git. You want the symlinks in the repo to come out correctly as Cygwin symlinks.
  • Early on I had a problem using msys git where things wouldn’t build because git had converted everything to Windows-style CRLF line endings. So you might want to make sure your git config says core.autocrlf=false
  • Once git is finished I recommend making a local copy of the android-lighthouse directory so you have a clean version you can duplicate if you want to start again. I found this easier than cleaning the tree if the configuration breaks badly.

Another thing to note: I have the NDK and android-lighthouse directories on the same drive. I’m not sure, but this might help in cases where commands ignore drive letters. Best to keep them on the same drive to be safe.

NDK compiler include paths

Since the NDK r5b gcc compiler no longer depends on Cygwin, it doesn’t understand Cygwin’s POSIX style paths that map Windows paths like C: /blah to /cygdrive/c/blah. When you configure and build Qt using Cygwin, qmake and all the Qt Makefiles will use Cygwin POSIX style paths. This works out OK for relative paths: the NDK gcc can deal with forward-slash path separators, but it can’t follow the Cygwin style /cygdrive/blah absolute paths used for some include and library directory arguments. The net result is that gcc will report it can’t find standard header files like <string.h> or <new>. If you invoke gcc with the -v option you get the real story: it can’t interpret the Cygwin paths and is ignoring them.

I tried a few of different fixes for this issue:

Attempt #1: Pass include paths to qmake as Windows paths, executable tool paths as Cygwin paths. This doesn’t work. Not only does qmake pass include paths to gcc, it also uses them internally to compute dependency information that gets embedded in the generated Makefiles. Qmake and make need to be able to understand all paths you use. Therefore you need to use Cygwin paths at this level.

Attempt #2: Defining QMAKE_RUN_CC and friends in mkspecs/android-g++/qmake.conf allows you to override how qmake invokes gcc (grep other qmake.conf files for examples). I was able to wrap $INCPATH with some sed foo that converts Cygwin paths to Windows paths which gcc would understand. This almost worked. Unfortunately qmake hardcodes (in qmake/generators/unixmake2.cpp) the $INCPATH text for generating the Makefile rule for precompiled headers, so it’s not possible to re-write the paths in all invocations of gcc using qmake.conf. I could have just disabled precompiled headers (-no-pch flag to ./configure) but that’s not a real solution.

Solution: having given up on a purely qmake.conf approach I decided to just wrap gcc and g++ with shell scripts that re-write include path (-I) and library path (-L) flags that use Cygwin paths. These scripts go in android-ndk-r5b\toolchains\arm-linux-androideabi-4.4.3\prebuilt\wi ndows\bin along side the NDK gcc and g++ binaries:

arm-linux-androideabi-cygwin-gcc.sh:

#!/bin/sh
b=`basename $0`
d=`dirname $0`
p=`echo $@ | sed -e "s,-I/cygdrive/\(.\)/,-I\1:/,g" | sed -e "s,-L/cygdrive/\(.\)/,-L\1:/,g"`
$d/arm-linux-androideabi-gcc.exe $p

arm-linux-androideabi-cygwin-g++.sh:

#!/bin/sh
b=`basename $0`
d=`dirname $0`
p=`echo $@ | sed -e "s,-I/cygdrive/\(.\)/,-I\1:/,g" | sed -e "s,-L/cygdrive/\(.\)/,-L\1:/,g"`
$d/arm-linux-androideabi-g++.exe $p

Then the definitions of QMAKE_CC and QMAKE_CXX in android-lighthouse/mkspecs/android-g++/qmake.conf need to be modified to invoke the wrapper scripts instead of the NDK gcc and g++ executables:

QMAKE_CC  = $$NDK_TOOLCHAIN_PATH/bin/$$NDK_TOOLCHAIN_PREFIX-cygwin-gcc.sh
...
QMAKE_CXX = $$NDK_TOOLCHAIN_PATH/bin/$$NDK_TOOLCHAIN_PREFIX-cygwin-g++.sh

Symlinks

Symbolic links are not well supported on Windows (although Vista and Windows 7 do add some support). Cygwin provides emulated symbolic links, but of course the new r5 NDK gcc can’t understand them. This causes two separate problems, solved thusly:

1. The current android-lighthouse tree uses symlinks in a number of places to alias .c and .h files to different locations in the tree. I’ve filed a ticket about this not working on Windows, but until it’s fixed you can run the following command (from a Cygwin prompt) to replace the symlinks with normal C files that #include the linked file:

find -type l -regex '.*/.*\.\(c\|cpp\|h\)$'
    -printf "rm %p; echo '#include \"%l\"' > %p\n" | sh

(all of the above on one line)

2. The Qt build process creates symlinks to redirect general shared library .so files to the version numbered ones (eg. libQtCore.so is a symlink to libQtCore.so.4.8.0). Since the Qt build process crosslinks Qt libraries with the general (usually symlink) versions this breaks if gcc can’t understand the symlinks. Qmake would usually use the ln -s command to create a symbolic link. The easy (but space hungry) fix is to tell Qt to just copy the libraries instead of linking them by adding the following to android-lighthouse/mkspecs/android-g++/qmake.conf:

QMAKE_LN_SHLIB = cp

Incidentally, that’s the behaviour of ln -s when you invoke it in msys/mingw.

Miscellaneous patches

There are a couple of patches that have been floating around for a while that are required to make the Necessitas framework build with Cygwin. I think I found them on the google code ticket 11 page.  Both are needed so that the Qt bootstrapping process can compile tools such as qmake, moc and rcc using the Cygwin toolchain. The first patch adds library prefixes and extensions to the Cygwin g++ qmake.conf, the second resolves a Unicode issue in src/corelib/global/qglobal.cpp by replacing OSVERSIONINFOW with _OSVERSIONINFOA.

diff --git a/mkspecs/cygwin-g++/qmake.conf b/mkspecs/cygwin-g++/qmake.conf
index ddfceb0..7b54298 100644
--- a/mkspecs/cygwin-g++/qmake.conf
+++ b/mkspecs/cygwin-g++/qmake.conf
@@ -25,6 +25,9 @@ QMAKE_CFLAGS_DEBUG    = -g
 QMAKE_CFLAGS_SHLIB     =
 QMAKE_CFLAGS_YACC      = -Wno-unused -Wno-parentheses
 QMAKE_CFLAGS_THREAD    = -D_REENTRANT
+QMAKE_PREFIX_SHLIB      = lib
+QMAKE_PREFIX_STATICLIB  = lib
+QMAKE_EXTENSION_STATICLIB = a

 QMAKE_CXX              = g++
 QMAKE_CXXFLAGS         = $$QMAKE_CFLAGS

diff --git a/src/corelib/global/qglobal.cpp b/src/corelib/global/qglobal.cpp
index 6105682..fad4c40 100644
--- a/src/corelib/global/qglobal.cpp
+++ b/src/corelib/global/qglobal.cpp
@@ -1742,7 +1742,8 @@ QSysInfo::WinVersion QSysInfo::windowsVersion()
     if (winver)
         return winver;
     winver = QSysInfo::WV_NT;
-    OSVERSIONINFOW osver;
+    _OSVERSIONINFOA osver;
     osver.dwOSVersionInfoSize = sizeof(osver);
     GetVersionEx(&osver);
 #ifdef Q_OS_WINCE

androidconfigbuild.sh bug fix

As of this writing there’s a bug in androidconfigbuild.sh’s use of the getopt built-in that means that the script ignores host and platform parameters passed on the command line (we need to be able to specify the host as windows). It should be fixed by the time you read this, but just to be sure, make sure the getopt line looks like this:

while getopts "Hr:h:p:v:a:q:c:i:d:" arg; do

The version of androidconfigbuild.sh I checked out of git passed a getopts parameter like this: “help:r:h:p:v:a:q:c:i:d:” That’s a problem because getopts doesn’t support multi-character flags which “help” is, and in any case the -help flag doesn’t accept a parameter so it shouldn’t have a trailing “:”.

Disable webkit build

During the build I encountered a problem with Windows’ 32k limit on command-line length. This meant that when the Qt build got around to linking the webkit library it failed with an “argument list too long” error. The command line arguments were about 60k. I don’t have a fix for this other than to disable building webkit. Do this by editing androidconfigbuild.sh, change the -webkit parameter to configure to -no-webkit.

Now we’re ready

If you’ve followed along you’re ready to actually launch the Qt build. From a Cygwin prompt type something like the following. You’ll have to substitute the Cygwin style path of your Android NDK. Mine’s in the root of G: drive:

./androidconfigbuild.sh -r /cygdrive/g/android-ndk-r5b -h windows
    -p arm-linux-androideabi -v 4.4.3 -q 1

(all of the above on one line)

This should proceed through the entire build process. It will print error messages at times, usually these are just configuration tests for whether things are present and functioning. Unless the process completely halts and returns to the command prompt you can trust that it’s doing its thing.

The configure and make process will complete but the final two steps in androidconfigbuild.sh will fail (qpatch and make install). I’m not sure whether these steps are important on Windows unless you want to relocate the libraries once you’ve built them. I’ll update the post if I find an answer, for now I think it should work without them.

Cygwin Win32 error 487 contingency

This may not happen to you, but after my build was about half way through it failed with an error like “could not load C:\WINDOWS\system32\winmm.dll, Win32 error 487.” A bit of digging suggests that this is a known issue with the current Cygwin build. I fixed it by copying the latest cygwin1.dll snapshot over the version in my Cygwin install path at C:\cygwin\bin\cygwin1.dll. After that I restarted the build and the error went away (you can pass -q 0 instead of -q 1 to prevent androidconfigbuild.sh from running configure from the start). If you’re brave you may want to update your cygwin1.dll before you start but I can’t guarantee that won’t introduce other problems.

Wrap up

Right now that’s what you need to do to build Qt/Necessitas with Cygwin. You won’t have Qt Creator and at this stage I can’t tell you how to install Qt projects on an Android device without it. You used to be able to just push everything with adb but things seem to have changed a bit since I last followed Damien Buhl’s instructions for manually pushing libs to your device using adb. Once I work that out I’ll post an update here. Please subscribe to the blog or follow my tweets if you want to hear about the next installment.

Thanks to BogDan for his great work on Necessitas, and to all the helpful developers on android-qt and android-ndk lists. Thanks also to Damien Buhl and the posters on googlecode. If I hadn’t succeeded in getting a previous version of android-lighthouse building with their instructions I probably wouldn’t have known where to start this time around. Thanks to David Turner on android-ndk for answering my questions about current Windows NDK status and to mingw.anrdroid who should be bringing us some Cygwin-free Necessitas goodness soon.

Internet audio streaming apps for music performance — some options

A couple of weeks ago bP/555 asked me to recommend a solution for streaming high quality audio from a music performance in Barcelona to the  DIALECTIC night at Horse Bazaar here in Melbourne. The venues at either end were connected to the Internet using domestic-grade ADSL2 modems. This certainly wasn’t a super-high-bandwidth Internet 2 academic network scenario. bP wanted high quality audio (“320 kbps mp3” was the way he put it), video was optional. It wasn’t a collaborative performance, the audio only had to travel in one direction.

I’ve been working with streaming real-time audio over LANs a bit lately, but streaming from Barcelona to Melbourne is quite a different proposition — not something I have any personal experience with. I do have an interest in network music peformance and I’ve been following development of the CELT low latency codec for a while, which is designed for low-latency distributed music performance. So I was interested to find some answers. I figured the best thing to do was to ask around and see what solutions people are using. I asked on ACMA-L and the celt-dev list and pinged a few friends privately too. This post shares the responses I received and a few of my thoughts on different approaches. If you know of something else I havn’t mentioned here please post it in the comments.

A few preliminaries

Before I get on to the alternatives people suggested I want to note a couple of points I made to bP:

  • The computers at either end need to be connected to the network using cables — you don’t want WiFi packet loss layered on top of the already high demands of real-time streaming media.
  • Since the computers will likely be behind NAT routers at either end, you either need a plug-and-play solution that can deal with NAT traversal  (possibly using intermediate servers) or have access to configure the routers to forward traffic on to your computers.

Another thing that became apparent, and that was reinforced to me by a number of people, was that you need to be sure your internet link can sustain the bandwidth needed for the performance. It’s all good and well to ask for 320kbps audio streaming, but if your Internet link can’t reliably sustain the bandwidth then it won’t happen. In general no public link between Barcelona and Melbourne with ADSL endpoints guarantees bandwidth but you can at least test things a work out what the upper practical limit is — keep in mind that it will depend on network routes and network load (i.e. day of week and time of day).

On to the options that were suggested…

Hi-fi chat apps

Early on I’d suggested Skype as a simple and easy plug-and-play option. I like the idea of using a voice chat-app because it’s super-easy to set up and the software should be able to navigate the hazards of domestic situations like NAT firewall traversal without fuss. However one of the key things bP wanted was high-fidelity music grade audio. This put a lot of voice-quality internet-chat applications out of the picture. I learnt there are solutions that use the music-quality CELT codec I mentioned above (which incidentally promises better quality than mp3 at the same bit rate). To this end, Dennis Heerema on the celt-dev mailing list suggested the following two free solutions:

  • Fideliphone – Simple to configure, point to point, almost but not-quite out of beta.
  • TeamTalk – Client-server config, uses speex codec or CELT (mono and stereo).

Shoutcast, Icecast and friends

A number of people suggested shoutcast or icecast streaming. These are the usual go-to choices for internet radio broadcasting. You can buy streams from various commercial suppliers around the web.

People had good things to say about Nicecast ($40, Mac OSX only) as a simple solution for non-technical people. Matt Hitchcock said: “It is a GUI wrapper with an icecast underbelly and runs intuitively and without any fuss.” There’s a list of other icecast clients at the icecast site.

Jordan Reyne uses shoutcast for her Second Life performances “their sound quality is excellent”. She uses a free broadcast client called butt (” broadcast using this tool”), which is available for Windows, Mac and Linux. Jordan has posted a 6 part blog on using shoutcast streams inside VRs such as Second Life or Heritge Trust etc.

Distributed network music performance

Distributed network music performance is the idea of playing music live with other people over the internet. Audio quality is important here, but so is low-delay. After all, playing in time is difficult with a 50ms delay, let alone a 10 second delay! One important thing to note here is that audio codecs such as mp3 add a lot of delay just encoding and decoding the audio. So it becomes important to use uncompressed audio or low latency codecs such as CELT or its successor Opus (both with <5ms codec delay).

For low-delay distributed network music performance Alex Carôt’s Soundjack seems to be the go-to solution. As well as distributed musical performances Alex says that it’s “already used by numerous radio stations and for other high-quality audio/video streaming purposes.” The big advantage of systems like this is that they are designed to provide low-latency two-way communication for collaborative performances. Delays are often orders-of-magnitude lower than systems designed for broadcast streaming. Unfortunately you still have the speed of light to contend with (~86ms from Melbourne to Barcelona in a fibre optic cable, not to mention routing delays).

For high-bandwidth situations a few people suggested Juan-Pablo Caceres’ JackTrip. JackTrip can handle uncompressed and multichannel audio and is commonly used on local area networks. For streaming over the Internet from Barcelona to Melbourne using ADSL modems this option just wasn’t going to cut it.

Mixlr

Mixlr’s mission “is to make audio broadcasting as easy as possible, both for casual broadcasters, musicians and DJs.” They provide client and server applications for both Mac and PC. It’s not a free service but you can sign up for a 15 day free trial. This solution really appealed to me for bP’s situation — it’s focused on high quality audio for musical performance and it’s packaged in an easy to use, off-the-shelf app.

VLC (Video Lan Client)

A couple of people suggested VLC. Scott Gresham-Lancaster wrote:

Another option that I have used in the past particularly if you are just going one way with most of the content is to use Video Lan Client. If you have enough bandwidth you can do point to point streaming of HD with that, especially if you have hardware compression. We did a direct link between the stage at Stanford and University in Bejing this way with great success. Engadget have a nice intro here:
www.engadget.com/2005/11/29/how-to-stream-almost-anything-using-vlc

Other Contenders

I’m not really familiar with live video broadcasting services such as Livestream and USTREAM but the venue in Barcelona had used Livestream before and it appears to offer good quality audio, although perhaps not the “320kbps mp3” quality we were looking for. These options support video and broadcast, which although not critical in this case could be useful for many applications.

Quicktime broadcaster was also suggested, this is “Apple’s standards-based live encoding software.”

Wrap up

Which solution did bP end up using? I’m not telling 🙂 As often happens there was little time to try out all of the options and a choice was made based on expediency. My feeling is that any of the solutions listed above could have worked well and are certainly worth exploring for future events.

In the future I hope setting up a hi-fi intercontinental audio link is as easy as placing a phone call, and with many of the solutions above we’re almost there. The hardest part for the uninitiated seems to be in working out which solution to choose. Do you have experience performing music over the internet? If so, please share your experience in the comments.

Many thanks to Alex Carôt, Nick Collins, Ken Fields, Scott Gresham-Lancaster, Dennis Heerema, Matt Hitchcock, Julian Knowles, Jordan Reyne, Rob Watson and the members of ACMA-L and celt-dev for helping bP and I out and answering our questions. Thanks to bP for asking the question, I’ve learnt a lot.