本文轉(zhuǎn)載自:Android.bp 語(yǔ)法淺析-Android10.0編譯系統(tǒng)(八)
本文基于Android 10.0源碼分析
1.概述
??在Android 7.0 之前,Android 編譯系統(tǒng)使用GNU Make描述和shell來(lái)構(gòu)建編譯規(guī)則,模塊定義都使用Android.mk進(jìn)行定義,Android.mk的本質(zhì)就是Makefile,但是隨著Android的工程越來(lái)越大,模塊越來(lái)越多,Makefile組織的項(xiàng)目編譯時(shí)間越來(lái)越長(zhǎng)。這樣下去Google工程師覺(jué)得不行,得要優(yōu)化。
??因此,在Android 7.0開(kāi)始,Google采用ninja來(lái)代取代之前使用的make,由于之前的Android.mk數(shù)據(jù)實(shí)在巨大,因此Google加入了一個(gè)kati工具,用于將Android.mk轉(zhuǎn)換成ninja的構(gòu)建規(guī)則文件buildxxx.ninja,再使用ninja來(lái)進(jìn)行構(gòu)建工作。
??ninja的網(wǎng)址:https://ninja-build.org
??編譯速度快了一些,但是既然要干, 那就干個(gè)大的,最終目標(biāo)要把make都取代,于是從Android8.0開(kāi)始,Google為了進(jìn)一步淘汰Makefile,因此引入了Android.bp文件來(lái)替換之前的Android.mk。
??Android系統(tǒng)的編譯歷程:
2.Android.bp文件格式
??根據(jù)設(shè)計(jì),Android.bp文件很簡(jiǎn)單。它們不包含任何條件語(yǔ)句,也不包含控制流語(yǔ)句;所有復(fù)雜問(wèn)題都由用Go 編寫的構(gòu)建邏輯處理。Android.bp文件的語(yǔ)法和語(yǔ)義都盡可能與Bazel BUILD文件類似。
2.1 模塊
??Android.bp文件中的模塊以模塊類型開(kāi)頭,后跟一組name: "value",格式的屬性。
cc_binary {
name: "gzip",
srcs: ["src/test/minigzip.c"],
shared_libs: ["libz"],
stl: "none",
}
每個(gè)模塊都必須具有name屬性,并且相應(yīng)值在所有name文件中必須是唯一的,僅有兩個(gè)例外情況是命名空間和預(yù)構(gòu)建模塊中的Android.bp屬性值,這兩個(gè)值可能會(huì)重復(fù)。
??srcs 屬性以字符串列表的形式指定用于構(gòu)建模塊的源文件。您可以使用模塊引用語(yǔ)法 ":<module-name>" 來(lái)引用生成源文件的其他模塊的輸出,如 genrule 或 filegroup。如需有效模塊類型及其屬性的列表,請(qǐng)參閱 Soong 模塊參考:https://www.cnblogs.com/linhaostudy/p/12361659.html
??常用模塊類型:
cc_binary
cc_library
cc_library_static
android_app
java_library
hidl_interface
aidl_interface
2.2 類型
??變量和屬性是強(qiáng)類型,變量根據(jù)第一項(xiàng)賦值動(dòng)態(tài)變化,屬性由模塊類型靜態(tài)設(shè)置。支持的類型為:
布爾值Bool(true 或 false)
整數(shù)Integers (int)
字符串Strings ("string")
字符串列表List of string (["string1", "string2"])
映射Maps ({key1: "value1", key2: ["value2"]})
映射可以包含任何類型的值,包括嵌套映射。列表和映射可能在最后一個(gè)值后面有終止逗號(hào)。
2.3 Glob
??接受文件列表的屬性(例如 srcs)也可以采用glob模式。glob模式可以包含普通的UNIX通配符,例如.java。glob模式還可以包含單個(gè)**通配符作為路徑元素,與零個(gè)或多個(gè)路徑元素匹配。例如,java/*/.java同時(shí)匹配 java/Main.java和java/com/android/Main.java模式。
2.4 變量
??Android.bp文件可能包含頂級(jí)變量賦值:
gzip_srcs = ["src/test/minigzip.c"]
cc_binary {
srcs: gzip_srcs,
shared_libs: ["libz"],
stl: "none",
}
變量的作用域限定在聲明它們的文件的其余部分,以及所有子Android.bp文件,可以使用 “=” 號(hào)賦值, 但是不能使用 “:=” 賦值。變量是不可變的,但有一個(gè)例外情況:可以使用 += 賦值將變量附加到別處,但只能在引用它們之前附加。例:
gzip_srcs = ["src/test/minigzip.c"]
gzip_srcs += [
"src/test/test.cpp",
]
cc_binary {
srcs: gzip_srcs,
shared_libs: ["libz"],
stl: "none",
}
2.5 注釋
??Android.bp文件可以包含C樣式的多行 /* */ 注釋以及 C++ 樣式的單行//注釋。例如:
// This is a "http://" Comments test
// =========================================================
/*This is a "/**/" Comments test*/
2.6 運(yùn)算符
??可以使用+運(yùn)算符附加字符串、字符串列表和映射??梢允褂?運(yùn)算符對(duì)整數(shù)求和。附加映射會(huì)生成兩個(gè)映射中鍵的并集,并附加在兩個(gè)映射中都存在的所有鍵的值。
2.7 條件語(yǔ)句
??Soong不支持Android.bp文件中的條件語(yǔ)句。但是,編譯規(guī)則中需要條件語(yǔ)句的復(fù)雜問(wèn)題將在Go(在這種語(yǔ)言中,可以使用高級(jí)語(yǔ)言功能,并且可以跟蹤條件語(yǔ)句引入的隱式依賴項(xiàng))中處理。大多數(shù)條件語(yǔ)句都會(huì)轉(zhuǎn)換為映射屬性,其中選擇了映射中的某個(gè)值并將其附加到頂級(jí)屬性。
??例如,要支持特定于架構(gòu)的文件,請(qǐng)使用以下命令:
cc_library {
...
srcs: ["generic.cpp"],
arch: {
arm: {
srcs: ["arm.cpp"],
},
x86: {
srcs: ["x86.cpp"],
},
},
}
2.8 格式設(shè)置工具
??Soong包含一個(gè)針對(duì)Blueprint文件的規(guī)范格式設(shè)置工具,類似于gofmt。如需以遞歸方式重新設(shè)置當(dāng)前目錄中所有Android.bp文件的格式,請(qǐng)運(yùn)行以下命令:
bpfmt -w .
規(guī)范格式包括縮進(jìn)四個(gè)空格、多元素列表的每個(gè)元素后面有換行符,以及列表和映射末尾有英文逗號(hào)。
2.9 默認(rèn)模塊
??默認(rèn)模塊可用于在多個(gè)模塊中重復(fù)使用相同的屬性。例如:
cc_defaults {
name: "gzip_defaults",
shared_libs: ["libz"],
stl: "none",
}
cc_binary {
name: "gzip",
defaults: ["gzip_defaults"],
srcs: ["src/test/minigzip.c"],
}
2.10 預(yù)編譯的模塊
??某些預(yù)構(gòu)建的模塊類型允許模塊與其基于源代碼的對(duì)應(yīng)模塊具有相同的名稱。例如,如果已有同名的 cc_binary,也可以將cc_prebuilt_binary命名為foo。這讓開(kāi)發(fā)者可以靈活地選擇要納入其最終產(chǎn)品中的版本。如果編譯配置包含兩個(gè)版本,則預(yù)編譯模塊定義中的prefer標(biāo)記值會(huì)指示哪個(gè)版本具有優(yōu)先級(jí)。請(qǐng)注意,某些預(yù)編譯模塊的名稱不能以prebuilt開(kāi)頭,例如android_app_import。
2.11 命名空間模塊
??在 Android 完全從Make轉(zhuǎn)換為Soong之前,Make產(chǎn)品配置必須指定PRODUCT_SOONG_NAMESPACES值。它的值應(yīng)該是一個(gè)以空格分隔的列表,其中包含Soong導(dǎo)出到Make以使用m命令進(jìn)行編譯的命名空間。在Android完成到Soong的轉(zhuǎn)換之后,啟用命名空間的詳細(xì)信息可能會(huì)發(fā)生變化。
??Soong 可以讓不同目錄中的模塊指定相同的名稱,只要每個(gè)模塊都在單獨(dú)的命名空間中聲明即可??梢园慈缦路绞铰暶髅臻g:
soong_namespace {
imports: ["path/to/otherNamespace1", "path/to/otherNamespace2"],
}
請(qǐng)注意,命名空間沒(méi)有 name 屬性;其路徑會(huì)自動(dòng)指定為其名稱。
??系統(tǒng)會(huì)根據(jù)每個(gè)Soong模塊在樹中的位置為其分配命名空間。每個(gè)Soong模塊都會(huì)被視為處于Android.bp(位于當(dāng)前目錄或最近的父級(jí)目錄中的soong_namespace 文件內(nèi))定義的命名空間中。如果未找到此類 soong_namespace模塊,則認(rèn)為該模塊位于隱式根命名空間中。
??下面是一個(gè)示例:Soong嘗試解析由模塊M在名稱空間N(導(dǎo)入命名空間 I1、I2、I3…)中聲明的依賴項(xiàng)D。
如果D是//namespace:module格式的完全限定名稱,系統(tǒng)將僅在指定的命名空間中搜索指定的模塊名稱。
否則,Soong將首先查找在命名空間N中聲明的名為D的模塊。
如果該模塊不存在,Soong會(huì)在命名空間 I1、I2、I3…中查找名為D的模塊。
最后,Soong在根命名空間中查找。
2.12 Android.mk文件自動(dòng)轉(zhuǎn)Android.bp方法
??Android源碼里邊提供了快捷直接Android.mk轉(zhuǎn)換成Android.bp的工具:androidmk。
(1)androidmk源碼位置
build/soong/androidmk/cmd/androidmk/androidmk.go
(2)編譯出來(lái)后androidmk可執(zhí)行文件位置
aosp/out/soong/host/linux-x86/bin/androidmk
(3)轉(zhuǎn)換方法
aosp/out/soong/host/linux-x86/bin/androidmk [Android.mk PATH] > [Android.bp PATH]
該工具可以轉(zhuǎn)換變量、模塊、注釋和一些條件,但任何自定義生成文件規(guī)則、復(fù)雜條件或額外的包含都必須手動(dòng)轉(zhuǎn)換。