`
xiaoheliushuiya
  • 浏览: 401764 次
文章分类
社区版块
存档分类
最新评论

Android NDK学习 <三> Android.mk实例和NDK实用技巧

 
阅读更多
例1:JNI程序使用libhello-jni.so的符号。
libhello-jni.so由hello-jni.c组成。

hello-jni.c如下:

#include <string.h>
#include <jni.h>
#include <android/log.h>



#define <wbr>LOG_TAG <wbr><wbr>"libhello-jni"</wbr></wbr></wbr>
#define <wbr>LOGE(...) <wbr>__android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__)</wbr></wbr>

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 <wbr><wbr>:= hello-jni</wbr></wbr>
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组成。
<wbr><br> hello-jni.h如下:<br></wbr>
#ifndef _HELLO_JNI_H
#define _HELLO_JNI_H

#include <string.h>
#include <jni.h>
#include <android/log.h>

#define <wbr>LOG_TAG <wbr><wbr>"libhello-jni"</wbr></wbr></wbr>
#define <wbr>LOGE(...) <wbr>__android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__)</wbr></wbr>

#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 <wbr><wbr>:= hello-jni</wbr></wbr>
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的符号<wbr><br> libhello-jni.so依赖于libB.a.<br> libhello-jni.so由hello-jni.c, hell-jniB.c,头文件hello-jni.h组成。<wbr><br> libB.a由libstatic/B1.c,libstatic/B2.c头文件libstatic/B.h组成。<br><br> B.h 如下:<br></wbr></wbr>
#ifndef _B_H
#define _B_H

#include <string.h>
#include <jni.h>
#include <android/log.h>

int iFunctionB1();
int iFunctionB2();

#define <wbr>LOG_TAG <wbr><wbr>"libStatic"</wbr></wbr></wbr>
#define <wbr>LOGI(...) <wbr>__android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__)</wbr></wbr>

#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 <string.h>
#include <jni.h>
#include <android/log.h>

#include "libstatic/B.h"

#define <wbr>LOG_TAG <wbr><wbr>"libhello-jni"</wbr></wbr></wbr>
#define <wbr>LOGE(...) <wbr>__android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__)</wbr></wbr>


#endif


hello-jni.c:

#include "hello-jni.h"<wbr><br><br></wbr>
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 <wbr><wbr>:= hello-B</wbr></wbr>
LOCAL_SRC_FILES := libstatic/B1.c libstatic/B2.c

include $(BUILD_STATIC_LIBRARY)




include $(CLEAR_VARS)

LOCAL_MODULE <wbr><wbr>:= hello-jni</wbr></wbr>
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<wbr>,否则不生成静态库)</wbr>




例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/ <wbr>-lhello-B<br><br> 但请注意:此时libA.so中所用到的libB.so 的符号只是一个空穴。并为将实现加进来。<br><br> 而如果使用:<br> LOCAL_SHARED_LIBRARIES := hello-B<br> 也仅仅是将libhello-B.so 添加进编译选项。并未将符号添加进去。<br><br> 在Linux下,此类情况可以将动态库放置于某个目录下,然后使用export LD_LIBRARY_PATH 来解决。但Android下并无此方法。导致运行时会找不到libhello-B.so中的符号。<br><br><br> 针对此类情况,有两种方法,但都不是特别好用。分别描述如下:<br><br> 方法1.<br> 将libhello-B.so放置于/system/lib下。<br> 且Android.mk如下:<br></wbr>
LOCAL_PATH := $(call my-dir)


include $(CLEAR_VARS)

LOCAL_MODULE <wbr><wbr>:= hello-B</wbr></wbr>
LOCAL_SRC_FILES := libstatic/B1.c libstatic/B2.c
LOCAL_LDLIBS := -llog
include $(BUILD_SHARED_LIBRARY)




include $(CLEAR_VARS)

LOCAL_MODULE <wbr><wbr>:= hello-jni</wbr></wbr>
LOCAL_SRC_FILES := hello-jni.c hell-jniB.c
#LOCAL_SHARED_LIBRARIES := hello-B
LOCAL_LDLIBS := -llog <wbr>-L$(LOCAL_PATH)/../libs/armeabi/ <wbr>-lhello-B</wbr></wbr>

include $(BUILD_SHARED_LIBRARY)<wbr><br><br></wbr>
此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()方式调用。
<wbr>据说使用-rpath可以指定应用程序查找库的目录。但Sam觉得理论上并不可能(因为Java无法指定Wl,-rpath).也没有尝试出来。<br><br><br><br><br> 例5:JNI程序使用libA.so(由A1.c A2.c, A.h组成)<br> libA.so依赖于libB.so(由B1.c, B2.c, B.h组成)<br> libB.so依赖于libC.so(由c.c组成)和libD.a(由d.c组成)<br> libC.so依赖于libD.a<span style="word-wrap:normal; word-break:normal">(由d.c组成)</span><wbr><br><br><br> Android.mk:<br><div>LOCAL_PATH := $(call my-dir)</div> <div><br></div> <div><br></div> <div>include $(CLEAR_VARS)</div> <div><br></div> <div>LOCAL_MODULE <wbr><wbr>:= hello-B</wbr></wbr> </div> <div>LOCAL_SRC_FILES := libstatic/B1.c libstatic/B2.c</div> <div>LOCAL_STATIC_LIBRARIES := D</div> <div>LOCAL_LDLIBS := -llog -lC -L$(LOCAL_PATH)/../libs/armeabi/</div> <div>include $(BUILD_SHARED_LIBRARY)</div> <div><br></div> <div><br></div> <div><br></div> <div><br></div> <div>include $(CLEAR_VARS)</div> <div><br></div> <div>LOCAL_MODULE <wbr><wbr>:= hello-jni</wbr></wbr> </div> <div>LOCAL_SRC_FILES := hello-jni.c hell-jniB.c</div> <div>#LOCAL_SHARED_LIBRARIES := hello-B</div> <div>LOCAL_LDLIBS := -llog <wbr>-L$(LOCAL_PATH)/../libs/armeabi/ <wbr>-lhello-B</wbr></wbr> </div> <div>include $(BUILD_SHARED_LIBRARY)</div> <div><br></div> <div><br></div> <div>include $(CLEAR_VARS)</div> <div>LOCAL_MODULE <wbr><wbr>:= C</wbr></wbr> </div> <div>LOCAL_SRC_FILES := c.c</div> <div>LOCAL_LDLIBS := -llog</div> <div>LOCAL_STATIC_LIBRARIES := D</div> <div>include $(BUILD_SHARED_LIBRARY)</div> <div><br></div> <div><br></div> <div>include $(CLEAR_VARS)</div> <div>LOCAL_MODULE <wbr><wbr>:= D</wbr></wbr> </div> <div>LOCAL_SRC_FILES := d.c</div> <div>LOCAL_LDLIBS := -llog</div> <div>include $(BUILD_STATIC_LIBRARY)</div> <br><br></wbr></wbr>

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



例6: JNI程序使用libA.so(由A1.c A2.c, A.h组成)<wbr><br> 并引用外部生成的:libE.so, libF.a.<br><br> Sam:经常发生这样的情况,某NDK工程A生成一个动态库,供另一个NDK工程B使用。我们常把此动态库放到B工程的lib/armeabi下。 但ndk-build时,它会首先删除lib/armeabi下所有.so文件。<br> 所以可以使用<span style="word-wrap:normal; word-break:normal">PREBUILT_SHARED_LIBRARY</span><wbr><br> Android.mk:<br></wbr></wbr>
LOCAL_PATH := $(call my-dir)


include $(CLEAR_VARS)

LOCAL_MODULE <wbr><wbr>:= hello-B</wbr></wbr>
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 <wbr><wbr>:= hello-jni</wbr></wbr>
LOCAL_SRC_FILES := hello-jni.c hell-jniB.c
#LOCAL_SHARED_LIBRARIES := hello-B
LOCAL_LDLIBS := -llog <wbr>-L$(LOCAL_PATH)/../libs/armeabi/ <wbr>-lhello-B</wbr></wbr>
include $(BUILD_SHARED_LIBRARY)

include $(CLEAR_VARS)
LOCAL_MODULE := prelib
LOCAL_SRC_FILES := libE.so

include $(PREBUILT_SHARED_LIBRARY)


注意:当PREBUILT_SHARED_LIBRARY<wbr>时,LOCAL_SRC_FILES不再是.c文件,而是动态库。它可以放置在jni下。编译时,它会自动被copy到lib/armaebi下。<br> 请注意模块名。它将被用作<span style="word-wrap:normal; word-break:normal">LOCAL_SHARED_LIBRARIES</span><wbr><br><br><br><br><br><br><span style="word-wrap:normal; word-break:normal">注1:<br> NDK实用技巧:</span><br> 1. 显示NDK Build过程中所有编译选项和动作:<br> ../../ndk-build V=1<br> 这样就可以看到编译时所用编译选项是否我们期望使用的。<br><br> 2.重新编译:<br> ../../ndk-build -B<br> 或者:<br> ../../ndk-build clean<br> ../../ndk-build<br><br><br><br><br><br></wbr></wbr>
注意:此处NDK版本为NDK R7C.(不同NDK版本,ndk-build所产生的Makefile并不完全相同)

文章摘自:http://blog.sina.com.cn/s/blog_602f877001014kgj.html
分享到:
评论

相关推荐

    Android NDK开发指南-android.mk文件

    android.mk文件语法详述及简单实例

    android ndk编程实例(含注释,如何打包多个so)

    android ndk编程实例,含Android.mk语法注释,如何打包多个so,如何移植到x86平台

    android NDK

    1.了解NDK,Android NDK带来什么 2.环境部署Windows xp Android NDK环境搭建 3.Ubuntu android NDK配置与开发 4.Android1.5 NDK Release 1 中文...8.实例分析与入门实例NDK自带实例分 9.NDK入门开发实战Ubuntu版本析

    Android开发之Android.mk模板的实例详解

    关于Android NDK开发的文章已经比较多了,我的博客中也分享了很多NDK开发相关经验和技巧,今天简单写了一个 Android.mk 的示例模板,供初学者参考。  本模板主要给大家示例 Android NDK 开发中的如下几个问题:  1...

    android 4.0以下处理webp图片所需jar包so库(实例)

    android4.0以及后续版本默认支持webp图片格式。但是android4.0以下要使用此类图片需要添加额外的webp格式的解析包。此解析包需要使用ndk环境编译。编译完成后形成libwebp.so库,和libwebp.jar包。

    Android应用开发揭秘pdf高清版

    最重要的是还全面介绍了如何利用原生的C,C++(NDK)和Python、Lua等脚本语言(AndroidScriptingEnvironment)来开发Android应用,《Android应用开发揭秘》实战性强,书中的每个知识点都有配精心设计的示例,尤为...

    Android Studio打包.so库到apk中实例详解

    首先在Android Studio工程的app目录下创建整个jni目录,jni目录里写Android.mk、Application.mk以及各类C/C++和汇编源文件。然后跟原来一样,用ndk_build工具去编,然后工具会自动生成libs目录,里面还有每个你在...

    openscenegraph(osg)3.2.1rc1 android静态库 http://521.be

    编译结果为 include+obj的形式,dome实例参考官方源码包中的examples/osgAndroidExampleGLES1 或 examples/osgAndroidExampleGLES2,编译工程时把Android.mk文件中的OSG_ANDROID_DIR指向解压后的根目录即可正常编译...

    Android JNI实例

    简单的JNI实例。 分为三部分: ①编写Java文件,编译成...③编写Android.mk(自定义要编译的文件、标签等)和Application.mk(编译的架构)文件。 注意: ①编译之前要配置好NDK环境变量。 ②要在c文件中注册本地方法。

    Eclipse_Jni_Opencv_NDK

    Eclipse_Jni_Opencv_NDK 配置JNI编译环境,一键触发,以Opencv为实例,包含 mk 文件 Demo (还不够一个百个字节么?)

Global site tag (gtag.js) - Google Analytics