android.mk主要描述了c或者c++文件時如何在ndk工程中被使用的,該小節主要描述了android.mk的構建規則html
編譯器僅僅安裝/拷貝動態庫到你的apk包中去。此外,靜態庫能夠生成動態庫android
在每一個android.mk文件中能夠定義一個或多個模塊,在多個模塊中能夠共用一個源文件c++
一樣的,當更新到新發布的NDK後,不須要修改android.mk文件就能夠自動使用新的工具鏈/平臺進行編譯windows
注意此語法很是接近完整的安卓開源項目中andriod.mk語法,可是編譯器是以不一樣的方式執行的。爲了讓開發者更容易得重複使用編譯底層庫的源文件,它們被有意的設計成相似格式。安全
在詳細描述語法以前,有必要考慮一下Hello_JNI中的Android.mk架構
---------- cut here ------------------ LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE := hello-jni LOCAL_SRC_FILES := hello-jni.c include $(BUILD_SHARED_LIBRARY) ---------- cut here ------------------
如今,仔細分析每一行的意義函數
LOCAL_PATH := $(call my-dir)
一個Android.ml文件必須以LOCAL_PATH變量的定義開頭,該變量主要用來定位源碼位置。在這個例子中,宏定義「my-dir」由編譯器提供,它返回當前文件夾路徑(包含Android.mk的文件夾)工具
include $(CLEAR_VARS)
CLEAR_VARS變量由編譯器定義,它指定了一個特殊的GNU makefile文件,該文件會清除除了LOCAL_PATH以外的LOCAL_XXX變量(好比,LOCAL_MODULE,LOCAL_SRC_FILES,LOCAL_STATIC_LIBRARIES等)。全部的構建控制文件都會被解析到一個GNU構建運行上下文中,在這裏全部的變量都是全局的,所以該變量是頗有價值的。測試
LOCAL_MODULE := hello-jni
LOCAL_MODULE變量用來定義全部須要被定義的模塊名。模塊名必須是惟一的並且不能包含空格。注意編譯器會在生成的模塊名稱上添加前綴和後綴。好比一個叫‘foo’的模塊會生成‘libfoo.so’優化
注意:若是定義一個名爲「libfoo」的模塊,編譯器不會再次添加‘lib’前綴,一樣生成了‘libfoo.so’。
LOCAL_SRC_FILES := hello-jni.c
LOCAL_SRC_FILES變量包含了構建模塊所須要的全部C/C++源碼文件。由於編譯器自動計算了文件以來關係,所以在這裏不須要添加頭文件,只須要直接列出全部源文件便可。
注意默認c++文件的後綴名是「.cpp」。可使用LOCAL_CPP_EXTENSION變量來修改c++文件所使用的後綴,注意必定要加上「.」(正確:‘.cxx’,錯誤:‘cxx’)。
include $(BUILD_SHARED_LIBRARY)
BUILD_SHARED_LIBRARY是一個指向GNU makefile腳本的系統變量,該變量負責收集全部定義在LOCAL_XXX中的信息而且決定決定構建的目標和如何構建該目標。使用BUILD_STATIC__LIBRARY來生成靜態庫。
在ndk的sample目錄下你能夠查看更復雜的Android.mk文件。
下面列出的一些變量在Android.mk中是徹底可靠的。你能夠本身定義一些變量,可是NDK編譯器保留了這些關鍵字:
若是須要自定義變量,推薦使用「MY_「做爲前綴,例如:
---------- cut here ------------------ MY_SOURCES := foo.c ifneq ($(MY_CONFIG_BAR),) MY_SOURCES += bar.c endif LOCAL_SRC_FILES += $(MY_SOURCES) ---------- cut here ------------------
這些GNU Make變量在Android.mk文件被解析以前已經被定義了。注意在某些狀況下,NDK也許會在不一樣的GNU Make變量的定義下解析Android.mk好幾回
指向清除大部分定義在」Module-description」節下LOCAL_XXX變量的構建腳本。它必須包含在開始說明一個新模塊以前,使用實例:
include $(CLEAR_VARS)
指向收集全部LOCAL_XXX變量提供的信息而且決定如何由源碼文件構建動態庫的腳本文件。注意在使用該變量以前必須定義LOCAL_MODULE和LOCAL_SRC_FILE。使用說明:
include $(BUILD_SHARED_LIBRARY)
這會生成一個明文libXXX.so的文件。
BUILD_SHARED_LIBRARY是生成一個靜態庫的變種。靜態庫不會被拷貝/打包進apk包文件中,可是咱們可使用它來生成動態庫(參照下面LOCAL_STATIC_LIBRARY和LOCAL_WHOLE_STATIC_LIBRARY的描述)。使用說明:
include $(BUILD_STATIC_LIBRARY)
指向一個預編譯動態庫的構建腳本。和BUILD_SHARED_LIBRARY與BUILD_STATIC_LIBRARY不一樣,LOCAL_SRC_FILES只能是一個預編譯動態庫的路徑而不是源文件(例如:foo/libfoo.so)。
能夠在其餘模塊中使用LOCAL_PREBUILTS變量來引用該預編譯庫(詳細請參照NDK Prebuilt Library Support)
和PREBUILT_SHARED_LIBRARY相似,可是指定的是靜態庫。
目標CPU架構的名稱,對全部的arm兼容的編譯器來講目標架構名都是arm,獨立的CPU架構將會不一樣
目標Android平臺的名稱。例如android-3對應於Android 1.5
目標CPU和ABI的名稱,能夠指定如下的一個或多個值
armeabi For ARMv5TE armeabi-v7a For ARMv7 arm64-v8a For ARMv8 AArch64 x86 For i686 x86_64 For x86-64 mips For mips32 (r1) mips64 For mips64 (r6)
注意:到Android NDK 1.6_r1爲止,這個變量被定義爲‘arm’.然而,這個值在內部使用時會被重定義成與Android平臺更加匹配的值。
目標平臺和ABI之間的聯繫,它實際上被定義成由」-「鏈接,這將會在測試裝有指定系統文件的實體機上顯得頗有用。
默認的數值是」android-3-armeabi「
一下是GNU Make中的」函數」宏,必須以「$(call <function>)」的方式進行調用。返回文本的返回值。
返回最後包含的Makefile路徑,一般狀況下是當前Android.mk的路徑。它一般在Android.mk頭文件用來定LOCAL_PATH:
LOCAL_PATH := $(call my-dir)
提示:基於GNU Make的工做方式,他實際上返回的最後包含的Makefile文件路徑。不要在調用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以前,my-dir已經變成了$PATH/foo,因此第二個調用my-dir時會定義LOCAL_PATH爲$PATH/foo而不是$PATH。所以,最好把包含文件的操做放在全部內容以後,例如:
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` include $(LOCAL_PATH)/foo/`Android.mk`
若是這麼使用不方便,把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
返回當前‘my-dir’目錄下子目錄中全部包含「Android.mk」文件的路徑,假設有如下幾個文件
sources/foo/Android.mk
sources/foo/lib1/Android.mk
sources/foo/lib2/Android.mk
若是source/foo/Android.mk包含如下代碼
include $(call all-subdir-makefiles)
那麼就會自動包含sources/foo/lib1/Android.mk
和 sources/foo/lib2/Android.mk
該功能一般在有多層源碼目錄的工程中使用。注意,NDK只會查找sources/*/
Android.mk
返回當前Makefile的目錄(該函數被調用的makefile)
返回在包含樹中該Makefile的父Makefile文件。包含當前Makefile文件
猜猜這是啥
經過名稱來包含另一個模塊的Android.mk。一個典型的例子:
$(call import-module,<name>)
它會經過查找當前設置的NDK_MODULE_PATH環境變量來查找模塊,自動包含該模塊的Android.mk文件
如下的變量用來在編譯系統中描述自定義的模塊。能夠再兩個‘include’之間包含它們。正如前面所寫,除非明確得表示它們,一個腳本會所有清理掉它們。
該變量用來得到當前路徑,必須定義在Android.mk文件的開頭,例如:
LOCAL_PATH := $(call my-dir)
該變量不會被清理,因此只須要定義一次(也許你會在一個文件中定義多個模塊)
當前模塊的名稱。它的命名必須是惟一的,也不能包含空格。須要在定義在任何腳本以前。模塊名稱默認決定了生成文件的名稱,好比lib<foo>.so是<foo>生成的動態庫文件。可是你只須要在NDK編譯系統中的其餘文件中使用「正常」的名稱(好比<foo>),好比說Android.mk或者Application.mk
該變量是可選的,它容許你重命名生成文件的名稱。塊名稱默認決定了生成文件的名稱,好比lib<foo>.so是<foo>生成的動態庫文件。
你能夠經過定義LOCAL_MODULE_FILENAME來改變,例如:
LOCAL_MODULE := foo-version-1
LOCAL_MODULE_FILENAME := libfoo
注意:不能把一個文件的路徑或者後綴定義到LOCAL_MODULE_FILENAME中,這些會由編譯系統自動添加。
列出全部編譯模塊所須要的源碼。在編譯器計算出依賴關係以前,只有列出的文件纔會參與編譯。
注意:全部文件都是在LOCAL_PATH目錄下的,能夠添加子目錄中的文件。例如:
LOCAL_SRC_FILES := foo.c \
toto/bar.c
也可使用絕對路徑。例如:
LOCAL_SRC_FILES := /home/user/mysources/foo.c
windows平臺:
LOCAL_SRC_FILES := c:/Users/user/sources/foo.c
爲了讓開發環境可以更好得移植,最好不要使用絕對路徑
注意:Unix風格一般使用斜槓(/)做爲路徑分隔符。windows風格的反斜槓不必定可以被很好得支持。
自定義C++文件的後綴名。必須以」.「開頭,默認的後綴名是」cpp「,舉例:
LOCAL_CPP_EXTENSION := .cxx
NDK r7之後,能夠定義多個後綴名:
LOCAL_CPP_EXTENSION := .cxx .cpp .cc
該可選變量能夠指定特定C++特性。若是你的代碼使用RTTI特性,能夠定義:
LOCAL_CPP_FEATURES := rtti
顯示代碼使用異常處理:
LOCAL_CPP_FEATURES := exceptions
能夠同時定義多個特性(順序無關)
LOCAL_CPP_FEATURES := rtti features
該變量能夠在編譯模塊時正確得設置編譯/連接的標誌。該變量能夠保證進行正確的來連接生成二進制文件。
推薦使用該變量來替代在LOCAL_CPPFLAGS中直接定義 -frtti和-fexceptions
包含文件路徑的可選變量,該路徑會在編譯時添加到包含目錄下,例如:
LOCAL_C_INCLUDES := sources/foo
甚至這樣也是能夠的:
LOCAL_C_INCLUDES := $(LOCAL_PATH)/../foo
這些定義被放在LOCAL_CFLAGS/LOCAL_CPPFLAGS以前
LOCAL_C_INCLUDE路徑也被用在自動使用ndk-gdb調試之中。
LOCAL_CFLAGS
可選的編譯標識,也能夠用來添加額外的宏定義或者編譯選項。
重要:不要修改任何Android.mk中的優化、調試級別,這些會在指定Andorid.mk文件中的目標信息時自動化處理,ndk也會在調試時自動生成調試文件。
注意:在android-ndk-1.5_r1中,只在C源代碼中產生做用(如今可使用LOCAL_CPPFLAG來指定編譯選項)。
可使用LOCAL_CFLAGS+=-I<path>來指定附加包含目錄。因爲ndk-gdb會使用該路徑,最好使用LOCAL_C_INCLUDES來實現該功能。
LOCAL_CPPFLAG的別名,注意該變量可能在將來的NDK版本中被拋棄。
在編譯C++源碼時的一個可選編譯選項的變量。該變量會出如今LOCAL_CFLAGS以後
注意:在android-ndk-1.5-r1中,該變量適用於C和C++格式的源碼。(如今也可使用LOCAL_CFLAGS來指定全部C/C++源碼編譯選項)
列出全部當前模塊因此來的靜態庫。
若是當前模塊時一個動態庫或者可運行文件,這些靜態庫會被強制鏈接到生成的二進制文件中。
若是當前文件是一個靜態庫,僅僅會通知其餘模塊該模塊會依賴這些列出的靜態庫
列出該模塊在運行時所依賴的動態庫。他會在連接時嵌入這些動態庫的一些信息,所以這些信息時頗有必要的。
LOCAL_STATIC_LIBRARIES的一個變種,用來表達對應的二進制模塊應該當作」完整的文件「來鏈接。
建立動態庫或者可運行文件時的一些其餘連接選項。例如,當ld.gold爲默認時,下面會在ARM/X86 GCC 4.6+下使用ld.bfd連接器連接
LOCAL_LDFLAGS += -fuse-ld=bfd
注意:該選項在編譯靜態庫時會被忽略,ndk會在你定義該變量時發出一個警告信息
默認狀況下,在動態庫中引用一個未定義的符號時,會產生一個」undefined symbol「錯誤。這會對你在源碼中找出錯誤有很大的幫助。
然而,若是一些緣由讓你須要禁用這個檢查,設置這個值爲‘true’便可。注意生成的二進制文件可能在運行時失敗。
注意:該選項在編譯靜態庫時會被忽略,ndk會在你定義該變量時發出一個警告信息
默認狀況下,ARM的目標程序的指令是‘thumb’模式的,‘thumb’模式下的指令長度是16位的,而且連接了thumb STL庫。可使用該變量來生成’arm’指令。該指令是32位的。使用實例:
LOCAL_ARM_MODE := arm
注意:能夠指定以’.arm’後綴源碼生成arm格式的彙編指令,例如:
LOCAL_SRC_FILES := foo.c bar.c.arm
告訴編譯器永遠編譯bar.成arm指令格式的,而foo.c的類型由LOCAL_ARM_MODE決定。
注意:在Android.mk中設置APP_OPTIM爲‘debug’後,也會生成arm格式的文件。這是因爲工具鏈中的調試工具對thumb指令不能很好得處理形成的。
當定義該變量時,容許C/C++/彙編代碼使用NEON技術。
只能當使用基於ARMv7指令集的」armeabi-v7a」才能定義。注意並非全部ARMv7系列的CPU都支持NEON擴展指令集的。
此外,還能夠經過添加‘.neon’後綴來指定文件採用NEON指令集編譯。
LOCAL_SRC_FILES = foo.c.neon bar.c zoo.c.arm.neon
在這個例子中,‘foo.c’會被編譯成thumb+neon模式,‘bar.c’會被編譯成thumb模式。zoo.c會被編譯成arm+neon模式
注意:若是要同時使用的話,‘.neon’後綴必須出如今‘.arm’後綴以後。
Android NDK r4添加了」NX bit「安全特性的支持。它默認時開啓的,能夠經過設置該值爲‘true’來關閉它。
By default, NDK compiled code is built with read-only relocations and GOT protection. This instructs the runtime linker to mark certain regions of memory as being read-only after relocation, making certain security exploits (such as GOT overwrites) harder to perform.
It is enabled by default, but you can disable it if you really need to by setting this variable to 'true
'.
NOTE: These protections are only effective on newer Android devices ("Jelly Bean" and beyond). The code will still run on older versions (albeit without memory protections).
參考http://blog.chinaunix.net/uid-24203478-id-3298210.html
By default, NDK compiled code is compiled with format string protection. This forces a compiler error if a non-constant format string is used in a printf style function.
It is enabled by default, but you can disable it if you really need to by setting this variable to 'true
'.
該變量會記錄當前模塊中設定的C/C++編譯選項。當其餘模塊使用LOCAL_STATIC_LIBRARIES或LOCAL_SHARED_LIBRARIES引用該模塊時,LOCAL_CFLAGS會自動添加上述設定的C/C++編譯選項。
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)
這樣,下面模塊的編譯標識會被設置成'-DFOO=1
-DBAR=2
'
導出標識在內部表現爲LOCAL_CFLAGS,所以能夠很方便得使用。這種特性是能夠傳遞的:好比‘zoo’依賴於‘bar’,而‘bar’依賴於‘foo’,那麼‘zoo’也會繼承‘foo’的導出符號。
LOCAL_EXPORT_CPPFLAGS
和LOCAL_EXPORT_CFLAGS相似,可是僅僅包含C++標識。
和LOCAL_EXPORT_CFLAGS相似,可是隻用來包含C頭文件路徑。當’bar.c’須要包含‘foo’所提供的頭文件時使用
和LOCAL_EXPORT_CFLAGS相似,可是用來處理連接符號。
和LOCAL_EXPORT_CFLAGS相似,一般會設置一個以‘-l’爲前綴的指定系統庫。因爲Unix編譯器的工做方式,導入的連接標識會添加到模塊的LOCAL_LDLIBS中。
當‘foo’須要編譯成靜態庫而它有一些代碼會依賴系統庫時,可使用LOCAL_EXPORT_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)
由於依賴於‘foo’,libbar.so編譯時會在連接命令的末尾添加-llog選項用來顯示它會依賴系統的日誌庫
當模塊中由不少源文件生成或者依賴靜態或者動態庫時設置該標識爲’true’,他會強制編譯系統使用內部的列表文件,而且使用一個二進制壓縮文件或者靜態連接到@語法。
這在windows系統中很是有用,命令行最多接收8191個字節,對一個複雜的工程來講這是遠遠不夠的。
這會影響每個單獨的文件,幾乎在每個內部列出的文件加上全部的編譯標識。
在編譯靜態庫的時候設置爲‘true’。他會生成一個簡單的歸檔文件。例如一個庫文件(libfoo.a)不包含任何對象文件,只包含了它應該包含對象的文件路徑。
他一般被用來減小編譯輸出的體積。它的缺點是這些包含的庫文件不能被移動到其餘路徑下去(全部的路徑都被內部依賴)。
有效的值是‘true’,‘false’或者爲空。能夠經過APP_THIN_ARCHIVE來設置默認值。
注意:該命令在非靜態庫或者預編譯靜態庫中會被忽略。
在命令行中定義該變量用來過濾來自LOCAL_SRC_FILES中定義的或者生成的彙編文件。
當它被定義後,將會發生如下的事情:
換句話說,若是你定義:
LOCAL_SRC_FILES := foo.c bar.S LOCAL_FILTER_ASM := myasmfilter foo.c --1--> $OBJS_DIR/foo.S.original --2--> $OBJS_DIR/foo.S --3--> $OBJS_DIR/foo.o bar.S --2--> $OBJS_DIR/bar.S --3--> $OBJS_DIR/bar.o
」1「對應編譯器,」2「對應過濾器,」3「對應彙編器。過濾器是第一個輸入的文件當作它第一個參數的命令,而輸出文件的名稱是它的第二個參數。
myasmfilter $OBJS_DIR/foo.S.original
$OBJS_DIR/foo.S
myasmfilter bar.S $OBJS_DIR/bar.S