| 
  再回到build/core/config.mk文件中,它最后加载build/core/dumpvar.mk文件。加载build/core/dumpvar.mk文件是为了生成make目标,以便可以对这些目标进行操作。例如,在我们这个情景中,我们要执行的make目标是dumpvar-TARGET_DEVICE,因此在加载build/core/dumpvar.mk文件的过程中,就会生成dumpvar-TARGET_DEVICE目标。        文件build/core/dumpvar.mk的内容也比较多,这里我们只关注生成make目标相关的逻辑:  
[plain] view plain copy 
 ![]() ![]()  
 
- ......  
 -   
 - # The "dumpvar" stuff lets you say something like  
 - #  
 - #     CALLED_FROM_SETUP=true \  
 - #       make -f config/envsetup.make dumpvar-TARGET_OUT  
 - # or  
 - #     CALLED_FROM_SETUP=true \  
 - #       make -f config/envsetup.make dumpvar-abs-HOST_OUT_EXECUTABLES  
 - #  
 - # The plain (non-abs) version just dumps the value of the named variable.  
 - # The "abs" version will treat the variable as a path, and dumps an  
 - # absolute path to it.  
 - #  
 - dumpvar_goals := \  
 -     $(strip $(patsubst dumpvar-%,%,$(filter dumpvar-%,$(MAKECMDGOALS))))  
 - ifdef dumpvar_goals  
 -   
 -   ifneq ($(words $(dumpvar_goals)),1)  
 -     $(error Only one "dumpvar-" goal allowed. Saw "$(MAKECMDGOALS)")  
 -   endif  
 -   
 -   # If the goal is of the form "dumpvar-abs-VARNAME", then  
 -   # treat VARNAME as a path and return the absolute path to it.  
 -   absolute_dumpvar := $(strip $(filter abs-%,$(dumpvar_goals)))  
 -   ifdef absolute_dumpvar  
 -     dumpvar_goals := $(patsubst abs-%,%,$(dumpvar_goals))  
 -     ifneq ($(filter /%,$($(dumpvar_goals))),)  
 -       DUMPVAR_VALUE := $($(dumpvar_goals))  
 -     else  
 -       DUMPVAR_VALUE := $(PWD)/$($(dumpvar_goals))  
 -     endif  
 -     dumpvar_target := dumpvar-abs-$(dumpvar_goals)  
 -   else  
 -     DUMPVAR_VALUE := $($(dumpvar_goals))  
 -     dumpvar_target := dumpvar-$(dumpvar_goals)  
 -   endif  
 -   
 - .PHONY: $(dumpvar_target)  
 - $(dumpvar_target):  
 -     @echo $(DUMPVAR_VALUE)  
 -   
 - endif # dumpvar_goals  
 -   
 - ......  
 
 
  
      我们在执行make命令时,指定的目示会经由MAKECMDGOALS变量传递到Makefile中,因此通过变量MAKECMDGOALS可以获得make目标。 
      上述代码的逻辑很简单,例如,在我们这个情景中,指定的make目标为dumpvar-TARGET_DEVICE,那么就会得到变量DUMPVAR_VALUE的值为$(TARGET_DEVICE)。TARGET_DEVICE的值在前面已经被设置为“generic”,因此变量DUMPVAR_VALUE的值就等于“generic”。此外,变量dumpvar_target的被设置为“dumpvar-TARGET_DEVICE”。最后我们就可以得到以下的make规则: 
 [plain] view plain copy 
 ![]() ![]()  
 
- .PHONY dumpvar-TARGET_DEVICE  
 - dumpvar-TARGET_DEVICE:  
 -     @echo generic  
 
 
  
       至此,在build/envsetup.sh文件中定义的函数check_product就分析完成了。看完了之后,小伙伴们可能会问,前面不是说这个函数是用来检查用户输入的产品名称是否合法的吗?但是这里没看出哪一段代码给出了true或者false的答案啊。实际上,在前面分析的build/core/config.mk和build/core/product_config.mk等文件的加载过程中,如果发现输入的产品名称是非法的,也就是找不到相应的产品Makefile文件,那么就会通过调用error函数来产生一个错误,这时候函数check_product的返回值$?就会等于非0值。 
       接下来我们还要继续分析在build/envsetup.sh文件中定义的函数check_variant的实现,如下所示:  
[plain] view plain copy 
 ![]() ![]()  
 
