Android编译系统集中于build/core下,几个很重要的*.mk文件以下:java
main.mk(主控
Makefile)
base_rules.mk(对一些
Makefile的变量规则化)
config.mk(关于编译参数、编译命令的一些配置)
definations.mk(定义了不少编译系统中用到的宏,至关于函数库)
Makefile(这个
Makefile特指build/core下的Makefile,此文件主要控制生成system.img,ramdisk.img,userdata.img,以及recorvery p_w_picpath,sdk等)
Binary.mk(控制如何生成目标文件
)
Clear_vars.mk(清除编译系统中用到的临时变量)
Combo/linux-arm.mk(控制如何生成
linux-arm二进制文件,包括ARM相关的编译器,编译参数等的设置)
Copy_headers.mk(将头文件拷贝到指定目录)
分散于各个目录下的
Android.mk(控制生成局部模块的源码,名称所需头文件路径,依赖库等特殊选项)
Build/envsetup.mk(编译环境初始化,定义一些实用的
shell函数,方便编译使用)
以上几个主要的文件,能够按照社会分工打一个比方:
Main.mk是总统,是老大,承担了不少工做。
Makefile是副总统,辅佐老大
Main.mk
Base_rules.mk是交警,让不规则的东西,变得规则。
Config.mk是省长,规定了各我的民群众该如何行事
Definations.mk是图书馆管理员
Binary.mk应该属于村长了,规定每一个人该如何行事
Clear_vars.mk应该属于×××公司的工人吧
Combo/linux-arm.mk应该属于社会公民了,他决定本身该如何去作
Main.mk分析
Main.mk主要包含以下几个部分的内容
1.
SHELL设置
2.
编译环境配置
3.
编译环境检查
4.
包含必要的宏
5.
根据
make参数设置编译时的变量
6.
包含须要编译的
Android.mk
7.
设置编译系统
Target:prerequisites 控制整个编译流程
下面对上面几点进行必要解释:
Main.mk的第一句就根据
ANDROID_BUILD_SHELL
来包裹编译系统用到的Shell,若是咱们不想使用bash,而想使用sh,那么就能够在它前面写上ANDROID_BUILD_SHELL := /bin/sh,或者在build/envsetup.sh中添加相关定义。(内容以下图)
定义完
SHELL以后,就是对MAKE_VERSION的检查,而后定义了默认的编译目标droid!若是咱们敲入
make以后,不加任何参数,默认的目标就是droid。注意虽而后面的include $(BUILD_SYSTEM)/config.mk写在默认目标droid依赖以后,但其和以后的语句都是要执行的,这是Makefile的语法决定的。(内容以下图)
后面会include config.mk cleanbuild.mk对编译系统进行必要的配置。后面就是对编译环境的检查,包括是否大小写敏感、路径检查、java版本检查、javac版本检查。Android对编译环境的检查若是符合条件,在下次编译的时候,不会再次进行检查。(内容以下图)
linux
检查完版本以后,会包含进definitions.mk,如前所述,definitions.mk中定义了不少编译系统中用到的宏,这些宏在编译时须要常常调用,所以在编译的很靠前的阶段,就将之包含了进来。(内容以下图)Definitions.mk中的内容本身有时间在回顾一下,里面定义了不少宏.
android
而后就是针对make时传入的编译类型(eng user userdebug showcommands等)进行编译配置,这些配置会影响到最终编译目标所包括的模块。对于eng user userdebug sdk win_sdk tests等编译目标的区别,能够经过查看main.mk的代码找出其中到底有什么不一样。(内容以下图)shell
(
在编译完整个系统以后,再运行make sdk,就能够进行sdk 的编译了。make sdk 将各类工具和p_w_picpath 打包,供开发和调试使用。
注: Make 命令
make droid:等同于make 命令。droid 是默认的目标名称。
make all: make all 将make 全部make droid 会编译的项目。同时,将编译
LOCAL_MODULE_TAGS 定义的不包括android tag 的模块。这将确保全部的在代码树里面同时有Android.mk 文件的模块。
clean-$(LOCAL_MODULE)和clean-$(LOCAL_PACKAGE_NAME):
删除某个模块的目标文件。例如:
clean-libutils 将删除全部的libutils.so 以及和它相关的中间文件;
clean-Home 将删除Home 应用。
make clean:删除本次配置所编译输出的结果文件。相似于:rm –rf ./out/ <configuration>
make clobber:删除全部配置所编译输出的结果文件。相似于:rm –rf ./out/
make dataclean:make dataclean deletes contents of the data directory inside the
current combo directory. This is especially useful on the simulator and emulator, where
the persistent data remains present between builds.
make showcommands在编译的时候显示脚本的命令而不是显示编译的简报。用于调试脚本。
make LOCAL_MODULE:编译一个单独得模块(须要有Android.mk 文件存在)。
make targets:将输出全部拟能够编译的模块名称列表。还有一些命令,从make 文件里面应该能够找到
。)
Ifeq($(SDK_ONLY),true)处,大概
400行上下,这个判断语句一直到这个语句块结束,都是对subdirs变量的设置,subdirs变量决定了哪些子文件夹最终被编译。在后面的subdir_makefiles变量的设置,决定了哪些Android.mk被编译。紧接着include $(subdir_makefiles)就会添加全部这些Android.mk文件的依赖。这其中包含了droid的依赖,后面咱们会发现。(内容以下图)
本地模块的
Makefile文件就是咱们在Android 里面几乎上随处可见的Android.mk。Android 进行编译的时候会经过下面的函数来遍历全部子目录中的Android.mk,一旦找到就不会再往层子目录继续寻找(全部你的模块定义的顶层Android.mk 必须包含本身定义的子目录中的Android.mk)。subdir_makefiles += \$(shellbuild/tools/findleaves.sh --prune="./out" $(subdirs) Android.mk)不一样类型的本地模块具备不一样的语法,但基本上是相通的,只有个别变量的不一样,如何添加模块在前面,如上图就是公司本身添加的模块。
而后就会根据这些
Makefile,找出全部须要编译的模块(module),以及进行必要的分类(eng_MODULES/debug_MODULES/tests_MODULES等、modules_to_check/modules_to_install等),用以区别对待。紧接着是定义了一系列的隐含目标:
prebuilt、all_copied_headers、files、checkbuild、ramdisk、systemtallball、userdatap_w_picpath、userdatatarball、bootimg、droidcore等。最重要的一点,是会发现droid依赖于droidcore,而droidcore依赖于
droidcore: files \
systemp_w_picpath \
$(INSTALLED_BOOTIMAGE_TARGET) \
$(INSTALLED_RECOVERYIMAGE_TARGET) \
$(INSTALLED_USERDATAIMAGE_TARGET) \
$(INSTALLED_FILES_FILE)
正是这几个依赖项,控制着整个
android的编译。
当咱们敲
Make实际上就等同于咱们执行make droid。当Make include全部的文件,完成对全部make我文件的解析之后就会寻找生成droid的规则,依次生成它的依赖,直到全部知足的模块被编译好,而后使用相应的工具打包成相应的img。
config.mk分析
build/core/config.mk该文件被
main.mk包含。config.mk 文件的主要内容以下:头文件的定义;(各类
include 文件夹的设定)在定义头文件的部分,还include 了pathmap.mk,以下:include $(BUILD_SYSTEM)/pathmap.mk
该文件设置
include 目录和frameworks/base 下子目录等的信息。编译系统内部
mk 文件的定义; <Build system internal files>。(内容以下图)
设定通用的名称;
<Set common values>
Include 必要的子配置文件;
<Include sub-configuration files>
buildspec.mk
envsetup.mk
BoardConfig.mk
/combo/select.mk
/combo/javac.mk
。(内容以下图)
检查
BUILD_ENV_SEQUENCE_NUMBER 版本号;
In order to make easier for people when the build system changes, when it is necessary
to make changes to buildspec.mk or to rerun the environment setup scripts, they contain
a version number in the variable BUILD_ENV_SEQUENCE_NUMBER. If this variable does
not match what the build system expects, it fails printing an error message explaining
what happened. If you make a change that requires an update, you need to update two
places so this message will be printed.
· In config/envsetup.make, increment the
CORRECT_BUILD_ENV_SEQUENCE_NUMBER definition.
· In buildspec.mk.default, update the BUILD_ENV_SEQUENCE_DUMBER definition
to match the one in config/envsetup.make
The scripts automatically get the value from the build system, so they will trigger the
warning as well.。(内容以下图)
设置经常使用工具的常量;
< Generic tools.>
设置目标选项;
< Set up final options.>
遍历并设置
SDK 版本;
envsetup.mk分析bash
125行又包含了另一个重要的
mk文件envsetup.mk,咱们来看一下。

上面的代码是指定了目标输出代码的位置和主机输出代码的位置,重要的几个以下:PRODUCT_OUT = 这个的结果要根据
product_config.mk文件内容来决定。envsetup.mk文件主要包含了
product_config.mk文件,而后指定了编译时要输出的全部文件的OUT目录。
envsetup.mk又包含了product_config.mk文件 app
在
build/core/product_config.mk又包含了product.mk文件。
所以
android编译系统经过各类依赖关系、确保某个模块的修改引发相依赖的文件的从新编译连接,甚至还包括目标文件系统的生成,配置文件的生成等。