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使用 的相关文章

  • Google+集成:无法加载可见圈子

    我想在我的应用程序中从 google plus 获取人员信息列表 朋友个人资料图像 URL 可见名称和 ID Here s 官方 google plus 集成教程 https developers google com mobile and
  • Android Market 公司注册

    抱歉 这个问题与编程无关 但我无处可问 我在 android 帮助中心和支持中询问 但没有任何回应 在 Android Market 开设公司帐户需要什么 我希望我的公司被视为卖家 他们将如何验证公司的身份 我需要向市场提供哪些文件 Tha
  • JavaScript接口注入漏洞修复

    我收到了来自 Google Play 管理中心的警告 提示我这一页 https support google com faqs answer 9095419因为我在我的应用程序中使用了 JavaScript 接口 并建议两个选项来解决该问题
  • 允许我的应用程序用户从单个帐户发布推文

    我有一个小应用程序 可以显示我的小国家 比利时的公共交通交通问题 例如 我在应用程序中创建了一个系统 允许用户在火车延误时警告所有人 我想做的是允许我信任的用户从我的帐户发布类似 用户 X 说 123456 号列车晚点 3 分钟 之类的推文
  • 动态改变ListView中TextView字体颜色

    我正在将 XML 文档绑定到自定义适配器 列表中的所有项目最初的字体颜色均为白色 XML 文档中的一个节点有一个我正在检查的属性 如果设置了该属性 我想将 ListView 中该项目的字体颜色更改为较深的颜色 我的代码似乎最初可以工作 但是
  • 文件路径在棒棒糖android中始终返回null

    这是我从内部存储 画廊 获取图像时的代码 在棒棒糖文件路径中返回始终为空 if requestCode PICK IMAGE if resultCode RESULT OK image successfully picked launchi
  • 如何更改 Kindle Fire 上 /mnt/SDcard 文件夹的读/写权限?

    我正在尝试在 Android 中开发 Amazon In app 为此 我从该网站下载示例代码https developer amazon com sdk in app purchasing sample code button click
  • 所选设备不兼容 - Android Studio

    我之前已经解决了这个问题 但现在不能 我需要永久修复 在测试我的应用程序时 Android Studio 中的一切都很顺利 我现在遇到了 所选设备不兼容 的问题 当我去运行应用程序时 我想知道如何阻止它读取我手机的 API 作为 1 而不是
  • 相机 java.lang.RuntimeException:setParameters 失败

    我使用创建了一个自定义相机应用程序this https github com davidgatti dgCam源代码 但在少数设备上 例如高分辨率设备 我得到 RuntimeException setParameters failed 我面
  • 哪个线程运行 ContentProvider?

    如果我从 Activity 调用 ContentProvider ContentProvider 会在哪个线程中运行 例如 如果 Activity 被终止并且查询正在 ContentProvider 中执行 会发生什么情况 假设您的网络查询
  • BitmapFactory.decodeResource 返回空值

    我试图从视图对象中的内部资源加载位图 源本身位于 可绘制 文件中 代码是 import android content Context import android graphics Bitmap import android graphi
  • 在特定时间启动应用程序

    我想知道是否有可能 以及如何 在特定时间启动我的应用程序 就像在特定时间响起的闹钟一样 假设我希望我的应用程序在早上 8 点启动 这可行吗 您可以使用 AlarmManager 来完成此操作 这是一个简短的示例 首先你需要设置闹钟 Alar
  • Android 4.2.1 错误的字符字距调整(间距)

    使用时Canvas and drawText 方法我在 Android 4 2 1 上看到了不同的渲染 4 2 以下 对于 Android 4 2 1 Nexus 7 我得到 正如你所看到的文字消耗很紧 似乎是4 2 1中引入的字距调整问题
  • 如何在android listview或线性布局中动态设置marginBottom?

    friends 我想使用java代码或动态设置layout marginBottom 在列表视图或线性布局中 有人指导我如何实现这一目标吗 任何帮助 将不胜感激 ListView lst getListView LinearLayout L
  • 带 Retrofit 的简单登录表单

    我开始使用 Retrofit 但我坚持这个简单的步骤 我有一个登录表单 我正在尝试通过服务器进行身份验证 但我无法发送请求 这是我尝试过的 我的改造客户 private static OkHttpClient Builder httpCli
  • 使用 SearchView 后重置操作栏

    我在用着SearchView小部件以在我的应用程序中启用搜索 首次单击搜索图标后 SearchView小部件会扩展到搜索字段 并且应用程序图标旁边会显示 后退 箭头 如果我单击应用程序图标 操作栏将恢复到初始状态 没有 后退 箭头 并且Se
  • setShadowLayer Android API 差异

    我为我的应用程序开发了一个自定义视图组件 并且正在努力向圆圈添加阴影 这是我的类扩展 View 的代码 public class ChartView extends View public ChartView Context context
  • 规范注册 ID 和消息 ID 格式

    我的理解有问题Canonical Registration Id并让谷歌返回它 我特意注册了两次我的Android应用程序 以测试Canonical Registration Id 但是当我尝试向两者推送消息时Registration Id
  • 我想分享带有单个标题的多张图片

    我想分享带有单个标题的多张图片 该标题显示在一张图像上而不是所有图像上 但标题会显示在一次共享的每张照片上 这是我的代码 private void pic with data Intent shareIntent new Intent sh
  • Android 列表视图布局 类似于 Google play

    我想实现一个类似于 Google Play 的列表布局 其中每个行都有菜单 请帮助我创建这个 我是否需要创建一个弹出菜单或者有任何选项可以实现此目的 Thanks 看起来您正在尝试完全按照图中所示的方式进行操作 我只是举一个例子来说明我如何

随机推荐