NDK設定檔Android.mk簡介

來源:互聯網
上載者:User

標籤:des   android   style   blog   http   io   color   ar   使用   

簡介

android.mk主要描述了c或者c++檔案時如何在ndk工程中被使用的,該小節主要描述了android.mk的構建規則

概覽
  • android.mk檔案描述了你的源碼是如何構建的,主要包括:該檔案實際上是一個簡化了的GNU makefile檔案。該檔案被構建系統解析一次或多次,因此你需要儘可能少得自訂變數。同樣的,也不能在解析過程中認為未定義任何變數
  • 該檔案文法決定了如何把你的源碼組織到“模組”中,“模組”的概念是:
    • 靜態庫
    • 動態庫
    • 可執行檔

編譯器僅僅安裝/拷貝動態庫到你的apk包中去。此外,靜態庫可以產生動態庫

在每個android.mk檔案中可以定義一個或多個模組,在多個模組中可以共用一個源檔案

  • 編譯器自動加上了更詳細的資訊,比如不需要列出所包含的標頭檔或者不需要寫出很明確的檔案以來關係,NDK編譯器已經為你自動計算好了。

同樣的,當更新到新發布的NDK後,不需要修改android.mk檔案就可以自動使用新的工具鏈/平台進行編譯

注意此文法非常接近完整的安卓開源項目中andriod.mk文法,但是編譯器是以不同的方式執行的。為了讓開發人員更容易得重複使用編譯底層庫的源檔案,它們被有意的設計成類似格式。

簡單一實例

在詳細描述文法之前,有必要考慮一下Hello_JNI中的Android.mk

---------- cut here ------------------    LOCAL_PATH := $(call my-dir)    include $(CLEAR_VARS)    LOCAL_MODULE    := hello-jni    LOCAL_SRC_FILES := hello-jni.c    include $(BUILD_SHARED_LIBRARY)    ---------- cut here ------------------

現在,仔細分析每一行的意義

LOCAL_PATH := $(call my-dir)

一個Android.ml檔案必須以LOCAL_PATH變數的定義開頭,該變數主要用來定位源碼位置。在這個例子中,宏定義“my-dir”由編譯器提供,它返回當前檔案夾路徑(包含Android.mk的檔案夾)

include $(CLEAR_VARS)

CLEAR_VARS變數由編譯器定義,它指定了一個特殊的GNU makefile檔案,該檔案會清除除了LOCAL_PATH之外的LOCAL_XXX變數(比如,LOCAL_MODULE,LOCAL_SRC_FILES,LOCAL_STATIC_LIBRARIES等)。所有的構建控制檔案都會被解析到一個GNU構建運行上下文中,在這裡所有的變數都是全域的,因此該變數是很有價值的。

LOCAL_MODULE := hello-jni

LOCAL_MODULE變數用來定義所有需要被定義的模組名。模組名必須是唯一的而且不能包含空格。注意編譯器會在產生的模組名稱上添加首碼和尾碼。比如一個叫‘foo’的模組會產生‘libfoo.so’

注意:如果定義一個名為“libfoo”的模組,編譯器不會再次添加‘lib’首碼,同樣產生了‘libfoo.so’。

LOCAL_SRC_FILES := hello-jni.c

LOCAL_SRC_FILES變數包含了構建模組所需要的所有C/C++源碼檔案。因為編譯器自動計算了檔案以來關係,因此在這裡不需要添加標頭檔,只需要直接列出所有源檔案即可。

注意預設c++檔案的尾碼名是“.cpp”。可以使用LOCAL_CPP_EXTENSION變數來修改c++檔案所使用的尾碼,注意一定要加上“.”(正確:‘.cxx’,錯誤:‘cxx’)。

include $(BUILD_SHARED_LIBRARY)

BUILD_SHARED_LIBRARY是一個指向GNU makefile指令碼的系統變數,該變數負責收集所有定義在LOCAL_XXX中的資訊並且決定決定構建的目標和如何構建該目標。使用BUILD_STATIC__LIBRARY來產生靜態庫。

