Android源碼分析(二):mk文件具體的具體的執行流程

 Android編譯系統集中於build/core下,幾個很重要的*.mk文件如下:

         main.mk(主控Makefile)
         base_rules.mk(對一些Makefile的變量規則化)
         config.mk(關於編譯參數、編譯命令的一些配置)
         definations.mk(定義了很多編譯系統中用到的宏,相當於函數庫)
         Makefile(這個Makefile特指build/core下的Makefile,此文件主要控制生成system.img,ramdisk.img,userdata.img,以及recorvery p_w_picpath,sdk等)
         Binary.mk(控制如何生成目標文件)
         Clear_vars.mk(清除編譯系統中用到的臨時變量)
         Combo/linux-arm.mk(控制如何生成linux-arm二進制文件,包括ARM相關的編譯器,編譯參數等的設置)
         Copy_headers.mk(將頭文件拷貝到指定目錄)
         分散於各個目錄下的Android.mk(控制生成局部模塊的源碼,名稱所需頭文件路徑,依賴庫等特殊選項)
         Build/envsetup.mk(編譯環境初始化,定義一些實用的shell函數,方便編譯使用)
         以上幾個主要的文件,可以按照社會分工打一個比方:
         Main.mk是總統,是老大,承擔了很多工作。
         Makefile是副總統,輔佐老大Main.mk
         Base_rules.mk是交警,讓不規則的東西,變得規則。
         Config.mk是省長,規定了各個人民羣衆該如何行事
         Definations.mk是圖書館管理員
         Binary.mk應該屬於村長了,規定每個人該如何行事
         Clear_vars.mk應該屬於保潔公司的工人吧
         Combo/linux-arm.mk應該屬於社會公民了,他決定自己該如何去做
Main.mk分析
   Main.mk主要包含如下幾個部分的內容
      1.   SHELL設置
      2.   編譯環境配置
      3.   編譯環境檢查
      4.   包含必要的宏
      5.   根據make參數設置編譯時的變量
      6.   包含需要編譯的Android.mk
      7.   設置編譯系統Target:prerequisites 控制整個編譯流程
      下面對上面幾點進行必要解釋:
       Main.mk的第一句就根據ANDROID_BUILD_SHELL來包裹編譯系統用到的Shell,如果我們不想使用bash,而想使用sh,那麼就可以在它前面寫上ANDROID_BUILD_SHELL := /bin/sh,或者在build/envsetup.sh中添加相關定義。(內容如下圖) 
          定義完SHELL之後,就是對MAKE_VERSION的檢查,然後定義了默認的編譯目標droid!如果我們敲入make之後,不加任何參數,默認的目標就是droid。注意雖然後面的include $(BUILD_SYSTEM)/config.mk寫在默認目標droid依賴之後,但其和之後的語句都是要執行的,這是Makefile的語法決定的。(內容如下圖) 

          後面會include config.mk cleanbuild.mk對編譯系統進行必要的配置。後面就是對編譯環境的檢查,包括是否大小寫敏感、路徑檢查、java版本檢查、javac版本檢查。Android對編譯環境的檢查如果符合條件,在下次編譯的時候,不會再次進行檢查。(內容如下圖) 

 

         檢查完版本之後,會包含進definitions.mk,如前所述,definitions.mk中定義了很多編譯系統中用到的宏,這些宏在編譯時需要經常調用,因此在編譯的很靠前的階段,就將之包含了進來。(內容如下圖)Definitions.mk中的內容自己有時間在回顧一下,裏面定義了很多宏. 

     然後就是針對make時傳入的編譯類型(eng user userdebug showcommands等)進行編譯配置,這些配置會影響到最終編譯目標所包括的模塊。對於eng user userdebug sdk win_sdk tests等編譯目標的區別,可以通過查看main.mk的代碼找出其中到底有什麼不同。(內容如下圖)

 

在編譯完整個系統之後,再運行make sdk,就可以進行sdk 的編譯了。make sdk 將各種工具和p_w_picpath 打包,供開發和調試使用。注: Make 命令
      make droid:等同於make 命令。droid 是默認的目標名稱。
      make all: make all 將make 所有make droid 會編譯的項目。同時,將編譯LOCAL_MODULE_TAGS 定義的不包括android tag 的模塊。這將確保所有的在代碼樹裏面同時有Android.mk 文件的模塊。
     clean-$(LOCAL_MODULE)和clean-$(LOCAL_PACKAGE_NAME):刪除某個模塊的目標文件。例如:clean-libutils 將刪除所有的libutils.so 以及和它相關的中間文件;
      clean-Home 將刪除Home 應用。
      make clean:刪除本次配置所編譯輸出的結果文件。類似於:rm –rf ./out/ <configuration>
      make clobber:刪除所有配置所編譯輸出的結果文件。類似於:rm –rf ./out/
      make dataclean:make dataclean deletes contents of the data directory inside the
     current combo directory. This is especially useful on the simulator and emulator, where
     the persistent data remains present between builds.
     make showcommands在編譯的時候顯示腳本的命令而不是顯示編譯的簡報。用於調試腳本。
     make LOCAL_MODULE:編譯一個單獨得模塊(需要有Android.mk 文件存在)。
     make targets:將輸出所有擬可以編譯的模塊名稱列表。還有一些命令,從make 文件裏面應該可以找到。)
 
       Ifeq($(SDK_ONLY),true)處,大概400行上下,這個判斷語句一直到這個語句塊結束,都是對subdirs變量的設置,subdirs變量決定了哪些子文件夾最終被編譯。在後面的subdir_makefiles變量的設置,決定了哪些Android.mk被編譯。緊接着include $(subdir_makefiles)就會添加所有這些Android.mk文件的依賴。這其中包含了droid的依賴,後面我們會發現。(內容如下圖)
 
  本地模塊的Makefile文件就是我們在Android 裏面幾乎上隨處可見的Android.mk。Android 進行編譯的時候會通過下面的函數來遍歷所有子目錄中的Android.mk,一旦找到就不會再往層子目錄繼續尋找(所有你的模塊定義的頂層Android.mk 必須包含自己定義的子目錄中的Android.mk)。subdir_makefiles += \$(shellbuild/tools/findleaves.sh --prune="./out" $(subdirs) Android.mk)不同類型的本地模塊具有不同的語法,但基本上是相通的,只有個別變量的不同,如何添加模塊在前面,如上圖就是公司自己添加的模塊。
         然後就會根據這些Makefile,找出所有需要編譯的模塊(module),以及進行必要的分類(eng_MODULES/debug_MODULES/tests_MODULES等、modules_to_check/modules_to_install等),用以區別對待。緊接着是定義了一系列的隱含目標:prebuilt、all_copied_headers、files、checkbuild、ramdisk、systemtallball、userdatap_w_picpath、userdatatarball、bootimg、droidcore等。最重要的一點,是會發現droid依賴於droidcore,而droidcore依賴於
droidcore: files \
         systemp_w_picpath \
         $(INSTALLED_BOOTIMAGE_TARGET) \
         $(INSTALLED_RECOVERYIMAGE_TARGET) \
         $(INSTALLED_USERDATAIMAGE_TARGET) \
         $(INSTALLED_FILES_FILE)
正是這幾個依賴項,控制着整個android的編譯。
         當我們敲Make實際上就等同於我們執行make droid。當Make include所有的文件,完成對所有make我文件的解析以後就會尋找生成droid的規則,依次生成它的依賴,直到所有滿足的模塊被編譯好,然後使用相應的工具打包成相應的img。
config.mk分析
          build/core/config.mk該文件被main.mk包含。config.mk 文件的主要內容如下:頭文件的定義;(各種include 文件夾的設定)在定義頭文件的部分,還include 了pathmap.mk,如下:include $(BUILD_SYSTEM)/pathmap.mk
該文件設置include 目錄和frameworks/base 下子目錄等的信息。編譯系統內部mk 文件的定義; <Build system internal files>。(內容如下圖)
 
設定通用的名稱;<Set common values>
 Include 必要的子配置文件;<Include sub-configuration files>
 buildspec.mk
 envsetup.mk
 BoardConfig.mk
 /combo/select.mk
 /combo/javac.mk
。(內容如下圖) 

 

檢查BUILD_ENV_SEQUENCE_NUMBER 版本號;
In order to make easier for people when the build system changes, when it is necessary
to make changes to buildspec.mk or to rerun the environment setup scripts, they contain
a version number in the variable BUILD_ENV_SEQUENCE_NUMBER. If this variable does
not match what the build system expects, it fails printing an error message explaining
what happened. If you make a change that requires an update, you need to update two
places so this message will be printed.
· In config/envsetup.make, increment the
CORRECT_BUILD_ENV_SEQUENCE_NUMBER definition.
· In buildspec.mk.default, update the BUILD_ENV_SEQUENCE_DUMBER definition
to match the one in config/envsetup.make
The scripts automatically get the value from the build system, so they will trigger the
warning as well.。(內容如下圖)
       設置常用工具的常量;< Generic tools.>
       設置目標選項;< Set up final options.>
       遍歷並設置SDK 版本;

envsetup.mk分析

       125行又包含了另外一個重要的mk文件envsetup.mk,我們來看一下。

        上面的代碼是指定了目標輸出代碼的位置和主機輸出代碼的位置,重要的幾個如下:PRODUCT_OUT = 這個的結果要根據product_config.mk文件內容來決定。envsetup.mk文件主要包含了product_config.mk文件,然後指定了編譯時要輸出的所有文件的OUT目錄。

        envsetup.mk又包含了product_config.mk文件

 

build/core/product_config.mk又包含了product.mk文件。
          因此android編譯系統通過各種依賴關係、確保某個模塊的修改引起相依賴的文件的重新編譯鏈接,甚至還包括目標文件系統的生成,配置文件的生成等。

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章