Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
578 views
in Technique[技术] by (71.8m points)

build - Android NDK - make two native shared libraries calling each other

Wasted half a day trying to build two shared libraries, e.g. mod1 and mod2 (which Android NDK compiles to libmod1.so and libmod2.so), from sources in a jni folder and sub-folders, then have mod1 call a function from mod2. Plenty of answers on how to make the build work, but then runtime dynamic linking was not working, the app crashed on startup.

Decided to post this question and immediately answer it, so that Q and A to the whole process are together, and hopefully someone else won't waste a day researching it again.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...