蘇州培訓(xùn)網(wǎng) > 蘇州JAVA培訓(xùn)機(jī)構(gòu) > 蘇州其然軟件開發(fā)培訓(xùn)
首頁(yè) 培訓(xùn)網(wǎng) 最新資訊 熱門問(wèn)答

蘇州其然軟件開發(fā)培訓(xùn)

13013833891 免費(fèi)試聽(tīng)

您當(dāng)前的位置: 蘇州IT認(rèn)證培訓(xùn) > 蘇州JAVA培訓(xùn) > 太倉(cāng)高級(jí)java前端培訓(xùn)班

太倉(cāng)高級(jí)java前端培訓(xùn)班_JAVA培訓(xùn)

¥詳詢

班制:周末班

蘇州其然軟件開發(fā)
上課(咨詢)地址:蘇州市昆山市震川西路111號(hào)名仕大廈
報(bào)名咨詢 預(yù)約試聽(tīng)
課程介紹
太倉(cāng)高級(jí)java前端培訓(xùn)班
其然IT 教育師資

任小龍(Will、龍17)高級(jí)講師

EasyJF開源團(tuán)隊(duì)成員,技術(shù)經(jīng)理,高級(jí)講師。 

擅長(zhǎng)技術(shù):JavaSE、Java Web、Spring、Hibernate、MyBatis、Spring MVC 、Struts2、Struts1、 WebService、Lucene、Android等開源技術(shù);以及Oracle、MySQL等數(shù)據(jù)庫(kù)技術(shù)。

龍老師實(shí)戰(zhàn)經(jīng)驗(yàn)豐富,熱衷探索新技術(shù),擁有多年的Java開發(fā)和培訓(xùn)經(jīng)驗(yàn), 授課富有激情又通俗易懂,知識(shí)點(diǎn)分析深入,舉例貼近生活不乏幽默生動(dòng),注重引導(dǎo)學(xué)生思維。

講課風(fēng)格:課堂幽默生動(dòng),思維行云流水,授課水到渠成。

學(xué)生點(diǎn)贊:龍哥的視頻,蒼老師都喜歡。 

太倉(cāng)高級(jí)java前端培訓(xùn)班

java入門要注意什么

太倉(cāng)高級(jí)java前端培訓(xùn)班

學(xué)習(xí)java就像是一個(gè)種花的過(guò)程,不斷地為其施肥澆水,它才會(huì)茁壯成長(zhǎng)。 而我們學(xué)習(xí)java,就要不斷的充實(shí)自己、提升自己,才能獲得更多機(jī)會(huì)。很多開始學(xué)習(xí)java編程的小白,經(jīng)常就會(huì)被概念、定義什么的搞糊涂。當(dāng)分類 、對(duì)象、接口、構(gòu)造函數(shù)等等各種專業(yè)名詞出現(xiàn)的時(shí)候,你一定是腦子里好像一片空白,根本就搞不懂這些字眼的意思和關(guān)系,而且,這種情況下,很 容易導(dǎo)致你喪失自信心,開始逃避、拒絕,這些小白經(jīng)常遇到的情況在我剛接觸java的時(shí)候也遇見(jiàn)了,但是好在我足夠幸運(yùn),遇見(jiàn)了誠(chéng)筑說(shuō)。我現(xiàn)在已 經(jīng)是公司的項(xiàng)目經(jīng)理了,今天,我為大家來(lái)總結(jié)了一些經(jīng)驗(yàn)和建議,希望能夠幫助到大家。

一點(diǎn):熟練基本的j2seAPI

除去java語(yǔ)言本身的語(yǔ)法之外呢,要懂得并且熟練j2seAPI的API也是非常有 必要的,在這里,就建議大家首先去掌握字符串的處理、異常的處理、容器、輸入輸出、線程等,這些相對(duì)來(lái)說(shuō)較為重要的。還有就是API的內(nèi)容是非 常龐大的,關(guān)于API,一定要懂得查詢API的文件說(shuō)明,在了解了其作用用途或者目的才能夠進(jìn)行相對(duì)于的程序。

二點(diǎn):穩(wěn)固java的語(yǔ)法基礎(chǔ)

學(xué)習(xí)java一定要學(xué)會(huì)使用java的程序語(yǔ)言,用來(lái)編寫程序,但是學(xué)習(xí)程序語(yǔ) 言就要熟悉語(yǔ)法是怎么使用的。程序語(yǔ)言其實(shí)也是一種語(yǔ)言,不過(guò)跟人類的語(yǔ)言不同,這種語(yǔ)言是要和計(jì)算機(jī)溝通交流,那怎么做才能熟悉這種語(yǔ)言呢 ,我給出的建議是多看別人寫的程序,了解人家是怎么用java來(lái)解決問(wèn)題的。然后再找類似的程序去練習(xí)了,這樣就能夠從實(shí)際操作中檢驗(yàn)自己是否真 的知道該怎么去解決問(wèn)題了。

三點(diǎn):加入貼吧論壇多參與討論

根據(jù)我當(dāng)時(shí)的經(jīng)驗(yàn),在大家學(xué)習(xí)的過(guò)程中,如果有人可以參與話題,共同討 論的話,會(huì)加快你學(xué)習(xí)的速度。所以大家可以和我一樣,找一個(gè)技術(shù)討論的地方,貼吧啊,論壇啊都可以,在這里進(jìn)行討論,畢竟大家有著共同的目標(biāo) 和理想,有著共同的話題可聊,這樣的話,又大大節(jié)省了學(xué)習(xí)的時(shí)間。

