下面是我個人對android-ndk-r4版本中Android.mk文件做的翻譯,,由于自己英語水平和專業(yè)知識的限制,有些地方可能翻譯的不是很準確,,敬請指正,,本文僅希望對做android NDK開發(fā)的同仁們能提供一點點的幫助而已。 Android.mk文件是用來描述你想要編譯進系統(tǒng)的資源的,。 這個文件的語法允許你把你的資源打包進“modules”,。Module應(yīng)該是下面module中的一種: - a static library - a shared library 只有shared library會被打包到你的應(yīng)用程序中,盡管static library也能用來生產(chǎn)shared library,。 你可以在一個Android.mk中定義多個module,,你也可以在幾個module中使用相同的資源文件。
編譯系統(tǒng)會為你處理一些細節(jié),。例如,,你不需要在你的Android.mk文件中列出你的頭文件或是你的文件之間明確的依賴關(guān)系,。NDK編譯系統(tǒng)會自動幫你處理。 這同時意味著,,當升級到新版本的NDK時,,你不需要動你的Android.mk文件就可以使用心得toolchain/platform支持。 注意,,用在Android.mk文件中的語法和整個的android平臺的開源資源語法是不同的,。編譯系統(tǒng)實現(xiàn)了對他們不同的使用,這是故意這樣設(shè)計的,,用來允許應(yīng)用開發(fā)人員更容易地重用外部庫資源代碼,。
一個簡單的例子: 在語法詳細說明之前,讓我們先來看一個簡單的“hello-jni”例子,,文件在$NDK/samples/hello-jni下: 在這我們可以看到: -src目錄下包含這個簡單的android工程的一個java源文件 -jni目錄下包含了這個例子的本地源文件 這個源文件實現(xiàn)了一個簡單的共享庫,,這個共享庫實現(xiàn)了一個想vm應(yīng)用程序返回一個字符串的本地方法。 -Android.mk文件向NDK編譯系統(tǒng)描述了一個共享庫,。它的內(nèi)容如下: LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE := hello-jni include $(BUILD_SHARED_LIBRARY 現(xiàn)在讓我們來解釋這些語法: LOCAL_PATH := $(call my-dir) 一個Android.mk文件必須以定義一個LOCAL_PATH 變量開始,。它用來在你的工程樹形目錄下定位你的資源文件的位置。在這個例子中,,那個編譯系統(tǒng)提供的“my-dir”宏函數(shù)用來返回當前目錄的路徑(Android.mk文件所在的目錄),。 include $(CLEAR_VARS) 編譯系統(tǒng)提供的一個指向特殊的GNU Makefile文件的CLEAR_VARS變量將為你清理很多LOCAL_PATH中的LOCAL_XXX變量(例如: LOCAL_MODULE, LOCAL_SRC_FILES, LOCAL_STATIC_LIBRARIES等等)。這是有必要的,,因為所有的編譯控制文件都會在一個單獨的GNU Make可執(zhí)行上下文中被解析,,在這里所有的變量都是全局的。 LOCAL_MODULE := hello-jni 用來標識分布在Android.mk文件中的每一個module的LOCAL_MODULE變量必須定義,。名字必須是唯一的而且不能有空格,。 注意,編譯系統(tǒng)會給相應(yīng)的生成文件自動地添加適當?shù)那熬Y和后綴,。換句話說,,一個命名為“foo”的共享庫module將生成名為“l(fā)ibfoo.so”的文件。 重點注意: 如果你的module命名為“l(fā)ibfoo”,,編譯系統(tǒng)不會為你添加另外一個“l(fā)ib”前綴,,還是會生成一個“l(fā)ibfoo.so”的文件而已。這個為了支持你需要使用的android平臺資源的Android.mk文件,。 LOCAL_SRC_FILES := hello-jni.c LOCAL_SRC_FILES變量必須包含一個將要被編譯和匯編進module的一個C/C++資源文件列表,。注意你不需要列出頭文件和包含文件,因為編譯系統(tǒng)會自動幫你計算依賴關(guān)系,;僅僅需要列出直接傳遞給編譯器的資源文件就可以了,。 注意:默認的C++資源文件的擴展名是“.cpp”。然而可以通過定義LOCAL_DEFAULT_CPP_EXTENSION變量來指定一個不同的擴展名,。不要忘記最開始的dot(例如:.cxx是可以的,,但是cxx是不行的),。 include $(BUILD_SHARED_LIBRARY) BUILD_SHARED_LIBRARY是編譯系統(tǒng)提供的一個指向GNU Makefile腳本的變量,它負責(zé)收集從最近的include $(CLEAR_VARS)' 變量開始的所有內(nèi)定義的 LOCAL_XXX變量的信息,,然后決定哪些需要編譯以及怎樣編譯,。BUILD_STATIC_LIBRARY變量可以生成一個static library。
在samples目錄下有幾個復(fù)雜的例子,,在他們的Android.mk文件中你可以看到一些注釋。 Reference: 下面是你可以在Android.mk文件里可以直接使用或是定義的變量的列表,。你能夠定義其它的變量供自己使用,,但是下面的變量名是NDK編譯系統(tǒng)的保留字: - 以LOCAL_ 開頭命名的 (例如LOCAL_MODULE) 如果你需要在Android.mk文件里定義一個你自己使用比較方便的變量,,我們建議使用MY_前綴,,這是一個普通的例子: MY_SOURCES := foo.c LOCAL_SRC_FILES += $(MY_SOURCES) 好,我們接著看: NDK提供的變量: 在你的Android.mk文件解析之前,,編譯系統(tǒng)定義了這些GNU Make變量,。注意,在某種情況下NDK可能會多次解析你的Android.mk文件,,每一次解析某些變量的定義可能不同,。 CLEAR_VARS 指向一個幾乎所有在"Module-description"部分列出的LOCAL_XXX變量都沒有定義的編譯腳本(我的理解就是在編譯前清空所有變量,然后在這個變量的下面再重新定義),。在開始一個新的module之前你必須包含這個腳本,,例如: include $(CLEAR_VARS) BUILD_SHARED_LIBRARY 指向一個收集所有你提供的關(guān)于module的LOCAL_XXX變量的信息的編譯腳本,然后決定如何根據(jù)你列出的資源編譯一個目標shared library,。注意,,你在包含這個變量之前必須至少OCAL_MODULE 和LOCAL_SRC_FILES 變量??梢赃@樣使用: include $(BUILD_SHARED_LIBRARY) 注意它將生成一個以lib$(LOCAL_MODULE).so命名的文件,。 BUILD_STATIC_LIBRARY BUILD_STATIC_LIBRARY變量的不同之處在于它是用來生成一個目標static ibrary 。static ibrary 不會被打包進你的工程包,,但是可以用來生成shared library(看下面的LOCAL_STATIC_LIBRARIES 和LOCAL_STATIC_WHOLE_LIBRARIES說明),。可以這樣使用: include $(BUILD_STATIC_LIBRARY) 注意,,它將生成一個以lib$(LOCAL_MODULE).a命名的文件,。 TARGET_ARCH 指明一個full Android open-source build明確說明的目標CPU架構(gòu)。如果是“arm”用來所有的兼容ARM的編譯,,不依賴與CPU架構(gòu)版本,。 TARGET_PLATFORM 當Android.mk文件解析時,指明一個android目標平臺,。例如"android-3”對應(yīng)"android1.5"系統(tǒng)鏡像,。完整的平臺名字和android系統(tǒng)鏡像的對應(yīng)列表可以閱讀docs/目錄下STABLE-APIS.TXT文檔,。 TARGET_ARCH_ABI 當Android.mk文件解析時,指明一個目標CPU+ABI,。有兩個值可供使用: armeabi armeabi-v7a 注意:Android NDK 1.6_r1之上的版本,,這個變量被定義為'arm'。然而,,這個變量的重定義能夠被Android platform內(nèi)部更好的使用,。 對于更多的ABI架構(gòu)和對應(yīng)的兼容性問題的細節(jié),可以閱讀docs目錄下的CPU-ARCH-ABIS.TXT文檔,。 其他的ABI架構(gòu)將會在以后的NDK版本中引入,,并且有不同的名字。注意,,所有基于ARM的ABIs都會被'TARGET_ARCH' 定義為 'arm',,但是可能有不同的'TARGET_ARCH_ABI'。 TARGET_ABI 目標平臺和abi的連結(jié),,它被定義為$(TARGET_PLATFORM)-$(TARGET_ARCH_ABI),,當你用真機測試一個指定的目標平臺鏡像的時候會有用處。 默認情況下,,它將是'android-3-armeabi' (Android NDK 1.6_r1以上的版本,,'android-3-arm'是默認的)
NDK提供的宏函數(shù) 下面是GNU Make宏函數(shù),通過使用'$(call <function>)'來獲得他的值,。它們返回文本信息,。 my-dir 返回相對于上層的NDK編譯系統(tǒng)的當前Android.mk文件目錄的路徑。這對于以下面這種方式在你的Android.mk文件的開始定義LOCAL_PATH變量很有用: LOCAL_PATH := $(call my-dir) all-subdir-makefiles 返回當前所有在'my-dir'路徑下以及他的子路徑下的Android.mk 文件列表,。例如,,考慮下面的這種層次結(jié)構(gòu): sources/foo/Android.mk 如果sources/foo/Android.mk文件包含下面這條指令: include $(call all-subdir-makefiles) 這時它將自動包含 sources/foo/lib1/Android.mk和sources/foo/lib2/Android.mk文件。 這個函數(shù)能用來為編譯系統(tǒng)提供深層嵌套的資源目錄層次結(jié)構(gòu),。注意,,默認情況下 ,NDK只會在sources/*/Android.mk目錄下尋找文件,。 this-makefile 返回當前Makefile文件的路徑(例如,,函數(shù)在哪里被調(diào)用)。 parent-makefile 放回父Makefile文件在包含樹中的路徑,。例如包含當前Makefile文件的Makefile文件的路徑,。
Module描述變量 下面的變量是用來向系統(tǒng)描述你的module的。你應(yīng)該在一個'include $(CLEAR_VARS)'和'一個include $(BUILD_XXXXX)'變量之間定義它們中的某些變量,。前面的部分已經(jīng)介紹過了,,$(CLEAR_VARS)變量是取消/清除所有這些變量的定義,除非在他們的描述說明確地注明,。 LOCAL_PATH 這個變量用來給出當前文件的路徑,。你必須在你的Android.mk文件的開始定義它,,比如下面這樣定義是可以的: LOCAL_PATH := $(call my-dir) 這個變量不會被$(CLEAR_VARS)清除掉,所以在每一個Android.mk文件中僅需要定義一次(在你的一個文件中定義了幾個module的情況下),。 LOCAL_MODULE 你的module的名字,。它必須在所有的module名字中是唯一的,而且不能有空格,。你必須在任何一個$(BUILD_XXXX)腳本之前定義它,。 module名字決定了生成文件的名字,例如:一個名字為lib<foo>.so的shared library的module名字為<foo>,??墒牵銘?yīng)該在你的NDK編譯文件中(無論是Android.mk還是 Application.mk)進引用其它module的通用的名字(例如<foo>),。 LOCAL_SRC_FILES 這是一個將用于你的module編譯的資源文件列表。只用在列表中的文件才會傳遞給編譯器,,因為編譯系統(tǒng)自動幫你計算依賴關(guān)系,。 注意,所有的資源文件名字都是相對于LOCAL_PATH的,,你能夠使用路徑分隔符,,例如: LOCAL_SRC_FILES := foo.c \ 注意:只有使用Unix風(fēng)格的正斜線(/)在編譯文件中才可以,windows風(fēng)格的反斜線(\)不能被正確處理,。 LOCAL_CPP_EXTENSION 這是一個可選擇的變量,,它能用來定義c++源文件的文件后綴名。默認的是'.cpp',,但是你可以改變它,。例如: LOCAL_CPP_EXTENSION := .cxx LOCAL_C_INCLUDES 一個可選的編譯所有源文件(C,C++,匯編)時會添加到include搜索路徑相對于NDK *root*文件夾的路徑的列表。例如: LOCAL_C_INCLUDES := sources/foo 或者 LOCAL_C_INCLUDES := $(LOCAL_PATH)/../foo 他們會在LOCAL_CFLAGS / LOCAL_CPPFLAGS中的任何inclusion flag之前被替換,。 LOCAL_CFLAGS 當編譯 C 和 C++源文件時傳遞的一組可選的編譯器標識,。 它可以用來指定額外的宏定義或編譯選項。 重要信息:不要在你的Android.mk文件中嘗試去改變優(yōu)化/調(diào)試等級,,這個可以通過在你的Android.mk文件中指明適當?shù)男畔碜屜到y(tǒng)自動處理,,將會使NDK生成在調(diào)試中可以使用的有用的數(shù)據(jù)文件。 注意:在android-ndk-1.5_r1中,,對應(yīng)標記僅能用在c源文件上,,不能用在c++源文件上。這能夠正確匹配所有的android編譯系統(tǒng)行為,。(你現(xiàn)在可以使用LOCAL_CPPFLAGS來僅為c++源文件設(shè)置標識),。 LOCAL_CXXFLAGS LOCAL_CPPFLAGS的一個別名。注意,,這種標識的使用是過時的,,因為在以后的NDK版本中它可能被取消,。 LOCAL_CPPFLAGS 當僅編譯 C++源文件時傳遞的一組可選的編譯器標識。他們將在LOCAL_CFLAGS之后顯示在命令行上,。 注意:在android-ndk-1.5_r1中,,對應(yīng)標記在c源文件上和在c++源文件上都能使用。這能夠正確匹配所有的android編譯系統(tǒng)行為,。(你現(xiàn)在可以使用LOCAL_CFLAGS來為c++源文件和c源文件設(shè)置標識),。 LOCAL_STATIC_LIBRARIES 將要被鏈接進這個module的static libraries modules的列表(用BUILD_STATIC_LIBRARY編譯過的)。這個僅在shared library modules中能被檢測到,。 LOCAL_SHARED_LIBRARIES 依賴于運行時的shared libraries *modules*的列表,。這在鏈接時是必要的,為了把對應(yīng)的信息嵌入到生成的文件中,。 注意:他不會把列出的module添加到編譯表中,,例如:你仍然需要在你的Application.mk文件中把他們添加到你的應(yīng)用程序需要的module中。 LOCAL_LDLIBS 編譯你的module時使用到的額外的鏈接器標識列表,。它能夠用一個帶 "-l" 前綴的表達式傳遞一個指明的系統(tǒng)庫的名字,。例如:下面的定義將會通知編譯器在加載的時候生成一個鏈接到/system/lib/libz.so的module: LOCAL_LDLIBS := -lz 閱讀docs目錄下的STABLE-APIS.TXT文檔,你將能了解到在這個NDK版本中你可以鏈接的系統(tǒng)庫的列表,。 LOCAL_ALLOW_UNDEFINED_SYMBOLS 默認情況下,,當嘗試編譯一個shared library時任何一個沒有定義的引用都將產(chǎn)生一個"undefined symbol"錯誤。這對在你的源代碼中捕獲bug很有幫助,。 LOCAL_ARM_MODE 默認情況下,,ARM的二進制文件將生成每一條指令都是16位的'thumb'模式,。你可以定義這個變量為'arm',如果你想強制生成的module目標文件為 'arm'(每條指令32位)模式的,。例如: LOCAL_ARM_MODE := arm 注意,,你也可以通過在源文件名后面添加一個'.arm'來指示編譯系統(tǒng)只把指定的文件編譯'bar.c'。例如: LOCAL_SRC_FILES := foo.c bar.c.arm 通知編譯系統(tǒng)總是把'bar.c'編譯成'.arm'模式,,而依據(jù)LOCAL_ARM_MODE變量的值來編譯 foo.c 文件,。 注意:在你的Application.mk文件中設(shè)置APP_OPTIM為 'debug'也能強制生成ARM二進制文件。這是因為在thumb模式下toolchain debugger 中的bug不能得到較好的處理,。 LOCAL_ARM_NEON 把這個變量設(shè)置為'true'能夠允許你在你的C和C++源碼中使用ARM Advanced SIMD(a.k.a. NEON)GCC,,也能在匯編文件中使用NEON指令。 你僅僅應(yīng)該在想要對應(yīng)ARMv7指令序列的'armeabi-v7a' ABI時定義它。注意,,不是所有基于ARMv7的CPU都支持NEON指令序列擴展,,你應(yīng)該開啟運行時檢查來確保你能安全地使用這些代碼在運行期間。更多的關(guān)于這些的內(nèi)容,,可以閱讀docs目錄下的CPU-ARM-NEON.TXT 和CPU-FEATURES.TXT.文檔,。 二選一,你也可以在指定的文件后面加上'.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' 后綴都是用,那么 '.neon' 后綴和一定要添加到'.arm' 后綴之后,。(例如: foo.c.arm.neon 可以,,但是 foo.c.neon.arm 不可以)。 LOCAL_DISABLE_NO_EXECUTE Android NDK r4添加的用來支持"NX bit"安全特性的,。默認情況下是啟用的,,但是你也可以設(shè)置這個變量為 'true'來啟用它,如果你真的需要這么做的話,。 注意:這個特性不會修改ABI,它僅僅是使內(nèi)核能夠指向ARMv6+ CPU設(shè)備,。在這種特性下生成的機器碼將不需要做修改就能運行在更早的CPU架構(gòu)上 |
|