Compiling native code without using the NDK?

Hi everyone! First time making a topic, I hope I picked the right category. I got a feeling this is a really stupid question… but I’ve been thinking and searching for this for too long. And now that I have the chance to ask people skilled in this area, who probably have had similar ideas (and ideals), I’m going to accept looking stupid see where this leads.

Debian’s Android Tools packaging team has put great effort into turning the android SDK into independent official packages (not a small accomplishment!), making it possible to build apps written in Java. But the NDK is still missing. I know about Android Rebuilds, but I would still like to limit the software I use to official distro packages.

But… just like the SDK, many parts of the NDK are existing software. So would it be possible to use the normal tools used for cross compiling (the same gcc used to target gnu/linux on the same architecture as the android system) to compile C code to include in an app (written in Java and built using the android sdk parts from debian)? I’ve heard people did experiment with this to build executables (run through a terminal in android) before there was an NDK, and I did see Guix running on Android recently. But I haven’t found much information on doing this, and no info on doing this to compile native code to include in an actual app.

So my questions are: Would this be possible? Has anyone done this? If so, is there some reference/demo/guide? Would there be any significant disadvantage from doing this? And would such an app be accepted in the F-Droid repo (which is buillt using the official NDK and SDK)?

Thanks for any response. And keep up the good work on F-Droid!

2 Likes

In short (and more technical): I’m wondering if one can use, say, arm-linux-gnueabi-gcc to compile a .so or .a and include it in an app like it’s been built from the NDK. I know it’s possible to build (static) programs this way, but would it work for a native library for an app? Or will this not work? Maybe using the “androideabi” abi is required?

I probably should have said this from the start. I hope it’s ok that I wrote this as a reply to myself.

1 Like

It’s a Debian VM, the build server, you can build anything.

How do you build your app now? You can repro the same setup… I guess.

Thanks for your feedback, it means a lot! (and sorry for the late reply!)

So the F-Droid part seems possible (simply apt-get in the build metadata). Now the big question is if something like arm-linux-gnueabi-gcc will work.

It seems compiling simple C code to .a or .so might work. But bionic and linking to more libraries might be a problem. I was hoping to link and use things like EGL, GLES.

How do you currently build? Explain…

Thanks for your reply. First some background: I got a old project (GPL3, C/C++, Using ODE, SDL, OpenGL, … and built using autoconf) that I’ve been wanting to get back to, redesign and also port to Android (specifically for F-Droid, not the google store). It currently supports GNU/Linux, other GNU variants, BSD:s, Windows, Mac and a few others.

So it currently doesn’t build against android. But before I try to port it I wanted to see if it’s feasible to rely entirely on debian packages. The android sdk is available, but the NDK is not. Since I’m free to design/port from scratch, maybe there are ways to design the “native code” around the fact that I would use the normal gcc (like arm-linux-gnueabi-gcc) instead of the NDK tools?

I’m also trying to see if I can get GNU Guile compiled and running as “native code” in an android app (I’m planing on using it in my project, if it’s portable enough). I know installing GUIX on android includes guile, but that is using proper elf binaries, placed and run directly from the filesytem outside the VM stuff, so not surprising it works and not quite what I’m looking for (unless I can still do GLES calls from outside the VM?)

I would suggest doing some experiments with simple “native” programs to test the feasibility of your idea. Although my instinct tells me that you will need the compilers from the NDK to build a fully native application, it seems that people have managed to build static executables using the gnueabi compilers (see this Stack Overflow question).

I don’t know how well you can integrate an application built in this way with the Android system it is running on.

Another approach might be to build the application using tools running in something like Termux and take advantage of its add-ons to build a user interface, though it might be a bit more limited than a normal application.

Yes, compiling normal elf programs to run directly on the underlying linux kernel can be done (that’s how GUIX, debian chroot:s and termux programs works). But then the program doesn’t get much access to the OS api (neither java or native libraries). At least that’s how it seems/what I think.

