宋建系統

在 Android 7.0 發布之前,Android 專門使用GNU Make來描述和執行其構建規則。 Make 構建系統得到廣泛支持和使用,但在 Android 的規模上變得緩慢、容易出錯、不可擴展且難以測試。 Soong 構建系統提供了 Android 構建所需的靈活性。

因此,平台開發者有望盡快從 Make 轉向採用 Soong。向android-building Google Group 發送問題以獲得支持。

什麼是宋?

在 Android 7.0 (Nougat) 中引入了Soong 構建系統以取代 Make。它利用Kati GNU Make 克隆工具和Ninja構建系統組件來加速 Android 的構建。

請參閱 Android 開源項目 (AOSP) 中的Android Make Build System描述,了解一般說明Android.mk 編寫者的 Build System Changes以了解從 Make 到 Soong 所需的修改。

有關關鍵術語的定義,請參閱詞彙表中與構建相關的條目,有關完整的詳細信息,請參閱Soong 參考文件

Make 和 Song 比較

這是 Make 配置與 Soong 在 Soong 配置(藍圖或.bp )文件中完成相同操作的比較。

做例子

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)

宋示例

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文件很簡單。它們不包含條件或控制流語句;所有復雜性都由用 Go 編寫的構建邏輯處理。如果可能, Android.bp文件的語法和語義類似於Bazel BUILD 文件

模塊

Android.bp文件中的模塊以模塊類型開頭,後跟name: "value",格式:

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

每個模塊都必須有一個name屬性,並且該值在所有Android.bp文件中必須是唯一的,但名稱空間和預構建模塊中的name屬性值可能會重複。

srcs屬性將用於構建模塊的源文件指定為字符串列表。您可以使用模塊引用語法":<module-name>"來引用生成源文件的其他模塊的輸出,例如genrulefilegroup

有關有效模塊類型及其屬性的列表,請參閱Soong 模塊參考

類型

變量和屬性是強類型的,變量基於第一個賦值動態,屬性由模塊類型靜態設置。支持的類型有:

  • 布爾值( truefalse
  • 整數 ( int )
  • 字符串( "string"
  • 字符串列表( ["string1", "string2"]
  • 地圖( {key1: "value1", key2: ["value2"]}

映射可以包含任何類型的值,包括嵌套映射。列表和地圖在最後一個值之後可能有尾隨逗號。

球體

採用文件列表的屬性,例如srcs ,也可以採用 glob 模式。 Glob 模式可以包含普通的 UNIX 通配符* ,例如*.java 。 Glob 模式還可以包含單個**通配符作為路徑元素,它匹配零個或多個路徑元素。例如, java/**/*.java匹配java/Main.javajava/com/android/Main.java模式。

變量

一個Android.bp文件可能包含頂級變量賦值:

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

變量的範圍僅限於聲明它們的文件的其餘部分,以及任何子藍圖文件。變量是不可變的,有一個例外:它們可以附加一個+=賦值,但只能在它們被引用之前。

評論

Android.bp文件可以包含 C 風格的多行/* */和 C++ 風格的單行//註釋。

運營商

可以使用 + 運算符附加字符串、字符串列表和映射。整數可以使用+運算符求和。附加一個映射會產生兩個映射中的鍵的聯合,附加兩個映射中存在的任何鍵的值。

條件句

Android.bp文件中,Soong 不支持條件。相反,需要條件的構建規則的複雜性在 Go 中處理,其中可以使用高級語言功能,並且可以跟踪條件引入的隱式依賴關係。大多數條件都轉換為映射屬性,其中選擇映射中的一個值並將其附加到頂級屬性。

例如,要支持特定於體系結構的文件:

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

格式化程序

Soong 包含一個用於藍圖文件的規範格式化程序,類似於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時,可以有一個名為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"],
}

請注意,命名空間沒有 name 屬性;它的路徑被自動分配為其名稱。

每個 Soong 模塊都根據其在樹中的位置分配一個命名空間。每個 Soong 模塊都被認為位於由當前目錄或最近的祖先目錄中的Android.bp文件中找到的soong_namespace定義的命名空間中。如果沒有找到這樣的soong_namespace模塊,則認為該模塊位於隱式根命名空間中。

這是一個示例:Soong 嘗試解析模塊 M 在命名空間 N 中聲明的依賴項 D,該命名空間 N 導入命名空間 I1、I2、I3……

  1. 然後,如果 D 是//namespace:module形式的完全限定名稱,則僅在指定的命名空間中搜索指定的模塊名稱。
  2. 否則,Soong 首先查找命名空間 N 中聲明的名為 D 的模塊。
  3. 如果該模塊不存在,Soong 會在命名空間 I1、I2、I3 中查找名為 D 的模塊……
  4. 最後,Soong 在根命名空間中查找。