Android構建系統

在如下位置描述了Android構建系統:<https://source.android.com/setup/build>
你可使用build/envsetup.sh設置一個"便利環境"來處理Android源代碼。在當前shell環境中執行source build/envsetup.sh後,你能夠輸入hmm做爲已定義函數的列表,這些函數有助於與源進行交互。html

概述

構建系統使用一些預設的環境變量和一系列"make"文件來構建Android系統並準備將其部署到平臺上。java

子項目的Android構建文件叫作Android.bp和Android.mk。linux

整個存儲庫的源樹頂部只有一個名爲"Makefile"的官方文件。你設置了一些環境變量,而後鍵入"make"或僅鍵入m來構建內容。你能夠在make命令行(其餘目標)中添加一些選項以打開詳細輸出或執行其餘操做。android

構建輸出放置在out/hostout/target中。out/host下的東西是爲你的主機平臺(臺式機)編譯的東西。最終在out/target/product/<platform-name>下的內容會以特定方式被放到目標設備(或模擬器)。shell

目錄out/target/product/<platform-name>/obj用於暫存"object"文件,這些文件是用於構建最終程序的中間二進制映像。實際落在目標文件系統中的內容存儲在out/target/product/<platform-name>下的root,system和data目錄中。一般,這些文件捆綁成名爲system.img,ramdisk.img和userdata.img的映像文件。緩存

這與大多數Android設備上使用的文件系統分區相匹配。app

一些細節

使用什麼工具

在構建期間,你將使用soong,ninja和'make'控制構建步驟。主機工具鏈(編譯器,連接器和其餘工具)和庫將用於構建將在主機上運行的程序和工具。使用不一樣的工具鏈來編譯將在目標(嵌入式板,設備或模擬器)上運行的C和C++代碼。這一般是在X86平臺上運行的"交叉"工具鏈,但會爲其餘平臺(最多見的是ARM)生成代碼。內核被編譯爲獨立的二進制文件(它不使用程序加載器或連接到任何外部庫)。其餘項目,例如本機程序(例如init或工具箱),守護程序或庫,將連接到仿生庫或其餘系統庫。框架

你將使用Java編譯器和大量與Java相關的工具來構建大多數應用程序框架,系統服務和Android應用程序自己。最後,使用工具打包應用程序和資源文件,並建立能夠安裝在設備上或與模擬器一塊兒使用的文件系統映像。函數

告訴系統Java工具鏈在哪裏

在構建任何東西以前,你必須告訴Android構建系統Java SDK的位置。(安裝Java SDK是構建的先決條件)。
經過設置JAVA_HOME環境變量來執行此操做。工具

指定要構建的內容

爲了決定要構建什麼以及如何構建,構建系統要求設置一些變量。能夠從同一源代碼樹構建具備不一樣軟件包和選項的不一樣產品。能夠經過帶有"make"變量聲明的文件來設置控制此變量的變量,也能夠在環境中指定該變量。

設備供應商能夠建立定義文件,以描述特定板或特定產品要包含的內容。定義文件稱爲:buildspec.mk,它位於頂級源目錄中。你能夠手動編輯此選項以對選擇進行硬編碼。

若是你有一個buildspec.mk文件,它會設置構建所需的全部make變量,而你沒必要弄亂選項。

指定選項的另外一種方法是設置環境變量。構建系統具備一種至關華麗的方法來爲你管理這些選項。

要設置你的構建環境,你須要在build/envsetup.sh中加載變量和函數。經過將文件source到你的shell環境中來執行此操做,以下所示:

. build/envsetup.sh

你能夠在此時輸入"help"(或"hmm")以查看一些實用程序功能,這些功能可使你更輕鬆地使用源代碼。

要選擇要構建的一組東西以及要構建的項目,請使用"choosecombo"功能或"lunch"功能。"choosecombo"將一步一步地引導你完成必須選擇的不一樣項目,而"lunch"則容許你選擇一些預設組合。

必須爲構建定義的項目是:

• 產品("generic"或某些特定的芯片或平臺名稱)
• 構建變體("user","userdebug"或"eng")
• 是否在模擬器上運行("true"或"false")
• 構建類型("發佈"或"調試")

這些不一樣的構建變體的說明位於http://source.android.com/porting/build_system.html#androidBuildVariants

在這篇博客文章中,從用戶角度很好地描述了構建過程:http://blog.codepainters.com/2009/12/18/first-android-platform-build/

實際構建系統

設置完畢後,實際上就可使用"make"命令來構建系統。

要構建整個內容,請在頂層目錄中運行"make"。若是要構建全部內容(例如,第一次進行構建),則構建將花費很長時間。

構建技巧

查看用於構建軟件的實際命令

在"make"行上使用"showcommands"目標:

make -j4 showcommands

能夠將其與另外一個make目標結合使用,以查看該構建的命令。也就是說,"showcommands"自己不是目標,而只是指定構建的修飾符。