I was hoping someone had, in a similar way, instead built libraries and used them inside an app. But I suspect there are limitations that makes it very disadvantageous. In some ways I think it can be worked around (like the fact that my code is GPL so I could ship the gnu c library instead of using bionic if necessary/solves anything). But others are probably a nightmare.

Another idea would be compile the code as a normal program, and handle all OS calls through an app (communication handled through a socket or similar). It would make it trivial to port GNU Guile (since I can just put and run everything needed directly on the filesystem and ignore the android layer, just like GUIX). But the disadvantage is that a lot of extra work will be needed and performance will suffer. It also wouldn’t solve potential problems with porting Guile to other embedded platforms, but that’s outside this topic…

Many of the projects to build Python apps on Android have involved using some mechanism to link the native code interpreter and the APIs in the Java world, either via JNI or some other indirection layer. The main problem with writing an application where the GUI is controlled from native code is that you have to mess about with a mechanism like that.

The alternative is to build an application where the GUI-controlling code resides in the Java world and you call out to libraries that do things at the native level. I’ve never done anything like that, though I discovered that you could run other processes using the AsyncTask class, which would give you access to the shell. This was with an old version of Android, however, so permissions and policies may have changed since then.

Short version: you can’t.

Long version: both ANativeActivity and JNI work by loading shared libraries. These shared libraries need to be built with the android toolchain (bionic is the Android C library + math library + dynamic linker). The linker will fail to load at runtime any shared library built against a toolchain that isn’t compliant with android ABIs.

One could, with unlimited skills and unlimited resources, start digging into the differences between the armeabi-v7a and a gnueabi toolchain and repeat that for each ABI but that’s a huge offtopic.

Also, the other solution (built a static executable against muslc or any other libc and execute it with Runtime.getRuntime().exec) could work in some devices/versions and be very broken on others. Usually apps shouldn’t rely on its runtime environment.

TL;DR: You can’t built a library without the NDK. You don’t need to install the NDK on debian. Just install the sdk tools, setup a new project and include the ndkVersion you need on your gradle files. As any other gradle dependencies it will be downloaded at build time if is not already on your build device.

Edit: Termux packages are already built against the NDK.

Thanks for the reply. I was afraid that would be the case, but thank you for bringing me closure on this. I will use the NDK (through android rebuilds or similar) and hope debian eventually will package it like the rest of the SDK.

But you also say gradle will download the NDK if it’s missing. This is news to me. How does F-Droid handle this? Normally dependencies are built and provided through F-Droid, right? Is the NDK built from source by F-Droid right now? If so is it something I can utilize (without setting up the entire F-Droid build server)?

https://forum.f-droid.org/t/call-for-help-making-free-software-builds-of-the-android-sdk/

Thank you. I’m aware of Android Rebuilds. Or do you mean this thread answers some other question, like if/how gradle downloads the NDK automatically?

If you need a specific version:

If not the last recommended NDK based on gradle plugin will be used, which is usually Ok.

On systems where the ndk isn’t installed it will be downloaded if is required by gradle build scripts.

Using externalNativeBuild is the common way of building native code on android/gradle and will trigger the download.

Anyways, this has nothing to do with F-Droid :smile:

Thanks. Yes this is a bit of topic, but I appreciate your reply! And the point for this topic was to avoid the non-free NDK, which is closely related to the desire for freedom that f-droid was created from.

I’m still unsure on how/if gradle will download the NDK without any user action. I thought it would require ticking a box (+agree on license) in “SDK Manager” or similar. I can’t find anything specific about gradle downloading the NDK (without using the sdkmanager) on the page you linked to. Is it possible gradle could ignore an already installed NDK (from Android Rebuilds) and download a non-free Google version on its own, without any heads-up?

Anyway, I will use the debian packages and the Android Rebuild NDK (instead of the official Android version which is non-free). And I’ll definitely try to avoid gradle entirely because it’s too happy to download code and binaries (both for the app and the host os), and even update itself while running. Proper nightmare fuel…

This topic was automatically closed 60 days after the last reply. New replies are no longer allowed.