一、概述 自Android开源以来,引起了嵌入式行业一股热潮,很多嵌入式开发者表示对Android有很强的兴趣,并下载Android源码进行编译和移植。Android源码的巨大(repo下来,大概2G)给人以Android相当复杂的错觉。本文从Android编译系统的角度,让大家了解Android其实也是很纯真的。 Android编译系统(build system)集中于Android源码下的build/core下,其下有n多个*.mk文件,另外还有一些shell脚本,可谓相当庞大。为什么google将它的编译系统弄的如此复杂庞大呢?在build/core下的build-system.html中有以下讲述:

1. Multiple Targets

2. Non-Recursive Make

3. Rapid Compile-Test Cycles

4. Both Environment and Config File Based Settings

5. Object File Directory / make clean ......
基于以上目标,google Android开发人员将Android build system做成了现在的样子。在android.git.kernel.org上可以看到android build system作为一个项目一直在更新,因此,对于其编译系统的维护也是一个相当复杂的项目。为了实现Android在除ARM平台(x86、mips甚至一个全新的架构)上移植,必须深入了解Android编译系统。

二、 Android编译系统的架构

分析Android编译系统,你会发现,Android编译系统完成的并不仅仅是对目标(主机)系统二进制文件、java应用程序的编译、链接、打包等,而且还有包括生成各种依赖关系、确保某个模块的修改引起相依赖的文件的重新编译链接,甚至还包括目标文件系统的生成,配置文件的生成等,因此Android编译系统具有支持多架构(linux-x86windowsarm等)、多语言(汇编、CC++Java等)、多目标、多编译方式。这些目标和结构决定其架构也很重要。

Android编译系统集中于build/core下,几个很重要的*.mk文件如下:

main.mk(主控Makefile)

base_rules.mk(对一些Makefile的变量规则化)

config.mk(关于编译参数、编译命令的一些配置)

definations.mk(定义了很多编译系统中用到的宏,相当于函数库)

Makefile(这个Makefile特指build/core下的Makefile,此文件主要控制生成system.img,ramdisk.img,userdata.img,以及recorvery imagesdk等)

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分析 执行make,实际执行的是:build\core\main.mk Main.mk主要包含如下几个部分的内容

1. SHELL设置

2. 编译环境配置

3. 编译环境检查

4. 包含必要的宏

5. 根据make参数设置编译时的变量

6. 包含需要编译的Android.mk

7. 设置编译系统Target:prerequisites 控制整个编译流程

下面对上面几点进行必要解释:

有了前面小节对Android编译系统架构的分析,如果需要修改Android编译系统,就可以不至于盲目找问题,修改代码了。今天分析下main.mk,看它能为我们Android编译提供什么有价值的信息,以及如何自己定制我们的Android编译系统。

1 Main.mk 的第一句就根据ANDROID_BUILD_SHELL来包裹编译系统用到的Shell,如果我们不想使用bash,而想使用sh,那么就可以在它前面写上ANDROID_BUILD_SHELL := /bin/sh,或者在build/envsetup.sh中添加相关定义。 # this turns off the suffix rules built into make

.SUFFIXES:

# If a rule fails, delete $@.

.DELETE_ON_ERROR:

# Figure out where we are.

#TOP := $(dir $(word $(words $(MAKEFILE_LIST)),$(MAKEFILE_LIST)))

#TOP := $(patsubst %/,%,$(TOP))

# TOPDIR is the normal variable you should use, because

# if we are executing relative to the current directory

# it can be "", whereas TOP must be "." which causes

# pattern matching probles when make strips off the

# trailing "./" from paths in various places.

#ifeq ($(TOP),.)

#TOPDIR :=

#else

#TOPDIR := $(TOP)/

#endif

2 MAKE_VERSION的检查。对这个项目的编译,需要make的版本大于或等于3.81

# check for broken versions of make

ifeq (0,$(shell expr $$(echo $(MAKE_VERSION) | sed "s/[^0-9/.].*//") />= 3.81))

$(warning ********************************************************************************)

$(warning * You are using version $(MAKE_VERSION) of make.)

$(warning * You must upgrade to version 3.81 or greater.)

