Hello World; Heaps on Android

Hello, and welcome.

As there’s no way for you to reasonably know, I built a puzzle game recently – in Haxe, using Heaps which I had only used once before, for a website that required a 3D can. Which may seem strange, but I assure you it made sense at the time. Anyway, Heaps seemed fairly nice, so I figured I should try it again.

But I wanted it to be an Android app.

Which is okay, because Heaps works on Android. It says it right there on the website! Unfortunately, there’s not much info on it beyond that, and compiling Heaps for Android turned out rather less straight forward than I had hoped.

Fast forward five days of debugging Android Studio configurations and C code, and I now have a simple Heaps app running on Android. And it’s on GitHub!


It’s built based on a couple of repos1, 2, the second of which was particularly helpful, but I had to mix and match some things between them.

I don’t intend to keep it up-to-date unless I have a use for it, but it works as of November 11, 2022.

How it works

The Haxe code lives in app/src/main/haxe. It’s a basic Heaps hello world project set up for VS Code, as described in the documentation section of the Heaps site. There’s a compile.hxml file which tells the compiler to place the generated C code in the out/ directory of the cpp folder.

The C code lives in app/src/main/cpp. It contains git submodules to some of the necessary libraries, as well as a CMakeLists.txt. Android Studio uses that during its build process. You can find out more about the other things there at the link, above.

This is also where the JNI function for the heaps app lives (in jni.c).

The Java code lives in app/src/main/java, io.heaps.android.HeapsActivity is the entry point to the Heaps hello world and triggers it to run. It extends org.libsdl.app.SDLActivity which handles a bunch of the SDL stuff. Add your own classes as necessary if you want, I probably won’t!

Each of those directories contains a readme with some info about what they contain.

One important note: The NDK version.

It didn’t work with any of the NDK versions I had installed. I ended up having to download r18b and use that. I placed it in the ndk/ folder of my Android SDK directory. You can find this under File > Project Structure, and then by clicking SDK Location.

So I placed it in C:\Users\Brad\AppData\Local\Android\sdk\ndk.

But that’s not all – apparently Android Studio expects the ndk version directory to be named a certain way, so I named mine 18.1.1.

The Android Studio project in the Git repo expects that, so if you name it something else, update build.gradle to reflect that.

After that it should just be a matter of clicking build in Android Studio.

Problems along the way

As you can imagine from the heading nearby I ran into so many problems along the way. So many problems, and so many android log statements.

But my memory is terrible, and Google found surprisingly few results, so I’m going to catalogue some of them here. You know, for next time. You should be able to ignore this portion, they should all be addressed already in the repo code.

OpenAL needs liblog.so: liblog.so needed by libopenal.so not found.

I tried a bunch of things for this, but the solution turned out to be adding arguments -DANDROID_LD=lld to the app gradle.build file.

hashlink/src/std/types.c error: undefined reference to 'hl_zalloc'

hl_zalloc is defined in hashlink/src/gc.c. I added that to CMakeLists.txt when building the Hashlink library.

fatal error: 'minimp3.h' file not found

Added hashlink/include/minimip3 to the target_include_directories for fmt.hdll, in CMakeLists.txt.

java unsupported major.minor version 52

I updated to Java 1.8.0.

E/EGL_emulation: eglCreateContext: EGL_BAD_CONFIG: no ES 3 support (and a bunch of other SDL / window creation errors)

These seemed to go away when I tracked down that Hashlink uses version 3.0 for mobile, added the appropriate declaration to my AndroidManifest.xml, and fiddled with the settings in the emulator. Honestly I’m not sure what ended up fixing these things because nothing did and then I restarted Android Studio and everything was magically working.

At which point I was just willing to accept that.