Android.mk文件的語法詳細定義

Android.mk文件的語法詳細定義


介紹: 
這個文檔詳細描述了"Android.mk"編譯文件的語法規則,這文件被寫來描述你的Android NDK的C和C++源文件。爲了理解接下來說明,假設你閱讀了說明其作用和用法的"docs/OVERVIEW.TXT"文本。
 

概要: 
一個"Android.mk"文件被用來描述你的編譯系統的源文件。更詳細地描述: 
--文件是一個真實的小的GNU Makefile片段。它被編譯系統分析一次或多次。因此,你應該試着儘量減少在這兒的變量申明。不要假設不會在解釋期間定義任何東西。
 --文件的語法規則被設計爲了允許你組織你的源代碼到模塊(modules).一個模塊是下面中的一個: 
----一個靜態庫 
----一個共享庫 
只有共享庫將被安裝或複製到你的應用程序包中。然而靜態庫只能被用來產生共享庫。 
你能定義一個或多個模塊在每個"Android.mk"文件裏。你能在幾個模塊中使用一樣源文件。
--編譯系統爲你處理許多細節。例如,你不需要在你的"Android.mk"文件中列出頭文件或明確依賴關係在生成文件之間。NDK編譯系統將爲你自己計算這些。 
這也以爲這,當跟新新版的NDK時,你應該能不用出擊你的Android.mk文件情況下,收益於新的工具鏈(toolchain)或平臺(platform)的支持。


注意:語法規則是非常近似被使用的一個Android.mk文件,這文件是全開源Android平臺代碼的分佈式的。然而使用它們的編譯系統實現是不同的,這是有意設計的決定,爲了應用程序開發者被允許更容易的重用外部庫的源代碼。
 

簡單例子: 
在詳細描述一個語法規則前,讓我們來認識一個簡單的"hello JNI"例子,即(i.e)一下文件: 
apps/hello-jni/project 
這兒,我們能看到: 
--"src"目錄包含了Java源代碼爲這個Android工程例子。 
--"jni"目錄包含了本地源代碼爲這個例子,即(i.e)"jni/hello-jni.c" 
這源代碼文件實現一個簡單共享庫,這庫實現一個本地方法返回一個字符給VM應用程序 
--"jni/Android.mk"文件描述了NDK編譯系統的共享庫.它的內容是: 
---------- 裁剪這個 ---------- 
LOCAL_PATH := $(call my-dir)


include $(CLEAR_VARS)


LOCAL_MODULE := hello-jni
LOCAL_SRC_FILES := hello-jni.c


include $(BUILD_SHARED_LIBRARY)
---------- 裁剪這個 ---------- 
現在,讓我們來解釋這些行:


LOCAL_PATH := $(call my-dir)
這個"Android.mk"文件必須開始於定義"LOCAL_PATH"變量。它被用來在開發樹中定位源文件。在這個例子中,宏函數"my-dir"是編譯系統提供的。它被用來返回當前目錄的路徑(即(i.e)這個路徑包含了"Android.mk"文件自己)。
 

include $(CLEAR_VARS)
這個"CLEAR_VARS"變量是編譯系統提供的。它指出一個指定GNU Makefile將清理許多"LOCAL_XXX"變量爲你。(例 如,"LOCAL_MODULE","LOCAL_SRC_FILES","LOCAL_STATIC_LIBRARIES",等(etc...)),但 處了"LOCAL_PATH"變量。這被需要,因爲所有編譯控制文件都是在唯一的GNU Make執行上下文中被剖析,這個執行上下文中所有的變量都是全局的。
 

LOCAL_MODULE := hello-jni
這個"LOCAL_MODULE"變量必須被定義,來標識你在你的Android.mk文件中描述的每個模塊。名字必須是唯一的,同時不能包含任何空白 符。注意編譯系統將自動地添加恰達的前綴和後綴到對應產生的文件。換而言之,共享庫模塊名字是"foo",那產生的爲"libfoo.so"文件。
 重要的備註: 
如果你命名你的模塊"libfoo"的名字,編譯系統將不加另一個"lib"前綴,也將產生"libfoo.so"名字的文件。這是爲了支持來至"Android"平臺源代碼的"Android.mk"文件,你需要用到這些。
 

LOCAL_SRC_FILES := hello-jni.c
這個"LOCAL_SRC_FILES"變量必須包含"C"和/或"C++"的源代碼文件列表,這個源文件被編譯成一個模塊。注意你不必列出頭文件和包含的文件在這兒,因爲編譯系統將自動地爲你計算依賴關係。只要列出將被直接地傳遞給編譯器的源代碼文件。這對你該不錯啊。
 注意對於“C++”源文件的默認擴展名是".cpp".然而,可以通過定義"LOCAL_CPP_EXTENSION"變量來指定不同的擴展名。不要忘記初始的點(即(i.e.)".cxx"將能工作,但"cxx"不行)。
 

