本文轉載自:
轉自:http://note.qidong.name/2017/08/android-blueprint/
Android編譯系統中的Android.bp、Blueprint與Soong
本文簡單介紹Android Nougat(7.0)中引入的Android.bp,及其相關工具鏈。
簡介
Android.bp,是用來替換Android.mk的配置文件。 它使用Blueprint框架來解析,最終轉換成Ninja文件。
與Android.mk不同的是,Android.bp是純粹的配置文件,不包含分支、循環等流程控制,也不能做算數、邏輯運算。 與此同時,Ninja文件也是如此。 這就產生了一些新的問題與需求——在Android項目上進行選擇編譯、解析配置、轉換成Ninja等——Soong應運而生。 Soong其實就相當於Makefile編譯系統的核心,即build/make/core/
下面的內容。 它負責提供Android.bp的含義定義與解析,並將之轉換為Ninja文件。。
此外,Soong還會編譯產生一個androidmk
命令,可以手動把Android.mk轉換成Android.bp。 這只對無選擇、循環等復雜流程控制的Android.mk生效。
Blueprint和Soong都是由Golang寫的項目。 從Android Nougat開始,prebuilts/go/
目錄下新增了Golang所需的運行環境,在編譯時使用。
Android.bp以及相關支持,從Android Nougat開始加入,從Android Oreo(8.0)開始默認開啟。 如果需要在Android Nougat的版本使用,需要在執行編譯時添加變量。
make 'USE_SOONG=true'
單獨編譯blueprint
啟用Soong以后,在Android編譯最開始的准備階段,會執行build/soong/soong.bash
進行環境准備。 其中會先編譯、安裝Blueprint到out
目錄下。 也就是說,在編譯Android項目時,Android.bp相關工具鏈會自動編譯,無需費神。
Soong是與Android強關聯的一個項目,而Blueprint則相對比較獨立,可以單獨編譯、使用。
編譯Blueprint,首先要具備Golang環境。 然后,按照以下步驟執行命令。
-
go get github.com/google/blueprint
-
cd $GOPATH/src/github.com/google/blueprint
-
./bootstrap.bash
-
./blueprint.bash
-
ls bin
在新生成的bin
目錄中,包含4個可執行文件:
- bpfmt
- bpmodify
- microfactory
- minibp
由於文檔較少,甚至連幫助命令都不包括命令的描述,所以其作用只能望文生義。
工具鏈關系
Android.mk、Android.bp、Soong、Blueprint、Ninja,它們之間到底有什么關系? 以下用簡單的方式表達這幾個概念之間的作用關系。
-
Android.bp --> Blueprint --> Soong --> Ninja
-
Makefile or Android.mk --> kati --> Ninja
-
-
( Android.mk --> Soong --> Blueprint --> Android.bp)
Blueprint是生成、解析Android.bp的工具,是Soong的一部分。 Soong則是專為Android編譯而設計的工具,Blueprint只是解析文件的形式,而Soong則解釋內容的含義。
Android.mk可以通過Soong提供的androidmk
轉換成Android.bp,但僅限簡單配置。 目前Oreo的編譯流程中,仍然是使用kati來做的轉換。
現存的Android.mk、既有的Android.bp,都會分別被轉換成Ninja。 從Android.mk與其它Makefile,會生成out/build-<product_name>.ninja
文件。 而從Android.bp,則會生成out/soong/build.ninja
。 此外,還會生成一個較小的out/combined-<product_name>.ninja
文件,負責把二者組合起來,作為執行入口。
最終,Ninja文件才是真正直接控制源碼編譯的工具。
Android.bp
樣例與基本概念
-
// Android.bp sample
-
cc_defaults(
-
deps = [
-
"libc",
-
],
-
)
-
-
cc_library(
-
name = "cmd",
-
srcs = [
-
"main.c",
-
],
-
)
-
-
subdirs = [ "subdir1", "subdir2"]
前面的樣例中,cc_library
這種()
前面的,就是模塊(module)。 這里module的概念,直接對應Android.mk中module的概念。 而=
前面的name
、srcs
等,就是該模塊的屬性(property)。
subdirs
是一個文件級的頂層屬性,指定后會查找次級目錄下的Android.bp。 類似於Android.mk中常用的include $(call all-subdir-makefiles)
。
模塊是可以繼承屬性的。 cc_defaults
就是一個文件中所有模塊的父模塊,可以指定公用的屬性。 在以上代碼中,cc_library
模塊雖然沒有指定,但已經包含了deps
屬性。
語法
Blueprint文件的語法比較簡單,畢竟只是配置文件。
變量與屬性都是動態強類型的,賦值時確定。 變量類型只有四種。
- Bool(
true
或false
) - 字符串Strings(”string”)
- 字符串列表(
["string1", "string2"]
) - 映射關系Map(
{key1: "value1", key2: ["value2"]}
)
注釋方式,與Golang類似。 支持行注釋// line
與塊注釋/* block */
。
操作符除了賦值的=
以外,只有+
。
常用工具
雖然編譯過程中的相關很多,不過在開發過程中可能需要手動執行的命令卻不多。
一個是格式化工具bpfmt
。 與gofmt類似,可以格式化Blueprint文件。 (其實,代碼基本上都是從gofmt復制而來。)
例如,格式化當前目錄及其遞歸子目錄下的所有Android.bp:
bpfmt -w .
另一個是androidmk
,負責轉換Android.mk為Android.bp。 其實,現階段沒有必要學會寫Android.bp,通過寫Android.mk來轉換也行。
androidmk Android.mk > Android.bp
Android.mk轉換Android.bp實例
下面,以一個AOSP上的簡單模塊,system/core/sdcard/Android.mk
,來做為案例。
-
LOCAL_PATH := $(call my-dir)
-
-
include $(CLEAR_VARS)
-
-
LOCAL_SRC_FILES := sdcard.cpp fuse.cpp
-
LOCAL_MODULE := sdcard
-
LOCAL_CFLAGS := -Wall -Wno-unused-parameter -Werror
-
LOCAL_SHARED_LIBRARIES := libbase libcutils libminijail libpackagelistparser
-
-
LOCAL_SANITIZE := integer
-
-
include $(BUILD_EXECUTABLE)
這是一個編譯二進制可執行文件的小模塊,內容非常簡單。 通過執行androidmk Android.mk > Android.bp
,可以轉換成Android.bp。
-
cc_binary {
-
srcs: [
-
"sdcard.cpp",
-
"fuse.cpp",
-
],
-
name: "sdcard",
-
cflags: [
-
"-Wall",
-
"-Wno-unused-parameter",
-
"-Werror",
-
],
-
shared_libs: [
-
"libbase",
-
"libcutils",
-
"libminijail",
-
"libpackagelistparser",
-
],
-
sanitize: {
-
misc_undefined: [ "integer"],
-
},
-
}
可以看出,雖然行數變多,但其實含義更明確了。 這個名為sdcard
的模塊,源碼有兩個cpp文件,依賴庫有四個。 cc_binary
,就相當於include $(BUILD_EXECUTABLE)
。 轉換前后,該有的信息都在,只是表達方式變化了而已。
注意:如果Android.mk中包含復雜的邏輯,則轉換結果會有問題,詳見結果文件中的注釋。
至於Android.bp支持多少像cc_binary
、cc_library
這樣的模塊,每個模塊又支持多少像name
、cflags
這樣的屬性, 則只能去查找Soong的文檔。
文檔
目前(2017年),整個Android.bp工具鏈,都處於文檔極度缺失的階段。 除了官方那點可憐的README以外,基本只能去看代碼與注釋,參考其它已經存在的Android.bp。
另外,在已經使用Soong編譯的項目中,out/soong/.bootstrap/docs/soong_build.html
描述了所有的可用模塊及其屬性。 這多少緩解了兩眼一抹黑症狀,不算太過難受。 實際上,整個Soong仍然處於發展期,Google肆無忌憚地修改,完全沒考慮兼容。 在8.0.0寫的Android.bp,也許在8.0.1就會編譯失敗。 這或許是文檔與編譯綁定的真意吧。 等Soong完全成熟了,也許Android開發官網,就會有詳盡的信息。
本站提供了從AOSP的android-8.0.0-r9,編譯出來的一個soong_build.html,僅供參考。