官术网_书友最值得收藏!

第2章 編譯結構和各種構建

2.1 Android的系統構建

2.1.1 編譯環境要求

Android的編譯需要在Linux主機準備以下幾個方面的支持。

● 目標機編譯工具(交叉編譯工具鏈)。

● 主機編譯工具(x86主機的編譯工具)。

● Java環境(包括Java編譯和運行環境)。

● 腳本運行環境。

Android的源代碼包中自帶了主要的編譯工具,也就是目標機的編譯工具,路徑通常為:prebuilt/linux-x86/toolchain/。

其中Linux-x86指的是Linux環境的x86主機環境(64位的機器對應目錄為linux-x86_64),toolchain目錄中的內容是GCC交叉編譯工具鏈。由此,Android對目標機內容的編譯,使用的就是這些工具,不需要使用主機自己安裝的工具。

Android編譯針對主機環境的要求有Linux主機和JDK兩個方面,如表2-1所示。

表2-1 Android編譯針對主機環境的要求

在Android系統的編譯中,實際上只有Android 2.3及之后對JDK1.6的要求是強制性的,如果不具有JDK1.6環境,將無法成功編譯一些Java代碼。對于其他的限制,去掉編譯中由錯誤引起的中斷,在一定程度上可以繞過編譯的限制。

2.1.2 構建流程

Android的構建流程從根目錄下直接執行make命令來完成一個基本的編譯。實際上這是從Android開源代碼的根目錄(TOP)中的Makefile文件開始,是Linux中使用make機制的標準流程。

Android系統編譯流程的片斷如下所示:

$ make
============================================
PLATFORM_VERSION_CODENAME=REL
PLATFORM_VERSION=2.3.4
TARGET_PRODUCT=generic
TARGET_BUILD_VARIANT=eng
TARGET_SIMULATOR=
TARGET_BUILD_TYPE=release
TARGET_BUILD_APPS=
TARGET_ARCH=arm
HOST_ARCH=x86
HOST_OS=linux
HOST_BUILD_TYPE=release
BUILD_ID=GRJ22
============================================
# ……編譯過程
Finding NOTICE files: out/target/product/generic/obj/NOTICE_FILES/hash-
timestamp
Combining NOTICE files: out/target/product/generic/obj/NOTICE.html
Target system fs image: out/target/product/generic/obj/PACKAGING/
systemimage_intermediates/system.img
Install system fs image: out/target/product/generic/system.img
Installed file list: out/target/product/generic/installed-files.txt

在編譯開始的過程中,TARGET_PRODUCT是編譯的主要環境變量。在開始編譯的時候,TARGET_PRODUCT,TARGET_ARCH等內容是從環境變量得到的,如果需要更改它們的內容,可以直接使用export導出環境變量,但正規的方式是通過Android的編譯系統進行配置。

Android TOP目錄中的Makefile內容如下所示:

### DO NOT EDIT THIS FILE ###
include build/core/main.mk
### DO NOT EDIT THIS FILE ###

TOP目錄中的Makefile也就是build/core/root.mk。在repo sync的階段,它被復制成TOP目錄的Makefile。這是因為在Android的代碼倉庫管理文件.repo/manifest.xml中包含了如下的內容:

  <project path="build" name="platform/build">
  <copyfile src="core/root.mk" dest="Makefile" />
  </project>

此時表示的就是將build/core/root.mk復制為TOP目錄的Makefile。

根據這個Makefile的內容,實際上使用的編譯文件是build/core/目錄中的main.mk文件,其中的一個片斷如下所示:

.PHONY: droid
DEFAULT_GOAL := droid
$(DEFAULT_GOAL):

這是基于Linux標準的Make機制,droid實際上就是默認情況的“Make目標”,直接進行Make的時候,使用的就是droid目標。

在main.mk文件中,還定義另外幾個重要的目標,使用這些目標可以獲得一些額外效果,例如make docs表示生成文檔。

其他的目標如下所示。

● ramdisk:生成內存盤映像。

● bootimage:生成啟動映像。

● systemimage:生成系統映像。

● userdataimage:生成用戶數據映像。

● apps_only:僅生成應用程序。

● docs:生成文檔,生成的文檔和SDK中的文檔類似。

● clean:清除目標,實際上只是刪除out目錄。

除此之外,showcommands也是一個有用的輔助目標,可以列出編譯時詳細執行的各個命令。

提示:showcommands和編譯目標結合使用,獲得具體一個編譯過程中執行的命令,然后可以在命令行單獨運行這些命令。

如果在32位的主機上編譯Android 2.3以后的系統,在編譯的開始將不能通過編譯工具的檢查,錯誤如下所示:

Checking build tools versions...
build/core/main.mk:76:
****************************************************
build/core/main.mk:77: You are attempting to build on a 32-bit system.
build/core/main.mk:78: Only 64-bit build environments are supported beyond
froyo/2.2.
build/core/main.mk:79:
****************************************************
build/core/main.mk:80: *** stop.  Stop.

此時實際上進行了一個強行的中斷,實際的錯誤沒有嚴重到不能進行編譯的程度。更改build/core/main.mk,注釋掉引發stop的一行,就可以進行編譯了。

除此之外,在源代碼中,有較少的部分和主機的位數(32位或64位)相關。在Android 2.3中,external/clearsilver/工程中的幾個Android.mk有相關的定義,其中的幾個LOCAL_CFLAGS和LOCAL_LDFLAGS被增加了-m64定義。將這幾個定義去除,就可以在32位環境中編譯通過了。

