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

  • Android 中“屏幕尺寸”和“屏幕密度”之间的区别?

    我有几个问题 是什么屏幕尺寸 是什么屏幕密度 什么是不同之处之间屏幕尺寸 and 屏幕密度 Android 如何支持不同的密度和不同的屏幕尺寸 我已经读过官方文档 http developer android com training mu
  • 如何减少基于位置的 Android 应用程序的功耗?

    如何减少应用程序的功耗 我可以使用什么代码来实现这个 有几种不同的方法可以减少尝试获取位置信息时所用的电量 Use the 最后已知位置 http developer android com reference android locati
  • 如何将 TextView 的文本设置为字符串资源? (适用于安卓的Java)

    我想更改a的文本TextView我已经在其中创建的另一个文本的组件strings xml 当应用程序启动时 显示的文本存储在strings xml 名称为 help0 我想以编程方式将其设置为名称 help00 下的字符串 方法是在名称的
  • UnsatisfiedLinkError:dlopen 失败:无法找到引用的符号“__aeabi_memcpy4”

    我刚刚从 NDK 12 x 更新到 13 x 现在遇到以下崩溃 Caused by java lang UnsatisfiedLinkError dlopen failed cannot locate symbol aeabi memcpy
  • 如何向我的 Android 应用程序授予系统权限?

    我正在实现一个从设备上静默卸载应用程序的演示 在 adb shell 中 我可以使用 pm uninstall packagename 来执行任务 但是当我编写代码时 我收到了一些权限被拒绝的错误 我已经用谷歌搜索了一段时间 发现要获得 D
  • 可以制作一个不调用Intent的Android通知吗? [关闭]

    就目前情况而言 这个问题不太适合我们的问答形式 我们希望答案得到事实 参考资料或专业知识的支持 但这个问题可能会引发辩论 争论 民意调查或扩展讨论 如果您觉得这个问题可以改进并可能重新开放 访问帮助中心 help reopen questi
  • Android - API 级别 21 中的日期 [已关闭]

    Closed 这个问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 help closed questions 目前不接受答案 你好 我对 Android 还很陌生 目前我对本地日期 或我尝试过的任何其他日期格式 有一个大问题 L
  • 获取 gradle 构建的 aapt2 参数?

    我有兴趣尝试使用 aapt2 从命令行编译 Android 应用程序 当我尝试执行以下操作时 链接约束布局库时遇到问题aapt2 link命令 该程序从 Android studio gradle 成功构建 如何使 gradle 命令行调用
  • 如何在 Android 的这个特定用例中实现 MQTT?

    我的用例 登录到我的应用程序的用户应该能够向在另一台 Android 设备上登录到该应用程序的自己发送消息 如果用户拥有多个设备 那么一旦他打开该消息 其他设备上的通知必然会消失 Doubts 如何跨设备向特定用户发送数据 我了解如何使用
  • 如何在两个图像之间淡出和淡出?

    好的 这里有一点帮助 所以我的启动屏幕中加载了两个图像 第一个图像打开 启动启动画面 然后第二个图像打开 一旦第二个图像关闭 主活动就会开始 现在我的问题是如何使我的第一张图像淡出 然后淡入第二张图像 哦 是的 而且没有交叉淡入淡出 只是完
  • NullPointerException 自定义列表视图适配器

    你好 stackoverflow 社区 我在扩展 BaseAdapter 的自定义适配器类的 getView 方法中得到了一个 NPE 我希望你可以帮助我 这是我的 getView 方法 Override public View getVi
  • 当滚动 Recyclerview 单选按钮更改其选择时

    我正在使用 RecyclerView 设置单选按钮 选定的按钮选择在滚动时会更改其位置 请帮助我 Thanx in advance 我的 RecylerView 布局
  • Android JSoup 示例

    我只是想知道是否有人有一个包含 JSoup 的工作实现的示例 Eclipse 项目 我试图用它从网站上获取信息 并在谷歌上到处搜索试图让它工作 但不能 如果有人可以提供帮助 我将非常感激 JSoup 真的很容易使用 看看 JSoup 食谱中
  • Android 上的 iptables 1.4.11

    我已经从以下位置下载了 Android 内核源代码http source android com source building kernels html http source android com source building ke
  • 在 Google Play 中更新 APK 而不更改扩展文件

    我的 Google Play 控制台中有一个 草稿 APK 它已连接到 APK 扩展文件 版本号为9 扩展文件为 main 9 com something something obb 现在 我正在尝试在发布之前更新 APK 我增加了版本代码
  • 为什么我的 QGestureRecognizer 收不到触摸事件?

    上下文 我正在尝试创建一个类似推子的小部件 它可以在同一视图中具有多个实例 每个实例都可以由不同的手指同时控制 我想用Qt的手势识别系统 http qt project org doc qt 4 8 gestures overview ht
  • Android AudioRecord 与 MediaRecorder 录制音频

    我想在我的 Android 手机上录制人声 我注意到 Android 有两个类可以做到这一点 录音带 http developer android com reference android media AudioRecord html a
  • Android 每个 Activity 中的通用进度条

    我已经修改了解决方案 我可以获得进度条 但进度条永远不会隐藏 这是创建具有相对布局的进度条的类 public class ProgressBarHandler private ProgressBar mProgressBar private
  • 如何在使用 Ionic3 开发的 PWA 中处理硬件后退按钮

    我使用 Ionic 3 开发了一个 PWA 基于选项卡 它工作正常 直到在 Android 浏览器中按下硬件后退按钮或浏览器的后退按钮 如果它从主屏幕运行 按硬件返回将关闭应用程序 如果应用程序在 android 中的 chrome 中运行
  • 监控当前运行的应用程序

    我遇到了一个暂时无法解决的问题 该代码的目的是监视当前正在运行哪些应用程序 我使用了以下代码并记录了生成的包名称 它起作用了 ActivityManager am ActivityManager context getSystemServi

随机推荐