Android.bp 简介
大部分内容来自官方文档,本文目的为用于备份查询。
Android 编译系统
从 Android 7.0 开始,Ninja 成为默认的编译框架。Ninja 是一个致力于速度的小型编译系统(类似于Make),它的设计就是为了更快的编译。Ninja 可以通过其他高级的编译系统生成其输入文件,Android 使用 Kati 把 makefile 转换成 Ninja 文件。
Soong 编译系统是在 Android 7.0 中引入的,旨在取代 Make。Soong 使用与 JSON 类似的 Blueprint 文件(即 .bp
文件)来对要编译的模块进行简单的声明性描述。Soong使用 Android.bp 做为配置文件,使用 Blueprint 框架来解析,最终通过 Soong 转换成 Ninja 文件。
Android.mk 、Android.bp 和 Ninja 三者的关系可以用下图来表示。
- Android.mk 和 Android.bp 代表高级编译系统的配置文件,其最终都要转化为 Ninja 文件。
- 如果 Android.mk 和 Android.bp 在编译目录中同时存在,Android.mk 会被忽略。
- Android.mk 可以通过 androidmk 转化为 Android.bp。
- Makefile编译系统终将不再使用,尽量使用 Android.bp。
Android.bp 文件格式
根据设计,Android.bp
文件很简单。它们不包含任何条件语句,也不包含控制流语句;所有复杂问题都由用 Go 编写的编译逻辑处理。Android.bp
文件的语法和语义类似于 Bazel BUILD 文件(如有可能)。
模块
Android.bp
文件中的模块以模块类型开头,后跟一组 name: "value",
格式的属性:
cc_binary {
name: "gzip",
srcs: ["src/test/minigzip.c"],
shared_libs: ["libz"],
stl: "none",
}
每个模块都必须具有 name
属性,并且相应值在所有 文件中必须是唯一的,仅有两个例外情况是命名空间和预编译模块中的 Android.bp
属性值,且可能会重复。
如需有效模块类型及其属性的列表,请参阅 Soong 模块参考。
类型
变量和属性是强类型,变量根据第一项赋值动态变化,属性由模块类型静态设置。支持的类型为:
- 布尔值(
true
或false
) - 整数 (
int
) - 字符串 (
"string"
) - 字符串列表 (
["string1", "string2"]
) - 映射 (
{key1: "value1", key2: ["value2"]}
)
映射可以包含任何类型的值,包括嵌套映射。列表和映射可能在最后一个值后面有终止逗号。
Glob
接受文件列表的属性(例如 srcs
)也可以采用 glob 模式。glob 模式可以包含普通的 UNIX 通配符 *
,例如 *.java
。glob 模式还可以包含单个 **
通配符作为路径元素,与零个或多个路径元素匹配。例如,java/**/*.java
与以下二者均匹配:java/Main.java
java/com/android/Main.java
变量
Android.bp
文件可能包含顶级变量赋值:
gzip_srcs = ["src/test/minigzip.c"],
cc_binary {
name: "gzip",
srcs: gzip_srcs,
shared_libs: ["libz"],
stl: "none",
}
变量的作用域限定在声明它们的文件的其余部分,以及所有子 Blueprint 文件。变量是不可变的,但有一个例外情况:可以使用 += 赋值将变量附加到别处,但只能在引用它们之前附加。
注释
Android.bp
文件可以包含 C 样式的多行 /* */
注释以及 C ++ 样式的单行 //
注释。
运算符
可以使用 + 运算符附加字符串、字符串列表和映射。可以使用 + 运算符对整数求和。附加映射会生成两个映射中键的并集,并附加在两个映射中都存在的所有键的值。
条件语句
Soong 不支持 Android.bp
文件中的条件语句。但是,编译规则中需要条件语句的复杂问题将在 Go(在这种语言中,您可以使用高级语言功能,并且可以跟踪条件语句引入的隐式依赖项)中处理。大多数条件语句都会转换为映射属性,其中选择了映射中的某个值并将其附加到顶级属性。
例如,要支持特定于架构的文件,请使用以下命令:
cc_library {
...
srcs: ["generic.cpp"],
arch: {
arm: {
srcs: ["arm.cpp"],
},
x86: {
srcs: ["x86.cpp"],
},
},
}
格式设置工具
Soong 包含一个针对 Blueprint 文件的规范格式设置工具,类似于 gofmt。要以递归方式重新格式化当前目录中的所有 Android.bp
文件,请运行以下命令:
bpfmt -w .
规范格式包括缩进四个空格、多元素列表的每个元素后面有换行符,以及列表和映射末尾有逗号。
Soong 中的特殊模块
一些特殊模块组具有独特的特征。
默认模块
默认模块可用于在多个模块中重复使用相同的属性。例如:
cc_defaults {
name: "gzip_defaults",
shared_libs: ["libz"],
stl: "none",
}
cc_binary {
name: "gzip",
defaults: ["gzip_defaults"],
srcs: ["src/test/minigzip.c"],
}
预编译的模块
某些预编译的模块类型允许模块与其基于源代码的对应模块具有相同的名称。例如,如果已有同名的 cc_binary
,也可以将 cc_prebuilt_binary
命名为 foo
。这让开发者可以灵活地选择要纳入其最终产品中的版本。如果编译配置包含两个版本,则预编译模块定义中的 prefer
标记值会指示哪个版本具有优先级。请注意,某些预编译模块的名称不能以 prebuilt
开头,例如 android_app_import
。
命名空间模块
在 Android 完全从 Make 转换为 Soong 之前,Make 产品配置必须指定 PRODUCT_SOONG_NAMESPACES
值。它的值应该是一个以空格分隔的列表,其中包含 Soong 导出到 Make 以使用 m
命令进行编译的命名空间。在 Android 完成到 Soong 的转换之后,启用命名空间的详细信息可能会发生变化。
Soong 可以让不同目录中的模块指定相同的名称,只要每个模块都在单独的命名空间中声明即可。可以按如下方式声明命名空间:
soong_namespace {
imports: ["path/to/otherNamespace1", "path/to/otherNamespace2"],
}
请注意,命名空间没有 name 属性;其路径会自动指定为其名称。
系统会根据每个 Soong 模块在树中的位置为其分配命名空间。每个 Soong 模块都会被视为处于 Android.bp
(位于当前目录或最近的父级目录中的 soong_namespace
文件内)定义的命名空间中。如果未找到此类 soong_namespace
模块,则认为该模块位于隐式根命名空间中。
下面是一个示例:Soong 尝试解析由模块 M 在名称空间 N(导入命名空间 I1、I2、I3…)中声明的依赖项 D
- 如果 D 是
//namespace:module
格式的完全限定名称,系统将仅在指定的命名空间中搜索指定的模块名称。 - 否则,Soong 将首先查找在命名空间 N 中声明的名为 D 的模块。
- 如果该模块不存在,Soong 会在命名空间 I1、I2、I3…中查找名为 D 的模块。
- 最后,Soong 在根命名空间中查找。
转换mk文件到bp文件
升级 Android 系统时,可以使用 androidmk 快速的将 Android.mk 转换为 Android.bp 文件。该工具可以转换变量、模块、注释和一些条件,但任何自定义Makefile规则、复杂条件或额外的include都必须手动转换。
Android.mk 文件通常有多个同名模块,如库的静态和共享版本或主机和设备版本。Android.bp 文件要求每个模块的名称都是唯一的,但是一个模块可以构建成多个变体,例如添加host-supported:true
。androidmk 转换同名模块会产生多个冲突,必须手改为单个模块,将模块的差异放在target: { android: { }, host: { } }
中。
例如一个原始的 Android.mk
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
common_src_dir := java
LOCAL_SRC_FILES += $(call all-java-files-under, $(common_src_dir))
LOCAL_MODULE := my-vendor
LOCAL_MODULE_CLASS := JAVA_LIBRARIES
LOCAL_PROPRIETARY_MODULE := true
include $(BUILD_JAVA_LIBRARY)
使用如下的命令将产生 Blueprint 格式的输出。
$ out/soong/host/linux-x86/bin/androidmk Android.mk > Android.bp
common_src_dir = ["java"]
java_library {
srcs: ["<'common_src_dir' unset>/**/*.java"],
name: "my-vendor",
proprietary: true,
}