刨根问底 - 安卓编译 Android.bp 使用方法

2023-02-28  本文已影响0人  star_walker

简介 - 这东西是从哪里来的呢?

Android.bp 是 Android 编译系统从 make 系统切换到 ninja 系统过程中的产物,Android 7.0 和 8.0 是该编译系统切换的过渡期,所以在 Android 7.0 和 8.0 时既可以看到 Android.mk,也可以看到 Android.bp,但是从 Android 9.0 开始,在Android 源码里面 Android.mk 已经看不到了,只有少数 Vendor 厂家的代码里面还可以看到。

这次切换的背后原因是,Android 要提升编译效率,显著提升的是第一次编译后增量编译的速度,但是由于 Android 工程越来越庞大,这个效率很难被大家感受到。

内容 - 这东西内容长啥样呢?

以 hardware/libhardware/Android.bp 为例,其内容与 json 文件非常类似,实际上也是一种更加简洁的编译配置文件,相比 Android.mk,可阅读性更强,但是前提是有很好的 Android.bp 语法基础。

cc_library_shared {
     name: “libxmlrpc++”,

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

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

相同的 Android.mk 长下面这样:

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)

语法 - 怎么阅读呢?

语法是这样的(多数内容来自 Android 官网介绍):

模块

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>" 来引用生成源文件的其他模块的输出,如 genrulefilegroup

如需有效模块类型及其属性的列表,请参阅 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 .

规范格式包括缩进四个空格、多元素列表的每个元素后面有换行符,以及列表和映射末尾有英文逗号。

特殊模块

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

默认模块

默认模块可用于在多个模块中重复使用相同的属性。例如:

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。这让开发者可以灵活地选择要纳入其最终产品中的版本。如果 build 配置包含两个版本,那么预编译模块定义中的 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。

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

举个栗子,实际解析一下

以 frameworks/native/services/surfaceflinger/Android.bp 的前 1/3 内容为例。

cc_defaults { // 到这个链接里面查一下,
// https://ci.android.com/builds/submitted/9670465/linux/latest/view/soong_build.html,
// cc_defaults provides a set of properties that can be inherited by other cc modules. A module 
// can use the properties from a cc_defaults using `defaults: ["<:default_module_name>"]`. 
// Properties of both modules are merged (when possible) by prepending the default module's values to 
// the depending module's values. 
// cc_defaults 一般是被继承的类常用的类型。
    name: "surfaceflinger_defaults", // 这个 module 的名字是 surfaceflinger_defaults,字符串类型。
    cflags: [ // 这是 gcc 的编译选项,不懂的话,可以参考下面链接:
              // https://blog.csdn.net/shenhuxi_yu/article/details/79788760。
        "-DLOG_TAG=\"SurfaceFlinger\"",
        "-Wall",
        "-Werror",
        "-Wthread-safety",
        "-Wunused",
        "-Wunreachable-code",
    ],
    cppflags: ["-std=c++1z"], // 这是 g++ 的编译选项。
}

cc_defaults { // 类型是 cc_defaults。
    name: "libsurfaceflinger_defaults", // 名字是 libsurfaceflinger_defaults
    defaults: ["surfaceflinger_defaults"], // 从 surfaceflinger_defaults 继承。
    cflags: [ // gcc 编译选项。
        "-DGL_GLEXT_PROTOTYPES",
        "-DEGL_EGLEXT_PROTOTYPES",
    ],

    shared_libs: [ // list of string, list of shared libraries that provide headers for this binding.
        "android.frameworks.vr.composer@1.0",
        "android.hardware.configstore-utils",
        "android.hardware.configstore@1.0",
        "android.hardware.configstore@1.1",
        "android.hardware.graphics.allocator@2.0",
        "android.hardware.graphics.composer@2.1",
        "android.hardware.graphics.composer@2.2",
        "android.hardware.power@1.0",
        "libbase",
        "libbinder",
        "libbufferhubqueue",
        "libcutils",
        "libdl",
        "libEGL",
        "libfmq",
        "libGLESv1_CM",
        "libGLESv2",
        "libgui",
        "libhardware",
        "libhidlbase",
        "libhidltransport",
        "libhwbinder",
        "liblayers_proto",
        "liblog",
        "libpdx_default_transport",
        "libprotobuf-cpp-lite",
        "libsync",
        "libtimestats_proto",
        "libui",
        "libutils",
        "libvulkan",
    ],
    static_libs: [ // list of string, list of static libraries that provide headers for this binding.
        "libserviceutils",
        "libtrace_proto",
        "libvkjson",
        "libvr_manager",
        "libvrflinger",
    ],
    header_libs: [ // list of string, List of libraries which export include paths required for this module.
        "android.hardware.graphics.composer@2.1-command-buffer",
        "android.hardware.graphics.composer@2.2-command-buffer",
    ],
    export_static_lib_headers: [ // list of string, list of static libraries to re-export include directories from. Entries must be present in static_libs.
        "libserviceutils",
    ],
    export_shared_lib_headers: [ // list of string, list of shared libraries to re-export include directories from. Entries must be present in shared_libs.
        "android.hardware.graphics.allocator@2.0",
        "android.hardware.graphics.composer@2.1",
        "android.hardware.graphics.composer@2.2",
        "libhidlbase",
        "libhidltransport",
        "libhwbinder",
    ],
}
上一篇下一篇

猜你喜欢

热点阅读