Android.mk文件語法詳述
1. 概述
Android.mk文件是用來描述build system(編譯系統)的,更准確的說:該文件是一個微型的GNU Makefile片段,將由build system解析一次或者多次。
這個文件的目的是用來允許你將源文件組織成模塊,這個模塊中含有:一個靜態庫(.a文件) 或 一個動態庫(.so文件)
只有動態庫才會被安裝/復制到你的應用程序包,盡管靜態庫可以被用來生成動態庫。
你可以在每個模塊中 都定義一個Android.mk文件,你也可以讓多個模塊共用一個Android.mk文件。build system可以為你處理許多細節,
例如:你不需要在Android.mk文件中列出頭文件或者其他的依賴關系,這些NDK的build system會自動為你計算並處理。
這也意味着,當更新到新版本的NDK的時候,你應該得益於新的toolchain/platform的支持,而無需修改你的Android.mk文件。
( 注意:這些語法非常接近於分布在完整的開源的Android源代碼中的Android.mk文件,盡管是build system實現的,但是它們的用法是不同的。
這樣故意設計的決定是為了讓應用程序開發者重用“外部”庫的源代碼更容易。)
2. 實例分析
‘jni/Android.mk’ 文件描述了如何生成一個共享庫,它的內容是:
-----------------Android.mk------------------------
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := hello-jni
LOCAL_SRC_FILES := hello-jni.c
include $(BUILD_SHARED_LIBRARY)
---------------------------------------------------
(1). LOCAL_PATH:=$(call my-dir) ----------必須
Android.mk文件必須以LOCAL_PATH變量開始,它用於在樹中定位文件。
宏功能'my-dir'是由build system提供的,用於返回當前目錄路徑(包括Android.mk文件本身)
(2). include $(CLEAR_VARS) ----------必須
CLEAR_VARS變量是由build system提供的,並且指明了一個GNU makefile文件,這個功能會清理掉所有以LOCAL_開頭的內容(例如
LOCAL_MODULE,LOCAL_SRC_FILES,LOCAL_STATIC_LIBRARIES等),除了LOCAL_PATH,這句話是必須的,
因為如果所有的變量都是全局變量的話,所有的可控的編譯文件都需要在一個單獨的GNU中被解析並執行
(3). LOCAL_MODULE :=hello-jni
LOCAL_MODULE變量必須被定義,用來區分Android.mk中的每一個模塊。文件名必須是唯一的,不能有空格。
注意,這里編譯器會為你自動加上一些前綴和后綴,來保證文件是一致的,
比如:這里表明一個動態連接庫模塊被命名為"hello-jni",但是最后會生成為"libhello-jni.so"文件。
但是在Java中裝載這個庫的時候還是使用"hello-jni"名稱。當然如果我們使用"IMPORTANT NOTE:" 編譯系統就不會為你加上前綴
但是為了支持Android平台源碼中的Android.mk文件,也同樣會生成libhello-jni.so這樣的文件。
如果你將你的模塊命名為'libfoo',編譯系統將不會將前綴'lib'加上去,並且也會生成libfoo.so文件。
(4). LOCAL_SRC_FILES := hello-jni.c
LOCAL_SRC_FILES變量被需包括一個C和C++源文件的列表,這些會編譯並聚合到一個模塊中。
注意:這里並不需要你列出頭文件和被包含的文件,因為編譯系統會自動為你計算相關的屬性,源代碼中的列表會直接傳遞給編譯器。
C++默認文件的擴展名是“.cpp”,我們可以通過定義一個LOCAL_DEFAULT_CPP_EXTENSION變量來定義一個不同的C文件。
不要忘記在初始化前面的“.”點(也就是說".cpp"可以正常工作,但是cpp不能正常工作)
(5). include $(BUILD_SHARED_LIBRARY)
BUILD_SHARED_LIBRARY這個變量是由系統提供的,並且指定給GNU Makefile的腳本,
它可以收集所有你定義的"include $(CLEAR_VARS)"中以LOCAL_開頭的變量,並且決定哪些要被編譯,哪些應該做的更加准確。
編譯生成的是以"lib<module_name>.so"的文件,這個就是共享庫了。
我們同樣也可以使用BUILD_STATIC_LIBRARY編譯系統便會生成一個以"lib<module_name>.a"的文件來供動態庫調用。
(6). LOCAL_SHORT_COMMANDS := true /flase
當你的module有很多的源文件,或者依賴很多的靜態或動態庫。這會強制編譯系統使用一個中間的列表文件,並通過@$(listfile) 語法和library archiver 或者 static linker一起使用。
這在Windows上是非常有用的,因為它的命令行只接收最大8191個字符,這對於復雜的工程來說太小了。
這同樣也會影響單個源文件的編譯,如果將所有的編譯器選項放在列表文件里面。
注意如果設置了‘true’以外的值,都會恢復成默認行為。
你也可以在Android.mk文件中定義APP_SHORT_COMMANDS來強制使你的工程中的所有modules使用這項功能
注意:默認我們不推薦啟用這個功能,因為它會使得編譯變慢。
該變量可以解決如下編譯問題:make: execvp: /home/android-ndk-r9d/toolchains/arm-linux-androideabi-4.6/prebuilt/windows-x86_64/bin/arm-linux- androideabi-g++: Argument list too long
特別注意:
APP_SHORT_COMMANDS , LOCAL_SHORT_COMMANDS 可以解決鏈接時參數太長的問題(生成*.a *.so時中間文件過多)
然而,編譯,生成 libcrypto.so時,
-
-
- 在libcrypto模塊中采用LOCAL_SHORT_COMMANDS:=true來指定會導致編譯錯誤
- 在Application.mk中指定 APP_SHORT_COMMANDS:=true可以順利編譯,鏈接
-