Android编译环境初始化,核心文件层级关系,阅读时可以参考
├──build/envsetup.sh
│ ├── device/vendor-platform/my-product/vendorsetup.sh
│
├── build/core/config.mk
│ ├── build/core/envsetup.mk
│ │ ├── build/core/product_config.mk
│ │ │ ├── build/core/node_fns.mk
│ │ │ ├── build/core/product.mk
│ │ │ │ ├── device/vendor-platform/my-product/AndroidProducts.mk
│ │ │ │ │ ├── device/vendor-platform/my-product/my_product.mk
│ │ │ │
│ │ │ ├── build/core/device.mk
│ │
│ ├── device/vendor-platform/my-product/BoardConfig.mk
│ └── build/core/dumpvar.mk
------------------------------------------------------------------------------------------------
$ source build/envsetup.sh
including device/moto/stingray/vendorsetup.sh
including device/samsung/maguro/vendorsetup.sh
including device/samsung/toro/vendorsetup.sh
including device/samsung/tuna/vendorsetup.sh
including device/vendor-platform/my-product/vendorsetup.sh
including device/vendor-platform/apollo-a70tb/vendorsetup.sh
including sdk/bash_completion/adb.bash
envsetup.sh有两个主要目的:
1.定义一些全局函数和一些命令 比如:add_lunch_combo、mm、jgrep等等
2.加载我们自己定义的产品 比如: my_product-eng
------------------------------------------------------------------------------------------------
$ vi build/envsetup.sh -c $ 友情提示: 编辑模式下“:$” 为跳到文件末尾
# Execute the contents of any vendorsetup.sh files we can find.
for f in `/bin/ls vendor/*/vendorsetup.sh vendor/*/*/vendorsetup.sh device/*/*/vendorsetup.sh 2> /dev/null`
do
echo "including $f"
. $f --> 执行 xxx/vendorsetup.sh
done
unset f
执行envsetup.sh第一步就是通过 for 去遍历 vendor、device下面的vendorsetup.sh 文件,目的是去加载我们自定义的产品
------------------------------------------------------------------------------------------------
vendorsetup.sh 我们自己产品,和相关模块加载都定义在这个文件里面
abner@THTFIT-Compiler:~/allwinner/a10/android$ vi device/vendor-platform/my-product/vendorsetup.sh
add_lunch_combo my_product-eng
------------------------------------------------------------------------------------------------
add_lunch_combo函数定义在 build/envsetup.sh
$ vi build/envsetup.sh -c /add_lunch_combo
# Clear this variable. It will be built up again when the vendorsetup.sh
# files are included at the end of this file.
unset LUNCH_MENU_CHOICES
function add_lunch_combo()
{
local new_combo=$1
local c
for c in ${LUNCH_MENU_CHOICES[@]} ; do --> "@" 表示数组所有元素
if [ "$new_combo" = "$c" ] ; then
return
fi
done
LUNCH_MENU_CHOICES=(${LUNCH_MENU_CHOICES[@]} $new_combo) --> 等同于 “array = array + new” 模式
}
LUNCH_MENU_CHOICES : 这个里面保存的就是,在lunch时终端展示给我们的选单
所以到了这步我们就可以lunch了
------------------------------------------------------------------------------------------------
$ lunch
You're building on Linux
Lunch menu... pick a combo:
1. full-eng --> 这个就是通过 add_lunch_combo 函数加载进来的
2. full_x86-eng
3. vbox_x86-eng
4. full_stingray-userdebug
5. full_wingray-userdebug
6. full_crespo4g-userdebug
7. full_crespo-userdebug
8. full_maguro-userdebug
9. full_toro-userdebug
10. full_tuna-userdebug
11. my_product-eng
Which would you like? [full-eng]11
============================================
PLATFORM_VERSION_CODENAME=REL
PLATFORM_VERSION=4.0.4
TARGET_PRODUCT=my_product
TARGET_BUILD_VARIANT=eng
TARGET_BUILD_TYPE=release
TARGET_BUILD_APPS=
TARGET_ARCH=arm
TARGET_ARCH_VARIANT=armv7-a-neon
HOST_ARCH=x86
HOST_OS=linux
HOST_BUILD_TYPE=release
BUILD_ID=IMM76D
============================================
------------------------------------------------------------------------------------------------
接下来分析lunch
$ vi build/envsetup.sh -c /lunch\(\)
function lunch()
{
local answer
if [ "$1" ] ; then
answer=$1
else
print_lunch_menu --> 如果lunch没有参数,则打印列表
echo -n "Which would you like? [full-eng] "
read answer --> 等待用户输入
fi
local selection=
if [ -z "$answer" ]
then
selection=full-eng
elif (echo -n $answer | grep -q -e "^[0-9][0-9]*$") --> 匹配0-9数值,-q 为静默模式,不向标准输出,输出信息
then
if [ $answer -le ${#LUNCH_MENU_CHOICES[@]} ] --> #LUNCH_MENU_CHOICES[@] 求整个数组长度
then
selection=${LUNCH_MENU_CHOICES[$(($answer-1))]}
fi
elif (echo -n $answer | grep -q -e "^[^\-][^\-]*-[^\-][^\-]*$") --> 匹配类似abc-efg,字符串部分不能有“-”的字符串
then
selection=$answer --> 获得要选择的产品,我们选择11,对应 “my_product-eng”
fi
if [ -z "$selection" ]
then
echo
echo "Invalid lunch combo: $answer"
return 1
fi
export TARGET_BUILD_APPS=
local product=$(echo -n $selection | sed -e "s/-.*$//") --> 意思是用空“”去替换“-”开始后面的串,就得到product
对应例子: my_product
check_product $product --> 检测产品等一系列动作
if [ $? -ne 0 ]
then
echo
echo "** Don't have a product spec for: '$product'"
echo "** Do you have the right repo manifest?"
product=
fi
local variant=$(echo -n $selection | sed -e "s/^[^\-]*-//") --> 同理替换前面字符串,对应:eng
check_variant $variant
if [ $? -ne 0 ]
then
echo
echo "** Invalid variant: '$variant'"
echo "** Must be one of ${VARIANT_CHOICES[@]}"
variant=
fi
if [ -z "$product" -o -z "$variant" ]
then
echo
return 1
fi
export TARGET_PRODUCT=$product
export TARGET_BUILD_VARIANT=$variant
export TARGET_BUILD_TYPE=release
echo
set_stuff_for_environment
printconfig
if [ "$NEED_TOUCH_SWITCH_PRODUCT_FILE" = "1" ]; then #added by lxj 2013-12-09
touch_switch_product_file
NEED_TOUCH_SWITCH_PRODUCT_FILE="0"
fi
}
------------------------------------------------------------------------------------------------
lunch打印函数
$ vi build/envsetup.sh -c /print_lunch_menu\(\)
function print_lunch_menu()
{
local uname=$(uname) --> 执行uname命令获得编译平台 等同: “local uname=`uname`”
echo
echo "You're building on" $uname
echo
echo "Lunch menu... pick a combo:"
local i=1
local choice
for choice in ${LUNCH_MENU_CHOICES[@]}
do
echo " $i. $choice" --> 打印选单
i=$(($i+1))
done
echo
}
------------------------------------------------------------------------------------------------
$ vi build/envsetup.sh -c /check_product\(\)
# check to see if the supplied product is one we can build
function check_product()
{
T=$(gettop)
if [ ! "$T" ]; then
echo "Couldn't locate the top of the tree. Try setting TOP." >&2
return
fi
CALLED_FROM_SETUP=true BUILD_SYSTEM=build/core \
TARGET_PRODUCT=$1 \ --> TARGET_PRODUCT = my_product
TARGET_BUILD_VARIANT= \
TARGET_BUILD_TYPE= \
TARGET_BUILD_APPS= \
get_build_var TARGET_DEVICE > /dev/null --> 调用函数 get_build_var TARGET_DEVICE
# hide successful answers, but allow the errors to show
}
------------------------------------------------------------------------------------------------
$ vi build/envsetup.sh -c /get_build_var\(\)
# Get the exact value of a build variable.
function get_build_var()
{
T=$(gettop)
if [ ! "$T" ]; then
echo "Couldn't locate the top of the tree. Try setting TOP." >&2
return
fi
CALLED_FROM_SETUP=true BUILD_SYSTEM=build/core \
make --no-print-directory -C "$T" -f build/core/config.mk dumpvar-$1
--> 相当于 make -f build/core/config.mk dumpvar-TARGET_DEVICE
}
------------------------------------------------------------------------------------------------
下一步我们要分析
vi build/core/config.mk
# Define most of the global variables. These are the ones that
# are specific to the user's build configuration.
include $(BUILD_SYSTEM)/envsetup.mk --> BUILD_SYSTEM在envsetup.sh定义,相当于build/core/envsetup.mk
定义了各种目标文件的目录,还用来确定“TARGET_DEVICE”
# 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 := \ --> 遍历build/target、device、vendor这几个目录的BoardConfig.mk文件,主要是板的配置信息
这里比较核心的问题就是如何确定“TARGET_DEVICE”
$(strip $(wildcard \
$(SRC_TARGET_DIR)/board/$(TARGET_DEVICE)/BoardConfig.mk \
device/*/$(TARGET_DEVICE)/BoardConfig.mk \
vendor/*/$(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)
...
include $(BUILD_SYSTEM)/dumpvar.mk
config.mk主要引入这几个文件envsetup.mk、BoardConfig.mk、dumpvar.mk
------------------------------------------------------------------------------------------------
$ vi build/core/envsetup.mk
分析和“TARGET_DEVICE”相关代码
# Read the product specs so we an get TARGET_DEVICE and other
# variables that we need in order to locate the output files.
include $(BUILD_SYSTEM)/product_config.mk
这是目标产品输出目录
ifneq ($(TARGET_BUILD_TYPE),debug)
TARGET_BUILD_TYPE := release
endif
TARGET_OUT_ROOT := $(TARGET_OUT_ROOT_$(TARGET_BUILD_TYPE))
TARGET_PRODUCT_OUT_ROOT := $(TARGET_OUT_ROOT)/product
PRODUCT_OUT := $(TARGET_PRODUCT_OUT_ROOT)/$(TARGET_DEVICE)
------------------------------------------------------------------------------------------------
$ vi build/core/product_config.mk
# Include the product definitions.
# We need to do this to translate TARGET_PRODUCT into its
# underlying TARGET_DEVICE before we start defining any rules.
#
include $(BUILD_SYSTEM)/node_fns.mk --> 定义函数 import-nodes
include $(BUILD_SYSTEM)/product.mk --> 定义函数 import-products、resolve-short-product-name、
get-all-product-makefiles、get-product-makefiles
include $(BUILD_SYSTEM)/device.mk
ifneq ($(strip $(TARGET_BUILD_APPS)),)
# An unbundled app build needs only the core product makefiles.
$(call import-products,$(call get-product-makefiles,\
$(SRC_TARGET_DIR)/product/AndroidProducts.mk)) --> build/target/product/AndroidProducts.mk
里面定义了一下些核心产品的makefile文件,比如core.mk
一并添加到“PRODUCT_MAKEFILES”
else
# Read in all of the product definitions specified by the AndroidProducts.mk
# files in the tree.
#
#TODO: when we start allowing direct pointers to product files,
# guarantee that they're in this list.
$(call import-products, $(get-all-product-makefiles)) --> 遍历所有AndroidProducts.mk,比如我们自己定义的产品
vi device/vendor-platform/my-product/AndroidProducts.mk
PRODUCT_MAKEFILES := $(LOCAL_DIR)/my_product.mk
endif # TARGET_BUILD_APPS
$(check-all-products)
ifneq ($(filter dump-products, $(MAKECMDGOALS)),)
$(dump-products)
$(error done)
endif
# Convert a short name like "sooner" into the path to the product
# file defining that product.
#
INTERNAL_PRODUCT := $(call resolve-short-product-name, $(TARGET_PRODUCT))
--> $(TARGET_PRODUCT)为my_product,resolve-short-product-name 函数通过产品名字获取makefile文件
--> 根据如下分析可以得出 “INTERNAL_PRODUCT” 为 device/vendor-platform/my-product/my_product.mk
#$(error TARGET_PRODUCT $(TARGET_PRODUCT) --> $(INTERNAL_PRODUCT))
# Find the device that this product maps to.
TARGET_DEVICE := $(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_DEVICE)
--> 等同于:
--> TARGET_DEVICE := $(PRODUCTS.device/vendor-platform/my-product/my_product.mk.PRODUCT_DEVICE)
--> "PRODUCTS.device/vendor-platform/my-product/my_product.mk.PRODUCT_DEVICE" 在 node_fns.mk分析给出,见如下分析
--> 最终得出: TARGET_DEVICE := my_product
------------------------------------------------------------------------------------------------
build/core/product.mk
#
# Returns the list of all AndroidProducts.mk files.
# $(call ) isn't necessary.
#
define _find-android-products-files --> 查找device、vendor、build/target/product 目录下说所有的AndroidProducts.mk
$(shell test -d device && find device -maxdepth 6 -name AndroidProducts.mk) \
$(shell test -d vendor && find vendor -maxdepth 6 -name AndroidProducts.mk) \
$(SRC_TARGET_DIR)/product/AndroidProducts.mk
endef
#
# Returns the sorted concatenation of PRODUCT_MAKEFILES
# variables set in the given AndroidProducts.mk files.
# $(1): the list of AndroidProducts.mk files.
#
define get-product-makefiles
$(sort \
$(foreach f,$(1), \
$(eval PRODUCT_MAKEFILES :=) \
$(eval LOCAL_DIR := $(patsubst %/,%,$(dir $(f)))) \
$(eval include $(f)) \ --> 包含 device/xxx/AndroidProducts.mk
$(PRODUCT_MAKEFILES) \ --> 具体产品的makefile文件,返回给调用者,比如:device/xxx/my_product.mk
) \
$(eval PRODUCT_MAKEFILES :=) \
$(eval LOCAL_DIR :=) \
)
endef
#
# Returns the sorted concatenation of all PRODUCT_MAKEFILES
# variables set in all AndroidProducts.mk files.
# $(call ) isn't necessary.
#
define get-all-product-makefiles
$(call get-product-makefiles,$(_find-android-products-files))
endef
_product_var_list := \ --> 具体每个产品属性定义在“PRODUCT_MAKEFILES”
如: device/vendor-platform/my-product/my_product.mk
PRODUCT_NAME \
PRODUCT_MODEL \
PRODUCT_LOCALES \
PRODUCT_AAPT_CONFIG \
PRODUCT_AAPT_PREF_CONFIG \
PRODUCT_PACKAGES \
PRODUCT_DEVICE \
PRODUCT_MANUFACTURER \
PRODUCT_BRAND \
PRODUCT_PROPERTY_OVERRIDES \
PRODUCT_DEFAULT_PROPERTY_OVERRIDES \
PRODUCT_CHARACTERISTICS \
PRODUCT_COPY_FILES \
PRODUCT_OTA_PUBLIC_KEYS \
PRODUCT_EXTRA_RECOVERY_KEYS \
PRODUCT_PACKAGE_OVERLAYS \
DEVICE_PACKAGE_OVERLAYS \
PRODUCT_TAGS \
PRODUCT_SDK_ADDON_NAME \
PRODUCT_SDK_ADDON_COPY_FILES \
PRODUCT_SDK_ADDON_COPY_MODULES \
PRODUCT_SDK_ADDON_DOC_MODULES \
PRODUCT_DEFAULT_WIFI_CHANNELS \
PRODUCT_DEFAULT_DEV_CERTIFICATE \
#
# $(1): product makefile list
#
#TODO: check to make sure that products have all the necessary vars defined
define import-products
$(call import-nodes,PRODUCTS,$(1),$(_product_var_list)) --> PRODUCTS 为返回的产品信息
endef
#
# Returns the product makefile path for the product with the provided name
#
# $(1): short product name like "generic"
#
define _resolve-short-product-name --> 根据product名字获得产品的makefile文件路径
$(eval pn := $(strip $(1)))
$(eval p := \
$(foreach p,$(PRODUCTS), \
$(if $(filter $(pn),$(PRODUCTS.$(p).PRODUCT_NAME)), \ --> 这个就是my_product.mk定义的产品名字
$(p) \
)) \
)
$(eval p := $(sort $(p)))
$(if $(filter 1,$(words $(p))), \
$(p), \
$(if $(filter 0,$(words $(p))), \
$(error No matches for product "$(pn)"), \
$(error Product "$(pn)" ambiguous: matches $(p)) \
) \
)
endef
define resolve-short-product-name
$(strip $(call _resolve-short-product-name,$(1)))
endef
------------------------------------------------------------------------------------------------
$ vi device/vendor-platform/my-product/my_product.mk
# Overrides
PRODUCT_BRAND := abner
PRODUCT_NAME := my_product
PRODUCT_DEVICE := my-product
PRODUCT_MODEL := love-1026
------------------------------------------------------------------------------------------------
$ find . -name "AndroidProducts.mk"
./device/vendor-platform/my-product/AndroidProducts.mk
./device/samsung/crespo/AndroidProducts.mk
./device/samsung/tuna/AndroidProducts.mk
./build/target/product/AndroidProducts.mk
$ vi device/vendor-platform/my-product/AndroidProducts.mk
PRODUCT_MAKEFILES := \
$(LOCAL_DIR)/my_product.mk \
$(LOCAL_DIR)/my_product_tw.mk
------------------------------------------------------------------------------------------------
$ vi build/core/node_fns.mk
# $(1): output list variable name, like "PRODUCTS" or "DEVICES"
# $(2): list of makefiles representing nodes to import
# $(3): list of node variable names
#
define import-nodes
$(if \
$(foreach _in,$(2), \
$(eval _node_import_context := _nic.$(1).[[$(_in)]]) \
$(if $(_include_stack),$(eval $(error ASSERTION FAILED: _include_stack \
should be empty here: $(_include_stack))),) \
$(eval _include_stack := ) \
$(call _import-nodes-inner,$(_node_import_context),$(_in),$(3)) \
$(call move-var-list,$(_node_import_context).$(_in),$(1).$(_in),$(3)) \ --> 分析见下
$(eval _node_import_context :=) \
$(eval $(1) := $($(1)) $(_in)) \ --> 返回的“PRODUCTS”,就是$(2)里面的值累加
$(if $(_include_stack),$(eval $(error ASSERTION FAILED: _include_stack \
should be empty here: $(_include_stack))),) \
) \
,)
endef
#
# $(1): context prefix
# $(2): makefile representing this node
# $(3): list of node variable names
#
# _include_stack contains the list of included files, with the most recent files first.
define _import-node
$(eval _include_stack := $(2) $$(_include_stack))
$(call clear-var-list, $(3))
$(eval LOCAL_PATH := $(patsubst %/,%,$(dir $(2))))
$(eval MAKEFILE_LIST :=)
$(eval include $(2))
$(eval _included := $(filter-out $(2),$(MAKEFILE_LIST)))
$(eval MAKEFILE_LIST :=)
$(eval LOCAL_PATH :=)
$(call copy-var-list, $(1).$(2), $(3)) --> 分析见下
$(call clear-var-list, $(3))
$(eval $(1).$(2).inherited := \
$(call get-inherited-nodes,$(1).$(2),$(3)))
$(call _import-nodes-inner,$(1),$($(1).$(2).inherited),$(3))
$(call _expand-inherited-values,$(1),$(2),$(3))
$(eval $(1).$(2).inherited :=)
$(eval _include_stack := $(wordlist 2,9999,$$(_include_stack)))
endef
# $(1): destination prefix
# $(2): list of variable names to copy
define copy-var-list
$(foreach v,$(2),$(eval $(strip $(1)).$(v):=$($(v))))
endef
# $(1): source prefix
# $(2): destination prefix
# $(3): list of variable names to move
define move-var-list
$(foreach v,$(3), \
$(eval $(2).$(v) := $($(1).$(v))) \
$(eval $(1).$(v) :=) \
)
endef
调试分析:$(info print info : $(xo))
$(call copy-var-list, $(1).$(2), $(3))
$(1).$(2) --> _nic.PRODUCTS.[[device/vendor-platform/my-product/my_product.mk]].device/vendor-platform/my-product/my_product.mk
$(3) --> PRODUCT_NAME PRODUCT_MODEL PRODUCT_LOCALES
根据 copy-var-list定义
$(foreach v,$(2),$(eval $(strip $(1)).$(v):=$($(v))))
_nic.PRODUCTS.[[device/vendor-platform/my-product/my_product.mk]].device/vendor-platform/my-product/my_product.mk.PRODUCT_NAME := $(PRODUCT_NAME)
move-var-list
$(2).$(v) := $($(1).$(v)
PRODUCTS.device/vendor-platform/my-product/my_product.mk.PRODUCT_NAME := $(_nic.PRODUCTS.[[device/vendor-platform/my-product/my_product.mk]].device/vendor-platform/my-product/my_product.mk.PRODUCT_NAME)
--> PRODUCTS.device/vendor-platform/my-product/my_product.mk.PRODUCT_NAME =: $(PRODUCT_NAME) //my_product
--> PRODUCTS.device/vendor-platform/my-product/my_product.mk.PRODUCT_NAME =: my_product
--> PRODUCTS.device/vendor-platform/my-product/my_product.mk.PRODUCT_DEVICE =: my_product
--> PRODUCTS.device/vendor-platform/my-product/my_product.mk.PRODUCT_MODEL =: A15S2
------------------------------------------------------------------------------------------------
再次回到build/core/config.mk
include $(board_config_mk)
此时是包含 BoardConfig.mk,同样是在 build/target、device、vendor这几个目录寻找
例如:
$ vi device/vendor-platform/my-product/BoardConfig.mk
TARGET_NO_BOOTLOADER := true
TARGET_NO_RECOVERY := false
TARGET_NO_KERNEL := false
INSTALLED_KERNEL_TARGET := kernel
BOARD_KERNEL_BASE := 0x40000000
#BOARD_KERNEL_CMDLINE := console=ttyS0,115200 rw init=/init loglevel=8
TARGET_USERIMAGES_USE_EXT4 := true
BOARD_FLASH_BLOCK_SIZE := 4096
BOARD_SYSTEMIMAGE_PARTITION_SIZE := 335544320
#BOARD_USERDATAIMAGE_PARTITION_SIZE := 1073741824
BOARD_USES_GSENSOR_TYPE := bma250
BOARD_GSENSOR_DIRECT_X := true
BOARD_GSENSOR_DIRECT_Y := true
BOARD_GSENSOR_DIRECT_Z := true
BOARD_GSENSOR_XY_REVERT := false
BOARD_HAVE_BLUETOOTH := true
TARGET_HARDWARE_NAME := a15s2
主要定义了一些板载模块的相关配置信息
------------------------------------------------------------------------------------------------
再一次回到build/core/config.mk
include $(BUILD_SYSTEM)/dumpvar.mk
$ vi build/core/dumpvar.mk
# the setpath shell function in envsetup.sh uses this to figure out
# what to add to the path given the config we have chosen.
ifeq ($(CALLED_FROM_SETUP),true)
ABP:=$(PWD)/$(HOST_OUT_EXECUTABLES)
# Add the toolchain bin dir if it actually exists
ifneq ($(wildcard $(PWD)/prebuilt/$(HOST_PREBUILT_TAG)/toolchain/arm-linux-androideabi-4.4.x/bin),)
# this should be copied to HOST_OUT_EXECUTABLES instead
ABP:=$(ABP):$(PWD)/prebuilt/$(HOST_PREBUILT_TAG)/toolchain/arm-linux-androideabi-4.4.x/bin
endif
ANDROID_BUILD_PATHS := $(ABP)
ANDROID_PREBUILTS := prebuilt/$(HOST_PREBUILT_TAG)
# 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)))) --> dumpvar_goals的值为 “TARGET_DEVICE”
ifdef dumpvar_goals
ifneq ($(words $(dumpvar_goals)),1) --> 只能有一个 dumpvar-TARGET_DEVICE 目标
$(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))
DUMPVAR_VALUE := $(PWD)/$($(dumpvar_goals))
dumpvar_target := dumpvar-abs-$(dumpvar_goals)
else
DUMPVAR_VALUE := $($(dumpvar_goals)) --> $(TARGET_DEVICE) 的值为 my_product
dumpvar_target := dumpvar-$(dumpvar_goals) --> dumpvar-TARGET_DEVICE
endif
.PHONY: $(dumpvar_target)
$(dumpvar_target): --> dumpvar-TARGET_DEVICE:
@echo $(DUMPVAR_VALUE) --> echo my_product
endif # dumpvar_goals
ifneq ($(dumpvar_goals),report_config) -->用来打印配置消息,如果目标是report_config才打印
PRINT_BUILD_CONFIG:=
endif
endif # CALLED_FROM_SETUP
ifneq ($(PRINT_BUILD_CONFIG),) --> 检查“PRINT_BUILD_CONFIG” 不为空才会打印
$(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_BUILD_TYPE=$(HOST_BUILD_TYPE))
$(info BUILD_ID=$(BUILD_ID))
$(info ============================================)
endif
最最终打印 -->
===========================================
PLATFORM_VERSION_CODENAME=REL
PLATFORM_VERSION=4.0.4
TARGET_PRODUCT=my_product
TARGET_BUILD_VARIANT=eng
TARGET_BUILD_TYPE=release
TARGET_BUILD_APPS=
TARGET_ARCH=arm
TARGET_ARCH_VARIANT=armv7-a-neon
HOST_ARCH=x86
HOST_OS=linux
HOST_BUILD_TYPE=release
BUILD_ID=IMM76D
============================================
------------------------------------------------------------------------------------------------
以上是chek_product 的过程分析,基本完毕
接下来就是 chek_variant的过程分析就很简单了
export TARGET_BUILD_APPS=
local product=$(echo -n $selection | sed -e "s/-.*$//")
echo "check product : $product"
check_product $product --> 具体分析见上
if [ $? -ne 0 ]
then
echo
echo "** Don't have a product spec for: '$product'"
echo "** Do you have the right repo manifest?"
product=
fi
local variant=$(echo -n $selection | sed -e "s/^[^\-]*-//")
check_variant $variant --> 检测变量是否为user、userdebug、eng其中一个
if [ $? -ne 0 ]
then
echo
echo "** Invalid variant: '$variant'"
echo "** Must be one of ${VARIANT_CHOICES[@]}"
variant=
fi
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
}
--> user表示发布版本
--> userdebug表示带调试信息的发布版本
--> eng表标工程机版本
------------------------------------------------------------------------------------------------
$ vi build/envsetup.sh
打印配置信息函数
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 --> 相当于 make -f build/core/config.mk dumpvar-report_config
}
check 完 product和variant 后再到 build/core/dumpvar.mk
dumpvar_goals := \ --> 此时“dumpvar_goals” 为 report_config
$(strip $(patsubst dumpvar-%,%,$(filter dumpvar-%,$(MAKECMDGOALS))))
.............
ifneq ($(dumpvar_goals),report_config) --> 如果是目标report_config,则不会设置“PRINT_BUILD_CONFIG”
PRINT_BUILD_CONFIG:=
endif
.............
ifneq ($(PRINT_BUILD_CONFIG),) "PRINT_BUILD_CONFIG" 定义在 build/core/envsetup.mk 默认设置为true
$(info ============================================)
$(info PLATFORM_VERSION_CODENAME=$(PLATFORM_VERSION_CODENAME))
$(info PLATFORM_VERSION=$(PLATFORM_VERSION))
........
$(info ============================================)
endif
------------------------------------------------------------------------------------------------
$ vi build/core/envsetup.mk
ifeq ($(PRINT_BUILD_CONFIG),)
PRINT_BUILD_CONFIG := true
endif
------------------------------------------------------------------------------------------------
至此,Android编译环境初始化过程基本分析完毕,但还有很多细节需要进一步完善
提示:在阅读时参照层级关系树,最好对着源码工程分析,逻辑就会很清晰明白了