Android 編譯之android.bp

引言

Android編譯知識的梳理文章共三篇:

本文是最后一篇掠拳,主要介紹android.bp债沮。

1. Ninja

1.1 Ninja簡介

Ninja 是一個專注于速度的小型構建系統(tǒng)。它與其他構建系統(tǒng)在兩個主要方面不同:

  • Ninja的輸入文件被設計為由更高級的構建系統(tǒng)生成。
  • Ninja被設計為盡可能快地運行構建, 其他構建系統(tǒng)基于高級語言,而Ninja基于匯編。

Ninja基于匯編妻导,專注于速度,不支持分支诀蓉、循環(huán)等流程控制栗竖,也不支持邏輯運算暑脆,但它允許以其它語言如來維護這些復雜的編譯流程和邏輯渠啤。例如,我們可以采用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構建文件的生成器壶栋。這些生成器就是一些元構建系統(tǒng)(meta-build system),例如Blueprint普监、CMake等等贵试。Ninja的基于底層實現(xiàn)使其非常適合嵌入到這些功能更強大的構建系統(tǒng)中琉兜。更多ninja構建文件的生成器,可參考:List of generators producing ninja build files毙玻。

Ninja用于構建Google Chrome瀏覽器豌蟋,Android,LLVM的一部分桑滩。由于CMake可在大多數平臺上運行梧疲,并且可以生成多種格式的項目文件,包括Ninja运准。所以Ninja也可以作為CMake的底層實現(xiàn)幌氮,在許多其他項目中使用。

1.3 Ninja的下載和使用

Ninja的最新版本為v1.10.2戳吝,于2020年11月23日發(fā)布: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 是一個元構建系統(tǒng),該系統(tǒng)讀取Blueprint文件來描述需要構建的模塊陆盘,并生成一個Ninja清單來描述需要運行的命令及其依賴項普筹。 在大多數構建系統(tǒng)使用內置規(guī)則或特定領域語言來描述將模塊描述轉換為構建規(guī)則的邏輯。Blueprint將其委托給使用Go編寫的針對每個項目的構建邏輯隘马。 對于大型太防,異構項目,這允許以高級語言維護固有酸员、復雜的構建邏輯蜒车,同時仍可以通過修改易于理解的Blueprint文件來對單個模塊進行簡單更改。

2.2 android中的Blueprint

前面在Ninja的構建文件一節(jié)我們提到了幔嗦,Blueprint是ninja構建文件的生成器酿愧。android編譯系統(tǒng)soong集成了Blueprint,Blueprint可將我們編寫的android.bp解析生成一個ninja構建文件邀泉。我們在編譯一個模塊時嬉挡,只需要將這個模塊的android.bp文件配置好,編譯系統(tǒng)會自動為這個模塊生成ninja清單汇恤,最終使用ninja來調用gcc庞钢、clang、java因谎、dex基括、aapt2等等命令來構建模塊。

3. kati

kati 是Google開發(fā)的一個實驗性的GNU make clone财岔,kati的主要目標是加快Android的增量構建风皿。目前饭冬,kati本身并不能提供更快的構建。 而是將Makefile轉換為ninja揪阶。一開始kati是用go語言開發(fā)的昌抠,但作者發(fā)現(xiàn)使用go寫的有性能問題,后來作者又用C++進行了重寫鲁僚,也就是kati變成了ckati(作者的原文描述可以查看android源碼目錄下的:build/kati/INTERNALS.md)炊苫。后續(xù)提到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的編譯系統(tǒng)(make-based build system),也就是android的各個庫徙垫、APK等等目標文件都是采用make來構建的讥裤。 但是,由于make在編譯時表現(xiàn)出效率不夠高姻报、增量編譯速度慢等問題己英,Google在android 7.0版本引進了編譯速度更快的soong來替代make。

Soong集成了Ninja, 而Ninja專注于速度逗抑,沒有條件或流程控制語句剧辐,也不支持邏輯運算寒亥。但它允許以其它語言如來維護這些復雜的編譯流程和邏輯邮府。例如,我們可以繼續(xù)采用makefile, 或者采用go語言來維護編譯流程和邏輯溉奕。上面已經提到了Ninja褂傀,Blueprint, kati等等好幾種工具加勤,為了完整仙辟、快速的構建一個android系統(tǒng)同波,就需要一個“管家”來協(xié)調這些工具。例如叠国,將.bp轉換成ninja時使用Blueprint, 將Makefile轉換成ninja時使用kati未檩。這個選擇轉換工具、選擇解析框架粟焊、解析維護構建邏輯的“管家”就是soong冤狡。

編譯android源碼時,soong也會被自動使用项棠,我們可以和原來一樣:

  • 首先悲雳,source build/envsetup.sh。
  • 然后香追,lunch選擇target合瓢。
  • 最后,使用m透典、mm晴楔、mmm或者make來編譯指定的模塊或者整個系統(tǒng)。

但是峭咒,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節(jié)中詳細介紹茸时。

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規(guī)則签杈,復雜的條件語句或其它的額外的include語句,必須手動轉換鼎兽。

在現(xiàn)有版本答姥,由于kati工具的存在铣除,繼續(xù)使用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的規(guī)范格式包括:

  • 4個空格縮進。
  • 多元素列表的每個元素后的換行符遂填。
  • 在lists和maps的結尾處始終包含一個逗號铲觉。

