天天看點

Android.mk檔案文法規範及使用模闆

Android.mk檔案文法規範

根據eoeandroid上的的連載,進行一些更新、修改和加亮。

今天翻譯ANDROID-MK.TXT檔案(英文原檔案在/development/Ndk/Docs/android-mk.txt)

Android.mk檔案文法規範

Introduction:

Android.mk編譯檔案是用來向Android NDK描述你的C,C++源代碼檔案的, 這篇文檔描述了它的文法。在閱讀下面的内容之前,假定你已經閱讀了docs/OVERVIEW.TXT檔案,了解了它們的腳色和用途。

概述:

一個Android.mk file用來向編譯系統描述你的源代碼。具體來說:-該檔案是GNU Makefile的一小部分,會被編譯系統解析一次或更多次的build系統。是以,您應盡量減少您聲明的變量,不要認為某些變量在解析過程中不會被定義。-這個檔案的文法允許把你的源代碼組織成子產品,一個子產品屬下列類型之一:

靜态庫

共享庫

隻有共享庫将被安裝/複制到您的應用軟體包。雖然靜态庫能被用于生成共享庫。

你可以在每一個Android.mk file中定義一個或多個子產品,你也可以在幾個子產品中使用同一個源代碼檔案。

-編譯系統為你處理許多細節問題。例如,你不需要在你的Android.mk中列出頭檔案和依賴檔案。NDK編譯系統将會為你自動處理這些問題。這也意味着,在更新NDK後,你應該得到新的toolchain/platform支援,而且不需要改變你的Android.mk檔案。

注意,這個文法同公開釋出的Android平台的開源代碼很接近,然而編譯系統實作他們的方式卻是不同的,這是故意這樣設計的,可以讓程式開發人員重用外部庫的源代碼更容易。

簡單的例子:

---------------

在描述文法細節之前,咱們來看一個簡單的"hello world"的例子,比如,下面的檔案:

sources/helloworld/helloworld.c

sources/helloworld/Android.mk

'helloworld.c'是一個JNI共享庫,實作傳回"hello world"字元串的原生方法。

相應的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變量。它用于在開發樹中查找源檔案。在這個例子中,宏函數’my-dir’, 由編譯系統提供,用于傳回目前路徑(即包含Android.mk file檔案的目錄)。

include $( CLEAR_VARS)

CLEAR_VARS由編譯系統提供,指定讓GNU MAKEFILE為你清除許多LOCAL_XXX變量(例如 LOCAL_MODULE, LOCAL_SRC_FILES, LOCAL_STATIC_LIBRARIES, 等等...),

除LOCAL_PATH 。這是必要的,因為所有的編譯控制檔案都在同一個GNU MAKE執行環境中,所有的變量都是全局的。

LOCAL_MODULE := helloworld

LOCAL_MODULE變量必須定義,以辨別你在Android.mk檔案中描述的每個子產品。名稱必須是唯一的,而且不包含任何空格。注意編譯系統會自動産生合适的字首和字尾,換句話說,一個被命名為'foo'的共享庫子產品,将會生成'libfoo.so'檔案。

重要注意事項

如果你把庫命名為‘libhelloworld’,編譯系統将不會添加任何的lib字首,也會生成libhelloworld.so,這是為了支援來源于Android平台的源代碼的Android.mk檔案,如果你确實需要這麼做的話。

LOCAL_SRC_FILES := helloworld.c

LOCAL_SRC_FILES變量必須包含将要編譯打包進子產品中的C或C++源代碼檔案。注意,你不用在這裡列出頭檔案和包含檔案,因為編譯系統将會自動為你找出依賴型的檔案;僅僅列出直接傳遞給編譯器的源代碼檔案就好。【注意,預設的C++源碼檔案的擴充名是’.cpp’. 指定一個不同的擴充名也是可能的,隻要定義LOCAL_DEFAULT_CPP_EXTENSION變量,不要忘記開始的小圓點(也就是定義為 ‘.cxx’,而不是‘cxx’)(當然這一步我們一般不會去改它)】

include $(BUILD_SHARED_LIBRARY)

