1. 程式人生 > >Android.mk檔案語法規範——深入瞭解android平臺的jni

Android.mk檔案語法規範——深入瞭解android平臺的jni

Android.mk是Android提供的一種makefile檔案,用來指定諸如編譯生成so庫名、引用的標頭檔案目錄、需要編譯的.c/.cpp檔案和.a靜態庫檔案等。要掌握jni,就必須熟練掌握Android.mk的語法規範。 

一、Android.mk檔案的用途
一個android子專案中會存在一個或多個Android.mk檔案 
1、單一的Android.mk檔案 
直接參考NDK的sample目錄下的hello-jni專案,在這個專案中只有一個Android.mk檔案 
2、多個Android.mk檔案 
如果需要編譯的模組比較多,我們可能會將對應的模組放置在相應的目錄中, 
這樣,我們可以在每個目錄中定義對應的Android.mk檔案(類似於上面的寫法), 

最後,在根目錄放置一個Android.mk檔案,內容如下: 
include $(call all-subdir-makefiles) 
只需要這一行就可以了,它的作用就是包含所有子目錄中的Android.mk檔案 
3、多個模組共用一個Android.mk 
這個檔案允許你將原始檔組織成模組,這個模組中含有: 
  -靜態庫(.a檔案) 
  -動態庫(.so檔案) 
只有共享庫才能被安裝/複製到您的應用軟體(APK)包中 
include $(BUILD_STATIC_LIBRARY),編譯出的是靜態庫 
include $(BUILD_SHARED_LIBRARY),編譯出的是動態庫 



二、自定義變數
以下是在 Android.mk中依賴或定義的變數列表,可以定義其他變數為自己使用,但是NDK編譯系統保留下列變數名: 

-以 LOCAL_開頭的名字(例如 LOCAL_MODULE) 
-以 PRIVATE_, NDK_ 或 APP_開頭的名字(內部使用) 
-小寫名字(內部使用,例如‘my-dir’) 
  如果為了方便在 Android.mk 中定義自己的變數,建議使用 MY_字首,一個小例子: 
MY_SOURCES := foo.c 
ifneq ($(MY_CONFIG_BAR),) 
MY_SOURCES += bar.c 
endif 
LOCAL_SRC_FILES += $(MY_SOURCES) 
注意:‘:=’是賦值的意思;'+='是追加的意思;‘$’表示引用某變數的值。 



三、GNU Make系統變數
  這些 GNU Make變數在你的 Android.mk 檔案解析之前,就由編譯系統定義好了。注意在某些情況下,NDK可能分析 Android.mk 幾次,每一次某些變數的定義會有不同。 

  (1)CLEAR_VARS:  指向一個編譯指令碼,幾乎所有未定義的 LOCAL_XXX 變數都在"Module-description"節中列出。必須在開始一個新模組之前包含這個指令碼:include$(CLEAR_VARS),用於重置除LOCAL_PATH變數外的,所有LOCAL_XXX系列變數。 
  (2)BUILD_SHARED_LIBRARY:  指向編譯指令碼,根據所有的在 LOCAL_XXX 變數把列出的原始碼檔案編譯成一個共享庫。 
       注意,必須至少在包含這個檔案之前定義 LOCAL_MODULE 和 LOCAL_SRC_FILES。 
  (3)BUILD_STATIC_LIBRARY:  一個 BUILD_SHARED_LIBRARY 變數用於編譯一個靜態庫。靜態庫不會複製到的APK包中,但是能夠用於編譯共享庫。 
       示例:include $(BUILD_STATIC_LIBRARY) 
       注意,這將會生成一個名為 lib$(LOCAL_MODULE).a 的檔案 
  (4)TARGET_ARCH: 目標 CPU平臺的名字 
  (5)TARGET_PLATFORM: Android.mk 解析的時候,目標 Android 平臺的名字.詳情可考/development/ndk/docs/stable- apis.txt. 
       android-3 -> Official Android 1.5 system images 
       android-4 -> Official Android 1.6 system images 
       android-5 -> Official Android 2.0 system images 
  (6)TARGET_ARCH_ABI:  暫時只支援兩個 value,armeabi 和 armeabi-v7a。。 
  (7)TARGET_ABI: 目標平臺和 ABI 的組合, 


四、模組描述變數
  下面的變數用於向編譯系統描述你的模組。應該定義在'include  $(CLEAR_VARS)'和'include $(BUILD_XXXXX)'之間。$(CLEAR_VARS)是一個指令碼,清除所有這些變數。 
  (1)LOCAL_PATH:  這個變數用於給出當前檔案的路徑。 
       必須在 Android.mk 的開頭定義,可以這樣使用:LOCAL_PATH := $(call my-dir) 
       如當前目錄下有個資料夾名稱 src,則可以這樣寫 $(call src),那麼就會得到 src 目錄的完整路徑 
       這個變數不會被$(CLEAR_VARS)清除,因此每個 Android.mk 只需要定義一次(即使在一個檔案中定義了幾個模組的情況下)。 
  (2)LOCAL_MODULE: 這是模組的名字,它必須是唯一的,而且不能包含空格。 
       必須在包含任一的$(BUILD_XXXX)指令碼之前定義它。模組的名字決定了生成檔案的名字。 
  (3)LOCAL_SRC_FILES:  這是要編譯的原始碼檔案列表。 
       只要列出要傳遞給編譯器的檔案,因為編譯系統自動計算依賴。注意原始碼檔名稱都是相對於 LOCAL_PATH的,你可以使用路徑部分,例如: 
        LOCAL_SRC_FILES := foo.c toto/bar.c\ 
        Hello.c 
       檔案之間可以用空格或Tab鍵進行分割,換行請用"\" 
       如果是追加原始碼檔案的話,請用LOCAL_SRC_FILES += 
       注意:可以LOCAL_SRC_FILES := $(call all-subdir-java-files)這種形式來包含local_path目錄下的所有java檔案。 
  (4)LOCAL_C_INCLUDES:  可選變數,表示標頭檔案的搜尋路徑。 
        預設的標頭檔案的搜尋路徑是LOCAL_PATH目錄。 
  (5)LOCAL_STATIC_LIBRARIES: 表示該模組需要使用哪些靜態庫,以便在編譯時進行連結。 
  (6)LOCAL_SHARED_LIBRARIES:  表示模組在執行時要依賴的共享庫(動態庫),在連結時就需要,以便在生成檔案時嵌入其相應的資訊。 
       注意:它不會附加列出的模組到編譯圖,也就是仍然需要在Application.mk 中把它們新增到程式要求的模組中。 
  (7)LOCAL_LDLIBS:  編譯模組時要使用的附加的連結器選項。這對於使用‘-l’字首傳遞指定庫的名字是有用的。 
       例如,LOCAL_LDLIBS := -lz表示告訴連結器生成的模組要在載入時刻連結到/system/lib/libz.so 
       可檢視 docs/STABLE-APIS.TXT 獲取使用 NDK發行版能連結到的開放的系統庫列表。 
   (8)LOCAL_MODULE_PATH 和 LOCAL_UNSTRIPPED_PATH 
       在 Android.mk 檔案中, 還可以用LOCAL_MODULE_PATH 和LOCAL_UNSTRIPPED_PATH指定最後的目標安裝路徑. 
       不同的檔案系統路徑用以下的巨集進行選擇: 
       TARGET_ROOT_OUT:表示根檔案系統。 
       TARGET_OUT:表示 system檔案系統。 
       TARGET_OUT_DATA:表示 data檔案系統。 
       用法如:LOCAL_MODULE_PATH :=$(TARGET_ROOT_OUT) 
       至於LOCAL_MODULE_PATH 和LOCAL_UNSTRIPPED_PATH的區別,暫時還不清楚。 
   (9)LOCAL_JNI_SHARED_LIBRARIES:定義了要包含的so庫檔案的名字,如果程式沒有采用jni,不需要 
        LOCAL_JNI_SHARED_LIBRARIES := libxxx 這樣在編譯的時候,NDK自動會把這個libxxx打包進apk; 放在youapk/lib/目錄下 



五、NDK提供的函式巨集
GNU Make函式巨集,必須通過使用'$(call  )'來呼叫,返回值是文字化的資訊。 
   (1)my-dir:返回當前 Android.mk 所在的目錄的路徑,相對於 NDK 編譯系統的頂層。這是有用的,在 Android.mk 檔案的開頭如此定義: 
        LOCAL_PATH := $(call my-dir) 
   (2)all-subdir-makefiles: 返回一個位於當前'my-dir'路徑的子目錄中的所有Android.mk的列表。 
       例如,某一子專案的目錄層次如下: 
            src/foo/Android.mk 
            src/foo/lib1/Android.mk 
            src/foo/lib2/Android.mk 
      如果 src/foo/Android.mk 包含一行: 
           include $(call all-subdir-makefiles) 
      那麼它就會自動包含 src/foo/lib1/Android.mk 和 src/foo/lib2/Android.mk。 
      這項功能用於向編譯系統提供深層次巢狀的程式碼目錄層次。 
      注意,在預設情況下,NDK 將會只搜尋在 src/*/Android.mk 中的檔案。 
   (3)this-makefile:  返回當前Makefile 的路徑(即這個函式呼叫的地方) 
   (4)parent-makefile:  返回呼叫樹中父 Makefile 路徑。即包含當前Makefile的Makefile 路徑。 
   (5)grand-parent-makefile:返回呼叫樹中父Makefile的父Makefile的路徑 



六、 Android.mk示例
Java程式碼  收藏程式碼
  1. #編譯靜態庫  
  2. LOCAL_PATH := $(call my-dir)  
  3. include $(CLEAR_VARS)  
  4. LOCAL_MODULE = libhellos  
  5. LOCAL_CFLAGS = $(L_CFLAGS)  
  6. LOCAL_SRC_FILES = hellos.c  
  7. LOCAL_C_INCLUDES = $(INCLUDES)  
  8. LOCAL_SHARED_LIBRARIES := libcutils  
  9. LOCAL_COPY_HEADERS_TO := libhellos  
  10. LOCAL_COPY_HEADERS := hellos.h  
  11. include $(BUILD_STATIC_LIBRARY)  
  12. #編譯動態庫  
  13. LOCAL_PATH := $(call my-dir)  
  14. include $(CLEAR_VARS)  
  15. LOCAL_MODULE = libhellod  
  16. LOCAL_CFLAGS = $(L_CFLAGS)  
  17. LOCAL_SRC_FILES = hellod.c  
  18. LOCAL_C_INCLUDES = $(INCLUDES)  
  19. LOCAL_SHARED_LIBRARIES := libcutils  
  20. LOCAL_COPY_HEADERS_TO := libhellod  
  21. LOCAL_COPY_HEADERS := hellod.h  
  22. include $(BUILD_SHARED_LIBRARY)  
  23. #使用靜態庫  
  24. LOCAL_PATH := $(call my-dir)  
  25. include $(CLEAR_VARS)  
  26. LOCAL_MODULE := hellos  
  27. LOCAL_STATIC_LIBRARIES := libhellos  
  28. LOCAL_SHARED_LIBRARIES :=  
  29. LOCAL_LDLIBS += -ldl  
  30. LOCAL_CFLAGS := $(L_CFLAGS)  
  31. LOCAL_SRC_FILES := mains.c  
  32. LOCAL_C_INCLUDES := $(INCLUDES)  
  33. include $(BUILD_EXECUTABLE)  
  34. #使用動態庫  
  35. LOCAL_PATH := $(call my-dir)  
  36. include $(CLEAR_VARS)  
  37. LOCAL_MODULE := hellod  
  38. LOCAL_MODULE_TAGS := debug  
  39. LOCAL_SHARED_LIBRARIES := libc libcutils libhellod  
  40. LOCAL_LDLIBS += -ldl  
  41. LOCAL_CFLAGS := $(L_CFLAGS)  
  42. LOCAL_SRC_FILES := maind.c  
  43. LOCAL_C_INCLUDES := $(INCLUDES)  
  44. include $(BUILD_EXECUTABLE)