PRODUCT_COPY_FILES的深入理解,为何不能在Android.mk使用

2023-05-16

PRODUCT_COPY_FILES本质是和定义产品的AndroidProducts.mk(get-all-product-makefiles来获取系统中所有AndroidProducts.mk 文件路径)联系在一起,这个文件内部会定义所属的产品的PRODUCT_MAKEFILES,该变量可定义多个xxx.mk产品相关定义文件,在编译初始化环境时会将其include进来。如同PRODUCT_NAME/PRODUCT_DEVICE一样,PRODUCT_COPY_FILES等定义的变量都会通过import-products->import-nodes函数重新生成以下格式的变量:
PRODUCTS_xxxx_PRODUCT_NAME = name;
PRODUCTS_xxxx_PRODUCT_COPY_FILES = copy_flie;
注意:其中xxxx根据find到产品AndroidProducts.mk所在的相对路径从而确定变量LOCAL_DIR,进一步确定其PRODUCT_MAKEFILES的文件路径,一般位于device或者vendor目录下的子目录中,如device/xxx/fish/fish.mk。
  1 PRODUCT_MAKEFILES := \
  2     $(LOCAL_DIR)/xxxx/fish.mk \ 这里必须写成LOCAL_DIR,变量值是取决于AndroidProduct.mk所在的路径。
以上的一组变量格局_product_var_list来生成,每个product node都会对应有一个这样的一组新的变量。而这些变量的初始化都是系统或者模块编译前的初始化过程(根据TARGET_PRODUCT来初始化Product相关的配置,以及确定TARGET_DEVICE),还没有到执行android.mk,任何一次编译都会执行该初始化过程。
对于PRODUCT_COPY_FILES来说,当确定好一种product后,新生成的PRODUCTS_xxxx_PRODUCT_COPY_FILES又会被赋值给PRODUCT_COPY_FILES:
/build/core/product_config.mk
331 PRODUCT_COPY_FILES := \
332     $(strip $(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_COPY_FILES)) //获取确定了Product即TARGET_DEVICE后的这组变量值, INTERNAL_PRODUCT为xxx.mk所在的相对路径,用于区别不同类型产品的定义。
当include build/core/Makefile时,会执行对PRODUCT_COPY_FILES遍历的处理,可以看到当copy输出的是xml文件时,会直接执行copy操作,而对其他文件是:
  
