Android 6.0中的Makefile

本文基于AOSP的android-6.0.1_r9分支木羹,介紹Android平臺編譯系統(tǒng)中的Makefile绷跑。

(本文轉(zhuǎn)載自本人的個人網(wǎng)站宾毒,謝絕二次轉(zhuǎn)載鸣峭。原文鏈接:http://note.qidong.name/2017/08/android-6.0-makefile/

簡介

之所以選android-6.0.1_r9這個分支前普,是因為這是最后一個純Makefile的大版本肚邢。后面隨著時間的發(fā)展,Android項目變得越來越龐大拭卿,純Makefile編譯系統(tǒng)已經(jīng)越來越不堪使用骡湖。使用Makefile,不僅擴(kuò)展不便峻厚,而且執(zhí)行效率也不太高响蕴。從7.0版本開始,Android已經(jīng)開始用Ninja來替代Makefile惠桃。

6.0版本浦夷,是Makefile最后的輝煌懊渡。Android平臺的編譯系統(tǒng),其實就是用Makefile寫出來的一個獨(dú)立項目军拟。這個項目剃执,不僅把分散在數(shù)百個Git庫中的代碼整合起來、統(tǒng)一編譯懈息,而且還把產(chǎn)物分門別類地輸出到一個目錄肾档,打包成手機(jī)ROM,更能產(chǎn)生應(yīng)用開發(fā)時所使用的SDK辫继、NDK怒见、網(wǎng)頁文檔等。以前姑宽,從來沒有這么大規(guī)模的一個手寫Makefile項目遣耍,以后應(yīng)該也不會再有了。

在大炮车、中型項目都普遍使用高級工具來生成Makefile的時候舵变,Android竟然還是手寫Makefile。現(xiàn)在看來瘦穆,這也是一件咄咄怪事纪隙。

主要文件

在Android項目根目錄,都有一個Makefile文件扛或,其核心內(nèi)容只有一行绵咱。

### 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以后住涉,全部調(diào)整到了build/make/core中麸锉,因為build目錄下,又新增了kati秆吵、soong淮椰、blueprint等項目的目錄。

Android的編譯系統(tǒng)的Makefile文件纳寂,主要分成三部分:

  1. 核心組件,全部在build/core/目錄下泻拦。
    這里的幾十個mk文件毙芜,是編譯系統(tǒng)的核心內(nèi)容,定義了編譯流程的框架争拐。
  2. 產(chǎn)品組件腋粥,出現(xiàn)在build/target/晦雨、device/vendor/目錄中。
    這部分的主要入口是AndroidProducts.mk文件隘冲,功能是指定一些產(chǎn)品獨(dú)特的內(nèi)容闹瞧。這些額外的組件,會隨著編譯前lunch PRODUCT的PRODUCT參數(shù)而改變展辞。
  3. 模塊組件奥邮,入口為各個Git庫的Android.mk
    這是普通平臺開發(fā)者最熟悉的文件罗珍,其中定義了一個模塊的必要參數(shù)洽腺,使模塊跟隨平臺編譯。

本文只分析核心組件中的結(jié)構(gòu)覆旱,以及build/core/下的一些重要文件蘸朋。

核心組件

結(jié)構(gòu)

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

以上結(jié)構(gòu)代表main.mk中對其它Makefile的include關(guān)系。排列順序扣唱,大致依照文件中include的順序藕坯,但要注意,Makefile的排列順序不一定代表執(zhí)行順序噪沙。

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

部分文件說明

文件 作用
main.mk make命令入口朋腋,是整個Android編譯系統(tǒng)最核心的文件齐疙。
help.mk 在執(zhí)行make help時打印幾個主要的Target信息。
config.mk 定義了編譯過程中的環(huán)境變量旭咽,包括BUILD_*贞奋、TARGET_*等。它include的其它mk文件穷绵,也是類似作用轿塔。
cleanbuild.mk 定義了完整編譯前,清理產(chǎn)物的步驟和內(nèi)容仲墨。
definitions.mk 定義了大量編譯過程中會用到的函數(shù)勾缭,如my-dirall-subdir-makefile等目养。
dex_preopt.mk 利用dexopt(Dalvik)或dex2oat(ART)對dex進(jìn)行優(yōu)化将谊。
pdk_config.mk 編譯PDK(Platform Developement Kit)的產(chǎn)物platform.zip岖食。
post_clean.mk 針對應(yīng)用層模塊的產(chǎn)物清理谎仲。
legacy_prebuilts.mk 定義了GRANDFATHERED_ALL_PREBUILT變量,指定一些預(yù)編譯Target兜畸。
Makefile 這是一個功能復(fù)雜的文件,可以看做main.mk的延伸碘梢。

在上述Makefile文件中咬摇,還include了tasks/*.mk,其中內(nèi)容如下:

  • 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

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

產(chǎn)品組件的相關(guān)文件

產(chǎn)品組件的主要入口是AndroidProducts.mk文件,而product_config.mk就是提供相關(guān)支持的文件汰翠。文件頭中龄坪,有一段注釋:

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

可見,這個文件原本只是一個臨時的獨(dú)立文件复唤,但因為歷史原因健田,一直沿用至今。這也體現(xiàn)了這個Makefile編譯系統(tǒng)的一些固有缺陷佛纫。

其中的核心邏輯如下:

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,是系統(tǒng)默認(rèn)自帶的文件呈宇,內(nèi)含aosp-arm好爬、aosp-arm64等PRODUCT。而get-all-product-makefiles則是在項目的device/甥啄、vendor/兩個目錄下存炮,查找6層以內(nèi)的所有AndroidProducts.mk文件。

它include的三個文件蜈漓,與definitions.mk類似穆桂,分別定義一些函數(shù)。比如融虽,product.mk中定義了get-product-makefiles享完、check-all-products等函數(shù),提供了查找AndroidProducts.mk文件有额、列出所有可以被lunch的PRODUCT參數(shù)等功能般又。

所以,如果要新增一個PRODUCT巍佑,只需在device/vendor/下合適的位置茴迁,新增一個AndroidProducts.mk,指定PRODUCT_*的各項參數(shù)即可句狼。

Android.mk的相關(guān)文件

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進(jìn)來腻菇。Android.mk的組合方式胳螟,本質(zhì)上和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_*參數(shù)即可。篇幅所限裁僧,不對此做詳細(xì)介紹个束。

其它文件

除了Makefile文件以外,在build/下還包含了其它的工具聊疲,主要集中在build/tools/目錄下茬底。很多用Makefile做起來不方便的工作,都由它們?nèi)プ觥?/p>

這些工具获洲,以Python阱表、Bash腳本為主,也包含部分C語言寫的微型項目贡珊,比如build/tools/acp/最爬。

總結(jié)

我在深入研究Android的編譯系統(tǒng)前,從未想過Makefile會有這樣壯麗的風(fēng)景飞崖。利用Makefile的依賴管理烂叔,構(gòu)建一個龐大而復(fù)雜的編譯系統(tǒng),這無疑是一個令人驚嘆的構(gòu)思固歪。

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

如果說Bash的語法逢防,令人難以把握,那么Makefile則更是令人每學(xué)每忘蒲讯。假如早知道要以Makefile為主忘朝,Python、Bash判帮、乃至C語言為輔局嘁,構(gòu)建這樣一個大型項目溉箕,說不定2003年組建之初的Android團(tuán)隊,就不會這樣選擇悦昵。若是以Python作為膠水肴茄,粘合各個模塊的Makefile,也許能經(jīng)久不衰但指。

Google從7.0開始寡痰,逐步用各種工具替換Makefile,利弊參半棋凳。在編譯前用kati來把Makefile轉(zhuǎn)換為Ninja拦坠,在實際編譯各模塊時用Ninja替代Makefile。歷時12年剩岳,Android中的Makefile終于在2016年贞滨,開始退場。

參考

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末卢肃,一起剝皮案震驚了整個濱河市疲迂,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌莫湘,老刑警劉巖尤蒿,帶你破解...
    沈念sama閱讀 211,639評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異幅垮,居然都是意外死亡腰池,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,277評論 3 385
  • 文/潘曉璐 我一進(jìn)店門忙芒,熙熙樓的掌柜王于貴愁眉苦臉地迎上來示弓,“玉大人,你說我怎么就攤上這事呵萨∽嗍簦” “怎么了?”我有些...
    開封第一講書人閱讀 157,221評論 0 348
  • 文/不壞的土叔 我叫張陵潮峦,是天一觀的道長囱皿。 經(jīng)常有香客問我,道長忱嘹,這世上最難降的妖魔是什么嘱腥? 我笑而不...
    開封第一講書人閱讀 56,474評論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮拘悦,結(jié)果婚禮上齿兔,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好分苇,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,570評論 6 386
  • 文/花漫 我一把揭開白布添诉。 她就那樣靜靜地躺著,像睡著了一般组砚。 火紅的嫁衣襯著肌膚如雪吻商。 梳的紋絲不亂的頭發(fā)上掏颊,一...
    開封第一講書人閱讀 49,816評論 1 290
  • 那天糟红,我揣著相機(jī)與錄音,去河邊找鬼乌叶。 笑死盆偿,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的准浴。 我是一名探鬼主播事扭,決...
    沈念sama閱讀 38,957評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼乐横!你這毒婦竟也來了求橄?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,718評論 0 266
  • 序言:老撾萬榮一對情侶失蹤葡公,失蹤者是張志新(化名)和其女友劉穎罐农,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體催什,經(jīng)...
    沈念sama閱讀 44,176評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡涵亏,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,511評論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了蒲凶。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片气筋。...
    茶點(diǎn)故事閱讀 38,646評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖旋圆,靈堂內(nèi)的尸體忽然破棺而出宠默,到底是詐尸還是另有隱情,我是刑警寧澤灵巧,帶...
    沈念sama閱讀 34,322評論 4 330
  • 正文 年R本政府宣布搀矫,位于F島的核電站,受9級特大地震影響孩等,放射性物質(zhì)發(fā)生泄漏艾君。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,934評論 3 313
  • 文/蒙蒙 一肄方、第九天 我趴在偏房一處隱蔽的房頂上張望冰垄。 院中可真熱鬧,春花似錦、人聲如沸虹茶。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,755評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽蝴罪。三九已至董济,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間要门,已是汗流浹背虏肾。 一陣腳步聲響...
    開封第一講書人閱讀 31,987評論 1 266
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留欢搜,地道東北人封豪。 一個月前我還...
    沈念sama閱讀 46,358評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像炒瘟,于是被迫代替她去往敵國和親吹埠。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,514評論 2 348

推薦閱讀更多精彩內(nèi)容