標籤:
郭孝星
微博:郭孝星的新浪微博
郵箱:[email protected]
部落格:http://blog.csdn.net/allenwells
Github:https://github.com/AllenWells
一 Android.mk檔案的作用和特點1.1 Android.mk檔案作用
該檔案用來描述編譯系統(build system)的,即一個微型的GNU Makefile片段,會由編譯系統解析一次或多次。
1.2 Android.mk檔案特點
- 該檔案用來將源檔案組織成模組,模組中含有靜態庫或動態庫。只有動態庫會被安裝到應用程式套件中,靜態庫可以用來產生動態庫。
- 一個模組可以定義一個Android.mk檔案,多個模組也可以公用一個Android.mk檔案
- 不需要再Android.mk中列出標頭檔或其他的依賴關係,編譯系統會自動計算處理。二 Android.mk檔案變數2.1 LOCAL變數2.1.1 LOCAL_PATH
LOCAL_PATH:=$(call my-dir)
Android.mk檔案必須以LOCAL_PATH變數開始,它用於在樹中定位檔案。宏功能“my-dir”是由編譯系統提供的,用於返回目前的目錄路徑(包括Android.mk檔案本身)。
2.1.2 LOCAL_MODULE
LOCAL_MODULE :=hello-jni
LOCAL_MODULE變數必須被定義,用來區分Android.mk中的每一個模組。檔案名稱必須是唯一的,不能有空格。
注意:編譯器會自動加上一些首碼和尾碼來保證模組名的唯一性。例如:“hello-jni”會被轉換為“libhellp-jni.so”,Java中載入動態庫時,依然使用“hello-jni”。
2.1.3 LOCAL_MODULE_FILENAME
該變數是可選的,並且允許重新定義組建檔案的名字。預設的,模組將始終產生lib.a或者lib.so檔案,這是標準的UNIX公約。
2.1.4 LOCAL_SRC_FILES
LOCAL_SRC_FILES := hello-jni.c
LOCAL_SRC_FILES變數被需包括一個C和C++源檔案的列表,這些會編譯並彙總到一個模組中。
注意:這裡並不需要列出標頭檔和被包含的檔案,編譯系統會自動計算相關屬性,原始碼中的列表會直接傳遞給編譯器。
2.1.5 LOCAL_C_INCLUDES
需要包含的標頭檔目錄。
2.1.6 LOCAL_LDLIBS
LOCAL_LDLIBS :=-lz
該語句表示載入該動態庫時必須連結/system/lib/libz.so這個動態庫。編譯模組時需要的附加的連結器選項,表明模組在編譯時間依賴的系統庫。
2.1.7 LOCAL_SHARED_LIBRARIES
表明模組運行時依賴的動態庫列表,在連結時是必需的,以便在組建檔案時嵌入相應的資訊。
注意:它不會附加列出的模組到編譯圖,即任然需要在Application.mk中把他們添加到程式要求的模組中。
2.1.8 LOCAL_STATIC_LIBRARIES
表示編譯該模組需要的靜態庫列表。只有當前模組是動態庫時該模組才有意義。
2.1.9 LOCAL_WHOLE_STATIC_LIBRARIES
該變數表示相應的庫被用作整個檔案到連結程式中。
注意:當幾個靜態庫之間有循環相依性關係的時候,通常是很有益的。注意,當用來編譯一個動態庫的時候,這將迫使你將所有的靜態庫中的對象檔案添加到最終的二進位檔案中。但產生可執行程式時,這是不確定的。
2.1.10 LOCAL_JAVA_LIBRARIES
編譯Java應用程式和庫的時候指定包含的Java類庫,目前有core和framework兩種。一般定義成以下形式:
LOCAL_JAVA_LIBRARIES := core framework
2.1.11 LOCAL_CPP_EXTENSION
這是個可選的變數,可以被定義為副檔名為c++的源檔案,預設是”.cpp”,但是你可以改變它,例如
LOCAL_CPP_EXTENSION:=.cxx
2.1.12 LOCAL_CPPFLAGS
編譯C++代碼的時候傳遞給編譯器的選項(編譯C代碼不會用這裡的選項)。最後得到的命令列選項中,這裡指定的選項在 LOCAL_CFLAGS 指定的選項的後面。
2.1.13 LOCAL_CFLAGS
當編譯C/C++源檔案時傳遞一個可選的編譯器標誌。
注意:
- 盡量不要改變Android.mk中的最佳化/調試層級,這個可以通過在Application.mk中設定相應的資訊來自動為你處理,並且會會讓NDK產生在調試過程中使用的有用的資料檔案。2.1.14 LOCAL_EXPORT_CFLAGS
定義這個變數用來記錄C/C++編譯器標誌集合,並且會被添加到其他任何以LOCAL_STATIC_LIBRARIES和LOCAL_SHARED_LIBRARIES的模組的LOCAL_CFLAGS定義中。
舉例
有模組“foo”
include $(CLEAR_VARS)LOCAL_MODULE :=fooLOCAL_SRC_FILES :=foo/foo.cLOCAL_EXPORT_CFLAGS :=-DFOO=1include $(BUILD_STATIC_LIBRARY)
另一個模組“bar”依賴於模組“foo”
include $(CLEAR_VARS)LOCAL_MODULE :=barLOCAL_SRC_FILES :=bar.cLOCAL_CFLAGS:=-DBAR=2LOCAL_STATIC_LIBRARIES:=fooinclude $(BUILD_SHARED_LIBRARY)
當編譯bar.c的時候,標誌“-DFOO=1 -DBAR=2”將被傳遞到編譯器,輸出的標誌被添加到模組的LOCAL_CFLAGS上,所以你可以很容易複寫它們。它們也有傳遞性:如果”zoo”依賴”bar”,“bar”依賴”foo”,那麼”zoo”也將繼承”foo”輸出的所有標誌。當編譯模組輸出標誌的時候,這些標誌並不會被使用。當編譯foo/foo.c時,-DFOO=1將不會被傳遞給編譯器。
2.1.15 LOCAL_EXPORT_CPPFLAGS
類似LOCAL_EXPORT_CFLAGS,但適用於C++標誌。
2.1.16 LOCAL_EXPORT_C_INCLUDES
類似LOCAL_EXPORT_C_CFLAGS,但是只有C能包含路徑,如果”bar.c”想包含一些由”foo”模組提供的標頭檔的時候這會很有用。
2.1.17 LOCAL_EXPORT_LDLIBS
類似於LOCAL_EXPORT_CFLAGS,但是只用於連結標誌。注意,引入的連結標誌將會被追加到模組的LOCAL_LDLIBS,這是因為UNIX連接器的工作方式。當模組foo是一個靜態庫的時候並且代碼依賴於系統庫時會很有用的。LOCAL_EXPORT_LDLIBS可以用於輸出依賴,
舉例
include $(CLEAR_VARS)LOCAL_MODULE := fooLOCAL_SRC_FILES := foo/foo.cLOCAL_EXPORT_LDLIBS := -lloginclude $(BUILD_STATIC_LIBRARY)include $(CLEAR_VARS)LOCAL_MODULE := barLOCAL_SRC_FILES := bar.cLOCAL_STATIC_LIBRARIES := fooinclude $(BUILD_SHARED_LIBRARY)
這裡,在連接器命令最後,libbar.so將以-llog參數進行編譯來表明它依賴於系統日誌庫,因為它依賴於foo。
2.1.18 LOCAL_PRELINK_MODULE
是否需要做prelink處理。預設需要,用來做動態庫最佳化。
2.1.19 LOCAL_PREBUILT_EXECUTABLES
先行編譯including (BUILDPREBUILT)或者(BUILD_HOST_PREBUILT)時所用,指定需要複製的可執行檔。
2.1.20 LOCAL_REQUIRED_MODULES
指定模組運行所依賴的模組(模組安裝時將會同步安裝它所依賴的模組)。
2.1.21 LOCAL_ALLOW_UNDEFINED_SYMBOLS
預設情況下,當試圖編譯一個共用庫的時候遇到任何未定義的引用都可能導致”未定義符號”(undefined symbol)的錯誤。這在你的原始碼中捕獲bug會很有用。如果想禁用此項檢查,可將值設定為true。
2.1.22 LOCAL_ARM_MODE
···
LOCAL_ARM_MODE := arm
···
預設情況下,在”thumb”模式下會產生ARM目標二進位,其中每個指令都是16位寬。你可以定義這個變數為”arm”,如果你想在”arm”模式下(32位指令)強迫模組對象檔案的產生。
2.1.23 LOCAL_ARM_NEON
該變數為”true”會允許在你的C或C++源檔案的GCC的內建函式中使用ARM進階SIMD(又名NEON),以及在彙總檔案中的NEON指令。
注意:當針對”armeabi-v7a”ABI對應的ARMv7指令集時你應該定義它。並不是所有的ARMv7都是基於NEON指令集擴充的CPU,你應該執行運行時來檢測在運行時中這段代碼的安全。另外,你也可以指定特定的源檔案,比如用支援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”尾碼之後。
2.1.24 LOCAL_DISABLE_NO_EXECUTE
Android NDK r4開始添加了支援”NX位”安全功能特性。它是預設啟用的,如果你需要的話,可以通過設定變數為“true”來禁用它。
注意:此功能不修改ABI,並且只在ARMv6及以上的CPU裝置的核心上被啟用。
2.1.25 LOCAL_SHORT_COMMANDS
LOCAL_SHORT_COMMANDS := true /flase
當模組中有很多的源檔案,或者依賴很多的靜態或動態庫。這會強制編譯系統使用一個中間的列表檔案,並通過@$(listfile) 文法和library archiver 或者 static linker一起使用。
注意:
- 這種寫法在Windows上特別有用,因為它的命令列最大隻接收8191個字元,這對於比較複雜的工程顯然太小了。
- 當該值被設定為true時就開啟了這項功能,其他的值都會恢複預設行為。
- 預設不推薦這項功能,因為它會使編譯速度變慢。2.1.26 LOCAL_FORCE_STATIC_EXECUTABLE
如果編譯的可執行程式要進行靜態連結(執行時不依賴於任何動態庫),則設定該值為true。
2.1.27 LOCAL_FILTER_ASM
這個變數指定一個shell命令,用於過濾LOCAL_SRC_FILES 中列出的彙編檔案或者LOCAL_SRC_FILES列出的檔案所編譯出的彙編檔案。定義該變數後,將導致以下行為:
- 所有的C/C++源碼首先翻譯為臨時彙編檔案(如果不定義LOCAL_FILTER_ASM,則C/C++源碼直接編譯為 obj 檔案)
- 這些彙編檔案被傳給 LOCAL_FILTER_ASM 所指定的shell命令處理,得到一批新的彙編檔案。
- (這些新的彙編檔案再被編譯成obj檔案。
換句話說,如果你定義:
LOCAL_SRC_FILES := foo.c bar.S LOCAL_FILTER_ASM := myasmfilter
則foo.c首先傳給編譯器(gcc),得到 foo.S.orignal,然後這個 foo.S.original 被傳給你指定的過濾器(LOCAL_ASM_FILTER),得到 foo.S,然後再傳給彙編器(例如as),得到 foo.o。 bar.S 直接傳給過濾器得到 bar.S.new,然後再傳給彙編器,得到 bar.o。即在從.S到.o的編譯流程中增加了一個過濾的環節。過濾器必須是獨立的shell命令,輸入檔案作為它的第一個命令列參數,輸出檔案作為第二個命令列參數,
例如:
myasmfilter $OBJS_DIR/foo.S.original $OBJS_DIR/foo.S myasmfilter bar.S $OBJS_DIR/bar.S
2.2 CLEAR變數2.2.1 CLEAR_VARS
CLEAR_VARS變數是由編譯系統提供的,並且指明了一個GNU Makefile檔案,其在/build/core/config.mk 檔案定義為:
CLEAR_VARS:=$(BUILD_SYSTEM)/clear_vars.mk)
這個功能會清理掉所有以LOCAL_開頭的內容。
2.3 BUILD變數2.3.1 BUILD_SHARED_LIBRARY
include $(BUILD_SHARED_LIBRARY)
BUILD_SHARED_LIBRARY這個變數是由系統提供的,並且指定給GNU Makefile的指令碼,它收集所有定義的”include $(CLEAR_VARS)”中以LOCAL_開頭的變數,並且決定哪些要被編譯,哪些應該做的更加準確。編譯產生的是以”lib.so”的檔案,該檔案便是產生的動態庫。
2.3.2 BUILD_STATIC_LIBRARY
include $(BUILD_ STATIC _LIBRARY)
BUILD_SHARED_LIBRARY這個變數是由系統提供的,並且指定給GNU Makefile的指令碼,它收集所有定義的”include $(CLEAR_VARS)”中以LOCAL_開頭的變數,並且決定哪些要被編譯,哪些應該做的更加準確。編譯產生的是以”lib.a”的檔案,該檔案便是產生的靜態庫。
2.3.3 BUILD_EXECUTABLE
include $( BUILD_EXECUTABLE)
編譯成Native C可執行程式。
2.3.4 BUILD_JAVA_LIBRARY.2.3.5 BUILD_STATIC_JAVA_LIBRARY
編譯靜態JAVA庫。
2.3.6 BUILD_HOST_JAVA_LIBRARY
編譯本機用的JAVA庫。
2.3.7 BUILD_PACKAGE
include $( BUILD_PACKAGE)
如果是Java檔案,用BUILD_PACKAGE來指明,會用到系統的編譯指令碼host_java_library.mk。
2.4 TARGET變數2.4.1 TARGET_ROOT_OUT
LOCAL_MODULE_PATH :=$(TARGET_ROOT_OUT)
根檔案系統。
2.4.2 TARGET_OUT
system檔案系統。
2.4.3 TARGET_OUT_DATA
data檔案系統
2.4.4 TARGET_ARCH
目標CPU架構名,如果為“arm”則聲稱ARM相容指令,與CPU架構版本無關。
2.4.5 TARGET_ABI
目標平台和ABI的連結,這裡要定義
(TARGETPLATFORM)? (TARGET_ARCH_ABI)
它們都非常有用,特別是當你想測試一下具體的系統鏡像在一個真實裝置環境的時候。預設地,這個是“android-3-armeabi”。
2.4.6 TARGET_PLATFORM
目標平台的名字。
2.4.7 TARGET_ARCH_ABI
CPU和ABI的名字。
三 Android.mk檔案宏3.1 my-dir
include $(call my-dir)
返回最後包含的makefile的路徑,這通常是當前Android.mk所在目錄的路徑,在Android.mk開始之前定義。
3.2 all-subdir-makefiles
include $(call all-subdir-makefiles)
返回一個Android.mk檔案所在位置的列表,以及當前的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包含進來。此功能可以用於提供深層嵌套的原始碼目錄build system的階層。請注意,預設情況下,NDK只會尋找sources/*Android.mk。
3.3 this-makefile
返回當前makefile的路徑。
3.4 parent-makefile
返回makefile的包含樹,也就是包含Makefile當前的檔案。
3.5 grand-parent-makefile
返回調用樹中父Makefile的父Makefile的路徑。
3.6 import-module
$(call import-module,)
允許你通過名字找到並包含另一個模組的的Android.mk。
這將會找到通過NDK_MODULE_PATH環境變數引用的模組的目錄列表,並且將其自動包含到Android.mk中。
著作權聲明:本文為博主原創文章,未經博主允許不得轉載。
【Android本地開發技術:編譯指令碼】Android.mk