• After 15+ years, we've made a big change: Android Forums is now Early Bird Club. Learn more here.

Apps JNI/NDK Difficulty linking libraries

djc6535

Lurker
Nov 26, 2009
8
0
I am writing an android app that wants to make JNI calls into a shared library built in using the NDK. The trick is this shared library calls functions provided by OTHER shared libraries. The other shared libraries are C libraries that have been compiled elsewhere.

Here's what I've tried:

**My Environment:**
I'm working in Eclipse. I've added native support and have a jni library. In that library I have my code and a \lib directory where I have copied my other .so files.

**Attempt #1 Android.mk: Just telling it where the libs are**

Code:
    LOCAL_PATH := $(call my-dir)
    include $(CLEAR_VARS)
    
    LOCAL_MODULE           := native_lib
    LOCAL_SRC_FILES        := native_lib.cpp

    LOCAL_LDLIBS := -L$(SYSROOT)/../usr/lib -llog
    LOCAL_LDLIBS += -L$(LOCAL_PATH)/lib/support_lib1
    LOCAL_LDLIBS += -L$(LOCAL_PATH)/lib/support_lib2

    include $(BUILD_SHARED_LIBRARY)

This builds just fine, but when I try to run I get errors indicating that dlopen(libnative_lib) failed because it couldn't load libsupport_lib1.

Then I found this:


android - Can shared library call another shared library? - Stack Overflow

which said that I needed to call load library on all necessary libraries. Great!

**Attempt #2 Opening each library first**

Code:
    static {
        System.loadLibrary("support_lib1");
        System.loadLibrary("support_lib2");
        System.loadLibrary("native_lib");
    }

Again, this builds just fine, however when I run I get a new error:

couldn't load libsupport_lib1. findLibrary returned null.

Now we're getting somewhere. It must not be loading the libraries over to the target.

**Attempt #3 Copying .so files into project/libs/armeabi**

Didn't work. When Eclipse builds it deleted the files I dropped in there.

**Attempt #4 Creating a new module for each library**

So then I found this:

linker - Android NDK: Link using a pre-compiled static library - Stack Overflow

It's about static libraries, but maybe I am having a similar problem. The gist is that I need to declare a module for each library. So my new Android.mk looks like this:

Code:
    LOCAL_PATH := $(call my-dir)

    #get support_lib1
    include $(CLEAR_VARS)
    LOCAL_MODULE           := support_lib1
    LOCAL_SRC_FILES        := $(LOCAL_PATH)/lib/support_lib1.so
    include $(BUILD_SHARED_LIBRARY)

    #get support_lib2
    include $(CLEAR_VARS)
    LOCAL_MODULE           := support_lib2
    LOCAL_SRC_FILES        := $(LOCAL_PATH)/lib/support_lib2.so
    include $(BUILD_SHARED_LIBRARY)

    #build native lib
    include $(CLEAR_VARS)    
    LOCAL_MODULE           := native_lib
    LOCAL_SRC_FILES        := native_lib.cpp

    LOCAL_LDLIBS := -L$(SYSROOT)/../usr/lib -llog
    LOCAL_LDLIBS += -L$(LOCAL_PATH)/lib/support_lib1
    LOCAL_LDLIBS += -L$(LOCAL_PATH)/lib/support_lib2

    include $(BUILD_SHARED_LIBRARY)

