Android编译系统入门(二)
Android.mk的使用方法
在上一篇Android編譯系統(tǒng)入門(一)中我們只要介紹了Android系統(tǒng)使用make命令默認(rèn)編譯的依賴樹是droid,而droid是一個偽目標(biāo),它有兩個先決條件droidcore和dist_files,其中重點(diǎn)是droidcore,它主要用于編譯系統(tǒng)所需的system.img,boot.img等。有了上一篇的基礎(chǔ),今天我們要分析一下Android.mk文件在整個編譯系統(tǒng)中的地位和作用。
一棵大樹的繁茂和枝葉的多少息息相關(guān)。一方面只有枝干足夠茁壯才能托起枝葉,另一方面枝葉的光合作用也能促進(jìn)枝干的生長。那么在Android編譯系統(tǒng)中,droid就是這棵樹中強(qiáng)有里的枝干,而Android.mk則是一片片的葉子,縱觀整個Android平臺Android.mk的數(shù)量在一千個以上。那么如此多的makefile文件又是在何時被整合進(jìn)整個編譯系統(tǒng)的呢?其實答案還是在main.mk中。
ifneq ($(ONE_SHOT_MAKEFILE),) # We've probably been invoked by the "mm" shell function # with a subdirectory's makefile. include $(ONE_SHOT_MAKEFILE) # Change CUSTOM_MODULES to include only modules that were # defined by this makefile; this will install all of those # modules as a side-effect. Do this after including ONE_SHOT_MAKEFILE # so that the modules will be installed in the same place they # would have been with a normal make. CUSTOM_MODULES := $(sort $(call get-tagged-modules,$(ALL_MODULE_TAGS))) FULL_BUILD := # Stub out the notice targets, which probably aren't defined # when using ONE_SHOT_MAKEFILE. NOTICE-HOST-%: ; NOTICE-TARGET-%: ;# A helper goal printing out install paths .PHONY: GET-INSTALL-PATH GET-INSTALL-PATH:@$(foreach m, $(ALL_MODULES), $(if $(ALL_MODULES.$(m).INSTALLED), \echo 'INSTALL-PATH: $(m) $(ALL_MODULES.$(m).INSTALLED)';))else # ONE_SHOT_MAKEFILEifneq ($(dont_bother),true) # # Include all of the makefiles in the system ## Can't use first-makefiles-under here because # --mindepth=2 makes the prunes not work. subdir_makefiles := \$(shell build/tools/findleaves.py $(FIND_LEAVES_EXCLUDES) $(subdirs) Android.mk)$(foreach mk, $(subdir_makefiles), $(info including $(mk) ...)$(eval include $(mk)))endif # dont_botherONE_SHOT_MAKEFILE變量和編譯選項有關(guān),當(dāng)選擇默認(rèn)make命令進(jìn)行整編的時候ONE_SHOT_MAKEFILE值為空,這是就會走下面這個分支
subdir_makefiles := \$(shell build/tools/findleaves.py $(FIND_LEAVES_EXCLUDES) $(subdirs) Android.mk)$(foreach mk, $(subdir_makefiles), $(info including $(mk) ...)$(eval include $(mk)))其中就是通過findleaves.py這個腳本來查找所有的Android.mk文件但可能并不是所有的Android.mk都會被包好進(jìn)來比如.repo .git下的就會被排除在外。這些排除選項由FIND_LEAVES_EXCLUDES決定。所有被包含進(jìn)來的Android.mk的路徑都會被追加到subdir_makefiles變量,接著通過一個foreach函數(shù)將所有的Android.mk文件都include進(jìn)來。其中$(info including $(mk) ...)負(fù)責(zé)打印這些文件信息,如下
再通過eval函數(shù)執(zhí)行include操作將Android.mk文件整合進(jìn)整棵大樹。
OK,到這里所有的Android.mk文件都被包含進(jìn)來了,等整個大樹被構(gòu)建完成后make會從依賴樹最外層的葉子開始往上執(zhí)行所有的COMMANDS。
接下來我們選取Settings模塊作為例子,詳細(xì)的解釋一下Android.mk的編寫規(guī)則和一些注意事項。Settings模塊的Android.mk內(nèi)容如下
#LOCAL_PATH表示當(dāng)前目錄的地址,一般位于include $(CLEAR_VARS)之前 LOCAL_PATH:= $(call my-dir)#CLEAR_VARS對應(yīng)的是clean_vars.mk,用于清除除了LOCAL_PATH以外的所有LOCAL_打頭的變量 include $(CLEAR_VARS)#重定向java庫文件 LOCAL_JAVA_LIBRARIES := bouncycastle conscrypt telephony-common ims-common#重定向java靜態(tài)庫文件 LOCAL_STATIC_JAVA_LIBRARIES := android-support-v4 android-support-v13 jsr305#模塊tag為optional,表示不管是選擇了什么模式都會編譯該模塊 LOCAL_MODULE_TAGS := optional#重定向本地源碼 LOCAL_SRC_FILES := \$(call all-java-files-under, src) \src/com/android/settings/EventLogTags.logtags#重定向本地資源文件 LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res#模塊名 LOCAL_PACKAGE_NAME := Settings#模塊證書簽名 LOCAL_CERTIFICATE := platform#是否是特權(quán)文件 LOCAL_PRIVILEGED_MODULE := true#使用代碼混淆 LOCAL_PROGUARD_FLAG_FILES := proguard.flags#判斷是否進(jìn)行增量編譯 ifneq ($(INCREMENTAL_BUILDS),)LOCAL_PROGUARD_ENABLED := disabledLOCAL_JACK_ENABLED := incremental endif#include三個makefile文件,進(jìn)項相關(guān)變量賦值 include frameworks/opt/setupwizard/navigationbar/common.mk include frameworks/opt/setupwizard/library/common.mk include frameworks/base/packages/SettingsLib/common.mk#開始編譯Settings模塊,對應(yīng)package.mk文件。感興趣的可以進(jìn)一步研究apk是怎么被編譯出來的,里面還是很復(fù)雜的 include $(BUILD_PACKAGE)# 如果使用的是mm或mmm命令單編Settings模塊的話會額外include test目錄下的Android.mk,用于編譯測試模塊。 ifeq (,$(ONE_SHOT_MAKEFILE)) include $(call all-makefiles-under,$(LOCAL_PATH)) endif通過上述對Android.mk文件的分析,我們可以看到需要編譯一個模塊要做的工作還是很少的,只要指定幾個變量就可以了,這也得益與google的用心良苦,它把所有的公共操作都抽取了出來,做好了各種模板,如BUILD_PACKAGE等,我們要做的只是調(diào)用適當(dāng)?shù)哪0寰托辛恕?br /> 下面介紹一些Android.mk中常用的變量,以供讀者參考。
| LOCAL_PATH | 用于確定源碼所在的目錄,一般把它放在CLEAR_VARS變量引用的前面,因為它不會背清除,每個Android.mk只需要定義一次就行 |
| CLAER_VARS | 清空很多LOCAL_開頭的變量(LOCAL_PATH除外)。因為所有的Makefile都是在一個編譯環(huán)境下執(zhí)行,因此變量的定義理論上都是全局的,每個模塊開始編譯前進(jìn)行清理工作是必不可少的 |
| LOCAL_MODULE | 模塊名,需要保證唯一存在且中間不能又空格 |
| LOCAL_MODULE_PATH | 模塊的輸出路徑 |
| LOCAL_SRC_FILES | 模塊編譯所涉及的源文件。如果是java程序,可以考慮調(diào)用all-java-files-under添加java代碼。因為有LOCAL_PATH,所以這里只需要給出文件名即可,如src |
| LOCAL_CC | 用于指定C編譯器 |
| LOCAL_CXX | 用于指定C++編譯器 |
| LOCAL_CPP_EXTENSION | 用于指定特殊的C++文件后綴名 |
| LOCAL_CFLAGS | C語言編譯時的額外選項 |
| LOCAL_CXXFLOAGS | C++編譯時的額外選項 |
| LOCAL_C_INCLUDES | 編譯C和C++時需要的額外頭文件 |
| LOCAL_STATIC_LIBRARIES | 編譯所需的靜態(tài)庫列表 |
| LOCAL_SHARED_LIBRARIES | 編譯所需的共享庫列表 |
| LOCAL_JAVA_LIBRARIES | 編譯時所需的JAVA類庫 |
| LOCAL_LDLIBS | 編譯時所需的鏈接選項 |
| LOCAL_COPY_HEADERS | 安裝應(yīng)用程序時需要復(fù)制的頭文件列表,需要和LOCAL_COPY_HEADERS_TO變量配合使用 |
| LOCAL_COPY_HEADERS_TO | 上述頭文件列表的復(fù)制目的地 |
| BUILD_XX_XX | 各種形式的編譯模板,如生成靜態(tài)、動態(tài)庫文件,可執(zhí)行文件,文檔等 |
總結(jié)
在Android編譯系統(tǒng)的學(xué)習(xí)中,我們先從最基礎(chǔ)的makefile語法規(guī)則入手,導(dǎo)出了依賴樹的概念,然后按照依賴樹的結(jié)構(gòu)逐步梳理出一個完整的Android版本編譯所設(shè)計的幾個重要節(jié)點(diǎn)。Android編譯系統(tǒng)是非常龐大的,不過經(jīng)過這次的學(xué)習(xí)希望大家能夠?qū)λ慕Y(jié)構(gòu)和基本原理有一個初步的認(rèn)識。那么接下來的各種編譯細(xì)節(jié)也能通過代碼的研讀和分析變得明朗起來。
轉(zhuǎn)載于:https://www.cnblogs.com/zqlxtt/p/5018956.html
總結(jié)
以上是生活随笔為你收集整理的Android编译系统入门(二)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: js 控制浏览器窗口大小
- 下一篇: Android中Cursor类的概念和用