本文基于Android 10.0源码分析
1.概述
在Android 7.0 之前,Android 编译系统使用GNU Make描述和shell来构建编译规则,模块定义都使用Android.mk进行定义,Android.mk的本质就是Makefile,但是随着Android的工程越来越大,模块越来越多,Makefile组织的项目编译时间越来越长。这样下去Google工程师觉得不行,得要优化。
因此,在Android 7.0开始,Google采用ninja来代取代之前使用的make,由于之前的Android.mk数据实在巨大,因此Google加入了一个kati工具,用于将Android.mk转换成ninja的构建规则文件buildxxx.ninja,再使用ninja来进行构建工作。
ninja的网址:https://ninja-build.org
编译速度快了一些,但是既然要干, 那就干个大的,最终目标要把make都取代,于是从Android8.0开始,Google为了进一步淘汰Makefile,因此引入了Android.bp文件来替换之前的Android.mk。
Android系统的编译历程:
2.Android.bp文件格式
根据设计,Android.bp文件很简单。它们不包含任何条件语句,也不包含控制流语句;所有复杂问题都由用Go 编写的构建逻辑处理。Android.bp文件的语法和语义都尽可能与Bazel BUILD文件类似。
2.1 模块
Android.bp文件中的模块以模块类型开头,后跟一组name: "value",格式的属性。
cc_binary {
name: "gzip",
srcs: ["src/test/minigzip.c"],
shared_libs: ["libz"],
stl: "none",
}
每个模块都必须具有name属性,并且相应值在所有name文件中必须是唯一的,仅有两个例外情况是命名空间和预构建模块中的Android.bp属性值,这两个值可能会重复。
srcs 属性以字符串列表的形式指定用于构建模块的源文件。您可以使用模块引用语法 ":<module-name>" 来引用生成源文件的其他模块的输出,如 genrule 或 filegroup。如需有效模块类型及其属性的列表,请参阅 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 类型
变量和属性是强类型,变量根据第一项赋值动态变化,属性由模块类型静态设置。支持的类型为:
布尔值Bool(true 或 false)
整数Integers (int)
字符串Strings ("string")
字符串列表List of string (["string1", "string2"])
映射Maps ({key1: "value1", key2: ["value2"]})
映射可以包含任何类型的值,包括嵌套映射。列表和映射可能在最后一个值后面有终止逗号。
2.3 Glob
接受文件列表的属性(例如 srcs)也可以采用glob模式。glob模式可以包含普通的UNIX通配符,例如.java。glob模式还可以包含单个**通配符作为路径元素,与零个或多个路径元素匹配。例如,java/*/.java同时匹配 java/Main.java和java/com/android/Main.java模式。
2.4 变量
Android.bp文件可能包含顶级变量赋值:
gzip_srcs = ["src/test/minigzip.c"]
cc_binary {
srcs: gzip_srcs,
shared_libs: ["libz"],
stl: "none",
}
变量的作用域限定在声明它们的文件的其余部分,以及所有子Android.bp文件,可以使用 “=” 号赋值, 但是不能使用 “:=” 赋值。变量是不可变的,但有一个例外情况:可以使用 += 赋值将变量附加到别处,但只能在引用它们之前附加。例:
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 "//" Comments test
// =========================================================
/*This is a "/**/" Comments test*/
2.6 运算符
可以使用+运算符附加字符串、字符串列表和映射。可以使用+运算符对整数求和。附加映射会生成两个映射中键的并集,并附加在两个映射中都存在的所有键的值。
2.7 条件语句
Soong不支持Android.bp文件中的条件语句。但是,编译规则中需要条件语句的复杂问题将在Go(在这种语言中,可以使用高级语言功能,并且可以跟踪条件语句引入的隐式依赖项)中处理。大多数条件语句都会转换为映射属性,其中选择了映射中的某个值并将其附加到顶级属性。
例如,要支持特定于架构的文件,请使用以下命令:
cc_library {
...
srcs: ["generic.cpp"],
arch: {
arm: {
srcs: ["arm.cpp"],
},
x86: {
srcs: ["x86.cpp"],
},
},
}
2.8 格式设置工具
Soong包含一个针对Blueprint文件的规范格式设置工具,类似于gofmt。如需以递归方式重新设置当前目录中所有Android.bp文件的格式,请运行以下命令:
bpfmt -w .
规范格式包括缩进四个空格、多元素列表的每个元素后面有换行符,以及列表和映射末尾有英文逗号。
2.9 默认模块
默认模块可用于在多个模块中重复使用相同的属性。例如:
cc_defaults {
name: "gzip_defaults",
shared_libs: ["libz"],
stl: "none",
}
cc_binary {
name: "gzip",
defaults: ["gzip_defaults"],
srcs: ["src/test/minigzip.c"],
}
2.10 预编译的模块
某些预构建的模块类型允许模块与其基于源代码的对应模块具有相同的名称。例如,如果已有同名的 cc_binary,也可以将cc_prebuilt_binary命名为foo。这让开发者可以灵活地选择要纳入其最终产品中的版本。如果编译配置包含两个版本,则预编译模块定义中的prefer标记值会指示哪个版本具有优先级。请注意,某些预编译模块的名称不能以prebuilt开头,例如android_app_import。
2.11 命名空间模块
在 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在根命名空间中查找。
2.12 Android.mk文件自动转Android.bp方法
Android源码里边提供了快捷直接Android.mk转换成Android.bp的工具:androidmk。
(1)androidmk源码位置
build/soong/androidmk/cmd/androidmk/androidmk.go
(2)编译出来后androidmk可执行文件位置
aosp/out/soong/host/linux-x86/bin/androidmk
(3)转换方法
aosp/out/soong/host/linux-x86/bin/androidmk [Android.mk PATH] > [Android.bp PATH]
该工具可以转换变量、模块、注释和一些条件,但任何自定义生成文件规则、复杂条件或额外的包含都必须手动转换。