Android.mk語法說明(android ndk開發)

下面是我個人對android-ndk-r4版本中Android.mk文件做的翻譯,由於自己英語水平和專業知識的限制,有些地方可能翻譯的不是很準確,敬請指正,本文僅希望對做android NDK開發的同仁們能提供一點點的幫助而已。

Android.mk文件是用來描述你想要編譯進系統的資源的。

這個文件的語法允許你把你的資源打包進“modules”。Module應該是下面module中的一種:

- a static library

- a shared library

只有shared library會被打包到你的應用程序中,儘管static library也能用來生產shared library。

你可以在一個Android.mk中定義多個module,你也可以在幾個module中使用相同的資源文件。

編譯系統會爲你處理一些細節。例如,你不需要在你的Android.mk文件中列出你的頭文件或是你的文件之間明確的依賴關係。NDK編譯系統會自動幫你處理。

這同時意味着,當升級到新版本的NDK時,你不需要動你的Android.mk文件就可以使用心得toolchain/platform支持。

注意,用在Android.mk文件中的語法和整個的android平臺的開源資源語法是不同的。編譯系統實現了對他們不同的使用,這是故意這樣設計的,用來允許應用開發人員更容易地重用外部庫資源代碼。

一個簡單的例子:

在語法詳細說明之前,讓我們先來看一個簡單的“hello-jni”例子,文件在$NDK/samples/hello-jni下:

在這我們可以看到:

-src目錄下包含這個簡單的android工程的一個java源文件

-jni目錄下包含了這個例子的本地源文件

這個源文件實現了一個簡單的共享庫,這個共享庫實現了一個想vm應用程序返回一個字符串的本地方法。

-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”宏函數用來返回當前目錄的路徑(Android.mk文件所在的目錄)。

include $(CLEAR_VARS)

編譯系統提供的一個指向特殊的GNU Makefile文件的CLEAR_VARS變量將爲你清理很多LOCAL_PATH中的LOCAL_XXX變量(例如: LOCAL_MODULE, LOCAL_SRC_FILES, LOCAL_STATIC_LIBRARIES等等)。這是有必要的,因爲所有的編譯控制文件都會在一個單獨的GNU Make可執行上下文中被解析,在這裏所有的變量都是全局的。

LOCAL_MODULE := hello-jni

用來標識分佈在Android.mk文件中的每一個module的LOCAL_MODULE變量必須定義。名字必須是唯一的而且不能有空格。

注意,編譯系統會給相應的生成文件自動地添加適當的前綴和後綴。換句話說,一個命名爲“foo”的共享庫module將生成名爲“libfoo.so”的文件。

重點注意:

如果你的module命名爲“libfoo”,編譯系統不會爲你添加另外一個“lib”前綴,還是會生成一個“libfoo.so”的文件而已。這個爲了支持你需要使用的android平臺資源的Android.mk文件。

LOCAL_SRC_FILES := hello-jni.c

LOCAL_SRC_FILES變量必須包含一個將要被編譯和彙編進module的一個C/C++資源文件列表。注意你不需要列出頭文件和包含文件,因爲編譯系統會自動幫你計算依賴關係;僅僅需要列出直接傳遞給編譯器的資源文件就可以了。

注意:默認的C++資源文件的擴展名是“.cpp”。然而可以通過定義LOCAL_DEFAULT_CPP_EXTENSION變量來指定一個不同的擴展名。不要忘記最開始的dot(例如:.cxx是可以的,但是cxx是不行的)。

  include $(BUILD_SHARED_LIBRARY)

BUILD_SHARED_LIBRARY是編譯系統提供的一個指向GNU Makefile腳本的變量,它負責收集從最近的include $(CLEAR_VARS)' 變量開始的所有內定義的 LOCAL_XXX變量的信息,然後決定哪些需要編譯以及怎樣編譯。BUILD_STATIC_LIBRARY變量可以生成一個static library。

在samples目錄下有幾個複雜的例子,在他們的Android.mk文件中你可以看到一些註釋。

Reference:

