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