學(xué)完基本的java語(yǔ)法呢,現(xiàn)在就該用java來(lái)進(jìn)行實(shí)際的編程了,假如你需要 編寫窗口程序,那就學(xué)Swing窗口設(shè)計(jì);假如你要編寫數(shù)據(jù)庫(kù)什么的,那就學(xué)JDBC等等。

JAVA 分布式大綱

太倉(cāng)高級(jí)java前端培訓(xùn)班

一階段 java基礎(chǔ),我們將學(xué)習(xí)變量,基本數(shù)據(jù)類型,進(jìn)制,轉(zhuǎn)義字符,運(yùn) 算符,分支語(yǔ)句和循環(huán)語(yǔ)句等,以達(dá)到訓(xùn)練基礎(chǔ)語(yǔ)法和邏輯能力的目的。還有對(duì)數(shù)組、面向?qū)ο蠛彤惓L幚淼取?/span>

二階段 javaWeb,主要是學(xué)習(xí)Web前端開發(fā)基礎(chǔ)和框架、Servlet和JSP在Web 后端的應(yīng)用、Web后端開發(fā)相關(guān)專題、MVC和分層架構(gòu)以及項(xiàng)目開發(fā)流程及CASE工具的使用等。

三階段 java框架,像框架整合開發(fā)(SSH/SSS)、RESTful架構(gòu)和移動(dòng)端接口 設(shè)計(jì)、第三方接口和在線支付功能、網(wǎng)站安全和Spring Security應(yīng)用實(shí)戰(zhàn)、復(fù)雜用戶交互處理和Spring Web Flow的應(yīng)用、MyBatis的應(yīng)用和SSM整合等 技術(shù)點(diǎn)都是需要你掌握的。

四階段 java 云數(shù)據(jù),億級(jí)并發(fā)架構(gòu)演進(jìn)、Linux基礎(chǔ)、搭建tomcat環(huán)境以 及大數(shù)據(jù)開發(fā)云計(jì)算等高級(jí)Java教程,是Java技術(shù)的高端知識(shí)。其中穿插項(xiàng)目實(shí)戰(zhàn)演練,企業(yè)真實(shí)項(xiàng)目供學(xué)員應(yīng)用學(xué)習(xí),進(jìn)行知識(shí)體系的“二次學(xué)習(xí)” 。

Android源代碼編譯命令m/mm/mmm/make分析


>

在前文中,我們分析了Android編譯環(huán)境的初始化過(guò)程。Android編譯環(huán)境初始化完成后,我們就可以用m/mm/mmm/make命令編譯源代碼了。當(dāng)然,這要求每一個(gè)模塊都有一個(gè)Android.mk文件。Android.mk實(shí)際上是一個(gè)Makefile腳本,用來(lái)描述模塊編譯信息。Android編譯系統(tǒng)**整合Android.mk文件完成編譯過(guò)程。本文就對(duì)Android源代碼的編譯過(guò)程進(jìn)行詳細(xì)分析。

從前面Android編譯系統(tǒng)環(huán)境初始化過(guò)程分析這篇文章可以知道,lunch命令其實(shí)是定義在build/envsetup.sh文件中的函數(shù)lunch提供的。與lunch命令一樣,m、mm和mmm命令也分別是由定義在build/envsetup.sh文件中的函數(shù)m、mm和mmm提供的,而這三個(gè)函數(shù)又都是**make命令來(lái)對(duì)源代碼進(jìn)行編譯的。事實(shí)上,命令m就是對(duì)make命令的簡(jiǎn)單封裝,并且是用來(lái)對(duì)整個(gè)Android源代碼進(jìn)行編譯,而命令mm和mmm都是**make命令來(lái)對(duì)Android源碼中的指定模塊進(jìn)行編譯。接下來(lái)我們就先分別介紹一下函數(shù)m、mm和mmm的實(shí)現(xiàn),然后進(jìn)一步分析它們是如何**make命令來(lái)編譯代碼的。

函數(shù)m的實(shí)現(xiàn)如下所示:

function m() { T=$(gettop) if [ "$T" ]; then make -C $T $@ else echo "Couldn t locate the top of the tree. Try setting ." fi }

函數(shù)m調(diào)用函數(shù)gettop得到的是Android源代碼根目錄T。在執(zhí)行make命令的時(shí)候,先**-C選項(xiàng)指定工作目錄為T,即Android源代碼根目錄,接著又將執(zhí)行命令m指定的參數(shù)$@作為命令make的參數(shù)。從這里就可以看出,命令m實(shí)際上就是對(duì)命令make的簡(jiǎn)單封裝。

函數(shù)mm的實(shí)現(xiàn)如下所示:

function mm() { # If we re sitting in the root of the build tree, just do a # normal make. if [ -f build/core/envsetup.mk -a -f Makefile ]; then make $@ else # Find the closest Android.mk file. T=$(gettop) local M=$(findmakefile) # Remove the path to top as the makefilepath needs to be relative local M=`echo $M|sed s: $T /:: ` if [ ! "$T" ]; then echo "Couldn t locate the top of the tree. Try setting ." elif [ ! "$M" ]; then echo "Couldn t locate a makefile from the current directory." else ONE_SHOT_MAKEFILE=$M make -C $T all_modules $@ fi fi }

函數(shù)mm首先是判斷當(dāng)前目錄是否就是Android源碼根目錄,即當(dāng)前目錄下是否存在一個(gè)build/core/envsetup.mk文件和一個(gè)Makefile文件。如果是的話,就將命令mm當(dāng)作是一個(gè)普通的make命令來(lái)執(zhí)行。否則的話,就調(diào)用函數(shù)findmakefile從當(dāng)前目錄開始一直往上尋找是否存在一個(gè)Android.mk文件。如果在尋找的過(guò)程中,發(fā)現(xiàn)了一個(gè)Android.mk文件,那么就獲得它的絕對(duì)路徑,并且停止上述尋找過(guò)程。

由于接下來(lái)執(zhí)行make命令時(shí),我們需要指定的是要編譯的Android.mk文件的相對(duì)于Android源碼根目錄路徑,因此函數(shù)mm需要將剛才找到的Android.mk絕對(duì)文件路徑M中與Android源碼根目錄T相同的那部分路徑去掉。這是**sed命令來(lái)實(shí)現(xiàn)的,也就是將字符串M前面與字符串T相同的子串刪掉。

**后,將找到的Android.mk文件的相對(duì)路徑設(shè)置給環(huán)境變量ONE_SHOT_MAKE,表示接下來(lái)要對(duì)它進(jìn)行編譯。另外,函數(shù)mm還將make命令目標(biāo)設(shè)置為all_modules。這是什么意思呢?我們知道,一個(gè)Android.mk文件同時(shí)可以定義多個(gè)模塊,因此,all_modules就表示要對(duì)前面指定的Android.mk文件中定義的所有模塊進(jìn)行編譯。

函數(shù)mmm的實(shí)現(xiàn)如下所示:

function mmm() { T=$(gettop) if [ "$T" ]; then local MAKEFILE= local MODULES= local ARGS= local DIR TO_CHOP local DASH_ARGS=$(echo "$@" | awk -v RS=" " -v ORS=" " /^-.*$/ ) local DIRS=$(echo "$@" | awk -v RS=" " -v ORS=" " /^[^-].*$/ ) for DIR in $DIRS ; do MODULES=`echo $DIR | sed -n -e s/.*:.?$/\1/p | sed s/,/ / ` if [ "$MODULES" = "" ]; then MODULES=all_modules fi DIR=`echo $DIR | sed -e s/:.*// -e s:/$:: ` if [ -f $DIR/Android.mk ]; then TO_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" = "" ] ; then MFILE=$DIR/Android.mk else MFILE=$MFILE/$DIR/Android.mk fi MAKEFILE="$MAKEFILE $MFILE" else if [ "$DIR" = snod ]; then ARGS="$ARGS snod" elif [ "$DIR" = showcommands ]; then ARGS="$ARGS showcommands" elif [ "$DIR" = dist ]; then ARGS="$ARGS dist" elif [ "$DIR" = incrementaljavac ]; then ARGS="$ARGS incrementaljavac" else echo "No Android.mk in $DIR." return 1 fi fi done ONE_SHOT_MAKEFILE="$MAKEFILE" make -C $T $DASH_ARGS $MODULES $ARGS else echo "Couldn t locate the top of the tree. Try setting ." fi }

函數(shù)mmm的實(shí)現(xiàn)就稍微復(fù)雜一點(diǎn),我們?cè)敿?xì)解釋一下。

首先,命令mmm可以這樣執(zhí)行:

$ mmm <dir-1> <dir-2> ... <dir-N>[:module-1,module-2,...,module-M]

其中,dir-1、dir-2、dir-N都是包含有Android.mk文件的目錄。在**后一個(gè)目錄dir-N的后面可以帶一個(gè)冒號(hào),冒號(hào)后面可以**逗號(hào)分隔一系列的模塊名稱module-1、module-2和module-M,用來(lái)表示要編譯前面指定的Android.mk中的哪些模塊。

