Android 编译之android.bp

引言

Android编译知识的梳理文章共三篇:

本文是最后一篇,主要介绍android.bp。

1. Ninja

1.1 Ninja简介

Ninja 是一个专注于速度的小型构建系统。它与其他构建系统在两个主要方面不同:

  • Ninja的输入文件被设计为由更高级的构建系统生成。
  • Ninja被设计为尽可能快地运行构建, 其他构建系统基于高级语言,而Ninja基于汇编。

Ninja基于汇编,专注于速度,不支持分支、循环等流程控制,也不支持逻辑运算,但它允许以其它语言如来维护这些复杂的编译流程和逻辑。例如,我们可以采用Makefile, go, python等等来维护编译的流程和逻辑。

1.2 Ninja的构建文件

虽然Ninja的构建文件是可读的(human-readable),但是手写不是特别方便。我们可以先来看一段ninja文件的内容:

# This file is used to build ninja itself.
# It is generated by configure.py.

ninja_required_version = 1.3

# The arguments passed to configure.py, for rerunning it.
configure_args = 

root = .
builddir = build
cxx = g++
ar = ar
cflags = -g -Wall -Wextra -Wno-deprecated -Wno-missing-field-initializers $
-Wno-unused-parameter -fno-rtti -fno-exceptions -fvisibility=hidden $
-pipe '-DNINJA_PYTHON="python"' -O2 -DNDEBUG -DUSE_PPOLL $
-DNINJA_HAVE_BROWSE -I.
ldflags = -L$builddir

rule cxx
  command = $cxx -MMD -MT $out -MF $out.d $cflags -c $in -o $out
  description = CXX $out
  depfile = $out.d
  deps = gcc

rule ar
  command = rm -f $out && $ar crs $out $in
  description = AR $out

rule link
  command = $cxx $ldflags -o $out $in $libs
  description = LINK $out

可以看到,ninja的构建文件,书写起来是不很方便的,所以,我们需要一些ninja构建文件的生成器。这些生成器就是一些元构建系统(meta-build system),例如Blueprint、CMake等等。Ninja的基于底层实现使其非常适合嵌入到这些功能更强大的构建系统中。更多ninja构建文件的生成器,可参考:List of generators producing ninja build files

Ninja用于构建Google Chrome浏览器,Android,LLVM的一部分。由于CMake可在大多数平台上运行,并且可以生成多种格式的项目文件,包括Ninja。所以Ninja也可以作为CMake的底层实现,在许多其他项目中使用。

1.3 Ninja的下载和使用

Ninja的最新版本为v1.10.2,于2020年11月23日发布:Ninja release v1.10.2
当然我们也可以下载ninja源码自行编译:

$ git clone git://github.com/ninja-build/ninja.git && cd ninja
$ git checkout release
$ cat README

Ninja的设计哲学和设计背景,是否以及如何在项目中使用Ninja,Ninja的平台支持以及Ninja详细的语言语义等等更多Ninja相关的知识,请参考:
Ninjia使用手册

2. Blueprint

2.1 Blueprint简介

Blueprint 是一个元构建系统,该系统读取Blueprint文件来描述需要构建的模块,并生成一个Ninja清单来描述需要运行的命令及其依赖项。 在大多数构建系统使用内置规则或特定领域语言来描述将模块描述转换为构建规则的逻辑。Blueprint将其委托给使用Go编写的针对每个项目的构建逻辑。 对于大型,异构项目,这允许以高级语言维护固有、复杂的构建逻辑,同时仍可以通过修改易于理解的Blueprint文件来对单个模块进行简单更改。

2.2 android中的Blueprint

前面在Ninja的构建文件一节我们提到了,Blueprint是ninja构建文件的生成器。android编译系统soong集成了Blueprint,Blueprint可将我们编写的android.bp解析生成一个ninja构建文件。我们在编译一个模块时,只需要将这个模块的android.bp文件配置好,编译系统会自动为这个模块生成ninja清单,最终使用ninja来调用gcc、clang、java、dex、aapt2等等命令来构建模块。

3. kati

