Android Build系統(tǒng)要點(diǎn)總結(jié)

在之前的公司參與項(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等命令就是在該腳本中定義的纹因,如圖:

image.png

除了命令的定義外喷屋,來看看運(yùn)行envsetup.sh腳本實(shí)際執(zhí)行的代碼:

image.png

image.png

可以看到,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)容:

image.png

可以看到它仍然是調(diào)用了add_lunch_combo命令屯曹。這樣看來,build/core/envsetup.sh 除了定義shell命令外,就是執(zhí)行add_lunch_combo命令而已恶耽。它的定義也是在envsetup.sh中密任,如下:

image.png

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后蜡豹,打印如下信息:

image.png

如上圖,這些環(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)源碼根目錄下贮尖。

main.png

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文件為例:

image.png
  • 模塊的編譯變量

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)》

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市军熏,隨后出現(xiàn)的幾起案子抖甘,更是在濱河造成了極大的恐慌柄沮,老刑警劉巖隆箩,帶你破解...
    沈念sama閱讀 211,042評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡耙替,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,996評(píng)論 2 384
  • 文/潘曉璐 我一進(jìn)店門绘趋,熙熙樓的掌柜王于貴愁眉苦臉地迎上來帽馋,“玉大人涛漂,你說我怎么就攤上這事距潘±赐溃” “怎么了虑椎?”我有些...
    開封第一講書人閱讀 156,674評(píng)論 0 345
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)俱笛。 經(jīng)常有香客問我捆姜,道長(zhǎng),這世上最難降的妖魔是什么迎膜? 我笑而不...
    開封第一講書人閱讀 56,340評(píng)論 1 283
  • 正文 為了忘掉前任泥技,我火速辦了婚禮,結(jié)果婚禮上磕仅,老公的妹妹穿的比我還像新娘珊豹。我一直安慰自己,他們只是感情好榕订,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,404評(píng)論 5 384
  • 文/花漫 我一把揭開白布店茶。 她就那樣靜靜地躺著,像睡著了一般劫恒。 火紅的嫁衣襯著肌膚如雪忽妒。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,749評(píng)論 1 289
  • 那天兼贸,我揣著相機(jī)與錄音,去河邊找鬼吃溅。 笑死溶诞,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的决侈。 我是一名探鬼主播螺垢,決...
    沈念sama閱讀 38,902評(píng)論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼赖歌!你這毒婦竟也來了枉圃?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,662評(píng)論 0 266
  • 序言:老撾萬榮一對(duì)情侶失蹤庐冯,失蹤者是張志新(化名)和其女友劉穎孽亲,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體展父,經(jīng)...
    沈念sama閱讀 44,110評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡返劲,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,451評(píng)論 2 325
  • 正文 我和宋清朗相戀三年玲昧,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片篮绿。...
    茶點(diǎn)故事閱讀 38,577評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出蚓哩,到底是詐尸還是另有隱情谁帕,我是刑警寧澤,帶...
    沈念sama閱讀 34,258評(píng)論 4 328
  • 正文 年R本政府宣布吼虎,位于F島的核電站犬钢,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏鲸睛。R本人自食惡果不足惜娜饵,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,848評(píng)論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望官辈。 院中可真熱鬧箱舞,春花似錦、人聲如沸拳亿。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,726評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽肺魁。三九已至电湘,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間鹅经,已是汗流浹背寂呛。 一陣腳步聲響...
    開封第一講書人閱讀 31,952評(píng)論 1 264
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留瘾晃,地道東北人贷痪。 一個(gè)月前我還...
    沈念sama閱讀 46,271評(píng)論 2 360
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像蹦误,于是被迫代替她去往敵國(guó)和親劫拢。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,452評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容