Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android NDK編譯選項設置

Android NDK編譯選項設置

編輯:關於Android編程

在Android NDK開發中,有兩個重要的文件:Android.mk和Application.mk,各盡其責,指導編譯器如何編譯程序,並決定編譯結果是什麼。本文將詳細說明幾個常見的NDK選項的配置,幫助大家理解相應的配置選項。


\


一、Application.mk


Application.mk實際上是輕量級Makefile,通常在$PROJECT/jni目錄下,用於配置所有modules的編譯變量,例子如下:

APP_ABI:=armeabiarm64-v8ax86_64x86armeabi-v7a
NDK_TOOLCHAIN_VERSION:=clang3.5
APP_STL:=stlport_static
APP_OPTIM:= debuge


1、APP_ABI(目標平台ABI類型)

NDK編譯中,APP_ABI默認選擇armeabi ABI,可通過設置APP_ABI設置一個或者多個ABI,表一為不同的APP_ABI所對應的指令集。 Instrunction set Value ARMv5TE based CPU APP_ABI := armeabi ARMv7 based CPU APP_ABI := armeabi-v7a ARMv8 AArch64 APP_ABI := arm64-v8a IA-32 APP_ABI := x86 Intel64 APP_ABI := x86_64 MIPS32 APP_ABI := mips MIPS64(r6) APP_ABI := mips64 All supported instruction sets APP_ABI := all 表一:ABI類型

在開發時可根據需求選擇APP_ABI,對於ABI的選擇需要考慮到效率和APK大小。由於armeabi-v7a指令集兼容armeabi;市面上的x86手機為了兼容性,基本都使用libhoudini模塊,兼容arm指令集;64位機型默認支持32位abi的so,因此在對大小要求比較高的情況下,可以只選擇市面上設備基本兼容的armeabi ABI,如果對性能有些許要求,可以再添加x86 ABI。

2、 NDK_TOOLCHAIN_VERSION(編譯器類型、版本)

默認采用的是GCC編譯器,對於GCC版本的選擇與NDK版本有關系,本人使用的是NDK R12,在64位ABI默認是GCC 4.9,32位ABI默認是GCC 4.8,當然也可以像上面例子中給出的設置一樣,設置clang編譯器。

3、 APP_STL(運行庫類型)

Android NDK 默認使用的是最小支持的C++運行庫,如果你需要你的NDK程序中使用STL,則可以設置APP_STL:=stlport_static,APP_STL有表二中的幾種取值。 Name Explanation system(default) 系統默認的C++運行庫 stlport_static 以靜態鏈接方式使用的sttport版本的STL stlport_shared 以動態鏈接方式使用的sttport版本的STL gnustl_static 以靜態鏈接方式使用的gnustl版本的STL gnustl_shared 以動態鏈接方式使用的gnustl版本的STL gabi++_static 以靜態鏈接方式使用的gabi++ gabi++_shared 以動態鏈接方式使用的gabi++ c++_static 以靜態鏈接方式使用的LLVM libc++ c++_shared 以動態鏈接方式使用的LLVM libc++ 表二:NDK運行庫

若APK中有多個SO文件用到STL,建議都使用動態方式鏈接STL,這樣可以減小整個APK文件大小。
另外需要注意的是官方提供的NDK運行庫除了默認的以外都支持RTTI和異常,然而默認是禁用的,將在下面的Android.mk中說明如何開啟。

4、APP_OPTIM(編譯模式)

“release”模式為默認的,生成的是優化後的二進制;也可以設置為“debug”模式,“debug”模式生成的是未優化二進制,提供很多BUG信息,便於調試和分析。
還有其他配置選項,有興趣可以查看Application.mk官方文檔。

二、Android.mk


Android.mk也是一個輕量級的Makefile,其將C/C++源碼組織到一個個module中,module可以是靜態庫、共享庫或者獨立的可執行文件, 一個Android.mk文件可以有一個,也可以是多個module,modules之間也可以有依賴關系。

