Android.mk簡(jiǎn)介:
Android.mk文件用來(lái)告知NDK Build系統(tǒng)關(guān)于Source的信息。Android.mk將是GNU Makefile的一部分,且將被Build System解析一次或多次。
所以,請(qǐng)盡量少的在Android.mk中聲明變量,也不要假定任何東西不會(huì)在解析過(guò)程中定義。
Android.mk文件語(yǔ)法允許我們將Source打包成一個(gè)"modules",modules可以是:
-
靜態(tài)庫(kù)
-
動(dòng)態(tài)庫(kù)
只有動(dòng)態(tài)庫(kù)可以被install/copy到應(yīng)用程序包(APK), 靜態(tài)庫(kù)則可以被鏈接入動(dòng)態(tài)庫(kù)。
可以在一個(gè)Android.mk中定義一個(gè)或多個(gè)modules. 也可以將同一份source加進(jìn)多個(gè)modules。
Build System幫我們處理了很多細(xì)節(jié)而不需要我們?cè)訇P(guān)心。例如:你不需要在Android.mk中列出頭文件和外部依賴文件。
NDK Build System自動(dòng)幫我們提供這些信息。這也意味著,當(dāng)用戶升級(jí)NDK后,你將可以受益于新的toolchain/platform而不必再去修改Android.mk。
Android.mk 語(yǔ)法
1. 基本語(yǔ)法
首先看一個(gè)最簡(jiǎn)單的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)
每個(gè)Android.mk文件必須以定義LOCAL_PATH為開(kāi)始,它用于在開(kāi)發(fā)tree中查找源文件;宏my-dir則由Build System提供,返回包含Android.mk的目錄路徑。
include $(CLEAR_VARS)
CLEAR_VARS 變量由Build System提供,并指向一個(gè)指定的GNU Makefile,由它負(fù)責(zé)清理很多LOCAL_xxx。
例如:LOCAL_MODULE, LOCAL_SRC_FILES, LOCAL_STATIC_LIBRARIES等等。但不清理LOCAL_PATH,這個(gè)清理動(dòng)作是必須的,因?yàn)樗械木幾g控制文件由同一個(gè)GNU Make解析和執(zhí)行,其變量是全局的,所以清理后才能避免相互影響。
LOCAL_MODULE := hello-jni
LOCAL_MODULE模塊必須定義,以表示Android.mk中的每一個(gè)模塊。名字必須唯一且不包含空格。
Build System會(huì)自動(dòng)添加適當(dāng)?shù)那熬Y和后綴。例如,foo,要產(chǎn)生動(dòng)態(tài)庫(kù),則生成libfoo.so。但請(qǐng)注意:如果模塊名被定為:libfoo,則生成libfoo.so,不再加前綴。
LOCAL_SRC_FILES := hello-jni.c
LOCAL_SRC_FILES 變量必須包含將要打包如模塊的 C/C++ 源碼。
不必列出頭文件,Build System 會(huì)自動(dòng)幫我們找出依賴文件。
缺省的C++源碼的擴(kuò)展名為.cpp。也可以修改,通過(guò)LOCAL_CPP_EXTENSION。
include $(BUILD_SHARED_LIBRARY)
BUILD_SHARED_LIBRARY 是Build System提供的一個(gè)變量,指向一個(gè)GNU Makefile Script。
它負(fù)責(zé)收集自從上次調(diào)用 include $(CLEAR_VARS) 后的所有LOCAL_XXX信息,并決定編譯為什么。
-
BUILD_STATIC_LIBRARY:編譯為靜態(tài)庫(kù)
-
BUILD_SHARED_LIBRARY:編譯為動(dòng)態(tài)庫(kù)
-
BUILD_EXECUTABLE:編譯為Native C可執(zhí)行程序
2. NDK Build System變量
NDK Build System 保留以下變量名:
-
以LOCAL_、PRIVATE_,NDK_、APP_ 開(kāi)頭的名字
-
小寫(xiě)字母名字,如:my-dir
如果想要定義自己在Android.mk中使用的變量名,建議添加 MY_ 前綴。
2.1 NDK提供的變量
此類GNU Make變量是NDK Build System在解析Android.mk之前就定義好了的。
2.1.1 CLEAR_VARS
指向一個(gè)編譯腳本,必須在新模塊前包含之。
include $(CLEAR_VARS)
2.1.2 BUILD_SHARED_LIBRARY
指向一個(gè)編譯腳本,它收集自從上次調(diào)用include $(CLEAR_VARS) 后的所有LOCAL_XXX信息。
并決定如何將你列出的Source編譯成一個(gè)動(dòng)態(tài)庫(kù)。注意:在包含此文件前,至少應(yīng)該包含:LOCAL_MODULE and LOCAL_SRC_FILES,例如:
include $(BUILD_SHARED_LIBRARY)
2.1.3 BUILD_STATIC_LIBRARY
與前面類似,它也指向一個(gè)編譯腳本,
收集自從上次調(diào)用 include $(CLEAR_VARS) 后的所有LOCAL_XXX信息。
并決定如何將你列出的Source編譯成一個(gè)靜態(tài)庫(kù)。靜態(tài)庫(kù)不能夠加入到Project 或者APK中。但它可以用來(lái)生成動(dòng)態(tài)庫(kù)。
LOCAL_STATIC_LIBRARIES and LOCAL_WHOLE_STATIC_LIBRARIES將描述之。
include $(BUILD_STATIC_LIBRARY)
2.1.4 BUILD_EXECUTABLE
與前面類似,它也指向一個(gè)編譯腳本,收集自從上次調(diào)用 include $(CLEAR_VARS) 后的所有LOCAL_XXX信息。
并決定如何將你列出的Source編譯成一個(gè)可執(zhí)行Native程序。
include $(BUILD_EXECUTABLE)
2.1.5 PREBUILT_SHARED_LIBRARY
把這個(gè)共享庫(kù)聲明為 “一個(gè)” 獨(dú)立的模塊。
指向一個(gè)build 腳本,用來(lái)指定一個(gè)預(yù)先編譯好多動(dòng)態(tài)庫(kù)。與BUILD_SHARED_LIBRARY and BUILD_STATIC_LIBRARY不同,
此時(shí)模塊的LOCAL_SRC_FILES應(yīng)該被指定為一個(gè)預(yù)先編譯好的動(dòng)態(tài)庫(kù),而非source file.
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := foo-prebuilt # 模塊名
LOCAL_SRC_FILES := libfoo.so # 模塊的文件路徑(相對(duì)于 LOCAL_PATH)
include $(PREBUILT_SHARED_LIBRARY) # 注意這里不是 BUILD_SHARED_LIBRARY
include $(PREBUILT_SHARED_LIBRARY) # 注意這里不是 BUILD_SHARED_LIBRARY
這個(gè)共享庫(kù)將被拷貝到 $PROJECT/obj/local 和 $PROJECT/libs/ (stripped) 主要是用在將已經(jīng)編譯好的第三方庫(kù)
使用在本Android Project中。為什么不直接將其copy到libs/armabi目錄呢?因?yàn)檫@樣做缺陷很多。
2.1.6 PREBUILT_STATIC_LIBRARY
預(yù)先編譯的靜態(tài)庫(kù),同上。
2.1.7 TARGET_ARCH
目標(biāo)CPU架構(gòu)名,如果為“arm” 則聲稱ARM兼容的指令,與CPU架構(gòu)版本無(wú)關(guān)。
ifeq ($(TARGET_ARCH),arm)
...
endif
2.1.8 TARGET_PLATFORM
目標(biāo)平臺(tái)的名字,對(duì)應(yīng)android版本號(hào),取值包括:android-8、android-9...android-21。
ifeq ($(TARGET_PLATFORM),android-8)
...
endif
2.1.9 TARGET_ARCH_ABI
是反應(yīng)當(dāng)前的cpu/abi的類型,取值包括:
32位:armeabi、armeabi-v7a、x86、mips;
64位:arm64-v8a、x86_64、mips64;
ifeq ($(TARGET_ARCH_ABI),armeabi-v7a)
RS_TRIPLE := armv7-none-linux-gnueabi
endif
ifeq ($(TARGET_ARCH_ABI),armeabi)
RS_TRIPLE := arm-none-linux-gnueabi
endif
ifeq ($(TARGET_ARCH_ABI),mips)
RS_TRIPLE := mipsel-unknown-linux
endif
ifeq ($(TARGET_ARCH_ABI),x86)
RS_TRIPLE := i686-unknown-linux
endif
2.2 NDK提供的功能宏
GNU Make 提供的功能宏,只有通過(guò)類似:$(call function) 的方式來(lái)得到其值,它將返回文本化的信息。
2.2.1 my-dir
返回最近一次include的Makefile的路徑,通常返回Android.mk所在的路徑,它用來(lái)作為Android.mk的開(kāi)頭來(lái)定義LOCAL_PATH。
LOCAL_PATH := $(call my-dir)
注意:返回的是最近一次include的Makefile的路徑。所以在include其它Makefile后,再調(diào)用$(call my-dir)會(huì)返回其它Android.mk所在路徑。
例如:
LOCAL_PATH := $(call my-dir) # declare one module
...
include $(LOCAL_PATH)/foo/Android.mk
LOCAL_PATH := $(call my-dir) # declare another module
則第二次返回的LOCAL_PATH為:$PATH/foo,而非$PATH。
2.2.2 all-subdir-makefiles
返回一個(gè)列表,包含 “my-dir” 中所有子目錄中的Android.mk。
例如:
sources/foo/Android.mk
sources/foo/lib1/Android.mk
sources/foo/lib2/Android.mk
在sources/foo/Android.mk中:
include $(call all-subdir-makefiles)
那則自動(dòng)include了:
sources/foo/lib1/Android.mk
sources/foo/lib2/Android.mk
2.2.3 this-makefile
當(dāng)前Makefile的路徑。
2.2.4 parent-makefile
返回include tree中父Makefile路徑,也就是include當(dāng)前Makefile的Makefile路徑。
2.2.5 import-module
允許尋找并import其它Modules到本Android.mk中來(lái)。它會(huì)從NDK_MODULE_PATH尋找指定的模塊名。
import-module和include區(qū)別:
功能基本一樣。
概念區(qū)別:include導(dǎo)入的是由我們自己寫(xiě)的Makefile。而import-module導(dǎo)入的是外部庫(kù)、外部模塊提供的Makefile。
用法區(qū)別:include的路徑是Makefile文件的絕對(duì)路徑。
而import-module是NDK_MODULE_PATH中路徑列表的相對(duì)路徑。
$(call import-module, 模塊名/子目錄)
NDK_MODULE_PATH的配置:
NDK_MODULE_PATH 是一個(gè)環(huán)境變量,是Android.mk中設(shè)置的變量。
直接將 “NDK_MODULE_PATH=路徑1:路徑2” 加到 ndk-build命令的參數(shù)后面:
$ndk-build -C $HELLOWORLD_ROOT NDK_MODULE_PATH=路徑1:路徑2
在Android.mk中設(shè)置NDK_MODULE_PATH:
$(call import-add-path,$(LOCAL_PATH)/platform/third_party/android/prebuilt)
在系統(tǒng)環(huán)境里手動(dòng)添加這個(gè)環(huán)境變量。
例如:
有一個(gè)Android.mk路徑如下:
F:cocos2d-xCocosDenshionandroidandroid.mk
已設(shè)置:NDK_MODULE_PATH=/cygdrive/f/cocos2d-x
那么在Android.mk引入此模塊的方法如下:
$(call import-module,CocosDenshion/android)
2.3 模塊描述變量
此類變量用來(lái)給Build System描述模塊信息。在'include $(CLEAR_VARS)' 和 'include $(BUILD_XXXXX)'之間,必須定義此類變量。
-
include $(CLEAR_VARS) 用來(lái)清空這些變量。
-
include $(BUILD_XXXXX) 收集和使用這些變量。
2.3.1 LOCAL_PATH
這個(gè)值用來(lái)給定當(dāng)前目錄,必須在Android.mk的開(kāi)是位置定義之。
例如:
LOCAL_PATH := $(call my-dir)
LOCAL_PATH不會(huì)被include $(CLEAR_VARS)清理。
2.3.2 LOCAL_MODULE
定義Modules名,在include $(BUILD_XXXXX)之前,必須定義這個(gè)變量,此變量必須唯一且不能有空格。通常由此變量名決定最終生成的目標(biāo)文件名。
2.3.3 LOCAL_MODULE_FILENAME
(可選)即允許用戶重新定義最終生成的目標(biāo)文件名。
LOCAL_MODULE := foo-version-1
LOCAL_MODULE_FILENAME := libfoo
2.3.4 LOCAL_SRC_FILES
為Build Modules而提供的Source文件列表,不需要列出依賴文件。
==注意:文件相對(duì)于LOCAL_PATH存放,且可以提供相對(duì)路徑。==
例如:
LOCAL_SRC_FILES := foo.c
toto/bar.c
2.3.5 LOCAL_CPP_EXTENSION
(可選)指出C++擴(kuò)展名。
LOCAL_CPP_EXTENSION := .cxx
從NDK R7后,可以寫(xiě)多個(gè):
LOCAL_CPP_EXTENSION := .cxx .cpp .cc
2.3.6 LOCAL_CPP_FEATURES
(可選)用來(lái)指定C++ features。
LOCAL_CPP_FEATURES := rtti
LOCAL_CPP_FEATURES := exceptions
2.3.7 LOCAL_C_INCLUDES
一個(gè)可選的path列表,相對(duì)于NDK ROOT目錄,編譯時(shí)將會(huì)把這些目錄附上,主要為了頭文件的引用。
LOCAL_C_INCLUDES := sources/foo
LOCAL_C_INCLUDES := $(LOCAL_PATH)/../foo
2.3.8 LOCAL_CFLAGS
(可選)在編譯C/C++ source 時(shí)添加如Flags,用來(lái)附加編譯選項(xiàng)。
注意:不要嘗試在此處修改編譯的優(yōu)化選項(xiàng)和Debug等級(jí),它會(huì)通過(guò)您Application.mk中的信息自動(dòng)指定。
-
-Wall:是打開(kāi)警告開(kāi)關(guān)。
-
-O:代表默認(rèn)優(yōu)化,可選:-O0不優(yōu)化,-O1低級(jí)優(yōu)化,-O2中級(jí)優(yōu)化,-O3高級(jí)優(yōu)化,-Os代碼空間優(yōu)化。
-
-g:是生成調(diào)試信息,生成的可執(zhí)行文件具有和源代碼關(guān)聯(lián)的可調(diào)試的信息。
-
-fopenmp:OpenMp是由OpenMP Architecture Review Board牽頭提出的,并已被廣泛接受的,用于共享內(nèi)存并行系統(tǒng)的多處理器程序設(shè)計(jì)的一套指導(dǎo)性的編譯處理方案(Compiler Directive)。
OpenMP支持的編程語(yǔ)言包括C語(yǔ)言、C++和Fortran;而支持OpenMp的編譯器包括Sun Compiler,GNU Compiler和Intel Compiler等。OpenMp提供了對(duì)并行算法的高層的抽象描述,程序員通過(guò)在源代碼中加入專用的pragma來(lái)指明自己的意圖,由此編譯器可以自動(dòng)將程序進(jìn)行并行化,并在必要之處加入同步互斥以及通信。當(dāng)選擇忽略這些pragma,或者編譯器不支持OpenMp時(shí),程序又可退化為通常的程序(一般為串行),代碼仍然可以正常運(yùn)作,只是不能利用多線程來(lái)加速程序執(zhí)行。
-
-D:增加全局宏定義(==常用==)
-
-ffast-math:浮點(diǎn)優(yōu)化選項(xiàng),極大地提高浮點(diǎn)運(yùn)算速度。
-
-mfloat-abi=softfp 浮點(diǎn)運(yùn)算
LOCAL_CFLAGS += -DXXX # 相當(dāng)于在所有源文件中增加一個(gè)宏定義'#define XXX'
2.3.10 LOCAL_CPPFLAGS
C++ Source 編譯時(shí)添加的C Flags,這些Flags將出現(xiàn)在LOCAL_CFLAGS flags 的后面。
2.3.11 LOCAL_STATIC_LIBRARIES
要鏈接到本模塊的靜態(tài)庫(kù)list,這僅僅對(duì)共享庫(kù)模塊才有意義。
Android.mk 1:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := mylib_static
LOCAL_SRC_FILES := src.c
include $(BUILD_STATIC_LIBRARY)
Android.mk 2:
include $(CLEAR_VARS)
LOCAL_MODULE := mylib_shared
LOCAL_SRC_FILES := src2.c
LOCAL_STATIC_LIBRARIES := mylib_static
include $(BUILD_SHARED_LIBRARY)
要編譯Android.mk 2,必須已經(jīng)先編譯mylib_static靜態(tài)庫(kù),即Android.mk 1。
2.3.12 LOCAL_SHARED_LIBRARIES
要鏈接到本模塊的動(dòng)態(tài)庫(kù),同上。
2.3.13 LOCAL_WHOLE_STATIC_LIBRARIES
靜態(tài)庫(kù)全鏈接,不同于LOCAL_STATIC_LIBRARIES,類似于使用--whole-archive,LOCAL_WHOLE_STATIC_LIBRARIES在連接靜態(tài)連接庫(kù)的時(shí)候不會(huì)移除"daed code",何謂dead code呢,就是調(diào)用者模塊永遠(yuǎn)都不會(huì)用到的代碼段和變量。
2.3.14 LOCAL_LDLIBS
鏈接flags,鏈接的庫(kù)不產(chǎn)生依賴關(guān)系,一般用于不需要重新編譯的庫(kù),可以用它來(lái)添加系統(tǒng)庫(kù)。
LOCAL_LDLIBS += -lm –lz –lc -lcutils –lutils –llog …
2.3.15 LOCAL_ALLOW_UNDEFINED_SYMBOLS
默認(rèn)情況下,在試圖編譯一個(gè)共享庫(kù)時(shí),任何未定義的引用將導(dǎo)致一個(gè)“未定義的符號(hào)”錯(cuò)誤。
然而,如果你因?yàn)槟承┰颍枰粏?dòng)這項(xiàng)檢查,把這個(gè)變量設(shè)為'true'。注意相應(yīng)的共享庫(kù)可能在運(yùn)行時(shí)加載失敗。(這個(gè)一般盡量不要去設(shè)為true)
2.3.16 LOCAL_ARM_MODE
缺省模式下,ARM目標(biāo)代碼被編譯為thumb模式。每個(gè)指令16位。如果指定此變量為'arm',則指令為32位。
LOCAL_ARM_MODE := arm
其實(shí)也可以指定某一個(gè)或者某幾個(gè)文件的ARM指令模式。
2.3.17 LOCAL_ARM_NEON
設(shè)置為true時(shí),會(huì)講浮點(diǎn)編譯成neon指令。這會(huì)極大地加快浮點(diǎn)運(yùn)算(前提是硬件支持)
只有targeting為'armeabi-v7a'時(shí)才可以。
2.3.18 LOCAL_DISABLE_NO_EXECUTE
Android NDK r4版本開(kāi)始支持這種"NX bit"的安全功能。默認(rèn)是啟用的,你也可以設(shè)置該變量的值為true來(lái)禁用它。但不推薦這么做。該功能不會(huì)修改ABI,只在ARMv6+CPU的設(shè)備內(nèi)核上啟用。
2.3.19 LOCAL_EXPORT_CFLAGS
定義這個(gè)變量用來(lái)記錄C/C++編譯器標(biāo)志集合,
并且會(huì)被添加到其他任何以LOCAL_STATIC_LIBRARIES和LOCAL_SHARED_LIBRARIES的模塊的LOCAL_CFLAGS定義中。
注意:此處NDK版本為NDK R7C。(不同NDK版本,ndk-build所產(chǎn)生的Makefile并不完全相同)
-
Android
+關(guān)注
關(guān)注
12文章
3935瀏覽量
127339 -
NDK
+關(guān)注
關(guān)注
0文章
17瀏覽量
14062 -
語(yǔ)法
+關(guān)注
關(guān)注
0文章
44瀏覽量
9807
原文標(biāo)題:Android.mk文件語(yǔ)法詳解
文章出處:【微信號(hào):哆啦安全,微信公眾號(hào):哆啦安全】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論