kati 是Google开发的一个实验性的GNU make clone,kati的主要目标是加快Android的增量构建。目前,kati本身并不能提供更快的构建。 而是将Makefile转换为ninja。一开始kati是用go语言开发的,但作者发现使用go写的有性能问题,后来作者又用C++进行了重写,也就是kati变成了ckati(作者的原文描述可以查看android源码目录下的:build/kati/INTERNALS.md)。后续提到kati时,如不特别指出,即是指ckati。

简单点说,kati就是一个转换工具,它可以将Makefile和.mk文件转换为ninja。

android源码目录下的:prebuilts/build-tools下有预置的kati,Android 7.0及以上版本,编译源码时会自动使用kati。大多数情况下,我们不会直接使用kati,但如果你还想了解更多kati的相关信息,可以访问:https://github.com/google/kati。也可以查看android源码目录下的 build/kati/INTERNALS.mdbuild/kati/README.md

4. soong

4.1 soong简介

在android 6.0版本之前,编译android源码采用的是基于make的编译系统(make-based build system),也就是android的各个库、APK等等目标文件都是采用make来构建的。 但是,由于make在编译时表现出效率不够高、增量编译速度慢等问题,Google在android 7.0版本引进了编译速度更快的soong来替代make。

Soong集成了Ninja, 而Ninja专注于速度,没有条件或流程控制语句,也不支持逻辑运算。但它允许以其它语言如来维护这些复杂的编译流程和逻辑。例如,我们可以继续采用makefile, 或者采用go语言来维护编译流程和逻辑。上面已经提到了Ninja,Blueprint, kati等等好几种工具,为了完整、快速的构建一个android系统,就需要一个“管家”来协调这些工具。例如,将.bp转换成ninja时使用Blueprint, 将Makefile转换成ninja时使用kati。这个选择转换工具、选择解析框架、解析维护构建逻辑的“管家”就是soong。

编译android源码时,soong也会被自动使用,我们可以和原来一样:

  • 首先,source build/envsetup.sh。
  • 然后,lunch选择target。
  • 最后,使用m、mm、mmm或者make来编译指定的模块或者整个系统。

但是,m、mm、mmm或者make最终都会使用soong来编译。因为source之后,build/envsetup.sh中已经将make指向soong了:

function get_make_command()
{
    # If we're in the top of an Android tree, use soong_ui.bash instead of make
    if [ -f build/soong/soong_ui.bash ]; then
        # Always use the real make if -C is passed in
        for arg in "$@"; do
            if [[ $arg == -C* ]]; then
                echo command make
                return
            fi
        done
        echo build/soong/soong_ui.bash --make-mode
    else
        echo command make
    fi
}

function make()
{
    _wrap_build $(get_make_command "$@") "$@"
}

function m()
{
    local T=$(gettop)
    if [ "$T" ]; then
        _wrap_build $T/build/soong/soong_ui.bash --make-mode $@
    else
        echo "Couldn't locate the top of the tree.  Try setting TOP."
        return 1
    fi
}

