一、简介
在官网对 Android.mk 的介绍中写道:
Android.mk 文件位于项目 jni/
目录的子目录中,用于向构建系统描述源文件和共享库。
二、基础知识
这里介绍一些Android.mk 文件所含内容的基本信息。举例如下:
# 注释内容使用 "#" 号
# := 是赋值
# $() 是取值
# call 是调用一个系统提供的宏函数,此处是 my-dir
LOCAL_PATH := $(call my-dir)
# 我们也可以使用 ifeq 和 ifneq 进行条件判断
ifeq ($(HOST_OS, linux))
...(省略)
else
...(省略)
endif
# 使用 := 是赋值,当某一行很长时,可以使用反斜杠 \ 换行
LOCAL_SRC_FILES := adb.c \
utils.c
# 使用 += 是附加
LOCAL_SRC_FILES += $(USB_SRCS)
对于一些文件中必须存在的变量,作出解释如下:
Android.mk 文件必须先定义 LOCAL_PATH
变量:
LOCAL_PATH := $(call my-dir)
此变量表示源文件在开发树中的位置。在上述命令中,构建系统提供的宏函数
my-dir
将返回当前目录(Android.mk 文件本身所在的目录)的路径。
下一行要声明 CLEAR_VARS
变量,其值由构建系统提供。
include $(CLEAR_VARS)
CLEAR_VARS 变量指向一个特殊的
GNU Makefile
,后者会为您清除许多 LOCAL_XXX 变量。
例如 LOCAL_MODULE、LOCAL_SRC_FILES 和 LOCAL_STATIC_LIBRARIES。
请注意,GNU Makefile
不会清除 LOCAL_PATH。此变量必须保留其值,因为系统在单一GNU Makefile
执行上下文(其中的所有变量都是全局变量)中解析所有构建控制文件。在描述每个模块之前,您必须声明(重新声明)此变量。
最后一行帮助系统将一切连接到一起:
include $(BUILD_PACKAGE)
BUILD_PACKAGE
是用来编译生成package/app/
下的apk
三、NDK 定义的 include 变量
构建系统在解析 Android.mk 文件前定义了 GNU Make
变量。在某些情况下,NDK 可能会多次解析 Android.mk 文件,每次使用其中某些变量的不同定义。
CLEAR_VARS
CLEAR_VARS
变量由Build System提供。并指向一个指定的GNU Makefile。
include $(CLEAR_VARS)
由它负责清理很多LOCAL_xxx,但不清理LOCAL_PATH
这个清理动作是必须的,因为所有的编译控制文件由同一个GNU Make解析和执行,其变量是全局的。所以清理后才能避免相互影响
BUILD_EXECUTABLE
BUILD_EXECUTABLE
收集 LOCAL_XXX 变量中提供的模块的所有相关信息,以及确定如何根据所列出的源文件构建目标可执行文件。
include $(BUILD_EXECUTABLE)
表示编译成可执行程序
请注意:使用此脚本要求您至少已经为LOCAL_MODULE
和LOCAL_SRC_FILES
赋值
注意:大多数 Android 应用不包含可执行文件,但它们对于创建单元测试和其他调试工具很有用
BUILD_SHARED_LIBRARY
BUILD_SHARED_LIBRARY
收集 LOCAL_XXX 变量中提供的模块的所有相关信息,以及确定如何根据所列出的源文件构建目标共享库。
include $(BUILD_SHARED_LIBRARY)
表示编译成动态库
注意,使用此脚本要求您至少已经为 LOCAL_MODULE 和 LOCAL_SRC_FILES 赋值
共享库变量会导致构建系统生成扩展名为.so
的库文件
BUILD_STATIC_LIBRARY
BUILD_STATIC_LIBRARY
是用于构建静态库的 BUILD_SHARED_LIBRARY 的变体。构建系统不会将静态库复制到您的项目/软件包中,但可以使用静态库构建共享库。
include $(BUILD_STATIC_LIBRARY)
表示编译成静态库
静态库变量会导致构建系统生成扩展名为.a
的库
BUILD_PACKAGE
BUILD_PACKAGE
用来编译生成package/app/下的apk。
include $(BUILD_PACKAGE)
四、目标信息变量
本部分介绍构建系统每次解析 Android.mk 时定义的变量。
TARGET_ARCH
构建系统解析此 Android.mk 文件时指向的 CPU 系列。
此变量将是下列其中一项:arm、arm64、x86 或 x86_64。
PLATFORM_VERSION
构建系统解析此 Android.mk 文件时指向的Android版本号的识别。
ifeq ($(PLATFORM_VERSION), 8.1.0)
# ... do something ...
else
# ... do something ...
endif
TARGET_PLATFORM
构建系统解析此 Android.mk 文件时指向的 Android API 级别号。
例如,Android 5.1 系统映像对应于 Android API 级别 22:android-22。
ifeq ($(TARGET_PLATFORM),android-22)
# ... do something ...
endif
TARGET_ARCH_ABI
构建系统解析此 Android.mk 文件时指向的 ABI。
下表显示了用于每个受支持 CPU 和架构的 ABI 设置:
CPU 和架构 | 设置 |
---|---|
ARMv7 | armeabi-v7a |
ARMv8 AArch64 | arm64-v8a |
i686 | x86 |
x86-64 | x86_64 |
示例演示如何检查 ARMv7
是否为目标 CPU 与 ABI 的组合如下:
ifeq ($(TARGET_ARCH_ABI), armeabi-v7a)
# ... do something ...
endif
未来的新目标 ABI 将使用不同的值
TARGET_ABI
目标 Android API 级别与 ABI 的串联,特别适用于要针对实际设备测试特定目标系统映像的情况。
例如,要检查在 Android API 级别 22 上运行的 64 位 ARM 设备
ifeq ($(TARGET_ABI),android-22-arm64-v8a)
# ... do something ...
endif
五、模块描述变量
此部分中的变量会向构建系统描述咱们的模块。每个模块描述都应遵守以下基本流程:
- 使用 CLEAR_VARS 变量初始化或取消定义与模块相关的变量。
- 为用于描述模块的变量赋值。
- 使用 BUILD_XXX 变量设置 NDK 构建系统,使其将适当的构建脚本用于该模块。
LOCAL_PATH
LOCAL_PATH
用于指定当前文件的路径。必须在 Android.mk 文件开头定义此变量。
LOCAL_PATH := $(call my-dir)
CLEAR_VARS 所指向的脚本不会清除此变量。因此,即使 Android.mk 文件描述了多个模块,也只需定义此变量一次
LOCAL_MODULE
LOCAL_MODULE
用于存储模块名称。指定的名称在所有模块名称中必须唯一,并且不得包含任何空格。
必须先定义该名称,然后才能添加任何脚本(CLEAR_VARS 的脚本除外)。
无需添加 lib
前缀或 .so
或 .a
文件扩展名;构建系统会自动执行这些修改。在整个 Android.mk 和 Application.mk 文件中,请用未经修改的名称引用模块。
例如,以下行会导致生成名为 libfoo.so
的共享库模块:
LOCAL_MODULE := "foo"
如果希望生成的模块使用除
“lib + LOCAL_MODULE 的值”
以外的名称,可以使用 LOCAL_MODULE_FILENAME 变量为生成的模块指定自己选择的名称
LOCAL_MODULE_FILENAME
LOCAL_MODULE_FILENAME
可选变量能够替换构建系统为其生成的文件默认使用的名称。
例如,如果 LOCAL_MODULE 的名称为 foo,可以强制系统将其生成的文件命名为 libnewfoo
,如下:
LOCAL_MODULE := foo
LOCAL_MODULE_FILENAME := libnewfoo
对于共享库模块,此示例将生成一个名为
libnewfoo.so
的文件
注意:无法替换文件路径或文件扩展名
LOCAL_SRC_FILES
LOCAL_SRC_FILES
包含构建系统生成模块时所用的源文件列表。只列出构建系统实际传递到编译器的文件,因为构建系统会自动计算所有相关的依赖项。
LOCAL_SRC_FILES += src/com/chris/xxx.java \
请注意,可以使用相对(相对于 LOCAL_PATH)和绝对文件路径
建议避免使用绝对文件路径;相对路径可以提高 Android.mk 文件的移植性
注意:务必在构建文件中使用 Unix 样式的正斜杠 (/),构建系统无法正确处理 Windows 样式的反斜杠 ()
LOCAL_STATIC_JAVA_LIBRARIES
LOCAL_STATIC_JAVA_LIBRARIES
表示把引用的外部Java库直接编译打包到本模块中,在runtime时可以直接从本模块中找到相关的东西。
LOCAL_STATIC_JAVA_LIBRARIES := \
chris.a.xxx \
chris.b.yyy \
指定依赖的静态java类库,最终会打包到apk里面
当前模块依赖的java静态库,在android里,导入的jar包和引用的第三方工程都属于java静态库
LOCAL_JNI_SHARED_LIBRARIES
LOCAL_JNI_SHARED_LIBRARIES
变量主要是用在JNI的编译中,如果你要在你的Java代码中引用JNI中的共享库 *.so
,此变量就是共享库的名字。
那么你要注意的一点是:在你的Project根目录下的Android.mk中要定义此变量用来引用你要使用的JNI中的共享库 *.so
。
LOCAL_JNI_SHARED_LIBRARIES := \
libxxx_jni \
定义了要包含的so库文件的名字,如果程序没有采用jni,则不需要
LOCAL_REQUIRED_MODULES
LOCAL_REQUIRED_MODULES
指定模块运行所依赖的模块(模块安装时将会同步安装它所依赖的模块)
LOCAL_REQUIRED_MODULES:= \
libxxx \
LOCAL_RESOURCE_DIR
LOCAL_RESOURCE_DIR
指定编译的资源文件文件路径。
LOCAL_RESOURCE_DIR += $(LOCAL_PATH)/res
LOCAL_PACKAGE_NAME
LOCAL_PACKAGE_NAME
指定当前APK应用的名称(编译的apk的名称),如下:
LOCAL_PACKAGE_NAME := ChrisChenAppServer
LOCAL_MODULE_TAGS
LOCAL_MODULE_TAGS
指定编译版本,版本有 eng、user、tests 版本参与编译;optional值所有版本都参与编译。
LOCAL_MODULE_TAGS:= user / eng / tests / optional 可选定义
user: 指该模组只在 user 版本下才编译
eng: 指该模组只在 eng 版本下才编译
tests: 指该模组只在 tests 版本下才编译
optional:指该模组在所有版本下都编译
LOCAL_CERTIFICATE
LOCAL_CERTIFICATE
使用平台文件签名,用于设置不同的签名方式。由它指定用哪个key签名,未指定的默认用testkey。
LOCAL_CERTIFICATE:= testkey / platform / shared / media 可选定义
build/target/product/security目录中有四组默认签名供Android.mk在编译APK使用:
- testkey:普通APK,默认情况下使用。
- platform:该APK完成一些系统的核心功能。经过对系统中存在的文件夹的访问测试,这种方式编译出来的APK所在进程的UID为system。
- shared:该APK需要和home/contacts进程共享数据。
- media:该APK是media/download系统中的一环。
LOCAL_PRIVATE_PLATFORM_APIS
LOCAL_PRIVATE_PLATFORM_APIS
指定使用sdk的hide的api来编译。
LOCAL_PRIVATE_PLATFORM_APIS := true
设置后,会使用sdk的hide的api来编译
六、NDK 提供的函数宏
此处介绍 NDK 提供的 GNU Make 函数宏。使用 $(call <function>)
可以对其进行求值;其返回文本信息。
my-dir
my-dir
返回最后包括的 makefile 的路径,通常是当前 Android.mk 的目录。
my-dir
可用于在 Android.mk 文件开头定义 LOCAL_PATH。
LOCAL_PATH := $(call my-dir)
由于 GNU Make 的工作方式,这个宏实际返回的是构建系统解析构建脚本时包含的最后一个 makefile 的路径。因此,包括其他文件后就不应调用 my-dir。
其他内容可参考官网对 Android.mk 的介绍