从 Make 转换为 Soong

在 Android 7.0 版本之前,Android 专门使用 GNU Make 来描述和执行其构建规则。Make 构建系统被广泛支持和使用,但在 Android 的规模下,变得缓慢、容易出错、不可扩展且难以测试。Soong 构建系统提供了 Android 构建所需的灵活性。

因此,平台开发人员应尽快从 Make 切换并采用 Soong。将问题发送到 android-building Google 网上论坛以获得支持。

什么是 Soong?

Soong 构建系统在 Android 7.0 (Nougat) 中引入,以取代 Make。它利用 Kati GNU Make 克隆工具和 Ninja 构建系统组件来加速 Android 的构建。

请参阅 Android 开源项目 (AOSP) 中的 Android Make 构建系统描述,以获取一般的 说明以及 Android.mk 编写者的构建系统更改,以了解从 Make 适应 Soong 所需的修改。

请参阅词汇表中的 构建相关条目,以获取关键术语的定义,以及 Soong 参考文件,以获取完整详细信息。

Make 和 Soong 比较

以下是将 Make 配置与 Soong 配置(Blueprint 或 .bp)文件中完成相同操作的 Soong 配置进行比较。

Make 示例

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)
LOCAL_MODULE := libxmlrpc++
LOCAL_MODULE_HOST_OS := linux

LOCAL_RTTI_FLAG := -frtti
LOCAL_CPPFLAGS := -Wall -Werror -fexceptions
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/src

LOCAL_SRC_FILES := $(call \
     all-cpp-files-under,src)
include $(BUILD_SHARED_LIBRARY)

Soong 示例

cc_library_shared {
     name: "libxmlrpc++",

     rtti: true,
     cppflags: [
           "-Wall",
           "-Werror",
           "-fexceptions",
     ],
     export_include_dirs: ["src"],
     srcs: ["src/**/*.cpp"],

     target: {
           darwin: {
                enabled: false,
           },
     },
}

有关特定于测试的 Soong 配置示例,请参阅 简单构建配置

有关 Android.bp 文件中字段的说明,请参阅 Android.bp 文件格式

特殊模块

一些特殊模块组具有独特的特性。

Defaults 模块

defaults 模块可用于在多个模块中重复相同的属性。例如

cc_defaults {
    name: "gzip_defaults",
    shared_libs: ["libz"],
    stl: "none",
}

cc_binary {
    name: "gzip",
    defaults: ["gzip_defaults"],
    srcs: ["src/test/minigzip.c"],
}

Prebuilt 模块

某些预构建模块类型允许模块与其基于源代码的对应模块具有相同的名称。例如,当已经有一个同名的 cc_binary 时,可以有一个名为 foocc_prebuilt_binary。这使开发人员可以灵活地选择要包含在其最终产品中的版本。如果构建配置同时包含这两个版本,则预构建模块定义中的 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"],
}

请注意,命名空间没有名称属性;其路径会自动分配为其名称。

每个 Soong 模块都根据其在树中的位置分配一个命名空间。每个 Soong 模块都被认为位于由当前目录或最近的祖先目录中的 Android.bp 文件中找到的 soong_namespace 定义的命名空间中。如果找不到这样的 soong_namespace 模块,则该模块被认为位于隐式根命名空间中。

这是一个示例:Soong 尝试解析命名空间 N 中模块 M 声明的依赖项 D,该命名空间导入命名空间 I1、I2、I3…

  1. 然后,如果 D 是 //namespace:module 形式的完全限定名称,则仅在指定的命名空间中搜索指定的模块名称。
  2. 否则,Soong 首先在命名空间 N 中查找名为 D 的模块。
  3. 如果该模块不存在,Soong 会在命名空间 I1、I2、I3… 中查找名为 D 的模块。
  4. 最后,Soong 在根命名空间中查找。