Android.mk 之 常用變量

一個Android.mk文件可以編譯多個模塊,每個模塊屬下列類型之一:

  1. APK程序-- 一般的Android程序,編譯打包生成apk文件
  2. JAVA庫 -- java類庫,編譯打包生成jar文件
  3. C\C++應用程序-- 可執行的C\C++應用程序
  4. C\C++靜態庫-- 編譯生成C\C++靜態庫,並打包成.a文件
  5. C\C++共享庫-- 編譯生成共享庫(動態鏈接庫),並打包成.so文,有且只有共享庫才能被安裝/複製到您的應用軟件(APK)包中。

可以在每一個Android.mk file 中定義一個或多個模塊,你也可以在幾個模塊中使用同一個源代碼文件。 編譯系統爲你處理許多細節問題。例如,你不需要在你的 Android.mk 中列出頭文件和依賴文件。編譯系統將會爲你自動處理這些問題。這也意味着,在升級 NDK 後,你應該得到新的toolchain/platform支持,而且不需要改變你的 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)

 

GNU Make系統變量

include $( CLEAR_VARS) CLEAR_VARS由編譯系統提供,指定讓GNU MAKEFILE爲你清除許多LOCAL_XXX變量(例如 LOCAL_MODULE, LOCAL_SRC_FILES, LOCAL_STATIC_LIBRARIES, 等等...),除LOCAL_PATH 。這是必要的,因爲所有的編譯控制文件都在同一個GNU MAKE執行環境中,所有的變量都是全局的;

include $(BUILD_EXECUTABLE)編譯應用程序;

include $(BUILD_STATIC_LIBRARY)編譯靜態庫,靜態庫不會被複制到APK包中,但是能夠用於編譯共享庫。這將會生成一個名爲 lib$(LOCAL_MODULE).a的文件;

include $(BUILD_SHARED_LIBRARY)編譯動態庫,根據所有的在 LOCAL_XXX 變量把列出的源代碼文件編譯成一個共享庫。注意,必須至少在包含這個文件之前定義 LOCAL_MODULE 和 LOCAL_SRC_FILES;

include $(BUILD_PACKAGE)編譯應用程序APK;

include $(BUILD_PREBUILT)預編譯應用程序;

TARGET_ARCH: 目標 CPU平臺的名字;

TARGET_PLATFORM: Android.mk 解析的時候,目標 Android 平臺的名字;

TARGET_ARCH_ABI:  暫時只支持兩個 value,armeabi 和 armeabi-v7a;

TARGET_ABI: 目標平臺和 ABI 的組合。

 

NDK提供的函數宏:

GNU Make函數宏,必須通過使用'$(call  )'來調用,返回值是文本化的信息。

my-dir:返回當前 Android.mk 所在的目錄的路徑,相對於 NDK 編譯系統的頂層。這是有用的,在 Android.mk 文件的開頭如此定義:

LOCAL_PATH := $(call my-dir)

all-subdir-makefiles: 返回一個位於當前'my-dir'路徑的子目錄中的所有Android.mk的列表。

例如,某一子項目的目錄層次如下:

src/foo/Android.mk

src/foo/lib1/Android.mk

src/foo/lib2/Android.mk

 

如果 src/foo/Android.mk 包含一行:include $(call all-subdir-makefiles) 那麼它就會自動包含 src/foo/lib1/Android.mk 和 src/foo/lib2/Android.mk。

這項功能用於向編譯系統提供深層次嵌套的代碼目錄層次。

 

