I have just this very second got the subject of this post working after tearing my hair out for much longer than I'd rather admit. In this post I will try to explain how to build a set of projects that depend on each other in to a shared object library.
I'd like to take this chance to note to this group my findings so that others may have an easier time. Some of this information should also be relevant to people building with the full ndk environment and not just the standalone toolchain.
So to start, if you are trying to create a .so file that will load in other .so files that it depends on then don't, not unless the .so you want to depend on is a system one. If you intend to create a chain of .so files that will depend and load in each other, don't. You may be in this situation if you want to just run auto conf tools like configure scripts and libtool that come with many projects to create a shared object. If you want to go down this route you will be in for heartache. I'll outline the problems in case you really think you have to go down this route, but believe me unless you have very good reason to then don't.
The first problem is that configure scripts will name a shared object with a version number, ala libshared.so.3.2 if you run readelf -d on a shared object you have created then you will see that the name will have the version number in it, which I believe android will have problems with. You can get round this by changing the value of soname_spec in the configure script.
The second issue is that the rpath, used to find other shared objects will he hardcoded in to your shared object, this makes is very hard to find other shared objects. You can remove rpath by getting rif of LD_RUN_PATH and rpath references in the configure script, but even then when you load your shared object on android, the android kernel will not look in the current directory for other shared objects, which is where your other shared objects will be. You can hardcode the rpath to point to where you know the so files are, but DONT! That path could change on any new device. The way around this path is when you load your shard object with System.loadLibrary("mylib") you should first load any other libs you depend on, e.g. System.loadLibrary("otherLib") as loadLibrary will look in the default library path for your app, which is the only chance you get to load from that path. Of course this will mean that all your libs will need a JNI_OnLoad, which is a pain.
Enough you say, I want to know what I should do. Well you should statically link all your archives together.
Here's my cook-book to do this.
1) Get the latest ndk, this supports standalone toolchains, read the standalone doc and create your own toolchain. It's very simple.
2) Configure up your build scripts. You can either go with what seems right for your project or use the build flags that ndk uses. You can find these out by setting export V=1 in your shell and building one of the sample ndk projects. This will show you all the build steps and allow you to extract the config you need to merge in to your project.
Here's an example of one I have used.
export NDK_ROOT=/tmp/myToolChain
export PATH=${NDK_ROOT}/bin:${PATH}
export LDFLAGS="-Wl,--no-undefined -Wl,-z,noexecstack -Wl,--fix-cortex-a8,--entry=main,-rpath-link=${NDK_ROOT}/sysroot/usr/lib"
export CFLAGS="-Os -fomit-frame-pointer -fno-strict-aliasing -finline-limit=64 -Wa,--noexecstack -Wno-psabi -march=armv5te -mtune=xscale -msoft-float -mthumb -mandroid -nostdlib -fpic -ffunction-sections -funwind-tables -fstack-protector -D__ARM_ARCH_5__ -D__ARM_ARCH_5T__ -D__ARM_ARCH_5E__ -D__ARM_ARCH_5TE__ "
export LIBS="-lc -lm -lgcc -llog -lstdc++ -lz"
./configure --host=arm-gnu
LDFLAGS + LIBS are not important but nice for completeness. I use arm-gnu as the host to invoke a cross-compile you could try other targets, YMMV. -build=arm-eabi can also be useful
3) Use this to build all your projects. You will need to add your JNI_OnLoad source in to one of the projects source tree and Makefile.in
4) At this point you will probably have a load of .so files, but you don't want them, you want the .a files used to create them. You are going to use them to create one shared object. I like to copy them to one directory and link them from there ala find . -name "*.a" -exec cp {} /tmp/archives {} \;
5) Now link them all in to one .so. Again I would use the link command that the sample ndk project uses, from your archive directory do something like
arm-linux-androideabi-g++ -shared -o libmylib.so -Wl,-soname,libmylib.so -Wl,--whole-archive *.a -Wl,--no-whole-archive -lsupc++ -llog -Wl,--no-undefined -Wl,-z,noexecstack
6) And that's it. To save you some heartache I would try linking your lib with some system libs to see if there are any unresolved symbols or any other system libs you need to link in. If you need any system libs then add them as -l<lib> in step 5. To try out a test link then follow the arm-eabi-ld step at
http://mpigulski.blogspot.com/2010/09/debugging-dlopen-unsatisfiedlinkerror.html This could save you a lot of time. The strace tip is also valuable.
Hopefully this will help someone and if not at least it's a reminder for me to lookup.
I'd appreciate any comments and corrections.
Wil