一、概述
Android.mk作用是将源文件按照module进行分组,然后将module生成静态库、共享库或者可执行文件
一个Android.mk里面可能有1个或者多个module,不同的module之间可以使用相同的源文件。
Android.mk里面不用列出头文件,Build System会帮我们处理
只有动态库可以被install或者copy到应用程序包,静态库可以被链接成动态库
二、语法
举例说明:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := hello-jni
LOCAL_SRC_FILES := hello-jni.c
include $(BUILD_SHARED_LIBRARY)
解析如下:
LOCAL_PATH := $(call my-dir)
Android.mk必须以定义LOCAL_PATH开头,表示源文件的位置,my-dir返回的是Android.mk的目录路径
include $(CLEAR_VARS)
负责清除所有的LOCAL_XXX变量,例如:LOCAL_MODULE、 LOCAL_SRC_FILES、LOCAL_STATIC_LIBRARIES等,但是不包括LOCAL_PATH,这个清理动作必须要有的,因为这些比阿尼朗都是全局的,防止之前被赋值,导致当前module解析编译异常
LOCAL_MODULE := hello-jni
LOCAL_MODULE可以配置模块的名字,模块的名字必须是唯一的并且中间不能包含空格,Build System会自动添加前缀和后缀,例如:模块名字是foo,要生成动态库,那么生成的动态库名字就是libfoo.so,其中前缀是lib,后缀是.so,但是如果名字是libfoo,前缀就不会添加了。生成的动态库的名字依然是libfoo.so
LOCAL_SRC_FILES := hello-jni.c
LOCAL_SRC_FILES变量里面包含的是模块用到的C/C++的源码,不必列出头文件,Build System会自动帮我们找到依赖文件,当包含C++源码是,这些文件的后缀默认是.cpp,如果文件后缀不是.cpp,则需要通过LOCAL_CPP_EXTENSION进行修改(后面单独介绍这个变量)。
include $(BUILD_SHARED_LIBRARY)
BUILD_SHARED_LIBRARY变量指向一个GNU Makefile脚本,它负责收集自从上次调用 include $(CLEAR_VARS)到这一行之间的所有LOCAL_XXX信息,并编译成动态库。也可以使用别的值,例如:
BUILD_STATIC_LIBRARY:编译为静态库。
BUILD_SHARED_LIBRARY :编译为动态库
BUILD_EXECUTABLE:编译为Native C可执行程序
三、NDK Build System变量:
1、NDK Build System 保留了以下变量名:
(1)以LOCAL_ 为开头的
(2)以PRIVATE_ ,NDK_ 或者APP_ 开头的名字
(3)小写字母名字,如my-dir
注意:如果要在Android.mk定义自己使用的变量名,建议使用MY_ 开头
2、NDK 定义的 include 变量
2.1:CLEAR_VARS:这个变量指向一个编译脚本,这个脚本是用来取消几乎所有LOCAL_XXX变量(LOCAL_PATH除外)。所以在描述新模块之前,必须使用此变量
例如:
include $(CLEAR_VARS)
2.2:BUILD_SHARED_LIBRARY:指向一个编译脚本,这个脚本会收集自从上次调用 include $(CLEAR_VARS) 到这一行之间所有的LOCAL_XXX信息。并决定如何这中间列出的源文件编译成动态库。
注意:在此行之前前,至少应该包含:LOCAL_MODULE和LOCAL_SRC_FILES
例如:
include $(BUILD_SHARED_LIBRARY)
2.3:BUILD_STATIC_LIBRARY:与2.2类似,它也指向一个编译脚本,这个脚本会收集自从上次调用 include $(CLEAR_VARS) 到这一行之间所有的LOCAL_XXX信息。并决定如何这中间列出的源文件编译成静态库。
注意:静态库不能够加入到Project 或者APK中。但它可以用来生成动态库。
例如:
include $(BUILD_STATIC_LIBRARY)
2.4: BUILD_EXECUTABLE: 与2.2类似,它也指向一个编译脚本,这个脚本会收集自从上次调用 include $(CLEAR_VARS) 到这一行之间所有的LOCAL_XXX信息。并决定如何这中间列出的源文件编译成Native程序。
例如:
include $(BUILD_EXECUTABLE)
2.5:PREBUILT_SHARED_LIBRARY:指向一个编译脚本,这个脚本可以指定一个预编译的共享库,与BUILD_SHARED_LIBRARY和BUILD_STATIC_LIBRARY不同,此时LOCAL_SRC_FILES应该被指定为预编译动态库的路径(例如:/foo/libfoo.so),而不是源文件
例如:
include $(PREBUILT_SHARED_LIBRARY)
例如:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := foo-prebuilt # 模块名
LOCAL_SRC_FILES := libfoo.so # 模块的文件路径(相对于 LOCAL_PATH)
include $(PREBUILT_SHARED_LIBRARY)
预编译库的使用请参照https://developer.android.google.cn/ndk/guides/prebuilts
2.6: PREBUILT_STATIC_LIBRARY: 预先编译的静态库。
与2.5类似
3、平台信息变量
Build system根据APP_ABI变量所指定的每个 ABI 分别解析一次Android.mk,该变量通常在Application.mk文件中定义。如果APP_ABI为all表示Build System会根据NDK支持的每个ABI分别解析一次Android.mk
3.1: TARGET_ARCH:
这个参数表示的是CPU架构,可以是arm、arm64、x86或x86_64中的一个
3.2: TARGET_PLATFORM:
这个参数表示的是Android API level,例如:Android 5.1的Android API level对应的是android-22
例如:
ifeq ($(TARGET_PLATFORM),android-22)
# ... do something ...
Endif
3.3:TARGET_ARCH_ABI
这个参数表示的是CPU架构及其支持的ABI
例如:
ifeq ($(TARGET_ARCH_ABI),arm64-v8a)
# ... do something ...
Endif
3.4:TARGET_ABI
这个参数表示的是Android API level和ABI
例如:
ifeq ($(TARGET_ABI),android-22-arm64-v8a)
# ... do something ...
Endif
4、模块描述变量
这类变量是用来向Build System描述模块信息,位于include $(CLEAR_VARS)和 include $(BUILD_XXXXX)之间。其中include $(CLEAR_VARS)用来清空这些变量,所以在一个新模块开始的时候,需要先调用include $(CLEAR_VARS)
4.1: LOCAL_PATH:
这个变量指定当前文件的路径,必须在Android.mk的开头,另外include $(CLEAR_VARS)不会清理这个变量
例如:
LOCAL_PATH := $(call my-dir)
4.2: LOCAL_MODULE:
这个变量用来设置模块名,模块名必须是唯一的,并且模块名内部不能有空格,在include $(BUILD_XXXXX)之前,必须要先定义这个变量。无需添加lib前缀和.so或.a后缀,build system会自动添加,如果名字是lib开头,例如libfoo,则build system不会再添加lib前缀
例如:
LOCAL_MODULE := "foo"
4.3: LOCAL_MODULE_FILENAME:
这个变量是可选的,LOCAL_MODULE只能生成libxxx.so或者libxxx.a这种名字,如果要生成其他名字可以使用这个变量替换系统自动生成的名字。
例如:
LOCAL_MODULE := foo
LOCAL_MODULE_FILENAME := libnewfoo
这样生成的名字就是libnewfoo.so而不是libfoo.so
4.4:LOCAL_SRC_FILES:
这个变量提供build system用来生成模块的源文件列表。不需要列出依赖文件。文件路径可以是相对路径也可以是绝对路径,绝对路径是相对于LOCAL_PATH的,官方建议使用相对路径提高可以执行
例如:
LOCAL_SRC_FILES := $(call all-java-files-under, src)
LOCAL_SRC_FILES += \
src/com/sdk/service/abc.aidl \
src/com/sdk/service/abcCallback.aidl
4.5: LOCAL_CPP_EXTENSION:
这个变量是可选的,用来设置C++源文件的扩展名
例如:
LOCAL_CPP_EXTENSION := .cxx
LOCAL_CPP_EXTENSION := .cxx .cpp .cc
4.6:LOCAL_CPP_FEATURES:
这个变量是可选的,用来指定C++ features,C++features启用 -frtti和-fexceptions时,不要使用LOCAL_CPPFLAGS,这个变量会导致编译器将制定的features用于所有模块,所以要使用LOCAL_CPP_FEATURES
例如:
LOCAL_CPP_FEATURES := rtti
LOCAL_CPP_FEATURES := exceptions
也可以这样
LOCAL_CPP_FEATURES := rtti features
4.7:LOCAL_C_INCLUDES:
这个变量是可选的,添加编译时,C、C++头文件搜索路径
例如:
LOCAL_C_INCLUDES := sources/foo
LOCAL_C_INCLUDES := $(LOCAL_PATH)/<subdirectory>/foo
Define this variable before setting any corresponding inclusion flags via LOCAL_CFLAGS or LOCAL_CPPFLAGS.
4.8: LOCAL_CFLAGS:
这个变量是可选的,可以在编译C/C++源文件时用来附加编译选项。
注意:不要在此处修改编译的优化选项和Debug等级。Build system会使用Application.mk中的信息自动处理。
可以使用LOCAL_CFLAGS指定头文件检测路径
LOCAL_CFLAGS += -I<path>,
这个方法比使用LOCAL_C_INCLUDES要好,这样也可以被ndk-debug使用。
4.9: LOCAL_CPPFLAGS:
这个变量是可选的,只能给C++源文件附加编译选项。要在LOCAL_CFLAGS之后
4.10: LOCAL_STATIC_LIBRARIES:
这个变量用来列出当前模块需要的静态库的列表
4.11: LOCAL_SHARED_LIBRARIES:
这个变量用来列出当前模块需要的动态库的列表
4.12:LOCAL_WHOLE_STATIC_LIBRARIES:
具体参考--whole-archive
4.13:LOCAL_LDLIBS:
这个变量可以用来添加系统库。 如 -lz:
例如:
LOCAL_LDLIBS := -lz
注意:这个是编译动态库用的,为静态库使用此变量,会被忽略
4.14: LOCAL_LDFLAGS
这个变量可以用来指定其他ld,例如要在ARM/X86上使用ld.bfd链接器
LOCAL_LDFLAGS += -fuse-ld=bfd
注意:这个是编译动态库用的,为静态库使用此变量,会被忽略
4.15: LOCAL_ALLOW_UNDEFINED_SYMBOLS:
默认情况下,build system在编译动态库的时候遇到未定义的引用,会报错: undefined symbol?error,如果不想报错,可以将这个变量设置成true
注意:这个是编译动态库用的,为静态库使用此变量,会被忽略
4.16: LOCAL_ARM_MODE:
默认情况下,build system会以thumb模式生成ARM平台的二进制文件。每个指令16位。如果指定此变量为:arm。 则指令为32位。
例如:
LOCAL_ARM_MODE := arm
也可以在文件后面加.arm表示以arm模式编译此源文件,例如:
LOCAL_SRC_FILES := foo.c bar.c.arm
表示以arm模式编译bar.c,以LOCAL_ARM_MODE的模式编译foo.c
4.17: LOCAL_ARM_NEON:
这个变量只有在armeabi-v7a ABI的平台上才有意义,也可以在文件后面加.neon,例如:
LOCAL_SRC_FILES = foo.c.neon bar.c zoo.c.arm.neon
含义是:foo.c按照neon编译,bar.c按照LOCAL_ARM_MODE编译,zoo.c按照arm和neon编译
注意:同时使用.arm和.neon时,.arm必须在.neon前面
4.18:LOCAL_DISABLE_FORMAT_STRING_CHECKS:
默认情况下,build system在编译代码的时候会对标准格式的字符串进行保护,如果在printf中有非标准格式的字符串就会报错,设置这个变量为true,可以不报错,这个变量默认是关闭的,不建议开启
4.19: LOCAL_EXPORT_CFLAGS:
这个变量可以记录一组 C/C++ 编译器flags,其他模块通过LOCAL_STATIC_LIBRARIES 或 LOCAL_SHARED_LIBRARIES 变量使用这个模块的时候,这些flags将会添加到其他模块的 LOCAL_CFLAGS中
例如:
include $(CLEAR_VARS)
LOCAL_MODULE := foo
LOCAL_SRC_FILES := foo/foo.c
LOCAL_EXPORT_CFLAGS := -DFOO=1
include $(BUILD_STATIC_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := bar
LOCAL_SRC_FILES := bar.c
LOCAL_CFLAGS := -DBAR=2
LOCAL_STATIC_LIBRARIES := foo
include $(BUILD_SHARED_LIBRARY)
build system在编译bar.c时候,LOCAL_CFLAGS就会有-DFOO=1和-DBAR=2两个flags
另外这个变量还有传递性:例如:如果zoo依赖于bar,而bar依赖于foo,那么zoo也会继承从foo导出的所有flags
但是编译foo的时候,不会使用LOCAL_EXPORT_CFLAGS中的flags,即-DFOO=1这个flags在编译foo的时候不会使用
4.20 LOCAL_EXPORT_CPPFLAGS
这个变量跟4.19类似,但是只适用于C++的flags
4.21 LOCAL_EXPORT_C_INCLUDES
这个变量跟4.19类似,但适用于C的头文件。例如,当 bar.c 需要包括模块 foo 的头文件时,此变量很有用。
4.22 LOCAL_EXPORT_LDFLAGS
这个变量跟4.19类似,但适用于ld
4.23 LOCAL_EXPORT_LDLIBS
这个变量跟4.19类似,但是是告诉build system向编译器传递某些系统库的,每个库名称前都要加-l,这些系统库会被追加其他模块(调用这个模块的)的LOCAL_LDLIBS变量下
例如:
include $(CLEAR_VARS)
LOCAL_MODULE := foo
LOCAL_SRC_FILES := foo/foo.c
LOCAL_EXPORT_LDLIBS := -llog
include $(BUILD_STATIC_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := bar
LOCAL_SRC_FILES := bar.c
LOCAL_STATIC_LIBRARIES := foo
include $(BUILD_SHARED_LIBRARY)
build system在编译libbar.so时,将在链接器命令的末尾指定?-llog。这样就会告知链接器,由于libbar.so依赖于foo,因此它也依赖于系统log库。
4.24 LOCAL_SHORT_COMMANDS
Windows下用这个,不建议开启
4.25 LOCAL_THIN_ARCHIVE
编译静态库的时候用可以减小生成的二进制文件,但是这个文件不能移动到其他位置,因为里面的路径都是相对路径
注意:非静态库和预编译静态库不能用
4.26 LOCAL_FILTER_ASM
5、NDK提供的函数宏:
这些宏通过类似$(call <function>)的方式来得到其值,将返回文本信息。
5.1: my-dir:
$(call my-dir): 这个宏返回的是最近一次include的Makefile的路径。通常返回Android.mk所在的路径。它用来作为Android.mk的开头来定义LOCAL_PATH.
例如:
LOCAL_PATH := $(call my-dir)
注意:这个宏返回的是最近一次include的Makefile的路径。所以在Include其它Makefile后,再调用$(call my-dir)会返回其它Android.mk 所在路径。
例如:
LOCAL_PATH := $(call my-dir)
# ... declare one module
include $(LOCAL_PATH)/foo/`Android.mk`
LOCAL_PATH := $(call my-dir)
# ... declare another module
这里LOCAL_PATH最后应该是:$PATH/foo,而不是$PATH.
如果要保留第一次的LOCAL_PATH,那么只能将第一次$(call my-dir)保存在其他变量中,例如:
MY_LOCAL_PATH := $(call my-dir)
LOCAL_PATH := $(MY_LOCAL_PATH)
# ... declare one module
include $(LOCAL_PATH)/foo/`Android.mk`
LOCAL_PATH := $(MY_LOCAL_PATH)
# ... declare another module
这样就可以将一开始LOCAL_PATH存放到MY_LOCAL_PATH里面,以备后面使用
5.2: all-subdir-makefiles:
返回包含在my-dir中所有子目录中的Android.mk的列表
例如:
sources/foo/Android.mk
sources/foo/lib1/Android.mk
sources/foo/lib2/Android.mk
在sources/foo/Android.mk 中使用
include $(call all-subdir-makefiles)
那么会自动include sources/foo/lib1/Android.mk和sources/foo/lib2/Android.mk
5.3:this-makefile:
返回当前Android.mk的路径。
5.4:parent-makefile:
返回当前Android.mk的上面一层的Android.mk的路径
5.5 grand-parent-makefile
返回当前Android.mk的上面两层的Android.mk的路径
5.6:import-module:
使用模块名寻找并include这个模块的Android.mk,例如:
$(call import-module,<name>)
它会从NDK_MODULE_PATH目录下寻找模块名<name>的模块并include这个模块的Android.mk。
6、其他变量
6.1 LOCAL_MODULE_TAGS
定义模块标签,Build system会根据标签决定哪些模块被安装
可以设置下面这些值:
user:指该模块只在user版本下才编译
eng:指该模块只在eng版本下才编译
tests:指该模块只在tests版本下才编译
optional:指该模块在所有版本下都编译
例如:
LOCAL_MODULE_TAGS := optional
6.2 all-java-files-under
这个宏可以用来获取java源码,例如:
$(call all-java-files-under, <src>)
获取<src>目录下的所有 Java 文件
all-java-files-under宏的定义是在build/core/definitions.mk中
6.3 LOCAL_PACKAGE_NAME
这个变量用来设置packet的名字
例如:
LOCAL_PACKAGE_NAME := Bluetooth
6.4 LOCAL_PRIVATE_PLATFORM_APIS
设置为true时,编译时可以使用sdk隐藏的api,例如
LOCAL_PRIVATE_PLATFORM_APIS := true
6.5 LOCAL_SDK_VERSION
编译时不可以使用sdk隐藏的api,有时一些系统的class被import后编译时说找不到这个类,就是这个原因造成的。
例如:
LOCAL_SDK_VERSION := current
LOCAL_SDK_VERSION也可以设置其他值中的一个:current system_current test_current core_current,具体含义暂时不清楚
注意:LOCAL_SDK_VERSION和LOCAL_PRIVATE_PLATFORM_APIS只能使用其中的一个,如果都不使用会报错
关于api可以分析下面几类:
Internal api:内部api,只能是sdk内部使用的,这类接口是不对外公开的
Hide api:隐藏api,在源码中使用@hide 标记的方法或者类,这类接口本意是公开的,但是目前扔不稳定,所以不建议使用
其他api:第三方app也可以使用的api
6.6 LOCAL_CERTIFICATE
指定用什么签名,例如:
LOCAL_CERTIFICATE := platform
表示使用platform签名
6.7 LOCAL_USE_AAPT2
表示是否使用aapt2工具
Aapt是android asset packaging tool的缩写,是编译和打包资源的工具,aapt2是在aapt的基础上做了优化
例如:
LOCAL_USE_AAPT2 := true
6.8 LOCAL_JNI_SHARED_LIBRARIES
这个变量表示编译时用到的JNI共享库
例如:
LOCAL_JNI_SHARED_LIBRARIES := libbluetooth_jni
6.9 LOCAL_JAVA_LIBRARIES
这个变量用来指定依赖的java共享库,这里只是依赖,不会将库打包到apk中
例如:
LOCAL_JAVA_LIBRARIES := javax.obex telephony-common services.net
6.10 LOCAL_STATIC_JAVA_LIBRARIES
这个变量用来指定依赖的java静态库,这里最终会将对应的库打包到apk中
例如:
LOCAL_STATIC_JAVA_LIBRARIES := \
com.android.vcard \
bluetooth.mapsapi \
sap-api-java-static \
services.net \
libprotobuf-java-lite \
bluetooth-protos-lite
6.11 LOCAL_STATIC_ANDROID_LIBRARIES
这个变量表明要调用的android的包,例如v7 v13包等
例如:
LOCAL_STATIC_ANDROID_LIBRARIES := android-support-v4
6.12 LOCAL_REQUIRED_MODULES
这个变量可以指定依赖的模块,一旦本模块安装,那么这个变量指定的依赖的模块也会被安装
例如:LOCAL_REQUIRED_MODULES := libbluetooth
6.13 LOCAL_PROGUARD_ENABLED
混淆器配置,默认是full obfuscation,即全代码混淆,disabled表示不开启混淆器
例如:
LOCAL_PROGUARD_ENABLED := disabled
6.14 all-Iaidl-files-under
这个宏可以获取指定目录下aidl文件
例如:
$(call all-Iaidl-files-under, <src>)
6.15 all-c-files-under
这个宏可以获取指定目录下C语言文件
例如:
$(call all-c-files-under, <src>)
6.16 all-makefiles-under
这个宏可以获取指定目录下makefile文件
例如:
$(call all-makefiles-under, <folder>)
6.17 BUILD_HOST_STATIC_LIBRARY
表示编译成主机上的静态库
6.18 BUILD_HOST_SHARED_LIBRARY
表示编译成主机上的动态库
6.18 BUILD_HOST_EXECUTABLE
表示编译成主机上的可执行文件
6.19 BUILD_JAVA_LIBRARY
表示编译成java动态库
6.20 BUILD_STATIC_JAVA_LIBRARY
表示编译成java静态库
6.21 BUILD_PACKAGE
表示编译成apk程序
6.22 BUILD_HOST_JAVA_LIBRARY
表示编译成主机上的java动态库