function mm()
{
    local T=$(gettop)
    # If we're sitting in the root of the build tree, just do a
    # normal build.
    if [ -f build/soong/soong_ui.bash ]; then
        _wrap_build $T/build/soong/soong_ui.bash --make-mode $@
    else
        # Find the closest Android.mk file.
        local M=$(findmakefile)
        local MODULES=
        local GET_INSTALL_PATH=
        local ARGS=
        # Remove the path to top as the makefilepath needs to be relative
        local M=`echo $M|sed 's:'$T'/::'`
        if [ ! "$T" ]; then
            echo "Couldn't locate the top of the tree.  Try setting TOP."
            return 1
        elif [ ! "$M" ]; then
            echo "Couldn't locate a makefile from the current directory."
            return 1
        else
            local ARG
            for ARG in $@; do
                case $ARG in
                  GET-INSTALL-PATH) GET_INSTALL_PATH=$ARG;;
                esac
            done
            if [ -n "$GET_INSTALL_PATH" ]; then
              MODULES=
              ARGS=GET-INSTALL-PATH-IN-$(dirname ${M})
              ARGS=${ARGS//\//-}
            else
              MODULES=MODULES-IN-$(dirname ${M})
              # Convert "/" to "-".
              MODULES=${MODULES//\//-}
              ARGS=$@
            fi
            if [ "1" = "${WITH_TIDY_ONLY}" -o "true" = "${WITH_TIDY_ONLY}" ]; then
              MODULES=tidy_only
            fi
            ONE_SHOT_MAKEFILE=$M _wrap_build $T/build/soong/soong_ui.bash --make-mode $MODULES $ARGS
        fi
    fi
}

function mmm()
{
    local T=$(gettop)
    if [ "$T" ]; then
        local MAKEFILE=
        local MODULES=
        local MODULES_IN_PATHS=
        local ARGS=
        local DIR TO_CHOP
        local DIR_MODULES
        local GET_INSTALL_PATH=
        local GET_INSTALL_PATHS=
        local DASH_ARGS=$(echo "$@" | awk -v RS=" " -v ORS=" " '/^-.*$/')
        local DIRS=$(echo "$@" | awk -v RS=" " -v ORS=" " '/^[^-].*$/')
        for DIR in $DIRS ; do
            DIR_MODULES=`echo $DIR | sed -n -e 's/.*:\(.*$\)/\1/p' | sed 's/,/ /'`
            DIR=`echo $DIR | sed -e 's/:.*//' -e 's:/$::'`
            # Remove the leading ./ and trailing / if any exists.
            DIR=${DIR#./}
            DIR=${DIR%/}
            if [ -f $DIR/Android.mk -o -f $DIR/Android.bp ]; then
                local TO_CHOP=`(\cd -P -- $T && pwd -P) | wc -c | tr -d ' '`
                local TO_CHOP=`expr $TO_CHOP + 1`
                local START=`PWD= /bin/pwd`
                local MDIR=`echo $START | cut -c${TO_CHOP}-`
                if [ "$MDIR" = "" ] ; then
                    MDIR=$DIR
                else
                    MDIR=$MDIR/$DIR
                fi
                MDIR=${MDIR%/.}
                if [ "$DIR_MODULES" = "" ]; then
                    MODULES_IN_PATHS="$MODULES_IN_PATHS MODULES-IN-$MDIR"
                    GET_INSTALL_PATHS="$GET_INSTALL_PATHS GET-INSTALL-PATH-IN-$MDIR"
                else
                    MODULES="$MODULES $DIR_MODULES"
                fi
                MAKEFILE="$MAKEFILE $MDIR/Android.mk"
            else
                case $DIR in
                  showcommands | snod | dist | *=*) ARGS="$ARGS $DIR";;
                  GET-INSTALL-PATH) GET_INSTALL_PATH=$DIR;;
                  *) if [ -d $DIR ]; then
                         echo "No Android.mk in $DIR.";
                     else
                         echo "Couldn't locate the directory $DIR";
                     fi
                     return 1;;
                esac
            fi
        done
        if [ -n "$GET_INSTALL_PATH" ]; then
          ARGS=${GET_INSTALL_PATHS//\//-}
          MODULES=
          MODULES_IN_PATHS=
        fi
        if [ "1" = "${WITH_TIDY_ONLY}" -o "true" = "${WITH_TIDY_ONLY}" ]; then
          MODULES=tidy_only
          MODULES_IN_PATHS=
        fi
        # Convert "/" to "-".
        MODULES_IN_PATHS=${MODULES_IN_PATHS//\//-}
        ONE_SHOT_MAKEFILE="$MAKEFILE" _wrap_build $T/build/soong/soong_ui.bash --make-mode $DASH_ARGS $MODULES $MODULES_IN_PATHS $ARGS
    else
        echo "Couldn't locate the top of the tree.  Try setting TOP."
        return 1
    fi
}

使用make构建项目,主要工作是编写Makefile;类似的,使用soong构建项目,主要工作是编写bp文件。关于bp文件我们会在接下来的第5节中详细介绍。

4.2 androidmk

soong中还集成了一个非常有用的工具androidmk。androidmk可以将android.mk转换成android.bp。我们可以使用androidmk来转换代码中已有的android.mk,以此来减少重写android.bp的工作量。例如,我们将一个Android.mk转换成Android.bp:

androidmk Android.mk > Android.bp

注意:androidmk工具可以转换变量,模块,注释和某些条件,但是自定义的Makefile规则,复杂的条件语句或其它的额外的include语句,必须手动转换。

在现有版本,由于kati工具的存在,继续使用android.mk也是没有问题的。但是,也许在将来的某一天,Google可能会不再支持Makefile。因此,建议新增的模块采用android.bp,存量的android.mk,在条件允许的情况下,也应当尽量转换成android.bp。

4.3 bpfmt

为了方便格式化,Soong还包含了一个用于格式化Android.bp文件的工具bpfmt,类似于gofmt。 以一个简单的bp文件为例:

cc_binary {
    name: "gzip",
    srcs: [
        "src/test/minigzip.c",
        "src/test/utils.c",
    ],
    shared_libs: ["libz"],
    stl: "none",
}

Android.bp的规范格式包括:

  • 4个空格缩进。
  • 多元素列表的每个元素后的换行符。
  • 在lists和maps的结尾处始终包含一个逗号。

我们可以使用bpfmt工具来规范格式化Android.bp文件。例如,要递归地格式化当前目录中的所有Android.bp文件:

bpfmt -w .

4.4 ninja,Blueprint,kati,androidmk与Soong的关系和作用

  • kati可以将Android.mk文件转换成ninja文件。
  • androidmk可以将Android.mk文件转换成Android.bp文件
  • Blueprint可以将Android.bp文件转换成ninja文件。
  • Blueprint,kati,androidmk由Soong调用和协调,一起合作完成android源码的构建。

它们的关系示意图如下:


Soong.png

5. Android.bp

5.1 bp文件的命名与文件格式

soong的编译配置文件以.bp结尾,通常命名为Android.bp,但也有少数情况不以Android.bp命名。例如:frameworks/rs/support.bp。与Makefile一样,使用soong编译前,会遍历所有以bp为后缀名的文件。因此,soong的编译配置文件只要以.bp结尾即可。

5.2 模块(module)

bp文件中的模块(module) 以模块类型(module type)开头,后面跟着一系列的属性(property)。每个模块都必须具有一个属性名为name的属性,并且name的属性值在所有Android.bp文件中必须是唯一的。bp文件的内容与JSON、Bazel BUILD很像,模块的格式为:

[module type] {
    name: "[name value]",
    [property1 name]:"[property1 value]",
    [property2 name]:"[property2 value]",
}

一个简单的bp文件:

cc_binary {
    name: "gzip",
    srcs: ["src/test/minigzip.c"],
    shared_libs: ["libz"],
    stl: "none",
}

常见的模块类型有:
cc_library,
cc_library_headers,
cc_library_shared,
cc_library_static,
android_app,
android_app_certificate,
java_library,
java_library_static,
java_sdk_library等等。

soong预置了一系列的模块类型和属性,芯片原厂也会添加一些自定义的模块类型和属性,例如,MTK平台就定义了一些以mtk开头的模块类型。如果想了解更多,已有源码并且已编译的可以查看:out/soong/docs/soong_build.html。如果没有源码,也可查看AOSP的在线文档:$AOSP/out/soong/docs/soong_build.html

5.2.1 默认模块(defaults)

soong提供了一系列xx_defaults模块类型,例如:cc_defaults, java_defaults, doc_defaults, stub_defaults等等。模块类型为xx_defaults的模块提供了一组可由其它模块继承的属性。其它模块可以通过添加属性`defaults:[“ <:default_module_name>”]“来指定继承xx_defaults类型的模块定义的属性。因此,我们定义一个新模块时,可以通过将默认模块的属性放在name属性之后,其它属性之前,来合并两个模块的属性。
例如:

java_defaults {
    name: "framework-defaults",
    installable: true,

    srcs: [
        // From build/make/core/pathmap.mk FRAMEWORK_BASE_SUBDIRS
        "core/java/**/*.java",
        "graphics/java/**/*.java",
        "location/java/**/*.java",
        "lowpan/java/**/*.java",
        "media/java/**/*.java",
    ]
    //......省略无关
}

java_library {
    name: "framework",
    defaults: ["framework-defaults"],
    javac_shard_size: 150,
}

java_library {
    name: "framework-annotation-proc",
    defaults: ["framework-defaults"],
    // Use UsedByApps annotation processor
    plugins: ["unsupportedappusage-annotation-processor"],
}

这个例子中,模块aidl_mapping在srcs属性中引用了framework-defaults。

5.2.2 引用模块

一个模块可以通过它的模块名来引用。在默认模块这一小节中,其实我们已经引用过了其它模块了。这里我们再来一个例子:

cc_binary {
    name: "app",
    shared_libs: ["libfoo"],
}

例子中,libfoo模块必须存在才有效,并且在构建树中有且仅有一个libfoo模块时才有效。

5.3 文件列表

一个属性的属性值为一系列文件时,属性值也可以采用全局匹配模式和输出路径扩展。

  • 全局匹配模式可以包含普通的Unix通配符*,例如“ * .java”。

  • 全局匹配模式也可以包含单个**通配符作为路径元素,它将匹配零个或多个路径元素。 例如,java / ** / *。java将匹配 java/Main.java 和 java/com/android/Main.java。

  • 输出路径扩展采用:module或:module {.tag}格式,其中module是生成输出文件的模块的名称,并且扩展为这些输出文件的列表。 使用可选的{.tag}后缀,模块可以根据tag生成不同的输出列表。
    例如:

// AIDL interface between storaged and framework.jar
filegroup {
    name: "storaged_aidl",
    srcs: [
        "binder/android/os/IStoraged.aidl",
    ],
    path: "binder",
}

java_library_static {
    name: "services.core.unboosted",
    srcs: [
        "java/**/*.java",
        ":storaged_aidl",
    ],
    //......省略无关
}

5.4 类型和变量

Android.bp文件中,变量和属性是强类型的,变量是基于首次分配动态地创建的,属性是根据模块类型静态地创建的。 支持的类型有:

  • Bool (true or false)
  • Integers (int)
  • Strings ("string")
  • Lists of strings (["string1", "string2"])
  • Maps ({key1: "value1", key2: ["value2"]})
    maps可以是任何类型的值,包括嵌套maps。 Lists和Map的最后一个值后面可能带有逗号。
    字符串可以使用\“包含双引号,例如” cat \“ a b \”“。

5.5 注释

Android.bp文件可以和C/C++的注释类似,可以包含多行注释和单行注释。

  • 多行注释:/ * 注释 * /
  • 单行注释://注释。

5.6 运算符

Android.bp文件可以使用+运算符附加字符串,字符串列表和映射。 整数可以使用+运算符求和。 追加映射会在两个映射中生成键的并集,并追加两个映射中都存在的任何键的值。
例如:

cc_test {
    name: "libandroidfw_tests",
    host_supported: true,
    defaults: ["libandroidfw_defaults"],
    cppflags: [
        // This is to suppress warnings/errors from gtest
        "-Wno-unnamed-type-template-args",
    ],
    srcs: [
        // Helpers/infra for testing.
        "tests/CommonHelpers.cpp",
        "tests/TestHelpers.cpp",
        "tests/TestMain.cpp",
        // 省略无关部分
    ],
    static_libs: ["libgmock"],
    target: {
        android: {
            srcs: [
                "tests/BackupData_test.cpp",
                "tests/ObbFile_test.cpp",
            ],
            shared_libs: common_test_libs + ["libui"],
        },
        host: {
            static_libs: common_test_libs + ["liblog", "libz"],
        },
    },
    data: ["tests/data/**/*.apk"],
}

注意:
除了上述介绍的内容之外,Soong还包含了包、命名空间、名称解析、可见性、soong配置变量等等内容。但是,我在Android 9.0和Android 10.0两份源码中都没有找到合适的例子,本人也不是很理解,为避免误导他人,这些内容就不介绍了,如果想了解更多,请参考:https://android.googlesource.com/platform/build/soong/

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

  • Android.mk文件通常可以包含多个同名模块(例如,用于库的静态(static)和共享(shared)版本,用于不同主机(host)的版本,用于不同设备(device)版本)。

  • Android.bp文件的每个模块都需要唯一的名称,但是单个模块可以构建为多个变体。例如,通过添加host_supported:true。 包含多个同名模块的Android.mk被androidmk转换成Android.bp之后,将生成多个冲突的模块,这些模块必须手动处理,将同名模块改为一个具有多个变体的模块,这些在target:{android:{},host:{}}块内的变体可以有区别,例如,引用不同的源文件,不同架构的共享库文件等等。

  • Soong故意不支持Android.bp文件中的大多数条件。 Google建议从构建中删除大多数条件。Soong将本地支持的大多数条件将转换为map属性。 构建模块时,将选择map中的属性之一,并且将其值追加到模块顶层的同名属性中。
    例如,要支持特定于体系结构的文件:

cc_library {
    ...
    srcs: ["generic.cpp"],
    arch: {
        arm: {
            srcs: ["arm.cpp"],
        },
        x86: {
            srcs: ["x86.cpp"],
        },
    },
}

为arm平台构建时,将构建generic.cpp和arm.cpp。 在为x86平台构建时,将构建generic.cpp和x86.cpp。

7.Android.bp实战

7.1 编译APP

以DocumentsUI为例(为看起来清晰,有整理和部分删减):

android_app {
    name: "DocumentsUI",
    manifest: "AndroidManifest.xml",

    srcs: [
       "src/**/*.java",
    ],

    resource_dirs: [
        "res",
    ],

    static_libs: [
        "androidx.appcompat_appcompat",
        "androidx.recyclerview_recyclerview",
    ],

    privileged: true,
    certificate: "platform",

    optimize: {
        proguard_flags_files: ["proguard.flags"],
    },

    sdk_version: "system_current",
    min_sdk_version: "28",
    target_sdk_version: "28",

    required: ["privapp_whitelist_com.android.documentsui"],
}

可以看到,Android.bp非常简洁,而且命名很清晰,基本上看属性名就知道是起什么作用的。这里只列出了android_app的常用属性,并没有将它的所有属性列出来,开发过程中如果需要配置APP的其它属性,请参考:out/soong/docs/soong_build.html。如果没有源码,也可查看AOSP的在线文档:$AOSP/out/soong/docs/soong_build.html

7.2 编译java库

java_library {
    name: "updatable-media",

    srcs: [
        ":updatable-media-srcs",
    ],

    aidl: {
        export_include_dirs: [
            "apex/java",
        ],

        // It would be great if we don't need to add include_dirs for public
        // parcelable classes. Find a better way.
        include_dirs: [
            // To refer:
            // android.os.Bundle
            // android.os.ResultReceiver
            "frameworks/base/core/java",
        ],
    },

    permitted_packages: [
        "android.media",
    ],

    installable: true,

    // Make sure that the implementaion only relies on SDK or system APIs.
    no_framework_libs: true,
    libs: [
        // The order matters. android_system_* library should come later.
        "framework_media_annotation",
        "android_system_stubs_current",
    ],
}

7.3 编译java静态库

java_library_static {
    name: "services.core.unboosted",

    aidl: {
        include_dirs: [
            "frameworks/native/aidl/binder",
            "system/core/storaged/binder",
            "system/netd/server/binder",
            "system/vold/binder",
        ],
    },
    srcs: [
        "java/**/*.java",
        ":netd_aidl",
        ":netd_metrics_aidl",
        ":installd_aidl",
        ":storaged_aidl",
        ":vold_aidl",
        ":mediaupdateservice_aidl",
        "java/com/android/server/EventLogTags.logtags",
        "java/com/android/server/am/EventLogTags.logtags",
    ],

    libs: [
        "services.net",
        "android.hardware.light-V2.0-java",
        "android.hardware.power-V1.0-java",
        "android.hardware.tv.cec-V1.0-java",
        "android.hidl.manager-V1.0-java",
    ],

    static_libs: [
        "time_zone_distro",
        "time_zone_distro_installer",
        "android.hardware.authsecret-V1.0-java",
        "android.hardware.broadcastradio-V2.0-java",
        "android.hardware.health-V1.0-java",
        "android.hardware.health-V2.0-java",
        "android.hardware.weaver-V1.0-java",
        "android.hardware.biometrics.fingerprint-V2.1-java",
        "android.hardware.oemlock-V1.0-java",
        "android.hardware.tetheroffload.control-V1.0-java",
        "android.hardware.vibrator-V1.0-java",
        "android.hardware.configstore-V1.0-java",
        "android.hardware.contexthub-V1.0-java",
    ],
}

7.4 编译共享库(shared)

cc_library_shared {
    name: "libbluetooth_jni",
    compile_multilib: "first",
    srcs: [
        "bluetooth_socket_manager.cc",
        "com_android_bluetooth_btservice_AdapterService.cpp",
        "com_android_bluetooth_hfp.cpp",
        "com_android_bluetooth_hfpclient.cpp",
        "com_android_bluetooth_a2dp.cpp",
        "com_android_bluetooth_a2dp_sink.cpp",
        "com_android_bluetooth_avrcp_controller.cpp",
        "com_android_bluetooth_avrcp_target.cpp",
        "com_android_bluetooth_hid_host.cpp",
        "com_android_bluetooth_hid_device.cpp",
        "com_android_bluetooth_hearing_aid.cpp",
        "com_android_bluetooth_pan.cpp",
        "com_android_bluetooth_gatt.cpp",
        "com_android_bluetooth_sdp.cpp",
        "IUserManager.cc",
        "permission_helpers.cc",
    ],
    header_libs: ["libbluetooth_headers"],
    include_dirs: [
        "libnativehelper/include/nativehelper",
        "system/bt/types",
    ],
    shared_libs: [
        "libandroid_runtime",
        "libbinder",
        "libbluetooth-binder",
        "libchrome",
        "libnativehelper",
        "liblog",
        "libutils",
    ],
    static_libs: [
        "libbluetooth-types",
        "libcutils",
    ],
    cflags: [
        "-Wall",
        "-Werror",
        "-Wextra",
        "-Wno-unused-parameter",
    ],
    sanitize: {
        scs: true,
    },
}

7.5 编译静态库(static)

cc_library_static {
    name: "libmedia_player2_util",

    defaults: [ "libmedia_defaults" ],

    srcs: [
        "AudioParameter.cpp",
        "BufferingSettings.cpp",
        "DataSourceDesc.cpp",
        "MediaCodecBuffer.cpp",
        "Metadata.cpp",
        "NdkWrapper.cpp",
    ],

    shared_libs: [
        "libbinder",
        "libcutils",
        "liblog",
        "libmediandk",
        "libnativewindow",
        "libmediandk_utils",
        "libstagefright_foundation",
        "libui",
        "libutils",
    ],

    export_shared_lib_headers: [
        "libbinder",
        "libmediandk",
    ],

    header_libs: [
        "media_plugin_headers",
    ],

    include_dirs: [
        "frameworks/av/media/ndk",
    ],

    static_libs: [
        "libstagefright_rtsp",
        "libstagefright_timedtext",
    ],

    export_include_dirs: [
        "include",
    ],

    cflags: [
        "-Werror",
        "-Wno-error=deprecated-declarations",
        "-Wall",
    ],

    sanitize: {
        misc_undefined: [
            "unsigned-integer-overflow",
            "signed-integer-overflow",
        ],
        cfi: true,
    },
}

8. 结语

Google在Android N就引入了Soong,目的是替换make。但是,很遗憾的是截止到Android Q,甚至Android R,它们的源码中都还存在大量的Makefile。也许make就是构建语言里的C语言,无论世界如何发展变化,它的生命力依然旺盛。未来的很长一段时间内Android.bp和Android.mk可能会一直共存,一起完成Android系统源码的构建。这并不代表我们可以不用去学习Android.bp,技术总是不断的发展,我们则需要不断的学习才能适应技术的发展。

9.本文参考

https://android.googlesource.com/platform/build/soong/
https://android.googlesource.com/platform/build/soong/+/HEAD/docs/best_practices.md#network-access

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,968评论 6 482
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,601评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 153,220评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,416评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,425评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,144评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,432评论 3 401
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,088评论 0 261
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,586评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,028评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,137评论 1 334
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,783评论 4 324
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,343评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,333评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,559评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,595评论 2 355
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,901评论 2 345

推荐阅读更多精彩内容