AOSP-编译系统是如何编译我们所选择的产品的?
上一篇文章AOSP-envsetup.sh里的lunch到底干了啥事情呢?
我们分析了source build/envsetup.sh
以后调用lunch方法去加载编译目标做了啥事情,由此我们了解到如何添加一个属于自己的编译目标。我们只要创建vendorsetup.sh
,调用此方法
add_lunch_combo 产品名-userdebug
注意事项:格式一定是产品名-userdebug/user/debug这样的格式
从源码中我们看到,它是要进行切割获取编译目标和构建形式
的。
但是,系统是如何编译我们所选中的构建目标的呢?我随便创建一个构建目标,它就可以编译出来吗?
显然不是,我们得有对应的配置文件。
编译入口Makefile,mk文件关系
我们在源码的根目录,可以看到有一个文件是Makefile
### DO NOT EDIT THIS FILE ###
include build/core/main.mk
### DO NOT EDIT THIS FILE ###
内容如上,当我们make
的时候,就会当前目录下Makefile去编译了。
从上面看,我们可以指导Makefile载入的是build/core/main.mk
文件
make.mk又载入了什么mk呢?
当然,子mk文件里还有载入子mk的,这是一个很庞大的tree.
有哪些mk文件是跟产品有关的呢?
一般来说,我们定义一个产品,要包括这些内容:
- 主板设备配置(硬件)
- 传感器配置
- 平台配置
- Uboot
- Kernel
- ....
- 产品配置(软件)
- 开机动画用哪个?
- 编译哪些应用软件
- 编译哪些库
- 配置信息
- ....
在哪里加载主板的配置信息,加载产品配置信息呢?
我们继续扩展前面的mk关系图
这图是我根据代码画出来的,接下来就说明一下。
首先config.mk里有加载envsetup.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
而evnsetup.mk加载了product_config.mk
# 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
product_config.mk加载了product.mk,device.mk 和其他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
include $(BUILD_SYSTEM)/product.mk
include $(BUILD_SYSTEM)/device.mk
在product.mk文件里,我们可以看到以下代码
#
# Functions for including AndroidProducts.mk files
# PRODUCT_MAKEFILES is set up in AndroidProducts.mks.
# Format of PRODUCT_MAKEFILES:
# <product_name>:<path_to_the_product_makefile>
# If the <product_name> is the same as the base file name (without dir
# and the .mk suffix) of the product makefile, "<product_name>:" can be
# omitted.
#
# Returns the list of all AndroidProducts.mk files.
# $(call ) isn't necessary.
#
define _find-android-products-files
$(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
以上代码就是搜寻AndroidProducts.mk文件,搜寻device目录下的,vendor目录下的,以及build/target目录下的。
到此,我们的产品相关的mk文件就找到了,至于是用谁我们后面再去分析。
我们再看看跟主板有关的配置文件加载是在哪里?
从前面的图,同学们应该已经看出了,在config.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') \
))
以上代码就是搜索vendor,device,build/target目录下的BoardConfig.mk文件。
由此,我们已经知道了主板配置文件和产品配置文件的查找了。其实此时有的是两个列表。
那么如何知道根据哪个来编译呢?
配置文件的过滤
加载产品相关的配置文件
在product_config.mk里,它通过product.mk获取到了AndroidProducts.mk列表,然后进行过滤
# Find the product config makefile for the current product.
# all_product_configs consists items like:
# <product_name>:<path_to_the_product_makefile>
# or just <path_to_the_product_makefile> in case the product name is the
# same as the base filename of the product config makefile.
current_product_makefile :=
all_product_makefiles :=
$(foreach f, $(all_product_configs),\
$(eval _cpm_words := $(subst :,$(space),$(f)))\
$(eval _cpm_word1 := $(word 1,$(_cpm_words)))\
$(eval _cpm_word2 := $(word 2,$(_cpm_words)))\
$(if $(_cpm_word2),\
$(eval all_product_makefiles += $(_cpm_word2))\
$(if $(filter $(TARGET_PRODUCT),$(_cpm_word1)),\
$(eval current_product_makefile += $(_cpm_word2)),),\
$(eval all_product_makefiles += $(f))\
$(if $(filter $(TARGET_PRODUCT),$(basename $(notdir $(f)))),\
$(eval current_product_makefile += $(f)),)))
_cpm_words :=
_cpm_word1 :=
_cpm_word2 :=
current_product_makefile := $(strip $(current_product_makefile))
all_product_makefiles := $(strip $(all_product_makefiles))
ifneq (,$(filter product-graph dump-products, $(MAKECMDGOALS)))
# Import all product makefiles.
$(call import-products, $(all_product_makefiles))
else
# Import just the current product.
ifndef current_product_makefile
$(error Can not locate config makefile for product "$(TARGET_PRODUCT)")
endif
ifneq (1,$(words $(current_product_makefile)))
$(error Product "$(TARGET_PRODUCT)" ambiguous: matches $(current_product_makefile))
endif
$(call import-products, $(current_product_makefile))
endif # Import all or just the current product makefile
过滤的代码也很简单,根据我们前面选的构建目标去过滤,然后导入对应的产品文件current_product_makefile
。
加载主板相关的配置信息
在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
# 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
TARGET_DEVICE_DIR := $(patsubst %/,%,$(dir $(board_config_mk)))
board_config_mk :=
这里面没有进行过滤,因为它是根据$(TARGET_DEVICE)
去加载的,如果不唯一怎么办呢?
后面就有判断了
ifneq ($(words $(board_config_mk)),1)
$(error Multiple board config files for TARGET_DEVICE $(TARGET_DEVICE): $(board_config_mk))
endif
如果找到多个,就会停止执行,输出提示。
这样子,我们就找到了跟主板相关的配置文件,然后include进来了。
整个过程,以及一些变量是在哪里控制的,请同学们看视频吧。