Przed wydaniem Androida 7.0, Android używał GNU Make wyłącznie do opisywania i wykonywania swoich reguł kompilacji. System kompilacji Make jest powszechnie 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 deweloperzy platform przejdą z Make i zastosują Soong tak szybko, jak to możliwe. Wyślij pytania do grupy dyskusyjnej Google zajmującej się tworzeniem systemu Android, aby uzyskać pomoc.
Co to jest wkrótce?
System kompilacji Soong został wprowadzony w systemie Android 7.0 (Nougat), aby zastąpić Make. Wykorzystuje narzędzie do klonowania Kati GNU Make i składnik systemu kompilacji Ninja , aby przyspieszyć kompilacje Androida.
Zapoznaj się z opisem 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 dotyczące kompilacji w glosariuszu, aby uzyskać definicje kluczowych terminów, oraz pliki referencyjne Soong, aby uzyskać szczegółowe informacje.
Porównanie marki i wkrótce
Oto porównanie konfiguracji Make z Soong osiągającą 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)
Niedługo 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 Simple Build Configuration , aby zapoznać się z przykładami konfiguracji Soong specyficznymi dla testu.
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 wstępnie utworzonych 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. Możesz odwoływać się do danych wyjściowych innych modułów, które generują pliki źródłowe, takie jak genrule
lub filegroup
, przy użyciu składni odwołania do modułu ":<module-name>"
.
Aby uzyskać listę prawidłowych typów modułów i ich właściwości, zobacz Soong Modules Reference .
Rodzaje
Zmienne i właściwości są silnie wpisane, przy czym zmienne są dynamicznie oparte na pierwszym przypisaniu, a właściwości są ustawiane statycznie przez typ modułu. Obsługiwane typy to:
- Boole'a (
true
lubfalse
) - Liczby całkowite (
int
) - Ciągi (
"string"
) - Listy ciągó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 glob. Wzorce glob mogą zawierać normalny symbol wieloznaczny UNIX *
, na przykład *.java
. Wzorce glob mogą również zawierać pojedynczy symbol wieloznaczny **
jako element ścieżki, który odpowiada zero lub większej liczbie elementów ścieżki. Na przykład java/**/*.java
pasuje zarówno do 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",
}
Zmienne są objęte zakresem pozostałej części pliku, w którym są zadeklarowane, jak również wszelkich podrzędnych plików Blueprint. Zmienne są niezmienne z jednym wyjątkiem: można je dołączyć za pomocą przypisania +=
, ale tylko przed wywołaniem.
Uwagi
Pliki Android.bp
mogą zawierać komentarze wielowierszowe /* */
w stylu C i jednowierszowe //
w stylu C++.
Operatorzy
Łańcuchy, listy łańcuchów i mapy mogą być dołączane za pomocą operatora +. Liczby całkowite można sumować za pomocą operatora +
. Dołączanie mapy tworzy sumę kluczy w obu mapach, dołączając wartości dowolnych kluczy, które są obecne na obu mapach.
Warunkowe
Soong nie obsługuje instrukcji warunkowych w plikach Android.bp
. Zamiast tego złożoność reguł kompilacji, która wymagałaby warunków warunkowych, jest obsługiwana w Go, gdzie można używać funkcji języka wysokiego poziomu i można ś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"],
},
},
}
Formater
Soong zawiera kanoniczny program do formatowania plików Blueprint, podobny do gofmt . Aby rekurencyjnie sformatować wszystkie pliki Android.bp
w bieżącym katalogu, uruchom:
bpfmt -w .
Format kanoniczny obejmuje wcięcia z czterema spacjami, nowe wiersze po każdym elemencie listy wieloelementowej oraz końcowy przecinek w listach i mapach.
Moduły specjalne
Niektóre grupy modułów specjalnych mają unikalne cechy.
Moduły domyślne
Moduł ustawień domyślnych może służyć do powtarzania 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 skompilowane typy modułów pozwalają modułowi mieć taką samą nazwę, jak jego odpowiedniki oparte na źródle. Na przykład może istnieć cc_prebuilt_binary
o nazwie foo
, gdy istnieje już cc_binary
o tej samej nazwie. Daje to programistom elastyczność w wyborze wersji, którą mają uwzględnić w ich produkcie końcowym. Jeśli konfiguracja kompilacji zawiera obie wersje, prefer
wartość flagi we wstępnie zbudowanej definicji modułu określa, która wersja ma priorytet. Zwróć uwagę, że niektóre wstępnie zbudowane 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ść powinna być rozdzieloną spacjami listą przestrzeni nazw, które Soong eksportuje do Make, aby zostały zbudowane za pomocą polecenia m
. Po zakończeniu konwersji Androida na Soong szczegóły włączania przestrzeni nazw mogą ulec zmianie.
Soong umożliwia modułom w różnych katalogach określenie 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żdy moduł Soong ma przypisaną przestrzeń nazw na podstawie jego lokalizacji w drzewie. Uważa się, że każdy moduł Soong znajduje się w przestrzeni nazw zdefiniowanej przez przestrzeń nazw soong_namespace
znalezioną w pliku Android.bp
w bieżącym katalogu lub katalogu najbliższego przodka. Jeśli nie zostanie odnaleziony żaden taki soong_namespace
przestrzeń nazw, uważa się, że moduł znajduje się w niejawnej głównej przestrzeni nazw.
Oto przykład: Wkrótce próbuje rozwiązać zależność D zadeklarowaną przez moduł M w przestrzeni nazw N, który importuje przestrzenie nazw I1, I2, I3…
- Następnie, jeśli D jest w pełni kwalifikowaną nazwą postaci
//namespace:module
, tylko określona przestrzeń nazw jest przeszukiwana dla określonej nazwy modułu. - W przeciwnym razie Soong najpierw szuka modułu o nazwie D zadeklarowanego w przestrzeni nazw N.
- Jeśli ten moduł nie istnieje, Soong szuka modułu o nazwie D w przestrzeniach nazw I1, I2, I3…
- Wreszcie Soong szuka w głównej przestrzeni nazw.