1、基本概念

Android.mk中包括NDK提供的宏、變量以及模塊描述變量,這些宏、變量以及變量的賦值共同組成了Android.mk文件,其在NDK編譯中各盡其責,指導著NDK的編譯。
宏:包括my-dir、all-subdir-makefiles等,通過‘$(call )’來調用,返回文本信息。
變量:包括CLEAR_VARS、BUILD_SHARED_LIBRARY、TARGET_ARCH等,由NDK編譯系統提供,並且在Android.mk文件被解析前就已經存在。Android.mk文件有可能被多次解析,因此每次解析時這些變量的值都有可能不同。
模塊描述變量:Module-description,包括LOCAL_PATH、LOCAL_MODULE、LOCAL_SRC_FILES等LOCAL_前綴變量,這些變量除LOCAL_PATH外,均填寫在語句include $(CLEAR_VARS)和include $(BUILD_XXX)之間。
其他Android.mk配置可以查看Android.mk官方文檔。

2、基礎

在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(當前目錄)
LOCAL_PATH為模塊描述變量,一個Android.mk必須定義LOCAL_PATH,用於定位源文件,在本例中,使用的是編譯系統提供的宏“my-dir”(“my-dir”返回最近一次包括Makefile文件路徑,通常為當前Android.mk所在目錄),用於返回當前目錄。
此變量不會被CLEAR_VARS清除,所以每個Android.mk文件只需要定義一次就可以了。

CLEAR_VARS(變量清除)
CLEAR_VARS變量由編譯系統提供,顧名思義,作用是清除模塊變量(在include $(CLEAR_VARS)和include $(BUILD_XXX)之間的LOCAL_XXX模塊變量),當然LOCAL_PATH除外。由於所有的編譯控制文件都是單一的GNU Make可執行上下文環境中解析,而這個上下文環境中所有的變量都是全局的,所以編譯module前需要清理相應變量。

LOCAL_MODULE(module名稱)
LOCAL_MODULE是Android.mk文件中module的唯一標識,這個名字必須是唯一的,且中間不能有空格。在默認情況下,它決定了生成的文件名,如“hello-jni”對應的動態庫名稱為libhello-jni.so,然而要索引它時,需要“hello-jni”即可,也可以通過變量LOCAL_MODULE_FILENAME來覆蓋這個默認名稱。

LOCAL_SRC_FILES(源碼文件)
LOCAL_SRC_FILES 變量包括C/C++源文件列表,這些源文件會被編譯到一個module中,不過也不必列出頭文件和包括文件,編譯系統會自動為你找打所有需要的依賴關系。值得注意的是linux下路徑使用順斜槓(/)。

BUILD_SHARED_LIBRARY(動態庫編譯)
BUILD_SHARED_LIBRARY是編譯器提供的變量,表示編譯成動態庫,它指向一個GNU Makefile腳本,這個腳本收集從include $(CLEAR_VARS)後所有的LOCAL_XXX變量中定義的所有信息,決定編譯什麼以及怎麼編譯。
還有BUILD_STATIC_LIBRARY,和BUILD_SHARED_LIBRARY類似,表示編譯成靜態庫,靜態庫不會被拷貝到APK中。

PREBUILT_SHARED_LIBRARY(預編譯)
指向一個編譯腳本,用來指定一個預編譯動態庫.使用此變量時,不像BUILD_SHARED_LIBRARY和BUILD_STATIC_LIBRARY那樣,LOCAL_SRC_FILES的值必須是只能有一個指向預編譯動態庫的路徑,如foo/libfoo.so,而不是源文件。如下栗子。

include $(CLEAR_VARS)
LOCAL_MODULE := test
LOCAL_SRC_FILES := lib/$(TARGET_ARCH_ABI)/libtest.so
include $(PREBUILT_SHARED_LIBRARY)


PREBUILD_STATIC_LIBRARY和PREBUILD_SHARED_LIBRARY一樣,只不過是用於引用靜態庫。

