Android.mk

Android.mk详解

第一部分

Android.mk文件是用来向编译系统描述如何编译你的源代码的,也就是一个小型的Makefile.
该文件会被NDK编译工具解析多次,因此尽量减少源码中声明变量,防止可能被多次定义而影响到后面的解析。
这个文件的语法允许把源代码组织成模块,每个模块属于下列类型之一:

  • APK程序: 一般的android程序,编译打包生成apk文件。

  • Java库: Java类库,编译打包生成jar文件

  • C\C++ 应用程序: 可执行的C\C++应用程序。

  • C\C++静态库: 编译产生C\C++静态库,并打包成.a文件

  • C\C++共享库:编译生成共享库,并打包成.so文件,有且只有共享库才能被安装/复制到APK包中.

第二部分,说明:
当编译"hello world"时,这时Android.mk, 例如下面文件:

  1. sources/test/hello.c
  2. sources/test/Android.mk

其中”hello.c”是一个JNI(java native interface)共享库,实现返回”hello world”字符串的原生方法,
因此,Android.mk文件内容如下:

LOCAL_PATH:=$(call my-dir)  
include $(CLEAR_VARS)
LOCAL_MODULE := hello 
LOCAL_SRC_FILES := hello.c  
include $(BUILD_SHARED_LIBRAY)  

代码说明:

  1. LOCAL_PATH := $(call my-dir) :
    一个Android.mk文件首先必须定义好LOCAL_PATH变量。
    用于在开发树种查找源文件。在这个例子中,宏函数my-dir由编译系统提供,
    用于返回当前路径(即包含Android.mk文件的目录)。
  2. include % (CLEARVARS) :
    CLEAR_VARS由编译系统提供,指定让GNU MAKEFILE清除除了
    LOCAL_PATH变量外的很多LOCAL
    *变量,(例如:LOCAL_MODULE,LOCAL_SRC_FILES等)。
    这是很必要的,因为所有的编译文件都在同一个GNU MAKE执行环境中,所有的变量都是全局变量,
    不清楚容易引起解析错误。
  3. LOCAL_MODULE:= hello :
    LOCAL_MODULE变量必须定义,用来标识在Android.mk文件描述的
    每一个模块,而且名称必须是唯一的,并且不能包含空格。编译系统会自动产生合适的前缀和后缀。比如
    一个被命名为hello的共享库模块,将会生成libhello.so文件。如果把库命名为libhello,编译系统时
    将不会添加lib前缀,也会生成libhello.so文件。
  4. LOCAL_SRC_FILES := hello.c :
    LOCAL_SRC_FILES变量必须包含将要打包进模块中的源代码文件。
  5. include $(BUILDSHARED_LIBRARY):
    BUILD_LIBRARY是编译系统提供的变量。指向一个GUN MAKEFLE脚本(应该是build/core目录下
    的shared_library.mk),负责收集自上次调用include $ (CLEAR_VARS)以来,定义在LOCAL
    *
    变量中的所有信息,并且决定编译什么,如何正确去做,并根据其规则生成静态库。
  6. 解释一下Android.mk里变量定义字符”:=” :
    “:=” 类似于C中的宏,即在定义处明确展开,完全进行文本替换。

描述变量的说明

    下面的变量是用于向系统描述我们自己的模块,它应该定义在
include $(CLEARVARS) 和 include $(BUILD*)之间。
正像前面说的那样,$(CLEAR_VARS) 是一个脚本,清除所有这些变量,除非在描述中说明。

  1. LOCAL_PATH:
    这个变量用于给出当前文件的路径,必须在Android.mk的开头定义.
    可以这样使用:LOCAL_PATH := $(call my-dir),这样这个变量不会被$(CLEAR_VARS)清除.
    因为每个Android.mk只需要定义一次(即使一个文件中定义了多个模块的情况下).

  2. LOCAL_SRC_FILES:
    当前模块包含的所有源代码文件。

  3. LOCAL_MODULE:
    当前模块的名称,这个名称应当是唯一的,并且不能包含空格.
    模块间的依赖关系就是通过这个名称来引用的.

  4. LOCAL_MODULE_CLASS:
    标识所编译模块最后放置的位置。ETC表示放置在/system/etc.目录下,
    APPS表示放置在/system/app目录下,SHARED_LIBRARIES表示放置在/system/lib目录下
    如果具体指定,则编译的模块不会放到编译系统中,最后会在out对应
    product的obj目录下的对应目录中。

  5. LOCAL_:

  6. LOCAL_JAVA_LIBRARYS:
    当前模块依赖的Java共享库,也叫Java动态库。例如framework.jar包

  7. LOCAL_STATIC_JAVA_LIBRARY:
    当前模块依赖的Java静态库,在Android里,导入的jar包和引用的第三方工程都属于Java静态库.

  8. LOCAL_STATIC_LIBRARIES:
    当前模块在运行时依赖的静态库的名称

  9. LOCAL_SHARED_LIBRARIES:
    当前模块在运行时依赖的动态库的名称。

  10. LOCAL_C_INCLUDES:
    C\C++语言需要的头文件的路径

  11. LOCAL_CFLAGS:
    提供给C/C++编译器的额外编译参数

  12. LOCAL_PACKAGE_NAME:
    当前APK应用的名称

  13. LOCAL_CERTIFICATE:
    签署当前应用的证书名称

  14. LOCAL_MODULE_TAGS:
    当前模块所包含的标签,一个模块可以包含多个标签。
    标签的值可能是eng、user、debug、development、optional。
    其中,optional是默认标签。

  15. LOCAL_DEX_PREORT:
    apk的odex优化开关,默认是false.

除此之外,Build系统中还定义了一些函数方便在Android.mk中使用,包括:

  1. $(call my-dir):
    获取当前文件夹的路径。
  2. $(call all-java-files-under, ):
    获取指定目录下的所有java文件。
  3. $(call all-c-files-under, ):
    获取指定目录下的所有c文件。
  4. $(call all-Iaidl-files-under, ):
    获取指定目录下的所有AIDL文件。
  5. $(call all-makefiles-under, ):
    获取指定目录下的所有Make文件。
  6. $(call intermediates-dir-for, , , , ):
    获取Build输入的目标文件夹路径。

chenzhao@hustunique.com