手動在目標文件系統中添加了內容,需要通過手動制作得到文件系統映像。例如,默認情況下制作yaffs2格式的映像文件的方法如下所示:

$./out/host/linux-x86/bin/mkyaffs2image -f out/target/product/generic/system
    out/target/product/generic/system.img
$./out/host/linux-x86/bin/mkyaffs2image -f out/target/product/generic/data
    out/target/product/generic/userdata.img

2.1.3 環境設置

默認情況下的Make不一定需要環境設置也可以編譯。但是設置環境可以方便開發和有選擇地進行編譯,方法如下所示:

$ . build/envsetup.sh

環境設置腳本envsetup執行后,可以直接在終端使用一些命令,如下所示。

● croot:切換到Android源代碼根目錄(TOP)。

● m:全系統編譯。

● mm:在一個目錄中編譯這個工程。

● mmm:編譯某個工程,參數為某個工程的路徑。

● cgrep:格式化查找C文件。

● jgrep:格式化查找Java文件。

● resgrep:格式化查找資源(xml)文件。

● godir:到包含某個文件的目錄。

設置完成環境變量后,幾個grep命令可以方便開發過程中的查找,它們實際上都是find和grep命令的結合。例如,格式化查找資源文件的方法如下:

$ resgrep "android:icon"

此時,將會列出包含“android:icon”字串的所有xml文件的相關行,并且用彩色表示行號和“android:icon”字串本身。

cgrep和jgrep的使用方法類似,前者將在擴展名為.c,.cc,.cpp和.h的文件中進行查找;后者在擴展名為.java的文件中進行查找。

2.1.4 系統構建結果

Android系統構建的結果全部在其根目錄的out目錄中,原始的各個工程的目錄不會改動,也不會生成內容。默認情況下生成的是名稱為generic的產品,表示“通用”的產品,可以用之運行仿真器。

Android編譯的結果包含以下的內容。

● 主機工具和其依賴的內容(out/host/)。

● 目標機程序(out/target/)。

● 目標機映像文件(out/target/product/<產品名稱>)。

out目錄的結構如下所示(帶有[]表示是目錄):

out/
|-- host                        [主機內容]
|   |-- common                  [主機的通用內容]
|   |   `-- obj
|   `-- linux-x86               [編譯所生成的主機Linux運行的工具]
|      |-- bin
|      |-- framework
|      |-- lib
|      `-- obj
`-- target                      [目標機內容]
  |-- common                   [目標機的通用內容]
  |   |-- R
  |   |-- docs
  |   `-- obj
  `-- product                  [目標機的產品目錄]
        `-- <TARGET_PRODUCT>

其中out/target/product目錄是目標產品的目錄,編譯的產品名稱由TARGET_PRODUCT宏表示。在默認的情況下使用generic作為目標產品的名稱。產品目錄結構如下所示(帶有[]表示是目錄):

out/target/product/generic/
|-- android-info.txt
|-- clean_steps.mk
|-- data                        [數據目錄]
|-- installed-files.txt
|-- obj                         [中間目標文件目錄]
|   |-- APPS                    [apk應用程序包]
|   |-- ETC                      [運行時配置文件]
|   |-- EXECUTABLES             [可執行程序]
|   |-- KEYCHARS
|   |-- NOTICE.html
|   |-- NOTICE.html.gz
|   |-- NOTICE_FILES
|   |-- PACKAGING
|   |-- SHARED_LIBRARIES        [動態庫(共享庫)]
|   |-- STATIC_LIBRARIES        [靜態庫(歸檔文件)]
|   |-- include
|   `-- lib
|-- previous_build_config.mk
|-- ramdisk.img                 根文件系統映像
|-- root                        [根文件系統目錄]
|-- symbols                     [符號的目錄]
|-- system                      [主文件系統目錄]
|-- system.img                  主文件系統映像
|-- userdata-qemu.img           QEMU的數據文件系統映像
`-- userdata.img                數據文件系統映像

系統構建的第一個步驟是“編譯”,將生成目錄obj中的內容,是目標機的各個目標。其中,EXECUTABLES為可執行程序目錄,SHARED_LIBRARIES為動態庫(*.so)目錄,STATIC_LIBRARIES為靜態庫(*.a)目錄,APPS為Android中的應用程序包(*.apk)目錄。

系統構建的第二個步驟是“安裝”,將生成root、system、data這3個目錄,分別是目標根文件系統、主文件系統和數據文件系統的目錄。

系統構建的第三個步驟是“生成映像”,將根據3 個文件系統目錄生成ramdisk.img、system.img和userdata.img。“生成映像”的步驟是一個簡單而機械的動作,只是根據3 個目錄生成3個映像,這樣目錄中的內容確定,映像文件的內容不會有變化。

主站蜘蛛池模板: 迭部县| 横峰县| 宁陵县| 胶南市| 缙云县| 香港| 蚌埠市| 山阴县| 玉溪市| 睢宁县| 盈江县| 仙居县| 陆良县| 杂多县| 灌阳县| 三江| 钟山县| 满洲里市| 栾城县| 岳池县| 苗栗县| 南京市| 古丈县| 银川市| 石狮市| 成都市| 山丹县| 梁山县| 成安县| 时尚| 大庆市| 达拉特旗| 香河县| 宁河县| 普格县| 新建县| 东阳市| 鄂伦春自治旗| 德安县| 星子县| 娄烦县|