Android.mk实例和NDK实用技巧

xiaoxiao2021-02-28  83

 Android.mk实例和NDK实用技巧

(2012-05-02 16:53:32) 转载▼ 标签:

android

andrord.mk

ndk

分类:Android 作者:Sam (甄峰)   sam_code@hotmail.com 例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.chell-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 functioniFunctionB1()"); return 0; } B2.c #include "B.h" int iFunctionB2() { LOGI("SamInfo: Enter static functioniFunctionB2()"); 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  注1: NDK实用技巧: 1. 显示NDK Build过程中所有编译选项和动作: ../../ndk-build V=1 这样就可以看到编译时所用编译选项是否我们期望使用的。 2.重新编译: ../../ndk-build -B 或者: ../../ndk-build clean ../../ndk-build 第三方库中编译方法:  Sam常需要NDK编译第三方库,但又不想破坏其原有目录结构.所以通常在src目录中,添加一个目录叫:jni. 在其中添加Android.mk,   Application.mk文件。 SourceCode 还是继续使用原有src目录下的源码文件。 在Android.mk中,只需要添加上一级目录的所有.c或者.cpp文件即可。 LOCAL_SRC_FILES := $(wildcard $(LOCAL_PATH)/..//*.c)
转载请注明原文地址: https://www.6miu.com/read-77700.html

最新回复(0)