赞
踩
随着android工程越来越大,包含的 module 越来越多,以 makefile 组织的项目编译花费的时间越来越多。谷歌在7.0 开始引入了 ninja 进行编译系统的组织。相对于make来说 Ninja 在大的项目管理中速度和并行方面有突出的优势,因此谷歌采用了 Ninja 来取代之前使用的make。
Android 7.0 之后在很多地方出现了 Android.bp 的文件,后缀bp 应该是 blueprint 的意思,本文主要是介绍其由来和简单的语法和其使用方法,以及与其相关的 Blueprint 和 Soong。
Android 7.0之后希望用 Android.bp 替换Android.mk,bp简单的配置更方便 Ninja 文件的产生,而Blueprint和Soong 就此产生。
Android 利用Blueprint和Soong 来解析bp 文件,经过最终转换为 ninja files。
Blueprint和Soong都是由Golang写的项目。 从Android Nougat开始,prebuilts/go/ 目录下新增了Golang所需的运行环境,在编译时使用。
Android.bp以及相关支持,从Android Nougat开始加入,从Android Oreo(8.0)开始默认开启。 如果需要在Android Nougat的版本使用,需要在执行编译时添加变量。
make 'USE_SOONG=true'
Android 提供了source code 目录为 build/:
经过试验表明,soong处理后的 bp 文件生成 build.ninja 的同时还包含 out/soong/Android-aosp_arm.mk,这个文件是编译完成后模块的安装脚本,负责将模块安装到对应位置。比如我们现在处理的 vndk 相关 vendor 处理就是在这个目录下进行的。
在 out/soong 目录下有两个文件 .minibootstrap/build.ninja 和 .bootstrap/build.ninja 两个目录。.minibootstrap/build.ninja 主要是用来编译 blueprint 和生成 .bootstrap/build.ninja。而 .bootstrap/build.ninja 主要是生成 soong 相关工具和 out/soong/build.ninja 文件,如下图。
另外,所有Android.mk 文件会编译成 out/build-<product_name>.ninja 文件,如下图。
将 out/soong/build.ninja 和 out/build-<product_name>.ninja 结合起来形成 out/combined-<product_name>.ninja 文件,进入ninja 编译系统,如下图。
Soong是以前 Android 基于make的编译系统的替代品。它以 Android.bp 文件替代Android.mk,Android.bp文件用类似 JSON 的简洁声明来描述需要构建的模块。
Android.bp文件设计得非常简洁。没有条件或控制流语言(任何复杂性都在用Go编写的构建逻辑中被处理)。Android.bp文件的语法和语义在可能的情况下有意类似于 Bazel构建文件。
详细的Android.bp 的描述文档看:Android.bp Build Docs (android-8.0.0-r9) · 零壹軒·笔记
语法:
Blueprint文件的语法比较简单,毕竟只是配置文件。
Android.bp文件中的模块以模块类型开头,后跟一组name: value
格式的属性:
- cc_binary {
- name: "gzip",
- srcs: ["src/test/minigzip.c"],
- shared_libs: ["libz"],
- stl: "none",
- }
每个模块必须有name
属性,且其值在所有Android.bp文件中必须是唯一的。
关于可用模块类型及其属性列表,参见$OUT_DIR/soong/.bootstrap/docs/soong_build.html.
Android.bp文件可包含顶级变量赋值:
- gzip_srcs = ["src/test/minigzip.c"],
- cc_binary {
- name: "gzip",
- srcs: gzip_srcs,
- shared_libs: ["libz"],
- stl: "none",
- }
变量范围限定为声明它们的文件的其余部分,以及任何子蓝图文件。变量是不可变的,但有一个例外 —— 它们可以附上+=
赋值,但仅在变量被引用之前。
注释方式,与Golang类似。 支持行注释//
与块注释/* block */
。
除了赋值的 = 以外,只有 +。
变量和属性是强类型的,变量动态地基于首次赋值,属性静态地由模块类型。支持的类型是:
true
or false
)int
)"string"
)["string1", "string2"]
){key1: "value1", key2: ["value2"]}
)Map可以是任何类型的值,包括嵌套Map。List和Map在最后一个值后可能有逗号。
默认模块可用于在多个模块中重复相同的属性。例如:
- cc_defaults {
- name: "gzip_defaults",
- shared_libs: ["libz"],
- stl: "none",
- }
- cc_binary {
- name: "gzip",
- defaults: ["gzip_defaults"],
- srcs: ["src/test/minigzip.c"],
- }
一个是格式化工具bpfmt。 与gofmt类似,可以格式化Blueprint文件。 (其实,代码基本上都是从gofmt复制而来。)
例如,格式化当前目录及其递归子目录下的所有Android.bp:
bpfmt -w .
另一个是androidmk,负责转换Android.mk为Android.bp。 其实,现阶段没有必要学会写Android.bp,通过写Android.mk来转换也行。
androidmk Android.mk > Android.bp
启用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个可执行文件:
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文件才是真正直接控制源码编译的工具。
下面,以一个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.mk 中一些变量,bp 还没有对应起来,例如:
- // ANDROIDMK TRANSLATION ERROR: unsupported assignment to LOCAL_STATIC_ANDROID_LIBRARIES
- // LOCAL_STATIC_ANDROID_LIBRARIES := android-support-v4 android-support-v13 android-support-v7-preference android-support-v14-preference
-
- // ANDROIDMK TRANSLATION ERROR: unsupported assignment to LOCAL_PROGUARD_ENABLED
- // LOCAL_PROGUARD_ENABLED := disabled
至于Android.bp支持多少像cc_binary
、cc_library
这样的模块,每个模块又支持多少像name
、cflags
这样的属性, 则只能去查找Soong的文档。
参考:
Android编译系统中的Android.bp、Blueprint与Soong · 零壹軒·笔记
相关文章:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。