$(warning * see file://$(shell pwd)/docs/development-environment/machine-setup.html)

$(warning ********************************************************************************)

$(error stopping)

endif

TOP := .

TOPDIR :=

BUILD_SYSTEM := $(TOPDIR)build/core
3 设定第一个目标:DEFAULT_GOAL := droid,在用户输入make之后,如果不加任何参数,那么默认的目标就是

droid。虽然后面的include $(BUILD_SYSTEM)/config.mk写在默认目标droid依赖之后,但该目标之后的语句

# 都是要执行的,这由Makefile的语法决定的。

# This is the default target. It must be the first declared target.

DEFAULT_GOAL := droid

$(DEFAULT_GOAL):

# Set up various standard variables based on configuration

# and host information.

4 包含config.mkinclude $(BUILD_SYSTEM)/config.mk,config.mk是一个总括性的文件,它里面定义了

# 各种module编译所需要使用的HOST工具以及如何来编译各种模块。

include $(BUILD_SYSTEM)/config.mk

# This allows us to force a clean build - included after the config.make

# environment setup is done, but before we generate any dependencies. This

# file does the rm -rf inline so the deps which are all done below will

# be generated correctly

5 包含cleanbuild.mk,cleanbuild.mk 完成三件事,一是载入所有的CleanSpec.mk,二是检查更新clean_steps.mk

# previous_build_config.mk,避免不同编译间的互相干扰。最后是,定义installcleandataclean

include $(BUILD_SYSTEM)/cleanbuild.mk

VERSION_CHECK_SEQUENCE_NUMBER := 1

-include $(OUT_DIR)/versions_checked.mk

ifneq ($(VERSION_CHECK_SEQUENCE_NUMBER),$(VERSIONS_CHECKED))

$(info Checking build tools versions...)

6 编译环境若不是windows的话,会检查Case-insensitive filesystems。(这里好像无关紧要)

ifneq ($(HOST_OS),windows)

ifneq ($(HOST_OS)-$(HOST_ARCH),darwin-ppc)

# check for a case sensitive file system

ifneq (a,$(shell mkdir -p $(OUT_DIR) ; /

echo a > $(OUT_DIR)/casecheck.txt; /

echo B > $(OUT_DIR)/CaseCheck.txt; /

cat $(OUT_DIR)/casecheck.txt))

$(warning ************************************************************)

$(warning You are building on a case-insensitive filesystem.)

$(warning Please move your source tree to a case-sensitive filesystem.)

$(warning ************************************************************)

$(error Case-insensitive filesystems not supported)

endif

endif

endif

# Make sure that there are no spaces in the absolute path; the

# build system can't deal with them.

7 检查当前编译的绝对路径是否纯在空格:ifneq ($(words $(shell pwd)),1)若是存在空格,会抛出警告并退出。

ifneq ($(words $(shell pwd)),1)

$(warning ************************************************************)

$(warning You are building in a directory whose absolute path contains)

$(warning a space character:)

$(warning $(space))

$(warning "$(shell pwd)")

$(warning $(space))

$(warning Please move your source tree to a path that does not contain)

$(warning any spaces.)

$(warning ************************************************************)

$(error Directory names containing spaces not supported)

endif

# The windows build server currently uses 1.6. This will be fixed.

ifneq ($(HOST_OS),windows)

# Check for the correct version of java

java_version := $(shell java -version 2>&1 | head -n 1 | grep '[ "]1/.5[/. "$$]')

ifeq ($(strip $(java_version)),)

$(info ************************************************************)

$(info You are attempting to build with the incorrect version)

$(info of java.)

$(info $(space))

$(info Your version is: $(shell java -version 2>&1 | head -n 1).)

$(info The correct version is: 1.5.)

$(info $(space))

$(info Please follow the machine setup instructions at)

$(info $(space)$(space)$(space)$(space)http://source.android.com/download)

$(info ************************************************************)

$(error stop)

endif

# Check for the correct version of javac

8 对编译的java 版本的检查,在windows编译是使用1.6的,在别的平台上要使用1.5,如下。

javac_version := $(shell javac -version 2>&1 | head -n 1 | grep '[ "]1/.5[/. "$$]')

ifeq ($(strip $(javac_version)),)

$(info ************************************************************)

$(info You are attempting to build with the incorrect version)

$(info of javac.)

$(info $(space))

$(info Your version is: $(shell javac -version 2>&1 | head -n 1).)

$(info The correct version is: 1.5.)

$(info $(space))

$(info Please follow the machine setup instructions at)

$(info $(space)$(space)$(space)$(space)http://source.android.com/download)

$(info ************************************************************)

$(error stop)

endif

endif # windows

$(shell echo 'VERSIONS_CHECKED := $(VERSION_CHECK_SEQUENCE_NUMBER)' /

> $(OUT_DIR)/versions_checked.mk)

endif

# These are the modifier targets that don't do anything themselves, but

# change the behavior of the build.

# (must be defined before including definitions.make)

INTERNAL_MODIFIER_TARGETS := showcommands checkbuild

# Bring in standard build system definitions.

9 包含definition.mk: definations.mk中定义了很多编译系统中用到的宏,这些宏在编译时需要经常调用,

# 因此在编译的很靠前的阶段,就将之包含了进来。

include $(BUILD_SYSTEM)/definitions.mk

ifneq ($(filter eng user userdebug tests,$(MAKECMDGOALS)),)

$(info ***************************************************************)

$(info ***************************************************************)

$(info Don't pass '$(filter eng user userdebug tests,$(MAKECMDGOALS))' on /

the make command line.)

# XXX The single quote on this line fixes gvim's syntax highlighting.

# Without which, the rest of this file is impossible to read.

$(info Set TARGET_BUILD_VARIANT in buildspec.mk, or use lunch or)

$(info choosecombo.)

$(info ***************************************************************)

$(info ***************************************************************)

$(error stopping)

endif

10 TARGET_BUILD_VARIANT buildspec.mk设定,这个参数决定了要安装的模块。(重要,在后面会用到)

ifneq ($(filter-out $(INTERNAL_VALID_VARIANTS),$(TARGET_BUILD_VARIANT)),)

$(info ***************************************************************)

$(info ***************************************************************)

$(info Invalid variant: $(TARGET_BUILD_VARIANT)

$(info Valid values are: $(INTERNAL_VALID_VARIANTS)

$(info ***************************************************************)

$(info ***************************************************************)

$(error stopping)

endif

###

### In this section we set up the things that are different

### between the build variants

###

11 is_sdk_build的设置,根据在主目录里执行make时,make后面的参数决定。

is_sdk_build :=

ifneq ($(filter sdk,$(MAKECMDGOALS)),)

is_sdk_build := true

endif

ifneq ($(filter sdk_addon,$(MAKECMDGOALS)),)

is_sdk_build := true

endif

## user/userdebug ##

12 查看buildspec.mk文件中定义的TARGET_BUILD_VARIANT是否已经定义有userdebuguser,将结果保存到user_variant

# user_variant这个参数在后面会用很多,关系到后面ADDITIONAL_DEFAULT_PROPERTIEStags_to_installenable_target_debugging

# 这些重要参数的设置。ADDITIONAL_BUILD_PROPERTIES用于指定被编译项的文件特性。

user_variant := $(filter userdebug user,$(TARGET_BUILD_VARIANT))

enable_target_debugging := true

ifneq (,$(user_variant))

# Target is secure in user builds.

ADDITIONAL_DEFAULT_PROPERTIES += ro.secure=1

tags_to_install := user

ifeq ($(user_variant),userdebug)

# Pick up some extra useful tools

tags_to_install += debug

else

# Disable debugging in plain user builds.

enable_target_debugging :=

endif

# TODO: Always set WITH_DEXPREOPT (for user builds) once it works on OSX.

# Also, remove the corresponding block in config/product_config.make.

ifeq ($(HOST_OS)-$(WITH_DEXPREOPT_buildbot),linux-true)

WITH_DEXPREOPT := true

endif

# Disallow mock locations by default for user builds

ADDITIONAL_DEFAULT_PROPERTIES += ro.allow.mock.location=0

else # !user_variant

# Turn on checkjni for non-user builds.

ADDITIONAL_BUILD_PROPERTIES += ro.kernel.android.checkjni=1

# Set device insecure for non-user builds.

ADDITIONAL_DEFAULT_PROPERTIES += ro.secure=0

# Allow mock locations by default for non user builds

ADDITIONAL_DEFAULT_PROPERTIES += ro.allow.mock.location=1

endif # !user_variant

13 根据enable_target_debugging的设置(在前面设定),设置 DDITIONAL_DEFAULT_PROPERTIES的值。

ifeq (true,$(strip $(enable_target_debugging)))

# Target is more debuggable and adbd is on by default

ADDITIONAL_DEFAULT_PROPERTIES += ro.debuggable=1 persist.service.adb.enable=1

# Include the debugging/testing OTA keys in this build.

INCLUDE_TEST_OTA_KEYS := true

else # !enable_target_debugging

# Target is less debuggable and adbd is off by default

ADDITIONAL_DEFAULT_PROPERTIES += ro.debuggable=0 persist.service.adb.enable=0

endif # !enable_target_debugging

## eng ##

14 若是buildspec.mk文件中定义的TARGET_BUILD_VARIANTeng,再对tags_to_installADDITIONAL_BUILD_PROPERTIES

# 进行设置。

ifeq ($(TARGET_BUILD_VARIANT),eng)

tags_to_install := user debug eng

# Don't require the setup wizard on eng builds

ADDITIONAL_BUILD_PROPERTIES := $(filter-out ro.setupwizard.mode=%,/

$(call collapse-pairs, $(ADDITIONAL_BUILD_PROPERTIES))) /

ro.setupwizard.mode=OPTIONAL

endif

## tests ##

15 若是buildspec.mk文件中定义的TARGET_BUILD_VARIANTtest,再对tags_to_install进行配置

ifeq ($(TARGET_BUILD_VARIANT),tests)

tags_to_install := user debug eng tests

endif

## sdk ##

16 若是对sdk的编译,会对MAKECMDGOALS的值进行检查,在编译sdk的时候,是不允许再另多其他中间目标的。

# 若是是sdk的边缘,还会tags_to_installADDITIONAL_BUILD_PROPERTIES添加一些值。

ifdef is_sdk_build

ifneq ($(words $(filter-out $(INTERNAL_MODIFIER_TARGETS),$(MAKECMDGOALS))),1)

$(error The 'sdk' target may not be specified with any other targets)

endif

# TODO: this should be eng I think. Since the sdk is built from the eng

# variant.

tags_to_install := user debug eng

ADDITIONAL_BUILD_PROPERTIES += xmpp.auto-presence=true

ADDITIONAL_BUILD_PROPERTIES += ro.config.nocheckin=yes

else # !sdk

endif

## precise GC ##

17 查看PRODUCT_TAGS是否有定义dalvik.gc.type-precisePRODUCT_TAGS这个变量在product_config.mk定义。

# 若是有定义的话还要在ADDITIONAL_BUILD_PROPERTIES添加dalvik.vm.dexopt-flags这个配置信息。

ifneq ($(filter dalvik.gc.type-precise,$(PRODUCT_TAGS)),)

# Enabling type-precise GC results in larger optimized DEX files. The

# additional storage requirements for ".odex" files can cause /system

# to overflow on some devices, so this is configured separately for

# each product.

ADDITIONAL_BUILD_PROPERTIES += dalvik.vm.dexopt-flags=m=y

endif

#########################################################################################################

#(18)若是PRODUCT_COPY_FILES没有记录apns-conf.xml,要确保添加上去。

# 注意:这几个文件的作用如下:

# apns-conf_sdk.xml如:$ANDROID_SRC_HOME/development/data/etc/apns-conf_sdk.xml

# --主要用于生成system/etc/apns-conf.xml文件,生成过程本质上就是原文拷贝

# apns.xml 如:$ANDROID_SRC_HOME/frameworks/base/core/res/res/xml/apns.xml

# --该文件实际上在apn的设置方面没有实际意义,然而在android apn设置的逻辑方面却很重要,尤其是里面的version的值。

# apns-conf.xml 如: $ANDROID_SRC_HOME/out/target/product/generic/system/etc/apns-conf.xml

# --该文件里记录的内容最终打包到system.img中:

##########################################################################################################

#

# Install an apns-conf.xml file if one's not already being installed.

ifeq (,$(filter %:system/etc/apns-conf.xml, $(PRODUCT_COPY_FILES)))

PRODUCT_COPY_FILES += /

development/data/etc/apns-conf_sdk.xml:system/etc/apns-conf.xml

ifeq ($(filter eng tests,$(TARGET_BUILD_VARIANT)),)

$(warning implicitly installing apns-conf_sdk.xml)

endif

endif

#(19)若是在test eng的创建,且不是sdk那么要替换上面添加的apns-conf_sdk.xml

# If we're on an eng or tests build, but not on the sdk, and we have

# a better one, use that instead.

ifneq ($(filter eng tests,$(TARGET_BUILD_VARIANT)),)

ifndef is_sdk_build

apns_to_use := $(wildcard vendor/google/etc/apns-conf.xml)

ifneq ($(strip $(apns_to_use)),)

PRODUCT_COPY_FILES := /

$(filter-out %:system/etc/apns-conf.xml,$(PRODUCT_COPY_FILES)) /

$(strip $(apns_to_use)):system/etc/apns-conf.xml

endif

endif

endif

#(20)再次配置ADDITIONAL_BUILD_PROPERTIES

ADDITIONAL_BUILD_PROPERTIES += net.bt.name=Android

ADDITIONAL_BUILD_PROPERTIES += ro.config.sync=yes

# enable vm tracing in files for now to help track

# the cause of ANRs in the content process

ADDITIONAL_BUILD_PROPERTIES += dalvik.vm.stack-trace-file=/data/anr/traces.txt

# ------------------------------------------------------------

# Define a function that, given a list of module tags, returns

# non-empty if that module should be installed in /system.

# For most goals, anything not tagged with the "tests" tag should

# be installed in /system.

define should-install-to-system

$(if $(filter tests,$(1)),,true)

endef

ifdef is_sdk_build

# For the sdk goal, anything with the "samples" tag should be

# installed in /data even if that module also has "eng"/"debug"/"user".

define should-install-to-system

$(if $(filter samples tests,$(1)),,true)

endef

endif

# If they only used the modifier goals (showcommands, checkbuild), we'll actually

# build the default target.

#(21)make 后面的参数和INTERNAL_MODIFIER_TARGETS相同,那么就设定INTERNAL_MODIFIER_TARGETSDEFAULT_GOAL

# 依赖关系。

ifeq ($(filter-out $(INTERNAL_MODIFIER_TARGETS),$(MAKECMDGOALS)),)

.PHONY: $(INTERNAL_MODIFIER_TARGETS)

$(INTERNAL_MODIFIER_TARGETS): $(DEFAULT_GOAL)

endif

#(22)根据make 后面的参数设定 dont_bother这个变量。

# These targets are going to delete stuff, don't bother including

# the whole directory tree if that's all we're going to do

ifeq ($(MAKECMDGOALS),clean)

dont_bother := true

endif

ifeq ($(MAKECMDGOALS),clobber)

dont_bother := true

endif

ifeq ($(MAKECMDGOALS),dataclean)

dont_bother := true

endif

ifeq ($(MAKECMDGOALS),installclean)

dont_bother := true

endif

# Bring in all modules that need to be built.

ifneq ($(dont_bother),true)

ifeq ($(HOST_OS),windows)

SDK_ONLY := true

endif

ifeq ($(HOST_OS)-$(HOST_ARCH),darwin-ppc)

SDK_ONLY := true

endif

这个判断语句一直到这个语句块结束,都是对subdirs变量的设置,subdirs变量决定了哪些子文件夹最终被编译。

ifeq ($(SDK_ONLY),true)

# ----- SDK for Windows ------

# These configure the build targets that are available for the SDK under Cygwin.

# The first section defines all the C/C++ tools that can be compiled under Cygwin,

# the second section defines all the Java ones (assuming javac is available.)

#23)确定subdirs,这里包含的文件目录下的文件最终被编译,其中第一部分决定了一些C/C++工具被编译的子目录。

# 第二部分为使用java编译器编译的目录。

#这是第一部分。

subdirs := /

prebuilt /

build/libs/host /

build/tools/zipalign /

dalvik/dexdump /

dalvik/libdex /

dalvik/tools/dmtracedump /

dalvik/tools/hprof-conv /

development/tools/line_endings /

development/tools/etc1tool /

sdk/emulator/mksdcard /

sdk/sdklauncher /

development/host /

external/expat /

external/libpng /

external/qemu /

external/sqlite/dist /

external/zlib /

frameworks/base/libs/utils /

frameworks/base/tools/aapt /

frameworks/base/tools/aidl /

frameworks/base/opengl/libs /

system/core/adb /

system/core/fastboot /

system/core/libcutils /

system/core/liblog /

system/core/libzipfile

# The following can only be built if "javac" is available.

# This check is used when building parts of the SDK under Cygwin.

#(24)调用which 命令查看在环境变量中是否有javac这个命令,若是有的话,说明java编译器是已经安装的了,

# 那么就包含这些目录,否则不包含这些目录,并抛出一个警告。

ifneq (,$(shell which javac 2>/dev/null))

$(warning sdk-only: javac available.)

#这是第二部分。

subdirs += /

build/tools/signapk /

dalvik/dx /

dalvik/libcore /

sdk/archquery /

sdk/androidprefs /

sdk/apkbuilder /

sdk/jarutils /

sdk/layoutlib_api /

sdk/layoutlib_utils /

sdk/ninepatch /

sdk/sdkstats /

sdk/sdkmanager /

sdk/layoutopt /

development/apps /

development/tools/mkstubs /

frameworks/base/tools/layoutlib /

external/googleclient /

packages

else

$(warning sdk-only: javac not available.)

endif

#(25)若当前HOST不是linux,那么还要要添加build/tools/acp这个目录。

# Exclude tools/acp when cross-compiling windows under linux

ifeq ($(findstring Linux,$(UNAME)),)

subdirs += build/tools/acp

endif

#(26)SDK_ONLY不为真,且BUILD_TINY_ANDROID为真,那么添加一些文件,编译一个最小的系统.

else # !SDK_ONLY

ifeq ($(BUILD_TINY_ANDROID), true)

# TINY_ANDROID is a super-minimal build configuration, handy for board

# bringup and very low level debugging

subdirs := /

bionic /

system/core /

build/libs /

build/target /

build/tools/acp /

build/tools/apriori /

build/tools/kcm /

build/tools/soslim /

external/elfcopy /

external/elfutils /

external/yaffs2 /

external/zlib

else # !BUILD_TINY_ANDROID

#(27)若上面的两个条件(SDK_ONLY为真,BUILD_TINY_ANDROID为真)都不成了,那么就要包含$(TOP)下面

# 的所有android.mk文件了。这才是最典型的编译.

#

# Typical build; include any Android.mk files we can find.

#

subdirs := $(TOP)

FULL_BUILD := true

endif # !BUILD_TINY_ANDROID

endif # !SDK_ONLY

ifneq ($(ONE_SHOT_MAKEFILE),)

# We've probably been invoked by the "mm" shell function

# with a subdirectory's makefile.

include $(ONE_SHOT_MAKEFILE)

# Change CUSTOM_MODULES to include only modules that were

# defined by this makefile; this will install all of those

# modules as a side-effect. Do this after including ONE_SHOT_MAKEFILE

# so that the modules will be installed in the same place they

# would have been with a normal make.

#(28)设定CUSTOM_MODULES,在后面会涉及到。非常重要。

CUSTOM_MODULES := $(sort $(call get-tagged-modules,$(ALL_MODULE_TAGS),))

FULL_BUILD :=

# Stub out the notice targets, which probably aren't defined

# when using ONE_SHOT_MAKEFILE.

NOTICE-HOST-%: ;

NOTICE-TARGET-%: ;

else # ONE_SHOT_MAKEFILE

#

# Include all of the makefiles in the system

#

# Can't use first-makefiles-under here because

# --mindepth=2 makes the prunes not work.

#(29)在这里调用findleaves.py查找在subdirs的包含的子目录下所有的 Android.mk文件。

subdir_makefiles := /

$(shell build/tools/findleaves.py --prune=out --prune=.repo --prune=.git $(subdirs) Android.mk)

include $(subdir_makefiles)

endif # ONE_SHOT_MAKEFILE

# -------------------------------------------------------------------

# All module makefiles have been included at this point.

# -------------------------------------------------------------------

# -------------------------------------------------------------------

# Include any makefiles that must happen after the module makefiles

# have been included.

# TODO: have these files register themselves via a global var rather

# than hard-coding the list here.

ifdef FULL_BUILD

# Only include this during a full build, otherwise we can't be

# guaranteed that any policies were included.

-include frameworks/policies/base/PolicyConfig.mk

endif

# -------------------------------------------------------------------

# Fix up CUSTOM_MODULES to refer to installed files rather than

# just bare module names. Leave unknown modules alone in case

# they're actually full paths to a particular file.

#(30)提取用户定义的定义的模块,用户定义的模块,不一定在系统的所有模块中有定义,这里做了分类

#分为: known_custom_modules:用户定义了,并且在系统中有定义。

# unknown_custom_modules:用户没有定义,但系统系统中有定义。

known_custom_modules := $(filter $(ALL_MODULES),$(CUSTOM_MODULES))

unknown_custom_modules := $(filter-out $(ALL_MODULES),$(CUSTOM_MODULES))

CUSTOM_MODULES := /

$(call module-installed-files,$(known_custom_modules)) /

$(unknown_custom_modules)

# -------------------------------------------------------------------

# Define dependencies for modules that require other modules.

# This can only happen now, after we've read in all module makefiles.

#

# TODO: deal with the fact that a bare module name isn't

# unambiguous enough. Maybe declare short targets like

# APPS:Quake or HOST:SHARED_LIBRARIES:libutils.

# BUG: the system image won't know to depend on modules that are

# brought in as requirements of other modules.

define add-required-deps

#(31)这里调用了module-installed-filesadd-required-deps函数,设定各个模块对各种库的依赖

$(1): $(2)

endef

$(foreach m,$(ALL_MODULES), /

$(eval r := $(ALL_MODULES.$(m).REQUIRED)) /

$(if $(r), /

$(eval r := $(call module-installed-files,$(r))) /

$(eval $(call add-required-deps,$(ALL_MODULES.$(m).INSTALLED),$(r))) /

) /

)

m :=

r :=

add-required-deps :=

# -------------------------------------------------------------------

# Figure out our module sets.

# Of the modules defined by the component makefiles,

# determine what we actually want to build.

# If a module has the "restricted" tag on it, it

# poisons the rest of the tags and shouldn't appear

# on any list.

#(32)设定Default_MODULES;

Default_MODULES := $(sort $(ALL_DEFAULT_INSTALLED_MODULES) /

$(CUSTOM_MODULES))

# TODO: Remove the 3 places in the tree that use

# ALL_DEFAULT_INSTALLED_MODULES and get rid of it from this list.

ifdef FULL_BUILD

# The base list of modules to build for this product is specified

# by the appropriate product definition file, which was included

# by product_config.make.

#

#(33)设定user_PACKAGES获取这个product的所有的moduleslist,这份list定义的module选择定义在

# product_config.mk这个文件以及这个文件包含的子*.mk文件中。

user_PACKAGES := $(call module-installed-files, /

$(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_PACKAGES))

ifeq (0,1)

$(info user packages for $(TARGET_DEVICE) ($(INTERNAL_PRODUCT)):)

$(foreach p,$(user_PACKAGES),$(info : $(p)))

$(error done)

endif

else

# We're not doing a full build, and are probably only including

# a subset of the module makefiles. Don't try to build any modules

# requested by the product, because we probably won't have rules

# to build them.

user_PACKAGES :=

endif

#(34)模块设定:引擎类模块eng_MODULES,应用类模块user_MODULES,测试模块test_MODULES,调试模块debug_MOUDLE

# Use tags to get the non-APPS user modules. Use the product

# definition files to get the APPS user modules.

user_MODULES := $(sort $(call get-tagged-modules,user,_class@APPS restricted))

user_MODULES := $(user_MODULES) $(user_PACKAGES)

eng_MODULES := $(sort $(call get-tagged-modules,eng,restricted))

debug_MODULES := $(sort $(call get-tagged-modules,debug,restricted))

tests_MODULES := $(sort $(call get-tagged-modules,tests,restricted))

ifeq ($(strip $(tags_to_install)),)

$(error ASSERTION FAILED: tags_to_install should not be empty)

endif

#(35)tags_to_install获取要安装的模块

# 获取关系如下:tags_to_install <- user_variant <- TARGET_BUILD_VARIANT,TARGET_BUILD_VARIANTbuildspec.mk设定

modules_to_install := $(sort $(Default_MODULES) /

$(foreach tag,$(tags_to_install),$($(tag)_MODULES)))

# Some packages may override others using LOCAL_OVERRIDES_PACKAGES.

# Filter out (do not install) any overridden packages.

overridden_packages := $(call get-package-overrides,$(modules_to_install))

ifdef overridden_packages

# old_modules_to_install := $(modules_to_install)

modules_to_install := /

$(filter-out $(foreach p,$(overridden_packages),$(p) %/$(p).apk), /

$(modules_to_install))

endif

#$(error filtered out

# $(filter-out $(modules_to_install),$(old_modules_to_install)))

# Don't include any GNU targets in the SDK. It's ok (and necessary)

# to build the host tools, but nothing that's going to be installed

# on the target (including static libraries).

#(36)剔除目标里包含的gnu里的tools,这是sdk里包含的工具类模块,是不能安装在目标里的。

ifdef is_sdk_build

target_gnu_MODULES := /

$(filter /

$(TARGET_OUT_INTERMEDIATES)/% /

$(TARGET_OUT)/% /

$(TARGET_OUT_DATA)/%, /

$(sort $(call get-tagged-modules,gnu)))

$(info Removing from sdk:)$(foreach d,$(target_gnu_MODULES),$(info : $(d)))

modules_to_install := /

$(filter-out $(target_gnu_MODULES),$(modules_to_install))

endif

# build/core/Makefile contains extra stuff that we don't want to pollute this

# top-level makefile with. It expects that ALL_DEFAULT_INSTALLED_MODULES

# contains everything that's built during the current make, but it also further

# extends ALL_DEFAULT_INSTALLED_MODULES.

#(37)ALL_DEFAULT_INSTALLED_MODULES 的处理

ALL_DEFAULT_INSTALLED_MODULES := $(modules_to_install)

include $(BUILD_SYSTEM)/Makefile

modules_to_install := $(sort $(ALL_DEFAULT_INSTALLED_MODULES))

ALL_DEFAULT_INSTALLED_MODULES :=

endif # dont_bother

# These are additional goals that we build, in order to make sure that there

# is as little code as possible in the tree that doesn't build.

#(38)确保我们定义我们构建的模块是没有冗余的。

modules_to_check := $(foreach m,$(ALL_MODULES),$(ALL_MODULES.$(m).CHECKED))

# If you would like to build all goals, and not skip any intermediate

# steps, you can pass the "all" modifier goal on the commandline.

ifneq ($(filter all,$(MAKECMDGOALS)),)

modules_to_check += $(foreach m,$(ALL_MODULES),$(ALL_MODULES.$(m).BUILT))

endif

# for easier debugging

modules_to_check := $(sort $(modules_to_check))

#$(error modules_to_check $(modules_to_check))

# -------------------------------------------------------------------

# This is used to to get the ordering right, you can also use these,

# but they're considered undocumented, so don't complain if their

# behavior changes.

.PHONY: prebuilt

prebuilt: $(ALL_PREBUILT)

# An internal target that depends on all copied headers

# (see copy_headers.make). Other targets that need the

# headers to be copied first can depend on this target.

.PHONY: all_copied_headers

all_copied_headers: ;

$(ALL_C_CPP_ETC_OBJECTS): | all_copied_headers

#(39)files 这个目标在这里是一个非常大的目标,包括moudules_to_install,modules_to_check,prebuilt等等

# 前面所做的就是为这几个目标的正确生成。关系如下:droid依赖于droidcore,droidcore依赖于files,如下,

# 就是这几项的依赖的关系控制着整个项目的编译流程。

# All the droid stuff, in directories

.PHONY: files

files: prebuilt /

$(modules_to_install) /

$(modules_to_check) /

$(INSTALLED_ANDROID_INFO_TXT_TARGET)

# -------------------------------------------------------------------

.PHONY: checkbuild

checkbuild: $(modules_to_check)

.PHONY: ramdisk

ramdisk: $(INSTALLED_RAMDISK_TARGET)

.PHONY: systemtarball

systemtarball: $(INSTALLED_SYSTEMTARBALL_TARGET)

.PHONY: userdataimage

userdataimage: $(INSTALLED_USERDATAIMAGE_TARGET)

.PHONY: userdatatarball

userdatatarball: $(INSTALLED_USERDATATARBALL_TARGET)

.PHONY: bootimage

bootimage: $(INSTALLED_BOOTIMAGE_TARGET)

ifeq ($(BUILD_TINY_ANDROID), true)

INSTALLED_RECOVERYIMAGE_TARGET :=

endif

#40)一下是整改项目的build动作,如果要把整个编译过程分成:配置和编译两部分的话,

# 上面的所有的都是配置过程,下面的为编译过程。

# 这里确定好要生成的子目标。

# Build files and then package it into the rom formats

.PHONY: droidcore

droidcore: files /

systemimage /

$(INSTALLED_BOOTIMAGE_TARGET) /

$(INSTALLED_RECOVERYIMAGE_TARGET) /

$(INSTALLED_USERDATAIMAGE_TARGET) /

$(INSTALLED_FILES_FILE)

# The actual files built by the droidcore target changes depending

# on the build variant.

#这里开始编译。

.PHONY: droid tests

droid tests: droidcore

$(call dist-for-goals, droid, /

$(INTERNAL_UPDATE_PACKAGE_TARGET) /

$(INTERNAL_OTA_PACKAGE_TARGET) /

$(SYMBOLS_ZIP) /

$(APPS_ZIP) /

$(INTERNAL_EMULATOR_PACKAGE_TARGET) /

$(PACKAGE_STATS_FILE) /

$(INSTALLED_FILES_FILE) /

$(INSTALLED_BUILD_PROP_TARGET) /

$(BUILT_TARGET_FILES_PACKAGE) /

)

# Tests are installed in userdata.img. If we're building the tests

# variant, copy it for "make tests dist". Also copy a zip of the

# contents of userdata.img, so that people can easily extract a

# single .apk.

ifeq ($(TARGET_BUILD_VARIANT),tests)

$(call dist-for-goals, droid, /

$(INSTALLED_USERDATAIMAGE_TARGET) /

$(BUILT_TESTS_ZIP_PACKAGE) /

)

endif

.PHONY: docs

docs: $(ALL_DOCS)

.PHONY: sdk

ALL_SDK_TARGETS := $(INTERNAL_SDK_TARGET)

sdk: $(ALL_SDK_TARGETS)

$(call dist-for-goals,sdk,$(ALL_SDK_TARGETS))

.PHONY: findbugs

findbugs: $(INTERNAL_FINDBUGS_HTML_TARGET) $(INTERNAL_FINDBUGS_XML_TARGET)

.PHONY: clean

dirs_to_clean := /

$(PRODUCT_OUT) /

$(TARGET_COMMON_OUT_ROOT) /

$(HOST_OUT) /

$(HOST_COMMON_OUT_ROOT)

clean:

@for dir in $(dirs_to_clean) ; do /

echo "Cleaning $$dir..."; /

rm -rf $$dir; /

done

@echo "Clean."; /

.PHONY: clobber

clobber:

@rm -rf $(OUT_DIR)

@echo "Entire build directory removed."

# The rules for dataclean and installclean are defined in cleanbuild.mk.

#xxx scrape this from ALL_MODULE_NAME_TAGS

.PHONY: modules

modules:

@echo "Available sub-modules:"

@echo "$(call module-names-for-tag-list,$(ALL_MODULE_TAGS))" | /

sed -e 's/ *//n/g' | sort -u | $(COLUMN)

.PHONY: showcommands

showcommands:

@echo >/dev/null

更多相关文章

  1. android gen文件不生成、R文件报错
  2. Android 4.0 Launcher2源码分析——主布局文件
  3. 丢失Android系统库或者Conversion to Dalvik format failed with
  4. Android、iOS系统架构
  5. Android 系统framework 概述【转载】

随机推荐

  1. Android学习之界面篇(一)Android(安卓)Anim
  2. 【原创】Android之修改AlertDialog对话框
  3. Android(安卓)Bluetooth 总结
  4. 【Android高级】DexClassloader和PathCla
  5. Android(安卓)Robotium搭建环境测试微信
  6. [置顶] Android的IPC访问控制设计与实现
  7. Android应用程序的自动更新升级(自身升级
  8. win10环境下Android(安卓)SDK下载安装及
  9. Android和蓝牙GPS结合的方法
  10. Android(安卓)属性动画