中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Android NDK編譯選項設置

發布時間:2020-07-06 07:49:35 來源:網絡 閱讀:3078 作者:網易云捕 欄目:移動開發

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

Android NDK編譯選項設置


     一、Application.mk


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

APP_ABI := armeabi arm64-v8a x86_64 x86 armeabi-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 setValue
ARMv5TE based CPUAPP_ABI := armeabi
ARMv7 based CPUAPP_ABI := armeabi-v7a
ARMv8 AArch74APP_ABI := arm64-v8a
IA-32APP_ABI := x86
Intel64APP_ABI := x86_64
MIPS32APP_ABI := mips
MIPS64(r6)APP_ABI := mips64
All supported instruction setsAPP_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有表二中的幾種取值。

NameExplanation
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 <function>)’來調用,返回文本信息。
      變量:包括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 levelLibExplanation
 
Android-3
-llogAndroid Log
-lzZlib Compression Library
-ldlDynamic Linker Library
Android-4-lGLESv1_CMOpenGL ES 1.x Library
Android-5-lGLESv2OpenGL ES 2.0 Library
Android-8-ljnigraphicsThe jnigraphics Library
 
Android-9
-lEGLThe EGL graphics library
-lOpenSLESOpen ES native audio Library
-landroidNatice Android API
Android-14-lOpenMAXALOpenMAX AL natice multimedia Library
Android-18-lGLESv3OpenGL ES 3.0 Library
Android-21-lGLESv3OpenGL 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,<option>選項是告訴編譯器,將后面選項<option>傳遞給連接器,-Wl,--gc-sections的意思是使用連接器ld鏈接時刪除不用的段。若使用LOCAL_CFLAGS += -ffunction-sections -fdata-sections,則代碼和數據均被分割成不同的段,若某個函數或數據未被任何函數調用,則ld不會鏈接未被調用的函數,從而減小so文件體積,達到優化so的目的。

       ⑦ LOCAL_LDFLAGS += -fPIC
       PIC(position independent code)用于編譯位置無關代碼,生成可用于共享庫的位置獨立代碼。若不添加-fPIC,則加載.so文件的代碼段時,代碼段引用的數據對象需要重定位,重定位會修改代碼段內容,這樣就導致沒使用這個.so,代碼段的進程在內核中就會生成這個文件的拷貝。

       ⑧ LOCAL_LDFLAGS += -Wall 
       這個的意思是wring all 意思在編譯和鏈接過程中顯示所有警告信息。

       ⑨其他
       若需要了解其他編譯標志,可以查看GCC Command Options 文檔。

 


向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

齐齐哈尔市| 中西区| 英吉沙县| 商城县| 托克逊县| 南京市| 新平| 荣昌县| 平罗县| 农安县| 景德镇市| 定州市| 临武县| 平度市| 福安市| 周口市| 遂平县| 张家口市| 永靖县| 宁阳县| 岢岚县| 吴忠市| 宜都市| 麻江县| 房产| 电白县| 新民市| 尉氏县| 黎城县| 云梦县| 扶风县| 刚察县| 镇宁| 上林县| 淳化县| 子洲县| 安乡县| 海门市| 鄂托克前旗| 蕲春县| 鄂托克旗|