在之前的公司參與項(xiàng)目開發(fā)的時(shí)候握截,雖然不負(fù)責(zé)系統(tǒng)固件編譯腳本的維護(hù),但為了工作的過程中更加的順利鹦付,便學(xué)習(xí)了一下Android的Build系統(tǒng)昆禽。本文就是對(duì)之前的學(xué)習(xí)做個(gè)總結(jié)蝗蛙。
- 系統(tǒng)版本:AOSP 5.1.1
1. Android Build 系統(tǒng)核心
Android Build系統(tǒng)的核心位于源碼目錄的build/core,該目錄下有幾十個(gè)mk文件以及若干個(gè)shell腳本醉鳖。
通常是使用下面的命令來編譯Android系統(tǒng):
$ . build/envsetup.sh
$ lunch
$ make
- envsetup.sh 文件的作用
該腳本會(huì)建立Android的編譯環(huán)境捡硅,該腳本中,定義了很多的shell命令盗棵,比如m壮韭、mm、mmm和lunch等命令就是在該腳本中定義的纹因,如圖:
除了命令的定義外喷屋,來看看運(yùn)行envsetup.sh腳本實(shí)際執(zhí)行的代碼:
可以看到,envsetup.sh有兩段代碼會(huì)執(zhí)行:
- 中間的6條add_lunch_combo命令的調(diào)用
- 結(jié)尾處的在device和vendor目錄下搜索vendorsetup.sh文件
這里以mako產(chǎn)品為例(對(duì)應(yīng)Nexus 4手機(jī))瞭恰,看一下device/lge/mako目錄下的vendorsetup.sh的內(nèi)容:
可以看到它仍然是調(diào)用了add_lunch_combo命令屯曹。這樣看來,build/core/envsetup.sh 除了定義shell命令外,就是執(zhí)行add_lunch_combo命令而已恶耽。它的定義也是在envsetup.sh中密任,如下:
add_lunch_combo命令的功能就是將調(diào)用該命令的參數(shù)存放到一個(gè)全局?jǐn)?shù)組變量LUNCH_MENU_CHOICES中。
執(zhí)行l(wèi)unch命令時(shí)的打印出來的菜單項(xiàng)正是這個(gè)數(shù)組的內(nèi)容偷俭。
envsetup.sh腳本定義了一些挺有用的命令浪讳,如下表:
命令 | 說明 |
---|---|
lunch | 用法:lunch <product_name>-<build_variant>,指定當(dāng)前編譯的產(chǎn)品 |
croot | 快速切換到源碼的根目錄涌萤,方便開始編譯 |
m | 編譯整個(gè)源碼淹遵,但是不用將當(dāng)前目錄切換到源碼的根目錄 |
mm | 編譯當(dāng)前目錄下的所有模塊,但不編譯它們的依賴模塊 |
mmm | 編譯指定目錄下的所有模塊负溪,但不編譯它們的依賴模塊 |
mma | 編譯當(dāng)前目錄下的所有模塊透揣,同時(shí)編譯它們的依賴模塊 |
mmma | 編譯指定目錄下的所有模塊,同時(shí)編譯它們的依賴模塊 |
cgrep | 對(duì)系統(tǒng)所有的C/C++文件執(zhí)行g(shù)rep命令 |
ggrep | 對(duì)系統(tǒng)中所有本地的gradle文件執(zhí)行g(shù)rep命令 |
jgrep | 對(duì)系統(tǒng)所有的Java文件執(zhí)行g(shù)rep命令 |
resgrep | 對(duì)系統(tǒng)中所有的res目錄下的XML文件執(zhí)行g(shù)rep命令 |
sgrep | 對(duì)系統(tǒng)中所有源文件執(zhí)行g(shù)rep命令 |
godir | 根據(jù)godir后的參數(shù)文件名在整個(gè)源碼目錄中查找笙以,然后切換到目錄 |
- lunch命令
lunch命令如果沒有參數(shù)淌实,系統(tǒng)會(huì)打印出產(chǎn)品列表供選擇冻辩。lunch命令也可以有參數(shù)猖腕,格式為:lunch <product_name>-<build_variant>
參數(shù)前半部分的 "product_name"必須是系統(tǒng)中已經(jīng)定義的產(chǎn)品名稱,后半部分的 "build_variant" 必須是 "eng"恨闪、"userdebug" 和 "user" 三者之一倘感。lunch命令的主要功能是根據(jù)用戶輸入或選擇的產(chǎn)品名來設(shè)置與之相關(guān)的環(huán)境變量。這些環(huán)境變量與產(chǎn)品編譯相關(guān)的咙咽,主要有下面三項(xiàng):
- TARGET_PRODUCT:對(duì)應(yīng) “product_name”;
- TARGET_BUILD_VARIANT:對(duì)應(yīng) "build_variant";
- TARGET_BUILD_TYPE:一般是release老玛。
- 與編譯相關(guān)的環(huán)境變量
執(zhí)行l(wèi)unch命令后,系統(tǒng)會(huì)打印出當(dāng)前配置所生成的環(huán)境變量钧敞。比如選擇 full_mako-eng后蜡豹,打印如下信息:
如上圖,這些環(huán)境變量將影響編譯過程溉苛,其中:
- PLATFORM_VERSION_CODENAME:表示平臺(tái)版本的名稱
- PLATFORM_VERSION:Android平臺(tái)的版本號(hào)
- TARGET_PRODUCT:所編譯的產(chǎn)品名稱
- TARGET_BUILD_VARIANT:表示編譯的產(chǎn)品的類型镜廉。可能的值有:eng愚战、user和userdebug
- TARGET_BUILD_TYPE:表示編譯的類型娇唯,可選的值是:release和debug。當(dāng)選擇debug版時(shí)寂玲,編譯系統(tǒng)會(huì)加入調(diào)試信息塔插,方便追蹤底層的bug。
- TARGET_BUILD_APPS:編譯Android系統(tǒng)時(shí)拓哟,該變量的值為NULL想许。使用Build系統(tǒng)編譯單個(gè)模塊時(shí),這個(gè)變量的值是所編譯模塊的路徑。
- TARGET_ARCH:表示編譯目標(biāo)的CPU架構(gòu)
- TARGET_ARCH_VARIANT:表示編譯目標(biāo)的CPU架構(gòu)版本
- TARGET_CPU_VARIANT:表示編譯目標(biāo)的CPU代號(hào)
- TARGET_2ND_ARCH:表示編譯目標(biāo)的第二CPU架構(gòu)
- TARGET_2ND_ARCH_VARIANT:表示編譯目標(biāo)的第二CPU架構(gòu)版本
- TARGET_2ND_CPU_VARIANT:表示編譯目標(biāo)的第二CPU的代號(hào)
- HOST_ARCH:表示編譯平臺(tái)的CPU架構(gòu)
- HOST_OS:表示編譯平臺(tái)使用的操作系統(tǒng)
- HOST_OS_EXTRA:編譯平臺(tái)操作系統(tǒng)的一些其他信息流纹,如內(nèi)核版本號(hào)谎砾,產(chǎn)品名稱和系統(tǒng)代號(hào)。
- BUILD_ID:BUILD_ID的值會(huì)出現(xiàn)在編譯的版本信息中捧颅,可以利用這個(gè)環(huán)境變量來定義公司特有的標(biāo)識(shí)
- OUT_DIR:指定編譯結(jié)果的輸出目錄
這些變量中景图,TARGET_2ND_ARCH、TARGET_2ND_ARCH_VARIANT和TARGET_2ND_CPU_VARIANT是Android 5.0新增加的碉哑。當(dāng)系統(tǒng)運(yùn)行在64位環(huán)境時(shí)挚币,考慮到還要支持32位的應(yīng)用,因此這里定義了兩套CPU架構(gòu).
- Build相關(guān)腳本的層次包含關(guān)系
下圖顯示了Build系統(tǒng)中編譯腳本的包含關(guān)系扣典,圖中不帶路徑的文件都位于build/core下妆毕,同時(shí) combo 目錄和 clang目錄也都位于 build/core目錄下,而device目錄位于系統(tǒng)源碼根目錄下贮尖。
Build系統(tǒng)會(huì)在其中的 $(TOP)/*/Android.mk笛粘、device/*/AndroidProducts.mk 和 device/*/BroadConfig.mk 三處地方引入具體的產(chǎn)品配置文件AndroidProduct.mk和BroadConfig.mk,以及各個(gè)模塊的編譯文件Android.mk湿硝。
combo目錄下的這些mk文件定義了gcc編譯器的版本和參數(shù)
clang目錄下的mk文件定義了LLVM的編譯器clang的版本和參數(shù)
下表羅列了Build系統(tǒng)各編譯腳本的簡(jiǎn)介:
文件名 | 說明 |
---|---|
main.mk | Android Build系統(tǒng)的主控文件薪前。該文件主要作用是包含進(jìn)其他mk文件,以及定義幾個(gè)最重要的編譯目標(biāo)关斜,如droid示括、sdk等。同事檢查編譯工具的版本痢畜,如make垛膝、gcc、javac等 |
help.mk | Android Build系統(tǒng)的幫助丁稀。文件中定義了一個(gè)名為help的編譯目標(biāo)吼拥,因此,輸入"make help"會(huì)打印出Build系統(tǒng)的使用說明 |
config.mk | Android Build系統(tǒng)的配置文件线衫,主要定義了許多常量來負(fù)責(zé)不同類型模塊的編譯凿可,定義編譯器參數(shù)并引入產(chǎn)品的BoardConfig.mk文件來配置產(chǎn)品參數(shù),同時(shí)也定義了一些編譯工具的路徑桶雀,如aapt矿酵、mkbootimg等 |
pathmap.mk | 給一些頭文件所在的目錄定義別名,將framework下的一些源碼目錄按類別組合在一起并定義了別名矗积,方便引用 |
buildspec.mk | 放在build目錄下的buildspec.mk文件可以定義產(chǎn)品編譯的參數(shù)全肮,但一般很少用它 |
envsetup.mk | 包含進(jìn)product_config.mk文件并根據(jù)其內(nèi)容設(shè)置編譯產(chǎn)品所需要的環(huán)境變量,如TARGET_PRODUCT棘捣、TARGET_BUILD_VARIANT等辜腺,并檢查這些變量值的合法性,同時(shí)還制定了各種編譯結(jié)果的輸出路徑 |
version_defaults.mk | 定義系統(tǒng)版本相關(guān)的變量 |
build_id.mk | 定義了環(huán)境變量BUILD_ID |
product_config.mk | 包含進(jìn)了系統(tǒng)中所有的AndroidProduct.mk文件,并根據(jù)當(dāng)前產(chǎn)品的配置文件來設(shè)置產(chǎn)品編譯相關(guān)的變量 |
product.mk | 定義product_config.mk文件中使用的各種函數(shù) |
combo/select.mk | 根據(jù)環(huán)境變量的設(shè)置评疗,指定對(duì)應(yīng)的系統(tǒng)和架構(gòu)中所使用的編譯工具路徑 |
clang/config.mk | 定義了LLVM編譯器clang在不同架構(gòu)下的路徑和參數(shù) |
dumpvar.mk | 打印輸出本次編譯的配置信息 |
cleanbuild.mk | 包含了源碼中所有CleanSpec.mk测砂,定義編譯目標(biāo)dataclean和installclean |
definitions.mk | 定義了大量Build系統(tǒng)中使用的函數(shù)。如果熟悉這些函數(shù)百匆,編寫產(chǎn)品配置文件將會(huì)更加得心應(yīng)手 |
dex_preopt.mk | 定義與dex優(yōu)化有關(guān)的路徑和參數(shù) |
pdk_config.mk | 編譯pdk的配置文件 |
post_clean.mk | 比較當(dāng)前系統(tǒng)的overlay目錄與上一次build時(shí)是否發(fā)生變化砌些,如果有變化,重新生成受影響模塊的資源定義文件R.java |
legacy_prebuilts.mk | 定義系統(tǒng)prebuild模塊列表 |
Makefile | 定義了系統(tǒng)最終編譯完成所需要的各種目標(biāo)和規(guī)則 |
Android Build系統(tǒng)中定義了大量的編譯變量加匈,通過改變這些編譯變量的值就能控制整個(gè)編譯過程和結(jié)果存璃。產(chǎn)品的配置文件實(shí)際上是對(duì)這些編譯變量賦值的腳本文件。學(xué)習(xí)Android Build系統(tǒng)很大程度上是在了解這些編譯變量的含義和用法雕拼。
2. Android的產(chǎn)品配置文件
產(chǎn)品配置文件的作用就是按照Build系統(tǒng)的要求纵东,將生成產(chǎn)品的各種image文件所需要的配置信息(如版本號(hào)、各種參數(shù)等)啥寇、資源(圖片偎球、字體、鈴聲等)辑甜、二進(jìn)制文件(apk衰絮、jar包、so庫等)有機(jī)地組織起來栈戳,同時(shí)進(jìn)行裁剪岂傲,加入或去掉一些模塊难裆。
Android的產(chǎn)品配置文件位于系統(tǒng)源碼根目錄的device目錄下子檀,但產(chǎn)品配置文件也可以放在vendor目錄下。這兩個(gè)目錄從Build系統(tǒng)的角度看沒有太大的區(qū)別乃戈,Build系統(tǒng)中搜尋產(chǎn)品配置的關(guān)聯(lián)文件時(shí)會(huì)同時(shí)在這兩個(gè)目錄進(jìn)行褂痰,但實(shí)際使用時(shí),往往會(huì)讓這兩個(gè)目錄配合使用症虑,通常產(chǎn)品配置文件放在device目錄下缩歪,而vendor目錄下則存放一些硬件的HAL庫。比如我給Nexus 4手機(jī)編譯固件之前谍憔,會(huì)從Google官方的相關(guān)站點(diǎn)下載適用于Nexus 4手機(jī)的不開源的那些HAL庫匪蝙、驅(qū)動(dòng),并將其放在系統(tǒng)源碼根目錄下并釋放出放在vendor目錄下习贫。
- 與mako相關(guān)的配置文件
通常device目錄下有以下幾個(gè)子目錄:
- common:用來存放各個(gè)產(chǎn)品通用的配置腳本逛球、文件等
- sample:一個(gè)產(chǎn)品配置的例子,寫一個(gè)新的產(chǎn)品配置時(shí)可以使用sample目錄下的文件作為模板
- google:用途不詳
- generic:存放的是用于模擬器的產(chǎn)品苫昌,包括x86颤绕、arm、mips架構(gòu)
- asus、lge奥务、samsung:分別代表宏碁物独、LG、三星3家公司氯葬。各家產(chǎn)品放在對(duì)應(yīng)的目錄下挡篓。
如果需要添加新的產(chǎn)品,可在device目錄下新建一個(gè)目錄帚称。
mako手機(jī)(Nexus 4) 是由LG代工的瞻凤,所以它的產(chǎn)品配置文件位于lge目錄下,內(nèi)容如下:
- mako:存放 Google Nexus4(mako) 的產(chǎn)品配置文件世杀。
- mako-kernel:存放的是mako kernel的二進(jìn)制文件
- hammerhead:存放Google Nexus5(hammerhead) 的產(chǎn)品配置文件阀参。
- hammerhead:存放的是 hammerhead kernel的二進(jìn)制文件。
下面簡(jiǎn)單說一下 device/lge/mako目錄下與Build系統(tǒng)相關(guān)的幾個(gè)產(chǎn)品配置的關(guān)鍵文件:
vendorsetup.sh
該文件在初始化編譯環(huán)境時(shí)被envsetup.sh文件包含進(jìn)去瞻坝。它作用是調(diào)用add_lunch_combo命令來添加產(chǎn)品名稱串蛛壳。AndroidProduct.mk
AndroidProduct.mk會(huì)在Build系統(tǒng)的ProductConfig.mk文件中被包含進(jìn)去,這個(gè)文件最重要的作用是定義了一個(gè)變量 PRODUCT_MAKEFILES所刀,它定義了本配置目錄中所有編譯入口文件衙荐,但每種產(chǎn)品編譯時(shí)只會(huì)使用其中之一。BoardConfig.mk
BoardConfig.mk文件會(huì)被Build系統(tǒng)的envsetup.sh文件包含進(jìn)去浮创。該文件主要定義了和設(shè)備硬件(包括CPU忧吟、WIFI、GPS等)相關(guān)的一些參數(shù)斩披。device.mk
device.mk是產(chǎn)品配置中經(jīng)常需要修改的一個(gè)文件溜族。產(chǎn)品定義中需要包含進(jìn)的模塊、文件以及各種環(huán)境變量的定義一般都放在這個(gè)文件里垦沉。device.mk中一些重要的編譯變量說明如下:
(1) PRODUCT_COPY_FILES:一個(gè)格式為"源文件路徑:目標(biāo)文件路徑" 字符串的組合煌抒。使用PRODUCT_COPY_FILES變量能方便地將編譯目錄下的一個(gè)文件復(fù)制到目標(biāo)文件系統(tǒng)中。需要注意的是厕倍,PRODUCT_COPY_FILES僅僅復(fù)制文件寡壮。如果復(fù)制的是apk或者Java庫,這些文件的簽名會(huì)保留讹弯。(2) PRODUCT_PACKAGES:用來定義產(chǎn)品的模塊列表况既,所有在模塊列表中的模塊的定義都會(huì)被執(zhí)行。
(3) PRODUCT_AAPT_CONFIG:指定了系統(tǒng)中能夠被支持的屏幕密度類型(dip)组民。所謂支持棒仍,是指系統(tǒng)編譯時(shí),會(huì)將相應(yīng)的資源文件添加到framework_res.apk文件中邪乍。
(4) PRODUCT_AAPT_PREF_CONFIG:指定系統(tǒng)實(shí)際的屏幕密度類型降狠。
(5) DEVICE_PACKAGE_OVERLAYS:這是一個(gè)很重要的變量对竣,它指定了系統(tǒng)的overlay目錄。系統(tǒng)編譯時(shí)會(huì)使用overlay目錄下存放的資源文件替換系統(tǒng)或模塊原有的資源文件榜配。這樣在不覆蓋原生資源文件的情況下否纬,就能實(shí)現(xiàn)產(chǎn)品的個(gè)性化。而且overlay的目錄可以有多個(gè)蛋褥,它們會(huì)按照在變量中的先后順序來替換資源文件临燃,利用這個(gè)特性可以定義公共的overlay目錄,以及各個(gè)產(chǎn)品專屬的overlay目錄烙心,最大限度地重用資源文件膜廊。
(6) PRODUCT_PROPERTY_OVERRIDES:定義系統(tǒng)的屬性值。如果屬性名稱以 "ro." 開頭淫茵,那這個(gè)屬性就是只讀屬性爪瓜。一旦設(shè)置,屬性值將不能改變匙瘪。如果屬性名稱以 "persist."開頭铆铆,則當(dāng)設(shè)置這個(gè)屬性時(shí),它的值將寫入文件/data/property中丹喻。
- 編譯類型 eng薄货、user和userdebug
(1) eng
缺省的編譯類型。執(zhí)行 "make" 相當(dāng)于執(zhí)行 "make eng"
編譯時(shí)會(huì)將下列模塊安裝到系統(tǒng):
- 在Android.mk 中用 LOCAL_MODULE_TAGS 變量定義了標(biāo)簽:eng碍论、debug谅猾、shell_$(TARGET_SHELL)、user和development 的模塊
- 非APK模塊并且不帶任何標(biāo)簽的模塊
所有產(chǎn)品配置文件中指定的APK模塊編譯的系統(tǒng)帶有如下屬性:
- ro.secure=0
- ro.debuggable=1
- ro.kernel.android.checkjni=1
編譯的系統(tǒng)中缺省情況下adb是可用的
(2) user
編譯時(shí)會(huì)將下列模塊安裝到系統(tǒng):
- 在Android.mk 中用 LOCAL_MODULE_TAGS 變量定義了標(biāo)簽:shell_$(TARGET_SHELL)鳍悠、user的模塊
- 非APK模塊并且不帶任何標(biāo)簽的模塊
所有產(chǎn)品配置文件中指定的APK模塊税娜,同時(shí)忽略其標(biāo)簽屬性編譯的系統(tǒng)帶有如下屬性:
- ro.secure=1
- ro.debuggable=0
編譯的系統(tǒng)中缺省情況下adb是不可用的,需要在系統(tǒng)設(shè)置中手動(dòng)開啟
(3) userdebug
編譯時(shí)會(huì)將下列模塊安裝到系統(tǒng):
- 在Android.mk 中用 LOCAL_MODULE_TAGS 變量定義了標(biāo)簽:shell_$(TARGET_SHELL)贼涩、debug和user的模塊
- 非APK模塊并且不帶任何標(biāo)簽的模塊
所有產(chǎn)品配置文件中指定的APK模塊巧涧,同時(shí)忽略其標(biāo)簽屬性編譯的系統(tǒng)帶有如下屬性:
- ro.secure=1
- ro.debuggable=1
編譯的系統(tǒng)中缺省情況下adb是不可用的,需要在系統(tǒng)設(shè)置中手動(dòng)開啟
3. 編譯Android的模塊
Android中的各種模塊遥倦,無論是APK應(yīng)用、可執(zhí)行程序還是jar包占锯,都可以通過Build系統(tǒng)編譯生成袒哥。在每個(gè)模塊的源碼目錄下,都有一個(gè)Android.mk文件消略,里面包含了模塊代碼的位置堡称、模塊的名稱、需要鏈接的動(dòng)態(tài)庫等一系列的定義艺演。
這里以 package/apps/Settings 目錄下的 Android.mk文件為例:
- 模塊的編譯變量
Android.mk 文件能編譯出不同的模塊却紧,是通過包含某個(gè)模塊編譯文件實(shí)現(xiàn)的桐臊,如上面例子中的 include $(BULID_PACKAGE) 。Android的Build系統(tǒng)定義了很多模塊編譯變量晓殊,如下表:
模塊編譯變量 | 說明 |
---|---|
BUILD_HOST_STATIC_LIBRARY | 對(duì)應(yīng)的文件是host_static_library.mk断凶,用來產(chǎn)生編譯平臺(tái)使用的本地靜態(tài)庫 |
BUILD_HOST_SHARED_LIBRARY | 對(duì)應(yīng)的文件是host_shared_library.mk,用來產(chǎn)生編譯平臺(tái)使用的本地共享庫 |
BUILD_STATIC_LIBRARY | 對(duì)應(yīng)的文件是 static_library.mk,用來產(chǎn)生目標(biāo)系統(tǒng)使用的本地靜態(tài)庫 |
BUILD_RAW_STATIC_LIBRARY | 對(duì)應(yīng)的文件是raw_static_library.mk认烁,用途不明 |
BUILD_SHARED_LIBRARY | 對(duì)應(yīng)的文件是shared_library.mk介汹,用來產(chǎn)生目標(biāo)系統(tǒng)使用的本地共享庫 |
BUILD_EXECUTABLE | 對(duì)應(yīng)的文件是executable.mk,用來產(chǎn)生目標(biāo)系統(tǒng)使用的Linux可執(zhí)行程序 |
BUILD_RAW_EXECUTABLE | 對(duì)應(yīng)的文件是raw_executable.mk嘹承,用途不明 |
BUILD_HOST_EXECUTABLE | 對(duì)應(yīng)的文件是host_executable.mk窗价,用來產(chǎn)生編譯平臺(tái)下使用的可執(zhí)行程序 |
BUILD_PACKAGE | 對(duì)應(yīng)的文件是package.mk。用來產(chǎn)生apk文件 |
BUILD_PHONY_PACKAGE | 對(duì)應(yīng)的文件是phony_package.mk |
BUILD_HOST_PREBUILT | 對(duì)應(yīng)的文件是host_prebuilt.mk叹卷。用來定義編譯平臺(tái)下的預(yù)編譯模塊目標(biāo) |
BUILD_PREBUILT | 對(duì)應(yīng)的文件是prebuilt.mk舌镶,定義預(yù)編譯的模塊目標(biāo),作用是將這些預(yù)編譯的模塊引入系統(tǒng) |
BUILD_MULTI_PREBUILT | 對(duì)應(yīng)的文件是multi_prebuilt.mk豪娜,定義多個(gè)預(yù)編譯模塊目標(biāo) |
BUILD_JAVA_LIBRARY | 對(duì)應(yīng)的文件是java_library.mk餐胀,用來產(chǎn)生目標(biāo)平臺(tái)的Java共享庫 |
BUILD_STATIC_JAVA_LIBRARY | 對(duì)應(yīng)的文件是static_java_library.mk,用來產(chǎn)生目標(biāo)平臺(tái)的Java靜態(tài)庫 |
BUILD_HOST_JAVA_LIBRARY | 對(duì)應(yīng)的文件是host_java_library.mk瘤载,用來產(chǎn)生編譯平臺(tái)下的Java共享庫 |
BUILD_DROIDDOC | 對(duì)應(yīng)的文件是droiddoc.mk |
BUILD_COPY_HEADERS | 對(duì)應(yīng)的文件是copy_headers.mk否灾,用來將LOCAL_COPY_HEADERS變量定義的文件復(fù)制到LOCAL_COPY_HEADERS_TO變量定義的路徑中 |
BUILD_NATIVE_TEST | 對(duì)應(yīng)的文件是native_test.mk,用來產(chǎn)生一個(gè)目標(biāo)系統(tǒng)的可執(zhí)行程序鸣奔,相比較BUILD_EXECUTABLE只是多定義了測(cè)試相關(guān)的庫的路徑和頭文件路徑 |
BUILD_HOST_NATIVE_TEST | 對(duì)應(yīng)的文件是host_native_test.mk墨技,用來產(chǎn)生一個(gè)編譯平臺(tái)下的可執(zhí)行程序,相比較BUILD_HOST_EXECUTABLE只是多定義了測(cè)試相關(guān)的庫的路徑和頭文件路徑 |
- 常用模塊的定義示例
(1) 編譯一個(gè)apk文件
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_JAVA_LIBRARIES := # 指定依賴的共享Java類庫
LOCAL_STATIC_JAVA_LIBRARIES := # 指定依賴的靜態(tài)Java類庫
# 指定源碼列表挎狸。這里使用系統(tǒng)定義的函數(shù)搜尋src目錄下的文件形成列表
LOCAL_SRC_FILES := $(call all-java-files-under, src)
LOCAL_MODULE_TAGS := optional #指定模塊的標(biāo)簽
LOCAL_CERTIFICATE := shared #指定模塊的簽名方式
LOCAL_PACKAGE_NAME := testapk # 指定模塊的名稱
include $(BUILD_PACKAGE)
(2) 編譯一個(gè)Java共享庫
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_SRC_FILES := $(call all-java-files-under, src)
LOCAL_MODULE_TAGS := optional # 指定模塊的標(biāo)簽
LOCAL_MODULE := javadynamiclib # 指定模塊的名稱
include $(BUILD_JAVA_LIBRARY)
(3) 編譯一個(gè)Java靜態(tài)庫
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_SRC_FILES := $(call all-java-files-under, src)
LOCAL_MODULE := javastaticlib # 指定模塊的名稱
include $(BUILD_STATIC_JAVA_LIBRARY)
(4) 編譯一個(gè)Java資源包文件
資源包也是一個(gè)apk文件扣汪,但沒有代碼,類似 framework_res.apk
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_NO_STANDARD_LIBRARIES := true # 指定依賴的靜態(tài)Java類庫
LOCAL_PACKAGE_NAME := javareslib # 定義模塊名
LOCAL_CERTIFICATE := platform # 指定簽名類型
LOCAL_AAPT_FLAGS := -x # 定義AAPT工具參數(shù)
LOCAL_MODULE_TAGS := user # 定義模塊標(biāo)簽為user
LOCAL_MODULE_PATH := $(TARGET_OUT_JAVA_LIBRARIES) #指定模塊的安裝路徑
LOCAL_EXPORT_PACKAGE_RESOURCES := true #為true時(shí)锨匆,其他的apk模塊能引用本模塊的資源
include $(BUILD_PACKAGE)
(5) 編譯一個(gè)可執(zhí)行文件
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_SRC_FILES := service.cpp
LOCAL_SHARED_LIBRARIES := libutils libbinder #指定模塊需要鏈接的動(dòng)態(tài)庫
ifeq ($(TARGET_OS), linux)
LOCAL_CFLAGS += -DXP_UNIX #定義編譯標(biāo)志
endif
LOCAL_MODULE := service #指定模塊的名稱
include $(BUILD_EXECUTABLE) #指定模塊的名稱
(6) 編譯一個(gè)native 的共享庫
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := optional
LOCAL_MODULE := libnativedynamic # 指定模塊的名稱
LOCAL_SRC_FILES := \ # 指定模塊的源文件
nativedynamic.cpp
LOCAL_SHARED_LIBRARIES := \ # 指定模塊需要鏈接的動(dòng)態(tài)庫
libcutils \
libutils
LOCAL_STATIC_LIBRARIES := libnativestatic # 指定模塊依賴的靜態(tài)庫
LOCAL_C_INCLUDES += \ # 指定頭文件的查找路徑
$(JNI_H_INCLUDE) \
$(LOCAL_PATH)/../include
LOCAL_CFLAGS += -O # 定義編譯標(biāo)志
include $(BUILD_SHARED_LIBRARY)
(7) 編譯一個(gè)native靜態(tài)庫
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := optional #指定模塊的標(biāo)簽
LOCAL_MODULE := libnativestatic #指定模塊的名稱
LOCAL_SRC_FILES := \ #指定模塊的源文件
nativestatic.cpp
LOCAL_C_INCLUDES +=
LOCAL_CFLAGS += -o #定義編譯標(biāo)志
include $(BUILD_STATIC_LIBRARY)
- 預(yù)編譯模塊的目標(biāo)定義
在實(shí)際的系統(tǒng)開發(fā)中崭别,并不會(huì)像Android一樣將所有源碼集中在一起編譯,有很多APK文件恐锣,jar包等都是預(yù)先編譯好的茅主,編譯系統(tǒng)時(shí)需要將這些二進(jìn)制文件復(fù)制到生成的image文件中土榴。
常用的方法是通過 PRODUCT_COPY_FILES 變量將這些文件直接復(fù)制到生成的image文件中玷禽。但有些APK文件或jar包,需要使用系統(tǒng)的簽名文件才能正常運(yùn)行贬丛,這樣用復(fù)制的方式就行不通了瘫寝。另外,一些動(dòng)態(tài)庫文件可能是源碼中的某些模塊所依賴的暮屡,用復(fù)制的方法也無法建立依賴關(guān)系褒纲,這將導(dǎo)致這些模塊編譯失敗。
Android 可通過定義預(yù)編譯模塊的方式來解決上述問題彻秆。
定義一個(gè)預(yù)編譯模塊和定義一個(gè)普通的編譯模塊格式相似唇兑。不同的是LOCAL_SRC_FILES 變量指定的不是源文件,而是二進(jìn)制文件的路徑结耀,同時(shí)還要通過 LOCAL_MODULE_CLASS 來指定模塊的類型香伴,最后 include 的是 BUILD_PREBUILT 變量定義的編譯文件具帮。
下面是常見預(yù)編譯模塊的示例:
(1) 定義apk文件目標(biāo)
include $(CLEAR_VARS)
LOCAL_MODULE := ThemeManager.apk #這里可以是任何字符串,但必須是系統(tǒng)唯一的目標(biāo)
LOCAL_SRC_FILES := app/$(LOCAL_MODULE)
LOCAL_MODULE_TAGS := optional
LOCAL_MODULE_CLASS := APPS #這里的值是APPS
LOCAL_CERTIFICATE := platform #這里可以指定簽名方式
include $(BUILD_PREBUILT)
(2) 定義靜態(tài)jar包目標(biāo)
include $(CLEAR_VARS)
LOCAL_MODULE := libfirewall.jar
LOCAL_SRC_FILES := app/$(LOCAL_MODULE)
LOCAL_MODULE_TAGS := optional
LOCAL_MODULE_CLASS := JAVA_LIBRARIES #這里的值是JAVA_LIBRARIES
LOCAL_CERTIFICATE := platform
include $(BUILD_PREBUILT)
(3) 定義動(dòng)態(tài)庫文件目標(biāo)
include $(CLEAR_VARS)
LOCAL_MODULE := libglobaltheme_jni.so
LOCAL_MODULE_OWNER :=
LOCAL_SRC_FILES := lib/$(LOCAL_MODULE)
LOCAL_MODULE_TAGS := optional
LOCAL_MODULE_CLASS := SHARED_LIBRARIES # 這里的值是SHARED_LIBRARIES
include $(BUILD_PREBUILT)
(4) 定義可執(zhí)行文件目標(biāo)
include $(CLEAR_VARS)
LOCAL_MODULE := bootanimation
LOCAL_MODULE_OWNER :=
LOCAL_SRC_FILES := bin/bootanimation
LOCAL_MODULE_TAGS := optional
LOCAL_MODULE_CLASS := EXECUTABLES #這里的值是EXECUTABLES
LOCAL_MODULE_PATH := $(TARGET_OUT)/bin #還可以指定復(fù)制到的目標(biāo)目錄
include $(BUILD_PREBUILT)
(5) 定義xml文件目標(biāo)
include $(CLEAR_VARS)
LOCAL_MODULE := apns-conf-cu.xml
LOCAL_MODULE_OWNER :=
LOCAL_SRC_FILES := etc/$(LOCAL_MODULE)
LOCAL_MODULE_TAGS := optional
LOCAL_MODULE_CLASS := ETC # ETC表示文件將復(fù)制到/system/etc 目錄下
include $(BUILD_PREBUILT)
(6) 定義host平臺(tái)下的jar包
這例子挺有意思的病游,將系統(tǒng)編譯時(shí)用到的 signapk.jar 預(yù)編譯衬衬,然后復(fù)制到out目錄下玉控,這樣Build系統(tǒng)將能夠使用這個(gè)文件來給其他文件簽名:
include $(CLEAR_VARS)
LOCAL_MODULE := signapk
LOCAL_PREBUILT_JAVA_LIBRARIES := lib/$(LOCAL_MODULE).jar
include $(BUILD_HOST_PREBUILT)
該例子中除了使用 BUILD_HOST_PREBUIT 表示目標(biāo)定義是針對(duì)編譯平臺(tái)而不是設(shè)備平臺(tái)外高诺,還給出了定義預(yù)編譯jar包模塊的另外一種定義方式,即使用變量 LOCAL_PREBUILT_JAVA_LIBRARIES 來定義牡拇。
- 常用的 "LOCAL_" 變量
編寫模塊的編譯文件,實(shí)際就是定義一系列以 "LOCAL_" 開頭的編譯變量罢杉,下表羅列了一些經(jīng)常使用的編譯變量和說明:
變量名 | 說明 |
---|---|
LOCAL_ASSET_FILES | 編譯APK文件時(shí)用于指定資源列表滩租,通常寫成 LOCAL_ASSET_FILES += $(call find-subdir-assets) |
LOCAL_CC | 自定義C編譯器來代替缺省的編譯器 |
LOCAL_CXX | 自定義C++編譯器來代替缺省的編譯器 |
LOCAL_CFLAGS | 定義額外的C/C++編譯器的參數(shù) |
LOCAL_CPPFLAGS | 僅定義額外的C++編譯器的參數(shù)律想,不用在C編譯器中 |
LOCAL_CPP_EXTENSION | 自定義C++源文件的后綴。例如:LOCAL_CPP_EXTENSION := .cc 注意:一旦定義身笤,模塊中所有源文件都必須使用該后綴液荸,目前不支持混合后綴 |
LOCAL_C_INCLUDES | 指定頭文件的搜索路徑 |
LOCAL_FORCE_STATIC_EXECUTABLE | 如果編譯時(shí)需要鏈接的庫有共享和靜態(tài)兩者并存的情況。設(shè)定此變量值為true將會(huì)優(yōu)先鏈接靜態(tài)庫文搂。通常這種情況只會(huì)在編譯root/sbin目錄下的應(yīng)用才會(huì)用到,因?yàn)樗鼈儓?zhí)行的時(shí)間比較早疯兼,文件系統(tǒng)的其他部分還沒有加載 |
LOCAL_GENERATED_SOURCES | 指定由系統(tǒng)自動(dòng)生成的源文件列表 |
LOCAL_MODULE_TAGS | 定義模塊標(biāo)簽,Build系統(tǒng)根據(jù)標(biāo)簽決定哪些模塊將安裝 |
LOCAL_REQUIRED_MODULES | 指定依賴的模塊姨裸。一旦本模塊被安裝,通過此變量指定的模塊也將被安裝 |
LOCAL_JAVACFLAGS | 定義額外的Javac編譯器的參數(shù) |
LOCAL_JAVA_LIBRARIES | 指定模塊依賴的Java共享庫 |
LOCAL_LDFLAGS | 定義鏈接器ld的參數(shù) |
LOCAL_LDLIBS | 指定模塊鏈接時(shí)依賴的庫赡艰。如果這些庫文件不存在,并不會(huì)引發(fā)對(duì)它們的編譯料身。這是此變量和LOCAL_SHARED_LIBRARIES的主要區(qū)別 |
LOCAL_NO_MANIFEST | 在一個(gè)資源apk中可以指定此變量為true芹血,表示此apk文件沒有AndroidManifest.xml文件 |
LOCAL_PACKAGE_NAME | 指定APP應(yīng)用名稱 |
LOCAL_PATH | 指定Android.mk 文件所在的目錄 |
LOCAL_POST_PROCESS_COMMAND | 在編譯host相關(guān)的模塊時(shí)抖部,可以用此變量定義一條命令在link完成后執(zhí)行 |
LOCAL_PREBUILT_LIBS | 指定預(yù)編譯C/C++動(dòng)態(tài)和靜態(tài)庫列表乡恕。用于預(yù)編譯模塊定義中 |
LOCAL_PREBUILT_JAVA_LIBRARIES | 指定預(yù)編譯Java庫列表。用于預(yù)編譯模塊定義中 |
LOCAL_SHARED_LIBRARIES | 指定模塊依賴的C/C++共享庫列表 |
LOCAL_SRC_FILES | 指定源文件列表 |
LOCAL_STATIC_LIBRARIES | 指定依賴的C/C++靜態(tài)庫列表 |
LOCAL_MODULE | 除應(yīng)用(apk)以 LOCAL_PACKAGE_NAME指定模塊名以外,其余的模塊都以LOCAL_MODULE指定模塊名 |
LOCAL_MODULE_PATH | 指定模塊在目標(biāo)系統(tǒng)的安裝路徑 |
LOCAL_UNSTRIPPED_PATH | 指定模塊的unstripped版本在out目錄下的保存路徑 |
LOCAL_WHOLE_STATIC_LIBRARIES | 這個(gè)變量也定義了模塊依賴的靜態(tài)庫列表,和 LOCAL_STATIC_LIBRARIES 類似锚国。但通過這個(gè)變量定義,鏈接時(shí)鏈接器不會(huì)將靜態(tài)庫中無人調(diào)用的代碼去掉 |
LOCAL_YACCFLAGS | 指定yacc的參數(shù) |
LOCAL_ADDITIONAL_DEPENDENCIES | 指定本模塊的依賴。用在不方便使用別的方法來指定依賴關(guān)系時(shí) |
LOCAL_BUILT_MODULE | 指定編譯時(shí)存放中間文件的目錄 |
LOCAL_INSTALLED_MODULE | 指定模塊的安裝路徑 |
LOCAL_MODULE_CLASS | 定義模塊的分類。根據(jù)分類沸枯,生成的模塊文件會(huì)安裝到目標(biāo)系統(tǒng)相應(yīng)的目錄下。例如翔怎,APPS:安裝到/system/app下飘痛;SHARED_LIBRARIES:安裝到/system/lib下; EXECUTABLES:安裝到/system/bin下塑猖;ETC:安裝到/system/etc 下感憾;但如果同時(shí)用LOCAL_MODULE_PATH定義了路徑凉倚,則安裝到該路徑 |
LOCAL_MODULE_NAME | 指定模塊的名稱 |
LOCAL_MODULE_SUFFIX | 指定當(dāng)前模塊的后綴鳍刷。一旦指定占遥,系統(tǒng)在產(chǎn)生目標(biāo)文件時(shí),會(huì)以模塊名加后綴創(chuàng)建目標(biāo)文件 |
LOCAL_STRIP_MODULE | 指定模塊是否需要strip输瓜,該模塊是可執(zhí)行文件或動(dòng)態(tài)庫時(shí)才能使用該變量 |
LOCAL_STRIPPABLE_MODULE | 此變量的值通常由Build系統(tǒng)設(shè)置瓦胎,一般編譯可執(zhí)行文件和動(dòng)態(tài)庫時(shí)設(shè)為true |
LOCAL_SYSTEM_SHARED_LIBRARIES | 此變量在編譯系統(tǒng)的基本庫,如libc尤揣、libm搔啊、libdl時(shí)北戏,用來定義這些庫的依賴庫锨天。通常在應(yīng)用模塊定義中不應(yīng)該使用該變量 |
LOCAL_PRELINK_MODULE | 編譯 .so 模塊時(shí),定義是否需要prelink。prelink通過預(yù)鏈接的方式來加快程序啟動(dòng)速度。如果要設(shè)置此值為true陡厘,要先在build/core/prelink-linux-arm.map文件中定義該庫的地址和大小,否則報(bào)錯(cuò)。但在Android4.2以后的代碼中找不到文件prelink-linux-arm.map了屋谭,在build目錄下也搜尋不到這個(gè)變量⊙砗模可能Android 已經(jīng)取消了prelink的功能 |
參考
http://gityuan.com/2016/03/19/android-build/
https://blog.csdn.net/luoshengyang/article/details/18928789
http://www.reibang.com/p/4a6d8c0e034a
https://www.ibm.com/developerworks/cn/opensource/os-cn-android-build/index.html
https://source.android.com/setup/develop/64-bit-builds
《深入解析Android 5.0系統(tǒng)》