How to link a prebuilt shared Library to an Android NDK project?

Here I used this Android.mk file in jni/ folder.

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

# Here we give our module name and source file(s)
LOCAL_MODULE    := offlineDownload
LOCAL_SRC_FILES := offline_download.c

LOCAL_SHARED_LIBRARIES :=../lib/libpackext.so.1.0
LOCAL_LDLIBS := -L$(SYSROOT)/usr/lib -llog

include $(BUILD_SHARED_LIBRARY)

And make one lib folder in project directory and put my prebuilt .so library and make one Android.mk file which contains following

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE    := packext
LOCAL_SRC_FILES := libpackext.so.1.0
LOCAL_C_INCLUDES := $(LOCAL_PATH)/../include

include $(PREBUILT_SHARED_LIBRARY)

And when i use ndk-build -B command than i got undefined reference to packageExtraction. Here I use my prebuilt library functions means I can't link my prebuilt shared library to my offlinedownload library.

So any body please help me to solved out this issue.


Solution 1:

Here is a complete Android.mk file for using a 3rd party shared library. The library (libffmpeg.so) is placed in the jni folder. Its "LOCAL_EXPORT_C_INCLUDES" specifies where the header files are kept for the library.

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)
LOCAL_MODULE := ffmpeg
LOCAL_SRC_FILES := libffmpeg.so
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/../../ffmpeg/libs/arm-linux-androideabi4.7_1/include
include $(PREBUILT_SHARED_LIBRARY)


include $(CLEAR_VARS)
LOCAL_MODULE    := ffmpegandroid
LOCAL_SRC_FILES := ffmpegandroid.c
LOCAL_SHARED_LIBRARIES := ffmpeg
include $(BUILD_SHARED_LIBRARY)

If you wanted to support multiple architectures then you could specify:

APP_ABI := armeabi armeabi-v7a x86 mips

in your jni/Application.mk and change the LOCAL_SRC_FILES to something like:

LOCAL_SRC_FILES := $(TARGET_ARCH_ABI)/libffmpeg.so

and place a libffmpeg.so at jni/armeabi/libffmpeg.so, jni/armeabi-v7a/libffmpeg.so etc ..

Solution 2:

Android NDK official hello-libs CMake example

https://github.com/googlesamples/android-ndk/tree/840858984e1bb8a7fab37c1b7c571efbe7d6eb75/hello-libs

Just worked for me on Ubuntu 17.10 host, Android Studio 3, Android SDK 26, NDK 15.2. so I strongly recommend that you base your project on it.

The shared library is called libgperf, the key code parts are:

  • hello-libs/app/src/main/cpp/CMakeLists.txt:

    // -L
    add_library(lib_gperf SHARED IMPORTED)
    set_target_properties(lib_gperf PROPERTIES IMPORTED_LOCATION
              ${distribution_DIR}/gperf/lib/${ANDROID_ABI}/libgperf.so)
    
    // -I
    target_include_directories(hello-libs PRIVATE
                               ${distribution_DIR}/gperf/include)
    // -lgperf
    target_link_libraries(hello-libs
                          lib_gperf)
    
  • on C++ code, use: #include <gperf.h>

  • header location: hello-libs/distribution/gperf/include/gperf.h

  • lib location: distribution/gperf/lib/arm64-v8a/libgperf.so

  • app/build.gradle:

    android {
        sourceSets {
            main {
                // let gradle pack the shared library into apk
                jniLibs.srcDirs = ['../distribution/gperf/lib']
    

    Then, if you look under /data/app on the device, libgperf.so will be there as well.

  • If you only support some architectures, see: Gradle Build NDK target only ARM

The example git tracks the prebuilt shared libraries, but it also contains the build system to actually build them as well: https://github.com/googlesamples/android-ndk/tree/840858984e1bb8a7fab37c1b7c571efbe7d6eb75/hello-libs/gen-libs

Solution 3:

You have to do either one of the following:

  1. Cut and paste everything except LOCAL_PATH := $(call my-dir) from your second Android.mk into your first.

  2. Put the following in the end of your first Android.mk:

    $(call import-module,packext)

    Also make sure that you set your NDK_MODULE_PATH environment variable to a path where the Android.mk-file defining the module packext can be found.

You also have to change the LOCAL_SHARED_LIBRARIES in the same way mgiza said in the first answer. I suppose the packageExtraction that you got undefined reference to is in your prebuilt library so unless you have other linking problems this should solve the issue.