Building Qt for Termux Android

This is by all means, not the first blog post about Termux. It serves as a journal for myself, as well for anyone who’s interested in cross building Qt or Qt-related projects for Termux (which is a native Linux environment for Android) from their x86_64 machines.

We already have @xeffyr who has done a great amount of work on building Qt for Termux. The work I’ve done recently would be 10 times harder, if not for what’s achieved by them already.

If you’re new to cross building for Termux, I recommend you to start with Developer Wiki.

Failure is a Stepping Stone

I jumped start with Qt 5.15.2 which is the latest open-source version of Qt 5. However, the last successful build of Qt for Termux was version 5.11.3. There is a huge log of changes committed between these two versions. From my personal point of view, I did one thing better, which is to use qtbase submodule instead of the huge tarball that includes all modules.

I first examined the current patches and realised that most of them are trying to differentiate Termux environment from a regular Android target. Termux is a Linux environment on top of Android, which means it is not a regular desktop Linux environment but by no means it’s close to Android. To find the right spot, there are two approaches, one is what @xeffyr had done by forcing Qt to recognise Termux as a regular Linux environment and then cherry-pick the places where it needs to be treated as Android. The other way is what Sailfish OS did. They’ve defined a new target called Q_OS_ANDROID_EMBEDDED which is similar to what we try to achieve.

I’ve started my effort to go the latter direction, which also required extra patches by the way. Like any marvellous engineering work hack, this process is try and error.

There is a bad system call issue which could be traced by strace and it revealed the shared memory function calls that had to be patched (by either directly invoking dlopen or forcing the library to link against android-shmem).

The qt515 branch was, in fact, able to produce binaries that work on the vnc QPA platform. I was troubled by a mysterious segmentation fault that was diagnosed by GDB to be triggered at Qt HiDPI position conversion function. My hunch told me that shouldn’t be the case as the code looks sane, plus the segmentation fault only happened with the xcb plug-in. After disabling the HiDPI feature, the segmentation fault happened at QCoreApplication, which was even more bizarre. After another day of futile work hacking, I gave up and switched to try my luck with Qt 5.12.10 which is the latest patched version of Qt 5.12 LTS, at the time of writing.

I started to question whether Q_OS_ANDROID_EMBEDDED was the right choice of hacking the way through, which led to a different approach (by pretending to be a regular Linux environment) applied on the Qt 5.12 branch. After another day of try and error, I managed to get to the same spot as my previous attempt with Qt 5.15.

Haunted Segmentation Fault

It felt back to square one with the same segmentation fault again! The only improvement I had over my work on Qt 5.15 branch was that the shared memory is now solved with a single linking flags change in the qmake.conf.

Malo nodo, malus quærendus cuneus

Desiderius Erasmus Roterodamus

Desperate times require desperate measures. I decided to follow my hunch on the xcb plug-in, knowing that wasn’t an issue on Qt 5.11 and that my Qt programs work on the VNC platform. I’ve reverted the whole plugins/platforms/xcb directory to what Qt 5.11.3 has, which by the way says a lot about the modularity of Qt (impressive separation). Yes, that’s how desperate it got.

No luck. Well, not directly.

Success at Last

Qt failed to be built altogether because xinput2 in Qt 5.11 was replaced by xcb-xinput in Qt 5.12. Hmm, what is that xinput thing then? My initial idea was to somehow stitch them so it could compile, which later seemed to be a lot of work hack. Desperate times require desperate measures. I was thinking since xcb-xinput is a new thing, and it doesn’t seem to be useful, if functional at all, in Termux environment. Maybe let’s just explicitly disable it.

🥳

A much needed surprise, it worked! I ran a few example projects provided by Qt and they all looked as expected!

One More Thing

The previous packaging script for Qt 5.11 doesn’t save the binaries produced for the host (this is cross building after all) into a package. That means in order to build any other Qt projects, this needs to be rebuilt, and the only way to trigger a rebuild is to bump the revision number. Let’s say that won’t scale well.

I’ve made some changes (an experience from my meddling with Qt 5.15) so that the host tools are saved into a deb package for the new Qt 5.12 package. With that, Qt projects should be able to be managed and packaged easier for Termux.

Other Things

There are other things that I left out from this post. For example, in Qt 5.15, the sysroot configuration actually works as expected. In Qt 5.12, it would mess up the linker and where to find the libraries (for which I had to add the path to the -L option directly so it gets passed on).

This blog post is only talking about the qtbase module. I’ve started to work hack on other modules to bring them onto Termux. Stay tuned!