Android——编译体系中的【PRODUCT_COPY_FILES】【ALL_PREBUILT】【BUILD_PREBUILT

       对andriod系统层进行开发,或者进行移植时,时常需要添加文件到编译体系中,在最终的编译中复制到out中,最后打包成镜像,这里总结一下Copy File 方法,这里以我的 android 4.2.1为例.

如有不对或者有其它的新招,欢迎拍砖留言~


                                                 撰写不易,转载请注明出处:http://blog.csdn.net/jscese/article/details/40615801


一.PRODUCT_COPY_FILES :

这个变量就是用来标记Copy操作的,比较常见的形式如下:

[html]  view plain copy print ? 在CODE上查看代码片 派生到我的代码片
  1. #jscese cp 3g script and   
  2. PRODUCT_COPY_FILES += \  
  3.     $(DEVICE_SOURCES)/3g-script/ip-up-datakey:system/etc/ppp/ip-up-datakey \  
  4.     $(DEVICE_SOURCES)/3g-script/ip-down-datakey:system/etc/ppp/ip-down-datakey \  
  5.     $(DEVICE_SOURCES)/3g-script/init.gprs-pppd:system/etc/ppp/init.gprs-pppd \  
  6.     device/sample/etc/apns-full-conf.xml:system/etc/apns-conf.xml \  
  7.     #external/usb-modeswitch/usb_modeswitch.d:system/etc/usb_modeswitch.d  
  8. #PRODUCT_COPY_FILES += \    
  9.     #$(DEVICE_SOURCES)/3g-script/ip-down-datakey:system/etc/ppp/ip-down-datakey   
  10.       
  11. #end  

可以看到 格式<source file>:<dest file> 中间用 “ :  ” 隔开!



编译过源码的都知道在最开始 编译的时候 都会出现:

[html]  view plain copy print ? 在CODE上查看代码片 派生到我的代码片
  1. PRODUCT_COPY_FILES frameworks/base/data/sounds/effects/ogg/Effect_Tick.ogg:system/media/audio/ui/Effect_Tick.ogg ignored.  
  2. PRODUCT_COPY_FILES frameworks/base/data/sounds/effects/ogg/KeypressStandard.ogg:system/media/audio/ui/KeypressStandard.ogg ignored.  
  3. PRODUCT_COPY_FILES frameworks/base/data/sounds/effects/ogg/KeypressSpacebar.ogg:system/media/audio/ui/KeypressSpacebar.ogg ignored.  
  4. PRODUCT_COPY_FILES frameworks/base/data/sounds/effects/ogg/KeypressDelete.ogg:system/media/audio/ui/KeypressDelete.ogg ignored.  
  5. PRODUCT_COPY_FILES frameworks/base/data/sounds/effects/ogg/KeypressReturn.ogg:system/media/audio/ui/KeypressReturn.ogg ignored.  
  6. ...  
这样的打印,现在告诉你这东西在哪里打出来的~   /build/core/Makefile  中最开始的:

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

这就是 PRODUCT_COPY_FILES 起作用的地方! 可以看上面注释,描述了规则用法,只能copy file

也就是上面编译打印的出处,代表忽略项. 详细的规则可跟进去细看,无非是依赖Copy之类的.



这里需要注意一点, PRODUCT_COPY_FILES 不能在 Android.mk 中使用 添加新的Copy 项!

详情可看/build/core/main.mk 中的:

[html]  view plain copy print ? 在CODE上查看代码片 派生到我的代码片
  1. # Can't use first-makefiles-under here because  
  2. --mindepth=2 makes the prunes not work.  
  3. subdir_makefiles := \  
  4.     $(shell build/tools/findleaves.py --prune=out --prune=.repo --prune=.git $(subdirs) Android.mk)  
  5.   
  6. include $(subdir_makefiles)  
  7.   
  8. endif # ONE_SHOT_MAKEFILE  
  9.   
  10. # Now with all Android.mks loaded we can do post cleaning steps.  
  11. include $(BUILD_SYSTEM)/post_clean.mk  
  12.   
  13. ifeq ($(stash_product_vars),true)  
  14.   $(call assert-product-vars, __STASHED)  
  15. endif  

在这里加载所有的Android.mk ,重点在后面的 assert-product-vars 函数:

[html]  view plain copy print ? 在CODE上查看代码片 派生到我的代码片
  1. #  
  2. # Assert that the the variable stashed by stash-product-vars remains untouched.  
  3. # $(1): The prefix as supplied to stash-product-vars  
  4. #  
  5. define assert-product-vars  
  6. $(strip \  
  7.   $(eval changed_variables:=)  
  8.   $(foreach v,$(_product_stash_var_list), \  
  9.     $(if $(call streq,$($(v)),$($(strip $(1))_$(call rot13,$(v)))),, \  
  10.         $(eval $(warning $(v) has been modified: $($(v)))) \  
  11.         $(eval $(warning previous value: $($(strip $(1))_$(call rot13,$(v))))) \  
  12.         $(eval changed_variables := $(changed_variables) $(v))) \  
  13.    ) \  
  14.   $(if $(changed_variables),\  
  15.     $(eval $(error The following variables have been changed: $(changed_variables))),)  
  16. )  
  17. endef  