include $(BUILD_SHARED_LIBRARY)
這個"BUILD_SHARED_LIBRARY"是一個變量,編譯系統提供的。這個變量指出一個"GNU Makefile"腳本負責收集所有的信息,這些信息是你定義在從最近的"include $(CLEAR_VARS)"開始的LOCAL_XXX變量中,這些變量決定你編譯什麼和怎樣確切實現它。也能"BUILD_STATIC_LIBRARY"來產生一個靜態的庫。
 

在實例目錄中有更多更復雜的例子,例子中你能看到帶有註釋的"Android.mk"文件。


參考: 
在"Android.mk"文件中,你應該定義和依賴了一組變量。你能爲你自己的使用定義其他的變量,但NDK編譯系統保留了下面的變量名字: 
--帶"LOCAL_"開頭的命名(例如(e.g.)LOACL_MODULE) 
--帶"PRIVATE_, NDK_ or APP_"開頭的命名(內部使用的) 
--小寫字符命名(內部使用的,例如(e.g.)"my-dir")


如果你需要在"Android.mk"的文件中定義你自己的方便有用的變量,我們推薦使用"MY_"爲前綴。如一個簡單的例子:
---------- 裁剪這個 ---------- 
MY_SOURCES := foo.c 
ifneq ($(MY_CONFIG_BAR),) 
  MY_SOURCES += bar.c 
endif


LOCAL_SRC_FILES += $(MY_SOURCES)
---------- 裁剪這個 ---------- 
因此,我們去這兒:


NDK提供的變量: 
這些"GNU Make"變量是編譯系統定義的,在你的"Android.mk"文件被剖析前。注意在某些情況下"NDK"可能會多次剖析你的"Android.mk"文件,對於這些變量一些每次有不同的定義。
 

CLEAR_VARS 
指向一個編譯腳本,它擦除了最近地所有的"LOCAL_XXX"變量的定義,這些變量在下面的模塊描述("Module_description")章節中列出。你必須包含這個腳本,在一個新模塊開始前。例如(e.g.):
 inlcude $(CLEAR_VARS)


BUILD_SHARED_LIBRARY
指向一個編譯腳本,它收集所有的關於模塊的信息,模塊在"LOCAL_XXX"變量中提供給你。這個腳本決定怎樣編譯來自你列表的源代碼的一個目標共享 庫。注意你必須有"LOCAL_MODULE"和"LOCAL_SRC_FILES"的定義,至少在包含這個文件前。使用例子(Example usage):
 include $(BUILD_SHARED_LIBRARY) 
注意這將產生一個名叫"lib$(LOCAL_MODULE).so"的文件。


BUILD_STATIC_LIBRARY
一個"BUILD_SHARE_LIBRARY"的變種被用來編譯一個目標靜態庫。靜態庫不會被拷貝到你的工程或包中 (project/packages),但他們能被用編譯共享庫(參考下面的"LOCAL_STATIC_LIBRARIES" 和"LOCAL_STATIC_WHOLE_LIBRARIES"描述)。
 使用例子(Example usage): 
include $(BUILD_STATIC_LIBRARY) 
注意這將產生一個名叫"lib$(LOCAL_MODULE).a"的庫文件。


TARTGET_ARCH 
目標"CPU"架構的名字,像他是被整個"Android"的開放源代碼編譯指定的。這兒"arm"是爲任何兼容“ARM"編譯,不依賴於特定的"CPU"架構修訂。


TARGET_PLATFORM
指定出了"Android"平臺目標的名字,當這個"Android.mk"文件被剖析時。例子,"Android-3"對應於"Android 1.5"系統映像。爲了平臺名字的完整的數組和對應的Android系統映像,閱讀"docs/STABLE-API.TXT"。
 

TARGER_ARCH_ABI
爲目標"CPU+ABI"的名字,當剖析"Android.mk"文件時。此刻有兩個值被支持: 
armeabi  爲了Arm5TE 
armeabi-v7a 
注意:直到"Android NDK 1.6_r1",這個變量被簡單地定義爲"arm"。然而,這個值被重新定義爲更好的匹配被"Android"平臺內部使用的名字。
 爲更多關於架構"ABIs"的細節和對應的兼容的說明,請參考"docs/CPU-ARCH-ABIS.TXT"。
另一個目標"ABIs"將被介紹在將來的"NDK"版本中.它將有不同的名字。注意所有基於"ARM"的"ABIs"將有定義爲"arm"值的"TARGET_ARCH"。但可以有不同的"TARGET_ARCH_ABI"。
 

