Android-NDK開發之基礎--Android.mk文件語法規範(轉JavaEye)

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'文件。

  重要注意事項

  如果你把庫命名爲‘libfoo’,編譯系統將不會添加任何的lib前綴,也會生成libfoo.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腳本,負責收集自從上次調用'include $(CLEAR_VARS)'以來,定義在LOCAL_XXX變量中的所有信息,並且決定編譯什麼,如何正確地去做。還有 BUILD_STATIC_LIBRARY變量生成靜態庫

  在 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 ------------------

  這樣,我們就達到目的了。

  NDK提供的變量:

  -

  - - - - - - - - - - -

  這些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平臺的名字,現在只支持'android-1.5'。

  TARGET_ARCH_ABI

  CPU+ABI的名字,只支持’arm’,它的含義是:

  ARMv5TE或更高級CPU,並且具有'softfloat'浮點支持。

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

    TARGET_ABI

 

  目標平臺和abi的組合,它事實上被定義成$(TARGET_PLATFORM)-$(TARGET_ARCH_ABI)

  在你想要在真實的設備中針對一個特別的目標系統進行測試時,會有用。

  在默認的情況下,它會是'android-1.5-arm'

  ///////////////////

  NDK-提供的功能宏

  -

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

  下面是GNU Make ‘功能’宏,必須通過使用'$(call )'來求值,他們返回文本化的信息。

  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 and

  sources/foo/lib2/Android.mk

  這項功能用於向編譯系統提供深層次嵌套的代碼目錄層次。注意,在默認情況下,NDK將會只搜索在 sources/*/Android.mk中的文件。

  this-makefile

  返回當前 Makefile的路徑(即這個函數調用的地方)

  parent-makefile

  返回調用樹中父Makefile路徑。即包含當前Makefile的Makefile路徑。

  grand-parent-makefile

  猜猜看...

  模塊描述變量:

  -

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

  下面的變量用於向編譯系統描述你的模塊。你應該定義在 '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)腳本之前定義它。模塊的名字決定了生成文件的名字,例如,如果一個一個共享庫模塊的名字是,那麼生成文件的名字就是lib.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_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’。注意相應的共享庫可能在運行時加載失敗。


發佈了24 篇原創文章 · 獲贊 10 · 訪問量 4萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章