Android NDK编译中在libs\armeabi中加入第三方so库文件的方法

假设要加入库文件的名字为libffmpeg.so文件

1.要在project\jni目录下新建一目录prebuilt,把libffmpeg.so文件copy到project\jni\prebuilt中,并在目录project\jni\prebuilt中添加文件Android.mk,内容如下:

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE := ffmpeg

LOCAL_SRC_FILES := libffmpeg.so

include $(PREBUILT_SHARED_LIBRARY)

2.在project\jni目录下的Android.mk文件中加入

LOCAL_SHARED_LIBRARIES := ffmpeg

并在末尾加入

include $(LOCAL_PATH)/prebuilt/Android.mk

一般模板的写法如下:


Android NDK about Library (static library , share library and 3rd party library)

A:Static library

文件Android.mk:

LOCAL_PATH := $(call my-dir)include $(CLEAR_VARS)LOCAL_MODULE := hello-jniLOCAL_SRC_FILES := hello-jni.cinclude $(BUILD_STATIC_LIBRARY)

文件Application.mk:

APP_MODULES :=hello-jni

B: Share library

文件Android.mk:

LOCAL_PATH := $(call my-dir)include $(CLEAR_VARS)LOCAL_MODULE := hello-jniLOCAL_SRC_FILES := hello-jni.cinclude $(BUILD_SHARED_LIBRARY)

C: Static library+Share library

文件Android.mk:

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)LOCAL_MODULE := mylib_staticLOCAL_SRC_FILES := src.cinclude $(BUILD_STATIC_LIBRARY)

include $(CLEAR_VARS)LOCAL_MODULE := mylib_sharedLOCAL_SRC_FILES := src2.c

LOCAL_STATIC_LIBRARIES := mylib_static

include $(BUILD_SHARED_LIBRARY)

D:Using 3rd party library

文件Android.mk:

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)LOCAL_MODULE := thirdlib1 # name it whateverLOCAL_SRC_FILES := $(TARGET_ARCH_ABI)/libthird1.a # or $(so_path)/libthird1.so#LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/includeinclude $(PREBUILT_STATIC_LIBRARY) #or PREBUILT_SHARED_LIBRARY

include $(CLEAR_VARS)LOCAL_MODULE := mylib_use_thirdlibLOCAL_SRC_FILES := src.c

LOCAL_STATIC_LIBRARIES := thirdlib1 #or LOCAL_SHARED_LIBRARY

include $(BUILD_SHARED_LIBRARY) #if static lib,need Application.mk(needn't,I have cheked!)


  When I use the static library ,I always got the undefined reference to** error no matter what I do.After a whole tough day,I found that it's not the problem of the mk file,it's the library!Holy Shit!!

  My static library was built in cygwin of windows.Of course it can't be used in Linux!!!!Then I built it with android ndk tool and it runs perfectly!!!

 a. check your library's mode (whether it isARM)

$ file libtest.solibtest.so: ELF 32-bit LSB shared object, ARM, version 1 (SYSV), dynamically linked, not stripped

   make sure you library is ARM mode.

b. use nm to view the method of the so file

$ nm libtutorial.so |grep T00001344 a _GLOBAL_OFFSET_TABLE_000002a8 T getinformation000002b4 T getinformation2

To use android ndk tool:http://stackoverflow.com/questions/7403036/compile-library-for-android-ndk

 

//@Android.mk  //静态库的编写

 

LOCAL_PATH:= $(call my-dir)

 

include $(CLEAR_VARS)

 

LOCAL_PRELINK_MODULE := false

LOCAL_ARM_MODE := arm

 

LOCAL_SRC_FILES:= /

 

   aa.c bb.c dd.c /

 

LOCAL_SHARED_LIBRARIES := /

 

  dd ee ff /

 

LOCAL_C_INCLUDES += /

        $(LOCAL_PATH)/../inc

 

LOCAL_CFLAGS += -MD /

 

-FF -Uarm -DMODULE -D__LINUX_ARM_ARCH__=7 /

 

LOCAL_MODULE:= libMyStaticLib

 

