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

  • 新的 Material Design 底部导航应使用哪个视图? [复制]

    这个问题在这里已经有答案了 我相信你们都听说过添加底部导航 https www google com design spec components bottom navigation html材料设计指南 我计划将其添加到我的应用程序中 但
  • Android 滚动分页

    Android 操作系统有可以实现滚动分页的功能吗 Edit滚动分页是指像主屏幕上一样的分页 您可以左右滑动并转到下一页或上一页 您可以在 android git kernel org 上查看 Launcher 的源代码作为示例 查找名为
  • Android ImageButton 在 Activity 中运行良好。它在片段中不起作用

    我正在尝试转换布局 使其包含片段 其中一个视图是具有侦听器的 ImageButton 该代码作为 Activity 运行良好 但作为 Fragment 会出现麻烦 第一个问题是我无法使用 findViewById 但我能够在这里找到答案并使
  • android 网格视图从右到左放置项目

    我正在开发一个 Android 应用程序阿拉伯文版本 在其中一个界面中 我有 gridView 因此 要以正确的顺序显示项目 我必须从右到左显示 GridView 中的项目 当然是从上到下 为此 我尝试在 GridView 中添加这些属性
  • Android 自定义对话框因布局而膨胀 - 对齐问题

    我有一个自定义对话框 它是从dialog xml 中膨胀的 当我打开对话框时 它看起来如下所示 我在列表视图和它下面的 确定 按钮之间有一些空间 我想消除列表视图与其下方的按钮之间的空间 我怎样才能做到这一点 对话框 xml
  • android中.so文件的实际用途是什么? [复制]

    这个问题在这里已经有答案了 我想在我的应用程序中实现类似聊天的环聊 我一直在使用 opentok 库 我在其中看到了 libopentok so 文件 谁能告诉我 libopentok so 文件的确切用法是什么 在Android中 我们可
  • 错误:java.lang.NoClassDefFoundError Android

    我正在关注这个创建滑动选项卡的教程 http www truiton com 2015 06 android tabs example fragments viewpager 但我收到上述错误 我的 gradle 依赖结构 dependen
  • OneSignal 推送通知 单击以打开活动

    我集成了一个用于推送通知的信号库 我想在应用程序未运行时通过单击推送通知来打开特定活动 我收到推送通知 但当我单击通知时 应用程序崩溃了 这是我的通知接收器代码 public class ExampleNotificationOpenedH
  • __stack_chk_fail_local 和 -fno-stack-protector - 如何让它工作?

    Update 我刚刚发现问题出在我的项目 libxml2 中包含的预构建库上 它是在启用堆栈保护的情况下构建的 因此依赖于 stack chk fail local方法 我现在已经重建了该库 fno stack protector也是 一切
  • 为什么 Android 中奇怪的命名约定是“AlertDialog.Builder”而不是“AlertDialogBu​​ilder”

    Why not AlertDialogBuilder builder new AlertDialogBuilder this builder setTitle foo 代替 AlertDialog Builder builder new A
  • 在较低的 SDK 上运行具有较高 SDK 的应用程序

    我想知道在 Android 3 0 中开发的应用程序是否可以在 Android 2 1 上运行 如果是这样 我该怎么做 如果我使用 3 0 中的库 例如片段 开发应用程序 它可以在 2 1 中使用吗 不会 但是 2 1 应用程序可以在 3
  • Android Studio,工具提示消失得这么快

    我有以下问题 我想从这个工具提示中复制错误文本 但是一旦我将鼠标悬停在它上面 它就消失得如此之快 这让我发疯 我有以下 android studio 版本 我有以下设置 谢谢您的帮助 如果有人遇到这个问题 这与logcat刷新的方式有关 每
  • 没有 GUI 的 Android Activity

    我创建了一个仅从链接启动的活动 使用意图过滤器 我不希望此活动有 GUI 我只希望它启动服务并在栏中放置通知 我尝试将链接的意图过滤器放入我的服务中 但这不起作用 有没有更好的方法可以响应意图过滤器 或者我可以让我的活动没有 GUI 吗 抱
  • Android studio 找不到 Theme.AppCompat.Light.DarkActionBar [重复]

    这个问题在这里已经有答案了 我已经导入了一个Android Studio项目来自Github into Android Studio 虽然我的build gradle有dependencies dependencies compile fi
  • Android - 带动画的可扩展 TextView

    我有一个TextView首先显示长文本的一小部分 用户可以按 查看更多 按钮来展开TextView并查看该文本的其余部分 进行测试 我可以通过简单地交换以下值来实现这一点TextView setMaxLines介于 4 之间 用于折叠 和
  • 从前台服务的活动中释放内存

    我有一个带有前台服务和一项活动的应用程序 该服务可以在启动时自行启动 也可以从 Activity 中启动 我注意到当服务在启动时自行启动时 内存使用量约为 3MB 一旦我打开该 Activity 内存使用量就会跃升至约 9mB 一旦 Act
  • 使用 LinearLayout 将按钮放在屏幕底部?

    我有以下代码 如何使 3 个按钮位于底部
  • 未捕获的引用错误:cordova 未定义

    这是我的 HelloPlugin js 文件 var HelloPlugin callNativeFunction function success fail resultType return cordova exec success f
  • 如何在ListView中标记视图?

    我有一个带有列表视图的应用程序 列表视图工作正常 当我希望列表以标记的某些行开始时 问题就开始了 如果我按下它 我可以标记一行 但是 似乎没有找到一种方法来在初始化时标记任何行 这是我的代码 listViewOfBluetooth getL
  • 如何复制 ArrayIterator 以保留其当前迭代位置?

    因为这似乎是我必须做的才能达到这种效果 arr a gt first b gt second iter new ArrayIterator arr Do a bunch of iterations iter gt next new iter

随机推荐