Android.mk是Android源碼中提供的一套用于編譯Android系統(tǒng)、子模塊的基于makefile語法規(guī)則的腳本文件。作為一名Android系統(tǒng)工程師,我們必須要了解Android.mk的語法規(guī)則挺据,這樣才能得心應(yīng)手的修改Android系統(tǒng)取具。
一個工程中的源文件不計其數(shù),其按類型扁耐、功能暇检、模塊分別放在若干個目錄中,makefile定義了一系列的規(guī)則來指定哪些文件需要先編譯婉称,哪些文件需要后編譯块仆,哪些文件需要重新編譯,甚至于進(jìn)行更復(fù)雜的功能操作王暗,因為 makefile就像一個Shell腳本一樣悔据,也可以執(zhí)行操作系統(tǒng)的命令 。
《百度百科:makefile》
雖然Android 7.0 之后Google提供了一種基于新語法結(jié)構(gòu)Android.bp
腳本來替代語法結(jié)構(gòu)繁雜的Android.mk
俗壹,但是即使是Android 10 中依然有大量模塊還在使用Android.mk
進(jìn)行構(gòu)建科汗,預(yù)計今后一段時間內(nèi),Android.mk
與Android.bp
依然會同時存在于Android源碼中绷雏。有關(guān)Android.bp
的使用头滔,請參考這里Android.bp入門教程。
一涎显、最基礎(chǔ)的Android.mk構(gòu)成
在詳細(xì)了解語法之前坤检,最好先了解 Android.mk
文件所含內(nèi)容的基本信息。為此期吓,我們先從一個最簡單的Android.mk入手缀蹄,來逐步了解mk的語法結(jié)構(gòu)。
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_SRC_FILES := hello-jni.c
LOCAL_MODULE := hello-jni
include $(BUILD_SHARED_LIBRARY)
Android.mk
文件必須先定義 LOCAL_PATH
變量
LOCAL_PATH := $(call my-dir)
此變量表示源文件在開發(fā)樹中的位置缺前。在上述命令中,構(gòu)建系統(tǒng)提供的宏函數(shù) my-dir
將返回當(dāng)前目錄(Android.mk
文件本身所在的目錄)的路徑悬襟。
聲明 CLEAR_VARS
變量
include $(CLEAR_VARS)
CLEAR_VARS
變量指向一個特殊的 GNU Makefile衅码,后者會為您清除許多 LOCAL_XXX
變量,例如 LOCAL_MODULE
脊岳、LOCAL_SRC_FILES
和 LOCAL_STATIC_LIBRARIES
逝段。請注意,GNU Makefile 不會清除 LOCAL_PATH
割捅。此變量必須保留其值奶躯,因為系統(tǒng)在單一 GNU Make 執(zhí)行上下文(其中的所有變量都是全局變量)中解析所有構(gòu)建控制文件。在描述每個模塊之前亿驾,您必須聲明(重新聲明)此變量嘹黔。
聲明LOCAL_SRC_FILES
變量
LOCAL_SRC_FILES := hello-jni.c
構(gòu)建系統(tǒng)生成模塊時所用的源文件,可以是單個源文件莫瞬,也可以是一個文件夾儡蔓。
聲明LOCAL_MODULE
變量
LOCAL_MODULE := hello-jni
LOCAL_MODULE
變量存儲您要構(gòu)建的模塊的名稱郭蕉。請在應(yīng)用的每個模塊中使用一次此變量。每個模塊名稱必須唯一喂江,且不含任何空格召锈。構(gòu)建系統(tǒng)在生成最終共享庫文件時,會對您分配給 LOCAL_MODULE
的名稱自動添加正確的前綴和后綴获询。例如涨岁,上述示例會生成名為 libhello-jni.so
的庫。
注意:如果模塊名稱的開頭已經(jīng)是
lib
吉嚣,構(gòu)建系統(tǒng)不會添加額外的lib
前綴卵惦;而是按原樣采用模塊名稱,并添加.so
擴(kuò)展名瓦戚。因此,比如原來名為libfoo.c
的源文件仍會生成名為libfoo.so
的共享對象文件丛塌。此行為是為了支持 Android 平臺源文件根據(jù)Android.mk
文件生成的庫较解;所有這些庫的名稱都以lib
開頭。
LOCAL_SRC_FILES
變量必須包含要構(gòu)建到模塊中的源文件列表赴邻。
聲明include $(BUILD_SHARED_LIBRARY)
include $(BUILD_SHARED_LIBRARY)
通過include $(BUILD_SHARED_LIBRARY)
編譯工具印衔,會將上面設(shè)定的一切連接到一起BUILD_SHARED_LIBRARY
變量指向一個 GNU Makefile 腳本,該腳本會收集您自最近 include
以來在 LOCAL_XXX
變量中定義的所有信息姥敛。此腳本確定要構(gòu)建的內(nèi)容以及構(gòu)建方式奸焙。
上面這些就組成了一個最基礎(chǔ)的Android.mk,下面我們繼續(xù)介紹Android.mk中出現(xiàn)的各種關(guān)鍵字含義和用法彤敛。
二与帆、模塊
在Android.mk中我們把以include $(CLEAR_VARS)
標(biāo)記開頭,到include $(BUILD_XXX)
標(biāo)記結(jié)束墨榄,這中間描述的所有行為玄糟,稱為一個模塊。
例如:下列mk中包含了袄秩,兩個模塊阵翎。
- 模塊一:源碼第2行至第9行,用于編譯一個java類庫
- 模塊二:源碼第12行至第26行之剧,用于編譯一個apk安裝包
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_SRC_FILES := \
$(call all-logtags-files-under, src)
LOCAL_MODULE := settings-logtags
## 構(gòu)建一個 java 類庫
include $(BUILD_STATIC_JAVA_LIBRARY)
# 構(gòu)建一個apk文件
include $(CLEAR_VARS)
LOCAL_PACKAGE_NAME := Settings
#省略其它描述...
LOCAL_USE_AAPT2 := true
LOCAL_SRC_FILES := $(call all-java-files-under, src)
LOCAL_STATIC_ANDROID_LIBRARIES := \
androidx-constraintlayout_constraintlayout \
#省略其它描述...
include frameworks/base/packages/SettingsLib/common.mk
include frameworks/base/packages/SettingsLib/search/common.mk
include $(BUILD_PACKAGE)
三郭卫、include變量
CLEAR_VARS
用于取消位于include $(CLEAR_VARS)
之前定義的所有的LOCAL_XXX變量中定義的值,但是LOCAL_PATH中定義的值不會被取消背稼。
在描述新的模塊前贰军,需要用include包含此變量。
BUILD_JAVA_LIBRARY
include $(BUILD_JAVA_LIBRARY)
用于構(gòu)建java類庫蟹肘,該類庫中的代碼會以dex的形式存在谓形,如圖所示
BUILD_STATIC_JAVA_LIBRARY
include $(BUILD_STATIC_JAVA_LIBRARY)
用于構(gòu)建java類庫灶伊,該類庫中代碼會以class文件的形式存在.
如果編譯出jar是用于app的開發(fā),應(yīng)該使用該變量描述寒跳。
BUILD_PACKAGE
include $(BUILD_PACKAGE)
用于構(gòu)建Android 應(yīng)用程序安裝包聘萨。
BUILD_MULTI_PREBUILT
include $(BUILD_MULTI_PREBUILT)
用于構(gòu)建預(yù)制庫,這些庫一般可以指定在lib文件夾下童太。
BUILD_STATIC_LIBRARIES
include $(BUILD_STATIC_LIBRARIES)
用于構(gòu)建native靜態(tài)庫米辐。
四、模塊描述變量
LOCAL_PATH
此變量用于指定當(dāng)前文件的路徑书释。必須在 Android.mk
文件開頭定義此變量翘贮。以下示例演示了如何定義此變量:
LOCAL_PATH := $(call my-dir)
CLEAR_VARS
所指向的腳本不會清除此變量。因此爆惧,即使 Android.mk
文件描述了多個模塊狸页,也只需定義此變量一次。
LOCAL_MODULE
此變量用于設(shè)定模塊的名稱扯再。指定的名稱在所有模塊名稱中必須唯一芍耘,并且不得包含任何空格。必須先定義該名稱熄阻,然后才能添加其它的腳本(CLEAR_VARS
的腳本除外)斋竞。如下定義在配合include $(BUILD_STATIC_JAVA_LIBRARY)
使用時會編譯時生成一個libsettings-logtags
的類庫,lib是編譯時系統(tǒng)自動加上的秃殉。
LOCAL_MODULE := settings-logtags
LOCAL_MODULE_FILENAME
此變量能夠替換構(gòu)建系統(tǒng)為其生成的文件默認(rèn)使用的名稱坝初。例如,如果 LOCAL_MODULE
的名稱為 settings-logtags
钾军,你可以強(qiáng)制系統(tǒng)將其生成的文件命名為 settingslib
鳄袍。
LOCAL_MODULE := settings-logtags
LOCAL_MODULE_FILENAME := settingslib
LOCAL_SRC_FILES
此變量包含構(gòu)建系統(tǒng)生成模塊時所用的源文件列表。
LOCAL_SRC_FILES := \
$(call all-logtags-files-under, src)
LOCAL_PACKAGE_NAME
此變量用于指定編譯后生成的Android APK的名字吏恭。例如畦木,如下方式,會生成一個Settings.apk的文件砸泛。
LOCAL_PACKAGE_NAME := Settings
LOCAL_CERTIFICATE
此變量用于指定APK的簽名方式十籍。如果不指定,默認(rèn)使用testkey簽名。
LOCAL_CERTIFICATE := platform
Android中共有四中簽名方式:
- testkey:普通APK,默認(rèn)使用該簽名狰晚。
- platform:該APK完成一些系統(tǒng)的核心功能。經(jīng)過對系統(tǒng)中存在的文件夾的訪問測試围俘,這種方式編譯出來的APK所在進(jìn)程的UID為system。
- shared:該APK需要和home/contacts進(jìn)程共享數(shù)據(jù)。
- media:該APK是media/download系統(tǒng)中的一環(huán)界牡。
LOCAL_PRODUCT_MODULE
為true表示將此apk安裝到priv-app目錄下簿寂。
LOCAL_PRODUCT_MODULE := true
LOCAL_SDK_VERSION
標(biāo)記SDK 的version 狀態(tài)。取值范圍有四個current
system_current
test_current
core_current
宿亡。
LOCAL_SDK_VERSION := current
LOCAL_PRIVATE_PLATFORM_APIS
設(shè)置后常遂,會使用sdk的hide的api?肀嘁搿1嘁氳牧PK中使用了系統(tǒng)級API挽荠,必須設(shè)定該值克胳。
LOCAL_PRIVATE_PLATFORM_APIS := true
LOCAL_USE_AAPT2
此值用于設(shè)定是否開啟AAPT2打包APK,AAPT是Android Asset Packaging Tool的縮寫圈匆,AAPT2在AAPT的基礎(chǔ)做了優(yōu)化漠另。
LOCAL_USE_AAPT2 := true
LOCAL_STATIC_ANDROID_LIBRARIES
此值用于設(shè)定依賴的靜態(tài)Android庫
LOCAL_STATIC_ANDROID_LIBRARIES := \
androidx-constraintlayout_constraintlayout \
androidx.slice_slice-builders \
LOCAL_JAVA_LIBRARIES
此值用于設(shè)定依賴的共享java類庫。LOCAL_JAVA_LIBRARIES
引用的外部Java庫在編譯時可以找到相關(guān)的東西跃赚,但并不打包到本模塊笆搓,在runtime時需要從別的地方查找,這個別的地方就是在編譯時將引用的外部Java庫的模塊名添加到PRODUCT_BOOT_JARS
纬傲。
LOCAL_JAVA_LIBRARIES := \
telephony-common \
ims-common
LOCAL_STATIC_JAVA_LIBRARIES
此值用于設(shè)定依賴的靜態(tài)java類庫满败。LOCAL_STATIC_JAVA_LIBRARIES
會把引用的外部Java庫直接編譯打包到本模塊中,在runtime時可以直接從本模塊中找到相關(guān)的jar嘹锁。
LOCAL_STATIC_JAVA_LIBRARIES := \
androidx-constraintlayout_constraintlayout-solver \
androidx.lifecycle_lifecycle-runtime \
androidx.lifecycle_lifecycle-extensions \
LOCAL_PROGUARD_FLAG_FILES
此值用于設(shè)定混淆的標(biāo)志。
LOCAL_PROGUARD_FLAG_FILES := proguard.flags
Android.mk中以LOCAL_XXX開頭的描述變量非常多着裹,這里只列舉了一些常用的變量领猾。
五、函數(shù)宏
Android系統(tǒng)中提供了大量的宏函數(shù)骇扇,使用 $(call <function>)
可以對其進(jìn)行求值摔竿,返回文本信息。
my-dir
這個宏返回最后包括的 makefile 的路徑少孝,通常是當(dāng)前 Android.mk
的目錄继低。my-dir
可用于在 Android.mk
文件開頭定義 LOCAL_PATH
。例如:
LOCAL_PATH := $(call my-dir)
由于 GNU Make 的工作方式稍走,這個宏實際返回的是構(gòu)建系統(tǒng)解析構(gòu)建腳本時包含的最后一個 makefile 的路徑袁翁。因此,包括其他文件后就不應(yīng)調(diào)用 my-dir
婿脸。
例如:
LOCAL_PATH := $(call my-dir)
# ... declare one module
include $(LOCAL_PATH)/foo/`Android.mk`
LOCAL_PATH := $(call my-dir)
# ... declare another module
這里的問題在于粱胜,對 my-dir
的第二次調(diào)用將 LOCAL_PATH
定義為 $PATH/foo
,而不是 $PATH
狐树,因為這是其最近的 include 所指向的位置焙压。
在 Android.mk
文件中的任何其他內(nèi)容后指定額外的 include 可避免此問題。例如:
LOCAL_PATH := $(call my-dir)
# ... declare one module
LOCAL_PATH := $(call my-dir)
# ... declare another module
# extra includes at the end of the Android.mk file
include $(LOCAL_PATH)/foo/Android.mk
如果以這種方式構(gòu)造文件不可行,請將第一個 my-dir
調(diào)用的值保存到另一個變量中涯曲。例如:
MY_LOCAL_PATH := $(call my-dir)
LOCAL_PATH := $(MY_LOCAL_PATH)
# ... declare one module
include $(LOCAL_PATH)/foo/`Android.mk`
LOCAL_PATH := $(MY_LOCAL_PATH)#
... declare another module
all-java-files-under
返回位于<name>目錄下的所有java文件野哭。如果不指定<name>,怎么返回my-dir
目錄下所有的java文件幻件。
include $(call all-java-files-under,<name>)
all-makefiles-under
返回位于當(dāng)前 <name> 路徑下所有目錄中的 Android.mk
文件列表拨黔。利用此函數(shù),可以為構(gòu)建系統(tǒng)提供深度嵌套的源目錄層次結(jié)構(gòu)傲武。默認(rèn)情況下蓉驹,系統(tǒng)只在 Android.mk
文件所在的目錄中查找文件。
include $(call all-makefiles-under,<name>)
六揪利、常見疑問
引入lib文件夾下的第三方庫
在實際開發(fā)中态兴,我們經(jīng)常需要在app中引入第三方的jar或aar,在Android.mk中疟位,可以按照如下的方式描述:
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
# ...
LOCAL_STATIC_JAVA_LIBRARIES := \
contextualcards # 給引入的jar或aar 起一個別名
# ...
include $(BUILD_PACKAGE)
# ==== 預(yù)制類庫 ========================
include $(CLEAR_VARS)
LOCAL_PREBUILT_STATIC_JAVA_LIBRARIES := \
contextualcards:libs/contextualcards.aar # 指定contextualcards的實際路徑
include $(BUILD_MULTI_PREBUILT)
這里需要特別注意一點:在android.mk中引入aar瞻润,編譯時只會引入aar包中的java文件,資源文件如:icon甜刻、xml等都不會被編譯到apk中绍撞。
引入AndroidX庫
開發(fā)過程如果想要引入AndroidX的類庫可以參考下面的方式編寫。
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
# ...
LOCAL_STATIC_ANDROID_LIBRARIES := \
androidx-constraintlayout_constraintlayout \
androidx.appcompat_appcompat \
LOCAL_STATIC_JAVA_LIBRARIES := \
androidx-constraintlayout_constraintlayout-solver \
# ...
include $(BUILD_PACKAGE)
# ...
上面的mk中主要是引入了AndroidX
下的appcompat
和constraintlayout
庫得院。其中constraintlayout
不僅需要在LOCAL_STATIC_ANDROID_LIBRARIES
引入androidx-constraintlayout_constraintlayout
傻铣,還需要在LOCAL_STATIC_JAVA_LIBRARIES
中引入androidx-constraintlayout_constraintlayout-solver
在控制臺使用指令 find prebuilts/sdk/ -name Android.bp|xargs grep "name.粗略的名字",查詢類庫的引入方式祥绞。使用之前需要先 # source build/envsetup.sh # lunch非洲,不然無法執(zhí)行find指令。
使用示例:find prebuilts/sdk/ -name Android.bp|xargs grep "name.constraintlayout"
七蜕径、參考『系統(tǒng)設(shè)置』的Android.mk
Android.mk的編寫两踏,我們很多時候可以參考系統(tǒng)中已有的Android.mk,例如下面給的就是Android R中系統(tǒng)設(shè)置的Android.mk兜喻。
該mk的位于 packages/apps/Settings 下
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_SRC_FILES := \
$(call all-logtags-files-under, src)
LOCAL_MODULE := settings-logtags
# 構(gòu)建一個 libsettings-logtags的靜態(tài)java類庫
include $(BUILD_STATIC_JAVA_LIBRARY)
# 構(gòu)建一個Settings.apk
include $(CLEAR_VARS)
LOCAL_PACKAGE_NAME := Settings
LOCAL_PRIVATE_PLATFORM_APIS := true
LOCAL_CERTIFICATE := platform
LOCAL_PRODUCT_MODULE := true
LOCAL_PRIVILEGED_MODULE := true
LOCAL_REQUIRED_MODULES := privapp_whitelist_com.android.settings
LOCAL_MODULE_TAGS := optional
LOCAL_USE_AAPT2 := true
LOCAL_SRC_FILES := $(call all-java-files-under, src)
LOCAL_STATIC_ANDROID_LIBRARIES := \
androidx-constraintlayout_constraintlayout \
androidx.slice_slice-builders \
androidx.slice_slice-core \
androidx.slice_slice-view \
androidx.core_core \
androidx.appcompat_appcompat \
androidx.cardview_cardview \
androidx.preference_preference \
androidx.recyclerview_recyclerview \
com.google.android.material_material \
setupcompat \
setupdesign
LOCAL_JAVA_LIBRARIES := \
telephony-common \
ims-common
LOCAL_STATIC_JAVA_LIBRARIES := \
androidx-constraintlayout_constraintlayout-solver \
androidx.lifecycle_lifecycle-runtime \
androidx.lifecycle_lifecycle-extensions \
guava \
jsr305 \
settings-contextual-card-protos-lite \
settings-log-bridge-protos-lite \
contextualcards \
settings-logtags \
zxing-core-1.7
LOCAL_PROGUARD_FLAG_FILES := proguard.flags
ifneq ($(INCREMENTAL_BUILDS),)
LOCAL_PROGUARD_ENABLED := disabled
LOCAL_JACK_ENABLED := incremental
LOCAL_JACK_FLAGS := --multi-dex native
endif
include frameworks/base/packages/SettingsLib/common.mk
include frameworks/base/packages/SettingsLib/search/common.mk
include $(BUILD_PACKAGE)
# ==== prebuilt library ========================
include $(CLEAR_VARS)
LOCAL_PREBUILT_STATIC_JAVA_LIBRARIES := \
contextualcards:libs/contextualcards.aar
include $(BUILD_MULTI_PREBUILT)
# Use the following include to make our test apk.
ifeq (,$(ONE_SHOT_MAKEFILE))
include $(call all-makefiles-under,$(LOCAL_PATH))
endif
八梦染、參考資料
Android.mk | Android NDK | Android Developers (google.cn)
編譯_tanliyin的博客-CSDN博客
Android.mk 使用 環(huán)境 小結(jié)_快樂&&平凡-CSDN博客