include $(BUILD_STATIC_LIBRARY)

 

//静态库生成后的文件是libMyStaticLib.a

 

//@Android.mk  //动态库的编写

 

LOCAL_PATH:= $(call my-dir)

 

include $(CLEAR_VARS)

 

LOCAL_PRELINK_MODULE := false

LOCAL_ARM_MODE := arm

 

LOCAL_SRC_FILES:= /

 

   aa.c bb.c dd.c /

 

LOCAL_SHARED_LIBRARIES := /

 

  dd ee ff /

 

LOCAL_C_INCLUDES += /

        $(LOCAL_PATH)/../inc

 

LOCAL_CFLAGS += -MD /

 

-FF -Uarm -DMODULE -D__LINUX_ARM_ARCH__=7 /

 

LOCAL_MODULE:= libMyShareLib

 

include $(BUILD_SHARED_LIBRARY)

 

//动态库生成后的文件是libMyShareLib.so

 

 

实例教程如下:

例1:JNI程序使用libhello-jni.so的符号。

libhello-jni.so由hello-jni.c组成。

 

hello-jni.c如下:

 

#include

#include

#include

 

 

 

#define  LOG_TAG    "libhello-jni"

#define  LOGE(...)  __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__)

 

void Java_com_example_hellojni_HelloJni_functionA(JNIEnv* env, jobject thiz)

{

LOGE("SamInfo: Enter Native functionA");

return;

}

 

Android.mk如下:

LOCAL_PATH := $(call my-dir)

 

include $(CLEAR_VARS)

 

LOCAL_MODULE    := hello-jni

LOCAL_SRC_FILES := hello-jni.c

LOCAL_LDLIBS := -llog

 

include $(BUILD_SHARED_LIBRARY)

 

../../../ndk-build -B V=1

 

可以正常编译,再使用Eclipse编译Android工程,可正常运行。

 

例2:JNI程序使用libhello-jni.so的符号。

libhello-jni.so由hello-jni.c,hell-jniB.c,头文件hello-jni.h组成。

 

hello-jni.h如下:

#ifndef _HELLO_JNI_H

#define _HELLO_JNI_H

 

#include

#include

#include

 

#define  LOG_TAG    "libhello-jni"

#define  LOGE(...)  __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__)

 

#endif

 

hello-jni.c如下:

#include "hello-jni.h"

 

void Java_com_example_hellojni_HelloJni_functionA(JNIEnv* env, jobject thiz)

{

LOGE("SamInfo: Enter Native functionA");

return;

}

 

hell-jniB.c如下:

#include "hello-jni.h"

 

 

void Java_com_example_hellojni_HelloJni_functionB(JNIEnv* env, jobject thiz)

{

LOGE("SamInfo: Enter Native functionB");

return;

}

 

Android.mk如下:

LOCAL_PATH := $(call my-dir)

 

include $(CLEAR_VARS)

 

LOCAL_MODULE    := hello-jni

LOCAL_SRC_FILES := hello-jni.c hell-jniB.c

 

LOCAL_LDLIBS := -llog

 

 

include $(BUILD_SHARED_LIBRARY)

 

注意:LOCAL_SRC_FILES := hello-jni.c hell-jniB.c

此模块hello-jni由两个C文件组成,因为hello-jni.h只是依赖文件,所以不必加入。

又因为hello-jni.h在project/jni目录中,此目录本身为-I,所以也不用再Android.h中指出。

 

 

 

例3:JNI程序使用libhello-jni.so的符号。

libhello-jni.so依赖于libB.a.

libhello-jni.so由hello-jni.c,hell-jniB.c,头文件hello-jni.h组成。

libB.a由libstatic/B1.c,libstatic/B2.c头文件libstatic/B.h组成。

 

B.h 如下:

#ifndef _B_H

#define _B_H

 

#include

#include

#include

 

int iFunctionB1();

int iFunctionB2();

 

#define  LOG_TAG    "libStatic"

#define  LOGI(...)  __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__)

 

#endif

 

B1.c:

#include "B.h"

 

 

int iFunctionB1()

{

LOGI("SamInfo: Enter static function iFunctionB1()");

return 0;

}

 

B2.c

#include "B.h"

 

 

int iFunctionB2()

{

LOGI("SamInfo: Enter static function iFunctionB2()");

return 0;

}

 

 

 

hello-jni.h:

#ifndef _HELLO_JNI_H

#define _HELLO_JNI_H

 

#include

#include

#include

 

#include "libstatic/B.h"

 

#define  LOG_TAG    "libhello-jni"

#define  LOGE(...)  __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__)

 

 

#endif

 

 

hello-jni.c:

 

#include "hello-jni.h"

 

void Java_com_example_hellojni_HelloJni_functionA(JNIEnv* env, jobject thiz)

{

LOGE("SamInfo: Enter Native functionA");

iFunctionB1();

return;

}

 

 

hell-jniB.c:

#include "hello-jni.h"

 

 

void Java_com_example_hellojni_HelloJni_functionB(JNIEnv* env, jobject thiz)

{

LOGE("SamInfo: Enter Native functionB");

iFunctionB2();

return;

}

 

 

 

Android.mk如下:

LOCAL_PATH := $(call my-dir)

 

 

include $(CLEAR_VARS)

 

LOCAL_MODULE    := hello-B

LOCAL_SRC_FILES := libstatic/B1.c libstatic/B2.c

 

include $(BUILD_STATIC_LIBRARY)

 

 

 

 

include $(CLEAR_VARS)

 

LOCAL_MODULE    := hello-jni

LOCAL_SRC_FILES := hello-jni.c hell-jniB.c

LOCAL_STATIC_LIBRARIES := hello-B

LOCAL_LDLIBS := -llog

 

include $(BUILD_SHARED_LIBRARY)

 

这就是典型的一个Android.mk中包含2个Modules的例子。其中一个是产生静态库,另一个产生动态库。

动态库依赖于静态库。(一定要添加 LOCAL_STATIC_LIBRARIES := hello-B ,否则不生成静态库)

 

 

 

例4:JNI程序使用libA.so(由A1.c,A2,c,A.h组成)

libA.so依赖于libB.so(由B1.c,B2.c,B.h组成)

 

情况分析:

因为libB.so被libA.so使用。所以肯定要加入:

LOCAL_LDLIBS := -L$(LOCAL_PATH)/../libs/armeabi/   -lhello-B

 

但请注意:此时libA.so中所用到的libB.so 的符号只是一个空穴。并为将实现加进来。

 

而如果使用:

LOCAL_SHARED_LIBRARIES := hello-B

也仅仅是将libhello-B.so 添加进编译选项。并未将符号添加进去。

 

在Linux下,此类情况可以将动态库放置于某个目录下,然后使用export LD_LIBRARY_PATH 来解决。但Android下并无此方法。导致运行时会找不到libhello-B.so中的符号。

 

 

针对此类情况,有两种方法,但都不是特别好用。分别描述如下:

 

方法1.

将libhello-B.so放置于/system/lib下。

且Android.mk如下:

LOCAL_PATH := $(call my-dir)

 

 

include $(CLEAR_VARS)

 

LOCAL_MODULE    := hello-B

LOCAL_SRC_FILES := libstatic/B1.c libstatic/B2.c

LOCAL_LDLIBS := -llog

include $(BUILD_SHARED_LIBRARY)

 

 

 

 

include $(CLEAR_VARS)

 

LOCAL_MODULE    := hello-jni

LOCAL_SRC_FILES := hello-jni.c hell-jniB.c

#LOCAL_SHARED_LIBRARIES := hello-B

LOCAL_LDLIBS := -llog  -L$(LOCAL_PATH)/../libs/armeabi/   -lhello-B

 

include $(BUILD_SHARED_LIBRARY)

 

此Android.mk有两个模块,分别产生libhello-B.so, libhello-jni.so. 后者依赖于前者。

 

而因为Java层程序使用:System.loadLibrary("hello-jni");

