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!