Si es la primera vez que utilizas Bazel, comienza con el curso Cómo compilar Android con Instructivo de Bazel.
Descripción general
Bazel puede ejecutarse en muchas configuraciones de compilación diferentes, incluidas varias que usan
conjunto de herramientas del kit de desarrollo nativo (NDK) de Android. Esto significa que lo normal
Las reglas cc_library
y cc_binary
se pueden compilar para Android directamente en
Bazel Bazel logra esto mediante el repositorio android_ndk_repository
.
.
Requisitos previos
Asegúrate de haber instalado el SDK y el NDK de Android.
Para configurar el SDK y el NDK, agrega el siguiente fragmento a tu WORKSPACE
:
android_sdk_repository(
name = "androidsdk", # Required. Name *must* be "androidsdk".
path = "/path/to/sdk", # Optional. Can be omitted if `ANDROID_HOME` environment variable is set.
)
android_ndk_repository(
name = "androidndk", # Required. Name *must* be "androidndk".
path = "/path/to/ndk", # Optional. Can be omitted if `ANDROID_NDK_HOME` environment variable is set.
)
Para obtener más información sobre la regla android_ndk_repository
, consulta el artículo Compila
Entrada de enciclopedia.
Inicio rápido
Para compilar C++ para Android, simplemente agrega dependencias cc_library
a tu
Reglas android_binary
o android_library
.
Por ejemplo, con el siguiente archivo BUILD
de una app para Android:
# In <project>/app/src/main/BUILD.bazel
cc_library(
name = "jni_lib",
srcs = ["cpp/native-lib.cpp"],
)
android_library(
name = "lib",
srcs = ["java/com/example/android/bazel/MainActivity.java"],
resource_files = glob(["res/**/*"]),
custom_package = "com.example.android.bazel",
manifest = "LibraryManifest.xml",
deps = [":jni_lib"],
)
android_binary(
name = "app",
deps = [":lib"],
manifest = "AndroidManifest.xml",
)
Este archivo BUILD
da como resultado el siguiente gráfico de destino:
Figura 1: Gráfico de compilación del proyecto de Android con dependencias de cc_library
Para compilar la app, simplemente ejecuta lo siguiente:
bazel build //app/src/main:app
El comando bazel build
compila los archivos Java, los archivos de recursos de Android y
cc_library
y empaqueta todo en un APK:
$ zipinfo -1 bazel-bin/app/src/main/app.apk
nativedeps
lib/armeabi-v7a/libapp.so
classes.dex
AndroidManifest.xml
...
res/...
...
META-INF/CERT.SF
META-INF/CERT.RSA
META-INF/MANIFEST.MF
Bazel compila todas las bibliotecas cc_bibliotecas en un único archivo de objeto compartido (.so
).
está orientada a la ABI armeabi-v7a
de forma predeterminada. Si quieres cambiar esto o crear contenido para
varias ABI al mismo tiempo; consulta la sección sobre cómo configurar el segmento
ABI.
Configuración de ejemplo
Este ejemplo está disponible en los ejemplos de Bazel Cloud Storage.
En el archivo BUILD.bazel
, se definen tres destinos con android_binary
.
Reglas android_library
y cc_library
.
El objetivo de nivel superior android_binary
compila el APK.
El destino cc_library
contiene un solo archivo de origen C++ con una función JNI.
implementación:
#include <jni.h>
#include <string>
extern "C"
JNIEXPORT jstring
JNICALL
Java_com_example_android_bazel_MainActivity_stringFromJNI(
JNIEnv *env,
jobject /* this */) {
std::string hello = "Hello from C++";
return env->NewStringUTF(hello.c_str());
}
El destino android_library
especifica las fuentes de Java, los archivos de recursos y el
dependencia en un objetivo cc_library
. En este ejemplo, se carga MainActivity.java
el archivo de objeto compartido libapp.so
y define la firma del método para la JNI
función:
public class MainActivity extends AppCompatActivity {
static {
System.loadLibrary("app");
}
@Override
protected void onCreate(Bundle savedInstanceState) {
// ...
}
public native String stringFromJNI();
}
Cómo configurar la STL
Para configurar la STL de C++, usa la marca --android_crosstool_top
.
bazel build //:app --android_crosstool_top=target label
Las STL disponibles en @androidndk
son las siguientes:
STL | Etiqueta de destino |
---|---|
STLport | @androidndk//:toolchain-stlport |
libc++ | @androidndk//:toolchain-libcpp |
Gnustl | @androidndk//:toolchain-gnu-libstdcpp |
Para r16 y versiones anteriores, el STL predeterminado es gnustl
. Para r17 y superiores, es
libc++
Para tu comodidad, el @androidndk//:default_crosstool
objetivo es
con alias a las STL predeterminadas respectivas.
Ten en cuenta que, a partir de r18, STLport y gnustl serán
quitadas,
por lo que libc++
será el único STL en el NDK.
Consulta el NDK documentación para obtener más información sobre estas STL.
Cómo configurar la ABI de destino
Para configurar la ABI de destino, usa la marca --fat_apk_cpu
de la siguiente manera:
bazel build //:app --fat_apk_cpu=comma-separated list of ABIs
De forma predeterminada, Bazel compila código nativo de Android para armeabi-v7a
. Para compilar para x86
(por ejemplo, para los emuladores), pasa --fat_apk_cpu=x86
. Para crear un APK multiarquitectura para varios
puedes especificar varias CPU: --fat_apk_cpu=armeabi-v7a,x86
.
Si se especifica más de una ABI, Bazel compilará un APK que contenga un archivo para cada ABI.
Según la revisión del NDK y el nivel de API de Android, las siguientes ABI se disponibles:
Revisión del NDK | ABI |
---|---|
16 y anteriores | armeabi, armeabi-v7a, arm64-v8a, mips, mips64, x86, x86_64 |
17 y más | armeabi-v7a, arm64-v8a, x86 y x86_64 |
Consulta la documentación del NDK para obtener más información sobre estas ABI.
No se recomienda usar APK Fat de varias ABI para compilaciones de lanzamiento, ya que aumentan el tamaño del APK, pero puede ser útil para compilaciones de desarrollo y control de calidad.
Cómo seleccionar un estándar C++
Usa las siguientes marcas para compilar según un estándar de C++:
C++ estándar | Marca |
---|---|
C++98 | Predeterminado, no se necesita marca |
C++11 | --cxxopt=-std=c++11 |
C++14 | --cxxopt=-std=c++14 |
Por ejemplo:
bazel build //:app --cxxopt=-std=c++11
Obtén más información sobre cómo pasar marcas del compilador y del vinculador con --cxxopt
, --copt
y
--linkopt
en el Manual del usuario.
Las marcas del compilador y del vinculador también se pueden especificar como atributos en cc_library
.
con copts
y linkopts
. Por ejemplo:
cc_library(
name = "jni_lib",
srcs = ["cpp/native-lib.cpp"],
copts = ["-std=c++11"],
linkopts = ["-ldl"], # link against libdl
)
Integración con plataformas y cadenas de herramientas
Se está avanzando el modelo de configuración de Bazel
plataformas y
cadenas de herramientas. Si el
La compilación usa la marca --platforms
para seleccionar la arquitectura o el sistema operativo.
para compilar, deberás pasar la marca --extra_toolchains
a Bazel en
para poder usar el NDK.
Por ejemplo, para realizar la integración con la cadena de herramientas de android_arm64_cgo
proporcionada por
las reglas de Go, pasa --extra_toolchains=@androidndk//:all
además del
--platforms
.
bazel build //my/cc:lib \
--platforms=@io_bazel_rules_go//go/toolchain:android_arm64_cgo \
--extra_toolchains=@androidndk//:all
También puedes registrarlos directamente en el archivo WORKSPACE
:
android_ndk_repository(name = "androidndk")
register_toolchains("@androidndk//:all")
Cuando registras estas cadenas de herramientas, se indica a Bazel que las busque en el BUILD
del NDK.
(para NDK 20) cuando resuelvas restricciones de la arquitectura y el sistema operativo:
toolchain(
name = "x86-clang8.0.7-libcpp_toolchain",
toolchain_type = "@bazel_tools//tools/cpp:toolchain_type",
target_compatible_with = [
"@platforms//os:android",
"@platforms//cpu:x86_32",
],
toolchain = "@androidndk//:x86-clang8.0.7-libcpp",
)
toolchain(
name = "x86_64-clang8.0.7-libcpp_toolchain",
toolchain_type = "@bazel_tools//tools/cpp:toolchain_type",
target_compatible_with = [
"@platforms//os:android",
"@platforms//cpu:x86_64",
],
toolchain = "@androidndk//:x86_64-clang8.0.7-libcpp",
)
toolchain(
name = "arm-linux-androideabi-clang8.0.7-v7a-libcpp_toolchain",
toolchain_type = "@bazel_tools//tools/cpp:toolchain_type",
target_compatible_with = [
"@platforms//os:android",
"@platforms//cpu:arm",
],
toolchain = "@androidndk//:arm-linux-androideabi-clang8.0.7-v7a-libcpp",
)
toolchain(
name = "aarch64-linux-android-clang8.0.7-libcpp_toolchain",
toolchain_type = "@bazel_tools//tools/cpp:toolchain_type",
target_compatible_with = [
"@platforms//os:android",
"@platforms//cpu:aarch64",
],
toolchain = "@androidndk//:aarch64-linux-android-clang8.0.7-libcpp",
)
Cómo funciona: Presentación de las transiciones de configuración de Android
La regla android_binary
puede pedirle explícitamente a Bazel que compile sus dependencias en
una configuración compatible con Android, de modo que la compilación de Bazel funcione sin
ninguna marca especial, excepto --fat_apk_cpu
y --android_crosstool_top
para
Configuración de ABI y STL.
En segundo plano, esta configuración automática usa la configuración de Android de transición.
Una regla compatible, como android_binary
, cambia automáticamente la
de sus dependencias a una configuración de Android, por lo que solo
Los subárboles específicos de Android de la compilación se ven afectados. Otras partes de la compilación
gráfico se procesan con la configuración objetivo de nivel superior. Incluso puede
procesar un único destino en ambas configuraciones, si hay rutas a través del
gráfico de compilación para respaldarlo.
Una vez que Bazel tenga una configuración compatible con Android, se especifica en el de nivel superior o debido a un punto de transición de nivel más alto, las transiciones adicionales los puntos encontrados no modifican aún más la configuración.
La única ubicación integrada que activa la transición a Android
es el atributo deps
de android_binary
.
Por ejemplo, si intentas crear un destino android_library
con un cc_library
sin marcas, es posible que se produzca un error con un error de
encabezado:
ERROR: project/app/src/main/BUILD.bazel:16:1: C++ compilation of rule '//app/src/main:jni_lib' failed (Exit 1)
app/src/main/cpp/native-lib.cpp:1:10: fatal error: 'jni.h' file not found
#include <jni.h>
^~~~~~~
1 error generated.
Target //app/src/main:lib failed to build
Use --verbose_failures to see the command lines of failed build steps.
Idealmente, estas transiciones automáticas deberían hacer que Bazel haga lo correcto en el
la mayoría de los casos. Sin embargo, si el destino en la línea de comandos de Bazel ya es
debajo de cualquiera de estas reglas de transición, como los desarrolladores de C++ que prueban una configuración
cc_library
, se debe usar una --crosstool_top
personalizada.
Cómo compilar un cc_library
para Android sin usar android_binary
Para compilar un cc_binary
o un cc_library
independiente para Android sin usar un
android_binary
, usa --crosstool_top
, --cpu
y --host_crosstool_top
.
marcas.
Por ejemplo:
bazel build //my/cc/jni:target \
--crosstool_top=@androidndk//:default_crosstool \
--cpu=<abi> \
--host_crosstool_top=@bazel_tools//tools/cpp:toolchain
En este ejemplo, se compilan los objetivos cc_library
y cc_binary
de nivel superior
mediante el conjunto de herramientas del NDK. Sin embargo, esto provoca que se compilen las propias herramientas de host de Bazel.
con el conjunto de herramientas del NDK (y, por lo tanto, para Android), ya que la cadena de herramientas del host no
copiado de la cadena de herramientas de destino. Para solucionar esto, especifica el valor de
--host_crosstool_top
pasará a ser de @bazel_tools//tools/cpp:toolchain
a
configurar de forma explícita la cadena de herramientas de C++ del host.
Con este enfoque, se ve afectado todo el árbol de compilación.
Estas marcas se pueden colocar en una configuración de bazelrc
(una para cada ABI), en
project/.bazelrc
common:android_x86 --crosstool_top=@androidndk//:default_crosstool
common:android_x86 --cpu=x86
common:android_x86 --host_crosstool_top=@bazel_tools//tools/cpp:toolchain
common:android_armeabi-v7a --crosstool_top=@androidndk//:default_crosstool
common:android_armeabi-v7a --cpu=armeabi-v7a
common:android_armeabi-v7a --host_crosstool_top=@bazel_tools//tools/cpp:toolchain
# In general
common:android_<abi> --crosstool_top=@androidndk//:default_crosstool
common:android_<abi> --cpu=<abi>
common:android_<abi> --host_crosstool_top=@bazel_tools//tools/cpp:toolchain
Luego, para compilar un cc_library
para x86
, por ejemplo, ejecuta lo siguiente:
bazel build //my/cc/jni:target --config=android_x86
En general, usa este método para objetivos de bajo nivel (como cc_library
) o cuando
sabes exactamente lo que estás construyendo; se basan en la configuración automática
Transiciones de android_binary
para objetivos de alto nivel en los que esperas
para construir muchos objetivos que no controlas.