BUILD_SHARED_LIBRARY是編譯系統提供的變量,指向一個GNU Makefile腳本(應該就是在build/core目錄下的shared_library.mk),負責收集自從上次調用'include $(CLEAR_VARS)'以來,定義在LOCAL_XXX變量中的所有資訊,并且決定編譯什麼,如何正确地去做。并根據其規則生成靜态庫。同理對于靜态庫。

在sources/samples目錄下有更複雜一點的例子,寫有注釋的Android.mk檔案,你可以看看。

參考:

這是一份你應該在Android.mk中依賴或定義的變量清單,您可以定義其他變量為自己使用,

但是NDK編譯系統保留下列變量名:

-以LOCAL_開頭的名字(例如 LOCAL_MODULE)

-以PRIVATE_, NDK_ or APP_開頭的名字(内部使用)

-小寫名字(内部使用,例如’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檔案解析之前,就由編譯系統定義好了。

注意在某些情況下,NDK可能分析Android.mk幾次,每一次某些變量的定義會有不同。

CLEAR_VARS

指向一個編譯腳本,幾乎所有未定義的LOCAL_XXX變量都在"Module-description"節中列出。

你必須在開始一個新子產品之前包含這個腳本。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變量用于編譯一個靜态庫。靜态庫不會複制到你的project/packages中,誕生能夠用于編譯共享庫,(看下面描述的LOCAL_STATIC_LIBRARIES and LOCAL_STATIC_WHOLE_LIBRARIES)

使用例子:

include $(BUILD_STATIC_LIBRARY)

注意,這将會生成一個名為lib$(LOCAL_MODULE).a的檔案。

TARGET_ARCH

目标CPU平台的名字,如同在android開放源碼中指定的那樣。如果是’arm’,表示要生成ARM相容的指令,與CPU架構的修訂版無關。

TARGET_PLATFORM

Android.mk解析的時候,目标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。在現在的版本中一般把這兩個值簡單的定義為arm,通過android 平台内部對它重定義來獲得更好的比對。

其他的ABI将在以後的NDK版本中介紹,它們會有不同的名字。注意所有基于ARM的ABI都會把'TARGET_ARCH'定義成‘arm’,但是會有不同的‘TARGET_ARCH_ABI’

TARGET_ABI

  目标平台和ABI的組合,它事實上被定義成$(TARGET_PLATFORM)-$(TARGET_ARCH_ABI) 在你想要在真實的裝置中針對一個特别的目标系統進行測試時,會有用。在預設的情況下,它會是'android-3-arm'。

下面是GNU Make ‘功能’宏,必須通過使用'$(call <function>)'來求值,他們傳回文本化的資訊。

my-dir

傳回目前Android.mk所在的目錄路徑,相對于NDK編譯系統的頂層。這是有用的,在Android.mk檔案的開頭如此定義:

LOCAL_PATH := $(call my-dir)

all-subdir-makefiles

   傳回一個位于目前'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

這項功能用于向編譯系統提供深層次嵌套的代碼目錄層次。注意,在預設情況下,NDK将會隻搜尋在sources

子產品描述變量:

下面的變量用于向編譯系統描述你的子產品。你應該定義在'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)腳本之前定義它。子產品的名字決定了生成檔案的名字,例如,如果一個一個共享庫子產品的名字是<foo>,那麼生成檔案的名字就是lib<foo>.so。但是,在你的NDK生成檔案中(或者Android.mk或者Application.mk),你應該隻涉及(引用)有正常名字的其他子產品。

LOCAL_SRC_FILES

這是要編譯的源代碼檔案清單。隻要列出要傳遞給編譯器的檔案,因為編譯系統自動為你計算依賴。

注意源代碼檔案名稱都是相對于LOCAL_PATH的,你可以使用路徑部分,例如:

LOCAL_SRC_FILES := foo.c /

toto/bar.c

注意:在生成檔案中都要使用UNIX風格的斜杠(/).windows風格的反斜杠不會被正确的處理。

LOCAL_CPP_EXTENSION

這是一個可選變量,用來指定C++代碼檔案的擴充名,預設是'.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标志之前。

 LOCAL_CFLAGS

可選的編譯器選項,在編譯C代碼檔案的時候使用。

這可能是有用的,指定一個附加的包含路徑(相對于NDK的頂層目錄),宏定義,或者編譯選項。

 重要資訊:不要在Android.mk中改變optimization/debugging級别,隻要在Application.mk中指定合适的資訊,就會自動地為你處理這個問題,在調試期間,會讓NDK自動生成有用的資料檔案。

LOCAL_CXXFLAGS

Same as LOCAL_CFLAGS for C++ source files

LOCAL_CPPFLAGS

與LOCAL_CFLAGS相同,但是對C 和 C++ source files都适用。

LOCAL_STATIC_LIBRARIES

應該連結到這個子產品的靜态庫清單(使用BUILD_STATIC_LIBRARY生成),這僅僅對共享庫子產品才有意義。

LOCAL_SHARED_LIBRARIES

這個子產品在運作時要依賴的共享庫子產品清單,在連結時需要,在生成檔案時嵌入的相應的資訊。注意:這不會附加列出的子產品到編譯圖,也就是,你仍然需要在Application.mk中把它們添加到程式要求的子產品中。

LOCAL_LDLIBS

編譯你的子產品要使用的附加的連結器選項。這對于使用”-l”字首傳遞指定庫的名字是有用的。例如,下面将告訴連結器生成的子產品要在加載時刻連結到/system/lib/libz.so

LOCAL_LDLIBS := -lz

看docs/STABLE-APIS.TXT擷取你使用NDK發行版能連結到的開放的系統庫清單。

LOCAL_ALLOW_UNDEFINED_SYMBOLS

  預設情況下,在試圖編譯一個共享庫時,任何未定義的引用将導緻一個“未定義的符号”錯誤。這對于在你的源代碼檔案中捕捉錯誤會有很大的幫助。

然而,如果你因為某些原因,需要不啟動這項檢查,把這個變量設為‘true’。注意相應的共享庫可能在運作時加載失敗。(這個一般盡量不要去設為true)

LOCAL_ARM_MODE

       預設情況下,arm目标二進制會以thumb的形式生成(16位),你可以通過設定這個變量為arm如果你希望你的module是以32位指令的形式。

    'arm' (32-bit instructions) mode. E.g.:

      LOCAL_ARM_MODE := arm

注意你同樣可以在編譯的時候告訴系統編譯特定的類型,比如

       LOCAL_SRC_FILES := foo.c bar.c.arm

這樣就告訴系統總是将bar.c以arm的模式編譯,

Android.mk使用模闆

在一個Android.mk中可以生成多個可執行程式、動态庫和靜态庫。

1,編譯應用程式的模闆:

     #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加入所需要連結的靜态庫(*.a)的名稱, LOCAL_SHARED_LIBRARIES中加入所需要連結的動态庫(*.so)的名稱,LOCAL_MODULE表示子產品最終的名稱, BUILD_EXECUTABLE表示以一個可執行程式的方式進行編譯。

2,編譯靜态庫的模闆:

     #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表示編譯一個靜态庫。

3,編譯動态庫的模闆:

     #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表示編譯一個共享庫。

以上三者的生成結果分别在如下,generic依具體target會變:

out/target/product/generic/obj/EXECUTABLE

out/target/product/generic/obj/STATIC_LIBRARY

out/target/product/generic/obj/SHARED_LIBRARY

      每個子產品的目标檔案夾分别為:

可執行程式:XXX_intermediates

靜态庫:      XXX_static_intermediates

動态庫:      XXX_shared_intermediates

      另外,在Android.mk檔案中,還可以指定最後的目标安裝路徑,用LOCAL_MODULE_PATH和LOCAL_UNSTRIPPED_PATH來指定。不同的檔案系統路徑用以下的宏進行選擇:

TARGET_ROOT_OUT:表示根檔案系統。

TARGET_OUT:表示system檔案系統。

TARGET_OUT_DATA:表示data檔案系統。

用法如:

LOCAL_MODULE_PATH:=$(TARGET_ROOT_OUT)

繼續閱讀