Android.mk
文件是GNU Makefile的一小部分,它用來對Android程序進(jìn)行編譯叨襟。
因?yàn)樗械木幾g文件都在同一個 GNU MAKE 執(zhí)行環(huán)境中進(jìn)行執(zhí)行床蜘,而Android.mk中所有的變量都是全局的粥诫。因此油航,您應(yīng)盡量少聲明變量,不要認(rèn)為某些變量在解析過程中不會被定義怀浆。
一個Android.mk文件可以編譯多個模塊谊囚,
每個模塊屬下列類型之一:
1)APK程序
一般的Android程序怕享,編譯打包生成apk文件
2)JAVA庫
java類庫,編譯打包生成jar文件
3)C\C++應(yīng)用程序
可執(zhí)行的C\C++應(yīng)用程序
4)C\C++靜態(tài)庫
編譯生成C\C++靜態(tài)庫镰踏,并打包成.a文件
5)C\C++共享庫
編譯生成共享庫(動態(tài)鏈接庫)函筋,并打包成.so文, 有且只有共享庫才能被安裝/復(fù)制到您的應(yīng)用軟件(APK)包中奠伪〉剩可以在每一個Android.mk file 中定義一個或多個模塊,你也可以在幾個模塊中使用同一個源代碼文件绊率。 編譯系統(tǒng)為你處理許多細(xì)節(jié)問題谨敛。例如,你不需要在你的 Android.mk 中列出頭文件和依賴文件滤否。編譯系統(tǒng)將會為你自動處理這些問題脸狸。這也意味著,在升級 NDK 后藐俺,你應(yīng)該得到新的toolchain/platform支持炊甲,而且不需要改變你的 Android.mk 文件。
注意欲芹,NDK的Anroid.mk語法同公開發(fā)布的Android平臺開源代碼的Anroid.mk語法很接近卿啡,然而編譯系統(tǒng)實(shí)現(xiàn)他們的方式卻是不同的,這是故意這樣設(shè)計(jì)的菱父,可以讓程序開發(fā)人員重用外部庫的源代碼更容易牵囤。
在描述語法細(xì)節(jié)之前,咱們來看一個簡單的"hello world"的例子滞伟,比如,下面的文件:
sources/helloworld/helloworld.c
sources/helloworld/Android.mk
helloworld.c是一個 JNI 共享庫炕贵,實(shí)現(xiàn)返回"hello world"字符串的原生方法梆奈。相應(yīng)的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變量。它表示是當(dāng)前文件的路徑称开。
在這個例子中亩钟, 宏函數(shù)‘my-dir’, 由編譯系統(tǒng)提供, 用于返回當(dāng)前路徑(即包含Android.mk file文件的目錄)鳖轰。
include $(CLEAR_VARS)
CLEAR_VARS 由編譯系統(tǒng)提供(可以在 android 安裝目錄下的 /build/core/config.mk文件看到其定義清酥,為CLEAR_VARS:= $(BUILD_SYSTEM)/clear_vars.mk),指定讓GNU MAKEFILE該腳本為你清除許多LOCAL_XXX 變量 ( 例如 LOCAL_MODULE 蕴侣, LOCAL_SRC_FILES 焰轻,LOCAL_STATIC_LIBRARIES,等等…)昆雀,除 LOCAL_PATH辱志。這是必要的蝠筑,因?yàn)樗械木幾g文件都在同一個 GNU MAKE 執(zhí)行環(huán)境中,所有的變量都是全局的揩懒。所以我們需要先清空這些變量(LOCAL_PATH除外)什乙。又因?yàn)長OCAL_PATH總是要求在每個模塊中都要進(jìn)行設(shè)置,所以并需要清空它已球。另外
注意臣镣,該語句的意思就是把CLEAR_VARS變量所指向的腳本文件包含進(jìn)來。
LOCAL_MODULE := helloworld
LOCAL_MODULE 變量必須定義智亮,以標(biāo)識你在 Android.mk 文件中描述的每個模塊忆某。名稱必須是唯一的,而且不包含任何空格鸽素。注意編譯系統(tǒng)會自動產(chǎn)生合適的前綴和后綴褒繁,換句話說,一個被命名為'foo'的共享庫模塊馍忽,將會生成'libfoo.so'文件棒坏。
注意:如果把庫命名為‘libhelloworld’,編譯系統(tǒng)將不會添加任何的 lib 前綴遭笋,也會生成 libhelloworld.so坝冕。
LOCAL_SRC_FILES := helloworld.c
LOCAL_SRC_FILES 變量必須包含將要編譯打包進(jìn)模塊中的 C 或 C++源代碼文件。不用在這里列出頭文件和包含文件瓦呼,編譯系統(tǒng)將會自動找出依賴型的文件喂窟,當(dāng)然對于包含文件,你包含時指定的路徑應(yīng)該正確央串。
注意磨澡,默認(rèn)的 C++源碼文件的擴(kuò)展名是‘.cpp’ 。指定一個不同的擴(kuò)展名也是可能的质和,只要定義LOCAL_DEFAULT_CPP_EXTENSION 變量稳摄,不要忘記開始的小圓點(diǎn)(也就是定義為 ‘.cxx’,而不是‘cxx’)
include $(BUILD_SHARED_LIBRARY)
BUILD_SHARED_LIBRARY 是編譯系統(tǒng)提供的變量,指向一個 GNU Makefile 腳本(應(yīng)該就是在 build/core 目錄下的 shared_library.mk) 饲宿,將根據(jù)LOCAL_XXX系列變量中的值厦酬,來編譯生成共享庫(動態(tài)鏈接庫)。
如果想生成靜態(tài)庫瘫想,則用BUILD_STATIC_LIBRARY在NDK的sources/samples目錄下有更復(fù)雜一點(diǎn)的例子仗阅,寫有注釋的 Android.mk 文件。
二国夜、自定義變量
以下是在 Android.mk中依賴或定義的變量列表减噪, 可以定義其他變量為自己使用,但是NDK編譯系統(tǒng)保留下列變量名:
- 以 LOCAL_開頭的名字(例如 LOCAL_MODULE)
- 以 PRIVATE_, NDK_ 或 APP_開頭的名字(內(nèi)部使用)
- 小寫名字(內(nèi)部使用,例如‘my-dir’)
如果為了方便在 Android.mk 中定義自己的變量旋廷,建議使用 MY_前綴鸠按,一個小例子:
MY_SOURCES := foo.c
ifneq ($(MY_CONFIG_BAR),)
MY_SOURCES += bar.c
endif
LOCAL_SRC_FILES += $(MY_SOURCES)
注意:‘:=’是賦值的意思;'+='是追加的意思饶碘;‘(CLEAR_VARS)烦衣,用于重置除LOCAL_PATH變量外的,所有LOCAL_XXX系列變量掩浙。
(2)BUILD_SHARED_LIBRARY: 指向編譯腳本花吟,根據(jù)所有的在 LOCAL_XXX 變量把列出的源代碼文件編譯成一個共享庫。
注意厨姚,必須至少在包含這個文件之前定義 LOCAL_MODULE 和 LOCAL_SRC_FILES衅澈。
(3) BUILD_STATIC_LIBRARY: 一個 BUILD_SHARED_LIBRARY 變量用于編譯一個靜態(tài)庫。靜態(tài)庫不會復(fù)制到的APK包中谬墙,但是能夠用于編譯共享庫今布。
示例:include $(BUILD_STATIC_LIBRARY)
注意,這將會生成一個名為 lib$(LOCAL_MODULE).a
的文件
(4)TARGET_ARCH: 目標(biāo) CPU平臺的名字, 和 android 開放源碼中指定的那樣拭抬。如果是arm部默,表示要生成 ARM 兼容的指令,與 CPU架構(gòu)的修訂版無關(guān)造虎。
(5)TARGET_PLATFORM: Android.mk 解析的時候甩牺,目標(biāo) 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累奈。在現(xiàn)在的版本中一般把這兩個值簡單的定義為 arm, 通過 android 平臺內(nèi)部對它重定義來獲得更好的匹配急但。其他的 ABI 將在以后的 NDK 版本中介紹澎媒,它們會有不同的名字。注意雖然所有基于ARM的ABI都會把 'TARGET_ARCH'定義成‘a(chǎn)rm’波桩, 但是會有不同的‘TARGET_ARCH_ABI’戒努。
(7) TARGET_ABI: 目標(biāo)平臺和 ABI 的組合,它事實(shí)上被定義成(TARGET_ARCH_ABI) ,在想要在真實(shí)的設(shè)備中針對一個特別的目標(biāo)系統(tǒng)進(jìn)行測試時储玫,會有用侍筛。在默認(rèn)的情況下,它會是'android-3-arm'撒穷。
五匣椰、模塊描述變量
下面的變量用于向編譯系統(tǒng)描述你的模塊。你應(yīng)該定義在'include (BUILD_XXXXX)'之間端礼。正如前面描寫的那樣禽笑,(call my-dir) 這個變量不會被(BUILD_XXXX)腳本之前定義它。模塊的名字決定了生成文件的名字拷恨。例如脖律,如果一個一個共享庫模塊的名字是,那么生成文件的名字就是 lib.so腕侄。但是小泉,在的 NDK 生成文件中(或者 Android.mk 或者 Application.mk),應(yīng)該只涉及(引用)有正常名字的其他模塊冕杠。
(3)LOCAL_SRC_FILES: 這是要編譯的源代碼文件列表微姊。只要列出要傳遞給編譯器的文件,因?yàn)榫幾g系統(tǒng)自動計(jì)算依賴分预。注意源代碼文件名稱都是相對于 LOCAL_PATH的兢交,你可以使用路徑部分,例如:
LOCAL_SRC_FILES := foo.c toto/bar.c\
Hello.c
文件之間可以用空格或Tab鍵進(jìn)行分割,換行請用"".如果是追加源代碼文件的話笼痹,請用LOCAL_SRC_FILES+=
注意:在生成文件中都要使用UNIX風(fēng)格的斜杠(/).windows風(fēng)格的反斜杠不會被正確的處理配喳。
注意:可以LOCAL_SRC_FILES := (LOCAL_PATH)/../foo`
LOCAL_C_INCLUDES需要在任何包含LOCAL_CFLAGS/LOCAL_CPPFLAGS標(biāo)志之前進(jìn)行設(shè)置。
(6)LOCAL_CFLAGS: 可選的編譯器選項(xiàng)泌绣,在編譯 C 代碼文件的時候使用钮追。這可能是有用的,指定一個附加的包含路徑(相對于NDK的頂層目錄)阿迈,宏定義元媚,或者編譯選項(xiàng)。
注意:不要在 Android.mk 中改變 optimization/debugging 級別仿滔,只要在 Application.mk 中指定合適的信息惠毁,就會自動地為你處理這個問題,在調(diào)試期間崎页,會讓 NDK自動生成有用的數(shù)據(jù)文件鞠绰。
(7)LOCAL_CXXFLAGS: 與 LOCAL_CFLAGS同理,針對 C++源文件飒焦。
(8)LOCAL_CPPFLAGS: 與 LOCAL_CFLAGS同理蜈膨,但是對 C 和 C++ source files都適
用。
(9)LOCAL_STATIC_LIBRARIES:表示該模塊需要使用哪些靜態(tài)庫牺荠,以便在編譯時進(jìn)行鏈接翁巍。
(10)LOCAL_SHARED_LIBRARIES: 表示模塊在運(yùn)行時要依賴的共享庫(動態(tài)庫),在鏈接時就需要休雌,以便在生成文件時嵌入其相應(yīng)的信息灶壶。注意:它不會附加列出的模塊到編譯圖,也就是仍然需要在Application.mk 中把它們添加到程序要求的模塊中杈曲。
(11)LOCAL_LDLIBS: 編譯模塊時要使用的附加的鏈接器選項(xiàng)驰凛。這對于使用‘-l’前綴傳遞指定庫的名字是有用的。
例如担扑,
LOCAL_LDLIBS := -lz
表示:告訴鏈接器生成的模塊要在加載時刻鏈接到/system/lib/libz.so恰响;可查看 docs/STABLE-APIS.TXT 獲取使用 NDK發(fā)行版能鏈接到的開放的系統(tǒng)庫列表。
(12) LOCAL_ALLOW_UNDEFINED_SYMBOLS: 默認(rèn)情況下涌献, 在試圖編譯一個共享庫時胚宦,任何未定義的引用將導(dǎo)致一個“未定義的符號”錯誤。這對于在源代碼文件中捕捉錯誤會有很大的幫助燕垃。然而枢劝,如果因?yàn)槟承┰颍枰粏舆@項(xiàng)檢查卜壕,可把這個變量設(shè)為‘true’呈野。
注意相應(yīng)的共享庫可能在運(yùn)行時加載失敗。(這個一般盡量不要去設(shè)為 true)印叁。
(13) LOCAL_ARM_MODE: 默認(rèn)情況下, arm目標(biāo)二進(jìn)制會以 thumb 的形式生成(16 位),你可以通過設(shè)置這個變量為 arm如果你希望你的 module 是以 32 位指令的形式轮蜕。
'arm' (32-bit instructions) mode. E.g.:
LOCAL_ARM_MODE := arm
注意:可以在編譯的時候告訴系統(tǒng)針對某個源碼文件進(jìn)行特定的類型的編譯
比如昨悼,LOCAL_SRC_FILES := foo.c bar.c.arm 這樣就告訴系統(tǒng)總是將 bar.c 以arm的模式編譯。
(14)LOCAL_MODULE_PATH 和 LOCAL_UNSTRIPPED_PATH
在 Android.mk 文件中跃洛, 還可以用
LOCAL_MODULE_PATH 和 LOCAL_UNSTRIPPED_PATH
指定最后的目標(biāo)安裝路徑.
不同的文件系統(tǒng)路徑用以下的宏進(jìn)行選擇:
TARGET_ROOT_OUT
:表示根文件系統(tǒng)率触。
TARGET_OUT
:表示 system文件系統(tǒng)。
TARGET_OUT_DATA
:表示 data文件系統(tǒng)汇竭。
用法如:LOCAL_MODULE_PATH :=$(TARGET_ROOT_OUT)
至于LOCAL_MODULE_PATH
和 LOCAL_UNSTRIPPED_PATH
的區(qū)別葱蝗,暫時還不清楚。
七细燎、GNU Make‘功能’宏
GNU Make‘功能’宏两曼,必須通過使用'(call my-dir)`
(2)all-subdir-makefiles: 返回一個位于當(dāng)前'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)
那么它就會自動包含 sources/foo/lib1/Android.mk 和 sources/foo/lib2/Android.mk嗤锉。
這項(xiàng)功能用于向編譯系統(tǒng)提供深層次嵌套的代碼目錄層次渔欢。
注意,在默認(rèn)情況下瘟忱,NDK 將會只搜索在 sources/*/Android.mk 中的文件奥额。
(3)this-makefile: 返回當(dāng)前Makefile 的路徑(即這個函數(shù)調(diào)用的地方)
(4)parent-makefile: 返回調(diào)用樹中父 Makefile 路徑。即包含當(dāng)前Makefile的Makefile 路徑酷誓。
(5)grand-parent-makefile:返回調(diào)用樹中父Makefile的父Makefile的路徑
八披坏、 Android.mk 使用模板
在一個 Android.mk 中可以生成多個APK應(yīng)用程序,JAVA庫盐数,C\C++可執(zhí)行程序,C\C++動態(tài)庫和C\C++靜態(tài)庫棒拂。
(1)編譯APK應(yīng)用程序模板。
關(guān)于編譯APK應(yīng)用程序的模板請參照
《Android.mk編譯APK范例》
(2)編譯JAVA庫模板
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
# Build all java files in the java subdirectory
LOCAL_SRC_FILES := $(call all-subdir-java-files)
# Any libraries that this library depends on
LOCAL_JAVA_LIBRARIES := android.test.runner
# The name of the jar file to create
LOCAL_MODULE := sample
# Build a static jar file.
include $(BUILD_STATIC_JAVA_LIBRARY)
注:LOCAL_JAVA_LIBRARIES := android.test.runner表示生成的JAVA庫的jar文件名
(3)編譯C/C++應(yīng)用程序模板如下
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
中加入所需要鏈接的靜態(tài)庫(*.a
)的名稱
LOCAL_SHARED_LIBRARIES
中加入所需要鏈接的動態(tài)庫(*.so
)的名稱
LOCAL_MODULE
表示模塊最終的名稱
BUILD_EXECUTABLE
表示以一個可執(zhí)行程序的方式進(jìn)行編譯
(4)編譯C\C++靜態(tài)庫
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
表示編譯一個靜態(tài)庫漾峡。
(5)編譯C\C++動態(tài)庫的模板
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
表示編譯一個共享庫。以上三者的生成結(jié)果分別在如下目錄中生逸,generic 依具體 target 會變:
out/target/product/generic/obj/APPS
out/target/product/generic/obj/JAVA_LIBRARIES
out/target/product/generic/obj/EXECUTABLE
out/target/product/generic/obj/STATIC_LIBRARY
out/target/product/generic/obj/SHARED_LIBRARY
每個模塊的目標(biāo)文件夾分別為:
1)APK程序:XXX_intermediates
2)JAVA庫程序:XXX_intermediates
3)C\C++可執(zhí)行程序:XXX_intermediates
4)C\C++靜態(tài)庫: XXX_static_intermediates
5)C\C++動態(tài)庫: XXX_shared_intermediates