转自: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-
文件。 而从Android.bp,则会生成out/soong/build.ninja
。 此外,还会生成一个较小的out/combined-
文件,负责把二者组合起来,作为执行入口。
最终,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,仅供参考。