下面是你可以在Android.mk文件裏可以直接使用或是定義的變量的列表。你能夠定義其它的變量供自己使用,但是下面的變量名是NDK編譯系統的保留字:

- 以LOCAL_ 開頭命名的 (例如LOCAL_MODULE)
- 以PRIVATE_,NDK_ 或是 APP_  命名的(僅供內部使用)
- 以小寫字母命名的(僅供內部使用, 例如 'my-dir')

如果你需要在Android.mk文件裏定義一個你自己使用比較方便的變量,我們建議使用MY_前綴,這是一個普通的例子:

    MY_SOURCES := foo.c
    ifneq ($(MY_CONFIG_BAR),)
      MY_SOURCES += bar.c
    endif

    LOCAL_SRC_FILES += $(MY_SOURCES)

好,我們接着看:

NDK提供的變量:

在你的Android.mk文件解析之前,編譯系統定義了這些GNU Make變量。注意,在某種情況下NDK可能會多次解析你的Android.mk文件,每一次解析某些變量的定義可能不同。

CLEAR_VARS

指向一個幾乎所有在"Module-description"部分列出的LOCAL_XXX變量都沒有定義的編譯腳本(我的理解就是在編譯前清空所有變量,然後在這個變量的下面再重新定義)。在開始一個新的module之前你必須包含這個腳本,例如:

include $(CLEAR_VARS)

BUILD_SHARED_LIBRARY

指向一個收集所有你提供的關於module的LOCAL_XXX變量的信息的編譯腳本,然後決定如何根據你列出的資源編譯一個目標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架構。如果是“arm”用來所有的兼容ARM的編譯,不依賴與CPU架構版本。

TARGET_PLATFORM

當Android.mk文件解析時,指明一個android目標平臺。例如"android-3”對應"android1.5"系統鏡像。完整的平臺名字和android系統鏡像的對應列表可以閱讀docs/目錄下STABLE-APIS.TXT文檔。

TARGET_ARCH_ABI

當Android.mk文件解析時,指明一個目標CPU+ABI。有兩個值可供使用:

armeabi
            對應Armv5TE

       armeabi-v7a

注意:Android NDK 1.6_r1之上的版本,這個變量被定義爲'arm'。然而,這個變量的重定義能夠被Android platform內部更好的使用。

對於更多的ABI架構和對應的兼容性問題的細節,可以閱讀docs目錄下的CPU-ARCH-ABIS.TXT文檔。

其他的ABI架構將會在以後的NDK版本中引入,並且有不同的名字。注意,所有基於ARM的ABIs都會被'TARGET_ARCH' 定義爲 'arm',但是可能有不同的'TARGET_ARCH_ABI'。

TARGET_ABI

目標平臺和abi的連結,它被定義爲$(TARGET_PLATFORM)-$(TARGET_ARCH_ABI),當你用真機測試一個指定的目標平臺鏡像的時候會有用處。

默認情況下,它將是'android-3-armeabi'

(Android NDK 1.6_r1以上的版本,'android-3-arm'是默認的)

NDK提供的宏函數

下面是GNU Make宏函數,通過使用'$(call <function>)'來獲得他的值。它們返回文本信息。

my-dir

返回相對於上層的NDK編譯系統的當前Android.mk文件目錄的路徑。這對於以下面這種方式在你的Android.mk文件的開始定義LOCAL_PATH變量很有用:

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文件的路徑(例如,函數在哪裏被調用)。

parent-makefile

放回父Makefile文件在包含樹中的路徑。例如包含當前Makefile文件的Makefile文件的路徑。

Module描述變量

