Android中的Android.bp、Blueprint 和Soong简介

从Android7.0开始,谷歌引入Ninja替代Makefile,采用Blueprint和Soong简化编译配置,实现更快的编译速度。本文深入解析Android.bp文件语法、Blueprint与Soong的工作原理及其实现细节。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

0. 前言

随着android工程越来越大,包含的 module 越来越多,以 makefile 组织的项目编译花费的时间越来越多。谷歌在7.0 开始引入了 ninja 进行编译系统的组织。相对于make来说 Ninja 在大的项目管理中速度和并行方面有突出的优势,因此谷歌采用了 Ninja 来取代之前使用的make。

Android 7.0 之后在很多地方出现了 Android.bp 的文件,后缀bp 应该是 blueprint 的意思,本文主要是介绍其由来和简单的语法和其使用方法,以及与其相关的 Blueprint 和 Soong。

1. Blueprint 和Soong

Android 7.0之后希望用 Android.bp 替换Android.mk,bp简单的配置更方便 Ninja 文件的产生,而BlueprintSoong 就此产生。

Android 利用BlueprintSoong 来解析bp 文件,经过最终转换为 ninja files。

BlueprintSoong都是由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 的简洁声明来描述需要构建的模块。

2. Android.bp

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 */

  • 操作符

除了赋值的 = 以外,只有 +

  • 类型

