編輯:關於Android編程
Android.mk簡介:
Android.mk文件用來告知NDK Build 系統關於Source的信息。 Android.mk將是GNU Makefile的一部分,且將被Build System解析一次或多次。
所以,請盡量少的在Android.mk中聲明變量,也不要假定任何東西不會在解析過程中定義。
Android.mk文件語法允許我們將Source打包成一個"modules". modules可以是:
靜態庫
動態庫。
只有動態庫可以被 install/copy到應用程序包(APK). 靜態庫則可以被鏈接入動態庫。
可以在一個Android.mk中定義一個或多個modules. 也可以將同一份source 加進多個modules.
Build System幫我們處理了很多細節而不需要我們再關心。例如:你不需要在Android.mk中列出頭文件和外部依賴文件。
NDK Build System自動幫我們提供這些信息。這也意味著,當用戶升級NDK後,你將可以受益於新的toolchain/platform而不必再去修改Android.mk.
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為開始。它用於在開發tree中查找源文件。
宏my-dir則由Build System提供。返回包含Android.mk的目錄路徑。
include $(CLEAR_VARS)
CLEAR_VARS 變量由Build System提供。並指向一個指定的GNU Makefile,由它負責清理很多LOCAL_xxx.
例如:LOCAL_MODULE, LOCAL_SRC_FILES, LOCAL_STATIC_LIBRARIES等等。但不清理LOCAL_PATH.
這個清理動作是必須的,因為所有的編譯控制文件由同一個GNU Make解析和執行,其變量是全局的。所以清理後才能避免相互影響。
LOCAL_MODULE := hello-jni
LOCAL_MODULE模塊必須定義,以表示Android.mk中的每一個模塊。名字必須唯一且不包含空格。
Build System會自動添加適當的前綴和後綴。例如,foo,要產生動態庫,則生成libfoo.so. 但請注意:如果模塊名被定為:libfoo.則生成libfoo.so. 不再加前綴。
LOCAL_SRC_FILES := hello-jni.c
LOCAL_SRC_FILES變量必須包含將要打包如模塊的C/C++ 源碼。
不必列出頭文件,build System 會自動幫我們找出依賴文件。
缺省的C++源碼的擴展名為.cpp. 也可以修改,通過LOCAL_CPP_EXTENSION。
include $(BUILD_SHARED_LIBRARY)
BUILD_SHARED_LIBRARY:是Build System提供的一個變量,指向一個GNU Makefile Script。
它負責收集自從上次調用 include $(CLEAR_VARS) 後的所有LOCAL_XXX信息。並決定編譯為什麼。
BUILD_STATIC_LIBRARY:編譯為靜態庫。
BUILD_SHARED_LIBRARY :編譯為動態庫
BUILD_EXECUTABLE:編譯為Native C可執行程序
一、Android.mk文件的用途
一個android子項目中會存在一個或多個Android.mk文件
1、單一的Android.mk文件
直接參考NDK的sample目錄下的hello-jni項目,在這個項目中只有一個Android.mk文件
2、多個Android.mk文件
如果需要編譯的模塊比較多,我們可能會將對應的模塊放置在相應的目錄中,這樣,我們可以在每個目錄中定義對應的Android.mk文件(類似於上面的寫法),最後,在根目錄放置一個Android.mk文件,內容如下:
include $(call all-subdir-makefiles)
只需要這一行就可以了,它的作用就是包含所有子目錄中的Android.mk文件
3、多個模塊共用一個Android.mk
這個文件允許你將源文件組織成模塊,這個模塊中含有:
-靜態庫(.a文件)
-動態庫(.so文件)
只有共享庫才能被安裝/復制到您的應用軟件(APK)包中
include $(BUILD_STATIC_LIBRARY),編譯出的是靜態庫
include $(BUILD_SHARED_LIBRARY),編譯出的是動態庫
二、自定義變量
以下是在 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系統變量
這些 GNU Make變量在你的 Android.mk 文件解析之前,就由編譯系統定義好了。注意在某些情況下,NDK可能分析 Android.mk 幾次,每一次某些變量的定義會有不同。
(1)CLEAR_VARS: 指向一個編譯腳本,幾乎所有未定義的 LOCAL_XXX 變量都在"Module-description"節中列出。必須在開始一個新模塊之前包含這個腳本: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平台的名字
(5)TARGET_PLATFORM: Android.mk 解析的時候,目標 Android 平台的名字.詳情可考/development/ndk/docs/stable- apis.txt.
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。。
(7)TARGET_ABI: 目標平台和 ABI 的組合,
四、模塊描述變量
下面的變量用於向編譯系統描述你的模塊。應該定義在'include $(CLEAR_VARS)'和'include $(BUILD_XXXXX)'之間。$(CLEAR_VARS)是一個腳本,清除所有這些變量。
(1)LOCAL_PATH: 這個變量用於給出當前文件的路徑。
必須在 Android.mk 的開頭定義,可以這樣使用:LOCAL_PATH := $(call my-dir)
如當前目錄下有個文件夾名稱 src,則可以這樣寫 $(call src),那麼就會得到 src 目錄的完整路徑
這個變量不會被$(CLEAR_VARS)清除,因此每個 Android.mk 只需要定義一次(即使在一個文件中定義了幾個模塊的情況下)。
(2)LOCAL_MODULE: 這是模塊的名字,它必須是唯一的,而且不能包含空格。
必須在包含任一的$(BUILD_XXXX)腳本之前定義它。模塊的名字決定了生成文件的名字。
(3)LOCAL_SRC_FILES: 這是要編譯的源代碼文件列表。
只要列出要傳遞給編譯器的文件,因為編譯系統自動計算依賴。注意源代碼文件名稱都是相對於 LOCAL_PATH的,你可以使用路徑部分,例如:
LOCAL_SRC_FILES := foo.c toto/bar.c\
Hello.c
文件之間可以用空格或Tab鍵進行分割,換行請用"\"
如果是追加源代碼文件的話,請用LOCAL_SRC_FILES +=
注意:可以LOCAL_SRC_FILES := $(call all-subdir-java-files)這種形式來包含local_path目錄下的所有java文件。
(4)LOCAL_C_INCLUDES: 可選變量,表示頭文件的搜索路徑。
默認的頭文件的搜索路徑是LOCAL_PATH目錄。
(5)LOCAL_STATIC_LIBRARIES: 表示該模塊需要使用哪些靜態庫,以便在編譯時進行鏈接。
(6)LOCAL_SHARED_LIBRARIES: 表示模塊在運行時要依賴的共享庫(動態庫),在鏈接時就需要,以便在生成文件時嵌入其相應的信息。
注意:它不會附加列出的模塊到編譯圖,也就是仍然需要在Application.mk 中把它們添加到程序要求的模塊中。
(7)LOCAL_LDLIBS: 編譯模塊時要使用的附加的鏈接器選項。這對於使用‘-l'前綴傳遞指定庫的名字是有用的。
例如,LOCAL_LDLIBS := -lz表示告訴鏈接器生成的模塊要在加載時刻鏈接到/system/lib/libz.so
可查看 docs/STABLE-APIS.TXT 獲取使用 NDK發行版能鏈接到的開放的系統庫列表。
(8)LOCAL_MODULE_PATH 和 LOCAL_UNSTRIPPED_PATH
在 Android.mk 文件中, 還可以用LOCAL_MODULE_PATH 和LOCAL_UNSTRIPPED_PATH指定最後的目標安裝路徑.
不同的文件系統路徑用以下的宏進行選擇:
TARGET_ROOT_OUT:表示根文件系統。
TARGET_OUT:表示 system文件系統。
TARGET_OUT_DATA:表示 data文件系統。
用法如:LOCAL_MODULE_PATH :=$(TARGET_ROOT_OUT)
至於LOCAL_MODULE_PATH 和LOCAL_UNSTRIPPED_PATH的區別,暫時還不清楚。
(9)LOCAL_JNI_SHARED_LIBRARIES:定義了要包含的so庫文件的名字,如果程序沒有采用jni,不需要
LOCAL_JNI_SHARED_LIBRARIES := libxxx 這樣在編譯的時候,NDK自動會把這個libxxx打包進apk; 放在youapk/lib/目錄下
五、NDK提供的函數宏
GNU Make函數宏,必須通過使用'$(call )'來調用,返回值是文本化的信息。
(1)my-dir:返回當前 Android.mk 所在的目錄的路徑,相對於 NDK 編譯系統的頂層。這是有用的,在 Android.mk 文件的開頭如此定義:
LOCAL_PATH := $(call my-dir)
(2)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 中的文件。
(3)this-makefile: 返回當前Makefile 的路徑(即這個函數調用的地方)
(4)parent-makefile: 返回調用樹中父 Makefile 路徑。即包含當前Makefile的Makefile 路徑。
(5)grand-parent-makefile:返回調用樹中父Makefile的父Makefile的路徑
六、 Android.mk示例
#編譯靜態庫 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_SHARED_LIBRARIES := 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)
前言 其實很幸運,入職一周之後就能跟著兩個師兄做android開發,師兄都是大神,身為小白的我只能多多學習,多多努力。最近一段時間都忙的沒機會總結,今天剛完成了andro
SQLite是Android平台軟件開發中會經常用到的數據庫產品,作為一款輕型數據庫,SQLite的設計目標就是是嵌入式的,而且目前已經在很多嵌入式產品中使用了它,它占用
本文操作手機平台 : 小米4 ;編譯平台 : Ubuntu 14.04 LTS 虛擬機,使用CyanogenMod 源碼編譯ROM。手機的兩種模式: 在下面有詳細的圖片示
過去的兩天,在項目中,拋棄了ListView, 想試一試RecyclerView, 在用的過程中,遇到了一些問題,比如:如何為RecyclerView添加Header和F