I’ve been pulling my hair out for the past couple days dealing with Android NDK build sensitivities. I hope this blog posting saves you some time and stress. If it does, you can send me flowers …. or money. Or both. It’s all good.
So, let’s say you have an existing Android NDK project and it works file. It’s complete. You want to add a shared library into the application, but it’s not required to build your application. That is, you need it during runtime, but you don’t need it to build your C/C++ code using NDK.
It should be simple, right, but the documentation for the Android NDK seems to suggest that you have to use LOCAL_MODULE and friends to accomplish this. But you’ll find that can be recipe for disaster. I sure did. It’s been tormenting me for the past several days and I think I finally solved the problem.
This blog presents one way to accomplish this. This is something I just discovered (by spending hours ruling out everything that didn’t work – modifying module definitions in Android.mk files, using APP_MODULES, and setting up module dependencies – you name it, I’ve tried it) which I have not seen explicitly discussed about in the existing android documentation.
The goal is simple. You have an existing NDK project and you want to:
- add a shared library to your Android NDK build that gets packed up into your .apk file. The library is one that is not needed to compile any other C/C++ module in your project. But it’s one that your application will rely upon indirectly. You just need it to be packed with the build.
- Load that library at runtime with a call to
If you read the documentation, you’re going to realize two things: a) the Android NDK build system is built on top of gmake, and b) it relies very heavy on makefile fragments. You’ll see things like this, from PREBUILTS.html (from the Android NDK docs directory):
II. Referencing the prebuilt library in other modules: ------------------------------------------------------ Simply list your prebuilt module's name in the LOCAL_STATIC_LIBRARIES or LOCAL_SHARED_LIBRARIES declaration in the Android.mk of any module that depends on them. For example, a naive example of a module using libfoo.so would be: include $(CLEAR_VARS) LOCAL_MODULE := foo-user LOCAL_SRC_FILES := foo-user.c LOCAL_SHARED_LIBRARIES := foo-prebuilt include $(BUILD_SHARED_LIBRARY)
You might be thinking that your shared library will just be pulled into the build. But then when you run the build you suddenly get linking errors for your application that was working properly before.
You find that not only is your build failing due to linking errors, your shared library is not getting incorporated into the .apk file. That’s what happened in my case.
Here’s Something That Works
I was able to accomplish this without build errors, after several days of fighting with the build, by using the following approach:
1. Do NOT add a module to your Android.mk make files. Leave that out. Apparently (and this is just a guess), you only should define prebuilt shared modules in your build file that your native application actually needs to be linked against.
2. Build your shared library in its own project. Make sure the code is cross-compiled for the platform of Android you want the library to run on. At this point you have two separate, independent projects: Your Android project with native code, and your shared library somewhere on the filesystem.
3. With your native project built, you’re going to see a libs directory at the top level of your project. In that directory, you’ll see something like this:
MyProject/ libs/ armeabi-v7a/ libfromyourndkproject.so
4. Copy your shared library into the directory that has the name of the architecture you’ve compiled it for. So, if you’ve built libfoo-user.so for armeabi, you’ll want something like this;
MyProject libs armeabi-v7a libfromyourndkproject.so libfoo-user.so
With that setup you should see your shared library as part of your apk build file. You can use
jar xvf YourApplicaton.apk
to verify it’s there.
There should be no mysteries, unanswered questions, or undocumented use cases when it comes to something as critical as a build system. Without that, your project can come to an untimely screeching halt.