Let's say we're building a shared library A that needs to link to 2 external static libs B and C. All you've got are libB.a and libC.a, along with their header files.
Here's a simplified Android.mk for libA:
LOCAL_LDLIBS := ../external/libB.a ../external/libC.a
include $(BUILD_SHARED_LIBRARY)
AFAIK, the way linking works for shared libraries is:
- grab all object files of B and C
- strip out object files that A doesn't reference
- resolve references in B and C
This gives link errors because B and C call each other, specifically they call functions that got stripped out in step 2 because A didn't call them.
If we built the static libs ourselves, then it's simply a matter of replacing LOCAL_STATIC_LIBRARIES with LOCAL_WHOLE_STATIC_LIBRARIES, which prevents code stripping (at the expense of code size). Under the hood, it passes --whole-archive to the linker.
Since we didn't build B and C (and don't even have the source to rebuild them), what are the options?
- manually reference the missing functions from A, so that they don't get stripped
- figure out how to pass --whole-archive to the linker for the external static libraries
- use the PREBUILT_STATIC_LIBRARY (seen it mentioned, but never used it, and the according to the docs it doesn't sound applicable in this case)
- build an executable instead of a shared library (which won't strip code the same way)
- move/rename external libs to trick the NDK build system into thinking they're mine, so that I can add them to LOCAL_WHOLE_STATIC_LIBRARIES.
I've gone with option 1 because it's the first thing that worked, but obviously it's not great. I'm asking whether there's a better solution.
The answer to this question ( Linking issue when prebuilt static and shared libraries with the Android NDK ) made me wonder if I need to re-evaluate my build setup (shared library linking to external static library). I'm unable to comment there, so I asked my own question here.
The answer can be found in How to deal with recursive dependencies between static libraries using the binutils linker?.
I took the two-libs NDK sample, and made minimal change to demonstrate the technique on GitHub.
Update (2017): since 2012, the rules of NDK became more strict, and now it will complain that
LOCAL_LDLIBS
contains non-system libraries:This is just a warning, so you can ignore it.
Or add space after
-l
to outsmart the NDK protection:Alternatively, you can use
If the libraries that are involved are not prebuilt, you don't need to guess their location (which may be especially tricky when using Android Studio NDK integration). Use
There exists an alternative approach, which does not use 'recursive' linking. But it involves iterations. First, try to build your shared library the usual way. When this fails with unresolved symbols, copy all these symbols to clipboard, and paste them your Android.mk. Let's say these symbols are
extBa
,extBb
, andextBc
(in the above scenario, I believe that some object of libC does not find these symbols that are defined somewhere in libB, that's why the link fails). What you need now, addYou can make the next step, and have this all bundled with libC:
Now any shared lib that uses libC will not miss these symbols.