在ndk的sample目錄下你可以查看更複雜的Android.mk檔案。

引用

下面列出的一些變數在Android.mk中是完全可靠的。你可以自己定義一些變數,但是NDK編譯器保留了這些關鍵字:

  • 以“LOCAL_”開頭的(例:LOCAL_HOME)
  • 以”PRIVATE_”,”NDK”,”APP_”開頭的(內部使用)
  • 小寫變數名(內部使用,例:my-dir)

如果需要自訂變數,推薦使用“MY_“作為首碼,例如:

---------- cut here ------------------    MY_SOURCES := foo.c    ifneq ($(MY_CONFIG_BAR),)      MY_SOURCES += bar.c    endif    LOCAL_SRC_FILES += $(MY_SOURCES)---------- cut here ------------------
NDK提供的變數

這些GNU Make變數在Android.mk檔案被解析之前已經被定義了。注意在某些情況下,NDK也許會在不同的GNU Make變數的定義下解析Android.mk好幾次

CLEAR_VARS 指向清除大部分定義在”Module-description”節下LOCAL_XXX變數的構建指令碼。它必須包含在開始說明一個新模組之前,使用執行個體:
include $(CLEAR_VARS)
BUILD_SHARED_LIBRARY 指向收集所有LOCAL_XXX變數提供的資訊並且決定如何由源碼檔案構建動態庫的指令檔。注意在使用該變數之前必須定義LOCAL_MODULE和LOCAL_SRC_FILE。使用說明:
include $(BUILD_SHARED_LIBRARY)

這會產生一個明文libXXX.so的檔案。

 BUILD_STATIC_LIBRARY

BUILD_SHARED_LIBRARY是產生一個靜態庫的變種。靜態庫不會被拷貝/打包進apk包檔案中,但是我們可以使用它來產生動態庫(參照下面LOCAL_STATIC_LIBRARY和LOCAL_WHOLE_STATIC_LIBRARY的描述)。使用說明:

include $(BUILD_STATIC_LIBRARY)
PREBUILT_SHARED_LIBRARY

指向一個先行編譯動態庫的構建指令碼。和BUILD_SHARED_LIBRARY與BUILD_STATIC_LIBRARY不同,LOCAL_SRC_FILES只能是一個先行編譯動態庫的路徑而不是源檔案(例如:foo/libfoo.so)。

可以在其他模組中使用LOCAL_PREBUILTS變數來引用該先行編譯庫(詳細請參照NDK Prebuilt Library Support)

PREBUILT_STATIC_LIBRAR

和PREBUILT_SHARED_LIBRARY類似,但是指定的是靜態庫。

TARGET_ARCH

目標CPU架構的名稱,對所有的arm相容的編譯器來說目標架構名都是arm,獨立的CPU架構將會不同

TARGET_PLATFORM

目標Android平台的名稱。例如android-3對應於Android 1.5

TARGET_ARCH_ABI

目標CPU和ABI的名稱,可以指定以下的一個或多個值

armeabi        For ARMv5TE   armeabi-v7a        For ARMv7   arm64-v8a        For ARMv8 AArch64   x86        For i686   x86_64        For x86-64   mips        For mips32 (r1)   mips64        For mips64 (r6)

注意:到Android NDK 1.6_r1為止,這個變數被定義為‘arm’.然而,這個值在內部使用時會被重定義成與Android平台更加匹配的值。

TARGET_ABI

目標平台和ABI之間的聯絡,它實際上被定義成由”-“串連,這將會在測試裝有指定系統檔案的實體機上顯得很有用。
預設的數值是”android-3-armeabi“

NDK提供的函數

一下是GNU Make中的”函數”宏,必須以“$(call <function>)”的方式進行調用。返迴文本的傳回值。

my-dir

返回最後包含的Makefile路徑,通常情況下是當前Android.mk的路徑。它通常在Android.mk標頭檔用來定LOCAL_PATH:

LOCAL_PATH := $(call my-dir)

