Wkrótce system budowania

Przed wydaniem Androida 7.0 Android używał GNU Make wyłącznie do opisywania i wykonywania swoich reguł kompilacji. System kompilacji Make jest szeroko obsługiwany i używany, ale w skali Androida stał się powolny, podatny na błędy, nieskalowalny i trudny do przetestowania. System kompilacji Soong zapewnia elastyczność wymaganą w przypadku kompilacji Androida.

Z tego powodu oczekuje się, że twórcy platform przestawią się z Make i zaadoptują Soong tak szybko, jak to możliwe. Wyślij pytania do grupy Google zajmującej się tworzeniem Androida , aby uzyskać pomoc.

Co to jest Soong?

System kompilacji Soong został wprowadzony w Androidzie 7.0 (Nougat) w celu zastąpienia Make. Wykorzystuje narzędzie do klonowania Kati GNU Make i komponent systemu kompilacji Ninja , aby przyspieszyć kompilacje Androida.

Zobacz opis systemu Android Make Build System w projekcie Android Open Source Project (AOSP), aby uzyskać ogólne instrukcje i zmiany systemu kompilacji dla twórców Android.mk, aby dowiedzieć się o modyfikacjach potrzebnych do dostosowania z Make do Soong.

Zobacz wpisy związane z budową w glosariuszu, aby znaleźć definicje kluczowych terminów, oraz pliki referencyjne Soong, aby uzyskać szczegółowe informacje.

Porównanie Make i Soong

Oto porównanie konfiguracji Make z Soong wykonującym to samo w pliku konfiguracyjnym Soong (Blueprint lub .bp ).

Zrób przykład

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)

Wkrótce przykład

cc_library_shared {
     name: “libxmlrpc++”,

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

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

Zobacz Prosta konfiguracja kompilacji , aby zapoznać się z przykładami konfiguracji Soong specyficznymi dla testów.

Format pliku Android.bp

Z założenia pliki Android.bp są proste. Nie zawierają instrukcji warunkowych ani instrukcji przepływu sterowania; cała złożoność jest obsługiwana przez logikę kompilacji napisaną w Go. Jeśli to możliwe, składnia i semantyka plików Android.bp są podobne do plików Bazel BUILD .

Moduły

Moduł w pliku Android.bp zaczyna się od typu modułu , po którym następuje zestaw właściwości w name: "value", format:

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

Każdy moduł musi mieć właściwość name , a wartość musi być unikatowa we wszystkich plikach Android.bp , z wyjątkiem wartości właściwości name w przestrzeniach nazw i gotowych modułach, które mogą się powtarzać.

Właściwość srcs określa pliki źródłowe użyte do zbudowania modułu, jako listę ciągów znaków. Możesz odwoływać się do danych wyjściowych innych modułów, które tworzą pliki źródłowe, takie jak genrule lub filegroup , przy użyciu składni odwołania do modułu ":<module-name>" .

Listę prawidłowych typów modułów i ich właściwości można znaleźć w podręczniku Soong Modules Reference .

typy

Zmienne i właściwości są ściśle typowane, przy czym zmienne są dynamicznie oparte na pierwszym przypisaniu, a właściwości są ustawiane statycznie według typu modułu. Obsługiwane typy to:

  • Boolean ( true czy false )
  • Liczby całkowite ( int )
  • Ciągi ( "string" )
  • Listy ciągów znaków ( ["string1", "string2"] )
  • Mapy ( {key1: "value1", key2: ["value2"]} )

Mapy mogą zawierać wartości dowolnego typu, w tym mapy zagnieżdżone. Listy i mapy mogą mieć końcowe przecinki po ostatniej wartości.

Globy

Właściwości, które pobierają listę plików, takie jak srcs , mogą również przyjmować wzorce globalne. Wzorce globalne mogą zawierać zwykłe symbole wieloznaczne systemu UNIX * , na przykład *.java . Wzorce globalne mogą również zawierać pojedynczy znak wieloznaczny ** jako element ścieżki, który pasuje do zera lub większej liczby elementów ścieżki. Na przykład java/**/*.java pasuje zarówno do wzorców java/Main.java , jak i java/com/android/Main.java .

Zmienne

Plik Android.bp może zawierać przypisania zmiennych najwyższego poziomu:

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

Zakres zmiennych obejmuje pozostałą część pliku, w którym zostały zadeklarowane, a także wszelkie podrzędne pliki Blueprint. Zmienne są niezmienne z jednym wyjątkiem: można do nich dołączać przypisanie += , ale tylko przed odwołaniem.

Uwagi

Pliki Android.bp mogą zawierać wielowierszowe komentarze /* */ w stylu C i jednowierszowe // komentarze w stylu C++.

Operatorzy

Ciągi, listy ciągów i mapy można dołączać za pomocą operatora +. Liczby całkowite można zsumować za pomocą operatora + . Dołączenie mapy tworzy połączenie kluczy w obu mapach, dołączając wartości dowolnych kluczy, które są obecne w obu mapach.

warunkowe

Soong nie obsługuje warunków w plikach Android.bp . Zamiast tego złożoność reguł kompilacji, która wymagałaby warunków, jest obsługiwana w Go, gdzie można używać funkcji języka wysokiego poziomu i śledzić niejawne zależności wprowadzone przez warunki. Większość warunków warunkowych jest konwertowana na właściwość mapy, w której jedna z wartości na mapie jest wybierana i dołączana do właściwości najwyższego poziomu.

Na przykład, aby obsługiwać pliki specyficzne dla architektury:

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

Formatowanie

Soong zawiera kanoniczny formater plików Blueprint, podobny do gofmt . Aby rekurencyjnie ponownie sformatować wszystkie pliki Android.bp w bieżącym katalogu, uruchom:

bpfmt -w .

Format kanoniczny obejmuje czteromiejscowe wcięcia, nowe wiersze po każdym elemencie listy wieloelementowej oraz końcowy przecinek na listach i mapach.

Specjalne moduły

Niektóre specjalne grupy modułów mają unikalne cechy.

Moduły domyślne

Modułu domyślnego można użyć do powtórzenia tych samych właściwości w wielu modułach. Na przykład:

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

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

Gotowe moduły

Niektóre wstępnie zbudowane typy modułów pozwalają, aby moduł miał taką samą nazwę, jak jego odpowiedniki oparte na źródle. Na przykład może istnieć plik cc_prebuilt_binary o nazwie foo , gdy istnieje już plik cc_binary o tej samej nazwie. Daje to programistom elastyczność w wyborze wersji, która ma zostać uwzględniona w ich produkcie końcowym. Jeśli konfiguracja kompilacji zawiera obie wersje, wartość flagi prefer w definicji gotowego modułu określa, która wersja ma priorytet. Zwróć uwagę, że niektóre gotowe moduły mają nazwy, które nie zaczynają się od prebuilt , na przykład android_app_import .

Moduły przestrzeni nazw

Do czasu pełnej konwersji Androida z Make na Soong konfiguracja produktu Make musi określać wartość PRODUCT_SOONG_NAMESPACES . Jego wartością powinna być oddzielona spacjami lista przestrzeni nazw, które Soong eksportuje do programu Make, aby można je było zbudować poleceniem m . Po zakończeniu konwersji Androida na Soong szczegóły włączania przestrzeni nazw mogą ulec zmianie.

Soong zapewnia modułom w różnych katalogach określanie tej samej nazwy, o ile każdy moduł jest zadeklarowany w oddzielnej przestrzeni nazw. Przestrzeń nazw można zadeklarować w następujący sposób:

soong_namespace {
    imports: ["path/to/otherNamespace1", "path/to/otherNamespace2"],
}

Zauważ, że przestrzeń nazw nie ma właściwości name; jego ścieżka jest automatycznie przypisywana jako nazwa.

Każdemu modułowi Soong przypisywana jest przestrzeń nazw na podstawie jego położenia w drzewie. Uznaje się, że każdy moduł Soong znajduje się w przestrzeni nazw zdefiniowanej przez soong_namespace znalezioną w pliku Android.bp w bieżącym katalogu lub katalogu najbliższego przodka. Jeśli nie zostanie znaleziony taki moduł soong_namespace , uznaje się, że moduł znajduje się w niejawnej głównej przestrzeni nazw.

Oto przykład: Soong próbuje rozwiązać zależność D zadeklarowaną przez moduł M w przestrzeni nazw N, która importuje przestrzenie nazw I1, I2, I3…

  1. Następnie, jeśli D jest w pełni kwalifikowaną nazwą w postaci //namespace:module , dla określonej nazwy modułu przeszukiwana jest tylko określona przestrzeń nazw.
  2. W przeciwnym razie Soong najpierw szuka modułu o nazwie D zadeklarowanego w przestrzeni nazw N.
  3. Jeśli ten moduł nie istnieje, Soong szuka modułu o nazwie D w przestrzeniach nazw I1, I2, I3…
  4. Na koniec Soong zagląda do głównej przestrzeni nazw.