TARGET_ABI 
目標平臺和"abi"的串聯,它真實地定義就像"$(TARGET_PLATFORM)-$(TARGET_ARCH_ABI)"。當我們想爲真實的設備針對一個特定目標系統的映像測試時很有用。
 默認,這個值是"android-3-armeabi"。 
(直到"Android NDK 1.6-r1"時,默認值是"android-3-arm")


NDK提供宏函數(NDK-provided function macros):
下面是"GNU Make"函數宏定義。它們必須通過使用"$(call <function>)"來評估。它們返回文本的信息。


my-dir 
返回當前的"Android.mk"文件的目錄的路徑。路徑是相對於NDK編譯系統的頂層的。這對於定義"LOCAL_PATH"變量有用在你的"Android.mk"文件的開始,正如(as with):
 LOCAL_PATH := $(call my-dir)


all-subdir-makefiles
返回在當前"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"文件。


這個函數可以被用來提供深層嵌套源代碼目錄層次給編譯系統。注意默認,NDK將只選在文件在"sources/*/Android.mk"文件中。


this-makefile 
返回當前"Makefile"的路經(即(i.e.)這個函數被調用的地方)


parent-makefile
返回父"Makefile"的路徑在包含樹中,即(i.e.)包含當前"Makefile"的"Makefile"的路徑)


grand-parent-makefile
猜到什麼了吧(Guess what...)

 


模塊描述變量(Module-description variables):
下面變量被用來描述你的模塊爲編譯系統。你應該定義它們的一些在"include $(CLEAR_VARS)"和"include $(BUILD_XXXXX)"之間。像前面寫的,$(CLEAR_VARS)是一個腳本,將清除/不定義所有這些變量,除非明確說明在他們的描述中。
 

LOCAL_PATH 
這個變量被用來給出當前文件的路徑。你必須定義它在你的"Android.mk"文件的開始,就像:
LOCAL_PATH :=$(call my-dir) 
這個變量不被$(CLEAR_VARS)清除。因此每個Android.mk文件只有需要一個定義(如果你定義多個模塊在一個文件中)。


LOCAL_MODULE 
這個是你模塊的名字。它必須在所有的模塊名中唯一。它不應該包含任何空字符。你必須定義它在包含任何"$(BUILD_XXXX)"腳本前。 
模塊名決定產生文件的名字。例如(e.g.)"lib<foo>.so"因爲共享庫模塊命名"<foo>"。然而你應該只參考其 他模塊用它們一般名字(例如<foo>),在你的"NDK"編譯系統文件之中。(無論Android.mk文件還是 Application.mk文件)
 

LOCAL_SRC_FILES
這是源代碼文件的列表,這些源代碼文件被編譯爲了你的模塊。所以只有列表的文件將被傳遞給編譯器,因爲編譯系統自動地爲你計算依賴關係。 
注意源代碼文件名字都是相對於"LOCAL_PATH"的,你能使用路徑組件,例如(e.g.): 
LOCAL_SRC_FILES := foo.c 
                   toto/bar.c 
注意:總是使用Unix風格(Unix-style)前進的斜線(/)在編譯文件中。Windows風格(Window-style)後退斜線將不能正確的處理。


LOCAL_CPP_EXTENSION
這個可選變量能用來定義說明C++源代碼文件的文件後綴。這個默認值是".cpp",但你能改變它。例如: 
LOCAL_CPP_EXTENSION := .cxx


LOCAL_C_INCLUDES
路徑的可選列表,相對於NDK的根目錄(NDK *root* directory),這個將擴展搜索路徑,當編譯所有的源代碼文件(C,C++和彙編(Assembly))。例如:
 LOCAL_C_INCLUDES := sources/foo 
或甚至: 
LOCAL_C_INCLUDES := $(LOCAL_PATH)/../foo 
他們被放置在LOCAL_CFLAGS/LOCAL_CPPFLAGS中的任何對應的包含標誌前


LOCAL_CFLAGS 
這編譯器標記的可選的設置,在編譯C和C++源代碼文件時被傳遞給編譯器。 
這對於指定額外宏定義和編譯選項是有用的。 
重點:不要嘗試改變優化或調式級別(optimization/debugging level)在你的"Android.mk"文件中,能通過在你的"Application.mk"文件中指定的其當信息,來爲你自動處理這個事。讓NDK產生被調試期間使用的有用的數據文件。
 注意:在"android-ndk-1.5_r1"中,對應的標誌只應用在C源代碼文件上,不對C++文件其作用。這被糾正來匹配整個"Android"編譯系統的行爲。(你現在只能使用"LOCAL_CPPFALGS"爲C++源代碼指定標記。)
 

LOCAL_CXXFLAGS
"LOCAL_CPPFLAGS"的一個別名。注意這個標記的使用被廢棄,在將來的NDK版本中可能不出現了。


LOCAL_CPPFLAGS 
編譯器標記的可選設置,只在編譯C++源代碼文件時傳遞給編譯器。他們出現在"LOCAL_CFLAGS"變量後面,在編譯器的命令行中。 
注意:在"android-ndk-1.5_r1"中,這個對應的標記實現應用在C和C++源代碼上。這被糾正來匹配整個"Android"編譯系統。(現在你能用"LOCAL_CFLAGS"爲C和C++源代碼文件來指定標記)。
 

LOCAL_STATIC_LIBRARIES
靜態庫模塊的列表(使用了"BUILD_STATIC_LIBRARY"編譯的),列表將被被鏈接到這個模塊上。這隻在共享庫模塊中有意義。


LOCAL_SHARED_LIBRARIES
共享庫模塊的列表,這個模塊在運行是依賴這些共享庫的模塊列表。這在鏈接時是必須的,爲在產生文件中嵌入對應的信息。 
注意這個不能追加列表模塊到編譯圖形(the build graph)。即(i.e.)你仍然應該在你的"Application.mk"文件中,添加共享庫模塊列表到你的應用程序的請求模塊。
 

LOCAL_LDLIBS
當編譯你的模塊時,被使用的額外鏈接標誌的列表。這對於傳遞使用"-l"前綴指定系統庫的名字很有用。例如,下面告訴鏈接器產生一個模塊, 這個模塊在載入時鏈接到"/system/lib/libz.so"庫上。
 LOCAL_LDLIBS := -lz 
參考"docs/STABLE-APIS.TXT"文件,爲針對這個NDK版本,你能鏈接到的系統導出的庫的列表。


LOCAL_ALLOW_UNDEFINED_SYMBOLS
默認情況下,在嘗試編譯一個共享庫時遇到任何未定義的參考將導致一個未定義符號(undefine symbol)錯誤。這對於在你的源代碼中找到問題(catch bugs)非常有幫助。
 然而,對於有些原因,你需要禁止這種檢查,設置這個變量爲"true"值。注意對應的共享庫可能在運行時加載出錯。


LOCAL_ARM_MODE 
默認情況下,"ARM"目標二進制將以"thumb"模式來產生,這樣每個命令是"16bit"寬。如果你想強制以"arm"模式(32-bit命令)來產生模塊對象文件,你能定義這個變量爲"arm"。例如(E.g.):
 LOCAL_ARM_MODE := arm 
注意你也能命令編譯系統用"arm"模式只編譯指定的源代碼,是通過追加".arm"後綴到它的源文件名字。例如(for expamle): 
LOCAL_SRC_FILES := foo.c bar.c.arm 
告知編譯系統總是用"arm"模式編譯"bar.c"文件,根據"LOCAL_ARM_MODE"變量的值來編譯"foo.c"。 
注意:在你的Application.mk文件中,設置APP_OPTIM爲"debug"將也總是強制"ARM"二進制文件的產生。由於問題(bugs),在調試工具鏈中,不能很好的處理"thumb"編碼。
 

LOCAL_ARM_NEON
定義變量爲"true"是允許ARM Andvanced SIMD(又名(a.k.a)NEON)的使用,在你的C和C++源代碼中GCC內建這,即在彙編文件中是"NEON"指令。
 當目標了"armeabi-v7a"ABI(對應了ARMv7指令集)時,你只能定義這個變量。注意不是所有ARMv7基礎的"CPUs"都支 持"NEON"指令集擴展,你應該執行運行時偵測來能在運行時安全地使用這代碼。爲了學習關於這更多的,請閱讀文本"docs/CPU-ARM- NEON.TXT"和"docs/CPU-FEATURES.TXT"。
 二選一地,你也能在指定只在指定的源代碼文件可以使用"NEON"編譯,是通過使用".neon"後綴來支持的。如(as in): 
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"後綴的後面,如果兩個都有時。(即(i.e.)foo.c.arm.neon能工作,但foo.c.neon.arm不行)
 

LOCAL_DISABLES_NO_EXECUTE
"Android NDK r4"添加對"NX bit"安全特性的支持。默認這個是打開的,但我們通過設置這個值爲"true"來關閉它,如果你真地需要這樣。 
注意:這個特性不會修改"ABI",它只能在內核目標爲"ARMv6+"的"CPU"設備上其作用。帶有這個特性能產生的機器碼將在運行着較早期CPU架構的設備上不修改的運行。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章