標籤:
在配置了以上的檔案之後,便可以編譯出我們新添加的裝置的系統鏡像了。
首先,調用“source build/envsetup.sh”該命令的輸出中會看到 Build 系統已經引入了剛剛添加的 vendorsetup.sh 檔案。
然後再調用“lunch”函數,該函數輸出的列表中將包含新添加的 vendorsetup.sh 中添加的條目。然後通過編號或名稱選擇即可。
最後,調用“make -j8”來執行編譯即可。
添加新的模組
關於“模組”的說明在上文中已經提到過,這裡不再贅述。
在 源碼樹中,一個模組的所有檔案通常都位於同一個檔案夾中。為了將當前模組添加到整個 Build 系統中,每個模組都需要一個專門的 Make 檔案,該檔案的名稱為“Android.mk”。Build 系統會掃描名稱為“Android.mk”的檔案,並根據該檔案中內容編譯出相應的產物。
需 要注意的是:在 Android Build 系統中,編譯是以模組(而不是檔案)作為單位的,每個模組都有一個唯一的名稱,一個模組的依賴對象只能是另外一個模組,而不能是其他類型的對象。對於已經 編譯好的二進位庫,如果要用來被當作是依賴對象,那麼應當將這些已經編譯好的庫作為單獨的模組。對於這些已經編譯好的庫使用 BUILD_PREBUILT 或 BUILD_MULTI_PREBUILT。例如:當編譯某個 Java 庫需要依賴一些 Jar 包時,並不能直接指定 Jar 包的路徑作為依賴,而必須首先將這些 Jar 包定義為一個模組,然後在編譯 Java 庫的時候通過模組的名稱來依賴這些 Jar 包。
下面,我們就來講解 Android.mk 檔案的編寫:
Android.mk 檔案通常以以下兩行代碼作為開頭:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
這兩行代碼的作用是:
設定當前模組的編譯路徑為當前檔案夾路徑。
清理(可能由其他模組設定過的)編譯環境中用到的變數。
為了方便模組的編譯,Build 系統設定了很多的編譯環境變數。要編譯一個模組,只要在編譯之前根據需要設定這些變數然後執行編譯即可。它們包括:
LOCAL_SRC_FILES:當前模組包含的所有原始碼檔案。
LOCAL_MODULE:當前模組的名稱,這個名稱應當是唯一的,模組間的依賴關係就是通過這個名稱來引用的。
LOCAL_C_INCLUDES:C 或 C++ 語言需要的標頭檔的路徑。
LOCAL_STATIC_LIBRARIES:當前模組在靜態連結時需要的庫的名稱。
LOCAL_SHARED_LIBRARIES:當前模組在運行時依賴的動態庫的名稱。
LOCAL_CFLAGS:提供給 C/C++ 編譯器的額外編譯參數。
LOCAL_JAVA_LIBRARIES:當前模組依賴的 Java 共用庫。
LOCAL_STATIC_JAVA_LIBRARIES:當前模組依賴的 Java 靜態庫。
LOCAL_PACKAGE_NAME:當前 APK 應用的名稱。
LOCAL_CERTIFICATE:簽署當前應用的認證名稱。
LOCAL_MODULE_TAGS:當前模組所包含的標籤,一個模組可以包含多個標籤。標籤的值可能是 debug, eng, user,development 或者 optional。其中,optional 是預設標籤。標籤是提供給編譯類型使用的。不同的編譯類型會安裝包含不同標籤的模組,關於編譯類型的說明如表 7 所示:
表 3 中的檔案已經定義好了各種類型模組的編譯方式。所以要執行編譯,只需要引入表 3 中對應的 Make 檔案即可(通過常量的方式)。例如,要編譯一個 APK 檔案,只需要在 Android.mk 檔案中,加入“include $(BUILD_PACKAGE)
除此以外,Build 系統中還定義了一些便捷的函數以便在 Android.mk 中使用,包括:
$(call my-dir):擷取當前檔案夾路徑。
$(call all-java-files-under, <src>):擷取指定目錄下的所有 Java 檔案。
$(call all-c-files-under, <src>):擷取指定目錄下的所有 C 語言檔案。
$(call all-Iaidl-files-under, <src>):擷取指定目錄下的所有 AIDL 檔案。
$(call all-makefiles-under, <folder>):擷取指定目錄下的所有 Make 檔案。
$(call intermediates-dir-for, <class>, <app_name>, <host or target>, <common?> ):擷取 Build 輸出的目標檔案夾路徑。
清單 2 和清單 3 分別是編譯 APK 檔案和編譯 Java 靜態庫的 Make 檔案樣本:
清單 2. 編譯一個 APK 檔案
雙擊代碼全選
| 12345678910 |
LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) # 擷取所有子目錄中的 Java 檔案LOCAL_SRC_FILES := $(call all-subdir-java-files) # 當前模組依賴的靜態 Java 庫,如果有多個以空格分隔LOCAL_STATIC_JAVA_LIBRARIES := static-library # 當前模組的名稱LOCAL_PACKAGE_NAME := LocalPackage # 編譯 APK 檔案include $(BUILD_PACKAGE) |
清單 3. 編譯一個 Java 的靜態庫
雙擊代碼全選
| 1234567891011121314 |
LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) # 擷取所有子目錄中的 Java 檔案LOCAL_SRC_FILES := $(call all-subdir-java-files) # 當前模組依賴的動態 Java 庫名稱LOCAL_JAVA_LIBRARIES := android.test.runner # 當前模組的名稱LOCAL_MODULE := sample # 將當前模組編譯成一個靜態 Java 庫include $(BUILD_STATIC_JAVA_LIBRARY) |
結束語
整個 Build 系統包含了非常多的內容,由於篇幅所限,本文只能介紹其中最主要內容。
由於 Build 系統本身也是在隨著 Android 平台不斷的開發過程中,所以不同的版本其中的內容和定義可能會發生變化。網路上關於該部分的資料很零碎,並且很多資料中的一些內容已經過時不再適用,再加上缺少官方文檔,所以該部分的學習存在一定的難度。
這就要求我們要有很強的代碼閱讀能力,畢竟代碼是不會說謊的。要知道,對於我們這些開發人員來說,原始碼就是我們最忠實的朋友。 Use the Source,Luke!
理解 Android Build 系統