理解Android Build 系統
簡介:Android Build 系統是用來編譯 Android 系統,Android SDK 以及相關文檔的一套框架。眾所周知,Android 是一個開源的操作系統。Android 的源碼中包含了許許多多的模塊。 不同產商的不同設備對於 Android 系統的定製都是不一樣的。如何將這些模塊統一管理起來,如何能夠在不同的操作系統上進行編譯,如何在編譯時能夠支持面向不同的硬體設備,不同的編譯類型,且還要提供面向各個產商的定製擴展,是非常有難度的。 但 Android Build 系統很好的解決了這些問題,這裡面有很多值得我們開發人員學習的地方。對於 Android 平台開發人員來說,本文可以幫助你熟悉你每天接觸到的構建環境。對於其他開發人員來說,本文可以作為一個 GNU Make 的使用案例,學習這些成功案例,可以提升我們的開發經驗。
發布日期:2013 年 3 月 28 日 級別:初級 訪問情況 :1723 次瀏覽 評論:0(查看|添加評論 - 登錄)
平均分 (11個評分)為本文評分
前言
Android Build 系統是 Android 源碼的一部分。關於如何獲取 Android 源碼,請參照 Android Source 官方網站:
http://source.android.com/source/downloading.html。
Android Build 系統用來編譯 Android 系統,Android SDK 以及相關文檔。該系統主要由 Make 文件,Shell 腳本以及 Python 腳本組成,其中最主要的是 Make 文件。
眾所周知,Android 是一個開源的操作系統。Android 的源碼中包含了大量的開源項目以及許多的模塊。不同產商的不同設備對於 Android 系統的定製都是不一樣的。
如何將這些項目和模塊的編譯統一管理起來,如何能夠在不同的操作系統上進行編譯,如何在編譯時能夠支持面向不同的硬體設備,不同的編譯類型,且還要提供面向各個產商的定製擴展,是非常有難度的。
但 Android Build 系統很好的解決了這些問題,這裡面有很多值得我們開發人員學習的地方。
對於 Android 平台開發人員來說,本文可以幫助你熟悉你每天接觸到的構建環境。
對於其他開發人員來說,本文可以作為一個 GNU Make 的使用案例,學習這些成功案例,可以提升我們的開發經驗。
回頁首
概述
Build 系統中最主要的處理邏輯都在 Make 文件中,而其他的腳本文件只是起到一些輔助作用,由於篇幅所限,本文只探討 Make 文件中的內容。
整個 Build 系統中的 Make 文件可以分為三類:
第一類是 Build 系統核心文件,此類文件定義了整個 Build 系統的框架,而其他所有 Make 文件都是在這個框架的基礎上編寫出來的。
圖 1 是 Android 源碼樹的目錄結構,Build 系統核心文件全部位於 /build/core(本文所提到的所有路徑都是以 Android 源碼樹作為背景的,「/」指的是源碼樹的根目錄,與文件系統無關)目錄下。
圖 1. Android 源碼樹的目錄結構第二類是針對某個產品(一個產品可能是某個型號的手機或者平板電腦)的 Make 文件,這些文件通常位於 device 目錄下,該目錄下又以公司名以及產品名分為兩級目錄,圖 2 是 device 目錄下子目錄的結構。對於一個產品的定義通常需要一組文件,這些文件共同構成了對於這個產品的定義。例如,/device/sony/it26 目錄下的文件共同構成了對於 Sony LT26 型號手機的定義。
圖 2. device 目錄下子目錄的結構第三類是針對某個模塊(關於模塊後文會詳細討論)的 Make 文件。整個系統中,包含了大量的模塊,每個模塊都有一個專門的 Make 文件,這類文件的名稱統一為「Android.mk」,該文件中定義了如何編譯當前模塊。Build 系統會在整個源碼樹中掃描名稱為「Android.mk」的文件並根據其中的內容執行模塊的編譯。
回頁首
編譯 Android 系統
執行編譯
Android 系統的編譯環境目前只支持 Ubuntu 以及 Mac OS 兩種操作系統。關於編譯環境的構建方法請參見以下路徑:http://source.android.com/source/initializing.html
在完成編譯環境的準備工作以及獲取到完整的 Android 源碼之後,想要編譯出整個 Android 系統非常的容易:
打開控制台之後轉到 Android 源碼的根目錄,然後執行如清單 1 所示的三條命令即可("$"
是命令提示符,不是命令的一部分。):
完整的編譯時間依賴於編譯主機的配置,在筆者的 Macbook Pro(OS X 10.8.2, i7 2G CPU,8G RAM, 120G SSD)上使用 8 個 Job 同時編譯共需要一個半小時左右的時間。
清單 1. 編譯 Android 系統$ source build/envsetup.sh $ lunch full-eng $ make -j8 |
這三行命令的說明如下:
第一行命令「source build/envsetup.sh」引入了 build/envsetup.sh
腳本。該腳本的作用是初始化編譯環境,並引入一些輔助的 Shell 函數,這其中就包括第二步使用 lunch 函數。
除此之外,該文件中還定義了其他一些常用的函數,它們如表 1 所示:
表 1. build/envsetup.sh 中定義的常用函數名稱 | 說明 |
---|---|
croot | 切換到源碼樹的根目錄 |
m | 在源碼樹的根目錄執行 make |
mm | Build 當前目錄下的模塊 |
mmm | Build 指定目錄下的模塊 |
cgrep | 在所有 C/C++ 文件上執行 grep |
jgrep | 在所有 Java 文件上執行 grep |
resgrep | 在所有 res/*.xml 文件上執行 grep |
godir | 轉到包含某個文件的目錄路徑 |
printconfig | 顯示當前 Build 的配置信息 |
add_lunch_combo | 在 lunch 函數的菜單中添加一個條目 |
第二行命令「lunch full-eng」是調用 lunch 函數,並指定參數為「full-eng」。lunch 函數的參數用來指定此次編譯的目標設備以及編譯類型。在這裡,這兩個值分別是「full」和「eng」。「full」是 Android 源碼中已經定義好的一種產品,是為模擬器而設置的。而編譯類型會影響最終系統中包含的模塊,關於編譯類型將在表 7 中詳細講解。
如果調用 lunch 函數的時候沒有指定參數,那麼該函數將輸出列表以供選擇,該列表類似圖 3 中的內容(列表的內容會根據當前 Build 系統中包含的產品配置而不同,具體參見後文「添加新的產品」),此時可以通過輸入編號或者名稱進行選擇。
圖 3. lunch 函數的輸出第三行命令「make -j8」才真正開始執行編譯。make 的參數「-j」指定了同時編譯的 Job 數量,這是個整數,該值通常是編譯主機 CPU 支持的並發線程總數的 1 倍或 2 倍(例如:在一個 4 核,每個核支持兩個線程的 CPU 上,可以使用 make -j8 或 make -j16)。在調用 make 命令時,如果沒有指定任何目標,則將使用默認的名稱為「droid」目標,該目標會編譯出完整的 Android 系統鏡像。
Build 結果的目錄結構
所有的編譯產物都將位於 /out 目錄下,該目錄下主要有以下幾個子目錄:
make dist
target」將文件拷貝到該目錄,默認的編譯目標不會產生該目錄。Build 生成的鏡像文件
Build 的產物中最重要的是三個鏡像文件,它們都位於 /out/target/product/<product_name>/ 目錄下。
這三個文件是:
回頁首
Make 文件說明
整個 Build 系統的入口文件是源碼樹根目錄下名稱為「Makefile」的文件,當在源代碼根目錄上調用 make 命令時,make 命令首先將讀取該文件。
Makefile 文件的內容只有一行:「include build/core/main.mk
」。該行代碼的作用很明顯:包含 build/core/main.mk 文件。在 main.mk 文件中又會包含其他的文件,其他文件中又會包含更多的文件,這樣就引入了整個 Build 系統。
這些 Make 文件間的包含關係是相當複雜的,圖 3 描述了這種關係,該圖中黃色標記的文件(且除了 $
開頭的文件)都位於 build/core/ 目錄下。
表 2 總結了圖 4 中提到的這些文件的作用:
表 2. 主要的 Make 文件的說明文件名 | 說明 |
---|---|
main.mk | 最主要的 Make 文件,該文件中首先將對編譯環境進行檢查,同時引入其他的 Make 文件。另外,該文件中還定義了幾個最主要的 Make 目標,例如 droid,sdk,等(參見後文「Make 目標說明」)。 |
help.mk | 包含了名稱為 help 的 Make 目標的定義,該目標將列出主要的 Make 目標及其說明。 |
pathmap.mk | 將許多頭文件的路徑通過名值對的方式定義為映射表,並提供 include-path-for 函數來獲取。例如,通過 $(call include-path-for, frameworks-native) 便可以獲取到 framework 本地代碼需要的頭文件路徑。 |
envsetup.mk | 配置 Build 系統需要的環境變數,例如:TARGET_PRODUCT,TARGET_BUILD_VARIANT,HOST_OS,HOST_ARCH 等。當前編譯的主機平台信息(例如操作系統,CPU 類型等信息)就是在這個文件中確定的。另外,該文件中還指定了各種編譯結果的輸出路徑。 |
combo/select.mk | 根據當前編譯器的平台選擇平台相關的 Make 文件。 |
dumpvar.mk | 在 Build 開始之前,顯示此次 Build 的配置信息。 |
config.mk | 整個 Build 系統的配置文件,最重要的 Make 文件之一。該文件中主要包含以下內容:
|
definitions.mk | 最重要的 Make 文件之一,在其中定義了大量的函數。這些函數都是 Build 系統的其他文件將用到的。例如:my-dir,all-subdir-makefiles,find-subdir-files,sign-package 等,關於這些函數的說明請參見每個函數的代碼注釋。 |
distdir.mk | 針對 dist 目標的定義。dist 目標用來拷貝文件到指定路徑。 |
dex_preopt.mk | 針對啟動 jar 包的預先優化。 |
pdk_config.mk | 顧名思義,針對 pdk(Platform Developement Kit)的配置文件。 |
${ONE_SHOT_MAKEFILE} |
ONE_SHOT_MAKEFILE 是一個變數,當使用「mm」編譯某個目錄下的模塊時,此變數的值即為當前指定路徑下的 Make 文件的路徑。 |
${subdir_makefiles} |
各個模塊的 Android.mk 文件的集合,這個集合是通過 Python 腳本掃描得到的。 |
post_clean.mk | 在前一次 Build 的基礎上檢查當前 Build 的配置,並執行必要清理工作。 |
legacy_prebuilts.mk | 該文件中只定義了 GRANDFATHERED_ALL_PREBUILT 變數。 |
Makefile | 被 main.mk 包含,該文件中的內容是輔助 main.mk 的一些額外內容。 |
Android 源碼中包含了許多的模塊,模塊的類型有很多種,例如:Java 庫,C/C++ 庫,APK 應用,以及可執行文件等 。並且,Java 或者 C/C++ 庫還可以分為靜態的或者動態的,庫或可執行文件既可能是針對設備(本文的「設備」指的是 Android 系統將被安裝的設備,例如某個型號的手機或平板)的也可能是針對主機(本文的「主機」指的是開發 Android 系統的機器,例如裝有 Ubuntu 操作系統的 PC 機或裝有 MacOS 的 iMac 或 Macbook)的。不同類型的模塊的編譯步驟和方法是不一樣,為了能夠一致且方便的執行各種類型模塊的編譯,在 config.mk 中定義了許多的常量,這其中的每個常量描述了一種類型模塊的編譯方式,這些常量有:
通過名稱大概就可以猜出每個變數所對應的模塊類型。(在模塊的 Android.mk 文件中,只要包含進這裡對應的常量便可以執行相應類型模塊的編譯。對於 Android.mk 文件的編寫請參見後文:「添加新的模塊」。)
這些常量的值都是另外一個 Make 文件的路徑,詳細的編譯方式都是在對應的 Make 文件中定義的。這些常量和 Make 文件的是一一對應的,對應規則也很簡單:常量的名稱是 Make 文件的文件名除去後綴全部改為大寫然後加上「BUILD_」作為前綴。例如常量 BUILD_HOST_PREBUILT 的值對應的文件就是 host_prebuilt.mk。
這些 Make 文件的說明如表 3 所示:
表 3. 各種模塊的編譯方式的定義文件文件名 | 說明 |
---|---|
host_static_library.mk | 定義了如何編譯主機上的靜態庫。 |
host_shared_library.mk | 定義了如何編譯主機上的共享庫。 |
static_library.mk | 定義了如何編譯設備上的靜態庫。 |
shared_library.mk | 定義了如何編譯設備上的共享庫。 |
executable.mk | 定義了如何編譯設備上的可執行文件。 |
host_executable.mk | 定義了如何編譯主機上的可執行文件。 |
package.mk | 定義了如何編譯 APK 文件。 |
prebuilt.mk | 定義了如何處理一個已經編譯好的文件 ( 例如 Jar 包 )。 |
multi_prebuilt.mk | 定義了如何處理一個或多個已編譯文件,該文件的實現依賴 prebuilt.mk。 |
host_prebuilt.mk | 處理一個或多個主機上使用的已編譯文件,該文件的實現依賴 multi_prebuilt.mk。 |
java_library.mk | 定義了如何編譯設備上的共享 Java 庫。 |
static_java_library.mk | 定義了如何編譯設備上的靜態 Java 庫。 |
host_java_library.mk | 定義了如何編譯主機上的共享 Java 庫。 |
不同類型的模塊的編譯過程會有一些相同的步驟,例如:編譯一個 Java 庫和編譯一個 APK 文件都需要定義如何編譯 Java 文件。因此,表 3 中的這些 Make 文件的定義中會包含一些共同的代碼邏輯。為了減少代碼冗餘,需要將共同的代碼復用起來,復用的方式是將共同代碼放到專門的文件中,然後在其他文件中包含這些文件的方式來實現的。這些包含關係如圖 5 所示。由於篇幅關係,這裡就不再對其他文件做詳細描述(其實這些文件從文件名稱中就可以大致猜出其作用)。
圖 5. 模塊的編譯方式定義文件的包含關係回頁首
Make 目標說明
make /make droid
如果在源碼樹的根目錄直接調用「make」命令而不指定任何目標,則會選擇默認目標:「droid」(在 main.mk 中定義)。因此,這和執行「make droid」效果是一樣的。
droid 目標將編譯出整個系統的鏡像。從源代碼到編譯出系統鏡像,整個編譯過程非常複雜。這個過程並不是在 droid 一個目標中定義的,而是 droid 目標會依賴許多其他的目標,這些目標的互相配合導致了整個系統的編譯。
圖 6 描述了 droid 目標所依賴的其他目標:
圖 6. droid 目標所依賴的其他 Make 目標圖 6 中這些目標的說明如表 4 所示:
表 4. droid 所依賴的其他 Make 目標的說明
名稱 | 說明 |
---|---|
apps_only | 該目標將編譯出當前配置下不包含 user,userdebug,eng 標籤(關於標籤,請參見後文「添加新的模塊」)的應用程序。 |
droidcore | 該目標僅僅是所依賴的幾個目標的組合,其本身不做更多的處理。 |
dist_files | 該目標用來拷貝文件到 /out/dist 目錄。 |
files | 該目標僅僅是所依賴的幾個目標的組合,其本身不做更多的處理。 |
prebuilt | 該目標依賴於 $(ALL_PREBUILT) ,$(ALL_PREBUILT) 的作用就是處理所有已編譯好的文件。 |
$(modules_to_install) |
modules_to_install 變數包含了當前配置下所有會被安裝的模塊(一個模塊是否會被安裝依賴於該產品的配置文件,模塊的標籤等信息),因此該目標將導致所有會被安裝的模塊的編譯。 |
$(modules_to_check) |
該目標用來確保我們定義的構建模塊是沒有冗餘的。 |
$(INSTALLED_ANDROID_INFO_TXT_TARGET) |
該目標會生成一個關於當前 Build 配置的設備信息的文件,該文件的生成路徑是:out/target/product/<product_name>/android-info.txt |
systemimage | 生成 system.img。 |
$(INSTALLED_BOOTIMAGE_TARGET) |
生成 boot.img。 |
$(INSTALLED_RECOVERYIMAGE_TARGET) |
生成 recovery.img。 |
$(INSTALLED_USERDATAIMAGE_TARGET) |
生成 userdata.img。 |
$(INSTALLED_CACHEIMAGE_TARGET) |
生成 cache.img。 |
$(INSTALLED_FILES_FILE) |
該目標會生成 out/target/product/<product_name>/ installed-files.txt 文件,該文件中內容是當前系統鏡像中已經安裝的文件列表。 |
其他目標
Build 系統中包含的其他一些 Make 目標說明如表 5 所示:
表 5. 其他主要 Make 目標Make 目標 | 說明 |
---|---|
make clean | 執行清理,等同於:rm -rf out/。 |
make sdk | 編譯出 Android 的 SDK。 |
make clean-sdk | 清理 SDK 的編譯產物。 |
make update-api | 更新 API。在 framework API 改動之後,需要首先執行該命令來更新 API,公開的 API 記錄在 frameworks/base/api 目錄下。 |
make dist | 執行 Build,並將 MAKECMDGOALS 變數定義的輸出文件拷貝到 /out/dist 目錄。 |
make all | 編譯所有內容,不管當前產品的定義中是否會包含。 |
make help | 幫助信息,顯示主要的 make 目標。 |
make snod | 從已經編譯出的包快速重建系統鏡像。 |
make libandroid_runtime | 編譯所有 JNI framework 內容。 |
makeframework | 編譯所有 Java framework 內容。 |
makeservices | 編譯系統服務和相關內容。 |
make <local_target> | 編譯一個指定的模塊,local_target 為模塊的名稱。 |
make clean-<local_target> | 清理一個指定模塊的編譯結果。 |
makedump-products | 顯示所有產品的編譯配置信息,例如:產品名,產品支持的地區語言,產品中會包含的模塊等信息。 |
makePRODUCT-xxx-yyy | 編譯某個指定的產品。 |
makebootimage | 生成 boot.img |
makerecoveryimage | 生成 recovery.img |
makeuserdataimage | 生成 userdata.img |
makecacheimage | 生成 cache.img |
回頁首
在 Build 系統中添加新的內容
添加新的產品
當我們要開發一款新的 Android 產品的時候,我們首先就需要在 Build 系統中添加對於該產品的定義。
在 Android Build 系統中對產品定義的文件通常位於 device 目錄下(另外還有一個可以定義產品的目錄是 vender 目錄,這是個歷史遺留目錄,Google 已經建議不要在該目錄中進行定義,而應當選擇 device 目錄)。device 目錄下根據公司名以及產品名分為二級目錄,這一點我們在概述中已經提到過。
通常,對於一個產品的定義通常至少會包括四個文件:AndroidProducts.mk,產品版本定義文件,BoardConfig.mk 以及 verndorsetup.sh。下面我們來詳細說明這幾個文件。
PRODUCT_MAKEFILES := $(LOCAL_DIR)/full_stingray.mk $(LOCAL_DIR)/stingray_emu.mk $(LOCAL_DIR)/generic_stingray.mk |
表 6. 產品版本定義文件中的變數及其說明
常量 | 說明 |
---|---|
PRODUCT_NAME | 最終用戶將看到的完整產品名,會出現在「關於手機」信息中。 |
PRODUCT_MODEL | 產品的型號,這也是最終用戶將看到的。 |
PRODUCT_LOCALES | 該產品支持的地區,以空格分格,例如:en_GB de_DE es_ES fr_CA。 |
PRODUCT_PACKAGES | 該產品版本中包含的 APK 應用程序,以空格分格,例如:Calendar Contacts。 |
PRODUCT_DEVICE | 該產品的工業設計的名稱。 |
PRODUCT_MANUFACTURER | 製造商的名稱。 |
PRODUCT_BRAND | 該產品專門定義的商標(如果有的話)。 |
PRODUCT_PROPERTY_OVERRIDES | 對於商品屬性的定義。 |
PRODUCT_COPY_FILES | 編譯該產品時需要拷貝的文件,以「源路徑 : 目標路徑」的形式。 |
PRODUCT_OTA_PUBLIC_KEYS | 對於該產品的 OTA 公開 key 的列表。 |
PRODUCT_POLICY | 產品使用的策略。 |
PRODUCT_PACKAGE_OVERLAYS | 指出是否要使用默認的資源或添加產品特定定義來覆蓋。 |
PRODUCT_CONTRIBUTORS_FILE | HTML 文件,其中包含項目的貢獻者。 |
PRODUCT_TAGS | 該產品的標籤,以空格分格。 |
通常情況下,我們並不需要定義所有這些變數。Build 系統的已經預先定義好了一些組合,它們都位於 /build/target/product 下,每個文件定義了一個組合,我們只要繼承這些預置的定義,然後再覆蓋自己想要的變數定義即可。例如:
# 繼承 full_base.mk 文件中的定義 $(call inherit-product, $(SRC_TARGET_DIR)/product/full_base.mk) # 覆蓋其中已經定義的一些變數 PRODUCT_NAME := full_lt26 PRODUCT_DEVICE := lt26 PRODUCT_BRAND := Android PRODUCT_MODEL := Full Android on LT26 |
在配置了以上的文件之後,便可以編譯出我們新添加的設備的系統鏡像了。
首先,調用「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 系統設置了很多的編譯環境變數。要編譯一個模塊,只要在編譯之前根據需要設置這些變數然後執行編譯即可。它們包括:
表 7. 編譯類型的說明
名稱 | 說明 |
---|---|
eng | 默認類型,該編譯類型適用於開發階段。當選擇這種類型時,編譯結果將:
|
user | 該編譯類型適合用於最終發布階段。當選擇這種類型時,編譯結果將:
|
userdebug | 該編譯類型適合用於 debug 階段。該類型和 user 一樣,除了:
|
表 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 文件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 的靜態庫
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!
參考資料
學習
你的讚賞是我堅持原創的動力
讚賞共 0 人讚賞推薦閱讀:
※Android四大組件之三(Content Provider)
※Android安卓系統怎麼才能不卡
※Android使用ViewPager實現左右循環滑動及輪播效果
※目前進行的工作日誌
※Unity 關於安卓和各平台讀寫本地json文件,WWW讀取本地文件,Unity各路徑API目前較完整的詳解