PRODUCT_COPY_FILES语法解析

Android 编译系统解析系列文档

编译系统入口envsetup.sh解析

解析lunch的执行过程以及make执行过程中include文件的顺序

关注一些make执行过程中的几个关键点

对一些独特的语法结构进行解析


PRODUCT_COPY_FILES变量很常用,但是这个变量的作用方式却又与一般的定义符号作用不一样,所以单独提出来说说

解析PRODUCT_COPY_FILES变量作用的函数,位于build/core/Makefile

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
# -----------------------------------------------------------------
# Define rules to copy PRODUCT_COPY_FILES defined by the product.
# PRODUCT_COPY_FILES contains words like <source file>:<dest file>[:<owner>].
# <dest file> is relative to $(PRODUCT_OUT), so it should look like,
# e.g., "system/etc/file.xml".
# The filter part means "only eval the copy-one-file rule if this
# src:dest pair is the first one to match the same dest"
#$(1): the src:dest pair
define check-product-copy-files
$(if $(filter %.apk, $(call word-colon, 2, $(1))),$(error \
Prebuilt apk found in PRODUCT_COPY_FILES: $(1), use BUILD_PREBUILT instead!))
endef
# filter out the duplicate <source file>:<dest file> pairs.
unique_product_copy_files_pairs :=
$(foreach cf,$(PRODUCT_COPY_FILES), \
$(if $(filter $(unique_product_copy_files_pairs),$(cf)),,\
$(eval unique_product_copy_files_pairs += $(cf))))
unique_product_copy_files_destinations :=
$(foreach cf,$(unique_product_copy_files_pairs), \
$(eval _src := $(call word-colon,1,$(cf))) \
$(eval _dest := $(call word-colon,2,$(cf))) \
$(call check-product-copy-files,$(cf)) \
$(if $(filter $(unique_product_copy_files_destinations),$(_dest)), \
$(info PRODUCT_COPY_FILES $(cf) ignored.), \
$(eval _fulldest := $(call append-path,$(PRODUCT_OUT),$(_dest))) \
$(if $(filter %.xml,$(_dest)),\
$(eval $(call copy-xml-file-checked,$(_src),$(_fulldest))),\
$(eval $(call copy-one-file,$(_src),$(_fulldest)))) \
$(eval ALL_DEFAULT_INSTALLED_MODULES += $(_fulldest)) \
$(eval unique_product_copy_files_destinations += $(_dest))))
unique_product_copy_files_pairs :=
unique_product_copy_files_destinations :=

我们来看这里使用了两个变量
unique_product_copy_files_pairs
unique_product_copy_files_destinations
从名字上来说,我们也能发现,这两个变量是分别用来处理copy对以及copy目标的,我们挨个儿解析,先去掉重复对(pairs)的,也就是source:dest 定义重复的

1
2
3
4
5
unique_product_copy_files_pairs :=
$(foreach cf,$(PRODUCT_COPY_FILES), \
$(if $(filter $(unique_product_copy_files_pairs),$(cf)),,\
$(eval unique_product_copy_files_pairs += $(cf))))

然后开始处理destination重复定义的

  1. 从之前去重的copy对中挨个提取_src,_dest,word-colon只是用来分离:前后字段的一个封装

  2. 使用check-product-copy-files检查apk混了进来,那么就报错,因为apk是使用BUILD_PREBUILT方式来处理的

  3. 然后以dest文件为目标过滤重复,保留出现的第一个,去掉后边重复的(dest file重复),然后对过滤出的文件追加out的路径(out/target/product/xxxxx/)

这里第三步比较关键,我们来分析一下:
这里用到一个if判断,如果检测到重复了,那么将这个pair打印出来,否则就做以下这些操作:

  1. 为dest追加out的路径,因为编译系统默认的路径都在源码根目录,所以拷贝的时候需要添加out目录前缀

  2. 对于xml文件来说,使用xmllint来验证格式是否正确,如果没问题,那么执行copy操作,对于其他文件直接copy(实际使用copy-file-to-target执行)

  3. 追加到ALL_DEFAULT_INSTALLED_MODULES 这个变量中,表示已经安装过了这个文件

  4. 以及加入到unique_product_copy_files_destinations变量表示已经执行拷贝操作了,下次遇到就要过滤

对于这样的实现方式,不是很符合我们的直觉,因为我们直觉是后边拷贝的文件会覆盖前边拷贝的文件,所以
我们通过追查build/core/Makefile的提交历史,找到了这样一条提交
518ce5753a95355eccf396f8ed9c36960c83274b
FenX1s.md.png

额,提交前的实现方式是直接覆盖,提交之后就变成拷贝第一个了,提交信息也比较含糊…没有办法看出这样做的原因是什么坑:对于PRODUCT_COPY_FILES,dest目标都是使用字符串匹配形式的,所以对于/system/system/这属于两个字符串,不会被过滤

作者

0xforee

发布于

2016-02-24

更新于

2016-03-05

许可协议


欢迎关注我的公众号 0xforee,第一时间获取更多有价值的思考

评论