如果有改变就会报错的,编译出错如下:

[html]  view plain copy print ? 在CODE上查看代码片 派生到我的代码片
  1. build/core/main.mk:528: *** The following variables have been changed: PRODUCT_COPY_FILES。 停止。  


使用 PRODUCT_COPY_FILES 应该算是最常用的Copy File 的方法了,一般可直接加在 device.mk 中!




二 .copy_to copy_from ALL_PREBUILT:

  这个方法用在Android.mk中,可参考 /system/core/rootdir/Android.mk

[html]  view plain copy print ? 在CODE上查看代码片 派生到我的代码片
  1. copy_from += etc/init.goldfish.sh  
  2.   
  3. copy_to := $(addprefix $(TARGET_OUT)/,$(copy_from))  
  4. copy_from := $(addprefix $(LOCAL_PATH)/,$(copy_from))  
  5.   
  6. $(copy_to) : PRIVATE_MODULE :system_etcdir  
  7. $(copy_to) : $(TARGET_OUT)/% : $(LOCAL_PATH)/% | $(ACP)  
  8.     $(transform-prebuilt-to-target)  
  9.   
  10. ALL_PREBUILT += $(copy_to)  

可以看到copy_from 就是需要copy的,copy_to 就是目的地!

可以看下规则,定义在/build/core/definitions.mk中:

[html]  view plain copy print ? 在CODE上查看代码片 派生到我的代码片
  1. # Copy a prebuilt file to a target location.  
  2. define transform-prebuilt-to-target  
  3. @echo "$(if $(PRIVATE_IS_HOST_MODULE),host,target) Prebuilt: $(PRIVATE_MODULE) ($@)"  
  4. $(copy-file-to-target)  
  5. endef  

[html]  view plain copy print ? 在CODE上查看代码片 派生到我的代码片
  1. define copy-file-to-target  
  2. @mkdir -p $(dir $@)  
  3. $(hide) $(ACP) -fp $< $@  
  4. endef  

需要注意的是,如果我们自己添加一些文件到 copy_from中,就会出现 :

[html]  view plain copy print ? 在CODE上查看代码片 派生到我的代码片
  1. build/core/main.mk:533: *** Some files have been added to ALL_PREBUILT.  
  2. build/core/main.mk:534: *  
  3. build/core/main.mk:535: * ALL_PREBUILT is a deprecated mechanism that  
  4. build/core/main.mk:536: * should not be used for new files.  
  5. build/core/main.mk:537: * As an alternative, use PRODUCT_COPY_FILES in  
  6. build/core/main.mk:538: * the appropriate product definition.  
  7. build/core/main.mk:539: * build/target/product/core.mk is the product  
  8. build/core/main.mk:540: * definition used in all products.  
  9. build/core/main.mk:541: *  
  10. build/core/main.mk:542: * unexpected usb_modeswitch.h in ALL_PREBUILT  
  11. build/core/main.mk:542: * unexpected usb_modeswitch.sh in ALL_PREBUILT  
  12. build/core/main.mk:542: * unexpected usb_modeswitch.tcl in ALL_PREBUILT  
  13. build/core/main.mk:543: *  
  14. build/core/main.mk:544: *** ALL_PREBUILT contains unexpected files。 停止。  

错误发生在  /build/core/main.mk

[html]  view plain copy print ? 在CODE上查看代码片 派生到我的代码片
  1. include $(BUILD_SYSTEM)/legacy_prebuilts.mk  
  2. ifneq ($(filter-out $(GRANDFATHERED_ALL_PREBUILT),$(strip $(notdir $(ALL_PREBUILT)))),)  
  3.   $(warning *** Some files have been added to ALL_PREBUILT.)  
  4.   $(warning *)  
  5.   $(warning * ALL_PREBUILT is a deprecated mechanism that)  
  6.   $(warning * should not be used for new files.)  
  7.   $(warning * As an alternative, use PRODUCT_COPY_FILES in)  
  8.   $(warning * the appropriate product definition.)  
  9.   $(warning * build/target/product/core.mk is the product)  
  10.   $(warning * definition used in all products.)  
  11.   $(warning *)  
  12.   $(foreach bad_prebuilt,$(filter-out $(GRANDFATHERED_ALL_PREBUILT),$(strip $(notdir $(ALL_PREBUILT)))),$(warning * unexpected $(bad_prebuilt) in ALL_PREBUILT))  
  13.   $(warning *)  
  14.   $(error ALL_PREBUILT contains unexpected files)  
  15. endif  


上面的打印信息告诉我们  ALL_PREBUILT  是一种过时的机制,已经不让用于copy新的文件了,推荐使用PRODUCT_COPY_FILES  !


而可以添加进 ALL_PREBUILT 变量的成员定义在 legacy_prebuilts.mk中:

