一、概述
Android.mk作用是將原始檔按照module進行分組,然後將module生成靜態庫、共用庫或者可執行檔案
一個Android.mk裏面可能有1個或者多個module,不同的module之間可以使用相同的原始檔。
Android.mk裏面不用列出頭檔案,Build System會幫我們處理
只有動態庫可以被install或者copy到應用程式包,靜態庫可以被鏈接成動態庫
二、語法
舉例說明:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := hello-jni
LOCAL_SRC_FILES := hello-jni.c
include $(BUILD_SHARED_LIBRARY)
解析如下:
LOCAL_PATH := $(call my-dir)
Android.mk必須以定義LOCAL_PATH開頭,表示原始檔的位置,my-dir返回的是Android.mk的目錄路徑
include $(CLEAR_VARS)
負責清除所有的LOCAL_XXX變數,例如:LOCAL_MODULE、 LOCAL_SRC_FILES、LOCAL_STATIC_LIBRARIES等,但是不包括LOCAL_PATH,這個清理動作必須要有的,因爲這些比阿尼朗都是全域性的,防止之前被賦值,導致當前module解析編譯異常
LOCAL_MODULE := hello-jni
LOCAL_MODULE可以設定模組的名字,模組的名字必須是唯一的並且中間不能包含空格,Build System會自動新增字首和後綴,例如:模組名字是foo,要生成動態庫,那麼生成的動態庫名字就是libfoo.so,其中字首是lib,後綴是.so,但是如果名字是libfoo,字首就不會新增了。生成的動態庫的名字依然是libfoo.so
LOCAL_SRC_FILES := hello-jni.c
LOCAL_SRC_FILES變數裏面包含的是模組用到的C/C++的原始碼,不必列出頭檔案,Build System會自動幫我們找到依賴檔案,當包含C++原始碼是,這些檔案的後綴預設是.cpp,如果檔案後綴不是.cpp,則需要通過LOCAL_CPP_EXTENSION進行修改(後面單獨介紹這個變數)。
include $(BUILD_SHARED_LIBRARY)
BUILD_SHARED_LIBRARY變數指向一個GNU Makefile指令碼,它負責收集自從上次呼叫 include $(CLEAR_VARS)到這一行之間的所有LOCAL_XXX資訊,並編譯成動態庫。也可以使用別的值,例如:
BUILD_STATIC_LIBRARY:編譯爲靜態庫。
BUILD_SHARED_LIBRARY :編譯爲動態庫
BUILD_EXECUTABLE:編譯爲Native C可執行程式
三、NDK Build System變數:
1、NDK Build System 保留了以下變數名:
(1)以LOCAL_ 爲開頭的
(2)以PRIVATE_ ,NDK_ 或者APP_ 開頭的名字
(3)小寫字母名字,如my-dir
注意:如果要在Android.mk定義自己使用的變數名,建議使用MY_ 開頭
2、NDK 定義的 include 變數
2.1:CLEAR_VARS:這個變數指向一個編譯指令碼,這個指令碼是用來取消幾乎所有LOCAL_XXX變數(LOCAL_PATH除外)。所以在描述新模組之前,必須使用此變數
例如:
include $(CLEAR_VARS)
2.2:BUILD_SHARED_LIBRARY:指向一個編譯指令碼,這個指令碼會收集自從上次呼叫 include $(CLEAR_VARS) 到這一行之間所有的LOCAL_XXX資訊。並決定如何這中間列出的原始檔編譯成動態庫。
注意:在此行之前前,至少應該包含:LOCAL_MODULE和LOCAL_SRC_FILES
例如:
include $(BUILD_SHARED_LIBRARY)
2.3:BUILD_STATIC_LIBRARY:與2.2類似,它也指向一個編譯指令碼,這個指令碼會收集自從上次呼叫 include $(CLEAR_VARS) 到這一行之間所有的LOCAL_XXX資訊。並決定如何這中間列出的原始檔編譯成靜態庫。
注意:靜態庫不能夠加入到Project 或者APK中。但它可以用來生成動態庫。
例如:
include $(BUILD_STATIC_LIBRARY)
2.4: BUILD_EXECUTABLE: 與2.2類似,它也指向一個編譯指令碼,這個指令碼會收集自從上次呼叫 include $(CLEAR_VARS) 到這一行之間所有的LOCAL_XXX資訊。並決定如何這中間列出的原始檔編譯成Native程式。
例如:
include $(BUILD_EXECUTABLE)
2.5:PREBUILT_SHARED_LIBRARY:指向一個編譯指令碼,這個指令碼可以指定一個預編譯的共用庫,與BUILD_SHARED_LIBRARY和BUILD_STATIC_LIBRARY不同,此時LOCAL_SRC_FILES應該被指定爲預編譯動態庫的路徑(例如:/foo/libfoo.so),而不是原始檔
例如:
include $(PREBUILT_SHARED_LIBRARY)
例如:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := foo-prebuilt # 模組名
LOCAL_SRC_FILES := libfoo.so # 模組的檔案路徑(相對於 LOCAL_PATH)
include $(PREBUILT_SHARED_LIBRARY)
預編譯庫的使用請參照https://developer.android.google.cn/ndk/guides/prebuilts
2.6: PREBUILT_STATIC_LIBRARY: 預先編譯的靜態庫。
與2.5類似
3、平臺資訊變數
Build system根據APP_ABI變數所指定的每個 ABI 分別解析一次Android.mk,該變數通常在Application.mk檔案中定義。如果APP_ABI爲all表示Build System會根據NDK支援的每個ABI分別解析一次Android.mk
3.1: TARGET_ARCH:
這個參數表示的是CPU架構,可以是arm、arm64、x86或x86_64中的一個
3.2: TARGET_PLATFORM:
這個參數表示的是Android API level,例如:Android 5.1的Android API level對應的是android-22
例如:
ifeq ($(TARGET_PLATFORM),android-22)
# ... do something ...
Endif
3.3:TARGET_ARCH_ABI
這個參數表示的是CPU架構及其支援的ABI
例如:
ifeq ($(TARGET_ARCH_ABI),arm64-v8a)
# ... do something ...
Endif
3.4:TARGET_ABI
這個參數表示的是Android API level和ABI
例如:
ifeq ($(TARGET_ABI),android-22-arm64-v8a)
# ... do something ...
Endif
4、模組描述變數
這類變數是用來向Build System描述模組資訊,位於include $(CLEAR_VARS)和 include $(BUILD_XXXXX)之間。其中include $(CLEAR_VARS)用來清空這些變數,所以在一個新模組開始的時候,需要先呼叫include $(CLEAR_VARS)
4.1: LOCAL_PATH:
這個變數指定當前檔案的路徑,必須在Android.mk的開頭,另外include $(CLEAR_VARS)不會清理這個變數
例如:
LOCAL_PATH := $(call my-dir)
4.2: LOCAL_MODULE:
這個變數用來設定模組名,模組名必須是唯一的,並且模組名內部不能有空格,在include $(BUILD_XXXXX)之前,必須要先定義這個變數。無需新增lib字首和.so或.a後綴,build system會自動新增,如果名字是lib開頭,例如libfoo,則build system不會再新增lib字首
例如:
LOCAL_MODULE := "foo"
4.3: LOCAL_MODULE_FILENAME:
這個變數是可選的,LOCAL_MODULE只能生成libxxx.so或者libxxx.a這種名字,如果要生成其他名字可以使用這個變數替換系統自動生成的名字。
例如:
LOCAL_MODULE := foo
LOCAL_MODULE_FILENAME := libnewfoo
這樣生成的名字就是libnewfoo.so而不是libfoo.so
4.4:LOCAL_SRC_FILES:
這個變數提供build system用來生成模組的原始檔列表。不需要列出依賴檔案。檔案路徑可以是相對路徑也可以是絕對路徑,絕對路徑是相對於LOCAL_PATH的,官方建議使用相對路徑提高可以執行
例如:
LOCAL_SRC_FILES := $(call all-java-files-under, src)
LOCAL_SRC_FILES += \
src/com/sdk/service/abc.aidl \
src/com/sdk/service/abcCallback.aidl
4.5: LOCAL_CPP_EXTENSION:
這個變數是可選的,用來設定C++原始檔的擴充套件名
例如:
LOCAL_CPP_EXTENSION := .cxx
LOCAL_CPP_EXTENSION := .cxx .cpp .cc
4.6:LOCAL_CPP_FEATURES:
這個變數是可選的,用來指定C++ features,C++features啓用 -frtti和-fexceptions時,不要使用LOCAL_CPPFLAGS,這個變數會導致編譯器將制定的features用於所有模組,所以要使用LOCAL_CPP_FEATURES
例如:
LOCAL_CPP_FEATURES := rtti
LOCAL_CPP_FEATURES := exceptions
也可以這樣
LOCAL_CPP_FEATURES := rtti features
4.7:LOCAL_C_INCLUDES:
這個變數是可選的,新增編譯時,C、C++標頭檔案搜尋路徑
例如:
LOCAL_C_INCLUDES := sources/foo
LOCAL_C_INCLUDES := $(LOCAL_PATH)/<subdirectory>/foo
Define this variable before setting any corresponding inclusion flags via LOCAL_CFLAGS or LOCAL_CPPFLAGS.
4.8: LOCAL_CFLAGS:
這個變數是可選的,可以在編譯C/C++原始檔時用來附加編譯選項。
注意:不要在此處修改編譯的優化選項和Debug等級。Build system會使用Application.mk中的資訊自動處理。
可以使用LOCAL_CFLAGS指定標頭檔案檢測路徑
LOCAL_CFLAGS += -I<path>,
這個方法比使用LOCAL_C_INCLUDES要好,這樣也可以被ndk-debug使用。
4.9: LOCAL_CPPFLAGS:
這個變數是可選的,只能給C++原始檔附加編譯選項。要在LOCAL_CFLAGS之後
4.10: LOCAL_STATIC_LIBRARIES:
這個變數用來列出當前模組需要的靜態庫的列表
4.11: LOCAL_SHARED_LIBRARIES:
這個變數用來列出當前模組需要的動態庫的列表
4.12:LOCAL_WHOLE_STATIC_LIBRARIES:
具體參考--whole-archive
4.13:LOCAL_LDLIBS:
這個變數可以用來新增系統庫。 如 -lz:
例如:
LOCAL_LDLIBS := -lz
注意:這個是編譯動態庫用的,爲靜態庫使用此變數,會被忽略
4.14: LOCAL_LDFLAGS
這個變數可以用來指定其他ld,例如要在ARM/X86上使用ld.bfd鏈接器
LOCAL_LDFLAGS += -fuse-ld=bfd
注意:這個是編譯動態庫用的,爲靜態庫使用此變數,會被忽略
4.15: LOCAL_ALLOW_UNDEFINED_SYMBOLS:
預設情況下,build system在編譯動態庫的時候遇到未定義的參照,會報錯: undefined symbol?error,如果不想報錯,可以將這個變數設定成true
注意:這個是編譯動態庫用的,爲靜態庫使用此變數,會被忽略
4.16: LOCAL_ARM_MODE:
預設情況下,build system會以thumb模式生成ARM平臺的二進制檔案。每個指令16位元。如果指定此變數爲:arm。 則指令爲32位元。
例如:
LOCAL_ARM_MODE := arm
也可以在檔案後面加.arm表示以arm模式編譯此原始檔,例如:
LOCAL_SRC_FILES := foo.c bar.c.arm
表示以arm模式編譯bar.c,以LOCAL_ARM_MODE的模式編譯foo.c
4.17: LOCAL_ARM_NEON:
這個變數只有在armeabi-v7a ABI的平臺上纔有意義,也可以在檔案後面加.neon,例如:
LOCAL_SRC_FILES = foo.c.neon bar.c zoo.c.arm.neon
含義是:foo.c按照neon編譯,bar.c按照LOCAL_ARM_MODE編譯,zoo.c按照arm和neon編譯
注意:同時使用.arm和.neon時,.arm必須在.neon前面
4.18:LOCAL_DISABLE_FORMAT_STRING_CHECKS:
預設情況下,build system在編譯程式碼的時候會對標準格式的字串進行保護,如果在printf中有非標準格式的字串就會報錯,設定這個變數爲true,可以不報錯,這個變數預設是關閉的,不建議開啓
4.19: LOCAL_EXPORT_CFLAGS:
這個變數可以記錄一組 C/C++ 編譯器flags,其他模組通過LOCAL_STATIC_LIBRARIES 或 LOCAL_SHARED_LIBRARIES 變數使用這個模組的時候,這些flags將會新增到其他模組的 LOCAL_CFLAGS中
例如:
include $(CLEAR_VARS)
LOCAL_MODULE := foo
LOCAL_SRC_FILES := foo/foo.c
LOCAL_EXPORT_CFLAGS := -DFOO=1
include $(BUILD_STATIC_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := bar
LOCAL_SRC_FILES := bar.c
LOCAL_CFLAGS := -DBAR=2
LOCAL_STATIC_LIBRARIES := foo
include $(BUILD_SHARED_LIBRARY)
build system在編譯bar.c時候,LOCAL_CFLAGS就會有-DFOO=1和-DBAR=2兩個flags
另外這個變數還有傳遞性:例如:如果zoo依賴於bar,而bar依賴於foo,那麼zoo也會繼承從foo導出的所有flags
但是編譯foo的時候,不會使用LOCAL_EXPORT_CFLAGS中的flags,即-DFOO=1這個flags在編譯foo的時候不會使用
4.20 LOCAL_EXPORT_CPPFLAGS
這個變數跟4.19類似,但是隻適用於C++的flags
4.21 LOCAL_EXPORT_C_INCLUDES
這個變數跟4.19類似,但適用於C的標頭檔案。例如,當 bar.c 需要包括模組 foo 的標頭檔案時,此變數很有用。
4.22 LOCAL_EXPORT_LDFLAGS
這個變數跟4.19類似,但適用於ld
4.23 LOCAL_EXPORT_LDLIBS
這個變數跟4.19類似,但是是告訴build system向編譯器傳遞某些系統庫的,每個庫名稱前都要加-l,這些系統庫會被追加其他模組(呼叫這個模組的)的LOCAL_LDLIBS變數下
例如:
include $(CLEAR_VARS)
LOCAL_MODULE := foo
LOCAL_SRC_FILES := foo/foo.c
LOCAL_EXPORT_LDLIBS := -llog
include $(BUILD_STATIC_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := bar
LOCAL_SRC_FILES := bar.c
LOCAL_STATIC_LIBRARIES := foo
include $(BUILD_SHARED_LIBRARY)
build system在編譯libbar.so時,將在鏈接器命令的末尾指定?-llog。這樣就會告知鏈接器,由於libbar.so依賴於foo,因此它也依賴於系統log庫。
4.24 LOCAL_SHORT_COMMANDS
Windows下用這個,不建議開啓
4.25 LOCAL_THIN_ARCHIVE
編譯靜態庫的時候用可以減小生成的二進制檔案,但是這個檔案不能移動到其他位置,因爲裏面的路徑都是相對路徑
注意:非靜態庫和預編譯靜態庫不能用
4.26 LOCAL_FILTER_ASM
5、NDK提供的函數宏:
這些宏通過類似$(call <function>)的方式來得到其值,將返迴文字資訊。
5.1: my-dir:
$(call my-dir): 這個宏返回的是最近一次include的Makefile的路徑。通常返回Android.mk所在的路徑。它用來作爲Android.mk的開頭來定義LOCAL_PATH.
例如:
LOCAL_PATH := $(call my-dir)
注意:這個宏返回的是最近一次include的Makefile的路徑。所以在Include其它Makefile後,再呼叫$(call my-dir)會返回其它Android.mk 所在路徑。
例如:
LOCAL_PATH := $(call my-dir)
# ... declare one module
include $(LOCAL_PATH)/foo/`Android.mk`
LOCAL_PATH := $(call my-dir)
# ... declare another module
這裏LOCAL_PATH最後應該是:$PATH/foo,而不是$PATH.
如果要保留第一次的LOCAL_PATH,那麼只能將第一次$(call my-dir)儲存在其他變數中,例如:
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
這樣就可以將一開始LOCAL_PATH存放到MY_LOCAL_PATH裏面,以備後面使用
5.2: all-subdir-makefiles:
返回包含在my-dir中所有子目錄中的Android.mk的列表
例如:
sources/foo/Android.mk
sources/foo/lib1/Android.mk
sources/foo/lib2/Android.mk
在sources/foo/Android.mk 中使用
include $(call all-subdir-makefiles)
那麼會自動include sources/foo/lib1/Android.mk和sources/foo/lib2/Android.mk
5.3:this-makefile:
返回當前Android.mk的路徑。
5.4:parent-makefile:
返回當前Android.mk的上面一層的Android.mk的路徑
5.5 grand-parent-makefile
返回當前Android.mk的上面兩層的Android.mk的路徑
5.6:import-module:
使用模組名尋找並include這個模組的Android.mk,例如:
$(call import-module,<name>)
它會從NDK_MODULE_PATH目錄下尋找模組名<name>的模組並include這個模組的Android.mk。
6、其他變數
6.1 LOCAL_MODULE_TAGS
定義模組標籤,Build system會根據標籤決定哪些模組被安裝
可以設定下面 下麪這些值:
user:指該模組只在user版本下才編譯
eng:指該模組只在eng版本下才編譯
tests:指該模組只在tests版本下才編譯
optional:指該模組在所有版本下都編譯
例如:
LOCAL_MODULE_TAGS := optional
6.2 all-java-files-under
這個宏可以用來獲取java原始碼,例如:
$(call all-java-files-under, <src>)
獲取<src>目錄下的所有 Java 檔案
all-java-files-under宏的定義是在build/core/definitions.mk中
6.3 LOCAL_PACKAGE_NAME
這個變數用來設定packet的名字
例如:
LOCAL_PACKAGE_NAME := Bluetooth
6.4 LOCAL_PRIVATE_PLATFORM_APIS
設定爲true時,編譯時可以使用sdk隱藏的api,例如
LOCAL_PRIVATE_PLATFORM_APIS := true
6.5 LOCAL_SDK_VERSION
編譯時不可以使用sdk隱藏的api,有時一些系統的class被import後編譯時說找不到這個類,就是這個原因造成的。
例如:
LOCAL_SDK_VERSION := current
LOCAL_SDK_VERSION也可以設定其他值中的一個:current system_current test_current core_current,具體含義暫時不清楚
注意:LOCAL_SDK_VERSION和LOCAL_PRIVATE_PLATFORM_APIS只能使用其中的一個,如果都不使用會報錯
關於api可以分析下面 下麪幾類:
Internal api:內部api,只能是sdk內部使用的,這類介面是不對外公開的
Hide api:隱藏api,在原始碼中使用@hide 標記的方法或者類,這類介面本意是公開的,但是目前扔不穩定,所以不建議使用
其他api:第三方app也可以使用的api
6.6 LOCAL_CERTIFICATE
指定用什麼簽名,例如:
LOCAL_CERTIFICATE := platform
表示使用platform簽名
6.7 LOCAL_USE_AAPT2
表示是否使用aapt2工具
Aapt是android asset packaging tool的縮寫,是編譯和打包資源的工具,aapt2是在aapt的基礎上做了優化
例如:
LOCAL_USE_AAPT2 := true
6.8 LOCAL_JNI_SHARED_LIBRARIES
這個變數表示編譯時用到的JNI共用庫
例如:
LOCAL_JNI_SHARED_LIBRARIES := libbluetooth_jni
6.9 LOCAL_JAVA_LIBRARIES
這個變數用來指定依賴的java共用庫,這裏只是依賴,不會將庫打包到apk中
例如:
LOCAL_JAVA_LIBRARIES := javax.obex telephony-common services.net
6.10 LOCAL_STATIC_JAVA_LIBRARIES
這個變數用來指定依賴的java靜態庫,這裏最終會將對應的庫打包到apk中
例如:
LOCAL_STATIC_JAVA_LIBRARIES := \
com.android.vcard \
bluetooth.mapsapi \
sap-api-java-static \
services.net \
libprotobuf-java-lite \
bluetooth-protos-lite
6.11 LOCAL_STATIC_ANDROID_LIBRARIES
這個變數表明要呼叫的android的包,例如v7 v13包等
例如:
LOCAL_STATIC_ANDROID_LIBRARIES := android-support-v4
6.12 LOCAL_REQUIRED_MODULES
這個變數可以指定依賴的模組,一旦本模組安裝,那麼這個變數指定的依賴的模組也會被安裝
例如:LOCAL_REQUIRED_MODULES := libbluetooth
6.13 LOCAL_PROGUARD_ENABLED
混淆器設定,預設是full obfuscation,即全程式碼混淆,disabled表示不開啓混淆器
例如:
LOCAL_PROGUARD_ENABLED := disabled
6.14 all-Iaidl-files-under
這個宏可以獲取指定目錄下aidl檔案
例如:
$(call all-Iaidl-files-under, <src>)
6.15 all-c-files-under
這個宏可以獲取指定目錄下C語言檔案
例如:
$(call all-c-files-under, <src>)
6.16 all-makefiles-under
這個宏可以獲取指定目錄下makefile檔案
例如:
$(call all-makefiles-under, <folder>)
6.17 BUILD_HOST_STATIC_LIBRARY
表示編譯成主機上的靜態庫
6.18 BUILD_HOST_SHARED_LIBRARY
表示編譯成主機上的動態庫
6.18 BUILD_HOST_EXECUTABLE
表示編譯成主機上的可執行檔案
6.19 BUILD_JAVA_LIBRARY
表示編譯成java動態庫
6.20 BUILD_STATIC_JAVA_LIBRARY
表示編譯成java靜態庫
6.21 BUILD_PACKAGE
表示編譯成apk程式
6.22 BUILD_HOST_JAVA_LIBRARY
表示編譯成主機上的java動態庫