七、AndroidProducts.mk

一、android build system编译系统概述
二、envsetup.sh脚本(Android10)
三、soong_ui.bash脚本
四、soong_ui的main.go
五、kati中调用main.mk
六、make目录中的main.mk
七、AndroidProducts.mk
八、module-info.json
九、子模块的执行


AndroidProducts.mk是什么

AndroidProducts.mk中定义了lunch-combolunch-combo对应的PRODUCT_MAKEFILESMakefile文件。

简单来说就是:

  1. lunch命令执行之后出来那些东西,就看AndroidProducts.mkCOMMON_LUNCH_CHOICES定义了啥
  2. lunch xxx执行之后,走那个product configMakefile文件,就看AndroidProducts.mkPRODUCT_MAKEFILES定义了啥

此外注意一下:

  • COMMON_LUNCH_CHOICES中定义的产品名需要和PRODUCT_MAKEFILES中定义的文件名(不考虑路径和.mk后缀)一样。

  • 如果不一样,需要在定义PRODUCT_MAKEFILES采用<product_name>:<path_to_the_product_makefile>格式

例子

/device/google/cuttlefish/AndroidProducts.mk中是AndroidProducts.mk

PRODUCT_MAKEFILES := \
	aosp_cf_arm64_phone:$(LOCAL_DIR)/vsoc_arm64/phone/device.mk \
	aosp_cf_x86_64_phone:$(LOCAL_DIR)/vsoc_x86_64/phone/device.mk \
	aosp_cf_x86_auto:$(LOCAL_DIR)/vsoc_x86/auto/device.mk \
	aosp_cf_x86_pasan:$(LOCAL_DIR)/vsoc_x86/pasan/device.mk \
	aosp_cf_x86_phone:$(LOCAL_DIR)/vsoc_x86/phone/device.mk \
	aosp_cf_x86_go_phone:$(LOCAL_DIR)/vsoc_x86/go_phone/device.mk \
	aosp_cf_x86_gsi:$(LOCAL_DIR)/vsoc_x86/gsi/aosp_cf_x86_gsi.mk \
	aosp_cf_x86_tv:$(LOCAL_DIR)/vsoc_x86/tv/device.mk

COMMON_LUNCH_CHOICES := \
	aosp_cf_arm64_phone-userdebug \
	aosp_cf_x86_64_phone-userdebug \
	aosp_cf_x86_auto-userdebug \
	aosp_cf_x86_phone-userdebug \
	aosp_cf_x86_tv-userdebug

AndroidProducts.mk怎么用

一般来说,AndroidProducts.mk中就定义两个变量PRODUCT_MAKEFILESCOMMON_LUNCH_CHOICES

尽量不要瞎几把乱加别的东西

/build/target/product/AndroidProducts.mk为例子

ifneq ($(TARGET_BUILD_APPS),)
PRODUCT_MAKEFILES := \
    $(LOCAL_DIR)/aosp_arm64.mk \
    $(LOCAL_DIR)/aosp_arm.mk \
    $(LOCAL_DIR)/aosp_x86_64.mk \
    $(LOCAL_DIR)/aosp_x86.mk \
    $(LOCAL_DIR)/full.mk \
    $(LOCAL_DIR)/full_x86.mk \