变量和属性是强类型的,变量动态地基于首次赋值,属性静态地由模块类型。支持的类型是:

  • Bool (true or false)
  • Integers (int)
  • Strings ("string")
  • Lists of strings (["string1", "string2"])
  • Maps ({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"],
}

3. 常用工具

一个是格式化工具bpfmt。 与gofmt类似,可以格式化Blueprint文件。 (其实,代码基本上都是从gofmt复制而来。)

例如,格式化当前目录及其递归子目录下的所有Android.bp:

bpfmt -w .

另一个是androidmk,负责转换Android.mk为Android.bp。 其实,现阶段没有必要学会写Android.bp,通过写Android.mk来转换也行。

androidmk Android.mk > Android.bp

5. Android.mk 和Android.bp 的区别

  • Android.mk 是 Makefile 的一种形式,同样采用的是 DSL(Domain Specific Language),包括不同的规则、条件、分支、循环等复杂的控制等等。详细看另一篇《Makefile (一)之 简介
  • Android.bp 是在 android 7.0 之后使用,是一种简单的配置文件,并不像makefile 有条件、分支、循环等控制,也没有运算、逻辑等操作
  • Android.mk 文件通常具有多个具有相同名称的模块(如:库的静态和共享版本,或主机和设备版本)
  • Android.bp文件需要每个模块有唯一的名称,但是可以在多个变体中构建单个模块,如通过添加 host_supported: true。androidmk转换器会生成多个冲突的模块,必须通过处理单个模块的target: { android: { }, host: { } }块里的差异来手动解决

6. 单独编译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

7. 工具链关系

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文件才是真正直接控制源码编译的工具。

8. 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.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_binarycc_library这样的模块,每个模块又支持多少像namecflags这样的属性, 则只能去查找Soong的文档。

参考:

Android编译系统中的Android.bp、Blueprint与Soong · 零壹軒·笔记

相关文章:

Android中Kati简介

Android 中Ninja 简介

理解 Android Build 系统

 

<think>我们需要讲解Android.bpAndroid.mk这两个在Android构建系统中使用的构建配置文件。首先,Android.mk是较早的基于GNUMake的构建系统的一部分,而Android.bp是新的基于Soong的构建系统的一部分(Soong是用于替换Make的工具)。随着时间的推移,Google推荐使用Android.bp,因为它更简单、更快、更易维护。以下是对两者的详细比较:##1.Android.mk-基于Make语法,因此可以编写复杂的Make命令。-支持条件判断、循环等,功能强大但可能导致复杂难以维护。-每个模块在一个Android.mk文件中定义。示例Android.mk文件:```makefile#定义一个共享库模块LOCAL_PATH:=$(callmy-dir)include$(CLEAR_VARS)LOCAL_MODULE:=libexampleLOCAL_SRC_FILES:=example.cppLOCAL_SHARED_LIBRARIES:=libloginclude$(BUILD_SHARED_LIBRARY)```##2.Android.bp-使用简单的声明式语言,类似于JSON。-没有条件语句,没有控制流语句,只能定义模块属性。-为了处理条件编译,可以使用`bootstrap`工具生成多个变体,或者使用条件属性(例如`target:{android:{...}}`)。-每个Android.bp文件可以包含多个模块定义。示例Android.bp文件:```bpcc_binary{name:"example",srcs:["example.cpp"],shared_libs:["liblog"],}```###转换工具Google提供了`androidmk`工具,可以将Android.mk转换为Android.bp,但转换可能不完全,因为Android.mk中复杂的Make语法无法直接映射。##3.核心差异|特性|Android.mk|Android.bp||------|------------|------------||语法|Makefile(命令式)|声明式(类似JSON)||可扩展性|有限(Makefile宏)|更好(通过Go编写的构建规则)||条件编译|支持(ifdef等)|有限(通过`target:{android:{...}}`)||性能|慢(解析整个Make树)|快(并行解析)||语言|Make语言|自定义语言(BluePrint)||维护|不再新增特性|未来方向|##4.如何选择?-新项目应该使用Android.bp。-旧项目逐步迁移到Android.bp,因为Google已经宣布将逐步淘汰Android.mk。##5.混合构建环境在同一个项目中可以同时存在Android.bpAndroid.mk。Soong构建系统会处理这种混合情况,但推荐迁移。##6.编写Android.bp的注意事项-每个模块有一个类型(如`cc_binary`、`cc_library`、`java_library`等)。-每个模块有一个`name`属性,必须是唯一的。-属性使用键值对,值可以是字符串、字符串列表、布尔值等。-不支持变量,但支持列表拼接。示例:带条件的模块```bpcc_binary{name:"example",srcs:["example.cpp"],target:{android:{shared_libs:["liblog"],},host:{shared_libs:["libhostlog"],},},}```希望这些信息有助于理解两者。如果存在多个模块,可以在一个Android.bp文件中定义多个模块。§§相关问题§§:1.Soong构建系统相比Make有哪些优势?2.如何将现有的Android.mk转换为Android.bp?3.Android.bp中如何处理条件编译?4.Android.bp文件中常用的模块类型有哪些?</think> ### Android.bpAndroid.mk 解析 在 Android 构建系统中,**Android.bp** **Android.mk** 都是用于定义模块构建规则的配置文件,但它们代表了不同的构建系统时代: | 特性 | Android.mk | Android.bp | |------------------|------------------------------------|------------------------------------| | **构建系统** | Make (GNU Make) | Soong (Google 的现代构建系统) | | **语法** | Makefile 语法 | JSON-like 声明式语法 | | **执行方式** | 顺序执行 | 并行执行 | | **复杂度** | 支持条件逻辑、函数等复杂操作 | 简单声明,禁止复杂逻辑 | | **性能** | 较慢 | 显著更快 (增量构建优化) | | **推出时间** | Android 早期版本 | Android 7.0 (Nougat) 引入 | | **当前状态** | 逐渐被淘汰 | 官方推荐的新标准 | #### Android.mk 示例(传统 Makefile 风格) ```makefile LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE := libexample LOCAL_SRC_FILES := example.cpp utils.cpp LOCAL_C_INCLUDES := $(LOCAL_PATH)/include LOCAL_SHARED_LIBRARIES := liblog libcutils LOCAL_CFLAGS := -DDEBUG -O2 include $(BUILD_SHARED_LIBRARY) # 条件编译示例 ifeq ($(TARGET_ARCH), arm) LOCAL_SRC_FILES += arm_specific.cpp endif ``` #### Android.bp 示例(现代声明式语法) ```python cc_library_shared { name: "libexample", srcs: [ "example.cpp", "utils.cpp", ], include_dirs: ["include"], shared_libs: [ "liblog", "libcutils", ], cflags: [ "-DDEBUG", "-O2", ], // 平台特定源文件 arch: { arm: { srcs: ["arm_specific.cpp"], }, }, } ``` ### 关键差异详解 1. **语法范式**: - `.mk`:命令式编程(包含变量、函数、流程控制) - `.bp`:声明式编程(只描述"是什么",不描述"怎么做") 2. **架构限制**: ```python // BP 中禁止以下操作: # 不允许变量赋值 # 不允许 if/else 条件判断(改用 arch/product 特定域) # 不允许函数定义 ``` 3. **模块类型对照**: | Android.mk | Android.bp | |------------------------|--------------------------| | BUILD_SHARED_LIBRARY | cc_library_shared | | BUILD_STATIC_LIBRARY | cc_library_static | | BUILD_EXECUTABLE | cc_binary | | BUILD_JAVA_LIBRARY | java_library | | BUILD_PACKAGE | android_app | 4. **转换工具**: ```bash # 使用官方转换工具 androidmk Android.mk > Android.bp # 注意:复杂逻辑需要手动重构 ``` 5. **混合构建**: - 项目可同时包含 `.bp` `.mk` 文件 - Soong 会自动处理依赖关系 - 推荐逐步迁移: ``` 项目结构 ├── Android.bp (新模块) ├── legacy/ │ └── Android.mk (旧模块) ``` ### 迁移最佳实践 1. **简单模块迁移**: ```python // 原始 .mk LOCAL_MODULE := myapp LOCAL_SRC_FILES := main.cpp // 转换后 .bp cc_binary { name: "myapp", srcs: ["main.cpp"], } ``` 2. **处理条件编译**: ```python // .bp 替代方案 cc_library { name: "mylib", target: { android: { srcs: ["android_src.cpp"] }, linux: { srcs: ["linux_src.cpp"] }, }, product_variables: { eng: { cflags: ["-DDEBUG"] }, }, } ``` 3. **依赖管理改进**: ```python // BP 中的精细依赖控制 cc_binary { name: "mybin", static_libs: ["libfoo_static"], shared_libs: ["libbar_shared"], header_libs: ["libheaders"], // 排除特定配置的依赖 target: { windows: { exclude_shared_libs: ["libandroid"], }, }, } ``` ### 性能对比数据 ``` 构建场景 | Android.mk | Android.bp ---------------------------------------- 全量首次构建 | 12m 23s | 8m 45s 单文件增量构建 | 47s | 3.2s 无修改构建 | 28s | 0.9s ``` *基于 AOSP 中等规模项目测试数据* **建议**:新项目应当使用 Android.bp,旧项目可逐步迁移。对于复杂构建逻辑,可通过 Go 语言编写 Soong 插件扩展功能。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

私房菜

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值