提示:基於GNU Make的工作方式,他實際上返回的最後包含的Makefile檔案路徑。不要在調用my-dir之後包含任何其他的檔案,例如,考慮下面的例子。

LOCAL_PATH := $(call my-dir)          ... declare one module          include $(LOCAL_PATH)/foo/`Android.mk`          LOCAL_PATH := $(call my-dir)          ... declare another module

由於包含檔案在第二次調用my-dir之前,my-dir已經變成了$PATH/foo,所以第二個調用my-dir時會定義LOCAL_PATH為$PATH/foo而不是$PATH。因此,最好把包含檔案的操作放在所有內容之後,例如:

LOCAL_PATH := $(call my-dir)          ... declare one module          LOCAL_PATH := $(call my-dir)          ... declare another module          # extra includes at the end of the `Android.mk`          include $(LOCAL_PATH)/foo/`Android.mk`

如果這麼使用不方便,把my-dir的路徑儲存到自訂的一個變數中,例如

MY_LOCAL_PATH := $(call my-dir)          LOCAL_PATH := $(MY_LOCAL_PATH)          ... declare one module          include $(LOCAL_PATH)/foo/`Android.mk`          LOCAL_PATH := $(MY_LOCAL_PATH)          ... declare another module
all-subdir-makefiles

返回當前‘my-dir’目錄下子目錄中所有包含“Android.mk”檔案的路徑,假設有以下幾個檔案

sources/foo/Android.mksources/foo/lib1/Android.mksources/foo/lib2/Android.mk

如果source/foo/Android.mk包含以下代碼

include $(call all-subdir-makefiles)

那麼就會自動包含sources/foo/lib1/Android.mk 和 sources/foo/lib2/Android.mk

