Android源代碼編譯命令m mm mmm make分析_第1頁
Android源代碼編譯命令m mm mmm make分析_第2頁
Android源代碼編譯命令m mm mmm make分析_第3頁
Android源代碼編譯命令m mm mmm make分析_第4頁
Android源代碼編譯命令m mm mmm make分析_第5頁
已閱讀5頁,還剩21頁未讀, 繼續(xù)免費閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認領

文檔簡介

Android源代碼編譯命令m/mm/mmm/make分析在前文中,我們分析了Android編譯環(huán)境的初始化過程。Android編譯環(huán)境初始化完成后,我們就可以用m/mm/mmm/make命令編譯源代碼了。當然,這要求每一個模塊都有一個Android.mk文件。Android.mk實際上是一個Makefile腳本,用來描述模塊編譯信息。Android編譯系統(tǒng)通過整合Android.mk文件完成編譯過程。本文就對Android源代碼的編譯過程進行詳細分析。從前面這篇文章可以知道,lunch命令其實是定義在build/envsetup.sh文件中的函數(shù)lunch提供的。與lunch命令一樣,m、mm和mmm命令也分別是由定義在build/envsetup.sh文件中的函數(shù)m、mm和mmm提供的,而這三個函數(shù)又都是通過make命令來對源代碼進行編譯的。事實上,命令m就是對make命令的簡單封裝,并且是用來對整個Android源代碼進行編譯,而命令mm和mmm都是通過make命令來對Android源碼中的指定模塊進行編譯。接下來我們就先分別介紹一下函數(shù)m、mm和mmm的實現(xiàn),然后進一步分析它們是如何通過make命令來編譯代碼的。函數(shù)m的實現(xiàn)如下所示:[plain]viewplaincopy在CODE上查看代碼片派生到我的代碼片functionm(){T=$(gettop)if["$T"];thenmake-C$T$@elseecho"Couldn'tlocatethetopofthetree.TrysettingTOP."fi}函數(shù)m調(diào)用函數(shù)gettop得到的是Android源代碼根目錄T。在執(zhí)行make命令的時候,先通過-C選項指定工作目錄為T,即Android源代碼根目錄,接著又將執(zhí)行命令m指定的參數(shù)$@作為命令make的參數(shù)。從這里就可以看出,命令m實際上就是對命令make的簡單封裝。函數(shù)mm的實現(xiàn)如下所示:[plain]viewplaincopy在CODE上查看代碼片派生到我的代碼片functionmm(){#Ifwe'resittingintherootofthebuildtree,justdoa#normalmake.if[-fbuild/core/envsetup.mk-a-fMakefile];thenmake$@else#FindtheclosestAndroid.mkfile.T=$(gettop)localM=$(findmakefile)#RemovethepathtotopasthemakefilepathneedstoberelativelocalM=`echo$M|sed's:'$T'/::'`if[!"$T"];thenecho"Couldn'tlocatethetopofthetree.TrysettingTOP."elif[!"$M"];thenecho"Couldn'tlocateamakefilefromthecurrentdirectory."elseONE_SHOT_MAKEFILE=$Mmake-C$Tall_modules$@fifi}函數(shù)mm首先是判斷當前目錄是否就是Android源碼根目錄,即當前目錄下是否存在一個build/core/envsetup.mk文件和一個Makefile文件。如果是的話,就將命令mm當作是一個普通的make命令來執(zhí)行。否則的話,就調(diào)用函數(shù)findmakefile從當前目錄開始一直往上尋找是否存在一個Android.mk文件。如果在尋找的過程中,發(fā)現(xiàn)了一個Android.mk文件,那么就獲得它的絕對路徑,并且停止上述尋找過程。由于接下來執(zhí)行make命令時,我們需要指定的是要編譯的Android.mk文件的相對于Android源碼根目錄路徑,因此函數(shù)mm需要將剛才找到的Android.mk絕對文件路徑M中與Android源碼根目錄T相同的那部分路徑去掉。這是通過sed命令來實現(xiàn)的,也就是將字符串M前面與字符串T相同的子串刪掉。最后,將找到的Android.mk文件的相對路徑設置給環(huán)境變量ONE_SHOT_MAKE,表示接下來要對它進行編譯。另外,函數(shù)mm還將make命令目標設置為all_modules。這是什么意思呢?我們知道,一個Android.mk文件同時可以定義多個模塊,因此,all_modules就表示要對前面指定的Android.mk文件中定義的所有模塊進行編譯。函數(shù)mmm的實現(xiàn)如下所示:[plain]viewplaincopy在CODE上查看代碼片派生到我的代碼片functionmmm(){T=$(gettop)if["$T"];thenlocalMAKEFILE=localMODULES=localARGS=localDIRTO_CHOPlocalDASH_ARGS=$(echo"$@"|awk-vRS=""-vORS=""'/^-.*$/')localDIRS=$(echo"$@"|awk-vRS=""-vORS=""'/^[^-].*$/')forDIRin$DIRS;doMODULES=`echo$DIR|sed-n-e's/.*:.?$/\1/p'|sed's/,//'`if["$MODULES"=""];thenMODULES=all_modulesfiDIR=`echo$DIR|sed-e's/:.*//'-e's:/$::'`if[-f$DIR/Android.mk];thenTO_CHOP=`(cd-P--$T&&pwd-P)|wc-c|tr-d''`TO_CHOP=`expr$TO_CHOP+1`START=`PWD=/bin/pwd`MFILE=`echo$START|cut-c${TO_CHOP}-`if["$MFILE"=""];thenMFILE=$DIR/Android.mkelseMFILE=$MFILE/$DIR/Android.mkfiMAKEFILE="$MAKEFILE$MFILE"elseif["$DIR"=snod];thenARGS="$ARGSsnod"elif["$DIR"=showcommands];thenARGS="$ARGSshowcommands"elif["$DIR"=dist];thenARGS="$ARGSdist"elif["$DIR"=incrementaljavac];thenARGS="$ARGSincrementaljavac"elseecho"NoAndroid.mkin$DIR."return1fifidoneONE_SHOT_MAKEFILE="$MAKEFILE"make-C$T$DASH_ARGS$MODULES$ARGSelseecho"Couldn'tlocatethetopofthetree.TrysettingTOP."fi}函數(shù)mmm的實現(xiàn)就稍微復雜一點,我們詳細解釋一下。首先,命令mmm可以這樣執(zhí)行:[plain]viewplaincopy在CODE上查看代碼片派生到我的代碼片$mmm<dir-1><dir-2>...<dir-N>[:module-1,module-2,...,module-M]其中,dir-1、dir-2、dir-N都是包含有Android.mk文件的目錄。在最后一個目錄dir-N的后面可以帶一個冒號,冒號后面可以通過逗號分隔一系列的模塊名稱module-1、module-2和module-M,用來表示要編譯前面指定的Android.mk中的哪些模塊。知道了命令mmm的使用方法之后,我們就可以分析函數(shù)mmm的執(zhí)行邏輯了:1.調(diào)用函數(shù)gettop獲得Android源碼根目錄。2.通過命令awk將執(zhí)行命令mmm時指定的選項參數(shù)提取出來,也就是將以橫線“-”開頭的字符串提取出來,并且保存在變量DASH_ARGS中。3.通過命令awk將執(zhí)行命令mmm時指定的非選項參數(shù)提取出來,也就是將非以橫線“-”開頭的字符串提取出來,并且保存在變量DIRS中。這里得到的實際上就是跟在命令mmm后面的字符串“<dir-1><dir-2>...<dir-N>[:module-1,module-2,...,module-M]”。4.變量DIRS保存的字符串可以看成是一系以空格分隔的子字符串,因此,就可以通過一個for循環(huán)來對這些子字府串進行遍歷。每一個子字符串DIR描述的都是一個包含有Android.mk文件的目錄。對每一個目錄DIR執(zhí)行以下操作:4.1由于目錄DIR后面可能會通過冒號指定有模塊名稱,因此就先通過兩個sed命令來獲得這些模塊名稱。第一個sed命令獲得的是一系列以逗號分隔的模塊名稱列表,第二個sed命令用來將前面獲得的以逗號分隔的模塊名稱列表轉(zhuǎn)化為以空格分隔的模塊名稱列表。最后,獲得的以空格分隔的模塊名稱列表保存在變量MODULES中。由于目錄DIR后面也可能不指定有模塊名稱,因此前面得到的變量MODULES的值就會為空。在這種情況下,需要將變量MODULES的值設置為“all_modules”,表示要編譯的是所有模塊。4.2通過兩個sed命令獲得真正的目錄DIR。第一個sed命令將原來DIR字符串后面的冒號以及冒號后面的模塊列表字符串刪掉。第二個sed命令將執(zhí)行前面一個sed命令獲得的目錄后面的"/"斜線去掉,最后就得到一個末尾不帶有斜線“/”的路徑,并且保存在變量DIR中。4.3如果變量DIR描述的是一個真正的路徑,也就是在該路徑下存在一個Android.mk文件,那么就進行以下處理:4.3.1統(tǒng)計Android源碼根目錄T包含的字符數(shù),并且將這個字符數(shù)加1,得到的值保存在變量TO_CHOP中。4.3.2通過執(zhí)行/bin/pwd命令獲得當前執(zhí)行命令mmm的目錄START。4.3.3通過cut命令獲得當前目錄START相對于Android源碼根目錄T的路徑,并且保存在變量MFILE中。4.3.4如果變量MFILE的值等于空,就表明是在Android源碼根目錄T中執(zhí)行mmm命令,這時候就表明變量DIR描述的就是相對Android源碼根目錄T的一個目錄,這時候指定的Android.mk文件相對于Android源碼根目錄T的路徑就為$DIR/Android.mk。4.3.5如果變量MFILE的值不等于空,就表明是在Android源碼根目錄T的某一個子目錄中執(zhí)行mmm命令,這時候$MFILE/$DIR/Android.mk表示的Android.mk文件路徑才是相對于Android源碼根目錄T的。4.3.6將獲得的Android.mk路徑MFILE附加在變量MAKEFILE描述的字符串的后面,并且以空格分隔。4.4如果變量DIR描述的不是一個真正的路徑,并且它的值等于"snod"、"showcomands"、“dist”或者“incrementaljavac”,那么它描述的其實是make修飾命令。這四個修飾命令的含義分別如下所示:4.4.1snod是“systemimagewithnodependencies”的意思,表示忽略依賴性地重新打包system.img。4.4.2showcommands表示顯示編譯過程中執(zhí)行的命令。4.4.3dist表示將編譯后產(chǎn)生的發(fā)布文件拷貝到out/dist目錄中。4.4.4incrementaljavac表示對Java源文件采用增量式編譯,也就是如果一個Java文件如果沒有修改過,那么就不要重新生成對應的class文件。5.上面的for循環(huán)執(zhí)行完畢,變量MAKEFILE保存的是要編譯的Android.mk文件列表,它們都是相對于Android源碼根目錄的路徑,變量DASH_ARGS保存的是原來執(zhí)行mmm命令時帶的選項參數(shù),變量MODULES保存的是指定要編譯的模塊名稱,變量ARGS保存的是修飾命令。其中,變量MAKEFILE的內(nèi)容通過環(huán)境變量ONE_SHOT_MAKEFILE傳遞給make命令,而其余變量都是通過參數(shù)的形式傳遞給make命令,并且變量MODULES作為make命令的目標。明白了函數(shù)m、mm和mmm的實現(xiàn)之后,我們就可以知道:1.mm和mmm命令是類似的,它們都是用來編譯某些模塊。2.m命令用來編譯所有模塊。如果我們理解了mm或者mmm命令的編譯過程,那么自然也會明白m命令的編譯過程,因為所有模塊的編譯過程就等于把每一個模塊的編譯都編譯出來,因此,接下來我們就選擇具有代表性的、常用的編譯命令mmm來分析Android源碼的編譯過程,如圖1所示:函數(shù)mmm在Android源碼根目錄執(zhí)行make命令的時候,沒有通過-f指定Makefile文件,因此默認就使用Android源碼根目錄下的Makefile文件,它的內(nèi)容如下所示:[plain]viewplaincopy在CODE上查看代碼片派生到我的代碼片###DONOTEDITTHISFILE###includebuild/core/main.mk###DONOTEDITTHISFILE###它僅僅是將build/core/main.mk文件加載進來。build/core/main.mk是Android編譯系統(tǒng)的入口文件,它通過加載其它的mk文件來對Android源碼中的各個模塊進行編譯,以及將編譯出來的文件打包成各種鏡像文件。以下就是build/core/main.mk文件的主要內(nèi)容:[plain]viewplaincopy在CODE上查看代碼片派生到我的代碼片......#Thisisthedefaulttarget.Itmustbethefirstdeclaredtarget..PHONY:droidDEFAULT_GOAL:=droid$(DEFAULT_GOAL):......#Setupvariousstandardvariablesbasedonconfiguration#andhostinformation.include$(BUILD_SYSTEM)/config.mk......#Bringinstandardbuildsystemdefinitions.include$(BUILD_SYSTEM)/definitions.mk......#Thesetargetsaregoingtodeletestuff,don'tbotherincluding#thewholedirectorytreeifthat'sallwe'regoingtodoifeq($(MAKECMDGOALS),clean)dont_bother:=trueendififeq($(MAKECMDGOALS),clobber)dont_bother:=trueendififeq($(MAKECMDGOALS),dataclean)dont_bother:=trueendififeq($(MAKECMDGOALS),installclean)dont_bother:=trueendif#Bringinallmodulesthatneedtobebuilt.ifneq($(dont_bother),true)......ifneq($(ONE_SHOT_MAKEFILE),)#We'veprobablybeeninvokedbythe"mm"shellfunction#withasubdirectory'smakefile.include$(ONE_SHOT_MAKEFILE)......else#ONE_SHOT_MAKEFILE##Includeallofthemakefilesinthesystem##Can'tusefirst-makefiles-underherebecause#--mindepth=2makestheprunesnotwork.subdir_makefiles:=\$(shellbuild/tools/findleaves.py--prune=out--prune=.repo--prune=.git$(subdirs)Android.mk)include$(subdir_makefiles)endif#ONE_SHOT_MAKEFILE......#-------------------------------------------------------------------#Definedependenciesformodulesthatrequireothermodules.#Thiscanonlyhappennow,afterwe'vereadinallmodulemakefiles.##TODO:dealwiththefactthatabaremodulenameisn't#unambiguousenough.Maybedeclareshorttargetslike#APPS:QuakeorHOST:SHARED_LIBRARIES:libutils.#BUG:thesystemimagewon'tknowtodependonmodulesthatare#broughtinasrequirementsofothermodules.defineadd-required-deps$(1):$(2)endef$(foreachm,$(ALL_MODULES),\$(evalr:=$(ALL_MODULES.$(m).REQUIRED))\$(if$(r),\$(evalr:=$(callmodule-installed-files,$(r)))\$(eval$(calladd-required-deps,$(ALL_MODULES.$(m).INSTALLED),$(r)))\)\)......modules_to_install:=$(sort\$(ALL_DEFAULT_INSTALLED_MODULES)\$(product_FILES)\$(foreachtag,$(tags_to_install),$($(tag)_MODULES))\$(callget-tagged-modules,shell_$(TARGET_SHELL))\$(CUSTOM_MODULES)\)......#build/core/Makefilecontainsextrastuffthatwedon'twanttopollutethis#top-levelmakefilewith.ItexpectsthatALL_DEFAULT_INSTALLED_MODULES#containseverythingthat'sbuiltduringthecurrentmake,butitalsofurther#extendsALL_DEFAULT_INSTALLED_MODULES.ALL_DEFAULT_INSTALLED_MODULES:=$(modules_to_install)include$(BUILD_SYSTEM)/Makefilemodules_to_install:=$(sort$(ALL_DEFAULT_INSTALLED_MODULES))ALL_DEFAULT_INSTALLED_MODULES:=endif#dont_bother......#-------------------------------------------------------------------#Thisisusedtotogettheorderingright,youcanalsousethese,#butthey'reconsideredundocumented,sodon'tcomplainiftheir#behaviorchanges..PHONY:prebuiltprebuilt:$(ALL_PREBUILT)......#Allthedroidstuff,indirectories.PHONY:filesfiles:prebuilt\$(modules_to_install)\$(modules_to_check)\$(INSTALLED_ANDROID_INFO_TXT_TARGET)......#Buildfilesandthenpackageitintotheromformats.PHONY:droidcoredroidcore:files\systemimage\$(INSTALLED_BOOTIMAGE_TARGET)\$(INSTALLED_RECOVERYIMAGE_TARGET)\$(INSTALLED_USERDATAIMAGE_TARGET)\$(INSTALLED_CACHEIMAGE_TARGET)\$(INSTALLED_FILES_FILE)......#Distfordroidifdroidisamongthecmdgoals,ornocmdgoalisgiven.ifneq($(filterdroid,$(MAKECMDGOALS))$(filter||,|$(filter-out$(INTERNAL_MODIFIER_TARGETS),$(MAKECMDGOALS))|),)ifneq($(TARGET_BUILD_APPS),)#Ifthisbuildisjustforapps,onlybuildappsandnotthefullsystembydefault........PHONY:apps_onlyapps_only:$(unbundled_build_modules)droid:apps_onlyelse#TARGET_BUILD_APPS......#Buildingafullsystem--thedefaultistobuilddroidcoredroid:droidcoredist_filesendif#TARGET_BUILD_APPSendif#droidin$(MAKECMDGOALS)......#phonytargetthatincludeanytargetsin$(ALL_MODULES).PHONY:all_modulesall_modules:$(ALL_MODULES)......接下來我們就先對build/core/main.mk文件的核心邏輯進行分析,然后再進一步對其中涉及到的關鍵點進行分析。build/core/main.mk文件的執(zhí)行過程如下所示:1.定義默認make目標為droid。目標droid根據(jù)不同的情形有不同的依賴關系。如果在初始化編譯環(huán)境時,指定了TARGET_BUILD_APPS環(huán)境變量,那么就表示當前只編譯特定的模塊,這些特定的模塊保存在變量unbundled_build_modules中,這時候目標droid就透過另外一個偽目標app_only依賴它們。如果在初始化編譯環(huán)境時沒有指定TARGET_BUILD_APPS環(huán)境變量,那么目標droid就依賴于另外兩個文件droidcore和dist_files。droidcore是一個make偽目標,它依賴于各種預編譯文件,以及system.img、boot.img、recovery.img和userdata.img等鏡像文件。dist_files也是一個make偽目標,用來指定一些需要在編譯后拷貝到out/dist目錄的文件。也就是說,當我們在Android源碼目錄中執(zhí)行不帶目標的make命令時,默認就會對目標droid進行編譯,也就是會將整個Android系統(tǒng)編譯出來。2.加載build/core/config.mk文件。從前面一文可以知道,在加載build/core/config.mk文件的過程中,會在執(zhí)行make命令的進程中完成對Android編譯環(huán)境的初始化過程,也就是會指定好目標設備以及編譯類型。3.加載build/croe/definitions.mk文件。該文件定義了很多在編譯過程中要用到的宏,相當于就是定義了很多通用函數(shù),供編譯過程調(diào)用。4.如果在執(zhí)行make命令時,指定的不是清理文件相關的目標,也就是不是clean、clobber、dataclean和installclean等目標,那么就會將變量dont_bother的值設置為true,表示接下來要執(zhí)行的是編譯命令。5.在變量dont_bother的值等于true的情況下,如果環(huán)境變量ONE_SHOT_MAKEFILE的值不等于空,也就是我們執(zhí)行的是mm或者mmm命令,那么就表示要編譯的是特定的模塊。這些指定要編譯的模塊的Android.mk文件路徑就保存在環(huán)境變量ONE_SHOT_MAKEFILE中,因此直接將這些Android,mk文件加載進來就獲得相應的編譯規(guī)則。另一方面,如果環(huán)境變量ONE_SHOT_MAKEFILE的值等于空,那么就說明我們執(zhí)行的是m或者make命令,那么就表示要對Android源代碼中的所有模塊進行編譯,這時候就通過build/tools/findleaves.py腳本獲得Android源代碼工程下的所有Android.mk文件的路徑列表,并且將這些Android.mk文件加載進行獲得相應的編譯規(guī)則。6.上一步指定的Android.mk文件加載完成之后,變量ALL_MODULES就包含了所有要編譯的模塊的名稱,這些模塊名稱以空格來分隔形成成一個列表。7.生成模塊依賴規(guī)則。每一個模塊都可以通過LOCAL_REQUIRED_MODULES來指定它所依賴的其它模塊,也就是說當一個模塊被安裝時,它所依賴的其它模塊也同樣會被安裝。每一個模塊m依賴的所有模塊都會被保存在ALL_MODULES.$(m).REQUIRED變量中。對于每一個被依賴模塊r,我們需要獲得它的安裝文件,也就是最終生成的模塊文件的文件路徑,以便可以生成相應的編譯規(guī)則。獲得一個模塊m的安裝文件是通過調(diào)用函數(shù)module-installed-files來實現(xiàn)的,實質(zhì)上就是保存在$(ALL_MODULES.$(m).INSTALLED變量中。知道了一個模塊m的所依賴的模塊的安裝文件路徑之后,我們就可以通過函數(shù)add-required-deps來指定它們之間的依賴關系了。注意,這里實際上指定的是模塊m的安裝文件與它所依賴的模塊r的安裝文件的依賴關系。8.將所有要安裝的模塊都保存在變量ALL_DEFAULT_INSTALLED_MODULES中,并且將build/core/Makefie文件加載進來。build/core/Makefie文件會根據(jù)要安裝的模塊產(chǎn)成system.img、boot.img和recovery.img等鏡像文件的生成規(guī)則。9.前面提到,當執(zhí)行mm命令時,make目標指定為all_moudles。另外,當執(zhí)行mmm命令時,默認的make目標也指定為all_moudles。因此,我們需要指定目標all_modules的編譯規(guī)則,實際上只要將它依賴于當前要編譯的所有模塊就行了,也就是依賴于由變量ALL_MODULES所描述的模塊。在上述過程中,最核心的就是第5步和第8步。由于本文只關心Android源碼的編譯過程,因此我們只分析第5步的執(zhí)行過程。在接下來一篇文章中分析Android鏡像文件的生成過程時,我們再分析第8步的執(zhí)行過程。第5步實際上就是將指定模塊的Android.mk文件加載進來。一個典型的Android.mk文件如下所示:[plain]viewplaincopy在CODE上查看代碼片派生到我的代碼片LOCAL_PATH:=$(callmy-dir)include$(CLEAR_VARS)LOCAL_MODULE_TAGS:=optionalLOCAL_MODULE:=libdisLOCAL_SHARED_LIBRARIES:=\liblog\libdlLOCAL_SRC_FILES:=\dispatcher.cpp\../common/common.cppinclude$(BUILD_SHARED_LIBRARY)以LOCAL開頭的變量都是屬于模塊局部變量,也就是說,一個模塊在開始編譯之前,必須要先對它們進行清理,然后再進行初始化。Android編譯系統(tǒng)定義了非常多的模塊局部變量,因此我們不可能手動地一個一個清理,需要加載一個由變量CLEAR_VARS指定的Makefile腳本來幫我們自動清理。變量CLEAR_VARS的值定義在build/core/config.mk文件,它的值等于build/core/clear_vars.mk。Android.mk文件中還有一個重要的變量LOCAL_PATH,用來指定當前正在編譯的模塊的目錄,我們可以通過調(diào)用宏my-dir來獲得。宏my-dir定義在build/core/definitions.mk文件,它實際上就是將當前正在加載的Android.mk文件路徑的目錄名提取出來。Android.mk文件接下來就是通過其它的LOCAL變量定義模塊名稱、源文件,以及所要依賴的各種庫文件等等。例如,在我們這個例子,模塊名稱定義為libdis,參與編譯的源文件為dispatcher.cpp和common.cpp、依賴的庫文件為liblog和libdl。最后,Android文件通過加載一個模板文件來告訴編譯系統(tǒng)它所要編譯的模塊的類型。例如,在我們這個例子中,就是通過加載由變量BUILD_SHARED_LIBRARY指定的模板文件來告訴編譯系統(tǒng)我們要編譯的模塊是一個動態(tài)鏈接庫。變量BUILD_SHARED_LIBRARY的值定義在build/core/config.mk文件,它的值等于build/core/shared_library.mk。Android編譯系統(tǒng)定義了非常多的模板文件,每一個模板文件都對應一種類型的模塊,例如除了我們上面的動態(tài)鏈接庫模板文件之外,還有:BUILD_PACKAGE:指向build/core/package.mk,用來編譯APK文件。BUILD_JAVA_LIBRARY:指向build/core/java_library.mk,用來編譯Java庫文件。BUILD_STATIC_JAVA_LIBRARY:指向build/core/tatic_java_library.mk,用來編譯Java靜態(tài)庫文件。BUILD_STATIC_LIBRARY:指向build/core/static_library.mk,用來編譯靜態(tài)庫文件。也就是.a文件。BUILD_EXECUTABLE:指向build/core/executable.mk,用來編譯可執(zhí)行文件。BUILD_PREBUILT:指向build/core/prebuilt.mk。用來編譯已經(jīng)預編譯好的第三方庫文件,實際上是將這些預編譯好的第三方庫文件拷貝到合適的位置去,以便可以讓其它模塊引用。不管編譯何種類型的模塊,都是主要完成以下的工作:1.制定好相應的依賴規(guī)則2.調(diào)用合適的命令進行編譯為了簡單起見,接下來我們就以動態(tài)鏈接庫(即.so文件)的編譯過程為例來說明Android編譯命令mmm的執(zhí)行過程。在分析動態(tài)鏈接庫的編譯過程之前,我們首先看一看使用mmm命令來編譯上述的Android.mk文件時得到的輸出,如下所示:[plain]viewplaincopy在CODE上查看代碼片派生到我的代碼片targetthumbC++:libdis<=external/si/dispatcher/dispatcher.cpptargetthumbC++:libdis<=external/si/dispatcher/../common/common.cpptargetSharedLib:libdis(out/target/product/generic/obj/SHARED_LIBRARIES/libdis_intermediates/LINKED/libdis.so)targetSymbolic:libdis(out/target/product/generic/symbols/system/lib/libdis.so)targetStrip:libdis(out/target/product/generic/obj/lib/libdis.so)Install:out/target/product/generic/system/lib/libdis.so從這些輸出我們大體推斷出一些文件之間的依賴關系及其生成過程:1.out/target/product/generic/obj/SHARED_LIBRARIES/libdis_intermediates/LINKED/libdis.so文件依賴于external/si/dispatcher/dispatcher.cpp和external/si/dispatcher/../common/common.cpp文件,并且由它們生成。2.out/target/product/generic/symbols/system/lib/libdis.so依賴于out/target/product/generic/obj/SHARED_LIBRARIES/libdis_intermediates/LINKED/libdis.so文件,并且由它生成。3.out/target/product/generic/obj/lib/libdis.so依賴于out/target/product/generic/symbols/system/lib/libdis.so文件,并且由它生成。4.out/target/product/generic/system/lib/libdis.so依賴于out/target/product/generic/obj/lib/libdis.so文件,并且由它生成?;貞浨懊娴姆治?,我們提到,當執(zhí)行mmm命令時,默認的make目標是all_modules,并且它依賴于變量ALL_MODULES指向的文件或者目標,因此,我們可以繼續(xù)推斷出,變量ALL_MODULES指向的文件或者目標一定會與文件out/target/product/generic/system/lib/libdis.so有依賴關系,這樣才能夠從make目標all_modules開始鏈式地生成上述文件。在接下來的分析中,我們就按照抓住上述文件的依賴關系進行逆向分析。從上面的分析可以知道,在編譯動態(tài)鏈接庫文件的過程中,文件build/core/shared_library.mk會被加載,它的核心內(nèi)容如下所示:[plain]viewplaincopy在CODE上查看代碼片派生到我的代碼片......ifeq($(strip$(LOCAL_MODULE_CLASS)),)LOCAL_MODULE_CLASS:=SHARED_LIBRARIESendififeq($(strip$(LOCAL_MODULE_SUFFIX)),)LOCAL_MODULE_SUFFIX:=$(TARGET_SHLIB_SUFFIX)endif......include$(BUILD_SYSTEM)/dynamic_binary.mk......$(linked_module):$(all_objects)$(all_libraries)\$(LOCAL_ADDITIONAL_DEPENDENCIES)\$(my_target_crtbegin_so_o)$(my_target_crtend_so_o)$(transform-o-to-shared-lib)LOCAL_MODULE_CLASS用來描述模塊文件的類型。對于動態(tài)鏈接庫文件來說,如果我們沒有對它進行設置的話,它的默認值就等于SHARED_LIBRARIES。LOCAL_MODULE_SUFFIX用來描述生成的模塊文件的后綴名。對于動態(tài)鏈接庫文件來說,如果我們沒有對它進行設置的話,它的默認值就等于TARGET_SHLIB_SUFFIX。即.so。上述兩個變量限定了生成的動態(tài)鏈接庫文件的完整文件名以及保存位置。接下來,build/core/shared_library.mk文件加載了另外一個文件build/core/dynamic_binary.mk文件,并且為變量linked_module指向的文件制定了一個依賴規(guī)則,這個依賴規(guī)則由函數(shù)transform-o-to-shared-lib來執(zhí)行。從函數(shù)transform-o-to-shared-lib就可以知道,它是根據(jù)一系列的中間編譯文件(object文件)以及依賴庫文件生成指定的動態(tài)鏈庫文件的,主要就是由變量all_objects和all_libraries所描述的文件?,F(xiàn)在,變量linked_module、all_objects和all_libraries所指向的文件是我們所要關心的。我們接著分析文件build/core/dynamic_binary.mk文件的加載過程,它的內(nèi)容如下所示:[plain]viewplaincopy在CODE上查看代碼片派生到我的代碼片......LOCAL_UNSTRIPPED_PATH:=$(strip$(LOCAL_UNSTRIPPED_PATH))ifeq($(LOCAL_UNSTRIPPED_PATH),)ifeq($(LOCAL_MODULE_PATH),)LOCAL_UNSTRIPPED_PATH:=$(TARGET_OUT_$(LOCAL_MODULE_CLASS)_UNSTRIPPED)else#WehavetofigureoutthecorrespondingunstrippedpathifLOCAL_MODULE_PATHiscustomized.LOCAL_UNSTRIPPED_PATH:=$(TARGET_OUT_UNSTRIPPED)/$(patsubst$(PRODUCT_OUT)/%,%,$(LOCAL_MODULE_PATH))endifendifLOCAL_MODULE_STEM:=$(strip$(LOCAL_MODULE_STEM))ifeq($(LOCAL_MODULE_STEM),)LOCAL_MODULE_STEM:=$(LOCAL_MODULE)endifLOCAL_INSTALLED_MODULE_STEM:=$(LOCAL_MODULE_STEM)$(LOCAL_MODULE_SUFFIX)LOCAL_BUILT_MODULE_STEM:=$(LOCAL_INSTALLED_MODULE_STEM)#base_rules.makedefines$(intermediates),butweneeditsvalue#beforeweincludebase_rules.Makeaguess,andverifythat#it'scorrectoncetherealvalueisdefined.guessed_intermediates:=$(calllocal-intermediates-dir)......linked_module:=$(guessed_intermediates)/LINKED/$(LOCAL_BUILT_MODULE_STEM)......LOCAL_INTERMEDIATE_TARGETS:=$(linked_module)###################################include$(BUILD_SYSTEM)/binary.mk###################################......#############################################################Compress###########################################################compress_input:=$(linked_module)ifeq($(strip$(LOCAL_COMPRESS_MODULE_SYMBOLS)),)LOCAL_COMPRESS_MODULE_SYMBOLS:=$(strip$(TARGET_COMPRESS_MODULE_SYMBOLS))endififeq($(LOCAL_COMPRESS_MODULE_SYMBOLS),true)$(errorSymbolcompressionnotyetsupported.)compress_output:=$(intermediates)/COMPRESSED-$(LOCAL_BUILT_MODULE_STEM)#TODO:writethereal$(STRIPPER)rule.#TODO:definearuletobuildTARGET_SYMBOL_FILTER_FILE,and#makeitdependonALL_ORIGINAL_DYNAMIC_BINARIES.$(compress_output):$(compress_input)$(TARGET_SYMBOL_FILTER_FILE)|$(ACP)@echo"targetCompressSymbols:$(PRIVATE_MODULE)($@)"$(copy-file-to-target)else#Spress_output:=$(compress_input)endif#############################################################Storeacopywithsymbolsforsymbolicdebugging###########################################################symbolic_input:=$(compress_output)symbolic_output:=$(LOCAL_UNSTRIPPED_PATH)/$(LOCAL_BUILT_MODULE_STEM)$(symbolic_output):$(mbolic_input)|$(ACP)@echo"targetSymbolic:$(PRIVATE_MODULE)($@)"$(copy-file-to-target)#############################################################Strip###########################################################strip_input:=$(symbolic_output)strip_output:=$(LOCAL_BUILT_MODULE)ifeq($(strip$(LOCAL_STRIP_MODULE)),)LOCAL_STRIP_MODULE:=$(strip$(TARGET_STRIP_MODULE))endififeq($(LOCAL_STRIP_MODULE),true)#Stripthebinary$(strip_output):$(strip_input)|$(TARGET_STRIP)$(transform-to-stripped)else......endif#LOCAL_STRIP_MODULELOCAL_UNSTRIPPED_PATH描述的是帶符號的模塊文件的輸出目錄。如果我們沒有設置它,并且也沒有設置變量LOCAL_MODULE_PATH的值,那么它的默認值就會與當前要編譯的產(chǎn)品以及當前要編譯的模塊文件類型有關。例如,如果我們在執(zhí)行l(wèi)unch命令時,選擇的是目標產(chǎn)品是模擬器,并且當前要編譯的是動態(tài)鏈接庫文件,那么得到的LOCAL_UNSTRIPPED_PATH值就為TARGET_OUT_$(LOCAL_MODULE_CLASS)_UNSTRIPPED。將$(LOCAL_MODULE_CLASS)替換為SHARED_LIBRARIES,就得到LOCAL_UNSTRIPPED_PATH的值為TARGET_OUT_SHARED_LIBRARIES_UNSTRIPPED,它值就等于out/target/product/generic/symbols/system/lib。也就是說,我們在為模擬器編譯動態(tài)鏈接庫模塊時,生成的帶符號文件都保存在目錄out/target/product/generic/symbols/system/lib中。如果我們沒有設置LOCAL_MODULE_STEM的值的話,那么它的默認值就等在我們在Android.mk文件中設置的LOCAL_MODULE的值。在我們的例子中,LOCAL_MODULE_STEM的值就等于LOCAL_MODULE的值,即libdis。LOCAL_INSTALLED_MODULE_STEM和LOCAL_BUILT_MODULE_STEM的值等于LOCAL_MODULE_STEM的值再加上后綴名LOCAL_MODULE_SUFFIX。在我們的例子中,LOCAL_INSTALLED_MODULE_STEM和LOCAL_BUILT_MODULE_STEM的值就等于libdis.so。這里調(diào)用函數(shù)local-intermediates-dir得到的是動態(tài)鏈接文件的中間輸出目錄,默認就是out/target/product/generic/obj/SHARED_LIBRARIES/libdis_intermediates了,因此,我們就可以得到變量linked_module的值為out/target/product/generic/obj/SHARED_LIBRARIES/libdis_intermediates/LINKED/libdis.so,這是編譯過程要生成的文件之一。LOCAL_INTERMEDIATE_TARGETS的值被設置為linked_module的值,接下來在加載build/core/binary.mk文件時需要用到。接下來會根據(jù)out/target/product/generic/obj/SHARED_LIBRARIES/libdis_intermediates/LINKED/libdis.so文件生成另外三個文件:1.生成帶符號壓縮的模塊文件,前提是LOCAL_COMPRESS_MODULE_SYMBOLS的值等于true。輸入是compress_input,即linked_module,輸出是compress_output,即$(intermediates)/COMPRESSED-$(LOCAL_BUILT_MODULE_STEM)。注意。目前還不支持此類型的模塊文件。因此,當變量LOCAL_COMPRESS_MODULE_SYMBOLS的值等于true時,就會報錯。2.拷貝一份帶符號的模塊文件到LOCAL_UNSTRIPPED_PATH描述的目錄中去,即out/target/product/generic/symbols/system/lib目錄。在我們這個情景中,得到的文件即為out/target/product/generic/symbols/system/lib/libdis.so。3.生成不帶符號的模塊文件,前提是LOCAL_STRIP_MODULE的值等于true。輸入是前面拷貝到out/target/product/generic/symbols/system/lib目錄的文件,輸出由變量LOCAL_BUILT_MODULE指定。變量LOCAL_BUILT_MODULE的值是在加載文件build/core/binary.mk的過程中指定的。到目前為止,我們就解決前面提到的文件out/target/product/generic/obj/SHARED_LIBRARIES/libdis_intermediates/LINKED/libdis.so和out/target/product/generic/symbols/system/lib/libdis.so的生成過程,還剩下out/target/product/generic/obj/lib/libdis.so和out/target/product/generic/system/lib/libdis.so文件的生成過程未搞清楚。這就需要繼續(xù)分析文件build/core/binary.mk的加載過程。文件build/core/binary.mk的核心內(nèi)容如下所示:[plain]viewplaincopy在CODE上查看代碼片派生到我的代碼片ifdefLOCAL_SDK_VERSION#GetthelistofINSTALLEDlibrariesasmodulenames.#WecannotcomputethefullpathoftheLOCAL_SHARED_LIBRARIESfor#theymaycusomizetheirinstallpathwithLOCAL_MODULE_PATHinstalled_shared_library_module_names:=\$(LOCAL_SHARED_LIBRARIES)elseinstalled_shared_library_module_names:=\$(LOCAL_SYSTEM_SHARED_LIBRARIES)$(LOCAL_SHARED_LIBRARIES)endif#TherealdependencywillbeaddedafterallAndroid.mksareloadedandtheinstallpaths#ofthesharedlibrariesaredetermined.LOCAL_REQUIRED_MODULES+=$(installed_shared_library_module_names)#######################################include$(BUILD_SYSTEM)/base_rules.mk#######################################......#############################################################C++:Compile.cppfilesto.o.############################################################wealsodothisonhostmodules,eventhough#it'snotreallyarm,becausetherearefilesthatareshared.cpp_arm_sources:=$(patsubst%$(LOCAL_CPP_EXTENSION).arm,%$(LOCAL_CPP_EXTENSION),$(filter%$(LOCAL_CPP_EXTENSION).arm,$(LOCAL_SRC_FILES)))cpp_arm_objects:=$(addprefix$(intermediates)/,$(cpp_arm_sources:$(LOCAL_CPP_EXTENSION)=.o))cpp_normal_sources:=$(filter%$(LOCAL_CPP_EXTENSION),$(LOCAL_SRC_FILES))cpp_normal_objects:=$(addprefix$(intermediates)/,$(cpp_normal_sources:$(LOCAL_CPP_EXTENSION)=.o))$(cpp_arm_objects):PRIVATE_ARM_MODE:=$(arm_objects_mode)$(cpp_arm_objects):PRIVATE_ARM_CFLAGS:=$(arm_objects_cflags)$(cpp_normal_objects):PRIVATE_ARM_MODE:=$(normal_objects_mode)$(cpp_normal_objects):PRIVATE_ARM_CFLAGS:=$(normal_objects_cflags)cpp_objects:=$(cpp_arm_objects)$(cpp_normal_objects)ifneq($(strip$(cpp_objects)),)$(cpp_objects):$(intermediates)/%.o:\$(TOPDIR)$(LOCAL_PATH)/%$(LOCAL_CPP_EXTENSION)\$(yacc_cpps)$(proto_generated_headers)$(my_compiler_dependencies)\$(LOCAL_ADDITIONAL_DEPENDENCIES)$(transform-$(PRIVATE_HOST)cpp-to-o)-include$(cpp_objects:%.o=%.P)endif......#############################################################C:Compile.cfilesto.o.###########################################################c_arm_sources:=$(patsubst%.c.arm,%.c,$(filter%.c.arm,$(LOCAL_SRC_FILES)))c_arm_objects:=$(addprefix$(intermediates)/,$(c_arm_sources:.c=.o))c_normal_sources:=$(filter%.c,$(LOCAL_SRC_FILES))c_normal_objects:=$(addprefix$(intermediates)/,$(c_normal_sources:.c=.o))$(c_arm_objects):PRIVATE_ARM_MODE:=$(arm_objects_mode)$(c_arm_objects):PRIVATE_ARM_CFLAGS:=$(arm_objects_cflags)$(c_normal_objects):PRIVATE_ARM_MODE:=$(normal_objects_mode)$(c_normal_objects):PRIVATE_ARM_CFLAGS:=$(normal_objects_cflags)c_objects:=$(c_arm_objects)$(c_normal_objects)ifneq($(strip$(c_objects)),)$(c_objects):$(intermediates)/%.o:$(TOPDIR)$(LOCAL_PATH)/%.c$(yacc_cpps)$(proto_generated_headers)\$(my_compiler_dependencies)$(LOCAL_ADDITIONAL_DEPENDENCIES)$(transform-$(PRIVATE_HOST)c-to-o)-include$(c_objects:%.o=%.P)endif......#somerulesdependonasm_objectsbeingfirst.Ifyourcodedependson#beingfirst,it'sreasonabletorequireittobeassemblyall_objects:=\$(asm_objects)\$(cpp_objects)\$(gen_cpp_objects)\$(gen_asm_objects)\$(c_objects)\$(gen_c_objects)\$(objc_objects)\$(yacc_objects)\$(lex_objects)\$(proto_generated_objects)\$(addprefix$(TOPDIR

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責。
  • 6. 下載文件中如有侵權(quán)或不適當內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論