- VARIANT_CHOICES=(user userdebug eng)  
 -   
 - # check to see if the supplied variant is valid  
 - function check_variant()  
 - {  
 -     for v in ${VARIANT_CHOICES[@]}  
 -     do  
 -         if [ "$v" = "$1" ]  
 -         then  
 -             return 0  
 -         fi  
 -     done  
 -     return 1  
 - }  
 
 
  
       这个函数的实现就简单多了。合法的编译类型定义在数组VARIANT_CHOICES中,并且它只有三个值user、userdebug和eng。其中,user表示发布版本,userdebug表示带调试信息的发布版本,而eng表标工程机版本。 
       最后,我们再来分析在build/envsetup.sh文件中定义的函数printconfig的实现,如下所示:  
[plain] view plain copy 
 ![]() ![]()  
 
- function printconfig()  
 - {  
 -     T=$(gettop)  
 -     if [ ! "$T" ]; then  
 -         echo "Couldn't locate the top of the tree.  Try setting TOP." >&2  
 -         return  
 -     fi  
 -     get_build_var report_config  
 - }  
 
 
  
       对比我们前面对函数check_product的分析,就会发现函数printconfig的实现与这很相似,都是通过调用get_build_var来获得相关的信息,但是这里传递给函数get_build_var的参数为report_config。 
       我们跳过前面build/core/config.mk和build/core/envsetup.mk等文件对目标产品Makefile文件的加载,直接跳到build/core/dumpvar.mk文件来查看与report_config这个make目标相关的逻辑:  
[plain] view plain copy 
 ![]() ![]()  
 
- ......  
 -   
 - dumpvar_goals := \  
 -     $(strip $(patsubst dumpvar-%,%,$(filter dumpvar-%,$(MAKECMDGOALS))))  
 - .....  
 -   
 - ifneq ($(dumpvar_goals),report_config)  
 - PRINT_BUILD_CONFIG:=  
 - endif  
 -   
 - ......  
 -   
 - ifneq ($(PRINT_BUILD_CONFIG),)  
 - HOST_OS_EXTRA:=$(shell python -c "import platform; print(platform.platform())")  
 - $(info ============================================)  
 - $(info   PLATFORM_VERSION_CODENAME=$(PLATFORM_VERSION_CODENAME))  
 - $(info   PLATFORM_VERSION=$(PLATFORM_VERSION))  
 - $(info   TARGET_PRODUCT=$(TARGET_PRODUCT))  
 - $(info   TARGET_BUILD_VARIANT=$(TARGET_BUILD_VARIANT))  
 - $(info   TARGET_BUILD_TYPE=$(TARGET_BUILD_TYPE))  
 - $(info   TARGET_BUILD_APPS=$(TARGET_BUILD_APPS))  
 - $(info   TARGET_ARCH=$(TARGET_ARCH))  
 - $(info   TARGET_ARCH_VARIANT=$(TARGET_ARCH_VARIANT))  
 - $(info   HOST_ARCH=$(HOST_ARCH))  
 - $(info   HOST_OS=$(HOST_OS))  
 - $(info   HOST_OS_EXTRA=$(HOST_OS_EXTRA))  
 - $(info   HOST_BUILD_TYPE=$(HOST_BUILD_TYPE))  
 - $(info   BUILD_ID=$(BUILD_ID))  
 - $(info   OUT_DIR=$(OUT_DIR))  
 - $(info ============================================)  
 - endif  
 
 
  
       变量PRINT_BUILD_CONFIG定义在文件build/core/envsetup.mk中,默认值设置为true。当make目标为report-config的时候,变量PRINT_BUILD_CONFIG的值就会被设置为空。因此,接下来就会打印一系列用来描述编译环境配置的变量的值,也就是我们执行lunch命令后看到的输出。注意,这些环境配置相关的变量量都是在加载build/core/config.mk和build/core/envsetup.mk文件的过程中设置的,就类似于前面我们分析的TARGET_DEVICE变量的值的设置过程。 
       至此,我们就分析完成Android编译系统环境的初始化过程了。从分析的过程可以知道,Android编译系统环境是由build/core/config.mk、build/core/envsetup.mk、build/core/product_config.mk、AndroidProducts.mk和BoardConfig.mk等文件来完成的。这些mk文件涉及到非常多的细节,而我们这里只提供了一个大体的骨架和脉络,希望能够起到抛砖引玉的作用。  
 |