AndroidBuild系统的入口文件是源码树根目录下名称为“Makefile”的文件,当在源代码根目录上执行make命令时,make命令首先将读取该文件。
Makefile文件的内容只有一行:includebuild/core/main.mk,该行代码的作用是:包含build/core/main.mk文件。在main.mk文件中又会包含其他的文件,其他文件中又会包含更多的文件,这样就引入了整个Build系统。
主要的make及其文件包含关系,如图:
说明
main.mk
最主要的Make文件,该文件中首先将对编译环境进行检查,同时引入其他的Make文件。另外,该文件中还定义了几个最主要的Make目标,例如droid,sdk,等(参见后文“Make目标说明”)。
help.mk
包含了名称为help的Make目标的定义,该目标将列出主要的Make目标及其说明。
pathmap.mk
将许多头文件的路径通过名值对的方式定义为映射表,并提供include-path-for函数来获取。例如,通过$(callinclude-path-for,frameworks-native)便可以获取到framework本地代码需要的头文件路径。
envsetup.mk
配置Build系统需要的环境变量,例如:TARGET_PRODUCT,TARGET_BUILD_VARIANT,HOST_OS,HOST_ARCH等。当前编译的主机平台信息(例如操作系统,CPU类型等信息)就是在这个文件中确定的。另外,该文件中还指定了各种编译结果的输出路径。
combo/select.mk
dumpvar.mk
在Build开始之前,显示此次Build的配置信息。
config.mk
整个Build系统的配置文件,最重要的Make文件之一。该文件中主要包含以下内容:
definitions.mk
最重要的Make文件之一,在其中定义了大量的函数。这些函数都是Build系统的其他文件将用到的。例如:my-dir,all-subdir-makefiles,find-subdir-files,sign-package等,关于这些函数的说明请参见每个函数的代码注释。
distdir.mk
针对dist目标的定义。dist目标用来拷贝文件到指定路径。
dex_preopt.mk
针对启动jar包的预先优化。
pdk_config.mk
顾名思义,针对pdk(PlatformDevelopementKit)的配置文件。
${ONE_SHOT_MAKEFILE}
ONE_SHOT_MAKEFILE是一个变量,当使用“mm”编译某个目录下的模块时,此变量的值即为当前指定路径下的Make文件的路径。
${subdir_makefiles}
各个模块的Android.mk文件的集合,这个集合是通过Python脚本扫描得到的。
post_clean.mk
在前一次Build的基础上检查当前Build的配置,并执行必要清理工作。
legacy_prebuilts.mk
该文件中只定义了GRANDFATHERED_ALL_PREBUILT变量。
Android源码中包含了许多的模块,模块的类型有很多种,例如:Java库,C/C++库,APK应用,以及可执行文件等。并且,Java或者C/C++库还可以分为静态的或者动态的,库或可执行文件既可能是针对设备的也可能是针对主机的。不同类型的模块的编译步骤和方法是不一样,为了能够一致且方便的执行各种类型模块的编译,在config.mk中定义了许多的常量,这其中的每个常量描述了一种类型模块的编译方式,这些常量有:
在模块的Android.mk文件中,只要包含进这里对应的常量便可以执行相应类型模块的编译。
这些常量的值都是另外一个Make文件的路径,详细的编译方式都是在对应的Make文件中定义的。这些常量和Make文件的是一一对应的,对应规则也很简单:常量的名称是Make文件的文件名除去后缀全部改为大写然后加上“BUILD_”作为前缀。例如常量BUILD_HOST_PREBUILT的值对应的文件就是host_prebuilt.mk。
不同类型的模块的编译过程会有一些相同的步骤,例如:编译一个Java库和编译一个APK文件都需要定义如何编译Java文件。因此,各模块编译方式的Make文件的定义中会包含一些共同的代码逻辑。为了减少代码冗余,需要将共同的代码复用起来,复用的方式是将共同代码放到专门的文件中,然后在其他文件中包含这些文件的方式来实现的。这些包含关系如图