TARGET_ARCH_ABI(目標ABI名稱)
如表一所示,目標ABI名稱。若定義了多個ABI,則每次解析Android.mk時,值都不一樣,主要使用場景為根本不同的ABI定義不同的文件等。

3、其他模塊變量LOCAL_LDLIBS(鏈接庫)

用於額外鏈接選項,所有的庫都有“-l”前綴。可同時列出多個庫,用空格隔開,例如:

LOCAL_LDLIBS := -llog -ldl


Android NDK默認鏈接了多個庫,不需要顯示的添加到LOCAL_LDLIBS中,包括the standard C libraries,the standard C++ libraries,real-time extensions和pthread庫。同時也提供了一些需要顯示添加的庫,這些庫版本有關系,如表三所示。 Android level Lib Explanation
Android-3 -llog Android Log -lz Zlib Compression Library -ldl Dynamic Linker Library Android-4 -lGLESv1_CM OpenGL ES 1.x Library Android-5 -lGLESv2 OpenGL ES 2.0 Library Android-8 -ljnigraphics The jnigraphics Library
Android-9 -lEGL The EGL graphics library -lOpenSLES Open ES native audio Library -landroid Natice Android API Android-14 -lOpenMAXAL OpenMAX AL natice multimedia Library Android-18 -lGLESv3 OpenGL ES 3.0 Library Android-21 -lGLESv3 OpenGL ES 3.1 Library 表三:鏈接庫

LOCAL_CFLAGS、LOCAL_CPPFLAGS和LOCAL_LDFLAGS(編譯、鏈接標志)

LOCAL_CFLAGS定義的是在編譯C/C++時,傳遞給編譯器的標志集合,LOCAL_CPPFLAGS只支持C++,作用也是傳遞給編譯器一些信息,LOCAL_LDFLAGS是指傳遞給連接器一些額外的參數。

在NDK開發中難免會用到這些標志位,特別是在優化編譯時,下面的是本人在開發中遇到的編譯選項。

① LOCAL_CPPFLAGS += -fexceptions
由於NDK編譯從R5開始才支持C++異常控制,為了通用性,異常處理默認是禁用的(-fno-exceptions),因此需要在指定module中添加LOCAL_CPPFLAGS += -fexceptions編譯選項方可編譯帶異常處理的C++代碼。也可以直接在Application.mk中配置APP_CPPFLAGS += -fexceptions。

② LOCAL_CPPFLAGS += -frtti
從NDK R5開始,NDK也開始支持C++ RTTI了,但為了通用性,所有的C++源文件被構建的時候默認是不支持RTTI的(-fno-rtti),可以通過在Android.mk中添加:LOCAL_CPPFLAGS += -frtti或者在Application.mk添加APP_CPPFLAGS += -frtti來開啟RTTI。

③ LOCAL_CFLAGS += -fvisibility=hidden
在NDK開發中,源文件的函數都有一個默認的visibility屬性為public,編譯生成的so文件中幾乎所有的函數名、全局變量名均被導出,其實只需要導出java_com開頭的jni函數即可,其他函數不需要暴露出來,在Android.mk中設置LOCAL_CFLAGS += -fvisibility=hidden,就可以隱藏不需要導出的函數,若某個函數需要導出,則添加JNIEXPORT或者__attribute__ ((visibility ("default")))即可。
除了安全,不導出不必要的函數外,還能減小so體積。

④ LOCAL_CFLAGS += -ffunction-sections
不添加此參數時,編譯文件.o中代碼部分只有.text段,使用此參數,會使每個函數單獨有一個段,舉個栗子,函數func1()會編譯成.text.func1段,雖然段多了,但對鏈接後代碼大小並沒有影響。

⑤ LOCAL_CFLAGS += -fdata-sections
同上,每個data都有一個單獨的段。

⑥ LOCAL_LDFLAGS += -Wl --gc-sections
-Wl,
  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved