Antes del lanzamiento de Android 7.0, Android usaba GNU Make exclusivamente para describir y ejecutar sus reglas de compilación. El sistema de compilación Make es ampliamente compatible y utilizado, pero a la escala de Android se volvió lento, propenso a errores, no escalable y difícil de probar. El sistema de compilación Soong proporciona la flexibilidad necesaria para las compilaciones de Android.
Por esta razón, se espera que los desarrolladores de plataformas abandonen Make y adopten Soong lo antes posible. Envíe preguntas al grupo de Google de creación de Android para recibir asistencia.
¿Qué es Soong?
El sistema de compilación Soong se introdujo en Android 7.0 (Nougat) para reemplazar a Make. Aprovecha la herramienta de clonación Kati GNU Make y el componente del sistema de compilación Ninja para acelerar las compilaciones de Android.
Consulte la descripción del sistema de compilación Make de Android en el Proyecto de código abierto de Android (AOSP) para obtener instrucciones generales y los cambios del sistema de compilación para escritores de Android.mk para conocer las modificaciones necesarias para adaptarse de Make a Soong.
Consulte las entradas relacionadas con la compilación en el glosario para obtener definiciones de términos clave y los archivos de referencia de Soong para obtener detalles completos.
Comparación de Make y Soon
Aquí hay una comparación de la configuración de Make con Soong logrando lo mismo en un archivo de configuración de Soong (Blueprint o .bp
).
hacer ejemplo
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)
Un buen ejemplo
cc_library_shared {
name: “libxmlrpc++”,
rtti: true,
cppflags: [
“-Wall”,
“-Werror”,
“-fexceptions”,
],
export_include_dirs: [“src”],
srcs: [“src/**/*.cpp”],
target: {
darwin: {
enabled: false,
},
},
}
Consulte Configuración de compilación simple para ver ejemplos de configuración de Soong específicos de la prueba.
Formato de archivo Android.bp
Por diseño, los archivos Android.bp
son simples. No contienen condicionales ni declaraciones de flujo de control; toda la complejidad es manejada por la lógica de compilación escrita en Go. Cuando es posible, la sintaxis y la semántica de los archivos Android.bp
son similares a los archivos Bazel BUILD .
Módulos
Un módulo en un archivo Android.bp
comienza con un tipo de módulo seguido de un conjunto de propiedades en name: "value",
formato:
cc_binary {
name: "gzip",
srcs: ["src/test/minigzip.c"],
shared_libs: ["libz"],
stl: "none",
}
Cada módulo debe tener una propiedad name
y el valor debe ser único en todos los archivos Android.bp
, excepto los valores de propiedad name
en espacios de nombres y módulos prediseñados, que pueden repetirse.
La propiedad srcs
especifica los archivos fuente utilizados para construir el módulo, como una lista de cadenas. Puede hacer referencia a la salida de otros módulos que producen archivos fuente, como genrule
o filegroup
, utilizando la sintaxis de referencia del módulo ":<module-name>"
.
Para obtener una lista de tipos de módulos válidos y sus propiedades, consulte la Referencia de módulos de Soong .
Tipos
Las variables y propiedades están fuertemente tipadas, con variables basadas dinámicamente en la primera asignación y propiedades establecidas estáticamente por el tipo de módulo. Los tipos soportados son:
- Booleanos (
true
ofalse
) - Números enteros (
int
) - Cadenas (
"string"
) - Listas de cadenas (
["string1", "string2"]
) - Mapas (
{key1: "value1", key2: ["value2"]}
Los mapas pueden contener valores de cualquier tipo, incluidos mapas anidados. Las listas y los mapas pueden tener comas al final del último valor.
globos
Las propiedades que toman una lista de archivos, como srcs
, también pueden tomar patrones globales. Los patrones globales pueden contener el comodín *
normal de UNIX, por ejemplo *.java
. Los patrones globales también pueden contener un único comodín **
como elemento de ruta, que coincide con cero o más elementos de ruta. Por ejemplo, java/**/*.java
coincide con los patrones java/Main.java
y java/com/android/Main.java
.
variables
Un archivo Android.bp
puede contener asignaciones de variables de nivel superior:
gzip_srcs = ["src/test/minigzip.c"],
cc_binary {
name: "gzip",
srcs: gzip_srcs,
shared_libs: ["libz"],
stl: "none",
}
Las variables tienen como alcance el resto del archivo en el que se declaran, así como cualquier archivo Blueprint secundario. Las variables son inmutables con una excepción: se les puede agregar una asignación +=
, pero solo antes de que se haga referencia a ellas.
Comentarios
Los archivos Android.bp
pueden contener comentarios /* */
multilínea de estilo C y //
de una sola línea de estilo C++.
Operadores
Se pueden agregar cadenas, listas de cadenas y mapas utilizando el operador +. Los números enteros se pueden resumir usando el operador +
. Agregar un mapa produce la unión de claves en ambos mapas, agregando los valores de cualquier clave que esté presente en ambos mapas.
Condicionales
Soong no admite condicionales en archivos Android.bp
. En cambio, la complejidad de las reglas de construcción que requerirían condicionales se maneja en Go, donde se pueden usar características de lenguaje de alto nivel y se pueden rastrear las dependencias implícitas introducidas por los condicionales. La mayoría de los condicionales se convierten en una propiedad de mapa, donde uno de los valores del mapa se selecciona y se agrega a las propiedades de nivel superior.
Por ejemplo, para admitir archivos específicos de la arquitectura:
cc_library {
...
srcs: ["generic.cpp"],
arch: {
arm: {
srcs: ["arm.cpp"],
},
x86: {
srcs: ["x86.cpp"],
},
},
}
Formateador
Soong incluye un formateador canónico para archivos Blueprint, similar a gofmt . Para reformatear recursivamente todos los archivos Android.bp
en el directorio actual, ejecute:
bpfmt -w .
El formato canónico incluye sangrías de cuatro espacios, nuevas líneas después de cada elemento de una lista de varios elementos y una coma final en listas y mapas.
Módulos especiales
Algunos grupos de módulos especiales tienen características únicas.
Módulos predeterminados
Se puede utilizar un módulo predeterminado para repetir las mismas propiedades en varios módulos. Por ejemplo:
cc_defaults {
name: "gzip_defaults",
shared_libs: ["libz"],
stl: "none",
}
cc_binary {
name: "gzip",
defaults: ["gzip_defaults"],
srcs: ["src/test/minigzip.c"],
}
Módulos prediseñados
Algunos tipos de módulos prediseñados permiten que un módulo tenga el mismo nombre que sus homólogos basados en código fuente. Por ejemplo, puede haber un cc_prebuilt_binary
llamado foo
cuando ya existe un cc_binary
con el mismo nombre. Esto brinda a los desarrolladores la flexibilidad de elegir qué versión incluir en su producto final. Si una configuración de compilación contiene ambas versiones, el valor del indicador prefer
en la definición del módulo precompilado dicta qué versión tiene prioridad. Tenga en cuenta que algunos módulos prediseñados tienen nombres que no comienzan con prebuilt
, como android_app_import
.
Módulos de espacio de nombres
Hasta que Android se convierta completamente de Make a Soong, la configuración del producto Make debe especificar un valor de PRODUCT_SOONG_NAMESPACES
. Su valor debe ser una lista de espacios de nombres separados por espacios que Soong exporta a Make para ser compilada por el comando m
. Una vez completada la conversión de Android a Soong, los detalles sobre la habilitación de espacios de nombres podrían cambiar.
Soong ofrece la posibilidad de que módulos en diferentes directorios especifiquen el mismo nombre, siempre que cada módulo se declare dentro de un espacio de nombres separado. Un espacio de nombres se puede declarar así:
soong_namespace {
imports: ["path/to/otherNamespace1", "path/to/otherNamespace2"],
}
Tenga en cuenta que un espacio de nombres no tiene una propiedad de nombre; su ruta se asigna automáticamente como su nombre.
A cada módulo de Soong se le asigna un espacio de nombres según su ubicación en el árbol. Se considera que cada módulo de Soong está en el espacio de nombres definido por el soong_namespace
que se encuentra en un archivo Android.bp
en el directorio actual o en el directorio ancestro más cercano. Si no se encuentra dicho módulo soong_namespace
, se considera que el módulo está en el espacio de nombres raíz implícito.
Aquí hay un ejemplo: Soong intenta resolver la dependencia D declarada por el módulo M en el espacio de nombres N que importa los espacios de nombres I1, I2, I3...
- Luego, si D es un nombre completo con el formato
//namespace:module
, solo se busca el espacio de nombres especificado para el nombre del módulo especificado. - De lo contrario, Soong primero busca un módulo llamado D declarado en el espacio de nombres N.
- Si ese módulo no existe, Soong busca un módulo llamado D en los espacios de nombres I1, I2, I3…
- Por último, Soong busca en el espacio de nombres raíz.