前面文章讲了NDK环境的配置,这篇文章将介绍NDK在编译过程中会使用到的Android.mk文件。
1.Android.mk文件简介
我们可以在Android源码的很多目录下看到Android.mk文件,Android.mk文件向系统描绘编译的一些规则,这样可以通过一些简单的命令,完成代码的组织和编译工作。Android.mk是GNU Makefile的一小部分,编译系统会解析该文件。在Android.mk文件中,可以定义一个或多个模块,也可以复用其他已经定义好的模块。简单概括来说,Android.mk文件可以更好的组织管理代码,让编译系统更好的工作。
2.Android.mk文件实例
接下来介绍一个在JNI实例中,用到的一个Android.mk文件,Android.mk的文件写法如下:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := JNITest
LOCAL_SRC_FILES := com_example_testndk_JNITest.c
include $(BUILD_SHARED_LIBRARY)
其中LOCAL_PATH := $(call my-dir) 用于在开发树中,查到源代码。"my-dir"是系统宏函数,用于返回当前路径,即包含Android.mk文件的路径。
include $(CLEAR_VARS)用于清除一些编译系统预定义的LOCAL_XX变量,除了LOCAL_PATH变量。这是必要的,因为所有的编译控制文件都在同一个GNU MAKE执行环境中,所有的变量都是全局的。
LOCAL_MODULE := JNITest 用于定义需要编译的模块名称,该名称必须全局范围内唯一,名称中不能包含有空格。编译系统会在模块名称前面加上一些前缀和后缀,例如该模块编译完成后,将生成libJNITest.so库文件。
LOCAL_SRC_FILES := com_example_testndk_JNITest.c 用于定义需要编译的源文件,编译系统会自动去寻找该源文件所依赖的其他文件,所以不需要包含.h文件进来。
include $(BUILD_SHARED_LIBRARY) 表示该模块将编译成一个共享库文件。
3.JNI实例
下面通过一个JNI实例,来演示Android.mk文件的使用。
1.首先配置好Eclipse和NDK环境,具体可以参考文章NDK配置之Eclipse;
2.创建一个Android工程——TestNDK工程;
3.在TestNDK工程的源文件目录src中,创建一个JNITest类,在该类中定义一个本地方法addInt()。
自动保存后,会在bin\classes目录下生成.class文件
class文件在包路径com.example.testndk下,通过cmd命令,进入命令行模式。进入bin\classes路径下,执行javah com.example.testndk.JNITest ,其中com.example.testndk为包名,JNITest为类名。执行成功后,可以看到在classes目录下生成com_example_testndk_JNITest.h文件,文件的命名方法是包名下划线+ 类名.h。
4.在TestNDK目录下,创建jni文件夹,将com_example_testndk_JNITest.h文件拷贝至jni文件夹下,同时在该文件夹下创建一个实现addInt()接口的c文件com_example_testndk_JNITest.c。该c文件如下所示:
#include "com_example_testndk_JNITest.h"
#include <stdio.h>
#include <stdlib.h>
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: com_example_testndk_JNITest
* Method: addInt
* Signature: (II)I
*/
JNIEXPORT jint JNICALL Java_com_example_testndk_JNITest_addInt
(JNIEnv *env, jclass arg, jint a, jint b)
{
return a+b;
}
#ifdef __cplusplus
}
#endif
5.在jni目录下,创建Android.mk文件,定义需要编译的模块名称,以及需要编译的源文件。Android.mk文件如下所示:
6.配置完成后,执行Build——>Make Project,会在libs目录下生成armeabi\libJNITest.so库文件。
7.在MainActivity.java文件中,加载so库,并引用本地方法addInt()。
加载so库需要调用System.loadLibrary("JNITest");方法,其中JNITest为需要加载的库文件,不需要lib前缀。加载完so库文件之后,就可以调用本地方法addInt()。
public class MainActivity extends Activity {
static{
System.loadLibrary("JNITest");
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.d("test##", " 3 + 4 = " + JNITest.addInt(3, 4));
}
}
执行完的结果如下:
至此,简单介绍了在NDK中如何使用Android.mk文件。