Android.mk文檔規範
Android.mk 編譯文件是用來向 Android NDK描述你的 C,C++源代碼文件的, 這篇文檔描
述了它的語法。在閱讀下面的內容以前,假定你已經閱讀了 docs/OVERVIEW.TXT 文件,瞭解
了它們的腳色和用途。
1、概述
一個 Android.mk file 用來向編譯系統描述你的源代碼。具體來講:
(1) 該文件是GNU Makefile的一小部分, 會被編譯系統解析一次或更屢次的build系統。
所以,您應儘可能減小您聲明的變量,不要認爲某些變量在解析過程當中不會被定義。
(2)這個文件的語法容許把你的源代碼組織成模塊,一個模塊屬下列類型之一:
1)靜態庫
2)共享庫
且只有共享庫將被安裝/複製到您的應用軟件包,雖然靜態庫能被用於生成共享庫。
能夠在每個 Android.mk file 中定義一個或多個模塊, 你也能夠在幾個模塊中使用同一個
源代碼文件。
編譯系統爲你處理許多細節問題。例如,你不須要在你的 Android.mk 中列出頭文件和依
賴文件。NDK 編譯系統將會爲你自動處理這些問題。這也意味着,在升級 NDK 後,你應該
獲得新的 toolchain/platform支持,並且不須要改變你的 Android.mk 文件。
注意,這個語法同公開發布的 Android平臺的開源代碼很接近,然而編譯系統實現他們的
方式倒是不一樣的,這是故意這樣設計的,可讓程序開發人員重用外部庫的源代碼更容易。
在描述語法細節以前,我們來看一個簡單的"hello world"的例子,好比,下面的文件:
sources/helloworld/helloworld.c
sources/helloworld/Android.mk
'helloworld.c'是一個 JNI 共享庫,實現返回"hello world"字符串的原生方法。相應的
Android.mk 文件會象下面這樣:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE:= helloworld
LOCAL_SRC_FILES := helloworld.c
include $(BUILD_SHARED_LIBRARY)
解釋一下這幾行代碼:
LOCAL_PATH := $(call my-dir)
一個Android.mk file首先必須定義好LOCAL_PATH變量。 它用於在開發樹中查找源文件。
在這個例子中, 宏函數‘my-dir’, 由編譯系統提供, 用於返回當前路徑(即包含Android.mk file
文件的目錄)。
include $(CLEAR_VARS)
CLEAR_VARS 由編譯系統提供(能夠在 android 安裝目錄下的/build/core/config.mk 文件看
到其定義,爲 CLEAR_VARS:= $(BUILD_SYSTEM)/clear_vars.mk),指定讓 GNU MAKEFILE
爲你清除許多 LOCAL_XXX 變量 ( 例如 LOCAL_MODULE , LOCAL_SRC_FILES , Android.mk 文檔規範 2
LOCAL_STATIC_LIBRARIES,等等…),除 LOCAL_PATH。這是必要的,由於全部的編譯控
制文件都在同一個 GNU MAKE 執行環境中,全部的變量都是全局的。
LOCAL_MODULE := helloworld
LOCAL_MODULE 變量必須定義,以標識你在 Android.mk 文件中描述的每一個模塊。名稱
必須是惟一的,並且不包含任何空格。注意編譯系統會自動產生合適的前綴和後綴,換句話
說,一個被命名爲'foo'的共享庫模塊,將會生成'libfoo.so'文件。注意:若是把庫命名爲
‘libhelloworld’,編譯系統將不會添加任何的 lib 前綴,也會生成 libhelloworld.so,這是
爲了支持來源於 Android平臺的源代碼的 Android.mk 文件。
LOCAL_SRC_FILES := helloworld.c
LOCAL_SRC_FILES 變量必須包含將要編譯打包進模塊中的 C 或 C++源代碼文件。不用
在這裏列出頭文件和包含文件,編譯系統將會自動找出依賴型的文件。
【注意,默認的 C++源碼文件的擴展名是‘.cpp’ 。指定一個不一樣的擴展名也是可能的,只要定義
LOCAL_DEFAULT_CPP_EXTENSION 變量,不要忘記開始的小圓點(也就是定義爲 ‘.cxx’,而不是‘cxx’)】
include $(BUILD_SHARED_LIBRARY)
BUILD_SHARED_LIBRARY 是編譯系統提供的變量,指向一個 GNU Makefile 腳本(應該
就是在 build/core 目錄下的 shared_library.mk) ,負責收集自從上次調用 'include
$(CLEAR_VARS)'以來,定義在 LOCAL_XXX 變量中的全部信息,而且決定編譯什麼,如何正
確地去作。並根據其規則生成靜態庫。同理對於靜態庫。
在 sources/samples目錄下有更復雜一點的例子,寫有註釋的 Android.mk 文件。
2、參考
這是一份你應該在 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)
1. GNU Make 變量
這些 GNU Make 變量在你的 Android.mk 文件解析以前,就由編譯系統定義好了。注意在
某些狀況下,NDK可能分析 Android.mk 幾回,每一次某些變量的定義會有不一樣。
(1)CLEAR_VARS: 指向一個編譯腳本,幾乎全部未定義的 LOCAL_XXX 變量都在
"Module-description"節中列出。必須在開始一個新模塊以前包含這個腳本:include
$(CLEAR_VARS)
(2)BUILD_SHARED_LIBRARY: 指向編譯腳本,收集全部的在 LOCAL_XXX 變量中提
供的信息,而且決定如何把列出的源代碼文件編譯成一個共享庫。注意,必須至少在包含這
個文件以前定義 LOCAL_MODULE 和 LOCAL_SRC_FILES。使用例子: Android.mk 文檔規範 3
include $(BUILD_SHARED_LIBRARY)
#這將生成一個名爲 lib$(LOCAL_MODULE).so 的文件
(3) BUILD_STATIC_LIBRARY: 一個 BUILD_SHARED_LIBRARY 變量用於編譯一個靜
態庫。靜態庫不會複製到的 project/packages 中,可是可以用於編譯共享庫, (看下面描述的
LOCAL_STATIC_LIBRARIES and LOCAL_STATIC_WHOLE_LIBRARIES) 。使用例子:
include $(BUILD_STATIC_LIBRARY)
#注意,這將會生成一個名爲 lib$(LOCAL_MODULE).a 的文件
(4)TARGET_ARCH: 目標 CPU平臺的名字, 和 android 開放源碼中指定的那樣。若是是
arm,表示要生成 ARM 兼容的指令,與 CPU架構的修訂版無關。
(5)TARGET_PLATFORM: Android.mk 解析的時候,目標 Android 平臺的名字.詳情可參
考/development/ndk/docs/stable- apis.txt.
android-3 -> Official Android 1.5 system images
android-4 -> Official Android 1.6 system images
android-5 -> Official Android 2.0 system images
(6)TARGET_ARCH_ABI: 暫時只支持兩個 value,armeabi 和 armeabi-v7a。在
如今的版本中通常把這兩個值簡單的定義爲 arm, 經過 android 平臺內部對它重定義來得到更
好的匹配。其餘的 ABI 將在之後的 NDK 版本中介紹,它們會有不一樣的名字。注意全部基於
ARM 的 ABI都會把 'TARGET_ARCH'定義成‘arm’, 可是會有不一樣的‘TARGET_ARCH_ABI’。
( 7 ) TARGET_ABI: 目標平臺和 ABI 的組合,它事實上被定義成
$(TARGET_PLATFORM)-$(TARGET_ARCH_ABI) ,在想要在真實的設備中針對一個特別的
目標系統進行測試時,會有用。在默認的狀況下,它會是'android-3-arm'。
2. 模塊描述變量
下面的變量用於向編譯系統描述你的模塊。你應該定義在'include $(CLEAR_VARS)'
和'include $(BUILD_XXXXX)'之間。正如前面描寫的那樣,$(CLEAR_VARS)是一個腳
本,清除全部這些變量,除非在描述中顯式註明。
(1) LOCAL_PATH: 這個變量用於給出當前文件的路徑。必須在 Android.mk 的開頭定
義,能夠這樣使用:
LOCAL_PATH := $(call my-dir)
這個變量不會被$(CLEAR_VARS)清除,所以每一個 Android.mk 只須要定義一次(即便在一
個文件中定義了幾個模塊的狀況下)。
(2)LOCAL_MODULE: 這是模塊的名字,它必須是惟一的,並且不能包含空格。必須在
包含任一的$(BUILD_XXXX)腳本以前定義它。模塊的名字決定了生成文件的名字。例如,如
果一個一個共享庫模塊的名字是,那麼生成文件的名字就是 lib.so。可是,在的 NDK 生成文
件中(或者 Android.mk 或者 Application.mk),應該只涉及(引用)有正常名字的其餘模塊。
(3)LOCAL_SRC_FILES: 這是要編譯的源代碼文件列表。只要列出要傳遞給編譯器的
文件,由於編譯系統自動計算依賴。注意源代碼文件名稱都是相對於 LOCAL_PATH的,你可
以使用路徑部分,例如:
LOCAL_SRC_FILES := foo.c
toto/bar.c
【注意:在生成文件中都要使用UNIX風格的斜槓(/).windows風格的反斜槓不會被正確的處理。 】 Android.mk 文檔規範 4
(4) LOCAL_CPP_EXTENSION: 這是一個可選變量, 用來指定C++代碼文件的擴展名,
默認是'.cpp',可是能夠改變它,好比:
LOCAL_CPP_EXTENSION := .cxx
(5) LOCAL_C_INCLUDES: 路徑的可選配置,是從根目錄開始的全部源文件(C, C++
and Assembly)。好比:
LOCAL_C_INCLUDES := sources/foo
或者:
LOCAL_C_INCLUDES := $(LOCAL_PATH)/../foo
須要在任何包含 LOCAL_CFLAGS/LOCAL_CPPFLAGS 標誌以前。
(6)LOCAL_CFLAGS: 可選的編譯器選項,在編譯 C 代碼文件的時候使用。這多是有
用的,指定一個附加的包含路徑(相對於 NDK的頂層目錄),宏定義,或者編譯選項。
注意:不要在 Android.mk 中改變 optimization/debugging 級別,只要在 Application.mk 中
指定合適的信息,就會自動地爲你處理這個問題,在調試期間,會讓 NDK自動生成有用的數
據文件。
(7)LOCAL_CXXFLAGS: 與 LOCAL_CFLAGS 相同,針對 C++源文件。
(8)LOCAL_CPPFLAGS: 與 LOCAL_CFLAGS 相同,可是對 C 和 C++ source files都適
用。
(9)LOCAL_STATIC_LIBRARIES: 應該連接到這個模塊的靜態庫列表(使用
BUILD_STATIC_LIBRARY 生成),這僅僅對共享庫模塊纔有意義。
(10)LOCAL_SHARED_LIBRARIES: 這個模塊在運行時要依賴的共享庫模塊列表,在
連接時須要,在生成文件時嵌入的相應的信息。注意:這不會附加列出的模塊到編譯圖,也
就是仍然須要在 Application.mk 中把它們添加到程序要求的模塊中。
(11)LOCAL_LDLIBS: 編譯模塊時要使用的附加的連接器選項。這對於使用‘-l’前綴
傳遞指定庫的名字是有用的。例如,下面將告訴連接器生成的模塊要在加載時刻連接到
/system/lib/libz.so
LOCAL_LDLIBS := -lz
可查看 docs/STABLE-APIS.TXT 獲取使用 NDK發行版能連接到的開放的系統庫列表。
(12) LOCAL_ALLOW_UNDEFINED_SYMBOLS: 默認狀況下, 在試圖編譯一個共享庫時,
任何未定義的引用將致使一個「未定義的符號」錯誤。這對於在源代碼文件中捕捉錯誤會有
很大的幫助。然而,若是由於某些緣由,須要不啓動這項檢查,可把這個變量設爲‘true’。
注意相應的共享庫可能在運行時加載失敗。(這個通常儘可能不要去設爲 true)。
(13) LOCAL_ARM_MODE: 默認狀況下, arm目標二進制會以 thumb 的形式生成(16 位),
你能夠經過設置這個變量爲 arm若是你但願你的 module 是以 32 位指令的形式。
'arm' (32-bit instructions) mode. E.g.:
LOCAL_ARM_MODE := arm
【注意:一樣能夠在編譯的時候告訴系統編譯特定的類型】
Android.mk 文檔規範 5
(14)LOCAL_SRC_FILES := foo.c bar.c.arm 這樣就告訴系統老是將 bar.c 以
arm的模式編譯,下面是 GNU Make‘功能’宏,必須經過使用'$(call )'來求值,他們返
迴文本化的信息。
(15)my-dir:返回當前 Android.mk 所在的目錄路徑,相對於 NDK 編譯系統的頂層。
這是有用的,在 Android.mk 文件的開頭如此定義:
LOCAL_PATH := $(call my-dir)
(16)all-subdir-makefiles: 返回一個位於當前'my-dir'路徑的子目錄列表。例
如,看下面的目錄層次:
sources/foo/Android.mk
sources/foo/lib1/Android.mk
sources/foo/lib2/Android.mk
若是 sources/foo/Android.mk 包含一行:
include $(call all-subdir-makefiles)
那麼它就會自動包含 sources/foo/lib1/Android.mk 和 sources/foo/lib2/Android.mk。這項功
能用於向編譯系統提供深層次嵌套的代碼目錄層次。注意,在默認狀況下,NDK 將會只搜索
在 sources/*/Android.mk 中的文件。
(17)this-makefile: 返回當前Makefile 的路徑(即這個函數調用的地方)
(18)parent-makefile: 返回調用樹中父 Makefile 路徑。即包含當前 Makefile 的
Makefile 路徑。
(19)grand-parent-makefile
3. Android.mk 使用模板
在一個 Android.mk 中能夠生成多個可執行程序、動態庫和靜態庫。
(1)編譯應用程序的模板:
#Test Exe
LOCAL_PATH := $(call my-dir)
#include $(CLEAR_VARS)
LOCAL_SRC_FILES := main.c
LOCAL_MODULE := test_exe
#LOCAL_C_INCLUDES :=
#LOCAL_STATIC_LIBRARIES :=
#LOCAL_SHARED_LIBRARIES :=
include $(BUILD_EXECUTABLE)
【注:‘:=’是賦值的意思,‘$’是引用某變量的值】
LOCAL_SRC_FILES 中加入源文件路徑,LOCAL_C_INCLUDES 中加入所須要包含的頭
文件路徑,LOCAL_STATIC_LIBRARIES 加入所須要連接的靜態庫(*.a)的名稱,
LOCAL_SHARED_LIBRARIES 中加入所須要連接的動態庫(*.so)的名稱,LOCAL_MODULE Android.mk 文檔規範 6
表示模塊最終的名稱,BUILD_EXECUTABLE 表示以一個可執行程序的方式進行編譯。
(2)編譯靜態庫的模板:
#Test Static Lib
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_SRC_FILES := \
helloworld.c
LOCAL_MODULE:= libtest_static
#LOCAL_C_INCLUDES :=
#LOCAL_STATIC_LIBRARIES :=
#LOCAL_SHARED_LIBRARIES :=
include $(BUILD_STATIC_LIBRARY)
和上面類似,BUILD_STATIC_LIBRARY 表示編譯一個靜態庫。
(3)編譯動態庫的模板:
#Test Shared Lib
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_SRC_FILES := helloworld.c
LOCAL_MODULE := libtest_shared
TARGET_PRELINK_MODULES := false
#LOCAL_C_INCLUDES :=
#LOCAL_STATIC_LIBRARIES :=
#LOCAL_SHARED_LIBRARIES :=
include $(BUILD_SHARED_LIBRARY)
和上面類似,BUILD_SHARED_LIBRARY 表示編譯一個共享庫。
以上三者的生成結果分別在以下目錄中,generic 依具體 target 會變:
out/target/product/generic/obj/EXECUTABLE
out/target/product/generic/obj/STATIC_LIBRARY
out/target/product/generic/obj/SHARED_LIBRARY
每一個模塊的目標文件夾分別爲:
1)可執行程序:XXX_intermediates
2)靜態庫: XXX_static_intermediates
3)動態庫: XXX_shared_intermediates
另外, 在 Android.mk 文件中, 還能夠指定最後的目標安裝路徑, 用 LOCAL_MODULE_PATH Android.mk 文檔規範 7
和 LOCAL_UNSTRIPPED_PATH 來指定。不一樣的文件系統路徑用如下的宏進行選擇:
TARGET_ROOT_OUT:表示根文件系統。
TARGET_OUT:表示 system文件系統。
TARGET_OUT_DATA:表示 data文件系統。
用法如:
LOCAL_MODULE_PATH :=$(TARGET_ROOT_OUT) android