一個Android.mk文件可以編譯多個模塊,每個模塊屬下列類型之一:
- APK程序-- 一般的Android程序,編譯打包生成apk文件
- JAVA庫 -- java類庫,編譯打包生成jar文件
- C\C++應用程序-- 可執行的C\C++應用程序
- C\C++靜態庫-- 編譯生成C\C++靜態庫,並打包成.a文件
- C\C++共享庫-- 編譯生成共享庫(動態鏈接庫),並打包成.so文,有且只有共享庫才能被安裝/複製到您的應用軟件(APK)包中。
可以在每一個Android.mk file 中定義一個或多個模塊,你也可以在幾個模塊中使用同一個源代碼文件。 編譯系統爲你處理許多細節問題。例如,你不需要在你的 Android.mk 中列出頭文件和依賴文件。編譯系統將會爲你自動處理這些問題。這也意味着,在升級 NDK 後,你應該得到新的toolchain/platform支持,而且不需要改變你的 Android.mk 文件。
‘:=’是賦值的意思;'+='是追加的意思;‘$’表示引用某變量的值
自定義變量:
以下是在 Android.mk中依賴或定義的變量列表, 可以定義其他變量爲自己使用,但是NDK編譯系統保留下列變量名:
-以 LOCAL_開頭的名字(例如 LOCAL_MODULE)
-以 PRIVATE_, NDK_ 或 APP_開頭的名字(內部使用)
-小寫名字(內部使用,例如‘my-dir’)
如果爲了方便在 Android.mk 中定義自己的變量,建議使用 MY_前綴,一個小例子:
MY_SOURCES := foo.c
ifneq ($(MY_CONFIG_BAR),)
MY_SOURCES += bar.c
endif
LOCAL_SRC_FILES += $(MY_SOURCES)
GNU Make系統變量
include $( CLEAR_VARS) CLEAR_VARS由編譯系統提供,指定讓GNU MAKEFILE爲你清除許多LOCAL_XXX變量(例如 LOCAL_MODULE, LOCAL_SRC_FILES, LOCAL_STATIC_LIBRARIES, 等等...),除LOCAL_PATH 。這是必要的,因爲所有的編譯控制文件都在同一個GNU MAKE執行環境中,所有的變量都是全局的;
include $(BUILD_EXECUTABLE)編譯應用程序;
include $(BUILD_STATIC_LIBRARY)編譯靜態庫,靜態庫不會被複制到APK包中,但是能夠用於編譯共享庫。這將會生成一個名爲 lib$(LOCAL_MODULE).a的文件;
include $(BUILD_SHARED_LIBRARY)編譯動態庫,根據所有的在 LOCAL_XXX 變量把列出的源代碼文件編譯成一個共享庫。注意,必須至少在包含這個文件之前定義 LOCAL_MODULE 和 LOCAL_SRC_FILES;
include $(BUILD_PACKAGE)編譯應用程序APK;
include $(BUILD_PREBUILT)預編譯應用程序;
TARGET_ARCH: 目標 CPU平臺的名字;
TARGET_PLATFORM: Android.mk 解析的時候,目標 Android 平臺的名字;
TARGET_ARCH_ABI: 暫時只支持兩個 value,armeabi 和 armeabi-v7a;
TARGET_ABI: 目標平臺和 ABI 的組合。
NDK提供的函數宏:
GNU Make函數宏,必須通過使用'$(call )'來調用,返回值是文本化的信息。
my-dir:返回當前 Android.mk 所在的目錄的路徑,相對於 NDK 編譯系統的頂層。這是有用的,在 Android.mk 文件的開頭如此定義:
LOCAL_PATH := $(call my-dir)
all-subdir-makefiles: 返回一個位於當前'my-dir'路徑的子目錄中的所有Android.mk的列表。
例如,某一子項目的目錄層次如下:
src/foo/Android.mk
src/foo/lib1/Android.mk
src/foo/lib2/Android.mk
如果 src/foo/Android.mk 包含一行:include $(call all-subdir-makefiles) 那麼它就會自動包含 src/foo/lib1/Android.mk 和 src/foo/lib2/Android.mk。
這項功能用於向編譯系統提供深層次嵌套的代碼目錄層次。
注意,在默認情況下,NDK 將會只搜索在 src/*/Android.mk 中的文件。
- all-makefiles-under: 獲取某個目錄下及子目錄的所有Android.mk。$(1):需要提取Android.mk的目錄
- this-makefile: 返回當前Makefile 的路徑(即這個函數調用的地方)
- parent-makefile: 返回調用樹中父 Makefile 路徑。即包含當前Makefile的Makefile 路徑。
- grand-parent-makefile:返回調用樹中父Makefile的父Makefile的路徑
注意:在寫Android.mk文件時,call all-subdir-makefiles和call all-makefiles-under,$(LOCAL_PATH)是有區別的。前者表示“當前目錄下沒有需要編譯的文件,請向子目錄深入”,是告訴編譯器繼續向目錄深處遞歸的一種規定寫法。後者從字面上理解也應該是同一個意思。
但是,請考慮這樣一種情況:如果當前目錄下有文件需要編譯,而且在當前目錄下還有子目錄,子目錄中也有文件需要編譯,那麼當前目錄下的Android.mk除了要包含編譯當前目錄下文件的語句,同樣也要包含告訴編譯器在編譯完當前目錄下的文件後,繼續向子目錄深入的語句。這裏就有一個問題,後面這個語句該如何寫呢?是call all-subdir-makefiles,還是call all-makefiles-under,$(LOCAL_PATH)呢?寫前者是不行的,編譯器會在編譯完當前目錄下的文件後不再進入子目錄編譯,而寫成後者則可以達到我們的期望。
常用模塊描述變量:
每個模塊都是以include $(CLEAR_VARS)開始,並且以include $(BUILD_XXX)結束(應用程序,靜態庫,動態庫等)。
每個Android.mk文件以定義LOCAL_PATH爲開始,它用於在開發tree中查找源文件LOCAL_PATH := $(call my-dir) my-dir宏是系統用來返回包含當前Android.mk的目錄路徑;
如果有多個module需要編譯,可以放置多個目錄,在每個目錄編寫一個Android.mk,然後在根目錄的Android.mk中添加一行include $(call all-subdir-makefiles);
LOCAL_PATH:=當前文件的路徑
LOCAL_MODULE:=這個模塊的名字,LOCAL_MODULE變量必須定義,以標識你在Android.mk文件中描述的每個模塊。名稱必須是唯一的,而且不包含任何空格。注意編譯系統會自動產生合適的前綴和後綴,換句話說,一個被命名爲'xxx'的共享庫模塊,將會生成'libxxx.so'文件。
LOCAL_MODULE_CLASS:=決定編譯時的中間文件存放的位置;
LOCAL_MODULE_SUFFIX:=預編譯程序模塊的後綴;
LOCAL_MODULE_TAGS:= user/eng/tests/optional默認爲optional:
- user: 指該模塊只在user版本下才編譯
- eng: 指該模塊只在eng版本下才編譯
- tests: 指該模塊只在tests版本下才編譯
- optional:指該模塊在所有版本下都編譯
如果兩次make之間選了不同的編譯模式,則需要運行一下make installclean,確保本次make不會用到上次install的文件,也可以運行make clean,不過耗時較長。
LOCAL_SRC_FILES:=要編譯的源代碼文件列表,多個文件見用空格或Tab間隔,換行用\,追加用LOCAL_SRC_FILES+=.變量必須包含將要編譯打包進模塊中的C或C++源代碼文件。注意,你不用在這裏列出頭文件和包含文件,因爲編譯系統將會自動爲你找出依賴型的文件;僅僅列出直接傳遞給編譯器的源代碼文件就好。可以LOCAL_SRC_FILES := $(call all-subdir-java-files)這種形式來包含LOCAL_PATH目錄下的所有java文件;
LOCAL_PRELINK_MODULE:= 是否需要預連接處理(默認需要,用來做動態庫優化);
LOCAL_REQUIRED_MODULES:= 指定模塊運行所依賴的模塊(模塊安裝時將會同步安裝它所依賴的模塊);
LOCAL_CERTIFICATE:=簽名認證類型,默認爲testkey。如果需要系統簽名就等於platform,如果不需要就等於PRESIGNED;
LOCAL_C_INCLUDES: 可選變量,表示頭文件的搜索路徑。默認的頭文件的搜索路徑是LOCAL_PATH目錄;
LOCAL_STATIC_LIBRARIES:= 該模塊需要使用的靜態鏈接庫(*.a)的名字;
LOCAL_SHARED_LIBRARIES:= 模塊在運行時需要用到的動態鏈接庫(*.so)的名稱;
LOCAL_COPY_HEADERS:= 安裝應用程序時需要複製的頭文件,必須同時定義LOCAL_COPY_HEADERS_TO;
LOCAL_COPY_HEADERS_TO:= 安裝應用程序時複製頭文件的目的路徑;
LOCAL_OVERRIDES_PACKAGES:=使其他的模塊不加入編譯:
如:DeskClock模塊的源碼中的android.mk有
LOCAL_OVERRIDES_PACKAGES := AlarmClock
使AlarmClock不會加入到編譯系統中,不會生成 AlarmClock.apk。(如果兩個模塊互相override對方,結果會怎樣?應該是先編譯到的模塊屏蔽另一個模塊);
LOCAL_BUILT_MODULE :=表示編譯鏈接後的目標文件(文件路徑+文件名);
LOCAL_BUILT_MODULE := $(built_module_path)/$(LOCAL_BUILT_MODULE_STEM);
LOCAL_BUILT_MODULE_STEM:= 表示編譯鏈接後的目標文件的文件名,帶後綴;
LOCAL_PACKAGE_NAME :=應用程序APK的名字;
LOCAL_MODULE_PATH和LOCAL_UNSTRIPPED_PATH來指定最後的目標安裝路徑。不同的文件系統路徑用以下的宏進行選擇:
1. TARGET_ROOT_OUT:表示根文件系統out/target/product/xxxxx/root。
2. TARGET_OUT:表示system文件系統out/target/product/xxxx/system。
3. TARGET_OUT_DATA:表示data文件系統out/target/product/xxxx/data。
4. TARGET_OUT_SHARED_LIBRARIES:表示out/target/product/xxxx/system/lib
5. TARGET_OUT_APPS:表示out/target/product/xxxx/system/app
6. ANDROID_PRODUCT_OUT:out/target/product/xxxx/
7. TARGET_OUT_JAVA_LIBRARIES:out/target/product/xxxx/system/framework
用法如:
LOCAL_MODULE_PATH:=$(TARGET_ROOT_OUT)
- LOCAL_JNI_SHARED_LIBRARIES:定義了要包含的so庫文件的名字,如果程序沒有采用jni,不需要
LOCAL_JNI_SHARED_LIBRARIES := libxxx
- LOCAL_CFLAGS:= 可選的編譯器選項,在編譯 C 代碼文件的時候使用。這可能是有用的,指定一個附加的包含路徑(相對於NDK的頂層目錄),宏定義,或者編譯選項。注意:不要在 Android.mk 中改變 optimization/debugging 級別,只要在 Application.mk 中指定合適的信息,就會自動地爲你處理這個問題,在調試期間,會讓NDK自動生成有用的數據文件。LOCAL_CFLAGS += -Dxxx這個就是你在源碼定義的宏,需要定義的話就在這個參數上加上-Dxxx,前面加"-D",後面就是宏的名稱了。
- LOCAL_LDLIBS:= 編譯模塊時要使用的附加的鏈接器選項。這對於使用‘-l’前綴傳遞指定庫的名字是有用的。
例如,LOCAL_LDLIBS := -lz表示告訴鏈接器生成的模塊要在加載時刻鏈接到/system/lib/libz.so(z是mk中定義的module name)
- LOCAL_INSTALLED_MODULE:= 表示模塊的安裝路徑+文件名,存放的安裝目錄
- LOCAL_PRIVILEGED_MODULE := true,以聲明app需要放在/system/priv-app下。
示例:
#編譯靜態庫
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE = libhellos
LOCAL_CFLAGS = $(L_CFLAGS)
LOCAL_SRC_FILES = hellos.c
LOCAL_C_INCLUDES = $(INCLUDES)
LOCAL_SHARED_LIBRARIES := libcutils
LOCAL_COPY_HEADERS_TO := libhellos
LOCAL_COPY_HEADERS := hellos.h
include $(BUILD_STATIC_LIBRARY)
#編譯動態庫
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE = libhellod
LOCAL_CFLAGS = $(L_CFLAGS)
LOCAL_SRC_FILES = hellod.c
LOCAL_C_INCLUDES = $(INCLUDES)
LOCAL_SHARED_LIBRARIES := libcutils
LOCAL_COPY_HEADERS_TO := libhellod
LOCAL_COPY_HEADERS := hellod.h
include $(BUILD_SHARED_LIBRARY)
#使用靜態庫
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := hellos
LOCAL_STATIC_LIBRARIES := libhellos
LOCAL_LDLIBS += -ldl
LOCAL_CFLAGS := $(L_CFLAGS)
LOCAL_SRC_FILES := mains.c
LOCAL_C_INCLUDES := $(INCLUDES)
include $(BUILD_EXECUTABLE)
#使用動態庫
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := hellod
LOCAL_MODULE_TAGS := debug
LOCAL_SHARED_LIBRARIES := libc libcutils libhellod
LOCAL_LDLIBS += -ldl
LOCAL_CFLAGS := $(L_CFLAGS)
LOCAL_SRC_FILES := maind.c
LOCAL_C_INCLUDES := $(INCLUDES)
include $(BUILD_EXECUTABLE)