Android Makefile 的流程 (non recursive make)
起始化相關變數
偵測編譯環境和目標環境
決定目標 product
讀取 product 的設定
讀取 product 所指定之目標平台架構設定
選擇 toolchain
指定編譯參數 (*-.mk)
清除輸出目錄
設定/檢查版本編號
讀取所有 BoardConfig.mk 檔案
讀取所有 module 的設定
根據設定,產生必需的 rule
產生 image
以上的主要流程都是由 build/core/main.mk 所安排。
3.1.起始化和偵測
Android Makefile 的參照關係是這樣的
Makefile -> build/core/main.mk -> build/core/config.mk -> build/core/envsetup.mk -> build/core/product_config.mk
由 build/core/config.mk 所進行。 build/core/envsetup.mk 檢查 developer 的設定 (buildspec.mk) ,並檢查執行環境,以決定輸出目錄、項目。
build/core/config.mk 本身還依據參數,決定解譯時的相關參數。像是 compiler 的路徑、flags, lex 、yacc 的路徑參數等。
關於 product 的相關設定,則是由 build/core/product_config.mk 所處理,使用 build/core/product.mk 提供之 macro 載入。根據 AndroidProduct.mk 的內容, product_config.mk 決定了
PRODUCT_TAGS
OTA_PUBLIC_KEYS
PRODUCT_POLICY
......
Product 設定的讀取
呼叫build/core/product.mk中定義的函數get-all-product-makefiles ,來搜尋整個vendor 的子目錄,找到vendor下所有的AndroidProducts.mk, 不同子目錄下的AndroidProducts.mk 中定義了不同的PRODUCT_NAME, PRODUCT_DEVICE 等資訊,(我們也可以通過打開build/core/product_config.mk 中的#$(dump-products) 語句使主控台編譯的時候輸出所有product 的資訊) , 接著build/core/product_config.mk 會呼叫resolve-short-product-name 將TARGET_PRODUCT符合的AndroidProducts.mk 中定義的PRODUCT_DEVICE 賦值給TARGET_DEVICE。
Module 設定的讀取
Module 是指 native code 的軟體元件,而 Java application 則被稱為 package。 build/core/definitions.mk 定義 module/package 相關 macro ,讀取、檢查 module/package 定義檔;分散 source tree 各處的 Android.mk 檔案。 build/core/main.mk 使用 find 指令,在這些子目錄下找出所有 Android.mk ,並將路徑存在 subdir_makefiles 變數裡。最後,include 這些檔案。
這些 Android.mk 會 include 定義成變數 BUILD_SHARED_LIBRARY 、BUILD_PACKAGE 等,和其目的相配的 makefile。這些 makefile 會變 Android.mk 定義之內容,存成 ALL_MODULES.Android.mk>. 形式。
例如;
Android.mk 定義了 LOCAL_MODULE_SUFFIX ,變會存成 ALL_MODULES.Android.mk>.LOCAL_MODULE_SUFFIX 。而 Android.mk 路徑,會存於 ALL_MODULES 變數裡。
Search Android.mk 的路徑,基本上會是整個 source tree 。但會依特定的 goal ,選擇性只找尋特定目錄。例如 SDK 只需特定目錄下的 Android.mk 。
Board Level 設定
和目標平台主板相關之設定,例如使用了什麼裝置、driver 等,或是是否需要編譯 bootloader 、 kernel 等,都是在 BoardConfig.mk 裡設定。同樣,每張主板可以有不同設定,存在不同目錄下的 BoardConfig.mk ,以 find 尋找如下檔案:
build/target/board/$(TARGET_DEVICE)/BoardConfig.mk
vendor/*/$(TARGET_DEVICE)/BoardConfig.mk
board_config_mk := \
$(strip $(wildcard \
$(SRC_TARGET_DIR)/board/$(TARGET_DEVICE)/BoardConfig.mk \
vendor/*/$(TARGET_DEVICE)/BoardConfig.mk \
))
include $(board_config_mk)
TARGET_DEVICE 是 product 所定義,因此同一個 BoardConfig.mk 可被多個 product 所使用。一個 TARGET_DEVICE ,通常只有一個 BoardConfig.mk 。 BoardConfig.mk 會被直接 include 到 building system 的 name space 裡。因此,一些 module 的 enable/disable ,可以在 BoardConfig.mk 以對映不同的主板。
另外在這裡TARGET_DEVICE 巨集也決定了TARGET_DEVICE_DIR,因為TARGET_DEVICE_DIR 取的是上面提到的BoardConfig.mk 的路徑。
TARGET_DEVICE_DIR := $(patsubst %/,%,$(dir $(board_config_mk)))
當然Android 的Ob目標輸出也是由TARGET_DEVICE決定,見build/core/envsetup.mk
TARGET_OUT_ROOT_release := $(OUT_DIR)/target
TARGET_OUT_ROOT_debug := $(DEBUG_OUT_DIR)/target
TARGET_OUT_ROOT := $(TARGET_OUT_ROOT_$(TARGET_BUILD_TYPE))
TARGET_PRODUCT_OUT_ROOT := $(TARGET_OUT_ROOT)/product
PRODUCT_OUT := $(TARGET_PRODUCT_OUT_ROOT)/$(TARGET_DEVICE)
Rules
在 module 的定義檔 Android.mk 裡,可定義 module 的 tag, LOCAL_MODULE_TAGS,以分類這些 module。每一個 product 可以指定需要的 tag (PRODUCT_TAGS),使 building system 只編譯標示這些 tag 的 module。在 build/core/main.mk 裡,所有標示特定 tag 的 module 收集為 ALL_DEFAULT_INSTALLED_MODULES ,並 include build/core/Makefile 處理。
build/core/Makefile 為這些 module 產生 rule ,並使產生 image 的 goal depend on 這些 rule ,使這些 module 被編譯。
再回到build/core/main.mk,編譯系統接著做的一個件事情是,遍歷所有字目錄,找到所有Android.mk檔案,並將這些Android.mk檔案include 進來
#
# Typical build; include any Android.mk files we can find.
#
subdir_makefiles := \
$(shell build/tools/findleaves.py --prune=out --prune=.repo --prune=.git $(subdirs) Android.mk)
include $(subdir_makefiles)
我們再來看其中的
./build/target/board/Android.mk
,對了它參照了
include $(TARGET_DEVICE_DIR)/AndroidBoard.mk
由上面TARGET_DEVICE_DIR的定義,這下又進入了vendor 下TARGET_DEVICE指向的目錄了,這個mk檔案中定義了特定Product需要編譯和安裝app 和script.
留言列表