else
PRODUCT_MAKEFILES := \
    $(LOCAL_DIR)/aosp_arm64_ab.mk \
    $(LOCAL_DIR)/aosp_arm64.mk \
    $(LOCAL_DIR)/aosp_arm_ab.mk \
    $(LOCAL_DIR)/aosp_arm.mk \
    $(LOCAL_DIR)/aosp_x86_64_ab.mk \
    $(LOCAL_DIR)/aosp_x86_64.mk \
    $(LOCAL_DIR)/aosp_x86_ab.mk \
    $(LOCAL_DIR)/aosp_x86_arm.mk \
    $(LOCAL_DIR)/aosp_x86.mk \
    $(LOCAL_DIR)/full.mk \
    $(LOCAL_DIR)/full_x86.mk \
    $(LOCAL_DIR)/generic.mk \
    $(LOCAL_DIR)/generic_x86.mk \
    $(LOCAL_DIR)/gsi_arm64.mk \
    $(LOCAL_DIR)/mainline_arm64.mk \
    $(LOCAL_DIR)/mainline_system_arm64.mk \
    $(LOCAL_DIR)/sdk_arm64.mk \
    $(LOCAL_DIR)/sdk.mk \
    $(LOCAL_DIR)/sdk_phone_arm64.mk \
    $(LOCAL_DIR)/sdk_phone_armv7.mk \
    $(LOCAL_DIR)/sdk_phone_x86_64.mk \
    $(LOCAL_DIR)/sdk_phone_x86.mk \
    $(LOCAL_DIR)/sdk_x86_64.mk \
    $(LOCAL_DIR)/sdk_x86.mk \

endif

COMMON_LUNCH_CHOICES := \
    aosp_arm64-eng \
    aosp_arm-eng \
    aosp_x86_64-eng \
    aosp_x86-eng \

从上面的配置可知,google在AOSP源码中加了如下四个默认的lunch-combo配置

aosp_arm64-eng
aosp_arm-eng
aosp_x86_64-eng
aosp_x86-eng

对应的PRODUCT_MAKEFILES会根据TARGET_BUILD_APPS而变动