24 define check-product-copy-files
  25 $(if $(filter %.apk, $(call word-colon, 2, $(1))),$(error \
  26     Prebuilt apk found in PRODUCT_COPY_FILES: $(1), use BUILD_PREBUILT instead!))
  27 endef
  28 # filter out the duplicate <source file>:<dest file> pairs.
  29 unique_product_copy_files_pairs :=
  30 $(foreach cf,$(PRODUCT_COPY_FILES), \
  31     $(if $(filter $(unique_product_copy_files_pairs),$(cf)),,\
  32         $(eval unique_product_copy_files_pairs += $(cf))))
  33 $(info $(unique_product_copy_files_pairs));
  34 unique_product_copy_files_destinations :=
  35 $(foreach cf,$(unique_product_copy_files_pairs), \
  36     $(eval _src := $(call word-colon,1,$(cf))) \
  37     $(eval _dest := $(call word-colon,2,$(cf))) \
  38     $(call check-product-copy-files,$(cf)) \
  39     $(if $(filter $(unique_product_copy_files_destinations),$(_dest)), \
  40         $(info PRODUCT_COPY_FILES $(cf) ignored.), \
  41         $(eval _fulldest := $(call append-path,$(PRODUCT_OUT),$(_dest))) \
  42         $(if $(filter %.xml,$(_dest)),\
  43             $(eval $(call copy-xml-file-checked,$(_src),$(_fulldest))),\
  44             $(eval $(call copy-one-file,$(_src),$(_fulldest)))) \
  45         $(eval ALL_DEFAULT_INSTALLED_MODULES += $(_fulldest)) \
  46         $(eval unique_product_copy_files_destinations += $(_dest))))
  47 $(info //$(ALL_DEFAULT_INSTALLED_MODULES));
  48 unique_product_copy_files_pairs :=
  49 unique_product_copy_files_destinations :=

这里本质是没有直接执行copy函数的,只是生成了一个目标与依赖的编译关系,同时将目标加入到来一个ALL_DEFAULT_INSTALLED_MODULES变量用于给系统的编译
2198 define copy-one-file
2199 $(2): $(1) | $(ACP)
2200     @echo "Copy: $$@"
2201     $$(copy-file-to-target)
2202 endef

跟踪后,发现如下依赖关系,即droidcore是编译整个系统的目标入口即make区别于mm等操作,具有以下的目标依赖关系:
在main.mk中
64 .PHONY: droid
65 DEFAULT_GOAL := droid //对于GNU make而言,当make无指定命令时,其预处理完成后,默认是将M akefile文件中 第一个规则的目标依赖作为全局编译目标入口,即这里的DEFAULT_GOAL
66 $(DEFAULT_GOAL):
 817 # All the droid stuff, in directories
 818 .PHONY: files
 819 files: prebuilt \
 820         $(modules_to_install) \
 821         $(INSTALLED_ANDROID_INFO_TXT_TARGET)

 877 .PHONY: droidcore
 878 droidcore: files \
 879     systemimage \
 880     $(INSTALLED_BOOTIMAGE_TARGET) \
 881     $(INSTALLED_RECOVERYIMAGE_TARGET) \
 882     $(INSTALLED_USERDATAIMAGE_TARGET) \
 883     $(INSTALLED_CACHEIMAGE_TARGET) \
 884     $(INSTALLED_VENDORIMAGE_TARGET) \
 885     $(INSTALLED_FILES_FILE)

 971 # Building a full system-- the default is to build droidcore
 972 droid: droidcore dist_files

 784 modules_to_install := $(sort $(ALL_DEFAULT_INSTALLED_MODULES)) //ALL_DEFAULT_INSTALLED_MODULES包含了需要copy的dst目的文件,此前在解析PRODUCT_COPY_FILES变量时已经建立了每个文件dst和src的目标依赖关系并将目标保存在ALL_DEFAULT_INSTALLED_MODULES变量中,即最终是执行copy-file-to-target函数。
    所以总的来说PRODUCT_COPY_FILES的执行是需要依赖于编译整个系统make时而言的,对于mm/mmm等单个Android.mk文件编译而言(编译入口为make all_modules和droid无关系)是不会进行任何编译的操作(虽然PRODUCT_COPY_FILES按初始化流程是被处理过的,也建立了编译的目标依赖关系,但all_modules只依赖于LOCAL_BUILT_MODULE和LOCAL_INSTALLED_MODULE),前者可以认为是系统级的大编译,后者是模块级的小编译。
这种解决方式只能利用Android.mk的BUILD_PREBUILT来解决
copy出现错误 error The following variables have been changed
在mm编译模块时,会先_product_stash_var_list 函数保存_product_stash_var_list变量,然后include Android.mk文件,再回去使用assert-product-vars对保存变量进行检测,确保这些变量在加载了Android.mk后,不会变化,因为这个变量表都是和Board/Product相关的
282 define stash-product-vars
283 $(foreach v,$(_product_stash_var_list), \
284         $(eval $(strip $(1))_$(call rot13,$(v)):=$$($$(v))) \)
286 endef

289 # Assert that the the variable stashed by stash-product-vars remains untouched.
290 # $(1): The prefix as supplied to stash-product-vars
291 #
292 define assert-product-vars
293 $(strip \
294   $(eval changed_variables:=)
295   $(foreach v,$(_product_stash_var_list), \
296     $(if $(call streq,$($(v)),$($(strip $(1))_$(call rot13,$(v)))),, \
297         $(eval $(warning $(v) has been modified: $($(v)))) \
298         $(eval $(warning previous value: $($(strip $(1))_$(call rot13,$(v))))) \
299         $(eval changed_variables := $(changed_variables) $(v))) \
300    ) \
301   $(if $(changed_variables),\
302     $(eval $(error The following variables have been changed: $(changed_variables))),) //变量list加载Android.mk发生变化(在main.mk中会加载ONE_SHORT_MAKEFILE也就是Android.mk文件)
303 )
304 endef

变量list加载mm/make多个Android.mk时内部变量发生变化则会出该错误(在main.mk中会加载ONE_SHORT_MAKEFILE也就是执行mm/mmm时传入的Android.mk文件,make时通过脚本加载所有的Android.mk文件)

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

PRODUCT_COPY_FILES的深入理解,为何不能在Android.mk使用 的相关文章

随机推荐