The correct build procedure was relatively easy, my problem was that making libmod1.so dependent on libmod2.so caused unsatisfied links upon startup - mod1 code could not find mod2 shared library, even though both were present within the same folder in the final APK, under libs/armeabi, libs/x86 etc. However, to make my answer complete:
Put your C or C++ sources and header files under sub-directories of jni dir in your Android project, e.g. folders mod1/ and mod2/
Per NDK instructions, create Application.mk file, e.g. mine is:
NDK_TOOLCHAIN_VERSION=4.7
APP_PLATFORM := android-8
APP_ABI := armeabi armeabi-v7a x86
- Create Android.mk following this template:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_SHARED_LIBRARIES := mod2 # this makes libmod1.so dependent on libmod2.so
LOCAL_MODULE := mod1
LOCAL_SRC_FILES := mod1/file1.c
LOCAL_SRC_FILES += mod1/file2.cpp
...
include $(BUILD_SHARED_LIBRARY) # this actually builds libmod1.so
include $(CLEAR_VARS)
LOCAL_MODULE := mod2
LOCAL_SRC_FILES := mod2/file1.cc
LOCAL_SRC_FILES += mod2/file2.cc
...
include $(BUILD_SHARED_LIBRARY) # this builds libmod2.so
That's about it, all builds without complains with ndkbuild script. You only need a C wrapper to call some functions from Java. And here was my problem. Since I had functions callable from Java only in libmod1.so, my C wrapper class in Java was like:
public class CWrapper {
static {
System.loadLibrary("mod1");
}
public static native int func1(String aParam);
...
}
This seemed perfectly logical to me - I call to libmod1.so from Java, so I used System.loadLibrary("mod1"), and since libmod1.so knows it depends on libmod2.so, and both files are in the same folder, libmod1 will know how to find and load libmod2, right? Wrong! It was crashing upon app startup with "unsatisfied link". The exact error message was:
java.lang.UnsatisfiedLinkError: Cannot load library: soinfo_link_image(linker.cpp:1635): could not load library "libmod2.so" needed by "libmod1.so"; caused by load_library(linker.cpp:745): library "libmod2.so" not found
I was searching everywhere for some more code to add to Android.mk to resolve this in vain. Finally Eureka! I modified my CWrapper class as follows:
public class CWrapper {
static {
System.loadLibrary("mod2"); // must be first, as mod1 depends on mod2!
System.loadLibrary("mod1");
}
public static native int func1(String aParam);
...
}
and things started working like a charm...
Greg
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…