日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 运维知识 > Android >内容正文

Android

Android编译系统环境过程初始化分析【转】

發(fā)布時(shí)間:2023/12/31 Android 25 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Android编译系统环境过程初始化分析【转】 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

本文轉(zhuǎn)載自:http://blog.csdn.net/luoshengyang/article/details/18928789

?Android源代碼在編譯之前,要先對(duì)編譯環(huán)境進(jìn)行初始化,其中最主要就是指定編譯的類型和目標(biāo)設(shè)備的型號(hào)。Android的編譯類型主要有eng、userdebug和user三種,而支持的目標(biāo)設(shè)備型號(hào)則是不確定的,它們由當(dāng)前的源碼配置情況所決定。為了確定源碼支持的所有目標(biāo)設(shè)備型號(hào),Android編譯系統(tǒng)在初始化的過(guò)程中,需要在特定的目錄中加載特定的配置文件。接下來(lái)本文就對(duì)上述的初始化過(guò)程進(jìn)行詳細(xì)分析。

老羅的新浪微博:http://weibo.com/shengyangluo,歡迎關(guān)注!

《Android系統(tǒng)源代碼情景分析》一書正在進(jìn)擊的程序員網(wǎng)(http://0xcc0xcd.com)中連載,點(diǎn)擊進(jìn)入!

? ? ? ?對(duì)Android編譯環(huán)境進(jìn)行初始化很簡(jiǎn)單,分為兩步。第一步是打開一個(gè)終端,并且將build/envsetup.sh加載到該終端中:

?

[html]?view plaincopy
  • $?.?./build/envsetup.sh???
  • including?device/asus/grouper/vendorsetup.sh??
  • including?device/asus/tilapia/vendorsetup.sh??
  • including?device/generic/armv7-a-neon/vendorsetup.sh??
  • including?device/generic/armv7-a/vendorsetup.sh??
  • including?device/generic/mips/vendorsetup.sh??
  • including?device/generic/x86/vendorsetup.sh??
  • including?device/lge/mako/vendorsetup.sh??
  • including?device/samsung/maguro/vendorsetup.sh??
  • including?device/samsung/manta/vendorsetup.sh??
  • including?device/samsung/toroplus/vendorsetup.sh??
  • including?device/samsung/toro/vendorsetup.sh??
  • including?device/ti/panda/vendorsetup.sh??
  • including?sdk/bash_completion/adb.bash??
  • ????? 從命令的輸出可以知道,文件build/envsetup.sh在加載的過(guò)程中,又會(huì)在device目錄中尋找那些名稱為vendorsetup.sh的文件,并且也將它們加載到當(dāng)前終端來(lái)。另外,在sdk/bash_completion目錄下的adb.bash文件也會(huì)加載到當(dāng)前終端來(lái),它是用來(lái)實(shí)現(xiàn)adb命令的bash completion功能的。也就是說(shuō),加載了該文件之后,我們?cè)谶\(yùn)行adb相關(guān)的命令的時(shí)候,通過(guò)按tab鍵就可以幫助我們自動(dòng)完成命令的輸入。關(guān)于bash completion的知識(shí),可以參考官方文檔:?http://www.gnu.org/s/bash/manual/bash.html#Programmable-Completion。
    ??? ? 第二步是執(zhí)行命令lunch,如下所示:

    ?

    ?

    [html]?view plaincopy
  • $?lunch??
  • ??
  • You're?building?on?Linux??
  • ??
  • Lunch?menu...?pick?a?combo:??
  • ?????1.?full-eng??
  • ?????2.?full_x86-eng??
  • ?????3.?vbox_x86-eng??
  • ?????4.?full_mips-eng??
  • ?????5.?full_grouper-userdebug??
  • ?????6.?full_tilapia-userdebug??
  • ?????7.?mini_armv7a_neon-userdebug??
  • ?????8.?mini_armv7a-userdebug??
  • ?????9.?mini_mips-userdebug??
  • ?????10.?mini_x86-userdebug??
  • ?????11.?full_mako-userdebug??
  • ?????12.?full_maguro-userdebug??
  • ?????13.?full_manta-userdebug??
  • ?????14.?full_toroplus-userdebug??
  • ?????15.?full_toro-userdebug??
  • ?????16.?full_panda-userdebug??
  • ??
  • Which?would?you?like??[full-eng]???
  • ?????? 我們看到lunch命令輸出了一個(gè)Lunch菜單,該菜單列出了當(dāng)前Android源碼支持的所有設(shè)備型號(hào)及其編譯類型。例如,第一項(xiàng)“full-eng”表示的設(shè)備“full”即為模擬器,并且編譯類型為“eng”即為工程機(jī)。

    ?

    ?????? 當(dāng)我們選定了一個(gè)Lunch菜單項(xiàng)序號(hào)(1-16)之后,按回車鍵,就可以完成Android編譯環(huán)境的初始化過(guò)程。例如,我們選擇1,可以看到以下輸出:

    ?

    [html]?view plaincopy
  • Which?would?you?like??[full-eng]?1??
  • ??
  • ============================================??
  • PLATFORM_VERSION_CODENAME=REL??
  • PLATFORM_VERSION=4.2??
  • TARGET_PRODUCT=full??
  • TARGET_BUILD_VARIANT=eng??
  • TARGET_BUILD_TYPE=release??
  • TARGET_BUILD_APPS=??
  • TARGET_ARCH=arm??
  • TARGET_ARCH_VARIANT=armv7-a??
  • HOST_ARCH=x86??
  • HOST_OS=linux??
  • HOST_OS_EXTRA=Linux-3.8.0-31-generic-x86_64-with-Ubuntu-13.04-raring??
  • HOST_BUILD_TYPE=release??
  • BUILD_ID=JOP40C??
  • OUT_DIR=out??
  • ============================================??
  • ?????? 我們可以看到,lunch命令幫我們?cè)O(shè)置好了很多環(huán)境變量。通過(guò)設(shè)置這些環(huán)境變量,就配置好了Android編譯環(huán)境。

    ?

    ?????? 通過(guò)圖1我們就可以直觀地看到Android編譯環(huán)境初始化完成后,我們所獲得的東西:

    圖1 Android編譯環(huán)境初始化完成之后

    ? ? ? ?總體來(lái)說(shuō),Android編譯環(huán)境初始化完成之后,獲得了以下三樣?xùn)|西:

    ? ? ? ?1. 將vendor和device目錄下的vendorsetup.sh文件加載到了當(dāng)前終端;

    ? ? ? ?2. 新增了lunch、m、mm和mmm等命令;

    ? ? ? ?3. 通過(guò)執(zhí)行l(wèi)unch命令設(shè)置好了TARGET_PRODUCT、TARGET_BUILD_VARIANT、TARGET_BUILD_TYPE和TARGET_BUILD_APPS等環(huán)境變量。 ?

    ? ? ? ?接下來(lái)我們就主要分析build/envsetup.sh文件的加載過(guò)程以及l(fā)unch命令的執(zhí)行過(guò)程。

    ? ? ? ?一. 文件build/envsetup.sh的加載過(guò)程

    ? ? ? ?文件build/envsetup.sh是一個(gè)bash shell腳本,從它里面定義的函數(shù)hmm可以知道,它提供了lunch、m、mm和mmm等命令供我們初始化編譯環(huán)境或者編譯Android源碼。

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

    ?

    [plain]?view plaincopy
  • function?hmm()?{??
  • cat?<<EOF??
  • Invoke?".?build/envsetup.sh"?from?your?shell?to?add?the?following?functions?to?your?environment:??
  • -?lunch:???lunch?<product_name>-<build_variant>??
  • -?tapas:???tapas?[<App1>?<App2>?...]?[arm|x86|mips]?[eng|userdebug|user]??
  • -?croot:???Changes?directory?to?the?top?of?the?tree.??
  • -?m:???????Makes?from?the?top?of?the?tree.??
  • -?mm:??????Builds?all?of?the?modules?in?the?current?directory.??
  • -?mmm:?????Builds?all?of?the?modules?in?the?supplied?directories.??
  • -?cgrep:???Greps?on?all?local?C/C++?files.??
  • -?jgrep:???Greps?on?all?local?Java?files.??
  • -?resgrep:?Greps?on?all?local?res/*.xml?files.??
  • -?godir:???Go?to?the?directory?containing?a?file.??
  • ??
  • Look?at?the?source?to?view?more?functions.?The?complete?list?is:??
  • EOF??
  • ????T=$(gettop)??
  • ????local?A??
  • ????A=""??
  • ????for?i?in?`cat?$T/build/envsetup.sh?|?sed?-n?"/^function?/s/function?[a?z]?.*/\1/p"?|?sort`;?do??
  • ??????A="$A?$i"??
  • ????done??
  • ????echo?$A??
  • }??
  • ?????? 我們?cè)诋?dāng)前終端中執(zhí)行hmm命令即可以看到函數(shù)hmm的完整輸出。

    ?

    ?????? 函數(shù)hmm主要完成三個(gè)工作:

    ?????? 1. 調(diào)用另外一個(gè)函數(shù)gettop獲得Android源碼的根目錄T。?

    ?????? 2. 通過(guò)cat命令顯示一個(gè)Here Document,說(shuō)明$T/build/envsetup.sh文件加載到當(dāng)前終端后所提供的主要命令。

    ?????? 3. 通過(guò)sed命令解析$T/build/envsetup.sh文件,并且獲得在里面定義的所有函數(shù)的名稱,這些函數(shù)名稱就是$T/build/envsetup.sh文件加載到當(dāng)前終端后提供的所有命令。

    ?????? 注意,sed命令是一個(gè)強(qiáng)大的文本分析工具,它以行為單位為執(zhí)行文本替換、刪除、新增和選取等操作。函數(shù)hmm通過(guò)執(zhí)行以下的sed命令來(lái)獲得在$T/build/envsetup.sh文件定義的函數(shù)的名稱:

    ?

    [plain]?view plaincopy
  • sed?-n?"/^function?/s/function?[a?z]?.*/\1/p"??
  • ?????? 它表示對(duì)所有以“function ”開頭的行,如果緊接在“function ”后面的字符串僅由字母a-z和下橫線(_)組成,那么就將這個(gè)字符串提取出來(lái)。這正好就對(duì)應(yīng)于shell腳本里面函數(shù)的定義。

    ?

    ?????? 文件build/envsetup.sh除了定義一堆函數(shù)之外,還有一個(gè)重要的代碼段,如下所示:

    ?

    [plain]?view plaincopy
  • #?Execute?the?contents?of?any?vendorsetup.sh?files?we?can?find.??
  • for?f?in?`/bin/ls?vendor/*/vendorsetup.sh?vendor/*/*/vendorsetup.sh?device/*/*/vendorsetup.sh?2>?/dev/null`??
  • do??
  • ????echo?"including?$f"??
  • ????.?$f??
  • done??
  • unset?f??
  • ??????? 這個(gè)for循環(huán)遍歷vendor目錄下的一級(jí)子目錄和二級(jí)子目錄以及device目錄下的二級(jí)子目錄中的vendorsetup.sh文件,并且通過(guò)source命令(.)將它們加載當(dāng)前終端來(lái)。vendor和device相應(yīng)子目錄下的vendorsetup.sh文件的實(shí)現(xiàn)很簡(jiǎn)單,它們主要就是添加相應(yīng)的設(shè)備型號(hào)及其編譯類型支持到Lunch菜單中去。

    ??????? 例如,device/samsung/maguro目錄下的vendorsetup.sh文件的實(shí)現(xiàn)如下所示:

    ?

    [plain]?view plaincopy
  • add_lunch_combo?full_maguro-userdebug??
  • ??????? 它調(diào)用函數(shù)add_lunch_combo添加一個(gè)名稱為“full_maguro-userdebug”的菜單項(xiàng)到Lunch菜單去。

    ?

    ??????? 函數(shù)add_lunch_combo定義在build/envsetup.sh文件中,它的實(shí)現(xiàn)如下所示:

    ?

    [plain]?view plaincopy
  • function?add_lunch_combo()??
  • {??
  • ????local?new_combo=$1??
  • ????local?c??
  • ????for?c?in?${LUNCH_MENU_CHOICES[@]}?;?do??
  • ????????if?[?"$new_combo"?=?"$c"?]?;?then??
  • ????????????return??
  • ????????fi??
  • ????done??
  • ????LUNCH_MENU_CHOICES=(${LUNCH_MENU_CHOICES[@]}?$new_combo)??
  • }??
  • ??????? 傳遞給函數(shù)add_lunch_combo的參數(shù)保存在位置參數(shù)$1中,接著又保存在一個(gè)本地變量new_combo中,用來(lái)表示一個(gè)要即將要添加的Lunch菜單項(xiàng)。函數(shù)首先是在數(shù)組LUNCH_MENU_CHOICES中檢查要添加的菜單項(xiàng)是否已經(jīng)存在。只有在不存在的情況下,才會(huì)將它添加到數(shù)組LUNCH_MENU_CHOICES中去。注意,${LUNCH_MENU_CHOICES[@]}表示數(shù)組LUNCH_MENU_CHOICES的所有元素。

    ?

    ??????? 數(shù)組LUNCH_MENU_CHOICES是定義在文件build/envsetup.sh的一個(gè)全局變量,當(dāng)文件build/envsetup.sh被加載的時(shí)候,這個(gè)數(shù)組會(huì)被初始化為化full-eng、full_x86-eng、vbox_x86-eng和full_mips-eng,如下所示:

    ?

    [plain]?view plaincopy
  • #?add?the?default?one?here??
  • add_lunch_combo?full-eng??
  • add_lunch_combo?full_x86-eng??
  • add_lunch_combo?vbox_x86-eng??
  • add_lunch_combo?full_mips-eng??
  • ?????? 這樣當(dāng)文件build/envsetup.sh加載完成之后,數(shù)組LUNCH_MENU_CHOICES就包含了當(dāng)前源碼支持的所有設(shè)備型號(hào)及其編譯類型,于是當(dāng)接下來(lái)我們執(zhí)行l(wèi)unch命令的時(shí)候,就可以通過(guò)數(shù)組LUNCH_MENU_CHOICES看到一個(gè)完整的Lunch藤蔓。

    ?

    ?????? 二. lunch命令的執(zhí)行過(guò)程

    ?????? lunch命令實(shí)際上是定義在文件build/envsetup.sh的一個(gè)函數(shù),它的實(shí)現(xiàn)如下所示:

    ?

    [plain]?view plaincopy
  • function?lunch()??
  • {??
  • ????local?answer??
  • ??
  • ????if?[?"$1"?]?;?then??
  • ????????answer=$1??
  • ????else??
  • ????????print_lunch_menu??
  • ????????echo?-n?"Which?would?you?like??[full-eng]?"??
  • ????????read?answer??
  • ????fi??
  • ??
  • ????local?selection=??
  • ??
  • ????if?[?-z?"$answer"?]??
  • ????then??
  • ????????selection=full-eng??
  • ????elif?(echo?-n?$answer?|?grep?-q?-e?"^[0-9][0-9]*$")??
  • ????then??
  • ????????if?[?$answer?-le?${#LUNCH_MENU_CHOICES[@]}?]??
  • ????????then??
  • ????????????selection=${LUNCH_MENU_CHOICES[$(($answer-1))]}??
  • ????????fi??
  • ????elif?(echo?-n?$answer?|?grep?-q?-e?"^[^\-][^\-]*-[^\-][^\-]*$")??
  • ????then??
  • ????????selection=$answer??
  • ????fi??
  • ??
  • ????if?[?-z?"$selection"?]??
  • ????then??
  • ????????echo??
  • ????????echo?"Invalid?lunch?combo:?$answer"??
  • ????????return?1??
  • ????fi??
  • ??
  • ????export?TARGET_BUILD_APPS=??
  • ??
  • ????local?product=$(echo?-n?$selection?|?sed?-e?"s/-.*$//")??
  • ????check_product?$product??
  • ????if?[?$??-ne?0?]??
  • ????then??
  • ????????echo??
  • ????????echo?"**?Don't?have?a?product?spec?for:?'$product'"??
  • ????????echo?"**?Do?you?have?the?right?repo?manifest?"??
  • ????????product=??
  • ????fi??
  • ??
  • ????local?variant=$(echo?-n?$selection?|?sed?-e?"s/^[^\-]*-//")??
  • ????check_variant?$variant??
  • ????if?[?$??-ne?0?]??
  • ????then??
  • ????????echo??
  • ????????echo?"**?Invalid?variant:?'$variant'"??
  • ????????echo?"**?Must?be?one?of?${VARIANT_CHOICES[@]}"??
  • ????????variant=??
  • ????fi??
  • ??
  • ????if?[?-z?"$product"?-o?-z?"$variant"?]??
  • ????then??
  • ????????echo??
  • ????????return?1??
  • ????fi??
  • ??
  • ????export?TARGET_PRODUCT=$product??
  • ????export?TARGET_BUILD_VARIANT=$variant??
  • ????export?TARGET_BUILD_TYPE=release??
  • ??
  • ????echo??
  • ??
  • ????set_stuff_for_environment??
  • ????printconfig??
  • }??
  • ??????? 函數(shù)lunch的執(zhí)行邏輯如下所示:

    ??????? 1. 檢查是否帶有參數(shù),即位置參數(shù)$1是否等于空。如果不等于空的話,就表明帶有參數(shù),并且該參數(shù)是用來(lái)指定要編譯的設(shè)備型號(hào)及其編譯類型的。如果等于空的話,那么就調(diào)用另外一個(gè)函數(shù)print_lunch_menu來(lái)顯示Lunch菜單項(xiàng),并且通過(guò)調(diào)用read函數(shù)來(lái)等待用戶輸入。無(wú)論通過(guò)何種方式,最終變量answer的值就保存了用戶所指定的備型號(hào)及其編譯類型。

    ??????? 2. 對(duì)變量answer的值的合法性進(jìn)行檢查。如果等于空的話,就將它設(shè)置為默認(rèn)值“full-eng”。如果不等于空的話,就分為三種情況考慮。第一種情況是值為數(shù)字,那么就需要確保該數(shù)字的大小不能超過(guò)Lunch菜單項(xiàng)的個(gè)數(shù)。在這種情況下,會(huì)將輸入的數(shù)字索引到數(shù)組LUNCH_MENU_CHOICES中去,以便獲得一個(gè)用來(lái)表示設(shè)備型號(hào)及其編譯類型的文本。第二種情況是非數(shù)字文本,那么就需要確保該文本符合<product>-<variant>的形式,其中<product>表示設(shè)備型號(hào),而<variant>表示編譯類型 。第三種情況是除了前面兩種情況之外的所有情況,這是非法的。經(jīng)過(guò)合法性檢查后,變量selection代表了用戶所指定的備型號(hào)及其編譯類型,如果它的值是非法的,即它的值等于空,那么函數(shù)lunch就不往下執(zhí)行了。

    ??????? 3. 接下來(lái)是解析變量selection的值,也就是通過(guò)sed命令將它的<product>和<variant>值提取出來(lái),并且分別保存在變量product和variant中。提取出來(lái)的product和variant值有可能是不合法的,因此需要進(jìn)一步通過(guò)調(diào)用函數(shù)check_product和check_variant來(lái)檢查。一旦檢查失敗,也就是函數(shù)check_product和check_variant的返回值$?等于非0,那么函數(shù)lunch就不往下執(zhí)行了。

    ??????? 4. 通過(guò)以上合法性檢查之后,就將變量product和variant的值保存在環(huán)境變量TARGET_PRODUCT和TARGET_BUILD_VARIANT中。此外,另外一個(gè)環(huán)境變量TARGET_BUILD_TYPE的值會(huì)被設(shè)置為"release",表示此次編譯是一個(gè)release版本的編譯。另外,前面還有一個(gè)環(huán)境變量TARGET_BUILD_APPS,它的值被函數(shù)lunch設(shè)置為空,用來(lái)表示此次編譯是對(duì)整個(gè)系統(tǒng)進(jìn)行編譯。如果環(huán)境變量TARGET_BUILD_APPS的值不等于空,那么就表示此次編譯是只對(duì)某些APP模塊進(jìn)行編譯,而這些APP模塊就是由環(huán)境變量TARGET_BUILD_APPS來(lái)指定的。

    ??????? 5. 調(diào)用函數(shù)set_stuff_for_environment來(lái)配置環(huán)境,例如設(shè)置Java?SDK路徑和交叉編譯工具路徑等。

    ??????? 6. 調(diào)用函數(shù)printfconfig來(lái)顯示已經(jīng)配置好的編譯環(huán)境參數(shù)。

    ??????? 在上述執(zhí)行過(guò)程中,函數(shù)check_product、check_variant和printconfig是比較關(guān)鍵的,因此接下來(lái)我們就繼續(xù)分析它們的實(shí)現(xiàn)。

    ??????? 函數(shù)check_product定義在文件build/envsetup.sh中,它的實(shí)現(xiàn)如下所示:

    ?

    [plain]?view plaincopy
  • #?check?to?see?if?the?supplied?product?is?one?we?can?build??
  • function?check_product()??
  • {??
  • ????T=$(gettop)??
  • ????if?[?!?"$T"?];?then??
  • ????????echo?"Couldn't?locate?the?top?of?the?tree.??Try?setting?TOP."?>&2??
  • ????????return??
  • ????fi??
  • ????CALLED_FROM_SETUP=true?BUILD_SYSTEM=build/core?\??
  • ????????TARGET_PRODUCT=$1?\??
  • ????????TARGET_BUILD_VARIANT=?\??
  • ????????TARGET_BUILD_TYPE=?\??
  • ????????TARGET_BUILD_APPS=?\??
  • ????????get_build_var?TARGET_DEVICE?>?/dev/null??
  • ????#?hide?successful?answers,?but?allow?the?errors?to?show??
  • }??
  • ??????? 函數(shù)gettop用來(lái)返回Android源代碼工程的根目錄。函數(shù)check_product需要在Android源代碼工程根目錄或者子目錄下調(diào)用。否則的話,函數(shù)check_product就出錯(cuò)返回。

    ?

    ??????? 接下來(lái)函數(shù)check_product設(shè)置幾個(gè)環(huán)境變量,其中最重要的是前面三個(gè)CALLED_FROM_SETUP、BUILD_SYSTEM和TARGET_PRODUCT。環(huán)境變量CALLED_FROM_SETUP的值等于true表示接下來(lái)執(zhí)行的make命令是用來(lái)初始化Android編譯環(huán)境的。環(huán)境變量BUILD_SYSTEM用來(lái)指定Android編譯系統(tǒng)的核心目錄,它的值被設(shè)置為build/core。環(huán)境變量TARGET_PRODUCT用來(lái)表示要檢查的產(chǎn)品名稱(也就是我們前面說(shuō)的設(shè)備型號(hào)),它的值被設(shè)置為$1,即函數(shù)check_product的調(diào)用參數(shù)。

    ??????? 最后函數(shù)check_product調(diào)用函數(shù)get_build_var來(lái)檢查由環(huán)境變量TARGET_PRODUCT指定的產(chǎn)品名稱是否合法,注意,它的調(diào)用參數(shù)為TARGET_DEVICE。

    ??????? 函數(shù)get_build_var定義在文件build/envsetup.sh中,它的實(shí)現(xiàn)如下所示:

    ?

    [plain]?view plaincopy
  • #?Get?the?exact?value?of?a?build?variable.??
  • function?get_build_var()??
  • {??
  • ????T=$(gettop)??
  • ????if?[?!?"$T"?];?then??
  • ????????echo?"Couldn't?locate?the?top?of?the?tree.??Try?setting?TOP."?>&2??
  • ????????return??
  • ????fi??
  • ????CALLED_FROM_SETUP=true?BUILD_SYSTEM=build/core?\??
  • ??????make?--no-print-directory?-C?"$T"?-f?build/core/config.mk?dumpvar-$1??
  • }??
  • ??????? 這里就可以看到,函數(shù)get_build_var實(shí)際上就是通過(guò)make命令在Android源代碼工程根目錄中執(zhí)行build/core/config.mk文件,并且將make目標(biāo)設(shè)置為dumpvar-$1,也就是dumpvar-TARGET_DEVICE。

    ?

    ??????? 文件build/core/config.mk的內(nèi)容比較多,這里我們只關(guān)注與產(chǎn)品名稱合法性檢查相關(guān)的邏輯,這些邏輯也基本上涵蓋了Android編譯系統(tǒng)初始化的邏輯,如下所示:

    ?

    [plain]?view plaincopy
  • ......??
  • ??
  • #?---------------------------------------------------------------??
  • #?Define?most?of?the?global?variables.??These?are?the?ones?that??
  • #?are?specific?to?the?user's?build?configuration.??
  • include?$(BUILD_SYSTEM)/envsetup.mk??
  • ??
  • #?Boards?may?be?defined?under?$(SRC_TARGET_DIR)/board/$(TARGET_DEVICE)??
  • #?or?under?vendor/*/$(TARGET_DEVICE).??Search?in?both?places,?but??
  • #?make?sure?only?one?exists.??
  • #?Real?boards?should?always?be?associated?with?an?OEM?vendor.??
  • board_config_mk?:=?\??
  • ????$(strip?$(wildcard?\??
  • ????????$(SRC_TARGET_DIR)/board/$(TARGET_DEVICE)/BoardConfig.mk?\??
  • ????????device/*/$(TARGET_DEVICE)/BoardConfig.mk?\??
  • ????????vendor/*/$(TARGET_DEVICE)/BoardConfig.mk?\??
  • ????))??
  • ifeq?($(board_config_mk),)??
  • ??$(error?No?config?file?found?for?TARGET_DEVICE?$(TARGET_DEVICE))??
  • endif??
  • ifneq?($(words?$(board_config_mk)),1)??
  • ??$(error?Multiple?board?config?files?for?TARGET_DEVICE?$(TARGET_DEVICE):?$(board_config_mk))??
  • endif??
  • include?$(board_config_mk)??
  • ??
  • ......??
  • ??
  • include?$(BUILD_SYSTEM)/dumpvar.mk??
  • ?????? 上述代碼主要就是將envsetup.mk、BoardConfig,mk和dumpvar.mk三個(gè)Makefile片段文件加載進(jìn)來(lái)。其中,envsetup.mk文件位于$(BUILD_SYSTEM)目錄中,也就是build/core目錄中,BoardConfig.mk文件的位置主要就是由環(huán)境變量TARGET_DEVICE來(lái)確定,它是用來(lái)描述目標(biāo)產(chǎn)品的硬件模塊信息的,例如CPU體系結(jié)構(gòu)。環(huán)境變量TARGET_DEVICE用來(lái)描述目標(biāo)設(shè)備,它的值是在envsetup.mk文件加載的過(guò)程中確定的。一旦目標(biāo)設(shè)備確定后,就可以在$(SRC_TARGET_DIR)/board/$(TARGET_DEVICE)、device/*/$(TARGET_DEVICE)和vendor/*/$(TARGET_DEVICE)目錄中找到對(duì)應(yīng)的BoradConfig.mk文件。注意,變量SRC_TARGET_DIR的值等于build/target。最后,dumpvar.mk文件也是位于build/core目錄中,它用來(lái)打印已經(jīng)配置好的編譯環(huán)境信息。

    ?

    ??????? 接下來(lái)我們就通過(guò)進(jìn)入到build/core/envsetup.mk文件來(lái)分析變量TARGET_DEVICE的值是如何確定的:

    ?

    [plain]?view plaincopy
  • #?Read?the?product?specs?so?we?an?get?TARGET_DEVICE?and?other??
  • #?variables?that?we?need?in?order?to?locate?the?output?files.??
  • include?$(BUILD_SYSTEM)/product_config.mk??
  • ?????? 它通過(guò)加載另外一個(gè)文件build/core/product_config.mk文件來(lái)確定變量TARGET_DEVICE以及其它與目標(biāo)產(chǎn)品相關(guān)的變量的值。

    ?

    ?????? 文件build/core/product_config.mk的內(nèi)容很多,這里我們只關(guān)注變量TARGET_DEVICE設(shè)置相關(guān)的邏輯,如下所示:

    ?

    [plain]?view plaincopy
  • ......??
  • ??
  • 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??
  • ??
  • #?all_product_configs?consists?items?like:??
  • #?<product_name>:<path_to_the_product_makefile>??
  • #?or?just?<path_to_the_product_makefile>?in?case?the?product?name?is?the??
  • #?same?as?the?base?filename?of?the?product?config?makefile.??
  • current_product_makefile?:=??
  • all_product_makefiles?:=??
  • $(foreach?f,?$(all_product_configs),\??
  • ????$(eval?_cpm_words?:=?$(subst?:,$(space),$(f)))\??
  • ????$(eval?_cpm_word1?:=?$(word?1,$(_cpm_words)))\??
  • ????$(eval?_cpm_word2?:=?$(word?2,$(_cpm_words)))\??
  • ????$(if?$(_cpm_word2),\??
  • ????????$(eval?all_product_makefiles?+=?$(_cpm_word2))\??
  • ????????$(if?$(filter?$(TARGET_PRODUCT),$(_cpm_word1)),\??
  • ????????????$(eval?current_product_makefile?+=?$(_cpm_word2)),),\??
  • ????????$(eval?all_product_makefiles?+=?$(f))\??
  • ????????$(if?$(filter?$(TARGET_PRODUCT),$(basename?$(notdir?$(f)))),\??
  • ????????????$(eval?current_product_makefile?+=?$(f)),)))??
  • _cpm_words?:=??
  • _cpm_word1?:=??
  • _cpm_word2?:=??
  • current_product_makefile?:=?$(strip?$(current_product_makefile))??
  • all_product_makefiles?:=?$(strip?$(all_product_makefiles))??
  • ??
  • ifneq?(,$(filter?product-graph?dump-products,?$(MAKECMDGOALS)))??
  • #?Import?all?product?makefiles.??
  • $(call?import-products,?$(all_product_makefiles))??
  • else??
  • #?Import?just?the?current?product.??
  • ifndef?current_product_makefile??
  • $(error?Cannot?locate?config?makefile?for?product?"$(TARGET_PRODUCT)")??
  • endif??
  • ifneq?(1,$(words?$(current_product_makefile)))??
  • $(error?Product?"$(TARGET_PRODUCT)"?ambiguous:?matches?$(current_product_makefile))??
  • endif??
  • $(call?import-products,?$(current_product_makefile))??
  • endif??#?Import?all?or?just?the?current?product?makefile??
  • ??
  • ......??
  • ??
  • #?Convert?a?short?name?like?"sooner"?into?the?path?to?the?product??
  • #?file?defining?that?product.??
  • #??
  • INTERNAL_PRODUCT?:=?$(call?resolve-short-product-name,?$(TARGET_PRODUCT))??
  • ifneq?($(current_product_makefile),$(INTERNAL_PRODUCT))??
  • $(error?PRODUCT_NAME?inconsistent?in?$(current_product_makefile)?and?$(INTERNAL_PRODUCT))??
  • endif??
  • current_product_makefile?:=??
  • all_product_makefiles?:=??
  • all_product_configs?:=??
  • ??
  • #?Find?the?device?that?this?product?maps?to.??
  • TARGET_DEVICE?:=?$(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_DEVICE)??
  • ??
  • ......??
  • ?????? 上述代碼的執(zhí)行邏輯如下所示:

    ?

    ?????? 1. 檢查環(huán)境變量TARGET_BUILD_APPS的值是否等于空。如果不等于空,那么就說(shuō)明此次編譯不是針對(duì)整個(gè)系統(tǒng),因此只要將核心的產(chǎn)品相關(guān)的Makefile文件加載進(jìn)來(lái)就行了,否則的話,就要將所有與產(chǎn)品相關(guān)的Makefile文件加載進(jìn)來(lái)的。核心產(chǎn)品Makefile文件在$(SRC_TARGET_DIR)/product/AndroidProducts.mk文件中指定,也就是在build/target/product/AndroidProducts.mk文件,通過(guò)調(diào)用函數(shù)get-product-makefiles可以獲得。所有與產(chǎn)品相關(guān)的Makefile文件可以通過(guò)另外一個(gè)函數(shù)get-all-product-makefiles獲得。無(wú)論如何,最終獲得的產(chǎn)品Makefie文件列表保存在變量all_product_configs中。

    ?????? 2. 遍歷變量all_product_configs所描述的產(chǎn)品Makefile列表,并且在這些Makefile文件中,找到名稱與環(huán)境變量TARGET_PRODUCT的值相同的文件,保存在另外一個(gè)變量current_product_makefile中,作為需要為當(dāng)前指定的產(chǎn)品所加載的Makefile文件列表。在這個(gè)過(guò)程當(dāng)中,上一步找到的所有的產(chǎn)品Makefile文件也會(huì)保存在變量all_product_makefiles中。注意,環(huán)境變量TARGET_PRODUCT的值是在我們執(zhí)行l(wèi)unch命令的時(shí)候設(shè)置并且傳遞進(jìn)來(lái)的。

    ?????? 3.? 如果指定的make目標(biāo)等于product-graph或者dump-products,那么就將所有的產(chǎn)品相關(guān)的Makefile文件加載進(jìn)來(lái),否則的話,只加載與目標(biāo)產(chǎn)品相關(guān)的Makefile文件。從前面的分析可以知道,此時(shí)的make目標(biāo)為dumpvar-TARGET_DEVICE,因此接下來(lái)只會(huì)加載與目標(biāo)產(chǎn)品,即$(TARGET_PRODUCT),相關(guān)的Makefile文件,這是通過(guò)調(diào)用另外一個(gè)函數(shù)import-products實(shí)現(xiàn)的。

    ?????? 4. 調(diào)用函數(shù)resolve-short-product-name解析環(huán)境變量TARGET_PRODUCT的值,將它變成一個(gè)Makefile文件路徑。并且保存在變量INTERNAL_PRODUCT中。這里要求變量INTERNAL_PRODUCT和current_product_makefile的值相等,否則的話,就說(shuō)明用戶指定了一個(gè)非法的產(chǎn)品名稱。

    ?????? 5. 找到一個(gè)名稱為PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_DEVICE的變量,并且將它的值保存另外一個(gè)變量TARGET_DEVICE中。變量PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_DEVICE是在加載產(chǎn)品Makefile文件的過(guò)程中定義的,用來(lái)描述當(dāng)前指定的產(chǎn)品的名稱。

    ?????? 上述過(guò)程主要涉及到了get-all-product-makefiles、import-products和resolve-short-product-name三個(gè)關(guān)鍵函數(shù),理解它們的執(zhí)行過(guò)程對(duì)理解Android編譯系統(tǒng)的初始化過(guò)程很有幫助,接下來(lái)我們分別分析它們的實(shí)現(xiàn)。

    ??????? 函數(shù)get-all-product-makefiles定義在文件build/core/product.mk中,如下所示:

    ?

    [plain]?view plaincopy
  • #??
  • #?Returns?the?sorted?concatenation?of?all?PRODUCT_MAKEFILES??
  • #?variables?set?in?all?AndroidProducts.mk?files.??
  • #?$(call?)?isn't?necessary.??
  • #??
  • define?get-all-product-makefiles??
  • $(call?get-product-makefiles,$(_find-android-products-files))??
  • endef??
  • ?????? 它首先是調(diào)用函數(shù)_find-android-products-files來(lái)找到Android源代碼目錄中定義的所有AndroidProducts.mk文件,然后再調(diào)用函數(shù)get-product-makefiles獲得在這里AndroidProducts.mk文件里面定義的產(chǎn)品Makefile文件。

    ?

    ?????? 函數(shù)_find-android-products-files也是定義在文件build/core/product.mk中,如下所示:

    ?

    [plain]?view plaincopy
  • #??
  • #?Returns?the?list?of?all?AndroidProducts.mk?files.??
  • #?$(call?)?isn't?necessary.??
  • #??
  • define?_find-android-products-files??
  • $(shell?test?-d?device?&&?find?device?-maxdepth?6?-name?AndroidProducts.mk)?\??
  • ??$(shell?test?-d?vendor?&&?find?vendor?-maxdepth?6?-name?AndroidProducts.mk)?\??
  • ??$(SRC_TARGET_DIR)/product/AndroidProducts.mk??
  • endef??
  • ????? 從這里就可以看出,Android源代碼目錄中定義的所有AndroidProducts.mk文件位于device、vendor或者build/target/product目錄或者相應(yīng)的子目錄(最深是6層)中。

    ?

    ????? 函數(shù)get-product-makefiles也是定義在文件build/core/product.mk中,如下所示:

    ?

    [plain]?view plaincopy
  • #??
  • #?Returns?the?sorted?concatenation?of?PRODUCT_MAKEFILES??
  • #?variables?set?in?the?given?AndroidProducts.mk?files.??
  • #?$(1):?the?list?of?AndroidProducts.mk?files.??
  • #??
  • define?get-product-makefiles??
  • $(sort?\??
  • ??$(foreach?f,$(1),?\??
  • ????$(eval?PRODUCT_MAKEFILES?:=)?\??
  • ????$(eval?LOCAL_DIR?:=?$(patsubst?%/,%,$(dir?$(f))))?\??
  • ????$(eval?include?$(f))?\??
  • ????$(PRODUCT_MAKEFILES)?\??
  • ???)?\??
  • ??$(eval?PRODUCT_MAKEFILES?:=)?\??
  • ??$(eval?LOCAL_DIR?:=)?\??
  • ?)??
  • endef??
  • ?????? 這個(gè)函數(shù)實(shí)際上就是遍歷參數(shù)$1所描述的AndroidProucts.mk文件列表,并且將定義在這些AndroidProucts.mk文件中的變量PRODUCT_MAKEFILES的值提取出來(lái),形成一個(gè)列表返回給調(diào)用者。

    ?

    ?????? 例如,在build/target/product/AndroidProducts.mk文件中,變量PRODUCT_MAKEFILES的值如下所示:

    ?

    [plain]?view plaincopy
  • #?Unbundled?apps?will?be?built?with?the?most?generic?product?config.??
  • ifneq?($(TARGET_BUILD_APPS),)??
  • PRODUCT_MAKEFILES?:=?\??
  • ????$(LOCAL_DIR)/full.mk?\??
  • ????$(LOCAL_DIR)/full_x86.mk?\??
  • ????$(LOCAL_DIR)/full_mips.mk??
  • else??
  • PRODUCT_MAKEFILES?:=?\??
  • ????$(LOCAL_DIR)/core.mk?\??
  • ????$(LOCAL_DIR)/generic.mk?\??
  • ????$(LOCAL_DIR)/generic_x86.mk?\??
  • ????$(LOCAL_DIR)/generic_mips.mk?\??
  • ????$(LOCAL_DIR)/full.mk?\??
  • ????$(LOCAL_DIR)/full_x86.mk?\??
  • ????$(LOCAL_DIR)/full_mips.mk?\??
  • ????$(LOCAL_DIR)/vbox_x86.mk?\??
  • ????$(LOCAL_DIR)/sdk.mk?\??
  • ????$(LOCAL_DIR)/sdk_x86.mk?\??
  • ????$(LOCAL_DIR)/sdk_mips.mk?\??
  • ????$(LOCAL_DIR)/large_emu_hw.mk??
  • endif??
  • ?????? 這里列出的每一個(gè)文件都對(duì)應(yīng)于一個(gè)產(chǎn)品。

    ?

    ?????? 我們?cè)賮?lái)看函數(shù)import-products的實(shí)現(xiàn),它定義在文件build/core/product.mk中,如下所示:

    ?

    [plain]?view plaincopy
  • #??
  • #?$(1):?product?makefile?list??
  • #??
  • #TODO:?check?to?make?sure?that?products?have?all?the?necessary?vars?defined??
  • define?import-products??
  • $(call?import-nodes,PRODUCTS,$(1),$(_product_var_list))??
  • endef??
  • ?????? 它調(diào)用另外一個(gè)函數(shù)import-nodes來(lái)加載由參數(shù)$1所指定的產(chǎn)品Makefile文件,并且指定了另外兩個(gè)參數(shù)PRODUCTS和$(_product_var_list)。其中,變量_product_var_list也是定義在文件build/core/product.mk中,它的值如下所示:

    ?

    ?

    [plain]?view plaincopy
  • _product_var_list?:=?\??
  • ????PRODUCT_NAME?\??
  • ????PRODUCT_MODEL?\??
  • ????PRODUCT_LOCALES?\??
  • ????PRODUCT_AAPT_CONFIG?\??
  • ????PRODUCT_AAPT_PREF_CONFIG?\??
  • ????PRODUCT_PACKAGES?\??
  • ????PRODUCT_PACKAGES_DEBUG?\??
  • ????PRODUCT_PACKAGES_ENG?\??
  • ????PRODUCT_PACKAGES_TESTS?\??
  • ????PRODUCT_DEVICE?\??
  • ????PRODUCT_MANUFACTURER?\??
  • ????PRODUCT_BRAND?\??
  • ????PRODUCT_PROPERTY_OVERRIDES?\??
  • ????PRODUCT_DEFAULT_PROPERTY_OVERRIDES?\??
  • ????PRODUCT_CHARACTERISTICS?\??
  • ????PRODUCT_COPY_FILES?\??
  • ????PRODUCT_OTA_PUBLIC_KEYS?\??
  • ????PRODUCT_EXTRA_RECOVERY_KEYS?\??
  • ????PRODUCT_PACKAGE_OVERLAYS?\??
  • ????DEVICE_PACKAGE_OVERLAYS?\??
  • ????PRODUCT_TAGS?\??
  • ????PRODUCT_SDK_ADDON_NAME?\??
  • ????PRODUCT_SDK_ADDON_COPY_FILES?\??
  • ????PRODUCT_SDK_ADDON_COPY_MODULES?\??
  • ????PRODUCT_SDK_ADDON_DOC_MODULES?\??
  • ????PRODUCT_DEFAULT_WIFI_CHANNELS?\??
  • ????PRODUCT_DEFAULT_DEV_CERTIFICATE?\??
  • ????PRODUCT_RESTRICT_VENDOR_FILES?\??
  • ????PRODUCT_VENDOR_KERNEL_HEADERS?\??
  • ????PRODUCT_FACTORY_RAMDISK_MODULES?\??
  • ????PRODUCT_FACTORY_BUNDLE_MODULES??
  • ?????? 它描述的是在產(chǎn)品Makefile文件中定義在各種變量。

    ?

    ?????? 函數(shù)import-nodes定義在文件build/core/node_fns.mk中,如下所示:

    ?

    [plain]?view plaincopy
  • #??
  • #?$(1):?output?list?variable?name,?like?"PRODUCTS"?or?"DEVICES"??
  • #?$(2):?list?of?makefiles?representing?nodes?to?import??
  • #?$(3):?list?of?node?variable?names??
  • #??
  • define?import-nodes??
  • $(if?\??
  • ??$(foreach?_in,$(2),?\??
  • ????$(eval?_node_import_context?:=?_nic.$(1).[[$(_in)]])?\??
  • ????$(if?$(_include_stack),$(eval?$(error?ASSERTION?FAILED:?_include_stack?\??
  • ????????????????should?be?empty?here:?$(_include_stack))),)?\??
  • ????$(eval?_include_stack?:=?)?\??
  • ????$(call?_import-nodes-inner,$(_node_import_context),$(_in),$(3))?\??
  • ????$(call?move-var-list,$(_node_import_context).$(_in),$(1).$(_in),$(3))?\??
  • ????$(eval?_node_import_context?:=)?\??
  • ????$(eval?$(1)?:=?$($(1))?$(_in))?\??
  • ????$(if?$(_include_stack),$(eval?$(error?ASSERTION?FAILED:?_include_stack?\??
  • ????????????????should?be?empty?here:?$(_include_stack))),)?\??
  • ???)?\??
  • ,)??
  • endef??
  • ?????? 這個(gè)函數(shù)主要是做了三件事情:

    ?

    ?????? 1. 調(diào)用函數(shù)_import-nodes-inner將參數(shù)$2描述的每一個(gè)產(chǎn)品Makefile文件加載進(jìn)來(lái)。

    ?????? 2. 調(diào)用函數(shù)move-var-list將定義在前面所加載的產(chǎn)品Makefile文件里面的由參數(shù)$3指定的變量的值分別拷貝到另外一組獨(dú)立的變量中。

    ?????? 3. 將參數(shù)$2描述的每一個(gè)產(chǎn)品Makefile文件路徑以空格分隔保存在參數(shù)$1所描述的變量中,也就是保存在變量PRODUCTS中。

    ?????? 上述第二件事情需要進(jìn)一步解釋一下。由于當(dāng)前加載的每一個(gè)文件都會(huì)定義相同的變量,為了區(qū)分這些變量,我們需要在這些變量前面加一些前綴。例如,假設(shè)加載了build/target/product/full.mk這個(gè)產(chǎn)品Makefile文件,它里面定義了以下幾個(gè)變量:

    ?

    [plain]?view plaincopy
  • #?Overrides??
  • PRODUCT_NAME?:=?full??
  • PRODUCT_DEVICE?:=?generic??
  • PRODUCT_BRAND?:=?Android??
  • PRODUCT_MODEL?:=?Full?Android?on?Emulator??
  • ?????? 當(dāng)調(diào)用了函數(shù)move-var-list對(duì)它進(jìn)行解析后,就會(huì)得到以下的新變量:

    ?

    ?

    [plain]?view plaincopy
  • PRODUCTS.build/target/product/full.mk.PRODUCT_NAME?:=?full??
  • PRODUCTS.build/target/product/full.mk.PRODUCT_DEVICE?:=?generic??
  • PRODUCTS.build/target/product/full.mk.PRODUCT_BRAND?:=?Android??
  • PRODUCTS.build/target/product/full.mk.PRODUCT_MODEL?:=?Full?Android?on?Emulator??
  • ?????? 正是由于調(diào)用了函數(shù)move-var-list,我們?cè)赽uild/core/product_config.mk文件中可以通過(guò)PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_DEVICE來(lái)設(shè)置變量TARGET_DEVICE的值。

    ?

    ?????? 回到build/core/config.mk文件中,接下來(lái)我們?cè)倏碆oardConfig.mk文件的加載過(guò)程。前面提到,當(dāng)前要加載的BoardConfig.mk文件由變量TARGET_DEVICE來(lái)確定。例如,假設(shè)我們?cè)谶\(yùn)行l(wèi)unch命令時(shí),輸入的文本為full-eng,那么build/target/product/full.mk就會(huì)被加載,并且我們得到TARGET_DEVICE的值就為generic,接下來(lái)加載的BoradConfig.mk文件就會(huì)在build/target/board/generic目錄中找到。

    ?????? BoardConfig.mk文件定義的信息可以參考build/target/board/generic/BoardConfig.mk文件的內(nèi)容,如下所示:

    ?

    [plain]?view plaincopy
  • #?config.mk??
  • #??
  • #?Product-specific?compile-time?definitions.??
  • #??
  • ??
  • #?The?generic?product?target?doesn't?have?any?hardware-specific?pieces.??
  • TARGET_NO_BOOTLOADER?:=?true??
  • TARGET_NO_KERNEL?:=?true??
  • TARGET_ARCH?:=?arm??
  • ??
  • #?Note:?we?build?the?platform?images?for?ARMv7-A?_without_?NEON.??
  • #??
  • #?Technically,?the?emulator?supports?ARMv7-A?_and_?NEON?instructions,?but??
  • #?emulated?NEON?code?paths?typically?ends?up?2x?slower?than?the?normal?C?code??
  • #?it?is?supposed?to?replace?(unlike?on?real?devices?where?it?is?2x?to?3x??
  • #?faster).??
  • #??
  • #?What?this?means?is?that?the?platform?image?will?not?use?NEON?code?paths??
  • #?that?are?slower?to?emulate.?On?the?other?hand,?it?is?possible?to?emulate??
  • #?application?code?generated?with?the?NDK?that?uses?NEON?in?the?emulator.??
  • #??
  • TARGET_ARCH_VARIANT?:=?armv7-a??
  • TARGET_CPU_ABI?:=?armeabi-v7a??
  • TARGET_CPU_ABI2?:=?armeabi??
  • ARCH_ARM_HAVE_TLS_REGISTER?:=?true??
  • ??
  • HAVE_HTC_AUDIO_DRIVER?:=?true??
  • BOARD_USES_GENERIC_AUDIO?:=?true??
  • ??
  • #?no?hardware?camera??
  • USE_CAMERA_STUB?:=?true??
  • ??
  • #?Enable?dex-preoptimization?to?speed?up?the?first?boot?sequence??
  • #?of?an?SDK?AVD.?Note?that?this?operation?only?works?on?Linux?for?now??
  • ifeq?($(HOST_OS),linux)??
  • ??ifeq?($(WITH_DEXPREOPT),)??
  • ????WITH_DEXPREOPT?:=?true??
  • ??endif??
  • endif??
  • ??
  • #?Build?OpenGLES?emulation?guest?and?host?libraries??
  • BUILD_EMULATOR_OPENGL?:=?true??
  • ??
  • #?Build?and?enable?the?OpenGL?ES?View?renderer.?When?running?on?the?emulator,??
  • #?the?GLES?renderer?disables?itself?if?host?GL?acceleration?isn't?available.??
  • USE_OPENGL_RENDERER?:=?true??
  • ?????? 它描述了產(chǎn)品的Boot Loader、Kernel、CPU體系結(jié)構(gòu)、CPU ABI和Opengl加速等信息。

    ?

    ?????? 再回到build/core/config.mk文件中,它最后加載build/core/dumpvar.mk文件。加載build/core/dumpvar.mk文件是為了生成make目標(biāo),以便可以對(duì)這些目標(biāo)進(jìn)行操作。例如,在我們這個(gè)情景中,我們要執(zhí)行的make目標(biāo)是dumpvar-TARGET_DEVICE,因此在加載build/core/dumpvar.mk文件的過(guò)程中,就會(huì)生成dumpvar-TARGET_DEVICE目標(biāo)。

    ?????? 文件build/core/dumpvar.mk的內(nèi)容也比較多,這里我們只關(guān)注生成make目標(biāo)相關(guān)的邏輯:

    ?

    [plain]?view plaincopy
  • ......??
  • ??
  • #?The?"dumpvar"?stuff?lets?you?say?something?like??
  • #??
  • #?????CALLED_FROM_SETUP=true?\??
  • #???????make?-f?config/envsetup.make?dumpvar-TARGET_OUT??
  • #?or??
  • #?????CALLED_FROM_SETUP=true?\??
  • #???????make?-f?config/envsetup.make?dumpvar-abs-HOST_OUT_EXECUTABLES??
  • #??
  • #?The?plain?(non-abs)?version?just?dumps?the?value?of?the?named?variable.??
  • #?The?"abs"?version?will?treat?the?variable?as?a?path,?and?dumps?an??
  • #?absolute?path?to?it.??
  • #??
  • dumpvar_goals?:=?\??
  • ????$(strip?$(patsubst?dumpvar-%,%,$(filter?dumpvar-%,$(MAKECMDGOALS))))??
  • ifdef?dumpvar_goals??
  • ??
  • ??ifneq?($(words?$(dumpvar_goals)),1)??
  • ????$(error?Only?one?"dumpvar-"?goal?allowed.?Saw?"$(MAKECMDGOALS)")??
  • ??endif??
  • ??
  • ??#?If?the?goal?is?of?the?form?"dumpvar-abs-VARNAME",?then??
  • ??#?treat?VARNAME?as?a?path?and?return?the?absolute?path?to?it.??
  • ??absolute_dumpvar?:=?$(strip?$(filter?abs-%,$(dumpvar_goals)))??
  • ??ifdef?absolute_dumpvar??
  • ????dumpvar_goals?:=?$(patsubst?abs-%,%,$(dumpvar_goals))??
  • ????ifneq?($(filter?/%,$($(dumpvar_goals))),)??
  • ??????DUMPVAR_VALUE?:=?$($(dumpvar_goals))??
  • ????else??
  • ??????DUMPVAR_VALUE?:=?$(PWD)/$($(dumpvar_goals))??
  • ????endif??
  • ????dumpvar_target?:=?dumpvar-abs-$(dumpvar_goals)??
  • ??else??
  • ????DUMPVAR_VALUE?:=?$($(dumpvar_goals))??
  • ????dumpvar_target?:=?dumpvar-$(dumpvar_goals)??
  • ??endif??
  • ??
  • .PHONY:?$(dumpvar_target)??
  • $(dumpvar_target):??
  • ????@echo?$(DUMPVAR_VALUE)??
  • ??
  • endif?#?dumpvar_goals??
  • ??
  • ......??
  • ????? 我們?cè)趫?zhí)行make命令時(shí),指定的目示會(huì)經(jīng)由MAKECMDGOALS變量傳遞到Makefile中,因此通過(guò)變量MAKECMDGOALS可以獲得make目標(biāo)。

    ?

    ????? 上述代碼的邏輯很簡(jiǎn)單,例如,在我們這個(gè)情景中,指定的make目標(biāo)為dumpvar-TARGET_DEVICE,那么就會(huì)得到變量DUMPVAR_VALUE的值為$(TARGET_DEVICE)。TARGET_DEVICE的值在前面已經(jīng)被設(shè)置為“generic”,因此變量DUMPVAR_VALUE的值就等于“generic”。此外,變量dumpvar_target的被設(shè)置為“dumpvar-TARGET_DEVICE”。最后我們就可以得到以下的make規(guī)則:

    [plain]?view plaincopy
  • .PHONY?dumpvar-TARGET_DEVICE??
  • dumpvar-TARGET_DEVICE:??
  • ????@echo?generic??
  • ?????? 至此,在build/envsetup.sh文件中定義的函數(shù)check_product就分析完成了。看完了之后,小伙伴們可能會(huì)問,前面不是說(shuō)這個(gè)函數(shù)是用來(lái)檢查用戶輸入的產(chǎn)品名稱是否合法的嗎?但是這里沒看出哪一段代碼給出了true或者false的答案啊。實(shí)際上,在前面分析的build/core/config.mk和build/core/product_config.mk等文件的加載過(guò)程中,如果發(fā)現(xiàn)輸入的產(chǎn)品名稱是非法的,也就是找不到相應(yīng)的產(chǎn)品Makefile文件,那么就會(huì)通過(guò)調(diào)用error函數(shù)來(lái)產(chǎn)生一個(gè)錯(cuò)誤,這時(shí)候函數(shù)check_product的返回值$?就會(huì)等于非0值。

    ?

    ?????? 接下來(lái)我們還要繼續(xù)分析在build/envsetup.sh文件中定義的函數(shù)check_variant的實(shí)現(xiàn),如下所示:

    ?

    [plain]?view plaincopy
  • VARIANT_CHOICES=(user?userdebug?eng)??
  • ??
  • #?check?to?see?if?the?supplied?variant?is?valid??
  • function?check_variant()??
  • {??
  • ????for?v?in?${VARIANT_CHOICES[@]}??
  • ????do??
  • ????????if?[?"$v"?=?"$1"?]??
  • ????????then??
  • ????????????return?0??
  • ????????fi??
  • ????done??
  • ????return?1??
  • }??
  • ?????? 這個(gè)函數(shù)的實(shí)現(xiàn)就簡(jiǎn)單多了。合法的編譯類型定義在數(shù)組VARIANT_CHOICES中,并且它只有三個(gè)值user、userdebug和eng。其中,user表示發(fā)布版本,userdebug表示帶調(diào)試信息的發(fā)布版本,而eng表標(biāo)工程機(jī)版本。

    ?

    ?????? 最后,我們?cè)賮?lái)分析在build/envsetup.sh文件中定義的函數(shù)printconfig的實(shí)現(xiàn),如下所示:

    ?

    [plain]?view plaincopy
  • function?printconfig()??
  • {??
  • ????T=$(gettop)??
  • ????if?[?!?"$T"?];?then??
  • ????????echo?"Couldn't?locate?the?top?of?the?tree.??Try?setting?TOP."?>&2??
  • ????????return??
  • ????fi??
  • ????get_build_var?report_config??
  • }??
  • ?????? 對(duì)比我們前面對(duì)函數(shù)check_product的分析,就會(huì)發(fā)現(xiàn)函數(shù)printconfig的實(shí)現(xiàn)與這很相似,都是通過(guò)調(diào)用get_build_var來(lái)獲得相關(guān)的信息,但是這里傳遞給函數(shù)get_build_var的參數(shù)為report_config。

    ?

    ?????? 我們跳過(guò)前面build/core/config.mk和build/core/envsetup.mk等文件對(duì)目標(biāo)產(chǎn)品Makefile文件的加載,直接跳到build/core/dumpvar.mk文件來(lái)查看與report_config這個(gè)make目標(biāo)相關(guān)的邏輯:

    ?

    [plain]?view plaincopy
  • ......??
  • ??
  • dumpvar_goals?:=?\??
  • ????$(strip?$(patsubst?dumpvar-%,%,$(filter?dumpvar-%,$(MAKECMDGOALS))))??
  • .....??
  • ??
  • ifneq?($(dumpvar_goals),report_config)??
  • PRINT_BUILD_CONFIG:=??
  • endif??
  • ??
  • ......??
  • ??
  • ifneq?($(PRINT_BUILD_CONFIG),)??
  • HOST_OS_EXTRA:=$(shell?python?-c?"import?platform;?print(platform.platform())")??
  • $(info?============================================)??
  • $(info???PLATFORM_VERSION_CODENAME=$(PLATFORM_VERSION_CODENAME))??
  • $(info???PLATFORM_VERSION=$(PLATFORM_VERSION))??
  • $(info???TARGET_PRODUCT=$(TARGET_PRODUCT))??
  • $(info???TARGET_BUILD_VARIANT=$(TARGET_BUILD_VARIANT))??
  • $(info???TARGET_BUILD_TYPE=$(TARGET_BUILD_TYPE))??
  • $(info???TARGET_BUILD_APPS=$(TARGET_BUILD_APPS))??
  • $(info???TARGET_ARCH=$(TARGET_ARCH))??
  • $(info???TARGET_ARCH_VARIANT=$(TARGET_ARCH_VARIANT))??
  • $(info???HOST_ARCH=$(HOST_ARCH))??
  • $(info???HOST_OS=$(HOST_OS))??
  • $(info???HOST_OS_EXTRA=$(HOST_OS_EXTRA))??
  • $(info???HOST_BUILD_TYPE=$(HOST_BUILD_TYPE))??
  • $(info???BUILD_ID=$(BUILD_ID))??
  • $(info???OUT_DIR=$(OUT_DIR))??
  • $(info?============================================)??
  • endif??
  • ?????? 變量PRINT_BUILD_CONFIG定義在文件build/core/envsetup.mk中,默認(rèn)值設(shè)置為true。當(dāng)make目標(biāo)為report-config的時(shí)候,變量PRINT_BUILD_CONFIG的值就會(huì)被設(shè)置為空。因此,接下來(lái)就會(huì)打印一系列用來(lái)描述編譯環(huán)境配置的變量的值,也就是我們執(zhí)行l(wèi)unch命令后看到的輸出。注意,這些環(huán)境配置相關(guān)的變量量都是在加載build/core/config.mk和build/core/envsetup.mk文件的過(guò)程中設(shè)置的,就類似于前面我們分析的TARGET_DEVICE變量的值的設(shè)置過(guò)程。

    ?

    ?????? 至此,我們就分析完成Android編譯系統(tǒng)環(huán)境的初始化過(guò)程了。從分析的過(guò)程可以知道,Android編譯系統(tǒng)環(huán)境是由build/core/config.mk、build/core/envsetup.mk、build/core/product_config.mk、AndroidProducts.mk和BoardConfig.mk等文件來(lái)完成的。這些mk文件涉及到非常多的細(xì)節(jié),而我們這里只提供了一個(gè)大體的骨架和脈絡(luò),希望能夠起到拋磚引玉的作用。

    ?????? 有了Android編譯系統(tǒng)環(huán)境的初始化過(guò)程知識(shí)之后,在接下來(lái)的一篇文章中,老羅將繼續(xù)分析Android編譯系統(tǒng)提供的m/mm/mmm編譯命令,敬請(qǐng)關(guān)注!更多信息也可以關(guān)注老羅的新浪微博:http://weibo.com/shengyangluo

    總結(jié)

    以上是生活随笔為你收集整理的Android编译系统环境过程初始化分析【转】的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。