http://www.2cto.com/kf/201410/347837.html
对andriod系统层进行开发,或者进行移植时,时常需要添加文件到编译体系中,在最终的编译中复制到out中,最后打包成镜像,这里总结一下Copy File 方法,这里以我的 android 4.2.1为例.
一.PRODUCT_COPY_FILES :
这个变量就是用来标记Copy操作的,比较常见的形式如下:
1
2
3
4
5
6
7
8
9
10
11
|
#jscese cp 3g script and
PRODUCT_COPY_FILES +=
$(DEVICE_SOURCES)/3g-script/ip-up-datakey:system/etc/ppp/ip-up-datakey
$(DEVICE_SOURCES)/3g-script/ip-down-datakey:system/etc/ppp/ip-down-datakey
$(DEVICE_SOURCES)/3g-script/init.gprs-pppd:system/etc/ppp/init.gprs-pppd
device/sample/etc/apns-full-conf.xml:system/etc/apns-conf.xml
#external/usb-modeswitch/usb_modeswitch.d:system/etc/usb_modeswitch.d
#PRODUCT_COPY_FILES +=
#$(DEVICE_SOURCES)/3g-script/ip-down-datakey:system/etc/ppp/ip-down-datakey
#end
|
可以看到 格式: 中间用 “ : ” 隔开!
编译过源码的都知道在最开始 编译的时候 都会出现:
1
2
3
4
5
6
|
PRODUCT_COPY_FILES frameworks/base/data/sounds/effects/ogg/Effect_Tick.ogg:system/media/audio/ui/Effect_Tick.ogg ignored.
PRODUCT_COPY_FILES frameworks/base/data/sounds/effects/ogg/KeypressStandard.ogg:system/media/audio/ui/KeypressStandard.ogg ignored.
PRODUCT_COPY_FILES frameworks/base/data/sounds/effects/ogg/KeypressSpacebar.ogg:system/media/audio/ui/KeypressSpacebar.ogg ignored.
PRODUCT_COPY_FILES frameworks/base/data/sounds/effects/ogg/KeypressDelete.ogg:system/media/audio/ui/KeypressDelete.ogg ignored.
PRODUCT_COPY_FILES frameworks/base/data/sounds/effects/ogg/KeypressReturn.ogg:system/media/audio/ui/KeypressReturn.ogg ignored.
...
|
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, $(
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 :=</dest></dest></owner></dest>
|
这就是 PRODUCT_COPY_FILES 起作用的地方! 可以看上面注释,描述了规则用法,只能copy file!
也就是上面编译打印的出处,代表忽略项. 详细的规则可跟进去细看,无非是依赖Copy之类的.
这里需要注意一点, PRODUCT_COPY_FILES 不能在 Android.mk 中使用 添加新的Copy 项!
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
# Can't use first-makefiles-under here because
# --mindepth=
2
makes the prunes not work.
subdir_makefiles :=
$(shell build/tools/findleaves.py --prune=out --prune=.repo --prune=.git $(subdirs) Android.mk)
include $(subdir_makefiles)
endif # ONE_SHOT_MAKEFILE
# Now with all Android.mks loaded we can
do
post cleaning steps.
include $(BUILD_SYSTEM)/post_clean.mk
ifeq ($(stash_product_vars),
true
)
$(call
assert
-product-vars, __STASHED)
endif
|
在这里加载所有的Android.mk ,重点在后面的 assert-product-vars 函数:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
#
# Assert that the the variable stashed by stash-product-vars remains untouched.
# $(
1
): The prefix as supplied to stash-product-vars
#
define
assert
-product-vars
$(strip
$(eval changed_variables:=)
$(foreach v,$(_product_stash_var_list),
$(
if
$(call streq,$($(v)),$($(strip $(
1
))_$(call rot13,$(v)))),,
$(eval $(warning $(v) has been modified: $($(v))))
$(eval $(warning previous value: $($(strip $(
1
))_$(call rot13,$(v)))))
$(eval changed_variables := $(changed_variables) $(v)))
)
$(
if
$(changed_variables),
$(eval $(error The following variables have been changed: $(changed_variables))),)
)
endef
|
如果有改变就会报错的,编译出错如下:
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:
1
2
3
4
5
6
7
8
9
10
|
copy_from += etc/init.goldfish.sh
copy_to := $(addprefix $(TARGET_OUT)/,$(copy_from))
copy_from := $(addprefix $(LOCAL_PATH)/,$(copy_from))
$(copy_to) : PRIVATE_MODULE := system_etcdir
$(copy_to) : $(TARGET_OUT)/% : $(LOCAL_PATH)/% | $(ACP)
$(transform-prebuilt-to-target)
ALL_PREBUILT += $(copy_to)
|
可以看到copy_from 就是需要copy的,copy_to 就是目的地!
可以看下规则,定义在/build/core/definitions.mk中:
1
2
3
4
5
|
# Copy a prebuilt file to a target location.
define transform-prebuilt-to-target
@echo
$(
if
$(PRIVATE_IS_HOST_MODULE),host,target) Prebuilt: $(PRIVATE_MODULE) ($@)
$(copy-file-to-target)
endef
|
1
2
3
4
|
define copy-file-to-target
@mkdir
-p $(dir $@)
$(hide) $(ACP) -fp $< $@
endef
|
需要注意的是,如果我们自己添加一些文件到 copy_from中,就会出现 :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
build/core/main.mk:
533
: *** Some files have been added to ALL_PREBUILT.
build/core/main.mk:
534
: *
build/core/main.mk:
535
: * ALL_PREBUILT is a deprecated mechanism that
build/core/main.mk:
536
: * should not be used
for
new
files.
build/core/main.mk:
537
: * As an alternative, use PRODUCT_COPY_FILES in
build/core/main.mk:
538
: * the appropriate product definition.
build/core/main.mk:
539
: * build/target/product/core.mk is the product
build/core/main.mk:
540
: * definition used in all products.
build/core/main.mk:
541
: *
build/core/main.mk:
542
: * unexpected usb_modeswitch.h in ALL_PREBUILT
build/core/main.mk:
542
: * unexpected usb_modeswitch.sh in ALL_PREBUILT
build/core/main.mk:
542
: * unexpected usb_modeswitch.tcl in ALL_PREBUILT
build/core/main.mk:
543
: *
build/core/main.mk:
544
: *** ALL_PREBUILT contains unexpected files。 停止。
|
错误发生在 /build/core/main.mk
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
include $(BUILD_SYSTEM)/legacy_prebuilts.mk
ifneq ($(filter-out $(GRANDFATHERED_ALL_PREBUILT),$(strip $(notdir $(ALL_PREBUILT)))),)
$(warning *** Some files have been added to ALL_PREBUILT.)
$(warning *)
$(warning * ALL_PREBUILT is a deprecated mechanism that)
$(warning * should not be used
for
new
files.)
$(warning * As an alternative, use PRODUCT_COPY_FILES in)
$(warning * the appropriate product definition.)
$(warning * build/target/product/core.mk is the product)
$(warning * definition used in all products.)
$(warning *)
$(foreach bad_prebuilt,$(filter-out $(GRANDFATHERED_ALL_PREBUILT),$(strip $(notdir $(ALL_PREBUILT)))),$(warning * unexpected $(bad_prebuilt) in ALL_PREBUILT))
$(warning *)
$(error ALL_PREBUILT contains unexpected files)
endif
|
上面的打印信息告诉我们 ALL_PREBUILT 是一种过时的机制,已经不让用于copy新的文件了,推荐使用PRODUCT_COPY_FILES !
而可以添加进 ALL_PREBUILT 变量的成员定义在 legacy_prebuilts.mk中:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
# This is the list of modules grandfathered to use ALL_PREBUILT
# DO NOT ADD ANY NEW MODULE TO THIS FILE
#
# ALL_PREBUILT modules are hard to control and audit and we don't want
# to add any
new
such module in the system
GRANDFATHERED_ALL_PREBUILT :=
akmd2
am
ap_gain.bin
...
|
注释写的很明白了!
所以如果我们自己想加个文件编译copy ,就不能使用 copy_from copy_to ALL_prebuilt 这种机制 !
三 .BUILD_PREBUILT :
这种方式把文件当成编译项目,在Android.mk中copy一个file:
1
2
3
4
5
6
7
8
|
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := usb_modeswitch.conf
LOCAL_MODULE_CLASS := ETC
LOCAL_MODULE_PATH := $(TARGET_OUT)/etc
LOCAL_SRC_FILES :=$(LOCAL_MODULE)
include $(BUILD_PREBUILT)
|
上面的就是copy usb_modeswitch.conf 文件到 OUT 下面的 etc目录,这个目录常用来存放配置相关文件。
上面所有的都说的是Copy File 但是如果需要 Copy 一个文件目录下所有就需要另做操作了!
四 .Copy Directory
以我前面的博客 Android——4.2 - 3G移植之路之usb-modeswitch (二) 中copy usb-modewitch.d 数据目录 为例.
在那里的Android.mk 中我使用了shell命令Copy:
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文件,内容如下:
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
|
# $(
1
): module name
# $(
2
): source file
# $(
3
): destination directory
define include-prebuilt-with-destination-directory
include $$(CLEAR_VARS)
LOCAL_MODULE := $(
1
)
LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/usb_modeswitch_data.mk
LOCAL_MODULE_STEM := $(notdir $(
2
))
LOCAL_MODULE_TAGS := optional
LOCAL_MODULE_CLASS := ETC
LOCAL_MODULE_PATH := $(
3
)
LOCAL_SRC_FILES := $(
2
)
include $$(BUILD_PREBUILT)
endef
#== rename
's/:/_/'
* ==#
usb_modeswitch_data := $(notdir $(wildcard $(LOCAL_PATH)/usb_modeswitch.d/*))
$(warning jscese display -usb_modeswitch_data--$(usb_modeswitch_data))
usb_modeswitch_data_target_directory := $(TARGET_OUT)/etc/usb_modeswitch.d
$(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))))
usb_modeswitch_data_target := $(addprefix $(usb_modeswitch_data_target_directory)/,$(foreach cacert,$(usb_modeswitch_data),$(notdir $(usb_modeswitch_data))))
.PHONY: usb_modeswitch_data_target
usb_modeswitch_data: $(usb_modeswitch_data_target)
# This is so that build/target/product/core.mk can use usb_modeswitch_data in PRODUCT_PACKAGES
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 把:换成 : 添加进去转义符号,好像是文件又找不到,不知道有没有遇到过这种情况.....