1. 程式人生 > >PRODUCT_COPY_FILES語法解析

PRODUCT_COPY_FILES語法解析

已開通新的部落格,後續文字都會發到新部落格

http://www.0xfree.top


Android 編譯系統解析系列文件

解析lunch的執行過程以及make執行過程中include檔案的順序

關注一些make執行過程中的幾個關鍵點

對一些獨特的語法結構進行解析


PRODUCT_COPY_FILES變數很常用,但是這個變數的作用方式卻又與一般的定義符號作用不一樣,所以單獨提出來說說

解析PRODUCT_COPY_FILES變數作用的函式,位於build/core/Makefile

# -----------------------------------------------------------------
# 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, $(call word-colon, 2, $(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 :=

我們來看這裡使用了兩個變數
unique_product_copy_files_pairs
unique_product_copy_files_destinations
從名字上來說,我們也能發現,這兩個變數是分別用來處理copy對以及copy目標的,我們挨個兒解析,先去掉重複對(pairs)的,也就是source:dest 定義重複的

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))))

然後開始處理destination重複定義的

  1. 從之前去重的copy對中挨個提取_src,_dest,word-colon只是用來分離:前後欄位的一個封裝

  2. 使用check-product-copy-files檢查apk混了進來,那麼就報錯,因為apk是使用BUILD_PREBUILT方式來處理的

  3. 然後以dest檔案為目標過濾重複,保留出現的第一個,去掉後邊重複的(dest file重複),然後對過濾出的檔案追加out的路徑(out/target/product/xxxxx/)

這裡第三步比較關鍵,我們來分析一下:
這裡用到一個if判斷,如果檢測到重複了,那麼將這個pair打印出來,否則就做以下這些操作:

  1. 為dest追加out的路徑,因為編譯系統預設的路徑都在原始碼根目錄,所以拷貝的時候需要新增out目錄字首

  2. 對於xml檔案來說,使用xmllint來驗證格式是否正確,如果沒問題,那麼執行copy操作,對於其他檔案直接copy(實際使用copy-file-to-target執行)

  3. 追加到ALL_DEFAULT_INSTALLED_MODULES 這個變數中,表示已經安裝過了這個檔案

  4. 以及加入到unique_product_copy_files_destinations變量表示已經執行拷貝操作了,下次遇到就要過濾

對於這樣的實現方式,不是很符合我們的直覺,因為我們直覺是後邊拷貝的檔案會覆蓋前邊拷貝的檔案,所以
我們通過追查build/core/Makefile的提交歷史,找到了這樣一條提交
518ce5753a95355eccf396f8ed9c36960c83274b
FenX1s.md.png

額,提交前的實現方式是直接覆蓋,提交之後就變成拷貝第一個了,提交資訊也比較含糊…沒有辦法看出這樣做的原因是什麼坑:對於PRODUCT_COPY_FILES,dest目標都是使用字串匹配形式的,所以對於/system/system/這屬於兩個字串,不會被過濾