標籤:
1 前言
本文檔描述了c和c++編寫的程式用Android NDK編譯時間,編譯檔案Android.mk的文法結構。為了便於理解下面的內容,假設你已經閱讀了前面OVERVIEW部分,瞭解了它們的作用和用法。
2 概要
Android.mk是用來描述源檔案是如何進行編譯的。更具體的:-Android.mk實際上是一個輕量級的Makefile,它會被編譯系統解析一次或多次。因此,你應該儘可能少的聲明變數,同時不要假定在解析過程中沒有定義任何東西。-Android.mk是用來允許你將源檔案組織在一個‘modeles’中。一個modele是以下兩種形式之一:
- a static library 靜態庫
- a shared library 動態庫
只有動態庫才會安裝或者拷貝到你的應用程式套件組合中,但是靜態庫可以用來產生動態庫。 你可以在每個Android.mk中定義一個或多個modeles,你也可以在多個modeles中使用相同的源檔案。
-編譯系統為你處理了很多細節。例如,你不需要在Android.mk中列出標頭檔,也不需要顯示的列出檔案之間的依賴關係。NDK編譯系統將會自動為你計算這些東西。這同樣意味著,當你升級到新的NDK版本時,你可以得到新的交叉工具和平台的支援,而不需要修改你的Android.mk檔案。
簡單例子:
在介紹文法細節之前,讓我們看一下“hello JNI”這個簡單的例子,檔案如下:
apps/hello-jni/project
這裡我們可以看到:
-‘src’目錄包含了Android工程的所有java源檔案。
-‘jni’目錄包含了本地源檔案。例如,‘jni/hello-jni.c’。這個源檔案實現了一個簡單的動態庫,而這個動態庫實現了一個native方法,這個方法返回一個string給VM應用。
-‘jni/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 := $(callmy-dir)
Android.mk檔案必須先定義LOCAL_PATH變數,它用來定位開發樹中的源檔案。在本例中,編譯系統提供的宏‘my-dir’,用來返回目前的目錄(即這個目錄包含了Android.mk檔案自身)。
include$(CLEAR_VARS)
CLEAR_VARS變數由編譯系統提供,它指向一個特殊的GNU Makefile,這個Makefile會為你清除很多LOCAL_XXX這樣的變數(如LOCAL_MODULE,LOCAL_SRC_FIELS, LOCAL_STATIC_LIBARIES, 等等),當然LOCAL_PATH除外。這樣做是必須的,因為所有的編譯控制檔案都是在單一的GNU Make可執行內容環境中解析的,而在這個上下文環境中所有的變數都是全域的。
LOCAL_MODULE := hello-jni
LOCAL_MODULE變數用來唯一標示Android.mk檔案中的每個module。這個名字必須是唯一的,並且不能包含任何空白字元。編譯系統會根據產生的檔案自動添加首碼和尾碼。換句話說,一個叫‘foo’的動態庫module,會產生‘libfoo.so’。
重要提示:
如果你的module命名為‘libfoo’,編譯系統將不會另外添加‘lib’首碼,同樣會產生libfoo.so。(註:為了養成統一習慣,個人建議不要自行加lib首碼了)
LOCAL_SRC_FILES := hello-jni.c
LOCAL_SRC_FILES變數必須包含c和c++源檔案清單,這些源檔案會被編譯和組裝到一個module中。注意這裡你不必列出標頭檔和包含檔案,因為編譯系統會自動為你計算出它們之間的依賴關係;你只需要列出源檔案,這些源檔案將直接傳遞給編譯器。
注意,預設的c++源檔案的副檔名是‘.cpp’,當然你可以通過定義變數LOCAL_CPP_EXTENSION指定不同的副檔名,但是要記住不能忘記前面的那個點(即‘.cxx’可以工作,但是‘cxx’不行的)。
include $(BUILD_SHARED_LIBRARY)
BUILD_SHARED_LIBRARY是編譯系統提供的一個變數,它指向一個GNU Makefile指令碼,這個指令碼負責收集從最近的‘include $(CLEAR_VARS)’,在LOCAL_XXX變數中定義的所有資訊,同時決定編譯什麼,以及怎麼編譯。顯然,BUILD_STATIC_LIBRARY是用來產生靜態庫的。
在samples目錄中,還有很多複雜的例子,在Android.mk檔案中都有注釋,可以自行查看。
參考:
------------
在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-descrption”section下面列出的所有LOCAL_XXX變數。在你開始聲明一個新的module之前,你必須包含這個指令碼,如:
include $(CLEAR_VARS)
BUILD_SHARED_LIBRARY
指向一個編譯指令碼,這個指令碼會搜集你在module中提供的LOCAL_XXX變數的所有資訊,以及決定如何從你列出的源檔案中編譯目標動態庫。注意在包含這個檔案之前,你必須至少先定義LOCAL_MODULE和LOCAL_SRC_FILES。如:
include$(BUILD_SHARED_LIBRARY)
記住,這會產生一個lib$(LOCAL_MODULE).so檔案
BUILD_STATIC_LIBRARY
BUILD_STATIC_LIBRARY用來編譯目標靜態庫。靜態庫不會拷貝到你的工程或者應用程式套件中,但是它可以用來編譯動態庫(參考下面的LOCAL_STATIC_LIBRARIES 和LOCAL_WHOLE_STATIC_LIBRARIES)。
使用樣本:
include $(BUILD_STATIC_LIBRARY)
注意,這會產生一個lib$(LOCAL_MODULE).a檔案。
PREBUILT_SHARED_LIBRARY
指向一個編譯指令碼,這個指令碼用來指定一個先行編譯動態庫。不像BUILD_SHARED_LIBRARY和BUILD_STATIC_LIBRARY,LOCAL_SRC_FILES的值必須是一個編譯好的動態庫的路徑(如foo/libfoo.so),而不是源檔案。
你可以使用LOCAL_PREBUILTS變數引用另外一個module中編譯好的庫(請查看PREBUILTS中的相關內容)。
PREBUILT_STATIC_LIBRARY
這個和PREBUILT_SHARED_LIBRARY相同,只是表示一個靜態庫而已。同樣請查看PREBUILTS中的相關內容。
TARGET_ARCH
它是由整個Android開源編譯指定的目標CPU架構的名稱。這個值為為‘arm’,表示相容任何ARM的編譯,並獨立於CPU架構的修訂。
TARGET_PLATFORM
當Android.mk檔案解析的時候,Android目標平台的名稱。如,‘android-3’對應Android1.5 系統鏡像。如果想要瞭解平台名稱和對應Android系統鏡像的完整資訊,請查看STABLE-APIS相關內容。
TARGET_ARCH_ABI
當Android.mk檔案解析的時候,目標CPU+ABI的名稱。目前支援兩個值:
armabi
For ARMv5TE
Armabi-v7a
注意:升級到Android NDK1.6_r1,這個變數僅僅用‘arm’來定義。但是,現在這個值已經被重新定義,以便更好的匹配Android的內部使用。
想要瞭解更多關於ABI架構和相關的相容性問題,請閱讀CPU-ARCH-ABIS相關部分。
在未來的NDK發布版本中,其他目標的ABIs可能會被引入,並且可能會有不同的名字。注意所有基於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的‘function’宏,通過‘$(call <function>)‘來調用。它們返迴文本資訊:
my-dir
返回最近一次包含Makefile檔案的路徑,通常是當前Android.mk所在目錄。在Android.mk開頭用來定義LOCAL_PATH是非常有用的:
LOCAL_PATH := $(call my-dir)
重要提示:由於GNU Make的工作方式,在解析編譯指令碼過程中,它實際上返回的是最近一次包含Makefile檔案的路徑。不要在包含另一個檔案後調用my-dir。
例如,考慮下面的例子:
LOCAL_PATH := $(call my-dir)
… 聲明一個module
include$(LOCAL_PATH)/foo/Android.mk
LOCAL_PATH := $(callmy-dir)
… 聲明另一個module
在第二次調用my-dir的時候,由於在它前麵包含了$(LOCAL_PATH)/foo/Android.mk,因此LOCAL_PATH被定義為$PATH/foo,而不是$PATH。
因為這樣,比較好的做法是,在Android.mk的最後再包含其他檔案,例如:
LOCAL_PATH := $(call my-dir)
... declare one module
LOCAL_PATH := $(call my-dir)
... declare another module
# extra includes at the end of the Android.mk
include $(LOCAL_PATH)/foo/Android.mk
如果這樣不方便的話,把第一次調用my-dir的值儲存到一個變數中。如:
MY_LOCAL_PATH := $(call my-dir)
LOCAL_PATH := $(MY_LOCAL_PATH)
... declare one module
include $(LOCAL_PATH)/foo/Android.mk
LOCAL_PATH := $(MY_LOCAL_PATH)
... declare another module
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-makefiles
返回當前Makefile所在路徑(即函數被調用的位置)。
parent-makefile
返回分類樹結構中parentMakefile的路徑。即被當前Makefile包含的那個Makefile檔案的路徑。
grand-parent-makefile
你猜。。。(汗。。。)
import-module
允許你通過名字來尋找和包含另一個module中的Android.mk檔案。一個典型的例子是:
$(call import-module, <name>)
它會在NDK_MODULE_PATH環境變數引用的目錄列表中,尋找所有標記為<name>的mudule,並自動為你包含它的Android.mk檔案。
請閱讀IMPORT-MODULE相關內容,瞭解更多細節。
Module-description變數:
----------------------------------
下面的這些變數,用來描述編譯系統中的module。你必須在‘include $(CLEAR_VARS)‘ 和 ‘include $(BUILD_XXXXX)‘之間來定義一些變數。根據前面的描述,$(CLEAR_VARS)會清除所有這些變數的定義,除非在它們的描述中顯示的指出來。
LOCAL_PATH
這個變數表示當前檔案的路徑。你必須在Android.mk的開始的時候定義:
LOCAL_PATH := $(call my-dir)
這個變數不會被$(CLEAR_VARS)清除,因此每一個Android.mk只需要定義一次(即使一個檔案裡面定義了很多個modules)。
LOCAL_MODULE
這個是module的名稱。在所有modules中,它必須是唯一的,不能包含空白字元。你必須在包含$(BUILD_XXXX)指令碼之前定義它。
預設情況下,module name決定了組建檔案的名稱,如module的名稱是<foo>,那麼共用庫的名字是lib<foo>.so。但是,在NDK編譯指令碼中(Android.mk或者Application.mk),你要引用其他module,只需要通過普通的名稱(如<foo>)引用即可。
你可以通過LOCAL_MODULE_FILENAME覆蓋這個預設值(see below)。
LOCAL_MODULE_FILENAME
這個變數是可選的,允許你重新定義組建檔案的名稱。預設,module <foo>總是產生lib<foo>.a的靜態庫或者lib<foo>.so的動態庫,這些都是Unix的約定。
你可以用LOCAL_MODULE_FILENAME覆蓋掉這個預設值,例如:
LOCAL_MODULE := foo-version-1
LOCAL_MODULE_FILENAME := libfoo
注意:在你的LOCAL_MODULE_FILENAME不需要添加路徑或者檔案尾碼,這些編譯系統會自動幫你處理好。
LOCAL_SRC_FILES
這個是編譯module的源檔案清單。只有在這些列表中的源檔案才能傳遞給編譯器,編譯系統會自動為你計算依賴關係。
注意這些源檔案都是相對於LOCAL_PATH,你可以使用path components,如:
LOCAL_SRC_FILES := foo.c \
toto/bar.c
注意:在編譯檔案中,總是要用Unix風格的正斜杠(/),而不要使用windows風格的反斜線。
LOCAL_CPP_EXTCEPTION
這是一個可選的變數,用來定義C++源檔案的尾碼。必須要以一個點開頭,預設的是‘.cpp’,但是你可以修改它。如:
LOCAL_CPP_EXTCEPTION := .cxx
從NDK r7開始,你可以在這個變數中定義一序列的尾碼,如:
LOCAL_CPP_EXTCEPTION := .cxx .cpp .cc
LOCAL_CPP_FEATURES
這是一個可選的變數,可以讓你的代碼使用一些c++的特性。為了讓你的代碼使用RTTI(RunTime Type Information),可以使用:
LOCAL_CPP_FEATURES := rtti
為了讓你的代碼支援c++異常,可以使用:
LOCAL_CPP_FEATURES := exceptions
你可以同時使用它們(順序不重要)
LOCAL_CPP_FEATURES := rtti features
這個變數的作用是,當從原始碼編譯module的時候,可以啟用正確的compiler/linker標誌。對於先行編譯二進位檔案,這同樣有助於聲明二進位檔案所依賴的特性,從而確保最終的連結器能正確工作。
建議你使用這個變數,代替在LOCAL_CPPFLAGS中直接定義-frtti、-fexceptions這種用法。
LOCAL_C_INCLUDES
相對於NDK根目錄的一個可選路徑列表,當編譯所有原始碼時(c,c++或者兩者的組合),將會添加到包含搜尋路徑中。如:
LOCAL_C_INCLUDES := sources/foo
或者甚至:
LOCAL_C_INCLUDES := $(LOCAL_PATH)/../foo
這些要放在LOCAL_CFLAGS / LOCAL_CPPFLAGS中對應包含的flag的前面。
當用ndk-gdb啟動本地調試的時候,LOCAL_C_INCLUDES 同樣會自動使用。
LOCAL_CFLAGS
當編譯c和c++原始碼的時候,傳遞給編譯器的可選的標誌集合。
對於指定附加宏的定義或者編譯選項,是非常有協助的。
重要:在Android.mk中不要試圖改變optimization/debugging的層級,通過在Application.mk中指定合適的資訊,系統會幫你自動處理,而且在debug過程中,NDK會產生有用的資料檔案。
注意:在android-ndk-1.5_r1中,相應的標誌只能應用在c檔案上,不能用在c++上。這個問題已經被修正,從而匹配整個Android編譯系統的行為。(你可以使用LOCAL_CPPFLAGS為c++源檔案指定標誌)
你可以通過LOCAL_CFLAGS += -I<path>來指定額外的包含路徑,但是,對於這個使用LOCAL_C_INCLUDES會更好,因為這些路徑可能在用ndk-gdb本地調試的時候會被用到。
LOCAL_CXXFLAGS
LOCAL_CPPFLAGS的別名。注意在後面的版本中,這個標誌可能會被移除掉。
LOCAL_CPPFLAGS
當編譯c++源檔案的時候(只編譯c++),傳遞給編譯器的可選的標誌集合。它們出現在LOCAL_CFLAGS之後的編譯器的命令列上。
注意:在android-ndk-1.5_r1中,相應的flag同時運用於c和c++原始碼。這些已經得到修正,以匹配整個Android編譯系統。(現在你可以使用LOCAL_CFLAGS來指定c和c++原始碼的標誌)。
LOCAL_STATIC_LIBRARIES
應該連結到這個module的靜態庫modules(用BUILD_STATIC_LIBRARY編譯)列表。這在共用庫模組才有意義。
LOCAL_SHARED_LIBRARIES
運行時這個module依賴的動態共用程式庫‘modules’列表。這個在連結的時候是有必要的,同時會在產生的檔案中嵌入相應的資訊。
LOCAL_WHOLE_STATIC_LIBRARIES
它是LOCAL_STATIC_LIBRARIES(用來表達相應library module)的一個變體,對於連結器它應該使用‘whole archives’。可以查看GNU 連結器的文檔來瞭解–whole-archive這個標誌。
當很多靜態庫之間中有環形依賴的時候,這個通常是非常有用的。注意當用它來編譯動態庫的時候,會強制將你的整個靜態庫中的所有對象檔案添加到最終的二進位檔案中。雖然在產生可執行檔的時候是不正確的。
LOCAL_LDLIBS
當編譯module時,被使用的附加的連結器標誌列表。使用“-l”首碼來傳遞指定系統庫的名稱是非常有用的。例如,下面這些將告訴連結器產生一個module,在載入的時候連結到/system/lib/libz.so。
LOCAL_LDLIBS := -lz
查看STABLE-APIS相關內容,瞭解這個NDK版本能夠連結的系統庫列表。
LOCAL_ALLOW_UNDEFINED_SYMBOLS
預設情況下,當試圖編譯動態庫時,如果沒有定義任何引用,將會導致“undefined symbol”的錯誤。這對在代碼中捕捉bug是非常有協助的。
然而由於某些原因你需要禁用這個檢查,設定這個值為‘true’。注意對應的動態庫可能在運行時會載入失敗。
LOCAL_ARM_MODE
預設情況下,ARM目標二進位檔案將產生在‘thumb’模式,其中每個指令是16位寬。如果你想強制產生‘arm’(32位指令)模式下module的對象檔案,你可以定義這個變數為‘arm’。例如:
LOCAL_ARM_MODE := arm
注意你也可以在源檔案加上尾碼‘.arm’來告訴編譯系統,你只想對某個源檔案使用arm指令。例如:
LOCAL_SRC_FILES :=foo.c bar.c.arm
告訴編譯系統總是用ARM模式編譯‘bar.c’,根據LOCAL_ARM_MODE的值編譯foo.c。
注意:在Application.mk設定APP_OPTM為‘debug’,同樣會強制產生ARM二進位檔案。這是因為工具鏈調試器存在的一個bug,並沒有很好的處理thumb代碼。
LOCAL_ARM_NEON
定義這個變數為‘true’,允許在c和c++代碼中使用ARM Advanced SIMD (又名 NEON)GCC指令,在組織檔案中使用NEON指令。
只有目標為‘armeabi-v7a’ABI(對應於ARMv7指令集),才應該定義它。注意並不是所有基於ARMv7的CPUs都支援NEON指令集擴充,比較安全的做法是在運行時檢測是否能夠使用這個代碼。如果要瞭解更多細節,請閱讀CPU-ARM-NEON和CPU-FEATURES相關內容。
你也可以使用‘.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’的後面,如果你同時使用的話。(如foo.c.arm.neon可以工作,但是foo.c.neon.arm不行!)
LOCAL_DISABLE_NO_EXECUTE
Android NDK r4為“NX bit”的安全功能提供支援。預設這個是啟用的,如果你確實需要禁用,可以設定這個變數為‘true’。
注意:這個功能不會修改ABI,只是在核心目標ARMv6+CPU的裝置上啟用。
想要瞭解更多資訊,請看:
http://en.wikipedia.org/wiki/NX_bit
http://www.gentoo.org/proj/en/hardened/gnu-stack.xml
LOCAL_DISABLE_RELRO
預設情況下,NDK編譯後的代碼是唯讀進行移動位置並得到GOT保護。這個會指示運行時連結器標記特定的記憶體區是唯讀,在移動位置之後。這樣會使得某些安全性漏洞(如GOT覆蓋)更難執行。
預設它是啟用的,但是如果你確實需要,你可以禁用它通過設定變數為‘true’。
注意:這些保護只對新的Android裝置有效("JellyBean" 和更高的版本)。代碼依然能夠運行在舊版本上(儘管沒有記憶體保護)。
想要瞭解更多資訊,請看:
http://isisblogs.poly.edu/2011/06/01/relro-relocation-read-only/ http://www.akkadia.org/drepper/nonselsec.pdf (section 6)
LOCAL_EXPORT_CFLAGS
定義這個變數是為了記錄c/c++編譯器flags的集合,這些flags會被添加到任何其他module定義的LOCAL_CFLAGS中,而這個module通過LOCAL_STATIC_LIBRARIES 或者LOCAL_SHARED_LIBRARIES使用它。
例如,考慮module‘foo’下面的定義:
include $(CLEAR_VARS)
LOCAL_MODULE := foo
LOCAL_SRC_FILES := foo/foo.c
LOCAL_EXPORT_CFLAGS := -DFOO=1
include $(BUILD_STATIC_LIBRARY)
另一個module‘bar’,依賴於它:
include $(CLEAR_VARS)
LOCAL_MODULE := bar
LOCAL_SRC_FILES := bar.c
LOCAL_CFLAGS := -DBAR=2
LOCAL_STATIC_LIBRARIES := foo
include $(BUILD_SHARED_LIBRARY)
當編譯bar.c的時候,標誌‘-DFOO=1 -DBAR=2‘將會傳遞給編譯器。
Exported flags被加在你module的LOCAL_CFLAGS中,所以你可以簡單的覆蓋它們。它們也可以傳遞:如果‘zoo’依賴‘bar’,‘bar’依賴‘foo’,那麼‘zoo’將繼承‘foo’匯出的所有flags。
最後,當編譯的module匯出它們時,exported flags不會被使用。在上面的例子中,當編譯foo/foo.c時,-DFOO=1不會傳遞給編譯器。
LOCAL_EXPORT_CPPFLAGS
和LOCAL_EXPORT_CFLAGS相同,但是只針對c++標誌。
LOCAL_EXPORT_C_INCLUDES
和LOCAL_EXPORT_CFLAGS相同,但是它是針對c包含路徑的。這是非常有用的,如果‘bar.c’想要包含module‘foo’提供的標頭檔。
LOCAL_EXPORT_LDLIBS
和LOCAL_EXPORT_CFLAGS相同,但是它是針對連結器標誌的。注意由於Unix連結器的工作方式,被匯入的連結器標誌將append到你module的LOCAL_LDLIBS中。
這是非常有用的,當module‘foo’是一個靜態庫和它有代碼依賴於系統庫的時候。LOCAL_EXPORT_LDLIBS可以用來匯出這個依賴關係。例如:
include $(CLEAR_VARS)
LOCAL_MODULE := foo
LOCAL_SRC_FILES := foo/foo.c
LOCAL_EXPORT_LDLIBS := -llog
include $(BUILD_STATIC_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := bar
LOCAL_SRC_FILES := bar.c
LOCAL_STATIC_LIBRARIES :=foo
這裡,libbar.so在連結器命令的尾部會使用-llog進行編譯,表明它依賴於系統日誌庫,因為它依賴於‘foo’。
LOCAL_SHORT_COMMANDS
設定這個變數為‘true’,當你的module有很多的源檔案,或者依賴很多的靜態或動態庫。這會強制編譯系統使用一個中間的列表檔案,並通過@$(listfile) 文法和library archiver 或者 static linker一起使用。
這在Windows上是非常有用的,因為它的命令列只接收最大8191個字元,這對於複雜的工程來說太小了。
這同樣也會影響單個源檔案的編譯,如果將所有的編譯器選項放在列表檔案裡面。
注意如果設定了‘true’以外的值,都會恢複成預設行為。你也可以在Android.mk檔案中定義APP_SHORT_COMMANDS來強制使你的工程中的所有modules使用這項功能。
注意:預設我們不推薦啟用這個功能,因為它會使得編譯變慢。
LOCAL_FILTER_ASM
為shell命令定義這個變數,將會過濾從你的LOCAL_SRC_FILES彙編或產生的檔案。
當它被定義時,將發生下面的事情:
- 所有的c或者c++會產生到一個臨時彙編檔案(而不是編譯進對象檔案中)。
- 任何臨時的、在LOCAL_SRC_FILES列出的彙編檔案通過LOCAL_FILTER_ASM命令發送來產生另一個臨時的彙編檔案。
- 這些被過濾後的彙編檔案被編譯到對象檔案中。
換句話說,如果你有:
LOCAL_SRC_FILES := foo.c bar.S
LOCAL_FILTER_ASM := myasmfilter
foo.c --1--> $OBJS_DIR/foo.S.original --2--> $OBJS_DIR/foo.S--3-->$OBJS_DIR/foo.o
bar.S --2--> $OBJS_DIR/bar.S --3-->$OBJS_DIR/bar.o
“1”對應編譯器,“2”對應過濾器,“3”對應彙編。過濾器必須是獨立的shell命令,把輸入檔案的名稱作為第一個參數,輸出檔案的名稱作為第二個參數,例如:
myasmfilter$OBJS_DIR/foo.S.original $OBJS_DIR/foo.S
myasmfilter bar.S $OBJS_DIR/bar.S
http://android.mk
Android.mk 檔案文法指南