Android.mk 用法
Android.mk 文件向系统描述源代码如何编译。该文件是GUN MakeFile的一小部分,会被编译系统解析一次或多次。可以在每一个Android.mk中定义一个或多个模块。每个模块属于下列类型之一。
-
APK程序,一般的Andrid程序,编译打包生成apk文件
-
JAVA库,java类库,编译打包生成jar文件
-
C/C++应用程序,可执行的C/C++应用程序
-
C/C++静态库,编译生成C/C++静态库,打包生成.a文件。
-
C/C++共享库,编译生成共享库(动态链接库),并打包成.so文件。有且只有共享库才能被安装到apk中。
举例
//packages/apps/SoundRecorder/Android.mk
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := optional
LOCAL_SRC_FILES := $(call all-subdir-java-files)
LOCAL_PACKAGE_NAME := SoundRecorder
LOCAL_PRIVILEGED_MODULE := true
include $(BUILD_PACKAGE)
说明
- LOCAL_PATH:= $(call my-dir)
一个Android.mk 文件必需定义好LOCAL_PATH变量。用于在开发树中查找源文件。宏函数 ‘my-dir’ 由编译系统提供,用于返回当前路径,即Android.mk所在目录
- include $(CLEAR_VARS)
CLEAR_VARS由编译系统提供((可以在 android 安装目录下的/build/core/config.mk 文件看到其定义,为 CLEAR_VARS:= $(BUILD_SYSTEM)/clear_vars.mk)),指定让GNU MAKEFILE为你清除许多LOCAL_XXX变量(例如 LOCAL_MODULE, LOCAL_SRC_FILES, LOCAL_STATIC_LIBRARIES, 等等…),除LOCAL_PATH 。这是必要的,因为所有的编译控制文件都在同一个GNU MAKE执行环境中,所有的变量都是全局的。
- LOCAL_MODULE_TAGS := optional
LOCAL_MODULE_TAGS := user eng tests optional user: 指该模块只在user版本下才编译eng: 指该模块只在eng版本下才编译tests: 指该模块只在tests版本下才编译optional:指该模块在所有版本下都编译默认,optional。
- LOCAL_SRC_FILES := $(call all-subdir-java-files)
用来指定参与编译的源代码文件。LOCAL_SRC_FILES变量必须包含将要编译打包进模块中的C或C++源代码文件。注意,你不用在这里列出头文件和包含文件,因为编译系统将会自动为你找出依赖型的文件;仅仅列出直接传递给编译器的源代码文件就好。
- LOCAL_PACKAGE_NAME := SoundRecorder
package的名字
- LOCAL_PRIVILEGED_MODULE := true
声明app需要放在/system/priv-app下
- include $(BUILD_PACKAGE)
编译一个apk程序
mk文件
Android.mk文件用来告知NDK Build 系统关于Source的信息。 Android.mk将是GNU Makefile的一部分,且将被Build System解析一次或多次。 所以,请尽量少的在Android.mk中声明变量,也不要假定任何东西不会在解析过程中定义。
Android.mk文件语法允许我们将Source打包成一个"modules". modules可以是:静态库、 动态库
只有动态库可以被 install/copy到应用程序包(APK). 静态库则可以被链接入动态库。可以在一个Android.mk中定义一个或多个modules. 也可以将同一份source 加进多个modules.
Build System帮我们处理了很多细节而不需要我们再关心。例如:你不需要在Android.mk中列出头文件和外部依赖文件。
NDK Build System自动帮我们提供这些信息。这也意味着,当用户升级NDK后,你将可以受益于新的toolchain/platform而不必再去修改Android.mk.
Android.mk语法
每个Android.mk文件必须以定义LOCAL_PATH为开始。它用于在开发tree中查找源文件。宏my-dir 则由Build System提供。返回包含Android.mk的目录路径。 LOCAL_PATH:= $(call my-dir)
CLEAR_VARS 变量由Build System提供。并指向一个指定的GNU Makefile,由它负责清理很多LOCAL_xxx. #例如:LOCAL_MODULE, LOCAL_SRC_FILES, LOCAL_STATIC_LIBRARIES等等。但不清理LOCAL_PATH. #这个清理动作是必须的,因为所有的编译控制文件由同一个GNU Make解析和执行,其变量是全局的。所以清理后才能避免相互影响。 include $(CLEAR_VARS)
LOCAL_MODULE模块必须定义,以表示Android.mk中的每一个模块。名字必须唯一且不包含空格。 #Build System会自动添加适当的前缀和后缀。例如,foo,要产生动态库,则生成libfoo.so. 但请注意:如果模块名被定为:libfoo.则生成libfoo.so. 不再加前缀。 LOCAL_MODULE := hello-jni
LOCAL_SRC_FILES变量必须包含将要打包如模块的C/C++ 源码。 #不必列出头文件,build System 会自动帮我们找出依赖文件。 #缺省的C++源码的扩展名为.cpp. 也可以修改,通过LOCAL_CPP_EXTENSION。 LOCAL_SRC_FILES := hello-jni.c
#BUILD_SHARED_LIBRARY:是Build System提供的一个变量,指向一个GNU Makefile Script。 #它负责收集自从上次调用 include $(CLEAR_VARS) 后的所有LOCAL_XXX信息。并决定编译为什么。 #BUILD_STATIC_LIBRARY:编译为静态库。 #BUILD_SHARED_LIBRARY :编译为动态库 #BUILD_EXECUTABLE:编译为Native C可执行程序
include $(BUILD_SHARED_LIBRARY)
#NDK Build System变量: #NDK Build System 保留以下变量名: #以LOCAL_ 为开头的 #以PRIVATE_ ,NDK_ 或者APP_ 开头的名字。 #小写字母名字:如my-dir
NDK提供的变量 #CLEAR_VARS:指向一个编译脚本。必须在新模块前包含之。 include $(CLEAR_VARS) #BUILD_STATIC_LIBRARY:与前面类似,它也指向一个编译脚本,收集自从上次调用 include $(CLEAR_VARS) 后的所有LOCAL_XXX信息。 #并决定如何将你列出的Source编译成一个静态库。 静态库不能够加入到Project 或者APK中。但它可以用来生成动态库。 #LOCAL_STATIC_LIBRARIES and LOCAL_WHOLE_STATIC_LIBRARIES将描述之。
include $(BUILD_STATIC_LIBRARY) #BUILD_EXECUTABLE:它也指向一个编译脚本,收集自从上次调用 include $(CLEAR_VARS) 后的所有LOCAL_XXX信息。并决定如何将你列出的Source编译成一个可执行Native程序。 include $(BUILD_EXECUTABLE)
others
LOCAL_MODULE := helloworld,LOCAL_MODULE变量必须定义,以标识你在Android.mk文件中描述的每个模块。名称必须是唯一的。注意编译系统会 自动产生合适的前缀和后缀,换句话说,一个被命名为’foo’的共享库模块,将会生成’libfoo.so’文件(也可以直接已libxxx命名好)。 此处虽没用到其他常用的还有: 5,LOCAL_C_INCLUDES:可选变量,表示头文件的搜索路径。默认的头文件的搜索路径是LOCAL_PATH目录。示例:LOCAL_C_INCLUDES := sources/foo或LOCAL_C_INCLUDES := $(LOCAL_PATH)/…/foo 6,TARGET_ARCH:目标 CPU平台的名字;TARGET_PLATFORM:Android.mk 解析的时候,目标 Android 平台的名字;TARGET_ARCH_ABI:暂时只支持两个 value,armeabi 和 armeabi-v7a 7,LOCAL_STATIC_LIBRARIES: 表示该模块需要使用哪些静态库,以便在编译时进行链接。 8,LOCAL_SHARED_LIBRARIES: 表示模块在运行时要依赖的共享库(动态库),在链接时就需要,以便在生成文件时嵌入其相应的信息。 9,LOCAL_LDLIBS: 编译模块时要使用的附加的链接器选项。 10,LOCAL_ARM_MODE: 默认情况下, arm目标二进制会以 thumb 的形式生成(16 位),你可以通过设置这个变量为 arm如果你希望你的 module 是以 32 位指令的形式11,LOCAL_CFLAGS: 可选的编译器选项,在编译 C 代码文件的时候使用 12,include $(call all-subdir-makefiles):返回一个位于当前’my-dir’路径的子目录中的所有Android.mk的列表。
Android.mk的用法和基础 && m、mm、mmm编译命令
Android MakeFfile文件讲解
Android build system & Android.mk 规范
Android Makefile 笔记
理解 Android Build 系统
android.mk语法详解
简单例子 Package
LOCAL_PATH := $(call my-dir)#每个Android.mk 文件必须定义LOCAL_PATH为开始,用于在tree中查找源文件。#宏my-dir 由Build System提供,返回包含Android.mk 的目录名字 |
---|
include $(CLEAR_VARS)#CLEAR_VARS 由Build System提供,指向一个GUN Makefile,负责清理LOCAL_xxx。#如LOCAL_MODULE, LOCAL_SRC_FILES, LOCAL_STATIC_LIBRARIES,等等,但是不清理LOCAL_PATH#这个是必须的,因为所有的编译控制文件由同一个GUN Make解析和执行。其变量是全局的,清理能够避免相互影响。 |
LOCAL_MODULE_TAGS := optional#进行编译的版本 #user 只在user版本下编译,user版本,adb 默认是关闭的,为了提高速度dex是打开的。#eng只在eng版本下编译,工程版本,debug版,adb默认打开,且设置向导是可选的。#tests只在test版本下编译#optional只在user版本下编译 ##取值范围debug eng tests optional samples shell_ash shell_mksh。注意不能取值user,如果要预装,则应定义core.mk。 |
LOCAL_PACKAGE_NAME := GaeiImage #package 的名字,这个名字在脚本中标识这个apk或package |
LOCAL_SRC_FILES := $(call all-java-files, src) #如果要包含的是java源码的话,可以调用all-java-files-under得到。(这种形式来包含local_path目录下的所有java文件)#当涉及到C/C++时,LOCAL_SRC_FILES变量就必须包含将要编译打包进模块中的C或C++源代码文件。注意,在这里你可以不用列出头文件和包含文件,因为编译系统将会自动为你找出依赖型的文件;仅仅列出直接传递给编译器的源代码文件就好。#all-java-files-under宏的定义是在build/core/definitions.mk中# |
LOCAL_CERTIFICATE := platform #是文件的签名文件的文件名, |
include $(BUILD_PACKAGE)#编译成apk#用来编译生成package/app下的app##其他方式,共四种,必须以其中一种结束#include $(BUILD_STATIC_LIBRARY) 表示编译成静态库#include $(BUILD_SHARED_LIBRARY) 表示编译成动态库#include $(BUILD_EXECUTABLE) 表示编译成可执行程序 |
常用属性
- all-makefiles-under
include ( c a l l a l l − m a k e f i l e s − u n d e r , (call all-makefiles-under, (callall−makefiles−under,(LOCAL_PATH))#加载当前目录下的所有makefile文件
all-makefiles-under会返回一个位于当前’my-dir’路径的子目录中的所有Android.mk的列表。#all-makefiles-under宏的定义是在build/core/definitions.mk中
mk常用语法
打印信息
$(warning xxxxx)或者$(error xxxxx)
输出变量方式为:$(warning $(XXX))
如果是$(error xxxxx)将会停止编译
subst函数
subst是一个替换函数,这个函数有三个参数,第一个参数是被替换字串,第二个参数是替换字串,第三个参数是替换操作作用的字串。 把 c 中的 a 替换成 b
subst $(a),$(b),$(c)
- 替换函数
comma:= ,
empty:=
space:= $(empty) $(empty)
foo:=a b c
bar:= $(subst $(space),$(comma),$(foo))
这个函数也就是把 ( f o o ) 中的空格替换成逗号,所以 (foo)中的空格替换成逗号,所以 (foo)中的空格替换成逗号,所以(bar)的值是 “a,b,c”
- 字符串替换
$(subst ee,EE,feet on the street)
把 feet on the street
中的 ee
替换成EE
,返回结果是 fEEt on the strEEt
。
推断文件是否存在,若存在则复制该文件到某个文件夹
$(shell test -f [文件] && echo yes) #的值假设是yes, 则文件存在,然后进行shell cp 动作
HAVE_TEST_CUST_FILE := $(shell test -f vendor/huaqin/resource/$(HQ_PROJECT)_$(HQ_CLIENT)/$(LOCAL_PATH)/DroidSansFallback.ttf && echo yes)
ifeq ($(HAVE_TEST_CUST_FILE),yes)
$(shell cp -f vendor/huaqin/resource/$(HQ_PROJECT)_$(HQ_CLIENT)/$(LOCAL_PATH)/DroidSansFallback.ttf $(PRODUCT_OUT)/system/fonts/DroidSansFallback.ttf)
endif
配置多个AndroidManifest.xml
ifeq ($(TARGET_BUILD_VARIANT), eng)
LOCAL_MANIFEST_FILE := ex_manifest/AndroidManifest.xml
else
LOCAL_MANIFEST_FILE := AndroidManifest.xml
endif
运行错误
- Makefile missing separator
Makefile missing separator
解决:
在Makefile文件中,命令必须以【tab】键开始
makefile里不要乱用TAB,只有命令所在的行才能且只能以TAB开头!
-
commands commence before first target
commands commence before first target
Makefile可能是以命令行开始:以[Tab]字符开始,但不是一个合法的命令行(例如,一个变量的赋值)。命令行必须和规则一一对应。
第二种的错误的原因可能是一行的第一个非空字符为分号,make会认为此处遗漏了规则的“target: prerequisite”部分。
Android 的编译环境
一、android 的build系统
android build系统可以分成三大块:
-
build/core 目录下,系统的框架和核心
-
device 目录,具体产品的配置文件
-
android.mk 各个模块的编译文件
android 5.0 的build 系统开始支持64位系统。
android build 系统核心
build/core 目录下有几十个mk 文件以及一些shell脚本和perl脚本,构成了android build系统的基础和框架。编译命令有以下三个。
. build/envsetup.sh
建立android 编译环境
lunch
打印菜单让用户选择需要编译的模块。
make
编译系统
envsetup.sh 文件的作用
结尾会在device和vendor目录下搜索所有vendorsetup.sh文件的内容。device/lge/hammerhead下存在。
android 的编译命令
lunch | lunch<product_name>-<build_variant> 指定当前编译的产品。 |
---|---|
tapas | |
croot | |
m | 编译整个源码,但是不用将当前目录切换到源码的根目录。 |
mm | 编译当前目录下的所有模块,但是不编译它们的依赖模块。 |
mmm | 编译指定目录下的所有模块,但是不编译它们的依赖模块 |
mma | 编译当前目录下的所有模块,同时编译它们的依赖模块。 |
mmma | 编译指定目录下的所有模块,同时编译它们的依赖模块。 |
cgrep | 对系统所有的C/C++文件执行grep命令。 |
ggrep | 对系统所有的本地的Gradle 文件执行grep命令。 |
jgrep | 对系统所有Java 文件执行grep文件。 |
resgrep | 对系统所有xml目录下的 XML文件执行grep命令。 |
sgrep | 对系统中所有源文件执行grep命令。 |
godir |
lunch命令的功能
执行完lunch命令后,系统会打印出当前配置所生成的环境变量。这些环境变量将会影响编译过程。
PLATFORM_VERSION_CODENAME=REL 平台版本名称,通常是AOSP(android open source project)
PLATFORM_VERSION=6.0.1 android平台版本号
TARGET_PRODUCT=leaderphone16 所编译的产品名称
TARGET_BUILD_VARIANT=userdebug 编译的产品类型(eng、user、userdebug)
TARGET_BUILD_TYPE=release 编译的类型(release、debug)
TARGET_BUILD_APPS= 编译android系统时,这个变量的值为null。使用build系统编译单个模块时,这个变量的值是所编译模块的路径。
TARGET_ARCH=arm64 编译目标的cpu架构
TARGET_ARCH_VARIANT=armv8-a 编译目标的cpu架构版本
TARGET_CPU_VARIANT=kryo 编译目标的cpu代号
TARGET_2ND_ARCH=arm 编译目标的第二cpu架构
TARGET_2ND_ARCH_VARIANT=armv7-a-neon 编译目标的第二cpu架构版本
TARGET_2ND_CPU_VARIANT=cortex-a53 编译目标的第二
HOST_ARCH=x86_64 编译平台的架构
HOST_OS=linux 编译平台使用的操作系统
HOST_OS_EXTRA=Linux-4.2.0-42-generic-x86_64-with-Ubuntu-14.04-trusty 编译平台操作系统的一些额外信息,包括内核版本号、产品名称、代号等
HOST_BUILD_TYPE=release
BUILD_ID=MMB29M Build_id的值会出现在编译的版本信息中,可以利用这个环境变量来定义公司特有的标识
OUT_DIR=out 指定编译结果的输出目录
- 修改 BUILD_ID的值
make BUILD_ID = “Android L”
- make命令会调用build/目录下的Makefile文件
他的内容如下 include build/core/main.mk
- Makefile文件
Makefile文件主要有三种内容构成:变量定义,函数定义、目标依赖规则。