Android 6.0中的Makefile

本文基于AOSP的android-6.0.1_r9分支,介紹Android平臺編譯系統中的Makefile。

(本文轉載自本人的個人網站,謝絕二次轉載。原文鏈接:http://note.qidong.name/2017/08/android-6.0-makefile/

簡介

之所以選android-6.0.1_r9這個分支,是因為這是最后一個純Makefile的大版本。后面隨著時間的發展,Android項目變得越來越龐大,純Makefile編譯系統已經越來越不堪使用。使用Makefile,不僅擴展不便,而且執行效率也不太高。從7.0版本開始,Android已經開始用Ninja來替代Makefile。

6.0版本,是Makefile最后的輝煌。Android平臺的編譯系統,其實就是用Makefile寫出來的一個獨立項目。這個項目,不僅把分散在數百個Git庫中的代碼整合起來、統一編譯,而且還把產物分門別類地輸出到一個目錄,打包成手機ROM,更能產生應用開發時所使用的SDK、NDK、網頁文檔等。以前,從來沒有這么大規模的一個手寫Makefile項目,以后應該也不會再有了。

在大、中型項目都普遍使用高級工具來生成Makefile的時候,Android竟然還是手寫Makefile。現在看來,這也是一件咄咄怪事。

主要文件

在Android項目根目錄,都有一個Makefile文件,其核心內容只有一行。

### DO NOT EDIT THIS FILE ###
include build/core/main.mk
### DO NOT EDIT THIS FILE ###

所以,build/core/main.mk就是Android真正的Makefile入口。

在Android 6.0以前,主要的Makefile都在build/core目錄下。在Android 7.0以后,全部調整到了build/make/core中,因為build目錄下,又新增了kati、soong、blueprint等項目的目錄。

Android的編譯系統的Makefile文件,主要分成三部分:

  1. 核心組件,全部在build/core/目錄下。
    這里的幾十個mk文件,是編譯系統的核心內容,定義了編譯流程的框架。
  2. 產品組件,出現在build/target/device/vendor/目錄中。
    這部分的主要入口是AndroidProducts.mk文件,功能是指定一些產品獨特的內容。這些額外的組件,會隨著編譯前lunch PRODUCT的PRODUCT參數而改變。
  3. 模塊組件,入口為各個Git庫的Android.mk
    這是普通平臺開發者最熟悉的文件,其中定義了一個模塊的必要參數,使模塊跟隨平臺編譯。

本文只分析核心組件中的結構,以及build/core/下的一些重要文件。

核心組件

結構

build/core/main.mk
├── help.mk
├── config.mk
│   ├── pathmap.mk
│   ├── envsetup.mk
│   │   ├── version_defaults.mk
│   │   └── product_config.mk
│   │       ├── node_fns.mk
│   │       ├── product.mk
│   │       └── device.mk
│   ├── combo/select.mk
│   ├── ccache.mk
│   ├── combo/javac.mk
│   ├── clang/config.mk
│   │   ├── clang/HOST_$(HOST_2ND_ARCH).mk
│   │   ├── clang/HOST_$(HOST_ARCH).mk
│   │   ├── clang/TARGET_$(TARGET_2ND_ARCH).mk
│   │   └── clang/TARGET_$(TARGET_ARCH).mk
│   └── dumpvar.mk
├── cleanbuild.mk
│   └── cleanspec.mk
├── definitions.mk
│   └── distdir.mk
├── dex_preopt.mk
│   └── dex_preopt_libart.mk
│       └── dex_preopt_libart_boot.mk
├── pdk_config.mk
├── post_clean.mk
├── legacy_prebuilts.mk
└── Makefile
    ├── sdk_font.mk
    └── tasks/*.mk

以上結構代表main.mk中對其它Makefile的include關系。排列順序,大致依照文件中include的順序,但要注意,Makefile的排列順序不一定代表執行順序。

這個圖中僅列出了build/core目錄下的文件,不包括其它目錄下被包含的mk文件。并且,build/core目錄下總計近百個mk文件,這里也未列出沒被包含到main.mk中的那些。

部分文件說明

文件 作用
main.mk make命令入口,是整個Android編譯系統最核心的文件。
help.mk 在執行make help時打印幾個主要的Target信息。
config.mk 定義了編譯過程中的環境變量,包括BUILD_*TARGET_*等。它include的其它mk文件,也是類似作用。
cleanbuild.mk 定義了完整編譯前,清理產物的步驟和內容。
definitions.mk 定義了大量編譯過程中會用到的函數,如my-dirall-subdir-makefile等。
dex_preopt.mk 利用dexopt(Dalvik)或dex2oat(ART)對dex進行優化。
pdk_config.mk 編譯PDK(Platform Developement Kit)的產物platform.zip
post_clean.mk 針對應用層模塊的產物清理。
legacy_prebuilts.mk 定義了GRANDFATHERED_ALL_PREBUILT變量,指定一些預編譯Target。
Makefile 這是一個功能復雜的文件,可以看做main.mk的延伸。

在上述Makefile文件中,還include了tasks/*.mk,其中內容如下:

  • apicheck.mk
  • boot_jars_package_check.mk
  • build_custom_images.mk
  • collect_gpl_sources.mk
  • cts.mk
  • deps_licenses.mk
  • ide.mk
  • oem_image.mk
  • product-graph.mk
  • sdk-addon.mk
  • vendor_module_check.mk

其作用可以通過文件名來推測,這里不再贅述。

產品組件的相關文件

產品組件的主要入口是AndroidProducts.mk文件,而product_config.mk就是提供相關支持的文件。文件頭中,有一段注釋:

# Generic functions
# TODO: Move these to definitions.make once we're able to include
# definitions.make before config.make.

可見,這個文件原本只是一個臨時的獨立文件,但因為歷史原因,一直沿用至今。這也體現了這個Makefile編譯系統的一些固有缺陷。

其中的核心邏輯如下:

ifneq ($(strip $(TARGET_BUILD_APPS)),)
# An unbundled app build needs only the core product makefiles.
all_product_configs := $(call get-product-makefiles,\
    $(SRC_TARGET_DIR)/product/AndroidProducts.mk)
else
# Read in all of the product definitions specified by the AndroidProducts.mk
# files in the tree.
all_product_configs := $(get-all-product-makefiles)
endif

$(SRC_TARGET_DIR)/product/AndroidProducts.mk,就是build/target/product/AndroidProducts.mk,是系統默認自帶的文件,內含aosp-armaosp-arm64等PRODUCT。而get-all-product-makefiles則是在項目的device/vendor/兩個目錄下,查找6層以內的所有AndroidProducts.mk文件。

它include的三個文件,與definitions.mk類似,分別定義一些函數。比如,product.mk中定義了get-product-makefilescheck-all-products等函數,提供了查找AndroidProducts.mk文件、列出所有可以被lunch的PRODUCT參數等功能。

所以,如果要新增一個PRODUCT,只需在device/vendor/下合適的位置,新增一個AndroidProducts.mk,指定PRODUCT_*的各項參數即可。

Android.mk的相關文件

build/core/main.mk中,有以下代碼:

subdir_makefiles := \
    $(shell build/tools/findleaves.py $(FIND_LEAVES_EXCLUDES) $(subdirs) Android.mk)

$(foreach mk, $(subdir_makefiles), $(info including $(mk) ...)$(eval include $(mk)))

這就是查找整個Android項目中所有的Android.mk文件,并且include進來。Android.mk的組合方式,本質上和AndroidProducts.mk并無不同。只是AndroidProducts.mk的范圍小一些,而Android.mk則是在整個項目中搜索。

除此之外,build/core/下還有很多mk文件,雖然沒有直接被main.mk所include,卻會被各種Android.mk所include。比如,clear_vars.mk、package.mk等。

新增一個LOCAL_MODULE,只需要在任意位置新增一個Android.mk,指定LOCAL_*參數即可。篇幅所限,不對此做詳細介紹。

其它文件

除了Makefile文件以外,在build/下還包含了其它的工具,主要集中在build/tools/目錄下。很多用Makefile做起來不方便的工作,都由它們去做。

這些工具,以Python、Bash腳本為主,也包含部分C語言寫的微型項目,比如build/tools/acp/

總結

我在深入研究Android的編譯系統前,從未想過Makefile會有這樣壯麗的風景。利用Makefile的依賴管理,構建一個龐大而復雜的編譯系統,這無疑是一個令人驚嘆的構思。

不過,無論如何,它也快走到了盡頭。

如果說Bash的語法,令人難以把握,那么Makefile則更是令人每學每忘。假如早知道要以Makefile為主,Python、Bash、乃至C語言為輔,構建這樣一個大型項目,說不定2003年組建之初的Android團隊,就不會這樣選擇。若是以Python作為膠水,粘合各個模塊的Makefile,也許能經久不衰。

Google從7.0開始,逐步用各種工具替換Makefile,利弊參半。在編譯前用kati來把Makefile轉換為Ninja,在實際編譯各模塊時用Ninja替代Makefile。歷時12年,Android中的Makefile終于在2016年,開始退場。

參考

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,488評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,034評論 3 414
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,327評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,554評論 1 307
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,337評論 6 404
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 54,883評論 1 321
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 42,975評論 3 439
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,114評論 0 286
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,625評論 1 332
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,555評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,737評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,244評論 5 355
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 43,973評論 3 345
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,362評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,615評論 1 280
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,343評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,699評論 2 370

推薦閱讀更多精彩內容