You learn something new every day.
I have a bunch of dynamic libraries that implement the native methods of the Classpath reference implementation classes. These libraries refer to Vajra internals via header files. Problem is, you not only need these header files, but also the implementation files while building the .so file.
Not having used shared libraries that extensively (from a development perspective, that is), this was news to me. I thought it was enough for the code calling a function in the library to be linked to the class definition object file and the function will resolve the symbol from this (both share the same address space, after all).
Anyway, I discovered this by using valgrind. valgrind, in addition to checking memory leaks, uninitialised pointers, etc., also shows the above class of errors (undefined symbol in .so file). Such errors are not always reported in such a straightforward way when the program is run without valgrind; you only get segmentation faults or illegal instructions, making it harder to pinpoint the problem.