Android NDK - make two native shared libraries calling each other

前端 未结 1 477
隐瞒了意图╮
隐瞒了意图╮ 2020-12-14 08:50

Wasted half a day trying to build two shared libraries, e.g. mod1 and mod2 (which Android NDK compiles to libmod1.so and libmod2

相关标签:
1条回答
  • 2020-12-14 09:53

    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

    0 讨论(0)
提交回复
热议问题