,在build/core/Makefile一開始就會先拷貝這個變量指定的文件。
6.加載BoardConfig.mk
又回到envsetup.mk中:
# Boards may be defined under $(SRC_TARGET_DIR)/board/$(TARGET_DEVICE)
# or under vendor/*/$(TARGET_DEVICE). Search in both places, but
# make sure only one exists.
# Real boards should always be associated with an OEM vendor.
board_config_mk := \
$(strip $(wildcard \
$(SRC_TARGET_DIR)/board/$(TARGET_DEVICE)/BoardConfig.mk \
$(shell test -d device && find device -maxdepth 4 -path '*/$(TARGET_DEVICE)/BoardConfig.mk') \
$(shell test -d vendor && find vendor -maxdepth 4 -path '*/$(TARGET_DEVICE)/BoardConfig.mk') \
))
ifeq ($(board_config_mk),)
$(error No config file found for TARGET_DEVICE $(TARGET_DEVICE))
endif
ifneq ($(words $(board_config_mk)),1)
$(error Multiple board config files for TARGET_DEVICE $(TARGET_DEVICE): $(board_config_mk))
endif
include $(board_config_mk)
ifeq ($(TARGET_ARCH),)
$(error TARGET_ARCH not defined by board config: $(board_config_mk))
endif
BoardConfig.mk中配置了重要的板級信息,比如cpu架構等。
至此,配置一個產品所需的AndroidProducts.mk,具體產品的配置文件,比如這裡的mini_x86.mk以及BoardConfig.mk都加載進來了。
三.加載所有模塊
加載完單板信息,make又回到main.mk中,不就就發現了ONE_SHOT_MAKEFILE變量的判斷:
1ONE_SHOT_MAKEFILE
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.
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-%: ;
# A helper goal printing out install paths
.PHONY: GET-INSTALL-PATH
GET-INSTALL-PATH:
@$(foreach m, $(ALL_MODULES), $(if $(ALL_MODULES.$(m).INSTALLED), \
echo 'INSTALL-PATH: $(m) $(ALL_MODULES.$(m).INSTALLED)';))
else # ONE_SHOT_MAKEFILE
ifneq ($(dont_bother),true)
#
# Include all of the makefiles in the system
#
# Can't use first-makefiles-under here because
# --mindepth=2 makes the prunes not work.
subdir_makefiles := \
$(shell build/tools/findleaves.py --prune=$(OUT_DIR) --prune=.repo --prune=.git $(subdirs) Android.mk)
$(foreach mk, $(subdir_makefiles), $(info including $(mk) ...)$(eval include $(mk)))
endif # dont_bother
endif # ONE_SHOT_MAKEFILE
如果這個變量定義了,那麼,就是編譯一個模塊,在上一篇博客中已將分析過了,如果沒有定義,就說明是編譯整個系統。
MAKECMDGOALS是make的一個環境變量,當我們執行make的時候並沒有設置它,因此它為空。所以dont_bother不等於true,因此,就會加載所有的Android.mk.這裡使用
一個python腳本查找系統中所有的Android.mk,然後Include進來。
四 收集所有要安裝的模塊
在main.mk中繼續往下看:
3.1FULL_BUILD
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.mk. product_MODULES := $(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_PACKAGES) # Filter out the overridden packages before doing expansion product_MODULES := $(filter-out $(foreach p, $(product_MODULES), \ $(PACKAGES.$(p).OVERRIDES)), $(product_MODULES)) # Resolve the :32 :64 module name modules_32 := $(patsubst %:32,%,$(filter %:32, $(product_MODULES))) modules_64 := $(patsubst %:64,%,$(filter %:64, $(product_MODULES))) modules_rest := $(filter-out %:32 %:64,$(product_MODULES)) # Note for 32-bit product, $(modules_32) and $(modules_64) will be # added as their original module names. product_MODULES := $(call get-32-bit-modules-if-we-can, $(modules_32)) product_MODULES += $(modules_64) # For the rest we add both product_MODULES += $(call get-32-bit-modules, $(modules_rest)) product_MODULES += $(modules_rest) $(call expand-required-modules,product_MODULES,$(product_MODULES)) product_FILES := $(call module-installed-files, $(product_MODULES)) ifeq (0,1) $(info product_FILES for $(TARGET_DEVICE) ($(INTERNAL_PRODUCT)):) $(foreach p,$(product_FILES),$(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. product_FILES := endif
在執行make的時候,FULL_BUILD:=true
product_MODULES是所有產品配置文件中添加的要打包進系統鏡像中的模塊,它只是一個名字,比如上篇博客分析過的screencap。
product_FILES獲取對應模塊的.INSTALLED的值。
define module-installed-files $(foreach module,$(1),$(ALL_MODULES.$(module).INSTALLED)) endef
在加載單個模塊的時候,會給每一個模塊生成另外兩個值:
$(ALL_MODULES.$(target)).BUILT
$(ALL_MODULES.$(target)).INSTALLED
它們在base_rule.mk中生成:
ALL_MODULES.$(my_register_name).BUILT := \ $(ALL_MODULES.$(my_register_name).BUILT) $(LOCAL_BUILT_MODULE) ifneq (true,$(LOCAL_UNINSTALLABLE_MODULE)) ALL_MODULES.$(my_register_name).INSTALLED := \ $(strip $(ALL_MODULES.$(my_register_name).INSTALLED) $(LOCAL_INSTALLED_MODULE)) ALL_MODULES.$(my_register_name).BUILT_INSTALLED := \ $(strip $(ALL_MODULES.$(my_register_name).BUILT_INSTALLED) $(LOCAL_BUILT_MODULE):$(LOCAL_INSTALLED_MODULE)) endif
$(ALL_MODULES.$(target)).BUILT代表的一般是out/target/product/xxx/obj下編譯生成的模塊。
$(ALL_MODULES.$(target)).INSTALLED代表的是out/target/product/xxx/system下生成的模塊。
3.2 全部安裝模塊
modules_to_install := $(sort \
$(ALL_DEFAULT_INSTALLED_MODULES) \
$(product_FILES) \
$(foreach tag,$(tags_to_install),$($(tag)_MODULES)) \
$(CUSTOM_MODULES) \
)
ALL_DEFAULT_INSTALLED_MODULES是系統默認要安裝的模塊,product_FILES是特定產品附加的要安裝的模塊,foreach找到的是特定
TAG的模塊,以及加上CUSTOM_MODULES,這樣modules_to_install就是全部的要安裝的模塊了。
ALL_DEFAULT_INSTALLED_MODULES := $(modules_to_install) include $(BUILD_SYSTEM)/Makefile
然後把modules_to_install的值全部賦給ALL_DEFAULT_INSTALLED_MODULES,接著加載build/core/Makefile。這個Makefile會使用
ALL_DEFAULT_INSTALLED_MODULES變量最終生成所有的鏡像文件。生成鏡像文件的過程放在下一節討論。
四.編譯所有模塊
依賴關系我們在一開始就做了簡單的梳理,現在開始分析編譯所有模塊的依賴關系。
從droid目標定義的地方來看,沒有看到它的依賴,但我們向下搜索,就會發現:
.PHONY: apps_only
apps_only: $(unbundled_build_modules)
droid: apps_only
# Building a full system-- the default is to build droidcore
droid: droidcore dist_files
我們會發現它有出現了兩個依賴,那它到底依賴哪一個呢?
droid依賴哪一個取決於ifneq ($(TARGET_BUILD_APPS),)是否成立,也就是有沒有給TARGET_BUILD_APPS賦值過,源碼如下:
ifneq ($(TARGET_BUILD_APPS),)
# If this build is just for apps, only build apps and not the full system by default.
unbundled_build_modules :=
ifneq ($(filter all,$(TARGET_BUILD_APPS)),)
# If they used the magic goal "all" then build all apps in the source tree.
unbundled_build_modules := $(foreach m,$(sort $(ALL_MODULES)),$(if $(filter APPS,$(ALL_MODULES.$(m).CLASS)),$(m)))
else
unbundled_build_modules := $(TARGET_BUILD_APPS)
endif
...
.PHONY: apps_only
apps_only: $(unbundled_build_modules)
droid: apps_only
else # TARGET_BUILD_APPS
$(call dist-for-goals, droidcore, \
$(INTERNAL_UPDATE_PACKAGE_TARGET) \
$(INTERNAL_OTA_PACKAGE_TARGET) \
$(BUILT_OTATOOLS_PACKAGE) \
$(SYMBOLS_ZIP) \
$(INSTALLED_FILES_FILE) \
$(INSTALLED_BUILD_PROP_TARGET) \
$(BUILT_TARGET_FILES_PACKAGE) \
$(INSTALLED_ANDROID_INFO_TXT_TARGET) \
$(INSTALLED_RAMDISK_TARGET) \
)
# Building a full system-- the default is to build droidcore
droid: droidcore dist_files
endif # TARGET_BUILD_APPS
我們期望的是整個系統的編譯,所以,droid依賴的是droidcore 和 dist_files
4.1droidcore的定義:
# 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_CACHEIMAGE_TARGET) \
$(INSTALLED_VENDORIMAGE_TARGET) \
$(INSTALLED_FILES_FILE)
可以droidcore又是一個偽目標,它又依賴於files 等一系列目標,從名字來看,這些目標應該是systemimage,userdataimage,recoryimage等,也就是說,droidcore的最終目的就是生成system.img,userdata.img等系統鏡像文件。
看到變量的定義就明白了:
1.boot.img:
INSTALLED_BOOTIMAGE_TARGET := $(PRODUCT_OUT)/boot.img
2.recovery.img:
INSTALLED_RECOVERYIMAGE_TARGET := $(PRODUCT_OUT)/recovery.img
3.userdata.img:
INSTALLED_USERDATAIMAGE_TARGET := $(BUILT_USERDATAIMAGE_TARGET)
--->BUILT_USERDATAIMAGE_TARGET := $(PRODUCT_OUT)/userdata.img
4.cache.img
INSTALLED_CACHEIMAGE_TARGET := $(BUILT_CACHEIMAGE_TARGET)
--->BUILT_CACHEIMAGE_TARGET := $(PRODUCT_OUT)/cache.img
5.vendor.img
INSTALLED_VENDORIMAGE_TARGET := $(BUILT_VENDORIMAGE_TARGET)
BUILT_VENDORIMAGE_TARGET := $(PRODUCT_OUT)/vendor.img
因此,droidcore的最終目的就是生成這些.Img文件。
dist_files的定義:
# dist_files only for putting your library into the dist directory with a full build.
.PHONY: dist_files
從定義來看,dist_files也是個偽目標,並且它沒有任何依賴,作用是完整編譯系統的時候拷貝庫文件。
4.2.files
它的第一個目標是files:
# All the droid stuff, in directories
.PHONY: files
files: prebuilt \
$(modules_to_install) \
$(INSTALLED_ANDROID_INFO_TXT_TARGET)、
1.1files又依賴了三個目標,第一個是prebuilt:
# -------------------------------------------------------------------
# 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)
prebuilt又是一個偽目標,它又依賴於ALL_PREBUILT變量指向的目標,ALL_PREBUILT是一些預編譯模塊:
Android.mk (makefile\frameworks\base\cmds\bmgr):ALL_PREBUILT += $(TARGET_OUT)/bin/bmgr
Android.mk (makefile\frameworks\base\cmds\ime):ALL_PREBUILT += $(TARGET_OUT)/bin/ime
Android.mk (makefile\frameworks\base\cmds\input):ALL_PREBUILT += $(TARGET_OUT)/bin/input
Android.mk (makefile\frameworks\base\cmds\pm):ALL_PREBUILT += $(TARGET_OUT)/bin/pm
Android.mk (makefile\frameworks\base\cmds\svc):ALL_PREBUILT += $(TARGET_OUT)/bin/svc
4.3modules_to_install
modules_to_install := $(sort \
$(ALL_DEFAULT_INSTALLED_MODULES) \
$(product_FILES) \
$(foreach tag,$(tags_to_install),$($(tag)_MODULES)) \
$(CUSTOM_MODULES) \
)
這個變量之前已經分析過,它包含所有的要安裝的模塊,make會為這個目標生成依賴關系鏈,也就是會給其中的每一個模塊生成依賴關系鏈,然後編譯每一個模塊,這個過程在上一節中已經說過了。
至此,所有應該編譯的模塊都已經被編譯,剩下的就是打包鏡像文件了。這將在下一節討論。