知道了命令mmm的使用方法之后 ,我們就可以分析函數(shù)mmm的執(zhí)行邏輯了: 1. 調(diào)用函數(shù)gettop獲得Android源碼根目錄。 2. **命令awk將執(zhí)行命令mmm時(shí)指定的選項(xiàng)參數(shù)提取出來(lái),也就是將以橫線“-”開頭的字符串提取出來(lái),并且保存在變量DASH_ARGS中。 3. **命令awk將執(zhí)行命令mmm時(shí)指定的非選項(xiàng)參數(shù)提取出來(lái),也就是將非以橫線“-”開頭的字符串提取出來(lái),并且保存在變量DIRS中。這里得到的實(shí)際上就是跟在命令mmm后面的字符串“<dir-1> <dir-2> ... <dir-N>[:module-1,module-2,...,module-M]”。 4. 變量DIRS保存的字符串可以看成是一系以空格分隔的子字符串,因此,就可以**一個(gè)for循環(huán)來(lái)對(duì)這些子字府串進(jìn)行遍歷。每一個(gè)子字符串DIR描述的都是一個(gè)包含有Android.mk文件的目錄。對(duì)每一個(gè)目錄DIR執(zhí)行以下操作: 4.1 由于目錄DIR后面可能會(huì)**冒號(hào)指定有模塊名稱,因此就先**兩個(gè)sed命令來(lái)獲得這些模塊名稱。**個(gè)sed命令獲得的是一系列以逗號(hào)分隔的模塊名稱列表,第二個(gè)sed命令用來(lái)將前面獲得的以逗號(hào)分隔的模塊名稱列表轉(zhuǎn)化為以空格分隔的模塊名稱列表。**后,獲得的以空格分隔的模塊名稱列表保存在變量MODULES中。由于目錄DIR后面也可能不指定有模塊名稱,因此前面得到的變量MODULES的值就會(huì)為空。在這種情況下,需要將變量MODULES的值設(shè)置為“all_modules”,表示要編譯的是所有模塊。 4.2 **兩個(gè)sed命令獲得真正的目錄DIR。**個(gè)sed命令將原來(lái)DIR字符串后面的冒號(hào)以及冒號(hào)后面的模塊列表字符串刪掉。第二個(gè)sed命令將執(zhí)行前面一個(gè)sed命令獲得的目錄后面的"/"斜線去掉,**后就得到一個(gè)末尾不帶有斜線“/”的路徑,并且保存在變量DIR中。 4.3 如果變量DIR描述的是一個(gè)真正的路徑,也就是在該路徑下存在一個(gè)Android.mk文件,那么就進(jìn)行以下處理: 4.3.1 統(tǒng)計(jì)Android源碼根目錄T包含的字符數(shù),并且將這個(gè)字符數(shù)加1,得到的值保存在變量TO_CHOP中。 4.3.2 **執(zhí)行/bin/pwd命令獲得當(dāng)前執(zhí)行命令mmm的目錄START。 4.3.3 **cut命令獲得當(dāng)前目錄START相對(duì)于Android源碼根目錄T的路徑,并且保存在變量MFILE中。 4.3.4 如果變量MFILE的值等于空,就表明是在Android源碼根目錄T中執(zhí)行mmm命令,這時(shí)候就表明變量DIR描述的就是相對(duì)Android源碼根目錄T的一個(gè)目錄,這時(shí)候指定的Android.mk文件相對(duì)于Android源碼根目錄T的路徑就為$DIR/Android.mk。 4.3.5 如果變量MFILE的值不等于空,就表明是在Android源碼根目錄T的某一個(gè)子目錄中執(zhí)行mmm命令,這時(shí)候$MFILE/$DIR/Android.mk表示的Android.mk文件路徑才是相對(duì)于Android源碼根目錄T的。 4.3.6 將獲得的Android.mk路徑MFILE附加在變量MAKEFILE描述的字符串的后面,并且以空格分隔。 4.4 如果變量DIR描述的不是一個(gè)真正的路徑,并且它的值等于"snod"、"showcomands"、“dist”或者“incrementaljavac”,那么它描述的其實(shí)是make修飾命令。這四個(gè)修飾命令的含義分別如下所示: 4.4.1 snod是“systemimage with no dependencies”的意思,表示忽略依賴性地重新打包system.img。 4.4.2 showcommands表示顯示編譯過(guò)程中執(zhí)行的命令。 4.4.3 dist表示將編譯后產(chǎn)生的發(fā)布文件拷貝到out/dist目錄中。 4.4.4 incrementaljavac表示對(duì)Java源文件采用增量式編譯,也就是如果一個(gè)Java文件如果沒(méi)有修改過(guò),那么就不要重新生成對(duì)應(yīng)的class文件。 5. 上面的for循環(huán)執(zhí)行完畢,變量MAKEFILE保存的是要編譯的Android.mk文件列表,它們都是相對(duì)于Android源碼根目錄的路徑,變量DASH_ARGS保存的是原來(lái)執(zhí)行mmm命令時(shí)帶的選項(xiàng)參數(shù),變量MODULES保存的是指定要編譯的模塊名稱,變量ARGS保存的是修飾命令。其中,變量MAKEFILE的內(nèi)容**環(huán)境變量ONE_SHOT_MAKEFILE傳遞給make命令,而其余變量都是**參數(shù)的形式傳遞給make命令,并且變量MODULES作為make命令的目標(biāo)。 明白了函數(shù)m、mm和mmm的實(shí)現(xiàn)之后,我們就可以知道: 1. mm和mmm命令是類似的,它們都是用來(lái)編譯某些模塊。 2. m命令用來(lái)編譯所有模塊。

如果我們理解了mm或者mmm命令的編譯過(guò)程,那么自然也會(huì)明白m命令的編譯過(guò)程,因?yàn)樗心K的編譯過(guò)程就等于把每一個(gè)模塊的編譯都編譯出來(lái),因此,接下來(lái)我們就選擇具有代表性的、常用的編譯命令mmm來(lái)分析Android源碼的編譯過(guò)程,如圖1所示:


圖1 mmm命令的編譯過(guò)程

函數(shù)mmm在Android源碼根目錄執(zhí)行make命令的時(shí)候,沒(méi)有**-f指定Makefile文件,因此默認(rèn)就使用Android源碼根目錄下的Makefile文件,它的內(nèi)容如下所示:

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

它僅僅是將build/core/main.mk文件加載進(jìn)來(lái)。build/core/main.mk是Android編譯系統(tǒng)的入口文件,它**加載其它的mk文件來(lái)對(duì)Android源碼中的各個(gè)模塊進(jìn)行編譯,以及將編譯出來(lái)的文件打包成各種鏡像文件。以下就是build/core/main.mk文件的主要內(nèi)容:

...... # This is the default target. It must be the first declared target. .PHONY: droid DEFAULT_GOAL := droid $(DEFAULT_GOAL): ...... # Set up various standard variables based on configuration # and host information. include $(BUILD_SYSTEM)/config.mk ...... # Bring in standard build system definitions. include $(BUILD_SYSTEM)/definitions.mk ...... # These targets are going to delete stuff, don t bother including # the whole directory tree if that s all we re going to do ifeq ($(MAKECMDGOALS),clean) dont_bother := true endif ifeq ($(MAKECMDGOALS),clobber) dont_bother := true endif ifeq ($(MAKECMDGOALS),dataclean) dont_bother := true endif ifeq ($(MAKECMDGOALS),installclean) dont_bother := true endif # Bring in all modules that need to be built. ifneq ($(dont_bother),true) ...... ifneq ($(ONE_SHOT_MAKEFILE),) # We ve probably been invoked by the "mm" shell function # with a subdirectory s makefile. include $(ONE_SHOT_MAKEFILE) ...... else # ONE_SHOT_MAKEFILE # # 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 --prune=out --prune=.repo --prune=.git $(subdirs) Android.mk) include $(subdir_makefiles) endif # ONE_SHOT_MAKEFILE ...... # ------------------------------------------------------------------- # Define dependencies for modules that require other modules. # This can only happen now, after we ve read in all module makefiles. # # TODO: deal with the fact that a bare module name isn t # unambiguous enough. Maybe declare short targets like # APPS:Quake or HOST:SHARED_LIBRARIES:libutils. # BUG: the system image won t know to depend on modules that are # brought in as requirements of other modules. define add-required-deps $(1): $(2) endef $(foreach m,$(ALL_MODULES), \ $(eval r := $(ALL_MODULES.$(m).REQUIRED)) \ $(if $(r), \ $(eval r := $(call module-installed-files,$(r))) \ $(eval $(call add-required-deps,$(ALL_MODULES.$(m).INSTALLED),$(r))) \ ) \ ) ...... modules_to_install := $(sort \ $(ALL_DEFAULT_INSTALLED_MODULES) \ $(product_FILES) \ $(foreach tag,$(tags_to_install),$($(tag)_MODULES)) \ $(call get-tagged-modules, shell_$(TARGET_SHELL)) \ $(CUSTOM_MODULES) \ ) ...... # build/core/Makefile contains extra stuff that we don t want to pollute this # top-level makefile with. It expects that ALL_DEFAULT_INSTALLED_MODULES # contains everything that s built during the current make, but it also further # extends ALL_DEFAULT_INSTALLED_MODULES. ALL_DEFAULT_INSTALLED_MODULES := $(modules_to_install) include $(BUILD_SYSTEM)/Makefile modules_to_install := $(sort $(ALL_DEFAULT_INSTALLED_MODULES)) ALL_DEFAULT_INSTALLED_MODULES := endif # dont_bother ...... # ------------------------------------------------------------------- # This is used to to get the ordering right, you can also use these, # but they re considered undocumented, so don t complain if their # behavior changes. .PHONY: prebuilt prebuilt: $(ALL_PREBUILT) ...... # All the droid stuff, in directories .PHONY: files files: prebuilt \ $(modules_to_install) \ $(modules_to_check) \ $(INSTALLED_ANDROID_INFO_TXT_TARGET) ...... # Build files and then package it into the rom formats .PHONY: droidcore droidcore: files \ systemimage \ $(INSTALLED_BOOTIMAGE_TARGET) \ $(INSTALLED_RECOVERYIMAGE_TARGET) \ $(INSTALLED_USERDATAIMAGE_TARGET) \ $(INSTALLED_CACHEIMAGE_TARGET) \ $(INSTALLED_FILES_FILE) ...... # Dist for droid if droid is among the cmd goals, or no cmd goal is given. ifneq ($(filter droid,$(MAKECMDGOALS))$(filter ||,|$(filter-out $(INTERNAL_MODIFIER_TARGETS),$(MAKECMDGOALS))|),) ifneq ($(TARGET_BUILD_APPS),) # If this build is just for apps, only build apps and not the full system by default. ...... .PHONY: apps_only apps_only: $(unbundled_build_modules) droid: apps_only else # TARGET_BUILD_APPS ...... # Building a full system-- the default is to build droidcore droid: droidcore dist_files endif # TARGET_BUILD_APPS endif # droid in $(MAKECMDGOALS) ...... # phony target that include any targets in $(ALL_MODULES) .PHONY: all_modules all_modules: $(ALL_MODULES) ......

接下來(lái)我們就先對(duì)build/core/main.mk文件的核心邏輯進(jìn)行分析,然后再進(jìn)一步對(duì)其中涉及到的關(guān)鍵點(diǎn)進(jìn)行分析。

