简介
Android.mk文件是GNU Make的一小部分,它用来对Android程序进行编译。
因为所有的android.mk都在同一个GNU Make执行环境中进行执行,而Android.mk中所有的变量都是全局的。因此,应尽量少声明变量。
一个Android.mk文件可以编译多个模块,模块类型如下:
1. APK程序
一般的Android程序,编译打包生成apk文件
2. JAVA库
java类库,编译打包生成jar文件
3. C\C++应用程序
可执行的C\C++应用程序
4. C\C++静态库
编译生成C\C++静态库,并打包成.a文件
5. C\C++动态库
编译生成动态库,并打包成.so文,有且只有动态库才能被安装/复制到您的应用软件(APK)包中。
注意,NDK的Anroid.mk语法同公开发 布的Android平台开源代码的Anroid.mk语法很接近,然而编译系统实现他们的方式却是不同的,这是故意这样设计的,可以让程序开发人员重用外部库的源代码更容易。
GNU MAKE系统变量
GNU Make变量在你的Android.mk文件解析之前,就由编译系统定义好了。
- CLEAR_VARS: 必须在开始一个新模块之前包含这个脚本:
include$(CLEAR_VARS)
,用于重置除LOCAL_PATH变量外的所有LOCAL_XXX系列变量。 - BUILD_SHARED_LIBRARY: 根据所有的LOCAL_XXX变量把列出的源代码文件编译成一个共享库。
注意,必须至少在包含这个文件之前定义 LOCAL_MODULE 和 LOCAL_SRC_FILES。 - BUILD_STATIC_LIBRARY:用于编译一个静态库。静态库不会复制到的APK包中,但是能够用于编译共享库。示例:
include $(BUILD_STATIC_LIBRARY)
,这将会生成一个名为lib$(LOCAL_MODULE).a
的文件 - TARGET_ARCH: 目标 CPU平台的名字, 和 android 开放源码中指定的那样。如果是
arm,表示要生成 ARM 兼容的指令,与 CPU架构的修订版无关。 - TARGET_PLATFORM: Android.mk 解析的时候,目标 Android 平台的名字。详情可参考/development/ndk/docs/stable- apis.txt.
android-3 -> Official Android 1.5 system images
android-4 -> Official Android 1.6 system images - TARGET_ARCH_ABI: 暂时只支持armeabi和armeabi-v7a。在现在的版本中一般把这两个值简单的定义为 arm, 通过android平台内部对它重定义来获得更好的匹配。其他的 ABI 将在以后的 NDK 版本中介绍,它们会有不同的名字。注意虽然所有基于ARM的ABI都会把 ‘TARGET_ARCH’定义成‘arm’, 但是会有不同的‘TARGET_ARCH_ABI’。
- TARGET_ABI: 目标平台和ABI的组合,它事实上被定义成
$(TARGET_PLATFORM)-$(TARGET_ARCH_ABI)
,在想要在真实的设备中针对一个特别的目标系统进行测试时,会有用。在默认的情况下,它会是’android-3-arm’。
模块描述变量
下面的变量用于向系统描述我们自己的模块,它们应该定义在include $(CLEAR_VARS)
和include $(BUILD_XXX)
之间。
LOCAL_PATH:当前文件的路径,必须在 Android.mk 的开头定义
include $(CLEAR_VARS)
LOCAL_SRC_FILES:编译的源文件
LOCAL_MODULE:模块名称
LOCAL_MODULE_CLASS:用于制定LOCAL_MODULE_PATH的路径
LOCAL_MODULE_PATH:模块的生成地址
LOCAL_PACKAGE_NAME:APK应用的名称
LOCAL_DEX_PREOPT:是否开启odex优化
LOCAL_CERTIFICATE:当前应用的证书名称
LOCAL_MODULE_TAGS:模块的标签,eng,user,debug,development,option
LOCAL_STATIC_JAVA_LIBRARIES: 模块依赖的java静态库,最终会打包到apk里面
LOCAL_JAVA_LIBRARIES:模块依赖的java动态库,比如framework.ja,只是编译的时候引用
LOCAL_STATIC_LIBRARIES: 模块依赖的c/c++静态库 .a
LOCAL_SHARED_LIBRARIES:模块依赖的c/c++动态库 .so
LOCAL_C_INCLUDES: 表示头文件的搜索路径,默认的头文件的搜索路径是LOCAL_PATH目录
LOCAL_CPP_EXTENSION: 用来指定C++代码文件的扩展名,默认是'.cpp'
LOCAL_CFLAGS: 提供给c/c++编译器额外的编译参数。指定一个附加的包含路径,宏定义,或者编译选项
LOCAL_CXXFLAGS: 与 LOCAL_CFLAGS同理,针对 C++源文件
LOCAL_CPPFLAGS: 与 LOCAL_CFLAGS同理,但是对 C 和 C++ source files都适用
LOCAL_LDLIBS: 编译模块时要使用的附加的链接器选项
include $(BUILD_XXX)
自定义变量
可以定义其他变量为自己使用,但是不能使用NDK编译系统保留的变量名:
- 以 LOCAL_开头的名字(例如 LOCAL_MODULE)
- 以 PRIVATE_, NDK_ 或 APP_开头的名字(内部使用)
- 小写名字(内部使用,例如‘my-dir’)
如果为了方便在 Android.mk 中定义自己的变量,建议使用 MY_前缀,一个小例子:
MY_SOURCES := foo.c
LOCAL_SRC_FILES += $(MY_SOURCES)
注意:
- = 是最基本的赋值,make会将整个mk文件展开后,再决定变量的值。也就是说,变量的值将会是整个mk文件最后被指定的值
- := 表示变量的值决定于它在mk文件中的位置,而不是整个mk展开后的最终值。
- ?= 是如果没有被赋值过就赋予等号后面的值
- += 是添加等号后面的值
宏函数
$(call command)
执行宏函数
my-dir:返回当前Android.mk文件所在的目录路径
all-subdir-makefiles:返回一个当前my-dir路径子目录中所有Android.mk列表
all-subdir-java-files:这个目录下的所有.java文件
this-makefile:返回当前makefile的路径,即这个函数调用的地方
parent-makefile:返回调用树中父makefile的路径,即包含当前makefile的makefile的路径
重点语法详解
include $(CLEAR_VARS)
CLEAR_VARS 由编译系统提供(可以在AOSP的build/core/config.mk 文件看到其定义,为 CLEAR_VARS:=$(BUILD_SYSTEM)/clear_vars.mk),其功能是清除除LOCAL_PATH外的其他LOCAL_XXX 变量 ( 如 LOCAL_MODULE , LOCAL_SRC_FILES 等)。因为所有的编译文件都在同一个 GNU Make 执行环境中,所有的变量都是全局的,所以我们需要先清空这些变量(LOCAL_PATH除外)。
LOCAL_MODULE_PATH :=$(TARGET_ROOT_OUT)
指定最后生成的模块的目标地址。
TARGET_ROOT_OUT:根文件系统,路径为out/target/product/generic/root
TARGET_OUT:system文件系统,路径为out/target/product/generic/system
TARGET_OUT_DATA:data文件系统,路径为out/target/product/generic/data
LOCAL_MODULE_TAGS :=user
user: 指该模块只在user版本下才编译
eng: 指该模块只在eng版本下才编译
tests: 指该模块只在tests版本下才编译
optional:指该模块在所有版本下都编译
include $(BUILD_SHARED_LIBRARY)
BUILD_SHARED_LIBRARY:位于build\core\shared_library.mk,负责收集自从上次调用 include $(CLEAR_VARS) 后的所有LOCAL_XXX信息并决定编译为动态库。
BUILD_STATIC_LIBRARY:编译为静态库。
BUILD_EXECUTABLE:编译为Native C可执行程序
BUILD_PREBUILT:该模块预先编译
BUILD_STATIC_JAVA_LIBRARY:静态jar包,使用.class文件打包,可以运行在任何Java虚拟机平台
BUILD_JAVA_LIBRARY:动态jar包,在静态jar包基础上使用.dex打包而成的jar文件。
BUILD_PACKAGE:编译APK
LOCAL_MODULE_CLASS := $(EXECUTABLES)
用于制定LOCAL_MODULE_PATH的路径
在编译为library,exe时,会默认就指定当前的LOCAL_MODULE_CLASS的值,比如EXECUTABLES、SHARED_LIBRARIES等。但当遇到include $(BUILD_PREBUILT)的预编译选项时不会默认指定LOCAL_MODULE_CLASS的值,需要在Android.mk中明确指定值,从而帮助系统确定LOCAL_MODULE_PATH的路径。
编译文件
#编译C/C++静态库
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := lib_hello_static #编译后的名称
LOCAL_SRC_FILES := hellos.c #编译的源文件
include $(BUILD_STATIC_LIBRARY) #指明要编译成静态库
#编译C/C++动态库
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := lib_hello_shared
LOCAL_SRC_FILES := hellod.c
include $(BUILD_SHARED_LIBRARY)
#编译C/C++应用程序
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := exe_hello
LOCAL_SRC_FILES := hellod.c
include $(BUILD_EXECUTABLE)
#编译Java静态库
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_SRC_FILES := $(call all-subdir-java-files)
LOCAL_JAVA_LIBRARIES := android.test.runner #依赖的动态jar
LOCAL_MODULE := sample
include $(BUILD_STATIC_JAVA_LIBRARY)
Settings中的Android.mk文件,编译APK
以Settings作为分析对象,来分析一下Android.mk文件的内容:
LOCAL_PATH:= $(call my-dir) #LOCAL_PATH表示当前目录的地址,一般位于include $(CLEAR_VARS)之前
include $(CLEAR_VARS)#清除除了LOCAL_PATH以外的所有LOCAL_打头的变量
LOCAL_JAVA_LIBRARIES := bouncycastle conscrypt telephony-common ims-common#依赖动态jar 不会打包到APK,使用时从系统获取
LOCAL_STATIC_JAVA_LIBRARIES := android-support-v4 android-support-v13 jsr305#依赖静态jar 需要打包到APK中
LOCAL_MODULE_TAGS := optional#模块tag为optional,表示不管是选择了什么模式都会编译该模块
LOCAL_SRC_FILES := \ #本地代码文件
$(call all-java-files-under, src) \
src/com/android/settings/EventLogTags.logtags
LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res #本地资源文件
LOCAL_PACKAGE_NAME := Settings#模块名
LOCAL_CERTIFICATE := platform#模块证书签名
LOCAL_PRIVILEGED_MODULE := true#是否是特权文件
LOCAL_PROGUARD_FLAG_FILES := proguard.flags#使用代码混淆
ifneq ($(INCREMENTAL_BUILDS),)#判断是否进行增量编译
LOCAL_PROGUARD_ENABLED := disabled
LOCAL_JACK_ENABLED := incremental
endif
#include三个makefile文件,进项相关变量赋值
include frameworks/opt/setupwizard/navigationbar/common.mk
include frameworks/opt/setupwizard/library/common.mk
include frameworks/base/packages/SettingsLib/common.mk
#开始编译Settings模块,对应package.mk文件。感兴趣的可以进一步研究apk是怎么被编译出来的,里面还是很复杂的
include $(BUILD_PACKAGE)
# 如果使用的是mm或mmm命令单编Settings模块的话会额外include test目录下的Android.mk,用于编译测试模块。
# Use the following include to make our test apk.
ifeq (,$(ONE_SHOT_MAKEFILE))
include $(call all-makefiles-under,$(LOCAL_PATH))
endif