Android NDK/JNI: Building a shared library that depends on other shared libraries

后端 未结 3 486
走了就别回头了
走了就别回头了 2021-02-01 06:29

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

相关标签:
3条回答
  • 2021-02-01 07:09

    The -L option gives the linker a directory path in which to look for libraries. The -l option gives the linker a library file name to link in. Library file names must begin with "lib". Your libraries should be named libsupport_lib1.so and libsupport_lib2.so. If you do that, then this is probably what you should do (replacing attempt #1):

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

    The linker will prefix the library name you specify using -l with "lib" and suffix it with ".so". (Why do you have -L$(SYSROOT)/../usr/lib?)

    I believe that attempts #1 and #2 failed because you did not link your libraries into your executable - they are not mentioned in a -l option. By the way, you can verify this yourself. Unzip the .apk file and look in the lib directory and subdirectories. Are your .so files in there?

    Looking at the error:

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

    Can you supply the entire message? dlopen() loads and links libraries into the running process.

    0 讨论(0)
  • 2021-02-01 07:10

    Not sure if this is exactly where you are at, but here's what I know about these sorts of things.

    1. Make each prebuilt libary its own separate Makefile. Multiple targets in Android.mk tends to get wonky. Sad.
    2. Include each make file using $(call import-add-path) and $(call import-module)
    3. Export as much as you can from the prebuilt's make files, using the LOCAL_EXPORT_ family of variables.

    Prebuilt Shared Library Android.mk

    LOCAL_PATH := $(call my-dir)
    
    include $(CLEAR_VARS)
    
    LOCAL_MODULE := my_module_name
    
    MY_LIBRARY_NAME := shared_library_name
    
    ### export include path
    LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/include
    
    ### path to library
    LOCAL_SRC_FILES := libs/$(TARGET_ARCH_ABI)/lib$(MY_LIBRARY_NAME).so
    
    ### export dependency on the library
    LOCAL_EXPORT_LDLIBS := -L$(LOCAL_PATH)/libs/$(TARGET_ARCH_ABI)/
    LOCAL_EXPORT_LDLIBS += -l$(MY_LIBRARY_NAME)
    
    include $(PREBUILT_SHARED_LIBRARY)
    

    This is assuming that the prebuilt libaries live in a dir structure like this

    + SharedProjectFolderName
    +--- Android.mk
    +--- include/
    +-+- libs/$(TARGET_ARCH_ABI)/
      |- libshared_library_name.so
    

    If you are not building for multiple ABI, I guess you can leave that bit out

    The Project's Android.mk

    LOCAL_PATH := $(call my-dir)
    
    include $(CLEAR_VARS)
    
    LOCAL_MODULE := my_jni_module
    
    ## source files here, etc...
    
    ### define dependency on the other library
    LOCAL_SHARED_LIBRARIES := my_module_name
    
    include $(BUILD_SHARED_LIBRARY)
    
    $(call import-add-path,$(LOCAL_PATH)/path/to/myLibraries/)
    $(call import-module,SharedProjectFolderName)
    $(call import-module,AnotherSharedProject)
    

    I recommend you put all shared libraries in one folder. When you say $(call import-module,SharedProjectFolderName) it looks for a folder containing an Android.mk along the search path you told it (import-add-path)

    By the way, you probably shouldn't specify LOCAL_LDLIBS := -L$(SYSROOT)/../usr/lib. It should be finding the proper libs from NDK by itself. Adding more linker paths will probably confuse it. The proper way is to export the linker paths as flags from the sub-modules.

    ALSO, you can use ndk-build V=1 to get a ton of info on why it can't find paths, etc

    0 讨论(0)
  • 2021-02-01 07:22

    Your problem is with the naming convention. NDK and Android insist on the shared library names to always begin with lib. Otherwise, the libraries will not be linked properly, and not copied to the libs/armeabi folder properly, and not installed on the device (copied to /data/data/package/lib directory properly.

    If you rename support_lib1.so to libsupport_1.so and support_lib2.so to libsupport_2.so, and put these two files in jni/lib directory, then your Attempt #5 will work with minor change:

    LOCAL_PATH := $(call my-dir)
    
    #get support_lib1
    include $(CLEAR_VARS)
    LOCAL_MODULE           := support_lib1
    LOCAL_SRC_FILES        := lib/libsupport_1.so
    include $(PREBUILT_SHARED_LIBRARY)
    
    #get support_lib2
    include $(CLEAR_VARS)
    LOCAL_MODULE           := support_lib2
    LOCAL_SRC_FILES        := lib/libsupport_2.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)
    

    BTW, I don't think you need this -L$(SYSROOT)/../usr/lib.

    PS Don't forget to update the Java side, too:

    static {
        System.loadLibrary("support_lib1");
        System.loadLibrary("support_lib2");
        System.loadLibrary("native_lib");
    }
    
    0 讨论(0)
提交回复
热议问题