This builds! Even better, armeabi has the sos now! Even *BETTER* I get the following messages when I try to run it (telling me that support_lib1 and 2 were opened by LoadLibrary:

Trying to load lib /data/app-lib/com.example.tst/libsupport_lib1.so
added shared lib /data/app-lib/com.example.tst/libsupport_lib1.so
no JNI_OnLoad found in /data/app-lib/com.example.tst/libsupport_lib1.so, skipping init


but then...
dlopen failed: Could not locate symbol func_that_exists_in_libsupport_lib.so referenced by libnative_lib.so

**Edit: Attempt 5: Use PREBUILT_SHARED_LIBRARY**

So I found this:
c - How can i Link prebuilt shared Library to Android NDK project? - Stack Overflow

which seems to be exactly what I'm asking. Their answer seems to be 'don't use 'build_shared_library' but instead 'use PREBUILT_SHARED_LIBRARY

Okay, let's try.

Code:
     LOCAL_PATH := $(call my-dir)

    #get support_lib1
    include $(CLEAR_VARS)
    LOCAL_MODULE           := support_lib1
    LOCAL_SRC_FILES        := $(LOCAL_PATH)/lib/support_lib1.so
    include $(PREBUILT_SHARED_LIBRARY)

    #get support_lib2
    include $(CLEAR_VARS)
    LOCAL_MODULE           := support_lib2
    LOCAL_SRC_FILES        := $(LOCAL_PATH)/lib/support_lib2.so
    include $(PREBUILT_SHARED_LIBRARY)

    #build native lib
    include $(CLEAR_VARS)    
    LOCAL_MODULE           := native_lib
    LOCAL_SRC_FILES        := native_lib.cpp

    LOCAL_LDLIBS := -L$(SYSROOT)/../usr/lib -llog
    LOCAL_SHARED_LIBRARIES := support_lib1 support_lib2

    include $(BUILD_SHARED_LIBRARY)

Build... fails! The build complains about missing symbols now.

**Edit: Attempt 6: Flatten everything**

So I went back to the prebuilts documentation in the NDK. It says:

Each prebuilt library must be declared as a single independent module to the build system. Here is a trivial example where we assume that the file "libfoo.so" is located in the same directory than the Android.mk below:

Code:
    LOCAL_PATH := $(call my-dir)

    include $(CLEAR_VARS)
    LOCAL_MODULE := foo-prebuilt
    LOCAL_SRC_FILES := libfoo.so
    include $(PREBUILT_SHARED_LIBRARY)

Notice that, to declare such a module, you really only need the following:

Give the module a name (here 'foo-prebuilt'). This does not need to correspond to the name of the prebuilt library itself.

Assign to LOCAL_SRC_FILES the path to the prebuilt library you are providing. As usual, the path is relative to your LOCAL_PATH.

Include PREBUILT_SHARED_LIBRARY, instead of BUILD_SHARED_LIBRARY, if you are providing a shared, library. For static ones, use PREBUILT_STATIC_LIBRARY.
A prebuilt module does not build anything. However, a copy of your prebuilt shared library will be copied into $PROJECT/obj/local, and another will be copied and stripped into $PROJECT/libs/<abi>.


So let's try flattening everything out to match the trivial example. I copied my libraries out of their cozy /lib folder and put them in the jni root. I then did this:

Code:
     LOCAL_PATH := $(call my-dir)

    #get support_lib1
    include $(CLEAR_VARS)
    LOCAL_MODULE           := support_lib1
    LOCAL_SRC_FILES        := support_lib1.so
    include $(PREBUILT_SHARED_LIBRARY)

    #get support_lib2
    include $(CLEAR_VARS)
    LOCAL_MODULE           := support_lib2
    LOCAL_SRC_FILES        := support_lib2.so
    include $(PREBUILT_SHARED_LIBRARY)

    #build native lib
    include $(CLEAR_VARS)    
    LOCAL_MODULE           := native_lib
    LOCAL_SRC_FILES        := native_lib.cpp

    LOCAL_LDLIBS := -L$(SYSROOT)/../usr/lib -llog
    LOCAL_SHARED_LIBRARIES := support_lib1 support_lib2

    include $(BUILD_SHARED_LIBRARY)
and... same error. Moreover I'm most definitely NOT seeing library files getting copied to $PROJECT/obj/local.


sooooo.... now what?
 

BEST TECH IN 2023

We've been tracking upcoming products and ranking the best tech since 2007. Thanks for trusting our opinion: we get rewarded through affiliate links that earn us a commission and we invite you to learn more about us.

Smartphones