build/core/main.mk文件的執(zhí)行過(guò)程如下所示: 1. 定義默認(rèn)make目標(biāo)為droid。目標(biāo)droid根據(jù)不同的情形有不同的依賴關(guān)系。如果在初始化編譯環(huán)境時(shí),指定了TARGET_BUILD_APPS環(huán)境變量,那么就表示當(dāng)前只編譯特定的模塊,這些特定的模塊保存在變量unbundled_build_modules中,這時(shí)候目標(biāo)droid就透過(guò)另外一個(gè)偽目標(biāo)app_only依賴它們。如果在初始化編譯環(huán)境時(shí)沒(méi)有指定TARGET_BUILD_APPS環(huán)境變量,那么目標(biāo)droid就依賴于另外兩個(gè)文件droidcore和dist_files。droidcore是一個(gè)make偽目標(biāo),它依賴于各種預(yù)編譯文件,以及system.img、boot.img、recovery.img和userdata.img等鏡像文件。dist_files也是一個(gè)make偽目標(biāo),用來(lái)指定一些需要在編譯后拷貝到out/dist目錄的文件。也就是說(shuō),當(dāng)我們?cè)贏ndroid源碼目錄中執(zhí)行不帶目標(biāo)的make命令時(shí),默認(rèn)就會(huì)對(duì)目標(biāo)droid進(jìn)行編譯,也就是會(huì)將整個(gè)Android系統(tǒng)編譯出來(lái)。 2. 加載build/core/config.mk文件。從前面Android編譯系統(tǒng)環(huán)境初始化過(guò)程分析一文可以知道,在加載build/core/config.mk文件的過(guò)程中,會(huì)在執(zhí)行make命令的進(jìn)程中完成對(duì)Android編譯環(huán)境的初始化過(guò)程,也就是會(huì)指定好目標(biāo)設(shè)備以及編譯類型。 3. 加載build/croe/definitions.mk文件。該文件定義了很多在編譯過(guò)程中要用到的宏,相當(dāng)于就是定義了很多通用函數(shù),供編譯過(guò)程調(diào)用。 4. 如果在執(zhí)行make命令時(shí),指定的不是清理文件相關(guān)的目標(biāo),也就是不是clean、clobber、dataclean和installclean等目標(biāo),那么就會(huì)將變量dont_bother的值設(shè)置為true,表示接下來(lái)要執(zhí)行的是編譯命令。 5. 在變量dont_bother的值等于true的情況下,如果環(huán)境變量ONE_SHOT_MAKEFILE的值不等于空,也就是我們執(zhí)行的是mm或者mmm命令,那么就表示要編譯的是特定的模塊。這些指定要編譯的模塊的Android.mk文件路徑就保存在環(huán)境變量ONE_SHOT_MAKEFILE中,因此直接將這些Android,mk文件加載進(jìn)來(lái)就獲得相應(yīng)的編譯規(guī)則。另一方面,如果環(huán)境變量ONE_SHOT_MAKEFILE的值等于空,那么就說(shuō)明我們執(zhí)行的是m或者make命令,那么就表示要對(duì)Android源代碼中的所有模塊進(jìn)行編譯,這時(shí)候就**build/tools/findleaves.py腳本獲得Android源代碼工程下的所有Android.mk文件的路徑列表,并且將這些Android.mk文件加載進(jìn)行獲得相應(yīng)的編譯規(guī)則。 6. 上一步指定的Android.mk文件加載完成之后,變量ALL_MODULES就包含了所有要編譯的模塊的名稱,這些模塊名稱以空格來(lái)分隔形成成一個(gè)列表。 7. 生成模塊依賴規(guī)則。每一個(gè)模塊都可以**LOCAL_REQUIRED_MODULES來(lái)指定它所依賴的其它模塊,也就是說(shuō)當(dāng)一個(gè)模塊被安裝時(shí),它所依賴的其它模塊也同樣會(huì)被安裝。每一個(gè)模塊m依賴的所有模塊都會(huì)被保存在ALL_MODULES.$(m).REQUIRED變量中。對(duì)于每一個(gè)被依賴模塊r,我們需要獲得它的安裝文件,也就是**終生成的模塊文件的文件路徑,以便可以生成相應(yīng)的編譯規(guī)則。獲得一個(gè)模塊m的安裝文件是**調(diào)用函數(shù)module-installed-files來(lái)實(shí)現(xiàn)的,實(shí)質(zhì)上就是保存在$(ALL_MODULES.$(m).INSTALLED變量中。知道了一個(gè)模塊m的所依賴的模塊的安裝文件路徑之后,我們就可以**函數(shù)add-required-deps來(lái)指定它們之間的依賴關(guān)系了。注意,這里實(shí)際上指定的是模塊m的安裝文件與它所依賴的模塊r的安裝文件的依賴關(guān)系。 8. 將所有要安裝的模塊都保存在變量ALL_DEFAULT_INSTALLED_MODULES中,并且將build/core/Makefie文件加載進(jìn)來(lái)。 build/core/Makefie文件會(huì)根據(jù)要安裝的模塊產(chǎn)成system.img、boot.img和recovery.img等鏡像文件的生成規(guī)則。 9. 前面提到,當(dāng)執(zhí)行mm命令時(shí),make目標(biāo)指定為all_moudles。另外,當(dāng)執(zhí)行mmm命令時(shí),默認(rèn)的make目標(biāo)也指定為all_moudles。因此,我們需要指定目標(biāo)all_modules的編譯規(guī)則,實(shí)際上只要將它依賴于當(dāng)前要編譯的所有模塊就行了,也就是依賴于由變量ALL_MODULES所描述的模塊。 在上述過(guò)程中,**核心的就是第5步和第8步。由于本文只關(guān)心Android源碼的編譯過(guò)程,因此我們只分析第5步的執(zhí)行過(guò)程。在接下來(lái)一篇文章中分析Android鏡像文件的生成過(guò)程時(shí),我們?cè)俜治龅?步的執(zhí)行過(guò)程。

第5步實(shí)際上就是將指定模塊的Android.mk文件加載進(jìn)來(lái)。一個(gè)典型的Android.mk文件如下所示:

LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE_TAGS := optional LOCAL_MODULE := libdis LOCAL_SHARED_LIBRARIES := \ liblog \ libdl LOCAL_SRC_FILES := \ dispatcher.cpp \ ../common/common.cpp include $(BUILD_SHARED_LIBRARY)

以LOCAL開頭的變量都是屬于模塊局部變量,也就是說(shuō),一個(gè)模塊在開始編譯之前,必須要先對(duì)它們進(jìn)行清理,然后再進(jìn)行初始化。Android編譯系統(tǒng)定義了非常多的模塊局部變量,因此我們不可能手動(dòng)地一個(gè)一個(gè)清理,需要加載一個(gè)由變量CLEAR_VARS指定的Makefile腳本來(lái)幫我們自動(dòng)清理。變量CLEAR_VARS的值定義在build/core/config.mk文件,它的值等于build/core/clear_vars.mk。

