最近研究了下Android的編譯系統(tǒng),下面結(jié)合編譯我們自己的產(chǎn)品mobot來(lái)對(duì)整個(gè)編譯系統(tǒng)進(jìn)行必要的介紹,方便大家今 后對(duì)默認(rèn)編譯的修改。
先列出幾個(gè)覺(jué)得重要的Make文件:
build/buildspec.mk
build/envsetup.sh
build/core/main.mk
build/core/envsetup.mk
build/config.mk
總的來(lái)說(shuō),Android以模塊(module/package)的形式來(lái)組織各個(gè)系統(tǒng)的部件,每個(gè)模塊(module/package)的目錄下都會(huì)有一個(gè)Android.mk。所謂module就是指系統(tǒng)的Native Code,而相對(duì)于Java寫(xiě)的Android application稱(chēng)為package。
產(chǎn)生相應(yīng)的Rules,生成image 5
Makefile的主要流程
以下主要流程都 在build/core/main.mk里 安排。
l 初始化相關(guān)的參數(shù)設(shè)置(buildspec.mk、envsetup.mk、config.mk)
l 檢測(cè)編譯環(huán)境和目標(biāo)環(huán)境
l 決定目標(biāo)product
l 讀取product的配置信息及目標(biāo)平臺(tái)信息
l 清除輸出目錄
l 檢查版本號(hào)
l 讀取Board的配置
l 讀取所有Module的配置
l 根據(jù)配置產(chǎn)生必要的規(guī)則(build/core/Makefile)
l 生成image
初始化參數(shù)設(shè)置
在 main.mk 里,簡(jiǎn)單設(shè)置 幾個(gè)主要編譯路徑的變量后,來(lái)到config.mk:
——————————————config.mk——————————————
其中設(shè)置了源文件的一系列路徑,包括頭文件、庫(kù)文件、服務(wù)、API已經(jīng)編譯工具的路徑。(前36行)
從40行開(kāi)始,定義一些編譯模塊的生成規(guī)則:
這里面除了第一個(gè)CLEAR_VARS外,其他都對(duì)應(yīng)的一種模塊的生成規(guī)則,每一個(gè)module都會(huì)來(lái)include其中某個(gè)來(lái)生成目標(biāo)模塊。
例如:
Camera模塊的makefile里( Android.mk )就包含了其中的一種生成規(guī)則BUILD_PACKAGE:
也就是Camera會(huì)按照package.mk里的生成規(guī)則去生成目標(biāo)模塊。
回到config.mk,接著會(huì)嘗試讀取buildspec.mk的設(shè)置:
如同注釋所說(shuō),會(huì)嘗試查找 buildspec.mk ,如果文件不 存在會(huì)自動(dòng)使用環(huán)境變量的設(shè)置,如果仍然未定義,會(huì)按arm默認(rèn)的設(shè)置去build。
這里的buildspec.mk可以自己創(chuàng)建,也可以將原先build/下的buildspec.mk.default直接命名為buildspec.mk并移到根目錄。
實(shí)際上,buildspec.mk配置都被屏蔽了,我們可以根據(jù)需要直接打開(kāi)和修改一些變量。在這里我們可以加入自己的目標(biāo)產(chǎn)品信息:
ifndef TARGET_PRODUCT
TARGET_PRODUCT:=mobot
endif
以及輸出目錄設(shè)置:
OUT_DIR:=$(TOPDIR)mobot
讀取Product的設(shè)定
回到config.mk,接著進(jìn)行全局變量設(shè)置,進(jìn)入envsetup.mk:
——————————————envsetup.mk——————————————
里面的大部分函數(shù)都在build/envsetup.sh中定義。
首先,設(shè)置版本信息,(11行)在build/core/version_defaults.mk中具體定義平臺(tái)版本、SDK版本、Product版本,我們可以將BUILD_NUMBER作為我們產(chǎn)品mobot的version信息,當(dāng)然,也可以自定義一個(gè)版本變量。
回到envsetup.mk,接著設(shè)置默認(rèn)目標(biāo)產(chǎn)品(generic),這里由于我們?cè)赽uildspec.mk里設(shè)置過(guò)TARGET_PRODUCT ,事實(shí)上這個(gè) 變量值為mobot。
然后讀取product的設(shè)置(41行), 具體實(shí)現(xiàn)在build/core/ product_config.mk 中,進(jìn)而進(jìn)入product.mk,從build/target/product/ AndroidProducts.mk 中讀出PRODUCT_MAKEFILES,這些makefile各自獨(dú)立定義product,而我們的產(chǎn)品mobot也應(yīng)添加一個(gè)makefile文件mobot.mk。在mobot.mk中我們可以加入所需編譯的PRODUCT_PACKAGES。
下面為HOST配置信息及輸出目錄,最后打印相關(guān)信息:
讀取BoardConfig
接著回到config.mk,(114行)這 里會(huì)搜索所有的BoardConfig.mk,主要有以下兩個(gè)地方:
$(SRC_TARGET_DIR)/board/$(TARGET_DEVICE)/BoardConfig.mk
vendor/*/$(TARGET_DEVICE)/BoardConfig.mk
這里的TARGET_DEVICE就是mobot,就是說(shuō)為了定義我們自己的產(chǎn)品mobot,我們要在build/target/board下添加一個(gè)自己的 目錄mobot用來(lái)加載自己 的board配置。
在BoardConfig.mk中會(huì)決定是否編譯bootloader、kernel等信息。
讀取所有Module
結(jié)束全局變量配置后,回到main.mk,馬上對(duì)編譯工具及版本進(jìn)行檢查,錯(cuò)誤便中斷編譯。
142行,包含文件 definitions.mk ,這里面定義了許多變量和函數(shù)供main.mk使用。main.mk第446行,這里會(huì)去讀取所有的Android.mk文件:
include $(ONE_SHOT_MAKEFILE)
這個(gè) ONE_SHOT_MAKEFILE 是在前面提到 的mm(envsetup.mk)函數(shù)中賦 值的:
ONE_SHOT_MAKEFILE=$M make -C $T files $@
而M=$(findmakefile),最終實(shí)現(xiàn)在:
回到main.mk,最終將遍歷查找到的所有子目錄下的Android.mk的路徑保存到subdir_makefiles變量里(main.mk里的470行):
我們?cè)趐ackage/apps下每個(gè)模塊根目錄都能看到Android.mk,里面會(huì)去定義當(dāng)前本地模塊的Tag: LOCAL_MODULE_TAGS ,Android會(huì)通過(guò)這個(gè)Tag來(lái)決定哪些本地模塊會(huì)編譯進(jìn)系統(tǒng),通過(guò)PRODUCT和LOCAL_MODULE_TAGS來(lái)決定哪些應(yīng)用包會(huì)編譯進(jìn)系統(tǒng)。( 前面說(shuō) 過(guò),你也能通過(guò)buildspec.mk來(lái) 制定你要編譯進(jìn)系統(tǒng)的模塊 )
這個(gè)過(guò) 程在mian.mk的445行開(kāi)始,最后需要編譯的模塊路徑打包到ALL_DEFAULT_INSTALLED_MODULES (602行):
產(chǎn)生相應(yīng)的Rules,生成image
所有需要配置的準(zhǔn)備工作都已完成,下面該決定如何生成image輸出文件了,這一過(guò)程實(shí)際上在build/core/Makefile中處理的。
這里定義各種img的生成方式,包括ramdisk.img、userdata.img、system.img、update.zip、recover.img等。具體對(duì)應(yīng)的rules可以參考下圖:
http://p.blog.csdn.net/images/p_blog_csdn_net/yili_xie/EntryImages/20091214/make%20goals.png
當(dāng)Make include所有的文件,完成對(duì)所有make文件的解析以后就會(huì)尋找生成 對(duì)應(yīng)目標(biāo) 的規(guī)則,依次生成它的依賴(lài),直到 所有滿足的模塊被編譯好,然后使用相應(yīng)的工具打包成相應(yīng)的img。
具體make操作:
完整編譯
我們?cè)诟夸浵螺斎雖ake命令即可開(kāi)始完全編譯。這個(gè)命令實(shí)際編譯生成的默認(rèn)目標(biāo)是droid:
也就是說(shuō),大家敲入make實(shí)際上執(zhí)行的make droid。而接下來(lái)大家看看main.mk文件里最后面的部分,會(huì)有很多偽目標(biāo),如sdk、clean、clobber等,這些在默認(rèn)的make droid的命令下是不會(huì)執(zhí)行的。我們可以在make后加上這些標(biāo)簽來(lái)單獨(dú)實(shí)現(xiàn)一些操作。如:輸入make sdk 將會(huì)生成該版本對(duì)應(yīng)的SDK,輸入make clean會(huì)清除上次編譯的輸出。
模塊編譯
有時(shí)候我們只修改了某一個(gè)模塊,希望能單獨(dú)編譯這個(gè)模塊而不是重新完整編譯一次,這時(shí)候我們要用到 build/envsetup.sh中提供的幾個(gè)bash的幫助函數(shù)。
在 源代碼根目錄下執(zhí)行:
. build/envsetup.sh(.后面有空格)
這 樣大家相當(dāng)于多了幾個(gè)可用的命令。
這 時(shí)可以用help命令查看幫助信息:
其中對(duì)模塊編譯有幫助的是tapas、m、mm、mmm這幾個(gè)命令。
1、 tapas——以交互方式設(shè)置build環(huán)境變量。
輸入:tapas
第一步,選擇目標(biāo)設(shè)備:
例如 我們選擇1
第二步,選擇代碼格式:
我們選擇1
第三步,選擇產(chǎn)品平臺(tái):
注意:這里,Google源代碼里默認(rèn)是generic,而我們針對(duì)自己的產(chǎn)品應(yīng)修改成mobot
具體在build/envsetup.sh里的函數(shù)chooseproduct()中對(duì)相應(yīng)代碼進(jìn)行修 改。
2、 m、mm、mmm使用獨(dú)立模塊的make命令。
幾個(gè)命 令的功能使用help命令查看。
舉個(gè)例 子,我們修改了Camera模塊的代碼,現(xiàn) 在需要重新單獨(dú)編譯這一塊,這時(shí)可以使用mmm命令,后面跟指定模塊的路徑(注意是模塊的根目錄)。
具體如 下:
mmm packages/apps/Camera/
為了可 以直接測(cè)試改動(dòng),編譯好后需要重新生成system.img
可以執(zhí) 行:make snod
單獨(dú)編譯image文件
一般我 們完整編譯后,會(huì)生成三個(gè)重要的image文 件:ramdisk.img、system.img和userdata.img。當(dāng)然我們可以分開(kāi)單獨(dú)去編譯 這三個(gè)目標(biāo):
make ramdisk —— ramdisk.img
make userdataimage —— userdata.img
make systemimage —— system.img
一些疑問(wèn)和解答:
1) 什么是recovery.img?
顧名思義,recovery.img是為了恢復(fù)系統(tǒng)的,相對(duì)于普通的boot.img,recovery.img多了一些圖片文件(恢復(fù)時(shí)界面的背景)、/sbin/recovery/目錄(跟 恢復(fù)有關(guān)的二進(jìn)制文件),一 些初始化文件也不相同(init.rc、init.goldfish.rc、default.prop)
這就是為什么啟 動(dòng)恢復(fù)模式時(shí)會(huì)進(jìn)入類(lèi)似文本界面而不是圖形界面。
將recovery.img文件復(fù)制到SD卡中,進(jìn)入shell下輸入:
mount -a
flash_image recovery /sdcard/recovery.img
若提示“no space on device”,可用fastboot模式刷
fastboot erase recovery
fastboot flash recovery recovery.img
在關(guān)機(jī)狀態(tài)下按home+power鍵進(jìn)入recovery模式,根據(jù)選項(xiàng)選擇需要的操作。
2) make sdk和make droid編譯有什么不同?
make sdk:
其實(shí),執(zhí)行make sdk,編譯后會(huì)在目錄out/host/linux-x86里生成sdk目錄,這個(gè)sdk和官方下載的sdk包是一樣的,可以直接使用。
make droid:
實(shí)際上droid就是默認(rèn)的生成目標(biāo),和直接敲make是一樣的,都會(huì)完整編譯出目標(biāo)image文件,但不會(huì)編譯出sdk。
3) 我們將默認(rèn)產(chǎn) 品改為mobot,那我怎么編譯原先的generic?
其實(shí),無(wú)論編譯哪個(gè)目標(biāo)產(chǎn)品版本,只要產(chǎn)品相關(guān)設(shè)置存在,都可以直接在編譯時(shí)加上目標(biāo)產(chǎn)品名來(lái)編譯。會(huì)在out/target/product/下生成對(duì)應(yīng)的 產(chǎn)品輸出目錄,如:要編譯generic版本:
make TARGET_PRODUCT := generic
原帖:http://bimoshi.blog.163.com/blog/static/14613297201022233711527/