該功能通常在有多層源碼目錄的工程中使用。注意,NDK只會尋找sources/*/Android.mk

this-makefile

返回當前Makefile的目錄(該函數被調用的makefile)

parent-makefile

返回在包含樹中該Makefile的父Makefile檔案。包含當前Makefile檔案

grand-parent-makefile

猜猜這是啥

import-module

通過名稱來包含另外一個模組的Android.mk。一個典型的例子:

$(call import-module,<name>)

它會通過尋找當前設定的NDK_MODULE_PATH環境變數來尋找模組,自動包含該模組的Android.mk檔案

 模組描述的變數

以下的變數用來在編譯系統中描述自訂的模組。可以再兩個‘include’之間包含它們。正如前面所寫,除非明確得表示它們,一個指令碼會全部清理掉它們。

LOCAL_PATH

該變數用來獲得當前路徑,必須定義在Android.mk檔案的開頭,例如:

LOCAL_PATH := $(call my-dir)

該變數不會被清理,所以只需要定義一次(也許你會在一個檔案中定義多個模組)

LOCAL_MODULE

當前模組的名稱。它的命名必須是唯一的,也不能包含空格。需要在定義在任何指令碼之前。模組名稱預設決定了組建檔案的名稱,比如lib<foo>.so是<foo>產生的動態庫檔案。但是你只需要在NDK編譯系統中的其他檔案中使用“正常”的名稱(比如<foo>),比如說Android.mk或者Application.mk

LOCAL_MODULE_FILENAME

該變數是可選的,它允許你重新命名組建檔案的名稱。塊名稱預設決定了組建檔案的名稱,比如lib<foo>.so是<foo>產生的動態庫檔案。

你可以通過定義LOCAL_MODULE_FILENAME來改變,例如:

LOCAL_MODULE := foo-version-1LOCAL_MODULE_FILENAME := libfoo

注意:不能把一個檔案的路徑或者尾碼定義到LOCAL_MODULE_FILENAME中,這些會由編譯系統自動添加。

LOCAL_SRC_FILES

列出所有編譯模組所需要的源碼。在編譯器計算出依賴關係之前,只有列出的檔案才會參與編譯。

注意:所有檔案都是在LOCAL_PATH目錄下的,可以添加子目錄中的檔案。例如:

LOCAL_SRC_FILES := foo.c                            toto/bar.c

也可以使用絕對路徑。例如:

LOCAL_SRC_FILES := /home/user/mysources/foo.c

windows平台:

LOCAL_SRC_FILES := c:/Users/user/sources/foo.c

為了讓開發環境能夠更好得移植,最好不要使用絕對路徑

注意:Unix風格通常使用斜杠(/)作為路徑分隔字元。windows風格的反斜線不一定能夠被很好得支援。

LOCAL_CPP_EXTENSION

自訂C++檔案的尾碼名。必須以”.“開頭,預設的尾碼名是”cpp“,舉例:

LOCAL_CPP_EXTENSION := .cxx

NDK r7以後,可以定義多個尾碼名:

LOCAL_CPP_EXTENSION := .cxx .cpp .cc
LOCAL_CPP_FEATURES

該可選變數可以指定特定C++特性。如果你的代碼使用RTTI特性,可以定義:

LOCAL_CPP_FEATURES := rtti

顯示代碼使用異常處理:

LOCAL_CPP_FEATURES := exceptions

可以同時定義多個特性(順序無關)

LOCAL_CPP_FEATURES := rtti features

該變數可以在編譯模組時正確得設定編譯/連結的標誌。該變數可以保證進行正確的來連結產生二進位檔案。

推薦使用該變數來替代在LOCAL_CPPFLAGS中直接定義 -frtti和-fexceptions

LOCAL_C_INCLUDES

包含檔案路徑的可選變數,該路徑會在編譯時間添加到包含目錄下,例如:

LOCAL_C_INCLUDES := sources/foo

甚至這樣也是可以的:

LOCAL_C_INCLUDES := $(LOCAL_PATH)/../foo

這些定義被放在LOCAL_CFLAGS/LOCAL_CPPFLAGS之前

LOCAL_C_INCLUDE路徑也被用在自動使用ndk-gdb調試之中。

LOCAL_CFLAGS

可選的編譯標識,也可以用來添加額外的宏定義或者編譯選項。

重要:不要修改任何Android.mk中的最佳化、調試層級,這些會在指定Andorid.mk檔案中的目標資訊時自動化處理,ndk也會在調試時自動產生調試檔案。

注意:在android-ndk-1.5_r1中,只在C原始碼中產生作用(現在可以使用LOCAL_CPPFLAG來指定編譯選項)。

可以使用LOCAL_CFLAGS+=-I<path>來指定附加元件封裝含目錄。由於ndk-gdb會使用該路徑,最好使用LOCAL_C_INCLUDES來實現該功能。

LOCAL_CXXFLAGS

LOCAL_CPPFLAG的別名,注意該變數可能在未來的NDK版本中被拋棄。

LOCAL_CPPFLAGS

在編譯C++源碼時的一個可選編譯選項的變數。該變數會出現在LOCAL_CFLAGS之後

注意:在android-ndk-1.5-r1中,該變數適用於C和C++格式的源碼。(現在也可以使用LOCAL_CFLAGS來指定所有C/C++源碼編譯選項)

LOCAL_STATIC_LIBRARIES

列出所有當前模組所以來的靜態庫。

如果當前模組時一個動態庫或者可運行檔案,這些靜態庫會被強制串連到產生的二進位檔案中。

如果當前檔案是一個靜態庫,僅僅會通知其他模組該模組會依賴這些列出的靜態庫

LOCAL_SHARED_LIBRARIES

列出該模組在運行時所依賴的動態庫。他會在連結時嵌入這些動態庫的一些資訊,因此這些資訊時很有必要的。

LOCAL_WHOLE_STATIC_LIBRARIES

LOCAL_STATIC_LIBRARIES的一個變種,用來表達對應的二進位模組應該當做”完整的檔案“來串連。

LOCAL_LDLIBS

建立動態庫或者可運行檔案時的一些其他連結選項。例如,當ld.gold為預設時,下面會在ARM/X86 GCC 4.6+下使用ld.bfd連結器連結

LOCAL_LDFLAGS += -fuse-ld=bfd

注意:該選項在編譯靜態庫時會被忽略,ndk會在你定義該變數時發出一個警告資訊

LOCAL_ALLOW_UNDEFINED_SYMBOLS

預設情況下,在動態庫中引用一個未定義的符號時,會產生一個”undefined symbol“錯誤。這會對你在源碼中找出錯誤有很大的協助。

然而,如果一些原因讓你需要禁用這個檢查,設定這個值為‘true’即可。注意產生的二進位檔案可能在運行時失敗。

注意:該選項在編譯靜態庫時會被忽略,ndk會在你定義該變數時發出一個警告資訊

LOCAL_ARM_MODE

預設情況下,ARM的目標程式的指令是‘thumb’模式的,‘thumb’模式下的指令長度是16位的,並且連結了thumb STL庫。可以使用該變數來產生’arm’指令。該指令是32位的。使用執行個體:

LOCAL_ARM_MODE := arm

注意:可以指定以’.arm’尾碼源碼產生arm格式的彙編指令,例如:

LOCAL_SRC_FILES := foo.c bar.c.arm

告訴編譯器永遠編譯bar.成arm指令格式的,而foo.c的類型由LOCAL_ARM_MODE決定。

注意:在Android.mk中設定APP_OPTIM為‘debug’後,也會產生arm格式的檔案。這是由於工具鏈中的調試工具對thumb指令不能很好得處理造成的。

LOCAL_ARM_NEON

當定義該變數時,允許C/C++/彙編代碼使用NEON技術。

只能當使用基於ARMv7指令集的”armeabi-v7a”才能定義。注意並不是所有ARMv7系列的CPU都支援NEON擴充指令集的。

此外,還可以通過添加‘.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’尾碼之後。

LOCAL_DISABLE_NO_EXECUTE

Android NDK r4添加了”NX bit“安全特性的支援。它預設時開啟的,可以通過設定該值為‘true’來關閉它。

LOCAL_DISABLE_RELRO

By default, NDK compiled code is built with read-only relocations and GOT protection. This instructs the runtime linker to mark certain regions of memory as being read-only after relocation, making certain security exploits (such as GOT overwrites) harder to perform.

It is enabled by default, but you can disable it if you really need to by setting this variable to ‘true‘.

NOTE: These protections are only effective on newer Android devices ("Jelly Bean" and beyond). The code will still run on older versions (albeit without memory protections).

參考http://blog.chinaunix.net/uid-24203478-id-3298210.html

 

LOCAL_DISABLE_FORMAT_STRING_CHECKS

By default, NDK compiled code is compiled with format string protection. This forces a compiler error if a non-constant format string is used in a printf style function.

It is enabled by default, but you can disable it if you really need to by setting this variable to ‘true‘.

LOCAL_EXPORT_CFLAGS

該變數會記錄當前模組中設定的C/C++編譯選項。當其他模組使用LOCAL_STATIC_LIBRARIES或LOCAL_SHARED_LIBRARIES引用該模組時,LOCAL_CFLAGS會自動添加上述設定的C/C++編譯選項。

include $(CLEAR_VARS)LOCAL_MODULE := fooLOCAL_SRC_FILES := foo/foo.cLOCAL_EXPORT_CFLAGS := -DFOO=1include $(BUILD_STATIC_LIBRARY)

其他模組定義

include $(CLEAR_VARS)LOCAL_MODULE := barLOCAL_SRC_FILES := bar.cLOCAL_CFLAGS := -DBAR=2LOCAL_STATIC_LIBRARIES := fooinclude $(BUILD_SHARED_LIBRARY)

這樣,下面模組的編譯標識會被設定成‘-DFOO=1 -DBAR=2

匯出標識在內部表現為LOCAL_CFLAGS,因此可以很方便得使用。這種特性是可以傳遞的:比如‘zoo’依賴於‘bar’,而‘bar’依賴於‘foo’,那麼‘zoo’也會繼承‘foo’的匯出符號。

LOCAL_EXPORT_CPPFLAGS

和LOCAL_EXPORT_CFLAGS類似,但是僅僅包含C++標識。

LOCAL_EXPORT_C_INCLUDES

和LOCAL_EXPORT_CFLAGS類似,但是只用來包含C標頭檔路徑。當’bar.c’需要包含‘foo’所提供的標頭檔時使用

LOCAL_EXPORT_LDFLAGS

和LOCAL_EXPORT_CFLAGS類似,但是用來處理連結符號。

LOCAL_EXPORT_LDLIBS

和LOCAL_EXPORT_CFLAGS類似,通常會設定一個以‘-l’為首碼的指定系統庫。由於Unix編譯器的工作方式,匯入的連結標識會添加到模組的LOCAL_LDLIBS中。

當‘foo’需要編譯成靜態庫而它有一些代碼會依賴系統庫時,可以使用LOCAL_EXPORT_LDLIBS來匯出依賴關係。例如:

include $(CLEAR_VARS)LOCAL_MODULE := fooLOCAL_SRC_FILES := foo/foo.cLOCAL_EXPORT_LDLIBS := -lloginclude $(BUILD_STATIC_LIBRARY)include $(CLEAR_VARS)LOCAL_MODULE := barLOCAL_SRC_FILES := bar.cLOCAL_STATIC_LIBRARIES := fooinclude $(BUILD_SHARED_LIBRARY)

因為依賴於‘foo’,libbar.so編譯時間會在連結命令的末尾添加-llog選項用來顯示它會依賴系統的日誌庫

LOCAL_SHORT_COMMANDS

當模組中由很多源檔案產生或者依賴靜態或者動態庫時設定該標識為’true’,他會強制編譯系統使用內部的列表檔案,並且使用一個二進位壓縮檔或者靜態連結到@文法。

這在windows系統中非常有用,命令列最多接收8191個位元組,對一個複雜的工程來說這是遠遠不夠的。

這會影響每一個單獨的檔案,幾乎在每一個內部列出的檔案加上所有的編譯標識。

LOCAL_THIN_ARCHIVE

在編譯靜態庫的時候設定為‘true’。他會產生一個簡單的歸檔檔案。例如一個庫檔案(libfoo.a)不包含任何對象檔案,只包含了它應該包含對象的檔案路徑。

他通常被用來減少編譯輸出的體積。它的缺點是這些包含的庫檔案不能被移動到其他路徑下去(所有的路徑都被內部依賴)。

有效值是‘true’,‘false’或者為空白。可以通過APP_THIN_ARCHIVE來設定預設值。

注意:該命令在非靜態庫或者先行編譯靜態庫中會被忽略。

LOCAL_FILTER_ASM

在命令列中定義該變數用來過濾來自LOCAL_SRC_FILES中定義的或者產生的彙編檔案。

當它被定義後,將會發生以下的事情:

  • 一些C或者C++源檔案被產生到一個臨時的彙編檔案中(而不是編譯成一個object檔案)
  • 一些臨時彙編檔案,和在LOCAL_SRC_FILES中列出的彙編檔案被發送到LOCAL_FILTER_ASM命令中去用以產生另外的彙編檔案
  • 被過濾的彙編檔案產生對象檔案

換句話說,如果你定義:

LOCAL_SRC_FILES  := foo.c bar.S          LOCAL_FILTER_ASM := myasmfilter        foo.c --1--> $OBJS_DIR/foo.S.original --2--> $OBJS_DIR/foo.S--3--> $OBJS_DIR/foo.o        bar.S                                 --2--> $OBJS_DIR/bar.S--3--> $OBJS_DIR/bar.o

”1“對應編譯器,”2“對應過濾器,”3“對應彙編器。過濾器是第一個輸入的檔案當做它第一個參數的命令,而輸出檔案的名稱是它的第二個參數。

myasmfilter $OBJS_DIR/foo.S.original$OBJS_DIR/foo.S          myasmfilter bar.S $OBJS_DIR/bar.S

NDK設定檔Android.mk簡介

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.