Android.mk文件中還有一個(gè)重要的變量LOCAL_PATH,用來(lái)指定當(dāng)前正在編譯的模塊的目錄,我們可以**調(diào)用宏my-dir來(lái)獲得。宏my-dir定義在build/core/definitions.mk文件,它實(shí)際上就是將當(dāng)前正在加載的Android.mk文件路徑的目錄名提取出來(lái)。

Android.mk文件接下來(lái)就是**其它的LOCAL變量定義模塊名稱、源文件,以及所要依賴的各種庫(kù)文件等等。例如,在我們這個(gè)例子,模塊名稱定義為libdis,參與編譯的源文件為dispatcher.cpp和common.cpp、依賴的庫(kù)文件為liblog和libdl。

**后,Android文件**加載一個(gè)模板文件來(lái)告訴編譯系統(tǒng)它所要編譯的模塊的類型。例如,在我們這個(gè)例子中,就是**加載由變量BUILD_SHARED_LIBRARY指定的模板文件來(lái)告訴編譯系統(tǒng)我們要編譯的模塊是一個(gè)動(dòng)態(tài)鏈接庫(kù)。變量BUILD_SHARED_LIBRARY的值定義在build/core/config.mk文件,它的值等于build/core/shared_library.mk。

Android編譯系統(tǒng)定義了非常多的模板文件,每一個(gè)模板文件都對(duì)應(yīng)一種類型的模塊,例如除了我們上面的動(dòng)態(tài)鏈接庫(kù)模板文件之外,還有:

BUILD_PACKAGE:指向build/core/package.mk,用來(lái)編譯APK文件。

BUILD_JAVA_LIBRARY:指向build/core/java_library.mk,用來(lái)編譯Java庫(kù)文件。

BUILD_STATIC_JAVA_LIBRARY:指向build/core/tatic_java_library.mk,用來(lái)編譯Java靜態(tài)庫(kù)文件。

BUILD_STATIC_LIBRARY:指向build/core/static_library.mk,用來(lái)編譯靜態(tài)庫(kù)文件。也就是.a文件。

BUILD_EXECUTABLE:指向build/core/executable.mk,用來(lái)編譯可執(zhí)行文件。

BUILD_PREBUILT:指向build/core/prebuilt.mk。用來(lái)編譯已經(jīng)預(yù)編譯好的第三方庫(kù)文件,實(shí)際上是將這些預(yù)編譯好的第三方庫(kù)文件拷貝到合適的位置去,以便可以讓其它模塊引用。

不管編譯何種類型的模塊,都是主要完成以下的工作:

制定好相應(yīng)的依賴規(guī)則

調(diào)用合適的命令進(jìn)行編譯

為了簡(jiǎn)單起見(jiàn),接下來(lái)我們就以動(dòng)態(tài)鏈接庫(kù)(即.so文件)的編譯過(guò)程為例來(lái)說(shuō)明Android編譯命令mmm的執(zhí)行過(guò)程。

在分析動(dòng)態(tài)鏈接庫(kù)的編譯過(guò)程之前,我們首先看一看使用mmm命令來(lái)編譯上述的Android.mk文件時(shí)得到的輸出,如下所示:

target thumb C : libdis <= external/si/dispatcher/dispatcher.cpp target thumb C : libdis <= external/si/dispatcher/../common/common.cpp target SharedLib: libdis (out/target/product/generic/obj/SHARED_LIBRARIES/libdis_intermediates/LINKED/libdis.so) target Symbolic: libdis (out/target/product/generic/symbols/system/lib/libdis.so) target Strip: libdis (out/target/product/generic/obj/lib/libdis.so) Install: out/target/product/generic/system/lib/libdis.so

從這些輸出我們大體推斷出一些文件之間的依賴關(guān)系及其生成過(guò)程:

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文件,并且由它生成。

回憶前面的分析,我們提到,當(dāng)執(zhí)行mmm命令時(shí),默認(rèn)的make目標(biāo)是all_modules,并且它依賴于變量ALL_MODULES指向的文件或者目標(biāo),因此,我們可以繼續(xù)推斷出,變量ALL_MODULES指向的文件或者目標(biāo)一定會(huì)與文件out/target/product/generic/system/lib/libdis.so有依賴關(guān)系,這樣才能夠從make目標(biāo)all_modules開始鏈?zhǔn)降厣缮鲜鑫募?。在接下?lái)的分析中,我們就按照抓住上述文件的依賴關(guān)系進(jìn)行逆向分析。

從上面的分析可以知道,在編譯動(dòng)態(tài)鏈接庫(kù)文件的過(guò)程中,文件build/core/shared_library.mk會(huì)被加載,它的核心內(nèi)容如下所示:

...... ifeq ($(strip $(LOCAL_MODULE_CLASS)),) LOCAL_MODULE_CLASS := SHARED_LIBRARIES endif ifeq ($(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用來(lái)描述模塊文件的類型。對(duì)于動(dòng)態(tài)鏈接庫(kù)文件來(lái)說(shuō),如果我們沒(méi)有對(duì)它進(jìn)行設(shè)置的話,它的默認(rèn)值就等于SHARED_LIBRARIES。

LOCAL_MODULE_SUFFIX用來(lái)描述生成的模塊文件的后綴名。對(duì)于動(dòng)態(tài)鏈接庫(kù)文件來(lái)說(shuō),如果我們沒(méi)有對(duì)它進(jìn)行設(shè)置的話,它的默認(rèn)值就等于TARGET_SHLIB_SUFFIX。即.so。

上述兩個(gè)變量限定了生成的動(dòng)態(tài)鏈接庫(kù)文件的完整文件名以及保存位置。

接下來(lái),build/core/shared_library.mk文件加載了另外一個(gè)文件build/core/dynamic_binary.mk文件,并且為變量linked_module指向的文件制定了一個(gè)依賴規(guī)則,這個(gè)依賴規(guī)則由函數(shù)transform-o-to-shared-lib來(lái)執(zhí)行。從函數(shù)transform-o-to-shared-lib就可以知道,它是根據(jù)一系列的中間編譯文件(object文件)以及依賴庫(kù)文件生成指定的動(dòng)態(tài)鏈庫(kù)文件的,主要就是由變量all_objects和all_libraries所描述的文件。現(xiàn)在,變量linked_module、all_objects和all_libraries所指向的文件是我們所要關(guān)心的。

我們接著分析文件build/core/dynamic_binary.mk文件的加載過(guò)程,它的內(nèi)容如下所示:

...... 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 # We have to figure out the corresponding unstripped path if LOCAL_MODULE_PATH is customized. LOCAL_UNSTRIPPED_PATH := $(TARGET_OUT_UNSTRIPPED)/$(patsubst $(PRODUCT_OUT)/%,%,$(LOCAL_MODULE_PATH)) endif endif LOCAL_MODULE_STEM := $(strip $(LOCAL_MODULE_STEM)) ifeq ($(LOCAL_MODULE_STEM),) LOCAL_MODULE_STEM := $(LOCAL_MODULE) endif LOCAL_INSTALLED_MODULE_STEM := $(LOCAL_MODULE_STEM)$(LOCAL_MODULE_SUFFIX) LOCAL_BUILT_MODULE_STEM := $(LOCAL_INSTALLED_MODULE_STEM) # base_rules.make defines $(intermediates), but we need its value # before we include base_rules. Make a guess, and verify that # it s correct once the real value is defined. guessed_intermediates := $(call local-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)) endif ifeq ($(LOCAL_COMPRESS_MODULE_SYMBOLS),true) $(error Symbol compression not yet supported.) compress_output := $(intermediates)/COMPRESSED-$(LOCAL_BUILT_MODULE_STEM) #TODO: write the real $(STRIPPER) rule. #TODO: define a rule to build TARGET_SYMBOL_FILTER_FILE, and # make it depend on ALL_ORIGINAL_DYNAMIC_BINARIES. $(compress_output): $(compress_input) $(TARGET_SYMBOL_FILTER_FILE) | $(ACP) @echo "target Compress Symbols: $(PRIVATE_MODULE) ($@)" $(copy-file-to-target) else # Skip this step. compress_output := $(compress_input) endif ########################################################### ## Store a copy with symbols for symbolic debugging ########################################################### symbolic_input := $(compress_output) symbolic_output := $(LOCAL_UNSTRIPPED_PATH)/$(LOCAL_BUILT_MODULE_STEM) $(symbolic_output) : $(symbolic_input) | $(ACP) @echo "target Symbolic: $(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)) endif ifeq ($(LOCAL_STRIP_MODULE),true) # Strip the binary $(strip_output): $(strip_input) | $(TARGET_STRIP) $(transform-to-stripped) else ...... endif # LOCAL_STRIP_MODULE

LOCAL_UNSTRIPPED_PATH描述的是帶符號(hào)的模塊文件的輸出目錄。如果我們沒(méi)有設(shè)置它,并且也沒(méi)有設(shè)置變量LOCAL_MODULE_PATH的值,那么它的默認(rèn)值就會(huì)與當(dāng)前要編譯的產(chǎn)品以及當(dāng)前要編譯的模塊文件類型有關(guān)。例如,如果我們?cè)趫?zhí)行l(wèi)unch命令時(shí),選擇的是目標(biāo)產(chǎn)品是模擬器,并且當(dāng)前要編譯的是動(dòng)態(tài)鏈接庫(kù)文件,那么得到的LOCAL_UNSTRIPPED_PATH值就為TARGET_OUT_(LOCALMODULECLASS)UNSTRIPPED。將

體驗(yàn)課預(yù)約試聽(tīng)

倒計(jì)時(shí)

12:00:00

課程熱線:

13013833891
在線咨詢

客服在線時(shí)間:早上9點(diǎn)~下午6點(diǎn),其他時(shí)間請(qǐng)?jiān)诰€預(yù)約報(bào)名或留言,謝謝!

蘇州JAVA

免費(fèi)體驗(yàn)課開班倒計(jì)時(shí)

11: 41: 09

稍后會(huì)有專業(yè)老師給您回電,請(qǐng)保持電話暢通

咨詢電話:13013833891
推薦機(jī)構(gòu) 全國(guó)分站 更多課程

本周僅剩 個(gè)試聽(tīng)名額

請(qǐng)鍵入信息,稍后系統(tǒng)將會(huì)把領(lǐng)獎(jiǎng)短信發(fā)至您的手機(jī)

申請(qǐng)?jiān)嚶?tīng)名額

已有10254人申請(qǐng)免費(fèi)試聽(tīng)

01電話咨詢 | 13013833891

QQ:1413838287
加盟合作:0755-83654572