在如下位置描述了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/host
和out/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應用程序自己。最後,使用工具打包應用程序和資源文件,並建立能夠安裝在設備上或與模擬器一塊兒使用的文件系統映像。函數
在構建任何東西以前,你必須告訴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> ...
- 構建提供的目錄中的全部模塊及其依賴項。
• 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
這些是你能夠在本身的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/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目標構建內核是一種不錯的,更短的方法:
步驟#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 分支。