http://blogold./u3/99423/showart_2206760.html
Android.mk文件語法規(guī)范及使用模板 Android.mk文件語法規(guī)范 根據(jù)eoeandroid上的的連載,進(jìn)行一些更新,、修改和加亮,。 今天翻譯ANDROID-MK.TXT文件(英文原文件在/development/Ndk/Docs/android-mk.txt) Android.mk文件語法規(guī)范
Introduction: Android.mk編譯文件是用來向Android NDK描述你的C,C++源代碼文件的, 這篇文檔描述了它的語法,。在閱讀下面的內(nèi)容之前,,假定你已經(jīng)閱讀了docs/OVERVIEW.TXT文件,了解了它們的腳色和用途,。
概述: 一個Android.mk file用來向編譯系統(tǒng)描述你的源代碼,。具體來說:-該文件是GNU Makefile的一小部分,會被編譯系統(tǒng)解析一次或更多次的build系統(tǒng),。因此,,您應(yīng)盡量減少您聲明的變量,不要認(rèn)為某些變量在解析過程中不會被定義,。-這個文件的語法允許把你的源代碼組織成模塊,,一個模塊屬下列類型之一: 靜態(tài)庫 共享庫 只有共享庫將被安裝/復(fù)制到您的應(yīng)用軟件包。雖然靜態(tài)庫能被用于生成共享庫,。 你可以在每一個Android.mk file中定義一個或多個模塊,,你也可以在幾個模塊中使用同一個源代碼文件。 /*****************************************************************************/ -編譯系統(tǒng)為你處理許多細(xì)節(jié)問題,。例如,,你不需要在你的Android.mk中列出頭文件和依賴文件。NDK編譯系統(tǒng)將會為你自動處理這些問題,。這也意味著,,在升級NDK后,,你應(yīng)該得到新的toolchain/platform支持,而且不需要改變你的Android.mk文件,。 注意,,這個語法同公開發(fā)布的Android平臺的開源代碼很接近,然而編譯系統(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文件會象下面這樣: ---------- cut here ------------------ LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE:= helloworld LOCAL_SRC_FILES := helloworld.c include $(BUILD_SHARED_LIBRARY) ---------- cut here ------------------ 好,我們來解釋一下這幾行代碼: LOCAL_PATH := $(call my-dir) 一個Android.mk file首先必須定義好LOCAL_PATH變量,。它用于在開發(fā)樹中查找源文件,。在這個例子中,,宏函數(shù)’my-dir’, 由編譯系統(tǒng)提供,,用于返回當(dāng)前路徑(即包含Android.mk file文件的目錄)。 include $( CLEAR_VARS) CLEAR_VARS由編譯系統(tǒng)提供,,指定讓GNU MAKEFILE為你清除許多LOCAL_XXX變量(例如 LOCAL_MODULE, LOCAL_SRC_FILES, LOCAL_STATIC_LIBRARIES, 等等...), 除LOCAL_PATH ,。這是必要的,,因?yàn)樗械木幾g控制文件都在同一個GNU MAKE執(zhí)行環(huán)境中,所有的變量都是全局的,。 LOCAL_MODULE := helloworld LOCAL_MODULE變量必須定義,,以標(biāo)識你在Android.mk文件中描述的每個模塊。名稱必須是唯一的,,而且不包含任何空格。注意編譯系統(tǒng)會自動產(chǎn)生合適的前綴和后綴,,換句話說,,一個被命名為'foo'的共享庫模塊,將會生成'libfoo.so'文件,。 重要注意事項(xiàng) 如果你把庫命名為‘libhelloworld’,,編譯系統(tǒng)將不會添加任何的lib前綴,也會生成libhelloworld.so,,這是為了支持來源于Android平臺的源代碼的Android.mk文件,,如果你確實(shí)需要這么做的話。 LOCAL_SRC_FILES := helloworld.c LOCAL_SRC_FILES變量必須包含將要編譯打包進(jìn)模塊中的C或C++源代碼文件,。注意,,你不用在這里列出頭文件和包含文件,,因?yàn)榫幾g系統(tǒng)將會自動為你找出依賴型的文件;僅僅列出直接傳遞給編譯器的源代碼文件就好,?!咀⒁猓J(rèn)的C++源碼文件的擴(kuò)展名是’.cpp’. 指定一個不同的擴(kuò)展名也是可能的,,只要定義LOCAL_DEFAULT_CPP_EXTENSION變量,,不要忘記開始的小圓點(diǎn)(也就是定義為‘.cxx’,而不是‘cxx’)(當(dāng)然這一步我們一般不會去改它)】 include $(BUILD_SHARED_LIBRARY) BUILD_SHARED_LIBRARY是編譯系統(tǒng)提供的變量,指向一個GNU Makefile腳本(應(yīng)該就是在build/core目錄下的shared_library.mk),,負(fù)責(zé)收集自從上次調(diào)用'include $(CLEAR_VARS)'以來,,定義在LOCAL_XXX變量中的所有信息,并且決定編譯什么,,如何正確地去做,。并根據(jù)其規(guī)則生成靜態(tài)庫。同理對于靜態(tài)庫,。
/****************************************************************************/ 在sources/samples目錄下有更復(fù)雜一點(diǎn)的例子,,寫有注釋的Android.mk文件,你可以看看,。 參考: 這是一份你應(yīng)該在Android.mk中依賴或定義的變量列表,,您可以定義其他變量為自己使用, 但是NDK編譯系統(tǒng)保留下列變量名: -以LOCAL_開頭的名字(例如 LOCAL_MODULE) -以PRIVATE_, NDK_ or APP_開頭的名字(內(nèi)部使用) -小寫名字(內(nèi)部使用,,例如’my-dir’) 如果您為了方便在Android.mk中定義自己的變量,,我們建議使用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文件解析之前,,就由編譯系統(tǒng)定義好了,。 注意在某些情況下,NDK可能分析Android.mk幾次,,每一次某些變量的定義會有不同,。 CLEAR_VARS 指向一個編譯腳本,幾乎所有未定義的LOCAL_XXX變量都在"Module-description"節(jié)中列出,。 你必須在開始一個新模塊之前包含這個腳本,。include $(CLEAR_VARS)
BUILD_SHARED_LIBRARY 指向編譯腳本,收集所有的你在LOCAL_XXX變量中提供的信息,,并且決定如何把你列出的源代碼文件編譯成一個共享庫,。注意,你必須至少在包含這個文件之前定義LOCAL_MODULE和LOCAL_SRC_FILES,,使用例子: include $(BUILD_SHARED_LIBRARY) 注意這將生成一個名為lib$(LOCAL_MODULE).so的文件,。
BUILD_STATIC_LIBRARY 一個BUILD_SHARED_LIBRARY變量用于編譯一個靜態(tài)庫。靜態(tài)庫不會復(fù)制到你的project/packages中,,誕生能夠用于編譯共享庫,,(看下面描述的LOCAL_STATIC_LIBRARIES and LOCAL_STATIC_WHOLE_LIBRARIES) 使用例子: include $(BUILD_STATIC_LIBRARY) 注意,,這將會生成一個名為lib$(LOCAL_MODULE).a的文件。
TARGET_ARCH 目標(biāo)CPU平臺的名字,,如同在android開放源碼中指定的那樣,。如果是’arm’,表示要生成ARM兼容的指令,,與CPU架構(gòu)的修訂版無關(guān),。
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
TARGET_ARCH_ABI 暫時只支持兩個value,,armeabi和armeabi-v7a,。在現(xiàn)在的版本中一般把這兩個值簡單的定義為arm,通過android 平臺內(nèi)部對它重定義來獲得更好的匹配,。 其他的ABI將在以后的NDK版本中介紹,,它們會有不同的名字。注意所有基于ARM的ABI都會把'TARGET_ARCH'定義成‘arm’,,但是會有不同的‘TARGET_ARCH_ABI’
TARGET_ABI 目標(biāo)平臺和ABI的組合,,它事實(shí)上被定義成$(TARGET_PLATFORM)-$(TARGET_ARCH_ABI) 在你想要在真實(shí)的設(shè)備中針對一個特別的目標(biāo)系統(tǒng)進(jìn)行測試時,會有用,。在默認(rèn)的情況下,,它會是'android-3-arm'。
/*****************************************************************************/ 下面是GNU Make ‘功能’宏,,必須通過使用'$(call <function>)'來求值,,他們返回文本化的信息。 my-dir 返回當(dāng)前Android.mk所在的目錄路徑,,相對于NDK編譯系統(tǒng)的頂層,。這是有用的,在Android.mk文件的開頭如此定義: LOCAL_PATH := $(call my-dir)
all-subdir-makefiles 返回一個位于當(dāng)前'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 這項(xiàng)功能用于向編譯系統(tǒng)提供深層次嵌套的代碼目錄層次。注意,,在默認(rèn)情況下,,NDK將會只搜索在sources/*/Android.mk中的文件。
this-makefile 返回當(dāng)前Makefile的路徑(即這個函數(shù)調(diào)用的地方)
parent-makefile 返回調(diào)用樹中父Makefile路徑,。即包含當(dāng)前Makefile的Makefile路徑。
grand-parent-makefile 猜猜看...
/*****************************************************************************/ 模塊描述變量: 下面的變量用于向編譯系統(tǒng)描述你的模塊,。你應(yīng)該定義在'include $(CLEAR_VARS)'和'include $(BUILD_XXXXX)'之間定義,。正如前面描寫的那樣,$(CLEAR_VARS是一個腳本,,清除所有這些變量,,除非在描述中顯式注明,。
LOCAL_PATH 這個變量用于給出當(dāng)前文件的路徑。你必須在Android.mk的開頭定義,,可以這樣使用:
LOCAL_PATH := $(call my-dir) 這個變量不會被$(CLEAR_VARS)清除,,因此每個Android.mk只需要定義一次(即使你在一個文件中定義了幾個模塊的情況下)。
LOCAL_MODULE 這是你模塊的名字,,它必須是唯一的,,而且不能包含空格。你必須在包含任一的$(BUILD_XXXX)腳本之前定義它,。模塊的名字決定了生成文件的名字,,例如,如果一個一個共享庫模塊的名字是<foo>,,那么生成文件的名字就是lib<foo>.so,。但是,在你的NDK生成文件中(或者Android.mk或者Application.mk),,你應(yīng)該只涉及(引用)有正常名字的其他模塊,。
LOCAL_SRC_FILES 這是要編譯的源代碼文件列表。只要列出要傳遞給編譯器的文件,,因?yàn)榫幾g系統(tǒng)自動為你計(jì)算依賴,。 注意源代碼文件名稱都是相對于LOCAL_PATH的,你可以使用路徑部分,,例如: LOCAL_SRC_FILES := foo.c \ toto/bar.c 注意:在生成文件中都要使用UNIX風(fēng)格的斜杠(/).windows風(fēng)格的反斜杠不會被正確的處理,。
LOCAL_CPP_EXTENSION 這是一個可選變量,用來指定C++代碼文件的擴(kuò)展名,,默認(rèn)是'.cpp',但是你可以改變它,,比如: LOCAL_CPP_EXTENSION := .cxx
LOCAL_C_INCLUDES 路徑的可選配置,是從根目錄開始的,, all sources (C, C++ and Assembly). For example: LOCAL_C_INCLUDES := sources/foo Or even: LOCAL_C_INCLUDES := $(LOCAL_PATH)/../foo 需要在任何包含LOCAL_CFLAGS / LOCAL_CPPFLAGS標(biāo)志之前,。
LOCAL_CFLAGS 可選的編譯器選項(xiàng),在編譯C代碼文件的時候使用,。 這可能是有用的,,指定一個附加的包含路徑(相對于NDK的頂層目錄),宏定義,,或者編譯選項(xiàng),。 重要信息:不要在Android.mk中改變optimization/debugging級別,只要在Application.mk中指定合適的信息,,就會自動地為你處理這個問題,,在調(diào)試期間,會讓NDK自動生成有用的數(shù)據(jù)文件。
LOCAL_CXXFLAGS Same as LOCAL_CFLAGS for C++ source files
LOCAL_CPPFLAGS 與LOCAL_CFLAGS相同,,但是對C 和 C++ source files都適用,。
LOCAL_STATIC_LIBRARIES 應(yīng)該鏈接到這個模塊的靜態(tài)庫列表(使用BUILD_STATIC_LIBRARY生成),這僅僅對共享庫模塊才有意義,。
LOCAL_SHARED_LIBRARIES 這個模塊在運(yùn)行時要依賴的共享庫模塊列表,,在鏈接時需要,在生成文件時嵌入的相應(yīng)的信息,。注意:這不會附加列出的模塊到編譯圖,,也就是,你仍然需要在Application.mk中把它們添加到程序要求的模塊中,。
LOCAL_LDLIBS 編譯你的模塊要使用的附加的鏈接器選項(xiàng),。這對于使用”-l”前綴傳遞指定庫的名字是有用的。例如,,下面將告訴鏈接器生成的模塊要在加載時刻鏈接到/system/lib/libz.so LOCAL_LDLIBS := -lz 看docs/STABLE-APIS.TXT獲取你使用NDK發(fā)行版能鏈接到的開放的系統(tǒng)庫列表,。
LOCAL_ALLOW_UNDEFINED_SYMBOLS 默認(rèn)情況下,在試圖編譯一個共享庫時,,任何未定義的引用將導(dǎo)致一個“未定義的符號”錯誤,。這對于在你的源代碼文件中捕捉錯誤會有很大的幫助。 然而,,如果你因?yàn)槟承┰?,需要不啟動這項(xiàng)檢查,把這個變量設(shè)為‘true’,。注意相應(yīng)的共享庫可能在運(yùn)行時加載失敗,。(這個一般盡量不要去設(shè)為true)
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)編譯特定的類型,比如 LOCAL_SRC_FILES := foo.c bar.c.arm 這樣就告訴系統(tǒng)總是將bar.c以arm的模式編譯,,
Android.mk使用模板 在一個Android.mk中可以生成多個可執(zhí)行程序,、動態(tài)庫和靜態(tài)庫。 1,,編譯應(yīng)用程序的模板: #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加入所需要鏈接的靜態(tài)庫(*.a)的名稱,,LOCAL_SHARED_LIBRARIES中加入所需要鏈接的動態(tài)庫(*.so)的名稱,LOCAL_MODULE表示模塊最終的名稱,,BUILD_EXECUTABLE表示以一個可執(zhí)行程序的方式進(jìn)行編譯,。 2,,編譯靜態(tài)庫的模板: #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表示編譯一個靜態(tài)庫,。 3,編譯動態(tài)庫的模板: #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表示編譯一個共享庫,。
以上三者的生成結(jié)果分別在如下,generic依具體target會變: out/target/product/generic/obj/EXECUTABLE out/target/product/generic/obj/STATIC_LIBRARY out/target/product/generic/obj/SHARED_LIBRARY 每個模塊的目標(biāo)文件夾分別為: 可執(zhí)行程序:XXX_intermediates 靜態(tài)庫: XXX_static_intermediates 動態(tài)庫: XXX_shared_intermediates 另外,,在Android.mk文件中,,還可以指定最后的目標(biāo)安裝路徑,用LOCAL_MODULE_PATH和LOCAL_UNSTRIPPED_PATH來指定,。不同的文件系統(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) |
|