则libhello-jni.so的符号加入到Java应用程序中。而它使用到的libhello-B.so,则能够在/system/lib下找到。

 

 

方法2. 将libhello-B.so也添加如Java程序中。且放置于hello-jni之前。

System.loadLibrary("hello-B");

System.loadLibrary("hello-jni");

 

 

方法3:

可以使用dlopen()方式调用。

 据说使用-rpath可以指定应用程序查找库的目录。但Sam觉得理论上并不可能(因为Java无法指定Wl,-rpath).也没有尝试出来。

 

 

 

 

例5:JNI程序使用libA.so(由A1.c A2.c, A.h组成)

libA.so依赖于libB.so(由B1.c, B2.c, B.h组成)

libB.so依赖于libC.so(由c.c组成)和libD.a(由d.c组成)

libC.so依赖于libD.a (由d.c组成)

 

 

Android.mk:

LOCAL_PATH := $(call my-dir)

 

 

include $(CLEAR_VARS)

 

LOCAL_MODULE    := hello-B

LOCAL_SRC_FILES := libstatic/B1.c libstatic/B2.c

LOCAL_STATIC_LIBRARIES := D

LOCAL_LDLIBS := -llog -lC -L$(LOCAL_PATH)/../libs/armeabi/

include $(BUILD_SHARED_LIBRARY)

 

 

 

 

include $(CLEAR_VARS)

 

LOCAL_MODULE    := hello-jni

LOCAL_SRC_FILES := hello-jni.c hell-jniB.c

#LOCAL_SHARED_LIBRARIES := hello-B

LOCAL_LDLIBS := -llog  -L$(LOCAL_PATH)/../libs/armeabi/   -lhello-B

include $(BUILD_SHARED_LIBRARY)

 

 

include $(CLEAR_VARS)

LOCAL_MODULE    := C

LOCAL_SRC_FILES := c.c

LOCAL_LDLIBS := -llog

LOCAL_STATIC_LIBRARIES := D

include $(BUILD_SHARED_LIBRARY)

 

 

include $(CLEAR_VARS)

LOCAL_MODULE    := D

LOCAL_SRC_FILES := d.c

LOCAL_LDLIBS := -llog

include $(BUILD_STATIC_LIBRARY)

 

 

 

请注意:如此写法:则libD.a中的符号分别被:libC.so, libB.so两次引用。

 

 

 

例6: JNI程序使用libA.so(由A1.c A2.c, A.h组成)

并引用外部生成的:libE.so, libF.a.

 

Sam:经常发生这样的情况,某NDK工程A生成一个动态库,供另一个NDK工程B使用。我们常把此动态库放到B工程的lib/armeabi下。 但ndk-build时,它会首先删除lib/armeabi下所有.so文件。

所以可以使用 PREBUILT_SHARED_LIBRARY

Android.mk:

LOCAL_PATH := $(call my-dir)

 

 

include $(CLEAR_VARS)

 

LOCAL_MODULE    := hello-B

LOCAL_SRC_FILES := libstatic/B1.c libstatic/B2.c

LOCAL_SHARED_LIBRARIES := prelib

 

LOCAL_LDLIBS := -llog

include $(BUILD_SHARED_LIBRARY)

 

 

 

 

include $(CLEAR_VARS)

 

LOCAL_MODULE    := hello-jni

LOCAL_SRC_FILES := hello-jni.c hell-jniB.c

#LOCAL_SHARED_LIBRARIES := hello-B

LOCAL_LDLIBS := -llog  -L$(LOCAL_PATH)/../libs/armeabi/   -lhello-B

include $(BUILD_SHARED_LIBRARY)

 

include $(CLEAR_VARS)

LOCAL_MODULE := prelib

LOCAL_SRC_FILES := libE.so

 

include $(PREBUILT_SHARED_LIBRARY)

 

 

注意:当 PREBUILT_SHARED_LIBRARY 时,LOCAL_SRC_FILES不再是.c文件,而是动态库。它可以放置在jni下。编译时,它会自动被copy到lib/armaebi下。

请注意模块名。它将被用作LOCAL_SHARED_LIBRARIES