2013年5月17日 星期五

[Android]Android.mk & m mm mmm之章

原廠NDK內附文件翻譯
Android.mk文件語法詳述
介紹: ————
這篇文檔是用來描述你的C或C++源文件中Android.mk編譯文件的語法的,為了理解她們我們需要您先看完 docs/OVERVIEW.html(http://hualang.iteye.com/blog/1135105)文件來了解它的作用
概覽: ———— Android.mk文件是用來描述build system(編譯系統)的,更準確的說:
–該文件是一個微型的GNU Makefile片段,將由build system解析一次或者多次。這樣,您就可以盡量減少您聲明的變數,並且不要以為在解析過程中沒有任何定義。
–這個文件但語法是用來允許你將源文件組織成模塊,這個模塊中含有: -一個靜態庫(.a文件) -一個動態庫(.so文件) 只有動態庫才會被安裝/複製到你的應用程序包,儘管靜態庫可以被用來生成動態庫。你可以在每個模塊中  都定義一個Android.mk文件,你也可以讓多個模塊共用一個Android.mk文件。
–build system可以為你處理許多細節,例如:你不許要在Android.mk文件中列出頭文件或者其他的依賴關係,這些NDK的build system會自動為你計算並處理。
這也意味著,當更新到新版本的NDK的時候,你應該得益於新的toolchain/platform的支持,而無需修改你的Android.mk文件。
注意:這些語法非常接近於分布在完整的開源的Android源代碼中的Android.mk文件,儘管是build system實現的,但是它們的用法是不同的。這樣故意設計的決定是為了讓應用程序開發者重用「外部」庫的源代碼更容易。
簡單實例: ————- 再詳細講解語法之前,讓我們先看看一個簡單的例子”hello JNI”,它在apps/hello-jni/project下
–’src’目錄下用於存放java源文件 –『jni』目錄下用於存放本地源文件,例如”jni/hello-jni.c”
這個源文件實現了一個簡單的共享庫(shared library):實現了一個本地方法,為VM應用程序返回一個字元串。
–『jni/Android.mk』文件描述了如何生成一個共享庫,它的內容是: —————–Android.mk———————— 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’是由build system提供的,用於返回當前目錄路徑(包括Android.mk文件本身)
include $(CLEAR_VARS)
CLEAR_VARS變數是由build system提供的,並且指明了一個GNU makefile文件,這個功能會清理掉所有以LOCAL_開頭的內容(例如LOCAL_MODULE,LOCAL_SRC_FILES,LOCAL_STATIC_LIBRARIES等),除了LOCAL_PATH,這句話是必須的,因為如果所有的變數都是全局變數的話,所有的可控的編譯文件都需要在一個單獨的GNU中被解析並執行
LOCAL_MODULE :=hello-jni
LOCAL_MODULE變數必須被定義,用來區分Android.mk中的每一個模塊。文件名必須是唯一的,不能有空格。注意,這裡編譯器會為你自動加上一些前綴和後綴,來保證文件是一致的,比如:這裡表明一個動態連接庫模塊被命名為”hello-jni”,但是最後會生成為”libhello-jni.so”文件。但是在Java中裝載這個庫的時候還是使用”hello-jni”名稱。當然如果我們使用”IMPORTANT NOTE:”,編譯系統就不會為你加上前綴,但是為了支持Android平台源碼中的Android.mk文件,也同樣會生成libhello-jni.so這樣的文件。
重要提示:如果你將你的模塊命名為’libfoo’,編譯系統將不會將前綴’lib’加上去,並且也會生成libfoo.so文件。
LOCAL_SRC_FILES := hello-jni.c
LOCAL_SRC_FILES變數被需包括一個C和C++源文件的列表,這些會編譯並聚合到一個模塊中。 注意:這裡並不需要你列出頭文件和被包含的文件,因為編譯系統會自動為你計算相關的屬性,源代碼中的列表會直接傳遞給編譯器。
C++默認文件的擴展名是「.cpp」,我們可以通過定義一個LOCAL_DEFAULT_CPP_EXTENSION變數來定義一個不同的C文件。不要忘記在初始化前面的「.」點(也就是說”.cpp”可以正常工作,但是cpp不能正常工作)
include $(BUILD_SHARED_LIBRARY) BUILD_SHARED_LIBRARY這個變數是由系統提供的,並且指定給GNU Makefile的腳本,它可以收集所有你定義的”include $(CLEAR_VARS)”中以LOCAL_開頭的變數,並且決定哪些要被編譯,哪些應該做的更加準確。編譯生成的是以”lib.so”的文件,這個就是共享庫了。我們同樣也可以使用BUILD_STATIC_LIBRARY編譯系統便會生成一個以”lib.a”的文件來供動態庫調用。
在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可能被解析幾次,每次以不同的變數的定義解析的
CLEAR_VARS CLEAR_VARS這個變數由系統提供,功能是清理掉所有以LOCAL_開頭的內容,再開始一個新的模塊之前,你必須包括這段腳本
include ($CLEAR_VARS)
BUILD_SHARED_LIBRARY
在編譯腳本中收集所有以LOCAL_開頭的信息並且決定從列出的源代碼中編譯一個目標共享庫。注意,你必須定義了LOCAL_MODULE和LOCAL_SRC_FILES變數,使用它的時候,可以這樣定義
include $(BUILD_SHARED_LIBRARY)
注意,我們會生成一個以lib.so為名的文件
BUILD_STATIC_LIBRARY
用來構建一個靜態庫,該靜態庫將不會被拷貝到你的project/packages下,但是可以被用於動態庫 (看下面的LOCAL_STATIC_LIBRARY和LOCAL_WHOLE_STATIC_LIBRARY介紹)
例如: include $(BUILD_STATIC_LIBRARY)
注意,這將生成一個lib.a為名字的模塊
PREBUILD_SHARED_LIBRARY 在編譯腳本中用於指定一個預先編譯的動態庫,不像BUILD_SHARED_LIBRARY和BUILD_STATIC_LIBRARY,LOCAL_SRC_FILES的預先共享庫必須是一個單獨的路徑(如:foo/libfoo.so),而不是源文件。
你可以在另一個模塊中引用預編譯的庫(參見docs/pribuilds.html)
PRIBUILD_STATIC_LIBRARY 這個變數類似於PREBUILD_SHARED_LIBRARY,但是是針對靜態庫的,(詳見docs/prebuilds.html)
TARGET_ARCH TARGET_ARCH指框架中CPU的名字已經被Android開源代碼明確指出了,這裡的arm包含了任何ARM-獨立結構的架構,以及每個獨立的CPU版本
TARGET_PLATFORM Android平台的名字在Android.mk中被解析,比如”android-3″對應Android 1.5系統鏡像,對於平台的名稱對應Android系統的列表,請看docs/STABLE-APIS.html
TARGET_ARCH_ABI 在Android.mk中被解析時指CPU+ABI的名字。
目前支持的兩個值 armeabi for ARMv5TE armeabi-v7a
注意,到Android NDK 1.6_r1,這個值被簡化為”arm”。然而,這個值被重定義可以更好的匹配Android平台內部使用的是什麼
更多的信息可以參見docs/CPU-ARCH-ABIS.html
未來的NDK版本中得到支持,它們會有一個不同的名字,注意所有基於ARM的ABI都會有一個”TARGET_ARCH”被定義給arm,但也有可能有不同的”TARGET_ARCH_ABI”
TARGET_ABI
目標平台和ABI的鏈接,這裡要定義$(TARGET_PLATFORM)-$(TARGET_ARCH_ABI)它們都非常有用,特別是當你想測試一下具體的系統鏡像在一個真實設備環境的時候
默認地,這個是”android-3-armeabi”
(到Android NDK 16_R1版本,使用”android-3-arm”作為默認)
NDK提供的宏功能 ——————————– 以下是使用GNU make的宏功能,必須通過使用”$(call )”,返回一個文本信息。
my-dir
返回最後包含的makefile的路徑,這通常是當前Android.mk所在目錄的路徑,在Android.mk開始之前定義 LOCAL——PATH是很有用的。
在Android.mk文件的開始位置定義 LOCAL_PATH :=$(call my-dir)
…聲明一個模塊 include $(LOCAL_PATH)/foo/Android.mk
LOCAL_PATH :=($call my-dir)
…聲明另一個模塊 這裡的問題是第二次調用”my-dir”定義LOCAL_PATH替換$PATH為$PATH/foo,由於在此之前執行過。
對於這個原因,最好是將額外的其他所有東西都在Android.mk中包含進來
LOCAL_PATH :=$(call my-dir)
…聲明一個模塊
LOCAL_PATH :=$(call my-dir) …聲明另一個模塊
#在Android.mk的最後額外包括進來 include $(LOCAL_PATH)/foo/Android.mk
如果這樣不方便的話,保存第一個my-dir調用的值到另一個變數中,例如
MY_LOCAL_PATH :=$(call my-dir) LOCAL_PATH :=$(MY_LOCAL_PATH) …聲明一個模塊
include $(LOCAL_PATH)/foo/Android.mk LOCAL_PATH :=$(MY_LOCAL_PATH) …聲明另一個模塊
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
this-makefile 返回當前makefile的路徑(也就是那個功能被調用了)
parent-makefile 返回makefile的包含樹,也就是包含Makefile當前的文件
grand-parent-makefile 你猜?
import-module 一個允許你通過名字找到並包含另一個模塊的的Android.mk的功能,例如
$(call import-module,)
這將會找到通過NDK_MODULE_PATH環境變數引用的模塊的目錄列表,並且將其自動包含到 Android.mk中
詳細信息請參閱:docs/IMPORT-MODULE.html
模塊變數描述: ———————————- 下面的這些變數是用來描述怎樣用你的模塊來編譯系統的。你可以定義它們中的一些比如 “include $(CLEAR_VARS)”和”include $(BUILD_XXX)”,正如前面所寫的,$(CLEAR_VARS)是一個可以取消定義/清楚所有變數的腳本。
LOCAL_PATH 這個變數是用來給出當前文件的路徑。您比系再您的Android.mk開始位置定義: LOCAL_PATH :=$(call my-dir) 注意,這個變數是不被$(CLEAR_VARS)清除的,其他的都要被清除(我們可以定義幾個模塊到一個文件中)
LOCAL_MODULE 這個是你模塊的名稱,它在你的所有模塊中名稱必須是唯一的,並且不能包含空格。你必須在包含任何 $(BUILD-XXX)腳本之前定義它。
默認情況下,模塊的名稱決定了生成的文件的名稱,例如lib.so,它是foo模塊的名字。
你可以用LOCAL_MODULE_FILENAME覆蓋默認的那一個
LOCAL_MODULE_FILENAME
這個變數是可選的,並且允許你重新定義生成文件的名字。默認的,模塊將始終生成lib.a或者lib.so文件,這是標準的UNIX公約
你可以通過LOCAL_MODULE_FILENAME覆蓋它
LOCAL_MODULE :=foo-version-1 LOCAL_MODULE_FILENAME :=libfoo 注意:你不能將文件路徑或者文件擴展名寫到LOCAL_MODULE_FILENAME里,這些將有build system自動處理。
LOCAL_SRC_FILES 這是你模塊中將要編譯的源文件列表。只列出將被傳遞到編譯器的文件,因為build system自動為您計算了它們的依賴。
注意:源文件的名稱都是相對LOCAL_PATH的,您可以使用路徑組件,例如 LOCAL_SRC_FILES :=foo.c\ toto/bar.c
注意:在build system時請務必使用UNIX風格的斜杠(/),windows風格的斜杠將不會得到處理
LOCAL_CPP_EXTENSION 這是個可選的變數,可以被定義為文件擴展名為c++的源文件,默認是”.cpp”,但是你可以改變它,比如
LOCAL_CPP_EXTENSION:=.cxx
LOCAL_C_INCLUDES
可選的路徑列表,相對於NDK的根目錄,當編譯所有的源文件(C、C++、或者彙編)時將被追加到搜索路徑中 例如: LOCAL_C_INCLUDES:=sources/foo 或者 LOCAL_C_INCLUDES:=$(LOCAL_PATH)/../foo
這些都在任何相應列入標誌之前被放置在 LOCAL_CFLAGS / LOCAL_CPPFLAGS
當用用ndk-gdb啟動本機調試時,LOCAL_C_INCLUDES也會自動被使用到
LOCAL_CFLAGS
當編譯C/C++源文件時傳遞一個可選的編譯器標誌。 這對於指定額外的宏定義或編譯選項很有用
重要提示:盡量不要改變Android.mk中的優化/調試級別,這個可以通過在Application.mk中設置相應的信息來自動為你處理,並且會會讓NDK生成在調試過程中使用的有用的數據文件。
注意:在Android-ndk-1.5_r1中,只使用於C源文件,而不適用於C++源文件。在匹配所有Android build system的行為已經得到了糾正。(現在你可以為C++源文件使用LOCAL_CPPFLAGS來指定標誌)
它可以用LOCAL_CFLAGS += -I來指定額外的包含路徑,然而,如果使用LOCAL_C_INCLUDES會更好,因為用ndk-gdk進行本地調試的時候,那些路徑依然是需要使用的
LOCAL_CXXFLAGS LOCAL_CPPFLAGS的別名。請注意,這個標誌在NDK的未來的版本中將會消失
LOCAL_CPPFLAGS 當只編譯C++源代碼的時候,將傳遞一個可選的編譯器標誌。它們將會出現再LOCAL_CFLAGS之後。
注意:在Android NDK-1.5_r1版本中,相應的標誌可以應用於C或C++源文件上。在配合完整的Android build system的時候,這已經得到了糾正。(你可以使用LOCAL_CFLAGS去指定C或C++源文件)
LOCAL_STATIC_LIBRARIES
靜態庫模塊的列表(通過BUILD_STATIC_LIBRARY創建)應與此模塊鏈接。這僅僅是為了使動態庫敏感。
LOCAL_SHARED_LIBRARY 共享庫的列表「模塊」,這個模塊依賴於運行時.這在鏈接的時候和在生成的文件中嵌入相應的信息是非常必要的
LOCAL_WHOLE_STATIC_LIBRARIES
LOCAL_WHOLE_STATIC_LIBRARIES是一個用於表示相應的庫模塊被用作為「整個檔案」到鏈接程序的變數。
當幾個靜態庫之間有循環依賴關係的時候,通常是很有益的。注意,當用來編譯一個動態庫的時候,這將迫使你將所有的靜態庫中的對象文件添加到最終的二進位文件中。但生成可執行程序時,這是不確定的。
LOCAL_LDLIBS 當額外的鏈接標誌列表被用於在編譯你的模塊時,通過用”-l”前綴的特定系統庫傳遞名字是很有用的。例如,下面的舊愛哪個告訴你生成一個在載入時鏈接到/system/lib/libz.so的模塊。
LOCAL_LDLIBS :=-lz
LOCAL_ALLOW_UNDEFINED_SYMBOLS 默認情況下,當試圖編譯一個共享庫的時候遇到任何未定義的引用都可能導致”未定義符號”(undefined symbol)的錯誤。這在你的源代碼中捕獲bug會很有用。
然而,但是由於某些原因,你需要禁用此檢查的話,設置變數為”true”即可。需要注意的是,相應的共享庫在運行時可能載入失敗。
LOCAL_ARM_MODE 默認情況下,在”thumb”模式下會生成ARM目標二進位,其中每個指令都是16位寬。你可以定義這個變數為”arm”,如果你想在”arm”模式下(32位指令)強迫模塊對象文件的生成。例如:
LOCAL_ARM_MODE := arm
注意,你需要執行編譯系統為在ARM模式下通過文件的名字增加後綴的方式編譯指定的源文件。比如:
LOCAL_SRC_FILES :=foo.c bar.c.arm
這會告訴編譯系統一直以ARM模式編譯”bar.c”,並且通過LOCAL_ARM_MODE的值編譯foo.c。
注意:在Application.mk文件中設置APP_OPTIM為”debug”也會強制ARM二進位文件的生成。這是因為工具鏈調試其中的bug不會處理thumb代碼。
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”後綴之後 (就是foo.c.arm.neon可以工作,但是foo.c.neon.arm不工作)
LOCAL_DISABLE_NO_EXECUTE
Android NDK r4開始添加了支持”NX位”安全功能特性。它是默認啟用的,如果你需要的話,可以通過設置變數為「true」來禁用它。
注意:此功能不修改ABI,並且只在ARMv6及以上的CPU設備的內核上被啟用。
更多信息,可以參見:
http://en.wikipedia.org/wiki/NX_bit
http://www.gentoo.org/proj/en/hardened/gnu-stack.xml
LOCAL_EXPORT_CFLAGS
定義這個變數用來記錄C/C++編譯器標誌集合,並且會被添加到其他任何以LOCAL_STATIC_LIBRARIES和LOCAL_SHARED_LIBRARIES的模塊的LOCAL_CFLAGS定義中。
例如:這樣定義”foo”模塊 include $(CLEAR_VARS) LOCAL_MODULE :=foo LOCAL_SRC_FILES :=foo/foo.c LOCAL_EXPORT_CFLAGS :=-DFOO=1 include $(BUILD_STATIC_LIBRARY)
另一個模塊,叫做”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″將被傳遞到編譯器。
輸出的標誌被添加到模塊的LOCAL_CFLAGS上,所以你可以很容易複寫它們。它們也有傳遞性:如果”zoo”依賴”bar”,「bar」依賴”foo”,那麼”zoo”也將繼承”foo”輸出的所有標誌。
最後,當編譯模塊輸出標誌的時候,這些標誌並不會被使用。在上面的例子中,當編譯foo/foo.c時, -DFOO=1將不會被傳遞給編譯器。
LOCAL_EXPORT_CPPFLAGS
類似LOCAL_EXPORT_CFLAGS,但適用於C++標誌。
LOCAL_EXPORT_C_INCLUDES
類似LOCAL_EXPORT_C_CFLAGS,但是只有C能包含路徑,如果”bar.c”想包含一些由”foo”模塊提供的頭文件的時候這會很有用。
LOCAL_EXPORT_LDLIBS
類似於LOCAL_EXPORT_CFLAGS,但是只用於鏈接標誌。注意,引入的鏈接標誌將會被追加到模塊的LOCAL_LDLIBS,這是因為UNIX連接器的工作方式。
當模塊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 include $(BUILD_SHARED_LIBRARY)
這裡,在連接器命令最後,libbar.so將以-llog參數進行編譯來表明它依賴於系統日誌庫,因為它依賴於foo。
LOCAL_FILTER_ASM
這個變數定義了一個shell命令,將用於過濾,從你的LOCAL_SRC_FILES中產生的或者聚合文件。
當它被定義了,將會出現如下的情況:
–任何C或C++源文件將會生成到一個臨時的聚合的文件中(而不是被編譯成目標文件) –任何臨時聚合文件,任何在LOCAL_SRC_FILES中列出的聚合文件將通過LOCAL_FILER_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
Android.mk檔重要解析

首先,這文件是一個在pdk文件中的抽象資訊。其次,你可能想要看之後的 how to build Android source code 。而現在,我們可以在一開始看到的Android源代碼中看到其中有applications, libraries, components 在framework中Android.mk這份文件存放在特定的目錄。這些Android.mk文件定義了如何build這些source code。
以下將總結Android.mk文件定義的具體規則:
  • Name(名稱): 我們需要定義我們要去build的名稱 (LOCAL_MODULE := )
  • Local Variables(區域變數): 所有 builds也許有一些區域變數,所以在一個新build中最好清除所有的區域變數 (include $(CLEAR_VARS))
  • Files(檔案): 我們需要去寫所有我們想要被build的檔案.(LOCAL_SRC_FILES := main.c)
  • Tags(標籤): 定義要build的標籤. (LOCAL_MODULE_TAGS := eng development)
  • Libraries(庫): 假如build需要被連到其它的庫 , 我們需要去定義它們(LOCAL_SHARED_LIBRARIES := cutils)
  • Template file(樣板文件): 我們可以定義我們的build是否為可執行的,庫或其他檔案.包含樣板文件 (include $(BUILD_EXECUTABLE))
BUILD_EXECUTABLE, CLEAR_VARS, 變數等.樣板文件的絕對位址被定義在 build/core/config.mk中
這裡有個簡單的 Android.mk 文件主要是用來 builds一個Android apk:
編譯Android apk專用的Android.mk
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
# Build all java files in the java subdirectory
LOCAL_SRC_FILES := $(call all-subdir-java-files)
# Name of the APK to build
LOCAL_PACKAGE_NAME := LocalPackage
# Tell it to build an APK
include $(BUILD_PACKAGE)
(1)Android.mk檔首先需要指定LOCAL_PATH變數,用於查找原始檔案。由於一般情況下        Android.mk和需要編譯的原始檔案在同一目錄下,所以定義成如下形式:        LOCAL_PATH:=$(call my-dir)        上面的語句的意思是將LOCAL_PATH變數定義成本檔所在目錄路徑。    (2)Android.mk中可以定義多個編譯模組,每個編譯模組都是以include $(CLEAR_VARS)開始以include $(BUILD_XXX)結束。         include $(CLEAR_VARS)         CLEAR_VARS由編譯系統提供,指定讓GNU MAKEFILE為你清除除LOCAL_PATH以外的所有LOCAL_XXX變數,         LOCAL_MODULELOCAL_SRC_FILESLOCAL_SHARED_LIBRARIESLOCAL_STATIC_LIBRARIES等。         include $(BUILD_STATIC_LIBRARY)表示編譯成靜態庫         include $(BUILD_SHARED_LIBRARY)表示編譯成動態庫。         include $(BUILD_EXECUTABLE)表示編譯成可執行程式
--------------------------------------------------------------------------------------------------------------------------------------------  在Android.mk文件的最後一行是生成APK文件. 不一樣的 source code 類型必須被不一樣地 built. 所以我們也可以根據我們的source code使用 $(BUILD_EXECUTABLE), $(HOST_JAVA_LIBRARY), $(HOST_PREBUILT) 等變數. (Definitions like my-dirall-subdir-java-files are in build/core/definitions.mk)
我們可以增加 LOCAL_MODULE_TAGS 變數到 Android.mk 檔中來決定模組被安裝在source code中 built. 在這邊有一些 tags 的定義及他們的意義:
  • eng
    • 默認變種.
    • 安裝模組標籤( tagged )與: eng, debug, user, 及 / 或 development
    • 安裝沒有定義標籤的非apk模組.
    • 安裝 APKs 根據產品定義該檔案.
    • adb 默認是啟用的.
  • user
    • 最終版本.
    • 安裝的模組會被標籤為user.
    • 安裝沒有標籤定義的非apk模組.
    • 安裝 APKs 根據產品定義該檔案.
    • adb默認是禁用的.
  • userdebug, 跟用戶一樣,除了:
    • 此外 安裝的模組會被標籤為debug.
    • adb 默認是啟用的.
These tags is same as build variants that can be specified in “choosecombo” function. “choosecombo” function is available after “source build/envsetup.sh” command.  We can specify build variant in building source code like below
make -j4 PRODUCT-generic-eng
eng” is the build variant “generic” is the product. The command above will build and install modules according to attributes of “eng” tag mentioned above.
編譯C code專用的Android.mk
=================================
[Android]Android Makefile(android.mk) 產生(非遞迴)
項目中需要將linux下的應用程序放在android的下面編譯。
以前的編譯用的makefile,而android用android.mk
需要linux的makefile文件轉換為android.mk
將生成可執行文件,靜態庫,動態庫的規則對應到Android.mk中
還有對應的makefile引入的文件順序。
大家認為對嗎?有補充嘛?
想確定難點在哪個位置
==================
寫法:
(1)Android .mk文件首先需要指定LOCAL_PATH變量,用於查找來源文件由於一般情況下       Android.mk和需要編譯的源文件在同一目錄下,所以定義成如下形式:
       LOCAL_PATH:=$(call my-dir)
       上面的語句的意思是將LOCAL_PATH變量定義成本文件所在目錄路徑
(2)Android.mk中可以定義多個編譯模塊,每個編譯模塊都是以include $(CLEAR_VARS)開始以include $(BUILD_XXX)結束
        include $(CLEAR_VARS)
        CLEAR_VARS由編譯系統提供,指定讓GNU MAKEFILE為你清除除LOCAL_PATH以外的所有LOCAL_XXX變量,
        如LOCAL_MODULE,LOCAL_SRC_FILES,LOCAL_SHARED_LIBRARIES,LOCAL_STATIC_LIBRARIES等
include $(BUILD_STATIC_LIBRARY)表示編譯成靜態庫
        include $(BUILD_SHARED_LIBRARY)表示編譯成動態庫
        include $(BUILD_EXECUTABLE)表示編譯成可執行程式
(3)舉例如下(frameworks/base/libs/audioflinger/Android.mk):
java代碼:   (4)編譯一個應用程式(APK)
java代碼:
  1. LOCAL_PATH:= $(call my-dir)
  2. include $(CLEAR_VARS) 模塊一
  3. ifeq ($(AUDIO_POLICY_TEST),true)
  4. ENABLE_AUDIO_DUMP := true
  5. endif
  6. LOCAL_SRC_FILES:= \
  7. AudioHardwareGeneric.cpp \
  8. AudioHardwareStub.cpp \
  9. AudioHardwareInterface.cpp
  10. ifeq ($(ENABLE_AUDIO_DUMP),true)
  11. LOCAL_SRC_FILES += AudioDumpInterface.cpp
  12. LOCAL_CFLAGS += -DENABLE_AUDIO_DUMP
  13. endif
  14. LOCAL_SHARED_LIBRARIES := \
  15. libcutils \
  16. libutils \
  17. libbinder \
  18. libmedia \
  19. libhardware_legacy
  20. ifeq ($(strip $(BOARD_USES_GENERIC_AUDIO)),true)
  21. LOCAL_CFLAGS += -DGENERIC_AUDIO
  22. endif
  23. LOCAL_MODULE:= libaudiointerface
  24. ifeq ($(BOARD_HAVE_BLUETOOTH),true)
  25. LOCAL_SRC_FILES += A2dpAudioInterface.cpp
  26. LOCAL_SHARED_LIBRARIES += liba2dp
  27. LOCAL_CFLAGS += -DWITH_BLUETOOTH -DWITH_A2DP
  28. LOCAL_C_INCLUDES += $(call include-path-for, bluez)
  29. endif
  30. include $(BUILD_STATIC_LIBRARY) 模塊一編譯成靜態庫
  31. include $(CLEAR_VARS) 模塊二
  32. LOCAL_SRC_FILES:= \
  33. AudioPolicyManagerBase.cpp
  34. LOCAL_SHARED_LIBRARIES := \
  35. libcutils \
  36. libutils \
  37. libmedia
  38. ifeq ($(TARGET_SIMULATOR),true)
  39. LOCAL_LDLIBS += -ldl
  40. LOCAL_SHARED_LIBRARIES += libdl
  41. endif
  42. LOCAL_MODULE:= libaudiopolicybase
  43. ifeq ($(BOARD_HAVE_BLUETOOTH),true)
  44. LOCAL_CFLAGS += -DWITH_A2DP
  45. endif
  46. ifeq ($(AUDIO_POLICY_TEST),true)
  47. LOCAL_CFLAGS += -DAUDIO_POLICY_TEST
  48. endif
  49. include $(BUILD_STATIC_LIBRARY) 模塊二編譯成靜態庫
  50. include $(CLEAR_VARS) 模塊三
  51. LOCAL_SRC_FILES:= \
  52. AudioFlinger.cpp \
  53. AudioMixer.cpp.arm \
  54. AudioResampler.cpp.arm \
  55. AudioResamplerSinc.cpp.arm \
  56. AudioResamplerCubic.cpp.arm \
  57. AudioPolicyService.cpp
  58. LOCAL_SHARED_LIBRARIES := \
  59. libcutils \
  60. libutils \
  61. libbinder \
  62. libmedia \
  63. libhardware_legacy
  64. ifeq ($(strip $(BOARD_USES_GENERIC_AUDIO)),true)
  65. LOCAL_STATIC_LIBRARIES += libaudiointerface libaudiopolicybase
  66. LOCAL_CFLAGS += -DGENERIC_AUDIO
  67. LOCAL_SHARED_LIBRARIES += libaudio libaudiopolicy
  68. endif
  69. ifeq ($(TARGET_SIMULATOR),true)
  70. LOCAL_LDLIBS += -ldl
  71. LOCAL_SHARED_LIBRARIES += libdl
  72. endif
  73. LOCAL_MODULE:= libaudioflinger
  74. ifeq ($(BOARD_HAVE_BLUETOOTH),true)
  75. LOCAL_CFLAGS += -DWITH_BLUETOOTH -DWITH_A2DP
  76. LOCAL_SHARED_LIBRARIES += liba2dp
  77. endif
  78. ifeq ($(AUDIO_POLICY_TEST),true)
  79. LOCAL_CFLAGS += -DAUDIO_POLICY_TEST
  80. endif
  81. ifeq ($(TARGET_SIMULATOR),true)
  82. ifeq ($(HOST_OS),linux)
  83. LOCAL_LDLIBS += -lrt -lpthread
  84. endif
  85. endif
  86. ifeq ($(BOARD_USE_LVMX),true)
  87. LOCAL_CFLAGS += -DLVMX
  88. LOCAL_C_INCLUDES += vendor/nxp
  89. LOCAL_STATIC_LIBRARIES += liblifevibes
  90. LOCAL_SHARED_LIBRARIES += liblvmxservice
  91. # LOCAL_SHARED_LIBRARIES += liblvmxipc
  92. endif
  93. include $(BUILD_SHARED_LIBRARY) 模塊三編譯成動態庫
複製代碼
  1. LOCAL_PATH := $(call my-dir)
  2. include $(CLEAR_VARS)
  3. # Build all java files in the java subdirectory-->直譯(建立在java子目錄中的所有Java文件)
  4. LOCAL_SRC_FILES := $(call all-subdir-java-files)
  5. # Name of the APK to build-->直譯(創建APK的名稱
  6. LOCAL_PACKAGE_NAME := LocalPackage
  7. # Tell it to build an APK-->直譯(告訴它來建立一個APK)
  8. include $(BUILD_PACKAGE)
複製代碼
   (5)編譯一個依賴於靜態Java庫(static.jar)的應用程式
java代碼:
  1. LOCAL_PATH := $(call my-dir)
  2. include $(CLEAR_VARS)
  3. # List of static libraries to include in the package
  4. LOCAL_STATIC_JAVA_LIBRARIES := static-library
  5. # Build all java files in the java subdirectory
  6. LOCAL_SRC_FILES := $(call all-subdir-java-files)
  7. # Name of the APK to build
  8. LOCAL_PACKAGE_NAME := LocalPackage
  9. # Tell it to build an APK
  10. include $(BUILD_PACKAGE)
複製代碼
(6)編譯一個需要用平台的key簽名的應用程式
java代碼:
  1. LOCAL_PATH := $(call my-dir)
  2. include $(CLEAR_VARS)
  3. # Build all java files in the java subdirectory
  4. LOCAL_SRC_FILES := $(call all-subdir-java-files)
  5. # Name of the APK to build
  6. LOCAL_PACKAGE_NAME := LocalPackage
  7. LOCAL_CERTIFICATE := platform
  8. # Tell it to build an APK
  9. include $(BUILD_PACKAGE)
複製代碼
      (7)編譯一個需要用特定key前面的應用程式
java代碼:
  1. LOCAL_PATH := $(call my-dir)
  2. include $(CLEAR_VARS)
  3. # Build all java files in the java subdirectory
  4. LOCAL_SRC_FILES := $(call all-subdir-java-files)
  5. # Name of the APK to build
  6. LOCAL_PACKAGE_NAME := LocalPackage
  7. LOCAL_CERTIFICATE := vendor/example/certs/app
  8. # Tell it to build an APK
  9. include $(BUILD_PACKAGE)
複製代碼
   (8)添加一個預編譯應用程式
java代碼:
  1. LOCAL_PATH := $(call my-dir)
  2. include $(CLEAR_VARS)
  3. # Module name should match apk name to be installed.
  4. LOCAL_MODULE := LocalModuleName
  5. LOCAL_SRC_FILES := $(LOCAL_MODULE).apk
  6. LOCAL_MODULE_CLASS := APPS
  7. LOCAL_MODULE_SUFFIX := $(COMMON_ANDROID_PACKAGE_SUFFIX)
  8. include $(BUILD_PREBUILT)
複製代碼
  (9)添加一個靜態JAVA庫
java代碼:
  1. LOCAL_PATH := $(call my-dir)
  2. include $(CLEAR_VARS)
  3. # Build all java files in the java subdirectory
  4. LOCAL_SRC_FILES := $(call all-subdir-java-files)
  5. # Any libraries that this library depends on
  6. LOCAL_JAVA_LIBRARIES := android .test.runner
  7. # The name of the jar file to create
  8. LOCAL_MODULE := sample
  9. # Build a static jar file.
  10. include $(BUILD_STATIC_JAVA_LIBRARY)
複製代碼
  (10)Android.mk的編譯模塊中間可以定義相關的編譯內容,也就是指定相關的變量如下:
java代碼:
[code]LOCAL_AAPT_FLAGS
LOCAL_ACP_UNAVAILABLE
LOCAL_ADDITIONAL_JAVA_DIR
LOCAL_AIDL_INCLUDES
LOCAL_ALLOW_UNDEFINED_SYMBOLS
LOCAL_ARM_MODE
LOCAL_ASFLAGS
LOCAL_ASSET_DIR
LOCAL_ASSET_FILES //在Android.mk文件中編譯應用程式(BUILD_PACKAGE)時設置此變量,表示資源文件,
通常會定義成LOCAL_ASSET_FILES += $(call find-subdir-assets)
LOCAL_BUILT_MODULE_STEM
LOCAL_C_INCLUDES //額外的C/C++編譯頭文件路徑,用LOCAL_PATH表示本文件所在目錄
舉例如下:
LOCAL_C_INCLUDES += extlibs/zlib-1.2.3
LOCAL_C_INCLUDES += $(LOCAL_PATH)/src
LOCAL_CC //指定C編譯器
LOCAL_CERTIFICATE //簽名認證
LOCAL_CFLAGS //為C/C++編譯器定義額外的標誌(如宏定義),舉例:LOCAL_CFLAGS += -DLIBUTILS_NATIVE=1
LOCAL_CLASSPATH
LOCAL_COMPRESS_MODULE_SYMBOLS
LOCAL_COPY_HEADERS //install應用程式時需要複製的頭文件,必須同時定義LOCAL_COPY_HEADERS_TO
LOCAL_COPY_HEADERS_TO //install應用程式時複製頭文件的目的路徑
LOCAL_CPP_EXTENSION //如果你的C++文件不是以cpp為文件尾碼,你可以通過LOCAL_CPP_EXTENSION//指定C++文件尾碼名
如:LOCAL_CPP_EXTENSION := .cc
注意統一模塊中C++文件尾碼必須保持一致。
LOCAL_CPPFLAGS //傳遞額外的標誌給C++編譯器,如:LOCAL_CPPFLAGS += -ffriend-injection
LOCAL_CXX //指定C++編譯器
LOCAL_DX_FLAGS
LOCAL_EXPORT_PACKAGE_RESOURCES
LOCAL_FORCE_STATIC_EXECUTABLE
//如果編譯的可執行程式要進行靜態連結(執行時不依賴於任何動態庫),則設置LOCAL_FORCE_STATIC_EXECUTABLE:=true
//目前只有libc有靜態庫形式,這個只有文件系統中/sbin目錄下的應用程式會用到,這個目錄下的應用程式在運行時通常
//文件系統的其它部分還沒有加載,所以必須進行靜態連結
LOCAL_GENERATED_SOURCES
LOCAL_INSTRUMENTATION_FOR
LOCAL_INSTRUMENTATION_FOR_PACKAGE_NAME
LOCAL_INTERMEDIATE_SOURCES
LOCAL_INTERMEDIATE_TARGETS
LOCAL_IS_HOST_MODULE
LOCAL_JAR_MANIFEST
LOCAL_JARJAR_RULES
LOCAL_JAVA_LIBRARIES //編譯java應用程式和庫的時候指定包含的java類庫,目前有core和framework兩種
多數情況下定義成:LOCAL_JAVA_LIBRARIES := core framework
注意LOCAL_JAVA_LIBRARIES不是必須的,而且編譯APK時不允許定義(系統會自動添加)
LOCAL_JAVA_RESOURCE_DIRS
LOCAL_JAVA_RESOURCE_FILES
LOCAL_JNI_SHARED_LIBRARIES
LOCAL_LDFLAGS //傳遞額外的參數給連接器(務必注意參數的順序)
LOCAL_LDLIBS //為可執行程式或者庫的編譯指定額外的庫,指定庫以"-lxxx"格式,舉例:
LOCAL_LDLIBS += -lcurses -lpthread
LOCAL_LDLIBS += -Wl,-z,origin
LOCAL_MODULE //生成的模塊的名稱(注意應用程式名稱用LOCAL_PACKAGE_NAME而不是LOCAL_MODULE)
LOCAL_MODULE_PATH //生成模塊的路徑
LOCAL_MODULE_STEM
LOCAL_MODULE_TAGS //生成模塊的標記
LOCAL_NO_DEFAULT_COMPILER_FLAGS
LOCAL_NO_EMMA_COMPILE
LOCAL_NO_EMMA_INSTRUMENT
LOCAL_NO_STANDARD_LIBRARIES
LOCAL_OVERRIDES_PACKAGES
LOCAL_PACKAGE_NAME //APK應用程式的名稱
LOCAL_POST_PROCESS_COMMAND
LOCAL_PREBUILT_EXECUTABLES //預編譯including $(BUILD_PREBUILT)或者$(BUILD_HOST_PREBUILT)時所用,指定需要複製的可執行文件
LOCAL_PREBUILT_JAVA_LIBRARIES
LOCAL_PREBUILT_LIBS //預編譯including $(BUILD_PREBUILT)或者$(BUILD_HOST_PREBUILT)時所用, 指定需要複製的庫.
LOCAL_PREBUILT_OBJ_FILES
LOCAL_PREBUILT_STATIC_JAVA_LIBRARIES
LOCAL_PRELINK_MODULE //是否需要預連接處理(默認需要,用來做動態庫優化)
LOCAL_REQUIRED_MODULES //指定模塊運行所依賴的模塊(模塊安裝時將會同步
安裝它所

m mm mmm重要解析

Survey:
在Android Source Code中有envsetup.sh檔案,當執行過此檔案後,可以大幅將build的過程簡單化、自動化
此檔案在src(android source code 位置)/build/中
所以可以執行以下指令
cd /src/build/
. envsetup.sh
可以使用help來檢示有哪些指令可以使用
Invoke ". build/envsetup.sh" from your shell to add the following functions to your environment:
- croot:   Changes directory to the top of the tree.
- m:       Makes from the top of the tree.
- mm:      Builds all of the modules in the current directory.
- mmm:     Builds all of the modules in the supplied directories.
- cgrep:   Greps on all local C/C++ files.
- hgrep:   Greps on all local C/C++ header files.
- jgrep:   Greps on all local Java files.
- mkgrep:  Greps on all local make files.
- rcgrep:  Greps on all local .rc files.
- resgrep: Greps on all local res/*.xml files.
- shgrep:  Greps on all local .sh files.
- godir:   Go to the directory containing a file.
其中對模組的編譯有輔助說明的是tapas、m、mm、mmm這幾個指令
其中mmm后面要跟模組的根目錄,不是所有的目錄下都有子模組,那些含有Android.mk檔案目錄才是模組的根目錄,模組名可以從Android.mk的LOCAL_MODULE或者LOCAL_PACKAGE_NAME變數中得到。
單獨編譯某模組,需要在mmm后面指定模組路徑,例如編譯external 中的jpeg
root@ubuntu:/home/android/src# mmm external/jpeg/
============================================
PLATFORM_VERSION_CODENAME=REL
PLATFORM_VERSION=2.1-update1
TARGET_PRODUCT=generic
TARGET_BUILD_VARIANT=eng
TARGET_SIMULATOR=
TARGET_BUILD_TYPE=release
TARGET_ARCH=arm
HOST_ARCH=x86
HOST_OS=linux
HOST_BUILD_TYPE=release
BUILD_ID=ECLAIR
============================================
make: Entering directory `/home/android/src'
Target buildinfo: out/target/product/generic/root/default.prop
Target buildinfo: out/target/product/generic/system/build.prop
Copy: out/target/product/generic/system/etc/apns-conf.xml
make: Leaving directory `/home/android/src'
root@ubuntu:/home/android/src#
或者可用 mm 再欲編譯的模組目錄下執行
root@ubuntu:/home/android/src/external/jpeg# mm
============================================
PLATFORM_VERSION_CODENAME=REL
PLATFORM_VERSION=2.1-update1
TARGET_PRODUCT=generic
TARGET_BUILD_VARIANT=eng
TARGET_SIMULATOR=false
TARGET_BUILD_TYPE=release
TARGET_ARCH=arm
HOST_ARCH=x86
HOST_OS=linux
HOST_BUILD_TYPE=release
BUILD_ID=ECLAIR
============================================
make: Entering directory `/home/android/src'
Copy: out/target/product/generic/system/etc/apns-conf.xml
make: Leaving directory `/home/android/src'
root@ubuntu:/home/android/src/external/jpeg#
或者可用 m 編譯全部的模組
root@ubuntu:/home/android/src# m
你也可以在src目錄下直接執行make module name:
打開看 ./external/jpeg/Android.mk
看到裡面模組名稱為 libjpeg
LOCAL_MODULE:= libjpeg
這樣你就可以直接打模組名稱編譯
cd ~/android/src make libjpeg
也可以在登入時自動執行此 script,編輯 ~/.bashrc 或其他 shell 的 rc 檔,加入此 script 即可
# invoke android envsetup.sh source ~/android/build/envsetup.sh

沒有留言:

張貼留言