在上面的示例中,-j4與showcommands選項無關,而且用於執行4個並行運行的make會話。

制定目標

這是可用於構建系統不一樣部分的不一樣make目標的列表:

make sdk - 構建屬於SDK的工具(adb,fastboot等)
make snod - 從當前軟件二進制文件構建系統映像
make services
make runtime
make droid - make droid是正常的構建。
make all - 構建全部內容,不管是否包含在產品定義中
make clean - 刪除全部構建的文件(準備進行新的構建)。與rm -rf out/<configuration>/相同
make modules - 顯示能夠構建的子模塊的列表(全部LOCAL_MODULE定義的列表)
make <local_module> - 構建一個特定的模塊(請注意,這與目錄名稱不一樣。它是Android.mk文件中的LOCAL_MODULE定義)
make clean <local_module> - 清理特定模塊
make bootimage TARGET_PREBUILT_KERNEL=/path/to/bzImage - 使用自定義bzImage建立新的啓動映像

輔助宏和函數

當你獲取envsetup.sh時,會安裝一些輔助宏和函數。它們記錄在envesetup.sh的頂部,可是這裏是其中一些信息:

hmm - 列出幫助內容
lunch <product_name>-<build_variant> - 加載產品和構建變體配置(驅動程序文件,設備特定的配置等)。
tapas [<App1> <App2> ...] [arm | x86 | mips | armv5 | arm64 | x86_64 | mips64] [eng | userdebug | user] - 該命令用於構建未捆綁的應用程序。若是你不提供構建版本,則默認爲eng。
provision - 燒錄具備全部必需分區的設備。選項將傳遞給fastboot。

構建宏和函數

croot - 將目錄更改成樹的頂部
m - 從樹的頂部執行"make"(即便當前目錄位於其餘位置)
mm - 構建當前目錄中的全部模塊
mmm <dir1> ... - 構建提供的目錄中的全部模塊,但不構建其依賴項。要限制正在構建的模塊,請使用如下語法:mmm dir /:target1,target2
mma - 構建當前目錄中的全部模塊及其依賴項。
mmma <dir1> ... - 構建提供的目錄中的全部模塊及其依賴項。

Grep宏和函數

