Android.mk文件語法規範及使用模板

zhuanzi : http://blogold.chinaunix.net/u3/99423/showart_2206760.html

 

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/*/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) 腳本之前定義它 。模塊的名字決定了生成文件的名字,例如,如果一個一個共享庫模塊的名字是 <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)

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