lunch-combo会用-分隔,前面的是项目名、后面是版本类型(useruserdebugeng

AndroidProducts.mk如何被加载

lunchAndroidProducts.mk.list

  1. 当用户执行lunch命令时会调用get_build_varbuild_build_var_cache等shell函数

  2. 这些shell函数又会调用build/soong/soong_ui.bash --dumpvar-mode

  3. soong_ui.bash走到/build/soong/cmd/soong_ui/main.go中的main函数中

  4. main函数中调用build.FindSources(buildCtx, config, f)

  5. FindSources代码逻辑如下

devicevendorproduct目录中查找AndroidProducts.mk文件。

并将所有的名为AndroidProducts.mk文件路径记录在AndroidProducts.mk.list

备注:这函数的作用不止如此,还会查找Android.mkAndroid.bpCleanSpec.mk等文件。

具体代码如下:

// FindSources searches for source files known to <f> and writes them to the filesystem for
// use later.
func FindSources(ctx Context, config Config, f *finder.Finder) {
	// note that dumpDir in FindSources may be different than dumpDir in NewSourceFinder
	// if a caller such as multiproduct_kati wants to share one Finder among several builds
	dumpDir := config.FileListDir()
	os.MkdirAll(dumpDir, 0777)

	androidMks := f.FindFirstNamedAt(".", "Android.mk")
	err := dumpListToFile(androidMks, filepath.Join(dumpDir, "Android.mk.list"))
	if err != nil {
		ctx.Fatalf("Could not export module list: %v", err)
	}

	androidProductsMks := f.FindNamedAt("device", "AndroidProducts.mk")
	androidProductsMks = append(androidProductsMks, f.FindNamedAt("vendor", "AndroidProducts.mk")...)
	androidProductsMks = append(androidProductsMks, f.FindNamedAt("product", "AndroidProducts.mk")...)
	err = dumpListToFile(androidProductsMks, filepath.Join(dumpDir, "AndroidProducts.mk.list"))
	if err != nil {
		ctx.Fatalf("Could not export product list: %v", err)
	}

	cleanSpecs := f.FindFirstNamedAt(".", "CleanSpec.mk")
	err = dumpListToFile(cleanSpecs, filepath.Join(dumpDir, "CleanSpec.mk.list"))
	if err != nil {
		ctx.Fatalf("Could not export module list: %v", err)
	}

	owners := f.FindNamedAt(".", "OWNERS")
	err = dumpListToFile(owners, filepath.Join(dumpDir, "OWNERS.list"))
	if err != nil {
		ctx.Fatalf("Could not find OWNERS: %v", err)
	}

	testMappings := f.FindNamedAt(".", "TEST_MAPPING")
	err = dumpListToFile(testMappings, filepath.Join(dumpDir, "TEST_MAPPING.list"))
	if err != nil {
		ctx.Fatalf("Could not find TEST_MAPPING: %v", err)
	}

	androidBps := f.FindNamedAt(".", "Android.bp")
	androidBps = append(androidBps, f.FindNamedAt("build/blueprint", "Blueprints")...)
	if len(androidBps) == 0 {
		ctx.Fatalf("No Android.bp found")
	}
	err = dumpListToFile(androidBps, filepath.Join(dumpDir, "Android.bp.list"))
	if err != nil {
		ctx.Fatalf("Could not find modules: %v", err)
	}
}

AndroidProducts.mk.list调用关系

AndroidProducts.mk.list会在makefile宏函数_find-android-products-files中被调用

_find-android-products-files宏函数

/build/make/core/product.mk文件中定义了该宏函数

代码如下:

#
# Returns the list of all AndroidProducts.mk files.
# $(call ) isn't necessary.
#
define _find-android-products-files
$(file <$(OUT_DIR)/.module_paths/AndroidProducts.mk.list) \
  $(SRC_TARGET_DIR)/product/AndroidProducts.mk
endef

$(_find-android-products-files)显示了所有AndroidProducts.mk的路径信息

get-all-product-makefiles宏函数

$(_find-android-products-files)get-all-product-makefiles调用

代码如下:

#
# 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

get-all-product-makefiles中,$(_find-android-products-files)作为参数,交给get-product-makefiles去处理

get-product-makefiles宏函数
#
# Returns the sorted concatenation of PRODUCT_MAKEFILES
# variables set in the given AndroidProducts.mk files.
# $(1): the list of AndroidProducts.mk files.
#
# As a side-effect, COMMON_LUNCH_CHOICES will be set to a
# union of all of the COMMON_LUNCH_CHOICES definitions within
# each AndroidProducts.mk file.
#
define get-product-makefiles
$(sort \
  $(eval _COMMON_LUNCH_CHOICES :=) \
  $(foreach f,$(1), \
    $(eval PRODUCT_MAKEFILES :=) \
    $(eval COMMON_LUNCH_CHOICES :=) \
    $(eval LOCAL_DIR := $(patsubst %/,%,$(dir $(f)))) \
    $(eval include $(f)) \
    $(call _validate-common-lunch-choices,$(COMMON_LUNCH_CHOICES),$(PRODUCT_MAKEFILES)) \
    $(eval _COMMON_LUNCH_CHOICES += $(COMMON_LUNCH_CHOICES)) \
    $(PRODUCT_MAKEFILES) \
   ) \
  $(eval PRODUCT_MAKEFILES :=) \
  $(eval LOCAL_DIR :=) \
  $(eval COMMON_LUNCH_CHOICES := $(sort $(_COMMON_LUNCH_CHOICES))) \
  $(eval _COMMON_LUNCH_CHOICES :=) \
 )
endef

通过foreach循环遍历$(_find-android-products-files)

然后依次include AndroidProducts.mk,然后通过_validate-common-lunch-choices宏函数,判断其是否有效

最终结果:

  1. 函数返回所有AndroidProducts.mk中定义的PRODUCT_MAKEFILES的值(全都囊括)
  2. 更新COMMON_LUNCH_CHOICES变量的值,将所有AndroidProducts.mk中定义的COMMON_LUNCH_CHOICES的值都囊括
_validate-common-lunch-choices宏函数
  • $(1): The new list of COMMON_LUNCH_CHOICES
  • $(2): The new list of PRODUCT_MAKEFILES

通过foreach循环遍历$(COMMON_LUNCH_CHOICES)$(1)

然后将其中的-替换为空格,然后通过words(内置宏函数)判断有几个单词

  • 如果小于2,是有问题的;

  • 如果大于等于4,是有问题的;

  • 如果版本不是eng userdebug user三个中的某一个,是有问题的;

  • 如果产品名字在$(PRODUCT_MAKEFILES)中没有,是有问题的;

备注:_decode-product-name函数会去解析$(PRODUCT_MAKEFILES)遍历

#
# Validates the new common lunch choices -- ensures that they're in an
# appropriate form, and are paired with definitions of their products.
# $(1): The new list of COMMON_LUNCH_CHOICES
# $(2): The new list of PRODUCT_MAKEFILES
#
define _validate-common-lunch-choices
$(strip $(foreach choice,$(1),\
  $(eval _parts := $(subst -,$(space),$(choice))) \
  $(if $(call math_lt,$(words $(_parts)),2), \
    $(error $(LOCAL_DIR): $(choice): Invalid lunch choice)) \
  $(if $(call math_gt_or_eq,$(words $(_parts)),4), \
    $(error $(LOCAL_DIR): $(choice): Invalid lunch choice)) \
  $(if $(filter-out eng userdebug user,$(word 2,$(_parts))), \
    $(error $(LOCAL_DIR): $(choice): Invalid variant: $(word 2,$(_parts)))) \
  $(if $(filter-out $(foreach p,$(2),$(call _decode-product-name,$(p))),$(word 1,$(_parts))), \
    $(error $(LOCAL_DIR): $(word 1,$(_parts)): Product not defined in this file)) \
  ))
endef
_decode-product-name宏函数

本宏函数,会去对传进来的参数进行解析:

先把传进来的参数$1中的`:`换为` `空格

如果,有两个word(即有冒号):
    返回替换后的传参$1
反之:
    返回$(basename $(notdir $(1))) 和 $(1)

返回值的格式如下:

# Returns two words:
#   <name> <file>

源码如下:

#
# For entries returned by get-product-makefiles, decode an entry to a short
# product name. These either may be in the form of <name>:path/to/file.mk or
# path/to/<name>.mk
# $(1): The entry to decode
#
# Returns two words:
#   <name> <file>
#
define _decode-product-name
$(strip \
  $(eval _cpm_words := $(subst :,$(space),$(1))) \
  $(if $(word 2,$(_cpm_words)), \
    $(wordlist 1,2,$(_cpm_words)), \
    $(basename $(notdir $(1))) $(1)))
endef

get-all-product-makefiles调用的地方

/build/make/core/product_config.mk中调用了get-all-product-makefiles

# Read in all of the product definitions specified by the AndroidProducts.mk
# files in the tree.
all_product_configs := $(get-all-product-makefiles)

all_product_configs变量里面存放了get-all-product-makefiles宏函数的返回值。

即,所有的AndroidProducts.mk中定义的PRODUCT_MAKEFILES的值(全都囊括)

all_product_configs变量

如下代码会检查TARGET_PRODUCT的值是不是有效的(即实际存在的),并放在current_product_makefile变量中

总结:

all_named_products       存放所有的产品名字
all_product_makefiles    存放所有的product makefile
current_product_makefile 存放当前使用的product makefile

代码如下:

# 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 := $(call _decode-product-name,$(f)))\
    $(eval _cpm_word1 := $(word 1,$(_cpm_words)))\
    $(eval _cpm_word2 := $(word 2,$(_cpm_words)))\
    $(eval all_product_makefiles += $(_cpm_word2))\
    $(eval all_named_products += $(_cpm_word1))\
    $(if $(filter $(TARGET_PRODUCT),$(_cpm_word1)),\
        $(eval current_product_makefile += $(_cpm_word2)),))
_cpm_words :=
_cpm_word1 :=
_cpm_word2 :=
current_product_makefile := $(strip $(current_product_makefile))
all_product_makefiles := $(strip $(all_product_makefiles))
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值