承接上篇Android遊戲開發實踐(1)之NDK與JNI開發01分享完JNI的基礎和簡要開發流程以後,再來分享下在Android環境下的JNI的開發,以及涉及到的NDK相關的操做。固然,本篇還是以Eclipse做爲開發IDE,雖然Google官方已經再也不支持Eclipse了,推薦是用AndroidStudio進行開發。但對於遊戲開發來講,IDE的影響並無那麼大,且從Eclipse那個時代過來的,對Eclipse仍是感情很深的。後續,還有專門一篇來分享下AndroidStudio的使用以及使用CMake編譯等,會提到JNI這方面的內容。php
做者:AlphaGL。版權全部,歡迎保留原文連接進行轉載 :)html
按照慣例,每一篇文章都喜歡附上官方的文檔。由於,只有官方的文檔纔是最準確,最實時,且內容最豐富的。那麼,NDK官方開發地址爲:android
Getting Started with the NDK:
https://developer.android.com/ndk/guides/index.htmlc++
本文目錄以下:shell
(1)安裝CDT
CDT全成是C/C++ DevelopmentTools,安裝該插件使得Eclipse也得支持C/C++的開發。須下載和Eclipse版本對應的CDT插件。是喜歡Eclipse的便捷,同時又開發C/C++的必裝插件。CDT的下載地址爲:
http://www.eclipse.org/cdt/downloads.php
安裝成功後,在Eclipse的Window-Preferences中看到多了一項C/C++的支持:
api
(2)NDK的下載
目前,NDK的最新版本爲android-ndk-r13b
,下載地址爲:
https://developer.android.com/ndk/downloads/index.html
這裏須要說明下,爲了方便演示筆者所使用的NDK版本爲android-ndk-r8b
。最新版本已經再也不支持GCC編譯,默認改用Clang。還修復了相關的bug,建議線上的產品更新最新的穩定版。安全
(3)NDK的集成
將下載好的NDK解壓,並將該路徑添加到Path環境變量中,而後集成至Eclipse中。如圖:
bash
NDK編譯的環境有不少,但基本都是經過ndk-build
工具來完成的。有直接經過Eclipse安裝CDT便可完編譯,也能夠經過安裝Cygwin來編譯。事實上,在android-ndk-r7
以後的版本,已經不須要安裝Cygwin就能夠編譯出.so
了。但這裏仍是想介紹下,由於筆者開發曾用Cygwin編譯過一段時間,並且多瞭解一種編譯途徑也沒什麼壞處。固然,熟悉Linux平臺或者Mac平臺開發的朋友會感受更親切些。網絡
Cygwin是一套在Window上模擬類Unix系統環境的工具。而Android底層又是基於Linux的。所以,對Linux環境下的開發支持也更好。只要在Cygwin中安裝gcc
、g++
、gdb
、make
等GUN
工具集便可。
(1)Cygwin的安裝
Cygwin的下載地址爲:
https://cygwin.com/install.html架構
(2)Cygwin的安裝步驟:
下載完setup-x86_64.exe
,直接下一步:
這裏有三個選項,分別是從網絡安裝,只下載不安裝,從本地目錄安裝(若是,以前安裝過)。可根據本身的實際狀況選擇。這裏選擇從網絡安裝。而後,下一步
這裏選擇第一項,Direct Connection。而後,下一步
這裏下載地址選擇mirrors.kernel.org
便可。也可選擇國內163的鏡像地址。
這裏選擇要安裝的包(autoconf
、automake
、make
、gcc
、g++
、gdb
、pcre
、gawk
等)。這裏偷懶就直接把Admin
、Debug
、Devel
、Doc
、Editors
、Shells
,固然還有Python
。而後,下一步
接着通過漫長的等待,大概下載3,4G的文件。
安裝完,運行Cygwin,輸入以下命令
(3)在Cygwin下配置NDK環境變量
在當前當前用戶目錄下運行,(例如,個人目錄爲D:\env\cygwin\home\John):
配置NDK環境變量,注意別覆蓋原來的PATH環境變量。
(4)驗證NDK配置
嘗試在Cygwin下用ndk-build
來編譯NDK下的hello-jni的samples。如圖:
能夠看到正確編譯出libhello-jni.so
庫(在項目目錄下的libs
,不一樣cup架構命名的文件夾裏)。如遇到各類權限錯誤,請將samples下的hello-jni項目的權限修改成可寫入、可修改等。
(1)將hello-jni
的項目導入到Eclipse中。
(2)給hello-jni
添加builder,來編譯C/C++代碼。
右鍵HelloJni項目,選擇Properties
,而後,選擇Builders
,點擊New
新建一個Builder
。選擇Program
,點擊OK
便可。
分別填寫Builder名稱。找到Cygwin的Shell程序和工做目錄。將要編譯的項目目錄和執行的命令當成參數參數Shell命令執行。
注意:
cd
與/cygdrive/d/android-ndk-r8b/samples/hello-jni
中間有個空格。
ANDROID_NDK_ROOT:是在Cygwin中配置NDK環境變量的名稱。
經過Cygwin中輸入bash --login -h
能夠獲取更詳細的信息:
Your group is currently "mkpasswd". This indicates that your gid is not in /etc/group and your uid is not in /etc/passwd. The /etc/passwd (and possibly /etc/group) files should be rebuilt. See the man pages for mkpasswd and mkgroup then, for example, run mkpasswd -l [-d] >> /etc/passwd mkgroup -l [-d] >> /etc/group
若是遇到這種,按照提示在Cygwin終端執行,mkpasswd -l [-d] >> /etc/passwd
與mkgroup -l [-d] >> /etc/group
命令便可。
(3)將配置JNI_Builder
優先級設爲最高
(4)編譯HelloJni
工程。
選中HelloJni
工程,在Eclipse中選擇Project-clean
。這樣,Eclipse即可自動編譯HelloJni
工程了。
這裏就不花篇幅介紹這相關的內容,下一篇專門介紹下AndroidStudio的使用及在AndroidStudio下NDK的開發。但願能給從其它IDE遷移到IntelliJ IDEA系開發或許剛接觸AndroidStudio一些啓發。因此,這裏先留個伏筆。
雖然,已經成功的將samples
下的hell-jni
項目成功編譯出了.so
動態庫。在整個交叉編譯過程當中,涉及到了三個比較重要的文件,分別是ndk-build
、Android.mk
和Application.mk
,因此,有必要了解一下,這三個文件在整個交叉編譯過程當中起了什麼做用。
首先,ndk-build
是一個shell
腳本,目標是幫助你正確的調用NDK的構建腳本。ndk-build
在<ndk-root-path>
(NDK安裝目錄根路徑下)有個ndk-build
的shell腳本文件,或ndk-build.cmd
的文件。
ndk-build
的官方指南爲:
cd $PROJECT_PATH $ <ndk>/ndk-build
用法:在項目的根目錄下,執行ndk-build
腳本命令。
例如:
進到hello-jni
的項目根目錄執行ndk-build
,ANDROID_NDK_ROOT
是在Cygwin中配置NDK環境變量的名稱。
$ <ndk>/ndk-build -C <PROJECT_PATH>
用法:在任意目錄下執行ndk-build
,用-C
來指定要編譯的項目的目錄。
例如:
實際上:執行ndk-build
至關於執行了如下命令:
$GNUMAKE -f <ndk>/build/core/build-local.mk <parameters>
例如:
$ ndk-build clean 清除編譯生成的二進制文件。 $ ndk-build -C <project> 指定項目路徑 $ ndk-build NDK_DEBUG=0 NDK_DEBUG爲0是編譯爲release版,爲debug版。
更多的ndk-build
的參數介紹,請參考上面貼出的ndk-build
的官方指南。
Android.mk
是用來向編譯系統指定項目中C/C++源代碼文件編譯、連接規則的一種描述文件。它是GUN makefile
文件的一小部分。那麼,簡單來講,就是用來起指定編譯引用的頭文件目錄、編譯出的so的名字、須要編譯的源文件或庫等做用。熟悉makefile
語法的,確定熟悉這種用法。Android.mk
文件在$project-path/jni/Android.mk
路徑下。
Android.mk
官方說明文檔地址爲:
https://developer.android.com/ndk/guides/android_mk.html
首先,仍以hello-jni
爲例,看看都定義了哪些內容。打開<ndk-path>/samples/hello-jni/jni/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
,它用來在開發的樹文件夾中定位文件的。my-dir
是由編譯系統提供的宏,用來返回當前目錄的路徑。(注意:這個路徑是包含了Android.mk
的路徑)
include $(CLEAR_VARS)
:
CLEAR_VARS
變量也是由編譯系統提供的,include $(CLEAR_VARS)
是引用一個特殊的GUN makefile
文件,這個makefile
文件所作的就是清除定義了不少LOCAL_XXX
(例如: LOCAL_MODULE
,LOCAL_SRC_FILES
,LOCAL_STATIC_LIBRARIES
等)這種格式的變量,但這裏不會清除LOCAL_PATH
變量。這麼作是頗有必要的,由於編譯系統解析這些編譯控制文件都是在單一的GUN make
上下文環境中,解析出來的LOCAL_XXX
變量都是全局的。
LOCAL_MODULE := hello-jni
:
LOCAL_MODULE
必須是惟一的,且不能包含空格。編譯系統會根據這個名字生成相應的共享庫,並自動添加前綴和後綴。本例中,最終生成的共享庫的名稱爲libhello-jni.so
。
注意:編譯生成的共享庫都是
lib
開頭的,若是,你聲明的名稱已經包含lib
(libhello-jni
),那麼,最終生成的共享庫名稱就不添加lib
前綴了,生成的仍爲libhello-jni.so
。
LOCAL_SRC_FILES := hello-jni.c
:
LOCAL_SRC_FILES
用來指明要編進共享庫(.so
)的C/C++源文件的列表。
注意:這裏只須要指定要編譯的
.c
或者.cpp
等源文件便可,不須要指定.h
頭文件。
include $(BUILD_SHARED_LIBRARY)
:
BUILD_SHARED_LIBRARY
變量是由系統提供,include $(BUILD_SHARED_LIBRARY)
會引用一個Gun makefile
腳本,用來收集你定義的LOCAL_XXX
格式的變量。同時,決定哪些要編譯,如何編譯等。
注意:顯然
BUILD_SHARED_LIBRARY
是用來編譯出共享庫.so
文件的,同理,也可使用BUILD_STATIC_LIBRARY
來編譯出靜態庫.a
文件。
以上即是編寫一個簡單的Android.mk
文件的全部元素。經過上面的描述發現,若是咱們要編寫一個本身的Android.mk
文件,沒有特殊需求的話,能夠直接將hello-jni
工程中的Android.mk
文件拷貝,而後,修改庫的名稱(LOCAL_MODULE
)和要編譯的源文件列表(LOCAL_SRC_FILES
)變量便可。
這裏來詳細瞭解下Android.mk
其餘的一些變量及語法規則。
(1)NDK變量與宏
在Android.mk
中還有一些其餘變量,是做爲NDK編譯系統的保留變量,你只能依賴它或者定義它。這些變量的規則以下:
LOCAL_
開頭的變量名稱(如:LOCAL_MODULE
,LOCAL_PATH
等)PRIVATE_
,NDK_
,APP
開頭的變量名稱(編譯系統內部使用)my-dir
,一樣,也是做爲內部使用)若是你須要在Android.mk中定義本身的變量,推薦用MY_
做爲前綴。
(2)NDK定義的變量
CLEAR_VARS:
上面已經介紹過了,這裏就不在贅述。記住一點,在定義LOCAL_XXX
前,必須引用這個腳本。用法:
include $(CLEAR_VARS)
BUILD_SHARED_LIBRARY:
該變量指向了一個腳本,這個腳本會收集你在每一個模塊定義的LOCAL_XXX
變量信息,而且這個變量還肯定了怎樣使用你的源碼去編譯一個共享庫。注意,使用這個變量須要你至少已經定義了LOCAL_MODULE和LOCAL_SRC_FILES。該變量會使編譯系統生成一個以.so
結尾的庫。用法:
include $(BUILD_SHARED_LIBRARY)
BUILD_STATIC_LIBRARY:
該變量是BUILD_SHARED_LIBRARY的一個變體,是用來生成一個靜態庫。構建系統並不會把靜態庫包含進你的工程裏面,可是能夠利用靜態庫生成共享庫。該變量會使編譯系統生成一個以.a
結尾的庫。
include $(BUILD_STATIC_LIBRARY)
PREBUILT_SHARED_LIBRARY:
指向一個腳本,這個腳本被用來指定一個預構建的共享庫。與BUILD_SHARED_LIBRARY和BUILD_STATIC_LIBRARY不一樣,LOCAL_SRC_FILES的值不能是一個源文件,它必須是一個單獨的指向預構建的共享庫的路徑,例如:foo/libfoo.so。用法:
PREBUILT_STATIC_LIBRARY:
該變量與PREBUILT_SHARED_LIBRARY相同,只是指向的一個預構建的靜態庫。
TARGET_ARCH:
這個變量是目標CPU架構的名字,就像Android Open Source Project裏面指定了目標CPU架構。這個變量用於任意的ARM兼容的構建,或者ARM,或者是獨立於CPU結構的修訂,或者ABI。
TARGET_PLATFORM:
編譯到目標平臺的api等級。例如,Android5.1對應的是Android api22。用法:
TARGET_PLATFORM := android-22
TARGET_ARCH_ABI:
當編譯系統解析Android.mk文件的時候,這個變量存儲CPU和架構的名字。你能夠指定一個或者多個下面列出的名字,使用空格分隔兩個名字
用法:
TARGET_ARCH_ABI := arm64-v8a
注意:android-ndk-1.6_r1以前這個這個變量被定義爲arm。
TARGET_ABI:
該變量將API的級別和ABI聯繫在一塊兒,當你在真機上調試系統的時候特別有用。用法:
TARGET_ABI := android-22-arm64-v8a
LOCAL_MODULE_FILENAME:
這是一個可選變量。容許你從新指定一個變量的名稱來覆蓋默認生成的名稱。例如:強制生成libnewfoo.so
LOCAL_MODULE := foo LOCAL_MODULE_FILENAME := libnewfoo
LOCAL_MODULE_FILENAME不須要指定文件路徑或擴展名
LOCAL_SRC_FILES:
該變量用來指定要編譯的源文件列表。這裏推薦使用相對路徑。用法:
LOCAL_SRC_FILES := foo1.c \ ../Module2/foo2.c
注意:使用Unix風格的/,多個文件使用\換行,注意\後面沒有空格。
LOCAL_CPP_EXTENSION:
一樣,LOCAL_CPP_EXTENSION也是一個可選變量。用來指定C++源文件的擴展名。默認是.cpp
。從NDK r7版本後,能夠指定一系列的擴展名。用法:
LOCAL_CPP_EXTENSION := .cxx .cpp .cc
LOCAL_CPP_FEATURES:
一樣,LOCAL_CPP_FEATURES也是一個可選變量。若是,你用到了C++的一些特殊功能(例如:RTTI,異常支持等),而且正確的編譯和連接,可使用該變量來聲明。用法:
LOCAL_CPP_FEATURES := rtti exceptions
建議使用該變量來代替LOCAL_CPPFLAGS中直接定義
-frtti
、-fexceptions
這種用法
LOCAL_C_INCLUDES:
可選變量,能夠經過該變量來指定一個相對於NDK根目錄的路徑列表,並在編譯C/C++時添加到搜索路徑中。用法:
LOCAL_C_INCLUDES := $(LOCAL_PATH)//foo
注意:該聲明要放在LOCAL_CFLAGS和LOCAL_CPPFLAGS的聲明前面。
LOCAL_CFLAGS:
可選變量,在編譯C/C++源代碼時,能給編譯器傳遞一個編譯標誌集合。用來指定附加宏的定義和編譯選項是頗有用的。
LOCAL_CPPFLAGS:
可選變量,在編譯C++源代碼時(只編譯C++),能給編譯器傳遞一個編譯標誌集合。
LOCAL_STATIC_LIBRARIES:
該變量定義了本模塊編譯連接過程當中用到的靜態庫列表。
LOCAL_SHARED_LIBRARIES:
該變量定義了本模塊編譯連接過程當中用到的共享庫列表。
LOCAL_WHOLE_STATIC_LIBRARIES:
該變量跟LOCAL_STATIC_LIBRARIES相似,不一樣的是在編譯連接過程當中會載入靜態庫的全部源代碼目標文件。這在解決幾個庫之間循環引用時,很是有用。能夠經過GUN的--whole-archive
標誌來查看相關說明。
LOCAL_LDLIBS:
該變量用來定義本模塊編譯時用到的附加的連接器選項。用-l
前綴指定。例如:要連接/system/lib/libz.so
LOCAL_LDLIBS := -lz
注意:若是,你編譯一個靜態庫是定義了該變量,編譯系統會忽略它,而且
ndk-build
會打印一個警告。
LOCAL_LDFLAGS:
該變量定義了在編譯給編譯系統傳遞一些其餘的連接標誌。用法:
LOCAL_LDFLAGS += -fuse-ld=bfd
注意:若是,你編譯一個靜態庫是定義了該變量,編譯系統會忽略它,而且
ndk-build
會打印一個警告。
LOCAL_ALLOW_UNDEFINED_SYMBOLS:
默認狀況下,在編譯一個共享庫的時候,任何未定義的引用,將會拋出"符號未定義(undefined symbol)"的錯誤。該變量能幫助你捕捉代碼中的bug。若是,要禁用這項檢查能夠把該變量設置爲true
。這麼設置
注意:若是,你編譯一個靜態庫是定義了該變量,編譯系統會忽略它,而且
ndk-build
會打印一個警告。
LOCAL_ARM_MODE:
默認狀況下,編譯系統會在ARM平臺"thumb"模式下生成16位的二進制文件。定義該變量則強制生成32位"arm"模式下的對象文件。例如:
LOCAL_ARM_MODE := arm
你也能夠加上.arm
後綴來告訴編譯系統,只想對某個源文件使用arm指令。例如:
LOCAL_SRC_FILES := foo.c bar.c.arm
LOCAL_ARM_NEON:
只有當目標平臺爲armeabi-v7a
指令集時,才定義它。它容許你的C/C++代碼中使用ARM高級指令。也能夠在彙編文件中使用NEON
指令。你可使用.neon
後綴來指定編譯器支持NEON指令編譯。例如:
LOCAL_SRC_FILES = foo.c.neon bar.c zoo.c.arm.neon
注意:不是全部的ARMv7架構的CPU都支持NEON擴展。
LOCAL_DISABLE_NO_EXECUTE:
Android NDK r4版本開始支持這種"NX bit"的安全功能。默認是啓用的,你也能夠設置該變量的值爲true來禁用它。但不推薦這麼作。該功能不會修改ABI,只在ARMv6+CPU的設備內核上啓用。
LOCAL_DISABLE_RELRO:
默認狀況下,NDK編譯代碼是隻讀重定位和GOT保護的。這個會指示運行時連接器標記特定的內存區是隻讀的,在移動位置以後。這樣會使得某些安全漏洞(如GOT覆蓋)更難執行。默認是啓用的,你也能夠把該變量的值設爲true來禁用。但不推薦這麼作。
LOCAL_DISABLE_FORMAT_STRING_CHECKS:
默認狀況下,編譯系統編譯代碼時會檢查格式化字符串,若是printf樣式的函數使用了很是嚴格的字符串,那麼編譯出錯。默認是開啓的,你也能夠經過設置該變量的值爲true來禁用。但不推薦這麼作。
LOCAL_EXPORT_CFLAGS:
該變量是用來記錄C/C++編譯器標誌集合,這些編譯器標誌會被添加到經過變量LOCAL_STATIC_LIBRARIES或LOCAL_SHARED_LIBRARIES使用本模塊的其餘模塊的LOCAL_CFLAGS變量中。例如:
include $(CLEAR_VARS) LOCAL_MODULE := foo LOCAL_SRC_FILES := foo/foo.c LOCAL_EXPORT_CFLAGS := -DFOO=1 include $(BUILD_STATIC_LIBRARY) include $(CLEAR_VARS) LOCAL_MODULE := bar LOCAL_SRC_FILES := bar.c LOCAL_CFLAGS := -DBAR=2 LOCAL_STATIC_LIBRARIES := foo include $(BUILD_SHARED_LIBRARY)
編譯bar
模塊時,"-DFOO=1 -DBAR=2"標誌將一塊兒傳遞給編譯器。
LOCAL_EXPORT_CPPFLAGS:
該變量與LOCAL_EXPORT_CFLAGS相似,但只適用於C++。
LOCAL_EXPORT_C_INCLUDES:
該變量與LOCAL_EXPORT_CFLAGS相似,可是該變量用來包含路徑的。例如,上例中bar.c
須要包含foo
模塊的頭文件。
LOCAL_EXPORT_LDFLAGS:
該變量與LOCAL_EXPORT_CFLAGS相似,可是它用做連接器標誌。
LOCAL_EXPORT_LDLIBS:
該變量與LOCAL_EXPORT_CFLAGS同樣,該變量的值將會被添加到其它模塊引用到本模塊的其它模塊的LOCAL_LDLIBS變量中。例如:
include $(CLEAR_VARS) LOCAL_MODULE := foo LOCAL_SRC_FILES := foo/foo.c LOCAL_EXPORT_LDLIBS := -llog include $(BUILD_STATIC_LIBRARY) include $(CLEAR_VARS) LOCAL_MODULE := bar LOCAL_SRC_FILES := bar.c LOCAL_STATIC_LIBRARIES := foo include $(BUILD_SHARED_LIBRARY)
編譯bar
的時候,會在連接log的系統日誌庫。
LOCAL_SHORT_COMMANDS:
當你的模塊有不少源代碼文件或依賴不少靜態庫或者共享庫時,設置爲true。這樣會強制編譯系統使用@語法來包含中間對象或連接庫來生成歸檔文件。
注意:這個功能在Windows上頗有用,由於Windows上的命令行支持的最大字符數爲8191個,這對於複雜的項目來講過小。默認是不推薦啓用這個功能,由於它會使編譯變得很慢。
LOCAL_THIN_ARCHIVE:
編譯靜態庫是,若是該變量值設爲true,會生成一個較小的歸檔文件。並不包含目標文件,而是用目標文件的路徑替代。有效值是true
,false
和空。
注意:若是該模塊不是編譯爲靜態塊,或者預編譯靜態庫,該值將被忽略。
LOCAL_FILTER_ASM:
該變量的值將做爲一個Shell命令,它會過濾從LOCAL_SRC_FILES生成的文件或彙編文件。定義該變量將會發生下面的狀況:
NDK提供的函數宏
NDK提供了GNU Make的函數宏。使用$(call <function>)
的方式調用,它們會返回相應的文本信息。
my-dir:
該宏返回的是最後包含的makefile文件路徑,通常是當前Android.mk的路徑。my-dir
對於Android.mk開頭定義的LOCAL_PATH變量頗有用。例如:
LOCAL_PATH := $(call my-dir)
因爲GNU Make的工做方式,這個宏返回的是構建系統在解析構建腳本時包含的最後一個makefile的路徑。所以,你不該該在include其餘的文件以後再繼續使用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
的調用將LOCAL_PATH的值設置爲了$PATH/foo
,由於$PATH/foo
纔是最近包含的路徑。你能夠經過在Android.mk文件中放置額外的包含來避免這個問題。例如:
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 file 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文件的列表。你可使用此函數向構建系統提供深層嵌套的源目錄層次結構。默認狀況下,NDK僅查找包含Android.mk文件的目錄中的文件。
this-makefile:
該宏返回的是當前makefile文件的路徑(從構建系統調用這個函數中)。
parent-makefile:
該宏返回當前目錄樹中的父makefile的路徑(包含當前makefile的makefile路徑)。
grand-parent-makefile:
該宏返回包含樹中的祖父類makefile的路徑(包含當前makefile的makefile的路徑)。
import-module:
該宏容許你經過模塊的名稱找到幷包含模塊的Android.mk文件。例如:
$(call import-module,<name>)
在這個示例中,構建系統會根據NDK_MODULE_PATH這個環境變量所指示的目錄裏面尋找名爲<name>
的模塊,而後自動爲你include對應的Android.mk文件。
經過上面的介紹,大致瞭解了Android.mk文件的用法及規則。但一般編譯本地C/C++代碼光有Android.mk還不夠,還得須要Application.mk文件。Application.mk也是一種makefile文件,跟Android.mk有類似之處。若是說,Android.mk用來描述單獨某個模塊的編譯規則的描述文件,那麼Application.mk則是描述整個應用程序的模塊的描述文件。Application.mk文件通常在$project-path/jni/Application.mk
下($project-path是項目根目錄)。固然,也能夠放在$NDK/apps/<myapp>/Application.mk
路徑下。這兩種方式,形成Application.mk
也有細微的區別。
(1)變量
APP_PROJECT_PATH:
該變量用來指定項目根目錄的絕對路徑。
注意:假如
Application.mk
文件的路徑是$NDK/apps/<myapp>/Application.mk
,那麼該變量爲強制定義的。若是,Application.mk
文件在$project-path/jni/Application.mk
路徑下,則是可選變量。
APP_OPTIM:
該變量爲可選變量,值爲release
或debug
。編譯應用程序模塊的時,能夠用來改變優化級別。默認是release
模式,而且會生成高度優化的二進制文件。debug
模式生成的是未優化的二進制代碼,但更容易調試。
APP_CFLAGS:
在編譯任何模塊的任何C/C++代碼時,構建系統會經過該變量給編譯器傳遞一個C編譯標誌集合。你可使用該變量根據應用程序中給定的模塊的須要來改變其構建,而不須要修改Android.mk文件自己了。
這些標誌的全部路徑必須相對於NDK的頂級目錄。例如:若是你有如下設置:
sources/foo/Android.mk sources/bar/Android.mk
在編譯期間,你須要在foo/Android.mk中指定你要添加的foo的源路徑,你應該使用:
APP_CFLAGS += -Isources/bar
或者:
APP_CFLAGS += -I$(LOCAL_PATH)/../bar
使用-I../bar
將不能正常工做,由於它等價於-I$NDK_ROOT/../bar
。
注意:在android-ndk-1.5_r1版本中,該變量只適用於C,不能做用於C++。以後的全部的版本,該變量可適用C/C++源碼上。
APP_CPPFLAGS:
該變量包含一組C++編譯器標誌,構建系統僅在構建C++源代碼時傳遞給編譯器。
APP_LDFLAGS:
在連接的時候,構建系統系統會想連接器傳遞一組連接標誌。該變量僅在構建系統構建共享庫和可執行文件的時候才生效,當構建靜態庫時,將被忽略。
APP_BUILD_SCRIPT:
默認狀況下,NDK構建系統會在$project-path/jni/
目錄下查找Android.mk文件。若是你想修改此行爲,你能夠定義APP_BUILD_SCRIPT
變量,並指向備用的構建腳本。編譯系統老是將一個非絕對路徑解釋爲NDK的頂級目錄。
APP_ABI:
默認狀況下,編譯系統會根據armeabi ABI
生成機器碼。該機器碼基於ARMv5TE而且支持浮點運算的CPU。你可使用APP_ABI參數來指定不一樣的ABI。不一樣的指令集的APP_ABI設置以下:
注意:all是android-ndk-r7版本開始支持的。
你也能夠指定多個值,將它們放在同一行,中間用空格隔開。例如:
APP_ABI := armeabi armeabi-v7a x86 mips
APP_PLATFORM:
此變量包含目標Android的名稱。例如:android-3對應的是Android1.5的系統鏡像。
APP_STL:
默認狀況下,NDK構建系統只爲最小的C++運行庫(/system/lib/libstdc++.so)提供C++頭文件。此外,你還能夠在本身的應用程序中使用或連接其餘C++實現。可使用APP_STL
來選擇其中的一個。例如:
APP_STL := stlport_static APP_STL := stlport_shared APP_STL := system
APP_SHORT_COMMANDS:
該變量至關於整個項目的Android.mk中定義了LOCAL_SHORT_COMMANDS。
NDK_TOOLCHAIN_VERSION:
將此變量定義爲4.9版本的GCC編譯器。在android-ndk-r13默認是Clang編譯器。
APP_PIE:
從Android 4.1(API級別16)開始,Android的動態連接器支持位置無關可執行文件(PIE)。從Android 5.0(API級別21),可執行文件須要PIE。要使用PIE構建可執行文件,需設置-fPIE
標誌。這個標誌會使得經過隨機代碼的位置來查找內存損壞的bug更加困難。默認狀況下,若是您的項目目標爲Android-16或更高版本,ndk-build會自動將此值設置爲true。您能夠將其手動設置爲true或false。
注意:此標誌僅適用於可執行文件。它在構建共享或靜態庫時沒有任何做用。
APP_THIN_ARCHIVE:
至關於在Android.mk文件中爲此項目中的全部靜態庫模塊設置LOCAL_THIN_ARCHIVE的默認值。
以上內容可能不必定徹底正確,大部份內容是根據Android官方文檔,經過本身的理解轉述的。並無每一個變量在.mk
文件中有實踐過。因此,若是遇到你以爲有問題的地方,歡迎與我交流。
技術交流QQ羣:528655025
做者:AlphaGL
出處:http://www.cnblogs.com/alphagl/ 版權全部,歡迎保留原文連接進行轉載 :)