PRODUCT_COPY_FILES語法解析
已開通新的部落格,後續文字都會發到新部落格
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重複定義的
-
從之前去重的copy對中挨個提取_src,_dest,
word-colon
只是用來分離:
前後欄位的一個封裝 -
使用check-product-copy-files檢查apk混了進來,那麼就報錯,因為apk是使用
BUILD_PREBUILT
方式來處理的 -
然後以dest檔案為目標過濾重複,保留出現的第一個,去掉後邊重複的(dest file重複),然後對過濾出的檔案追加out的路徑(out/target/product/xxxxx/)
這裡第三步比較關鍵,我們來分析一下:
這裡用到一個if判斷,如果檢測到重複了,那麼將這個pair打印出來,否則就做以下這些操作:
-
為dest追加out的路徑,因為編譯系統預設的路徑都在原始碼根目錄,所以拷貝的時候需要新增out目錄字首
-
對於xml檔案來說,使用xmllint來驗證格式是否正確,如果沒問題,那麼執行copy操作,對於其他檔案直接copy(實際使用copy-file-to-target執行)
-
追加到ALL_DEFAULT_INSTALLED_MODULES 這個變數中,表示已經安裝過了這個檔案
-
以及加入到unique_product_copy_files_destinations變量表示已經執行拷貝操作了,下次遇到就要過濾
對於這樣的實現方式,不是很符合我們的直覺,因為我們直覺是後邊拷貝的檔案會覆蓋前邊拷貝的檔案,所以
我們通過追查build/core/Makefile的提交歷史,找到了這樣一條提交
518ce5753a95355eccf396f8ed9c36960c83274b
額,提交前的實現方式是直接覆蓋,提交之後就變成拷貝第一個了,提交資訊也比較含糊…沒有辦法看出這樣做的原因是什麼坑:對於PRODUCT_COPY_FILES,dest目標都是使用字串匹配形式的,所以對於/system/system/這屬於兩個字串,不會被過濾