下面的變量是用來向系統描述你的module的。你應該在一個'include $(CLEAR_VARS)'和'一個include $(BUILD_XXXXX)'變量之間定義它們中的某些變量。前面的部分已經介紹過了,$(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>。可是,你應該在你的NDK編譯文件中(無論是Android.mk還是 Application.mk)進引用其它module的通用的名字(例如<foo>)。

LOCAL_SRC_FILES

這是一個將用於你的module編譯的資源文件列表。只用在列表中的文件纔會傳遞給編譯器,因爲編譯系統自動幫你計算依賴關係。

注意,所有的資源文件名字都是相對於LOCAL_PATH的,你能夠使用路徑分隔符,例如:

  LOCAL_SRC_FILES := foo.c \
                         toto/bar.c

注意:只有使用Unix風格的正斜線(/)在編譯文件中纔可以,windows風格的反斜線(\)不能被正確處理。

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文件中嘗試去改變優化/調試等級,這個可以通過在你的Android.mk文件中指明適當的信息來讓系統自動處理,將會使NDK生成在調試中可以使用的有用的數據文件。

注意:在android-ndk-1.5_r1中,對應標記僅能用在c源文件上,不能用在c++源文件上。這能夠正確匹配所有的android編譯系統行爲。(你現在可以使用LOCAL_CPPFLAGS來僅爲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

將要被鏈接進這個module的static libraries modules的列表(用BUILD_STATIC_LIBRARY編譯過的)。這個僅在shared library modules中能被檢測到。

LOCAL_SHARED_LIBRARIES

依賴於運行時的shared libraries *modules*的列表。這在鏈接時是必要的,爲了把對應的信息嵌入到生成的文件中。

注意:他不會把列出的module添加到編譯表中,例如:你仍然需要在你的Application.mk文件中把他們添加到你的應用程序需要的module中。

LOCAL_LDLIBS

編譯你的module時使用到的額外的鏈接器標識列表。它能夠用一個帶 "-l" 前綴的表達式傳遞一個指明的系統庫的名字。例如:下面的定義將會通知編譯器在加載的時候生成一個鏈接到/system/lib/libz.so的module:

LOCAL_LDLIBS := -lz

閱讀docs目錄下的STABLE-APIS.TXT文檔,你將能瞭解到在這個NDK版本中你可以鏈接的系統庫的列表。

LOCAL_ALLOW_UNDEFINED_SYMBOLS

默認情況下,當嘗試編譯一個shared library時任何一個沒有定義的引用都將產生一個"undefined symbol"錯誤。這對在你的源代碼中捕獲bug很有幫助。
可是,如果由於某種原因你需要讓這些檢查失效,把這個變量設置爲'true'。注意,對應的shared library在運行時加載可能出錯。

LOCAL_ARM_MODE

默認情況下,ARM的二進制文件將生成每一條指令都是16位的'thumb'模式。你可以定義這個變量爲'arm',如果你想強制生成的module目標文件爲 'arm'(每條指令32位)模式的。例如:

LOCAL_ARM_MODE := arm

注意,你也可以通過在源文件名後面添加一個'.arm'來指示編譯系統只把指定的文件編譯'bar.c'。例如:

  LOCAL_SRC_FILES := foo.c bar.c.arm

通知編譯系統總是把'bar.c'編譯成'.arm'模式,而依據LOCAL_ARM_MODE變量的值來編譯 foo.c 文件。

注意:在你的Application.mk文件中設置APP_OPTIM爲 'debug'也能強制生成ARM二進制文件。這是因爲在thumb模式下toolchain debugger 中的bug不能得到較好的處理。

LOCAL_ARM_NEON

把這個變量設置爲'true'能夠允許你在你的C和C++源碼中使用ARM Advanced SIMD(a.k.a. NEON)GCC,也能在彙編文件中使用NEON指令。

你僅僅應該在想要對應ARMv7指令序列的'armeabi-v7a' ABI時定義它。注意,不是所有基於ARMv7的CPU都支持NEON指令序列擴展,你應該開啓運行時檢查來確保你能安全地使用這些代碼在運行期間。更多的關於這些的內容,可以閱讀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"安全特性的。默認情況下是啓用的,但是你也可以設置這個變量爲 'true'來啓用它,如果你真的需要這麼做的話。

注意:這個特性不會修改ABI,它僅僅是使內核能夠指向ARMv6+ CPU設備。在這種特性下生成的機器碼將不需要做修改就能運行在更早的CPU架構上。

原文地址:http://blog.csdn.net/ygc87/article/details/6707814

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