cgrep <PATTERN> 在全部本地C/C++文件上顯示。
ggrep <PATTERN> 在全部本地Gradle文件上顯示。
jgrep <PATTERN> 在全部本地Java文件上使用。
resgrep <PATTERN> 在全部本地res/*。xml文件上進行鎖定。
mangrep <PATTERN> 在全部本地AndroidManifest.xml文件上進行掃描。
mgrep <PATTERN> 在全部本地Makefile文件上進行抓緊。
sepgrep <PATTERN> 在全部本地Sepolicy文件上進行鎖定。
sgrep <PATTERN> 在全部本地源文件上進行抓緊。
godir <文件名> 轉到包含文件的目錄

加快構建

你能夠在make中使用'-j'選項,以同時啓動多個make執行線程。

根據個人經驗,你應該指定比計算機上具備處理器多2個線程。若是你有2個處理器,請使用'make -j4';若是它們是超線程的(意味着你有4個虛擬處理器),請嘗試'make -j6。

你還能夠指定使用"ccache"編譯器緩存,這將在你首次構建內容後加快處理速度。爲此,請在你的shell命令行中指定"export USE_CCACHE = 1"。(請注意,ccache包含在存儲庫的預構建部分中,沒必要單獨安裝在主機上。)

對於最新的Android版本,沒有預建的ccache,而且須要根據此commit,使用CCACHE_EXEC將路徑設置爲本地二進制文件。

僅構建單個程序或模塊

若是使用build/envsetup.sh,則可使用某些已定義的函數來僅構建樹的一部分。使用"mm"或"mmm"命令執行此操做。

"mm"命令在當前目錄(和子目錄,我相信)中進行填充。使用"mmm"命令,你能夠指定目錄或目錄列表,而後將其構建。
要安裝你的更改,請從樹的頂部開始"make snod"。"make snod"從當前的二進制文件構建新的系統映像。

設置模塊特定的構建參數

Android系統中的某些代碼能夠按照其構建方式進行自定義(與構建變體以及發行版和調試選項分開)。你能夠設置變量來控制各個構建選項,方法是在環境中進行設置,或者將其直接傳遞給"make"(或稱爲"make"的"m ..."函數)。

例如,能夠經過設置INIT_BOOTCHART變量來構建支持bootchart日誌記錄的'init'程序。(有關爲何你可能要執行此操做,請參見在Android上使用Bootchart。)

你可使用如下任一方法來完成:

touch system/init/init.c
export INIT_BOOTCHART=true
make

或者

touch system/init/init.c
m INIT_BOOTCHART=true

Makefile技巧

這些是你能夠在本身的Android.mk文件中使用的東西的一些提示。

創建助手功能

在文件build/core/definitions.mk中定義了不少構建幫助器函數

嘗試列出詳盡的清單。grep define build/core/definitions.mk

經過如下方式調用它們:或不帶參數:$(call <FUNCTION>, <PARAM-1>, <PARAM-2>)$(call <FUNCTION>)

如下是一些可能有趣的功能:

print-vars - 打印全部Makefile變量,以進行調試(而不是它們的值)。
emit-line - 在構建期間將線輸出到文件
dump-words-to-file - 將單詞列表輸出到文件
copy-one-file - 將文件從一個地方複製到另外一個地方(目標是否在目的地?)
all-subdir-makefiles - 從當前目錄開始遞歸調用全部文件(用法:)。Android.mkinclude $(調用all-subdir-makefiles)

構建變量

$(ANDROID_BUILD_TOP) - AOSP文件系統根文件夾
$(LOCAL_PATH)- 一般爲當前目錄。由開發人員/用戶在每一個Android.mk文件中設置。
它會在文件樹下的其餘文件中被覆蓋(例如,使用時)。Android.mk include $(call all-subdir-makefiles)

解決方法:

SAVED_LOCAL_PATH := $(call my-dir)
 include $(call all-subdir-makefiles)
 LOCAL_PATH:= $(SAVED_LOCAL_PATH)

將文件直接添加到輸出區域

你可使用add-prebuilt-files函數將文件直接複製到輸出區域,而無需構建任何內容。

prebuilt/android-arm/gdbserver/Android.mk中提取的如下行將文件列表複製到輸出區域的EXECUTABLES目錄中:

$(call add-prebuilt-files, EXECUTABLES, $(prebuilt_files))

添加新程序以進行構建

將新程序添加到Android源代碼樹的步驟

• 在"外部"下創建目錄
• 例如ANDROID/external/myprogram
• 建立你的C/cpp文件。
• 建立Android.mk做爲external/ping/Android.mk的克隆
• 更更名稱ping.c和ping以匹配你的C/cpp文件和程序名稱
• 在external/zlib以後將ANDROID/build/core/main.mk中的目錄名稱添加爲external/myprogram(至少從Android 7.1起再也不須要)
• 從源代碼樹的根開始
• 你的文件將顯示在構建輸出區域和系統映像中。
• 若是要將文件單獨複製到目標(而不執行整個安裝),則能夠從構建輸出區域的out/target/product/...下複製文件。

有關更多詳細信息,請參見http://www.aton.com/android-native-development-using-the-android-open-source-project/

構建內核

內核是普通Android構建系統的"外部"(實際上,默認狀況下,Android Open Source Project中不包括該內核)。可是,AOSP中有一些用於構建內核的工具。若是要構建內核,請今後頁面開始:http : //source.android.com/source/building-kernels.html

若是你正在爲模擬器構建內核,則可能還須要查看:http : //stackoverflow.com/questions/1809774/android-kernel-compile-and-test-with-android-emulator

並且,Ron M寫道(在2012年5月21日在android-kernel郵件列表中):

這篇文章很老-但就AOSP而言,什麼都沒有改變,因此若是有人對QEMU感興趣並遇到此問題,請執行如下操做:
實際上,爲AOSP提供的QEMU目標構建內核是一種不錯的,更短的方法:

  1. cd到你的內核源目錄(僅金魚2.6.29在模擬器中可用)
  2. $ {ANDROID_BUILD_TOP} /external/qemu/distrib/build-kernel.sh -j = 64 --arch = x86 --out = $ YourOutDir
  3. emulator -kernel ${YourOutDir}/kernel-qemu # run emulator:

步驟#2 調用toolbox.sh包裝程序腳本,該腳本可在SSE禁用gcc警告的狀況下工做-在GCC <4.5時發生(如AOSP預先構建的X86工具鏈中同樣)。

若是它是X86,該腳本會添加"-mfpmath = 387 -fno-pic",從而消除了上面看到的編譯錯誤。

爲了更好地控制構建過程,可使用"toolbox.sh"包裝器並設置一些其餘內容,而無需修改腳本文件。

下面是構建相同模擬器的示例:

# Set arch
export ARCH=x86
# Have make refer to the QEMU wrapper script for building android over x86 
(eliminates the errors listed above)
export 
CROSS_COMPILE=${ANDROID_BUILD_TOP}/external/qemu/distrib/kernel-toolchain/android-kernel-toolchain-
# Put your cross compiler here. I am using the AOSP prebuilt one in this example
export 
REAL_CROSS_COMPILE=${ANDROID_BUILD_TOP}/prebuilt/linux-x86/toolchain/i686-android-linux-4.4.3/bin/i686-android-linux-
# Configure your kernel - here I am taking the default goldfish_defconfig
make goldfish_defconfig
# build
make -j64
# Run emulator:
emulator -kernel arch/x86/boot/bzImage -show-kernel

這適用於2.6.29 goldfish 分支。

譯自https://elinux.org/Android_Build_System

相關文章
相關標籤/搜索