注意,在默認情況下,NDK 將會只搜索在 src/*/Android.mk 中的文件。

  1. all-makefiles-under: 獲取某個目錄下及子目錄的所有Android.mk。$(1):需要提取Android.mk的目錄
  2. this-makefile:  返回當前Makefile 的路徑(即這個函數調用的地方)
  3. parent-makefile:  返回調用樹中父 Makefile 路徑。即包含當前Makefile的Makefile 路徑。
  4. grand-parent-makefile:返回調用樹中父Makefile的父Makefile的路徑

 

注意:在寫Android.mk文件時,call all-subdir-makefiles和call all-makefiles-under,$(LOCAL_PATH)是有區別的。前者表示“當前目錄下沒有需要編譯的文件,請向子目錄深入”,是告訴編譯器繼續向目錄深處遞歸的一種規定寫法。後者從字面上理解也應該是同一個意思。

但是,請考慮這樣一種情況:如果當前目錄下有文件需要編譯,而且在當前目錄下還有子目錄,子目錄中也有文件需要編譯,那麼當前目錄下的Android.mk除了要包含編譯當前目錄下文件的語句,同樣也要包含告訴編譯器在編譯完當前目錄下的文件後,繼續向子目錄深入的語句。這裏就有一個問題,後面這個語句該如何寫呢?是call all-subdir-makefiles,還是call all-makefiles-under,$(LOCAL_PATH)呢?寫前者是不行的,編譯器會在編譯完當前目錄下的文件後不再進入子目錄編譯,而寫成後者則可以達到我們的期望。

 

常用模塊描述變量:

每個模塊都是以include $(CLEAR_VARS)開始,並且以include $(BUILD_XXX)結束(應用程序,靜態庫,動態庫等)。

每個Android.mk文件以定義LOCAL_PATH爲開始,它用於在開發tree中查找源文件LOCAL_PATH := $(call my-dir) my-dir宏是系統用來返回包含當前Android.mk的目錄路徑;

如果有多個module需要編譯,可以放置多個目錄,在每個目錄編寫一個Android.mk,然後在根目錄的Android.mk中添加一行include $(call all-subdir-makefiles);

LOCAL_PATH:=當前文件的路徑

LOCAL_MODULE:=這個模塊的名字,LOCAL_MODULE變量必須定義,以標識你在Android.mk文件中描述的每個模塊。名稱必須是唯一的,而且不包含任何空格。注意編譯系統會自動產生合適的前綴和後綴,換句話說,一個被命名爲'xxx'的共享庫模塊,將會生成'libxxx.so'文件。

LOCAL_MODULE_CLASS:=決定編譯時的中間文件存放的位置;

LOCAL_MODULE_SUFFIX:=預編譯程序模塊的後綴;

LOCAL_MODULE_TAGS:= user/eng/tests/optional默認爲optional:

  1. user: 指該模塊只在user版本下才編譯
  2. eng: 指該模塊只在eng版本下才編譯
  3. tests: 指該模塊只在tests版本下才編譯
  4. optional:指該模塊在所有版本下都編譯

如果兩次make之間選了不同的編譯模式,則需要運行一下make installclean,確保本次make不會用到上次install的文件,也可以運行make clean,不過耗時較長。

LOCAL_SRC_FILES:=要編譯的源代碼文件列表,多個文件見用空格或Tab間隔,換行用\,追加用LOCAL_SRC_FILES+=.變量必須包含將要編譯打包進模塊中的C或C++源代碼文件。注意,你不用在這裏列出頭文件和包含文件,因爲編譯系統將會自動爲你找出依賴型的文件;僅僅列出直接傳遞給編譯器的源代碼文件就好。可以LOCAL_SRC_FILES := $(call all-subdir-java-files)這種形式來包含LOCAL_PATH目錄下的所有java文件;

LOCAL_PRELINK_MODULE:= 是否需要預連接處理(默認需要,用來做動態庫優化);

LOCAL_REQUIRED_MODULES:= 指定模塊運行所依賴的模塊(模塊安裝時將會同步安裝它所依賴的模塊); 

LOCAL_CERTIFICATE:=簽名認證類型,默認爲testkey。如果需要系統簽名就等於platform,如果不需要就等於PRESIGNED;

LOCAL_C_INCLUDES:  可選變量,表示頭文件的搜索路徑。默認的頭文件的搜索路徑是LOCAL_PATH目錄;

LOCAL_STATIC_LIBRARIES:= 該模塊需要使用的靜態鏈接庫(*.a)的名字;

LOCAL_SHARED_LIBRARIES:= 模塊在運行時需要用到的動態鏈接庫(*.so)的名稱;

LOCAL_COPY_HEADERS:= 安裝應用程序時需要複製的頭文件,必須同時定義LOCAL_COPY_HEADERS_TO;

LOCAL_COPY_HEADERS_TO:= 安裝應用程序時複製頭文件的目的路徑;

LOCAL_OVERRIDES_PACKAGES:=使其他的模塊不加入編譯:

如:DeskClock模塊的源碼中的android.mk有

LOCAL_OVERRIDES_PACKAGES := AlarmClock

使AlarmClock不會加入到編譯系統中,不會生成 AlarmClock.apk。(如果兩個模塊互相override對方,結果會怎樣?應該是先編譯到的模塊屏蔽另一個模塊);

LOCAL_BUILT_MODULE :=表示編譯鏈接後的目標文件(文件路徑+文件名);

LOCAL_BUILT_MODULE := $(built_module_path)/$(LOCAL_BUILT_MODULE_STEM);

LOCAL_BUILT_MODULE_STEM:= 表示編譯鏈接後的目標文件的文件名,帶後綴;

LOCAL_PACKAGE_NAME :=應用程序APK的名字;

LOCAL_MODULE_PATH和LOCAL_UNSTRIPPED_PATH來指定最後的目標安裝路徑。不同的文件系統路徑用以下的宏進行選擇:

  1. TARGET_ROOT_OUT:表示根文件系統out/target/product/xxxxx/root。

  2. TARGET_OUT:表示system文件系統out/target/product/xxxx/system。

  3. TARGET_OUT_DATA:表示data文件系統out/target/product/xxxx/data。

  4. TARGET_OUT_SHARED_LIBRARIES:表示out/target/product/xxxx/system/lib

  5. TARGET_OUT_APPS:表示out/target/product/xxxx/system/app

  6. ANDROID_PRODUCT_OUT:out/target/product/xxxx/

  7. TARGET_OUT_JAVA_LIBRARIES:out/target/product/xxxx/system/framework

 

用法如:

LOCAL_MODULE_PATH:=$(TARGET_ROOT_OUT)

  1. LOCAL_JNI_SHARED_LIBRARIES:定義了要包含的so庫文件的名字,如果程序沒有采用jni,不需要
    LOCAL_JNI_SHARED_LIBRARIES := libxxx
     這樣在編譯的時候,NDK自動會把這個libxxx打包進apk; 放在apk/lib/目錄下
  2. LOCAL_CFLAGS:=  可選的編譯器選項,在編譯 C 代碼文件的時候使用。這可能是有用的,指定一個附加的包含路徑(相對於NDK的頂層目錄),宏定義,或者編譯選項。注意:不要在 Android.mk 中改變 optimization/debugging 級別,只要在 Application.mk 中指定合適的信息,就會自動地爲你處理這個問題,在調試期間,會讓NDK自動生成有用的數據文件。LOCAL_CFLAGS += -Dxxx這個就是你在源碼定義的宏,需要定義的話就在這個參數上加上-Dxxx,前面加"-D",後面就是宏的名稱了。
  3. LOCAL_LDLIBS:=  編譯模塊時要使用的附加的鏈接器選項。這對於使用‘-l’前綴傳遞指定庫的名字是有用的。

例如,LOCAL_LDLIBS := -lz表示告訴鏈接器生成的模塊要在加載時刻鏈接到/system/lib/libz.so(z是mk中定義的module name)

  1. LOCAL_INSTALLED_MODULE:= 表示模塊的安裝路徑+文件名,存放的安裝目錄
  2. LOCAL_PRIVILEGED_MODULE := true,以聲明app需要放在/system/priv-app下。

 

示例:

#編譯靜態庫

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE = libhellos

LOCAL_CFLAGS = $(L_CFLAGS)

LOCAL_SRC_FILES = hellos.c

LOCAL_C_INCLUDES = $(INCLUDES)

LOCAL_SHARED_LIBRARIES := libcutils

LOCAL_COPY_HEADERS_TO := libhellos

LOCAL_COPY_HEADERS := hellos.h

include $(BUILD_STATIC_LIBRARY)

#編譯動態庫
LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE = libhellod

LOCAL_CFLAGS = $(L_CFLAGS)

LOCAL_SRC_FILES = hellod.c

LOCAL_C_INCLUDES = $(INCLUDES)

LOCAL_SHARED_LIBRARIES := libcutils

LOCAL_COPY_HEADERS_TO := libhellod

LOCAL_COPY_HEADERS := hellod.h

include $(BUILD_SHARED_LIBRARY)

#使用靜態庫

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE := hellos

LOCAL_STATIC_LIBRARIES := libhellos

LOCAL_LDLIBS += -ldl

LOCAL_CFLAGS := $(L_CFLAGS)

LOCAL_SRC_FILES := mains.c

LOCAL_C_INCLUDES := $(INCLUDES)

include $(BUILD_EXECUTABLE)

#使用動態庫
LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE := hellod

LOCAL_MODULE_TAGS := debug

LOCAL_SHARED_LIBRARIES := libc libcutils libhellod

LOCAL_LDLIBS += -ldl

LOCAL_CFLAGS := $(L_CFLAGS)

LOCAL_SRC_FILES := maind.c

LOCAL_C_INCLUDES := $(INCLUDES)

include $(BUILD_EXECUTABLE)

 

發佈了53 篇原創文章 · 獲贊 8 · 訪問量 1萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章