我們可以使用bpfmt工具來規(guī)范格式化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調用和協(xié)調,一起合作完成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 引用模塊

一個模塊可以通過它的模塊名來引用。在默認模塊這一小節(jié)中黄锤,其實我們已經引用過了其它模塊了麻献。這里我們再來一個例子:

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文件中梗脾,變量和屬性是強類型的荸型,變量是基于首次分配動態(tài)地創(chuàng)建的,屬性是根據模塊類型靜態(tài)地創(chuàng)建的炸茧。 支持的類型有:

  • 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的區(qū)別

  • Android.mk文件通常可以包含多個同名模塊(例如形娇,用于庫的靜態(tài)(static)和共享(shared)版本锰霜,用于不同主機(host)的版本,用于不同設備(device)版本)桐早。

  • Android.bp文件的每個模塊都需要唯一的名稱癣缅,但是單個模塊可以構建為多個變體厨剪。例如,通過添加host_supported:true友存。 包含多個同名模塊的Android.mk被androidmk轉換成Android.bp之后祷膳,將生成多個沖突的模塊,這些模塊必須手動處理爬立,將同名模塊改為一個具有多個變體的模塊钾唬,這些在target:{android:{}万哪,host:{}}塊內的變體可以有區(qū)別侠驯,例如,引用不同的源文件奕巍,不同架構的共享庫文件等等吟策。

  • 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實戰(zhàn)

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的常用屬性伶唯,并沒有將它的所有屬性列出來觉既,開發(fā)過程中如果需要配置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靜態(tài)庫

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 編譯靜態(tài)庫(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語言秒际,無論世界如何發(fā)展變化,它的生命力依然旺盛狡汉。未來的很長一段時間內Android.bp和Android.mk可能會一直共存娄徊,一起完成Android系統(tǒng)源碼的構建。這并不代表我們可以不用去學習Android.bp盾戴,技術總是不斷的發(fā)展寄锐,我們則需要不斷的學習才能適應技術的發(fā)展。

9.本文參考

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

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末尖啡,一起剝皮案震驚了整個濱河市橄仆,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌衅斩,老刑警劉巖盆顾,帶你破解...
    沈念sama閱讀 207,113評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異畏梆,居然都是意外死亡您宪,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,644評論 2 381
  • 文/潘曉璐 我一進店門奠涌,熙熙樓的掌柜王于貴愁眉苦臉地迎上來宪巨,“玉大人,你說我怎么就攤上這事溜畅∧笞浚” “怎么了?”我有些...
    開封第一講書人閱讀 153,340評論 0 344
  • 文/不壞的土叔 我叫張陵达皿,是天一觀的道長天吓。 經常有香客問我,道長峦椰,這世上最難降的妖魔是什么龄寞? 我笑而不...
    開封第一講書人閱讀 55,449評論 1 279
  • 正文 為了忘掉前任张惹,我火速辦了婚禮肿轨,結果婚禮上枷颊,老公的妹妹穿的比我還像新娘闷游。我一直安慰自己,他們只是感情好封寞,可當我...
    茶點故事閱讀 64,445評論 5 374
  • 文/花漫 我一把揭開白布惫周。 她就那樣靜靜地躺著钥勋,像睡著了一般餐茵。 火紅的嫁衣襯著肌膚如雪科阎。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,166評論 1 284
  • 那天忿族,我揣著相機與錄音锣笨,去河邊找鬼蝌矛。 笑死,一個胖子當著我的面吹牛错英,可吹牛的內容都是我干的入撒。 我是一名探鬼主播,決...
    沈念sama閱讀 38,442評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼椭岩,長吁一口氣:“原來是場噩夢啊……” “哼茅逮!你這毒婦竟也來了?” 一聲冷哼從身側響起判哥,我...
    開封第一講書人閱讀 37,105評論 0 261
  • 序言:老撾萬榮一對情侶失蹤献雅,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后姨伟,有當地人在樹林里發(fā)現(xiàn)了一具尸體惩琉,經...
    沈念sama閱讀 43,601評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡豆励,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 36,066評論 2 325
  • 正文 我和宋清朗相戀三年夺荒,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片良蒸。...
    茶點故事閱讀 38,161評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡技扼,死狀恐怖,靈堂內的尸體忽然破棺而出嫩痰,到底是詐尸還是另有隱情剿吻,我是刑警寧澤,帶...
    沈念sama閱讀 33,792評論 4 323
  • 正文 年R本政府宣布串纺,位于F島的核電站丽旅,受9級特大地震影響,放射性物質發(fā)生泄漏纺棺。R本人自食惡果不足惜榄笙,卻給世界環(huán)境...
    茶點故事閱讀 39,351評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望祷蝌。 院中可真熱鬧茅撞,春花似錦、人聲如沸巨朦。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,352評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽糊啡。三九已至拄查,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間棚蓄,已是汗流浹背堕扶。 一陣腳步聲響...
    開封第一講書人閱讀 31,584評論 1 261
  • 我被黑心中介騙來泰國打工腺毫, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人挣柬。 一個月前我還...
    沈念sama閱讀 45,618評論 2 355
  • 正文 我出身青樓潮酒,卻偏偏與公主長得像,于是被迫代替她去往敵國和親邪蛔。 傳聞我的和親對象是個殘疾皇子急黎,可洞房花燭夜當晚...
    茶點故事閱讀 42,916評論 2 344

推薦閱讀更多精彩內容