[html]  view plain copy print ? 在CODE上查看代码片 派生到我的代码片
  1.  # This is the list of modules grandfathered to use ALL_PREBUILT  
  2.   
  3. # DO NOT ADD ANY NEW MODULE TO THIS FILE  
  4. #  
  5. # ALL_PREBUILT modules are hard to control and audit and we don't want  
  6. # to add any new such module in the system  
  7.   
  8. GRANDFATHERED_ALL_PREBUILT := \  
  9.     akmd2 \  
  10.     am \  
  11.     ap_gain.bin \  
  12.   
  13. ...  

注释写的很明白了!

所以如果我们自己想加个文件编译copy ,就不能使用 copy_from copy_to ALL_prebuilt 这种机制 !




三 .BUILD_PREBUILT :

      这种方式把文件当成编译项目,在Android.mk中copy一个file:

[html]  view plain copy print ? 在CODE上查看代码片 派生到我的代码片
  1. LOCAL_PATH := $(call my-dir)  
  2.   
  3. include $(CLEAR_VARS) \  
  4. LOCAL_MODULE :usb_modeswitch.conf \  
  5. LOCAL_MODULE_CLASS :ETC  \  
  6. LOCAL_MODULE_PATH := $(TARGET_OUT)/etc \  
  7. LOCAL_SRC_FILES :=$(LOCAL_MODULE)  \  
  8. include $(BUILD_PREBUILT)   

上面的就是copy usb_modeswitch.conf 文件到 OUT 下面的 etc目录,这个目录常用来存放配置相关文件。

上面所有的都说的是Copy File  但是如果需要 Copy 一个文件目录下所有就需要另做操作了!




四 .Copy Directory

       以我前面的博客  Android——4.2 - 3G移植之路之usb-modeswitch (二)  中copyusb-modewitch.d 数据目录 为例.

在那里的Android.mk 中我使用了shell命令Copy:

[html]  view plain copy print ? 在CODE上查看代码片 派生到我的代码片
  1. $(shell cp -rf $(LOCAL_PATH)/usb_modeswitch.d $(TARGET_OUT)/etc/usb_modeswitch.d)    

这样做在源码已经编译好了的情况下,是没有问题的,因为$(TARGET_OUT)/etc 目录已经存在,但是作为新编译是不会Copy的,

所以说在android的编译体系中 还得按照android提供的机制来进行操作,像这种shell取巧,是方便,但不是正途!

我现在的处理:

在上面的shell的地方 include 处理Copy usb-modewitch.d 的mk文件,内容如下:

[html]  view plain copy print ? 在CODE上查看代码片 派生到我的代码片
  1. # $(1): module name  
  2. # $(2): source file  
  3. # $(3): destination directory  
  4. define include-prebuilt-with-destination-directory  
  5. include $$(CLEAR_VARS)  
  6. LOCAL_MODULE := $(1)  
  7. LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/usb_modeswitch_data.mk  
  8. LOCAL_MODULE_STEM := $(notdir $(2))  
  9. LOCAL_MODULE_TAGS :optional  
  10. LOCAL_MODULE_CLASS :ETC  
  11. LOCAL_MODULE_PATH := $(3)  
  12. LOCAL_SRC_FILES := $(2)  
  13. include $$(BUILD_PREBUILT)  
  14. endef  
  15.   
  16. #== rename 's/:/_/' * ==#  
  17.   
  18.   
  19. usb_modeswitch_data := $(notdir $(wildcard $(LOCAL_PATH)/usb_modeswitch.d/*))  
  20.   
  21. $(warning jscese display -usb_modeswitch_data--$(usb_modeswitch_data))  
  22.   
  23. usb_modeswitch_data_target_directory := $(TARGET_OUT)/etc/usb_modeswitch.d  
  24. $(foreach data, $(usb_modeswitch_data), $(eval $(call include-prebuilt-with-destination-directory,target-data-$(notdir $(data)),usb_modeswitch.d/$(data),$(usb_modeswitch_data_target_directory))))  
  25. usb_modeswitch_data_target := $(addprefix $(usb_modeswitch_data_target_directory)/,$(foreach cacert,$(usb_modeswitch_data),$(notdir $(usb_modeswitch_data))))  
  26. .PHONY: usb_modeswitch_data_target  
  27. usb_modeswitch_data: $(usb_modeswitch_data_target)  
  28.   
  29. # This is so that build/target/product/core.mk can use usb_modeswitch_data in PRODUCT_PACKAGES  
  30. ALL_MODULES.usb_modeswitch_data.INSTALLED := $(usb_modeswitch_data_target)  

可以看到原理同 Copy 一个单独的 File是一样的 BUILD_PREBUILT ,只不过是遍历了一下文件夹,而且把这个当成一个module来处理 写进 PRODUCT_PACKAGES

关于PRODUCT_PACKAGES 变量的作用可参考我之前的博文 Android——编译安装Module的控制因素


另外因为文件名称都是 XXXX:XXXX类型,我这里先在直接使用reanme命令把:全替换成 _ 

如果不替换,导致传入文件的时候 makefile 把中间的 : 可能当成了依赖符号~ 会报错

我如果使用subst 把:换成 \: 添加进去转义符号,好像是文件又找不到,不知道有没有遇到过这种情况.....


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值