1. Android編譯系統分析 ---系統變量解析
LOCAL_PATH - 編譯時的目錄
LOCAL_MODULE - 編譯的目標對象
LOCAL_SRC_FILES - 編譯的源文件
LOCAL_C_INCLUDES - 需要包含的頭文件目錄
LOCAL_SHARED_LIBRARIES - 鏈接時需要的外部庫
LOCAL_PRELINK_MODULE - 是否需要prelink處理
BUILD_STATIC_LIBRARY - 指明要編譯成靜態庫
BUILD_SHARED_LIBRARY - 指明要編譯成動態庫
(1). LOCAL_PATH - 編譯時的目錄
$(call 目錄,目錄….) 目錄引入操作符: 如該目錄下有個文件夾名稱 src,則可以這樣寫 $(call src),那麼就會得到 src 目錄的完整路徑
(2). include $(CLEAR_VARS) -清除之前的一些系統變量
CLEAR_VARS:= $(BUILD_SYSTEM)/clear_vars.mk
在 build/core/config.mk 定義 CLEAR_VARS:= $(BUILD_SYSTEM)/clear_vars.mk
通過include 包含自定義的.mk文件(即是自定義編譯規則)或是引用系統其他的.mk文件(系統定義的編譯規則)。
(3). LOCAL_SRC_FILES - 編譯的源文件
可以是.c, .cpp, .java, .S(彙編文件)或是.aidl等格式, 不同的文件用空格隔開。
如果編譯目錄子目錄,採用相對路徑,如子目錄/文件名。
也可以通過$(call 目錄),指明編譯某目錄下所有.c/.cpp/.java/.S/ .aidl文件. 追加文件 LOCAL_SRC_FILES += 文件
(4). LOCAL_C_INCLUDES - 需要包含的頭文件目錄
可以是系統定義路徑,也可以是相對路徑. 如該編譯目錄下有個include目錄,寫法是include/*.h
(5). LOCAL_MODULE - 編譯的目標對象
module 是指系統的 native code,通常針對c,c++代碼
./system/core/sh/Android.mk:32:LOCAL_MODULE:= sh
./system/core/libcutils/Android.mk:71:LOCAL_MODULE := libcutils
./system/core/cpio/Android.mk:9:LOCAL_MODULE := mkbootfs
./system/core/mkbootimg/Android.mk:8:LOCAL_MODULE := mkbootimg
./system/core/toolbox/Android.mk:61:LOCAL_MODULE:= toolbox
./system/core/logcat/Android.mk:10:LOCAL_MODULE:= logcat
./system/core/adb/Android.mk:65:LOCAL_MODULE := adb
./system/core/adb/Android.mk:125:LOCAL_MODULE := adbd
./system/core/init/Android.mk:20:LOCAL_MODULE:= init
./system/core/vold/Android.mk:24:LOCAL_MODULE:= vold
./system/core/mountd/Android.mk:13:LOCAL_MODULE:= mountd
(6). LOCAL_PACKAGE_NAME
Java 應用程序的名字用該變量定義
./packages/apps/Music/Android.mk:9:LOCAL_PACKAGE_NAME := Music
./packages/apps/Browser/Android.mk:14:LOCAL_PACKAGE_NAME := Browser
./packages/apps/Settings/Android.mk:8:LOCAL_PACKAGE_NAME := Settings
./packages/apps/Stk/Android.mk:10:LOCAL_PACKAGE_NAME := Stk
./packages/apps/Contacts/Android.mk:10:LOCAL_PACKAGE_NAME := Contacts
./packages/apps/Mms/Android.mk:8:LOCAL_PACKAGE_NAME := Mms
./packages/apps/Camera/Android.mk:8:LOCAL_PACKAGE_NAME := Camera
./packages/apps/Phone/Android.mk:11:LOCAL_PACKAGE_NAME := Phone
./packages/apps/VoiceDialer/Android.mk:8:LOCAL_PACKAGE_NAME := VoiceDialer
(7). 依賴庫
LOCAL_SHARED_LIBRARIES - 鏈接時需要的外部共享庫
LOCAL_STATIC_LIBRARIES - 鏈接時需要的外部外部靜態
LOCAL_JAVA_LIBRARIES 加入jar包
(8). BUILD_SHARED_LIBRARY - 指明要編譯成動態庫。編譯的目標,用include 操作符
BUILD_STATIC_LIBRARY --- 來指明要編譯成靜態庫。
如果是java文件的話,用 BUILD_PACKAGE 來指明。會用到系統的編譯腳本host_java_library.mk,
-------------------
include $(BUILD_STATIC_LIBRARY)
BUILD_STATIC_LIBRARY:= $(BUILD_SYSTEM)/static_library.mk
-------------------
include $(BUILD_SHARED_LIBRARY)
./build/core/config.mk:50:BUILD_SHARED_LIBRARY:= $(BUILD_SYSTEM)/shared_library.mk
-------------------
include $(BUILD_HOST_SHARED_LIBRARY)
BUILD_HOST_SHARED_LIBRARY:= $(BUILD_SYSTEM)/host_shared_library.mk
-------------------
include $(BUILD_EXECUTABLE)
build/core/config.mk:51:BUILD_EXECUTABLE:= $(BUILD_SYSTEM)/executable.mk
-------------------
include $(BUILD_HOST_EXECUTABLE)
./build/core/config.mk:53:BUILD_HOST_EXECUTABLE:= $(BUILD_SYSTEM)/host_executable.mk
-------------------
BUILD_HOST_JAVA_LIBRARY:= $(BUILD_SYSTEM)/host_java_library.mk
-------------------
BUILD_JAVA_LIBRARY
./build/core/config.mk:58:BUILD_JAVA_LIBRARY:= $(BUILD_SYSTEM)/java_library.mk
------------------
BUILD_STATIC_JAVA_LIBRARY 編譯靜態JAVA庫
./build/core/config.mk:59:BUILD_STATIC_JAVA_LIBRARY:= $(BUILD_SYSTEM)/static_java_library.mk
------------------
BUILD_HOST_JAVA_LIBRARY 編譯本機用的JAVA庫
./build/core/config.mk:60:BUILD_HOST_JAVA_LIBRARY:= $(BUILD_SYSTEM)/host_java_library.mk
------------------
BUILD_HOST_STATIC_LIBRARY:= $(BUILD_SYSTEM)/host_static_library.mk
BUILD_HOST_SHARED_LIBRARY:= $(BUILD_SYSTEM)/host_shared_library.mk
BUILD_STATIC_LIBRARY:= $(BUILD_SYSTEM)/static_library.mk
BUILD_RAW_STATIC_LIBRARY := $(BUILD_SYSTEM)/raw_static_library.mk
BUILD_SHARED_LIBRARY:= $(BUILD_SYSTEM)/shared_library.mk
BUILD_EXECUTABLE:= $(BUILD_SYSTEM)/executable.mk
BUILD_RAW_EXECUTABLE:= $(BUILD_SYSTEM)/raw_executable.mk
BUILD_HOST_EXECUTABLE:= $(BUILD_SYSTEM)/host_executable.mk
BUILD_PACKAGE:= $(BUILD_SYSTEM)/package.mk
BUILD_HOST_PREBUILT:= $(BUILD_SYSTEM)/host_prebuilt.mk
BUILD_PREBUILT:= $(BUILD_SYSTEM)/prebuilt.mk
BUILD_MULTI_PREBUILT:= $(BUILD_SYSTEM)/multi_prebuilt.mk
BUILD_JAVA_LIBRARY:= $(BUILD_SYSTEM)/java_library.mk
BUILD_STATIC_JAVA_LIBRARY:= $(BUILD_SYSTEM)/static_java_library.mk
BUILD_HOST_JAVA_LIBRARY:= $(BUILD_SYSTEM)/host_java_library.mk
BUILD_DROIDDOC:= $(BUILD_SYSTEM)/droiddoc.mk
BUILD_COPY_HEADERS := $(BUILD_SYSTEM)/copy_headers.mk
BUILD_KEY_CHAR_MAP := $(BUILD_SYSTEM)/key_char_map.mk
2. NDK提供的宏功能 及 Anroid.mk 規範
以下是使用GNU make的宏功能,必須通過使用"$(call <function>)",返回一個文本信息。
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,<name>)
這將會找到通過NDK_MODULE_PATH環境變量引用的模塊<name>的目錄列表,並且將其自動包含到
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<foo>.so,它是foo模塊的名字。
你可以用LOCAL_MODULE_FILENAME覆蓋默認的那一個
LOCAL_MODULE_FILENAME
這個變量是可選的,並且允許你重新定義生成文件的名字。默認的,模塊<foo>將始終生成lib<foo>.a或者lib<foo>.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<path>來指定額外的包含路徑,然而,如果使用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。
=================================================================================
一個Android.mk file用來向編譯系統描述你的源代碼。具體來說:該文件是GNU Makefile的一小部分,會被編譯系統解析一次或多次。你可以在每一個Android.mk file中定義一個或多個模塊,你也可以在幾個模塊中使用同一個源代碼文件。選項參考以下文件:build/core/config.mk,默認的值在以下文件中定義:build/core/base_rules.mk。編譯系統爲你處理許多細節問題。例如,你不需要在你的Android.mk中列出頭文件和依賴文件。NDK編譯系統將會爲你自動處理這些問題。
最後發現還是看ndk的文檔最直接,也最全面,下面的總結主要是根據ndk提供的文檔編寫的。
1、單一的Android.mk文件:
Java代碼
-
LOCAL_PATH := $(call my-dir)
-
include $(CLEAR_VARS)
-
-
LOCAL_MODULE := hello-jni
-
LOCAL_SRC_FILES := hello-jni.c
-
-
include $(BUILD_SHARED_LIBRARY)
LOCAL_PATH必須位於Android.mk文件的最開始。它是用來定位源文件的位置,$(call my-dir)的作用就是返回當前目錄的路徑。
include $(CLEAR_VARS)的作用是清除一些變量的值,但是LOCAL_PATH除外。
LOCAL_MODULE是用來指定當前待編譯模塊的名稱,在示例中的模塊名稱爲hello-jni
LOCAL_SRC_FILES是用來指定參與編譯的源代碼文件。這裏只編譯hell0-jin.c
include $(BUILD_SHARED_LIBRARY)是用來指示將當前模塊編譯爲共享庫,前綴爲lib,後綴爲.so。
還有另外一個BUILD_STATIC_LIBRARY,是用來指示將當前模塊編譯爲靜態庫的,前綴爲.a,後綴爲.a。
這就是一個最簡單的Android.mk的結構。可能還有另外一點需要介紹:
LOCAL_C_INCLUDES:=include 這個是用來指定在編譯時即將使用的c頭文件的位置,以當前目錄爲起點。
例如:
Java代碼
-
SDL_PATH := ../SDL #定義一個變量
-
-
LOCAL_C_INCLUDES += #加載c頭文件的目錄
-
$(LOCAL_PATH)/$(SDL_PATH)/include
-
$(LOCAL_PATH)/../ffmpeg
2、定義多個Android.mk文件。
有的時候,需要編譯的模塊比較多,我們可能會將對應的模塊放置在相應的目錄中,這樣,我們可以在每個目錄中定義對應的Android.mk文件(類似於上面的寫法),最後,在根目錄放置一個Android.mk文件,內容如下:
Java代碼
-
include $(call all-subdir-makefiles)
只需要這一行就可以了,它的作用就是包含所有子目錄中的Android.mk文件
3、也可以在一個Android.mk文件裏包含多個模塊。
很直觀的想法就是將第一個Android.mk文件的內容複製一份,然後修改。我最開始也是這樣做的,但是後來出現問題了,在第二個模塊中的源碼找不到,最後還是看文檔,發現裏面已經有示例解釋了:
Java代碼
-
LOCAL_PATH := $(call my-dir)
基於GNU make的工作方式,$(call my-dir)會返回在解析build腳本時,遇到的最後一個 include中涉及的目錄。
所以,很多時候,在這個Android.mk裏面只需要調用一次$(call my-dir)就夠了,如果所有的源文件都在一個目錄中。
如果需要的話,可以在第一次調用call my-dir的時候,將值保存下來,比如:
Java代碼
-
MY_LOCAL_PATH := $(call my-dir)
-
LOCAL_PATH := $(MY_LOCAL_PATH)
-
-
然後,在另外一個模塊中,繼續如下定義:
-
LOCAL_PATH := $(MY_LOCAL_PATH)
在編譯一般的c源代碼時,上面的基本可以滿足了
關於LOCAL_CFLAGS
在某些時候,編譯源碼需要定義宏變量,這個時候,我們可以直接在對應的源碼裏面去修改,但也有一些情況,我們是沒法在別人的源碼裏定義宏變量的,這個時候,就需要使用到LOCAL_CFLAGS 了 ,舉例如下:
Java代碼
-
LOCAL_CFLAGS += -D__FAVOR_BSD
-
這行代碼的作用就是在原有的cflags基礎上,再定義一個宏變量__FAVOR_BSD
類似於#define __FAVOR_BSD
二、自定義變量
以下是在 Android.mk中依賴或定義的變量列表, 可以定義其他變量爲自己使用,但是NDK編譯系統保留下列變量名:
Java代碼
-
-以 LOCAL_開頭的名字(例如 LOCAL_MODULE)
-
-以 PRIVATE_, NDK_ 或 APP_開頭的名字(內部使用)
-
-小寫名字(內部使用,例如‘my-dir’)
如果爲了方便在 Android.mk 中定義自己的變量,建議使用 MY_前綴,一個小例子:
Java代碼
-
MY_SOURCES := foo.c
-
ifneq ($(MY_CONFIG_BAR),)
-
MY_SOURCES += bar.c
-
endif
-
LOCAL_SRC_FILES += $(MY_SOURCES)
注意:‘:=’是賦值的意思;'+='是追加的意思;‘$’表示引用某變量的值。
三、GNU Make系統變量
這些 GNU Make變量在你的 Android.mk 文件解析之前,就由編譯系統定義好了。注意在
某些情況下,NDK可能分析 Android.mk 幾次,每一次某些變量的定義會有不同。
(1)CLEAR_VARS: 指向一個編譯腳本,幾乎所有未定義的 LOCAL_XXX 變量都在"Module-des cription"節中列出。必須在開始一個新模塊之前包含這個腳本:include$(CLEAR_VARS),用於重置除LOCAL_PATH變量外的,所有LOCAL_XXX系列變量。
(2)BUILD_SHARED_LIBRARY: 指向編譯腳本,根據所有的在 LOCAL_XXX 變量把列出的源代碼文件編譯成一個共享庫。
注意,必須至少在包含這個文件之前定義 LOCAL_MODULE 和 LOCAL_SRC_FILES。
(3) BUILD_STATIC_LIBRARY: 一個 BUILD_SHARED_LIBRARY 變量用於編譯一個靜態庫。靜態庫不會複製到的APK包中,但是能夠用於編譯共享庫。
示例:include $(BUILD_STATIC_LIBRARY)
注意,這將會生成一個名爲 lib$(LOCAL_MODULE).a 的文件
(4)TARGET_ARCH: 目標 CPU平臺的名字, 和 android 開放源碼中指定的那樣。如果是
arm,表示要生成 ARM 兼容的指令,與 CPU架構的修訂版無關。
(5)TARGET_PLATFORM: Android.mk 解析的時候,目標 Android 平臺的名字.詳情可參考/development/ndk/docs/stable- apis.txt.
Java代碼
-
android-3 -> Official Android 1.5 system images
-
android-4 -> Official Android 1.6 system images
-
android-5 -> Official Android 2.0 system images
(6)TARGET_ARCH_ABI:
暫時只支持兩個 value,armeabi 和 armeabi-v7a。在現在的版本中一般把這兩個值簡單的定義爲 arm, 通過 android 平臺內部對它重定義來獲得更好的匹配。其他的 ABI 將在以後的 NDK 版本中介紹,它們會有不同的名字。注意雖然所有基於
ARM的ABI都會把 'TARGET_ARCH'定義成‘arm’, 但是會有不同的‘TARGET_ARCH_ABI’。
( 7 ) TARGET_ABI: 目標平臺和 ABI 的組合,它事實上被定義成$(TARGET_PLATFORM)-$(TARGET_ARCH_ABI) ,在想要在真實的設備中針對一個特別的目標系統進行測試時,會有用。在默認的情況下,它會是'android-3-arm'。
五、模塊描述變量
下面的變量用於向編譯系統描述你的模塊。你應該定義在'include $(CLEAR_VARS)'和'include $(BUILD_XXXXX)'之間。正如前面描寫的那樣,$(CLEAR_VARS)是一個腳本,清除所有這些變量。
(1) LOCAL_PATH: 這個變量用於給出當前文件的路徑。必須在 Android.mk 的開頭定義,可以這樣使用:LOCAL_PATH := $(call my-dir) 這個變量不會被$(CLEAR_VARS)清除,因此每個 Android.mk 只需要定義一次(即使在一個文件中定義了幾個模塊的情況下)。
(2)LOCAL_MODULE: 這是模塊的名字,它必須是唯一的,而且不能包含空格。必須在包含任一的$(BUILD_XXXX)腳本之前定義它。模塊的名字決定了生成文件的名字。例如,如果一個一個共享庫模塊的名字是,那麼生成文件的名字就是 lib.so。但是,在的 NDK 生成文
件中(或者 Android.mk 或者 Application.mk),應該只涉及(引用)有正常名字的其他模塊。
(3)LOCAL_SRC_FILES: 這是要編譯的源代碼文件列表。只要列出要傳遞給編譯器的文件,因爲編譯系統自動計算依賴。注意源代碼文件名稱都是相對於 LOCAL_PATH的,你可以使用路徑部分,例如:
Java代碼
-
LOCAL_SRC_FILES := foo.c toto/bar.c
-
Hello.c
文件之間可以用空格或Tab鍵進行分割,換行請用"".如果是追加源代碼文件的話,請用LOCAL_SRC_FILES +=
注意:在生成文件中都要使用UNIX風格的斜槓(/).windows風格的反斜槓不會被正確的處理。
注意:可以LOCAL_SRC_FILES := $(call all-subdir-java-files)這種形式來包含local_path目錄下的所有java文件。
(4) LOCAL_CPP_EXTENSION:
這是一個可選變量, 用來指定C++代碼文件的擴展名,默認是'.cpp',但是可以改變它,比如:
LOCAL_CPP_EXTENSION := .cxx
(5) LOCAL_C_INCLUDES: 可選變量,表示頭文件的搜索路徑。默認的頭文件的搜索路徑是LOCAL_PATH目錄。
示例:
Java代碼
-
LOCAL_C_INCLUDES := sources/foo或LOCAL_C_INCLUDES := $(LOCAL_PATH)/../foo
LOCAL_C_INCLUDES需要在任何包含LOCAL_CFLAGS/LOCAL_CPPFLAGS標誌之前進行設置。
(6)LOCAL_CFLAGS: 可選的編譯器選項,在編譯 C 代碼文件的時候使用。這可能是有
用的,指定一個附加的包含路徑(相對於NDK的頂層目錄),宏定義,或者編譯選項。
注意:不要在 Android.mk 中改變 optimization/debugging 級別,只要在 Application.mk 中指定合適的信息,就會自動地爲你處理這個問題,在調試期間,會讓 NDK自動生成有用的數據文件。
(7)LOCAL_CXXFLAGS: 與 LOCAL_CFLAGS同理,針對 C++源文件。
(8)LOCAL_CPPFLAGS: 與 LOCAL_CFLAGS同理,但是對 C 和 C++ source files都適用。
(9)LOCAL_STATIC_LIBRARIES: 表示該模塊需要使用哪些靜態庫,以便在編譯時進行鏈接。
(10)LOCAL_SHARED_LIBRARIES: 表示模塊在運行時要依賴的共享庫(動態庫),在鏈接時就需要,以便在生成文件時嵌入其相應的信息。注意:它不會附加列出的模塊到編譯圖,也就是仍然需要在Application.mk 中把它們添加到程序要求的模塊中。
(11)LOCAL_LDLIBS: 編譯模塊時要使用的附加的鏈接器選項。這對於使用‘-l’前綴傳遞指定庫的名字是有用的。
例如,LOCAL_LDLIBS := -lz表示告訴鏈接器生成的模塊要在加載時刻鏈接到/system/lib/libz.so
可查看 docs/STABLE-APIS.TXT 獲取使用 NDK發行版能鏈接到的開放的系統庫列表。
(12) LOCAL_ALLOW_UNDEFINED_SYMBOLS:
默認情況下, 在試圖編譯一個共享庫時,任何未定義的引用將導致一個“未定義的符號”錯誤。這對於在源代碼文件中捕捉錯誤會有很大的幫助。然而,如果因爲某些原因,需要不啓動這項檢查,可把這個變量設爲‘true’。
注意相應的共享庫可能在運行時加載失敗。(這個一般儘量不要去設爲 true)。
(13) 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的模式編譯。
(14)LOCAL_MODULE_PATH 和 LOCAL_UNSTRIPPED_PATH
在 Android.mk 文件中, 還可以用LOCAL_MODULE_PATH 和LOCAL_UNSTRIPPED_PATH指定最後的目標安裝路徑.
不同的文件系統路徑用以下的宏進行選擇:
Java代碼
-
TARGET_ROOT_OUT:表示根文件系統。
-
TARGET_OUT:表示 system文件系統。
-
TARGET_OUT_DATA:表示 data文件系統。
用法如:LOCAL_MODULE_PATH :=$(TARGET_ROOT_OUT)
至於LOCAL_MODULE_PATH 和LOCAL_UNSTRIPPED_PATH的區別,暫時還不清楚。
七、GNU Make‘功能’宏
GNU Make‘功能’宏,必須通過使用'$(call )'來調用,調用他們將返回文本化的信息。
(1)my-dir:返回當前 Android.mk 所在的目錄的路徑,相對於 NDK 編譯系統的頂層。這是有用的,在 Android.mk 文件的開頭如此定義:
Java代碼
-
LOCAL_PATH := $(call my-dir)
(2)all-subdir-makefiles: 返回一個位於當前'my-dir'路徑的子目錄中的所有Android.mk的列表。
例如,看下面的目錄層次:
Java代碼
-
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 中的文件。
(3)this-makefile: 返回當前Makefile 的路徑(即這個函數調用的地方)
(4)parent-makefile: 返回調用樹中父 Makefile 路徑。即包含當前Makefile的Makefile 路徑。
(5)grand-parent-makefile:返回調用樹中父Makefile的父Makefile的路徑
八、 Android.mk 使用模板
在一個 Android.mk 中可以生成多個APK應用程序,JAVA庫,CC++可執行程序,CC++動態庫和CC++靜態庫。
(1)編譯APK應用程序模板。
關於編譯APK應用程序的模板請參照《Android.mk編譯APK範例》
(2)編譯JAVA庫模板
Java代碼
-
LOCAL_PATH := $(call my-dir)
-
include $(CLEAR_VARS)
-
# Build all java files in the java subdirectory
-
LOCAL_SRC_FILES := $(call all-subdir-java-files)
-
# Any libraries that this library depends on
-
LOCAL_JAVA_LIBRARIES := android.test.runner
-
# The name of the jar file to create
-
LOCAL_MODULE := sample
-
# Build a static jar file.
-
include $(BUILD_STATIC_JAVA_LIBRARY)
注:LOCAL_JAVA_LIBRARIES := android.test.runner表示生成的JAVA庫的jar文件名
(3)編譯C/C++應用程序模板如下:
Java代碼
-
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 表示以一個可執行程序的方式進行編譯。
(4)編譯CC++靜態庫
Java代碼
-
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 表示編譯一個靜態庫。
(5)編譯CC++動態庫的模板
Java代碼
-
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 會變:
Java代碼
-
out/target/product/generic/obj/APPS
-
out/target/product/generic/obj/JAVA_LIBRARIES
-
out/target/product/generic/obj/EXECUTABLE
-
out/target/product/generic/obj/STATIC_LIBRARY
-
out/target/product/generic/obj/SHARED_LIBRARY
每個模塊的目標文件夾分別爲:
1)APK程序:XXX_intermediates
2)JAVA庫程序:XXX_intermediates
這裏的XXX
3)CC++可執行程序:XXX_intermediates
4)CC++靜態庫: XXX_static_intermediates
5)CC++動態庫: XXX_shared_intermediates