android.mk詳解


1. 為什么是Android.mk

不知道有沒有人想過,Android源碼里為什么每個模塊的編譯文件叫Android.mk? 而不是別的什么名字呢。這是因為main.mk明確指定了,以每個子目錄下的Android.mk作為模塊編譯的起始makfile文件。

 

[build/core/main.mk]

    subdir_makefiles := \        $(shell build/tools/findleaves.py --prune=$(OUT_DIR) --prune=.repo --prune=.git $(subdirs) Android.mk)    $(foreach mk, $(subdir_makefiles), $(info including $(mk) ...)$(eval include $(mk)))

所以在Android源碼里,我們每次看一個模塊是如何編譯時,總是把模塊所在目錄里的Android.mk作為編譯的起始Makefile文件。

 

2. 如何閱讀Android.mk

可能有朋友在琢磨是不是Android的編譯系統重新定義了一套和GNU Makefile完全不同的規則?答案是否定的。其實在編譯源碼時,無論是直接使用make全編,還是使用mm\mmm命令全編譯單個模塊,我們所遵循的原則和GNU Makefile是一模一樣的,最終都是使用相同的make命令,所有GNU Makefile規則在Android源碼里照樣適用,只不過Android封裝了寵大且復雜的編譯系統,使得我們可以清晰簡便的做修改。

 

對於Android源碼的build系統,比較復雜,涉及的知識點也相對較多,這里只以Android.mk作為切入點,剩下的以后有機會展開,由點及面,對build系統熟悉起來。

 

以Android源碼里一個系統APP的Android.mk文件作為例子:

    LOCAL_PATH:= $(call my-dir)    include $(CLEAR_VARS)    LOCAL_MODULE_TAGS := optional    LOCAL_SRC_FILES := $(call all-java-files-under, src) \                    src/com/android/music/IMediaPlaybackService.aidl    LOCAL_PACKAGE_NAME := Music    LOCAL_PROGUARD_FLAG_FILES := proguard.flags    include $(BUILD_PACKAGE)

 

具體解釋如下:

  • 每一個Androi.mk文件都必須以定義LOCAL_PATH變量開頭,my-dir是由build系統定義的函數,作用是返回當前Android.mk在源碼中目錄

 

  • CLEARVARS是由build系統所定義的一個變量,它的值是build/core/clear_vars.mk,作用是清除很多LOCAL開頭的變量,但是不清理LOCAL_PATH,所以你可以當include $(CLEAR_VARS)作為每個模塊編譯的開始。

 

  • LOCAL_MODULE_TAGS用於定義當前模塊在什么編譯模式中被編譯,它的值有eng, user, tests, optional。

 

  • LOCAL_PACKAGE_NAME變量指明了編譯出apk的名字,只有當前模塊是一個應用(APP)才使用LOCAL_PACKAGE_NAME; 其余情況,無論so或jar包,全部都使用LOCAL_MODULE變量。

 

  • LOCAL_SRC_FILES變量指明編譯使用的源碼文件,all-java-files-under是由build系統定義的函數,作用是列出指定目錄下所有的java文件。

 

  • LOCAL_PROGUARD_FLAG_FILES指定混淆文件,上例中表明當前目錄下proguard.flags作為混淆文件。

     

 

 

  • BUILD_PACKAGE也是由build系統定義的一個變量,值是build/core/package.mk, 表示編譯出一個apk文件。一般來講,類似include $(BUILD_PACKAGE)可以作為一個模塊編譯的結束。

     

 

和BUILD_PACKAGE變量類似的還有好幾個,這里列出其中常見的一部分:

  • BUILD_JAVA_LIBRARY  —  build/core/java_library.mk; 表示編譯一個jar包, 里面是DEX格式的文件

 

 

  • BUILD_STATIC_JAVA_LIBRARY – build/core/static_java_library.mk; 也編譯一個jar包,但是里面每個java文件所對應的class文件都存在

 

  • BUILD_EXECUTABLE  — build/core/executable.mk; 編譯一個可執行的bin程序

  • BUILD_PREBUILT  — build/core/prebuilt.mk;用於集成第三方的jar包或者so庫等

     

 

 

3. 常見變量

  • LOCAL_STATIC_JAVA_LIBRARIES/LOCAL_JAVA_LIBRARIES - 指明編譯當前模塊所依賴的jar包

  • LOCAL_CERTIFICATE := platform - 指明使用platform key來對當前模塊進行簽名

  • LOCAL_AAPT_FLAGS - Android源碼里使用aapt打包jar包或apk文件,這個變量可以定義aapt打包參數,比如 :—auto-add-overlay, —extra-packages

  • LOCAL_PROGUARD_ENABLED - 是否進行混淆

 

4. 調試手段

我們調試代碼的時候,最常用的手段就是打log, 在不明白的地方,或者不知道走了哪個if分支,或者想看看變量的值是什么,都可以打log看。

 

Android build系統里也可以打Log,使用函數warning / info / error。

需要注意的是,error函數會讓編譯直接停下來,所以一般用warning和info

 

使用示例(以warning為例,其它兩個類似):

  • 打印普通字符串(hello world):

    $(warning hello world)
  • 打印變量的值:

    $(warning $(LOCAL_PACKAGE_NAME))
  • 變量和字符串組合打印:

    $(warning this apk is $(LOCAL_PACKAGE_NAME))

 

下面以一個真實的App編譯為例,在這個Android.mk里,可能我不知道PLATFORM_VERSION的值,所以我不知道它會不會進ifeq語句,這時打個log, 編譯一下:

include $(CLEAR_VARS) ... ... $(warning tmac_lover $(PLATFORM_VERSION)) ifeq ($(PLATFORM_VERSION), 6.0)    LOCAL_STATIC_JAVA_LIBRARIES += upgrade_httpclient endif ... ... include $(BUILD_PACKAGE)

使用mm -B命令編譯apk, 從編譯輸出中可以看到下面這些,6.0就是PLATFORM_VERSION的值。

packages/apps/TVUpdate/Android.mk:29: tmac_lover 6.0

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM