Se você não conhece o Bazel, comece com o tutorial Como criar apps Android com o Bazel.
Visão geral
O Bazel pode ser executado em várias configurações de build diferentes, incluindo várias que usam
a cadeia de ferramentas do Kit de desenvolvimento nativo (NDK) do Android. Isso significa que as regras normais de
cc_library e cc_binary podem ser compiladas para Android diretamente no
Bazel. O Bazel faz isso usando a regra de repositório android_ndk_repository e a extensão bzlmod relacionada.
Para compilação geral do Android, use rules_android.
Este tutorial demonstra como integrar dependências de biblioteca C++ a
apps Android e usa
rules_android_ndk para descoberta e registro de
cadeia de ferramentas do NDK.
Pré-requisitos
Verifique se você instalou o SDK e o NDK do Android.
Configuração do NDK e do SDK
A configuração do repositório externo varia dependendo se você está usando WORKSPACE ou bzlmod (MODULE.bazel). O Bzlmod é a solução preferida para o Bazel 7 ou versões mais recentes. As estrofes de configuração MODULE.bazel e WORKSPACE são independentes umas das outras. Se você estiver usando uma solução de gerenciamento de dependências, não será necessário adicionar o boilerplate para a outra.
Configuração do MODULE.bazel do Bzlmod
Adicione o seguinte snippet ao seu MODULE.bazel:
# NDK
bazel_dep(name = "rules_android_ndk", version = "0.1.3")
android_ndk_repository_extension = use_extension("@rules_android_ndk//:extension.bzl", "android_ndk_repository_extension")
use_repo(android_ndk_repository_extension, "androidndk")
register_toolchains("@androidndk//:all")
# SDK
bazel_dep(name = "rules_android", version = "0.6.6")
register_toolchains(
"@rules_android//toolchains/android:android_default_toolchain",
"@rules_android//toolchains/android_sdk:android_sdk_tools",
)
android_sdk_repository_extension = use_extension("@rules_android//rules/android_sdk_repository:rule.bzl", "android_sdk_repository_extension")
use_repo(android_sdk_repository_extension, "androidsdk")
register_toolchains("@androidsdk//:sdk-toolchain", "@androidsdk//:all")
Configuração legada do WORKSPACE
Adicione o seguinte snippet ao seu WORKSPACE:
load("@rules_android//rules:rules.bzl", "android_sdk_repository")
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.
)
load("@rules_android_ndk//:rules.bzl", "android_ndk_repository")
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.
)
Observações sobre compatibilidade para o WORKSPACE:
- As regras
rules_androiderules_android_ndkexigem um modelo extra que não está representado no snippet do WORKSPACE acima. Para uma estrofe de instanciação atualizada e totalmente formada, consulte o arquivo WORKSPACE do app de exemplo básico derules_android_ndk.
Para mais informações sobre a regra android_ndk_repository, consulte a
string de documentação.
Início rápido
Para criar C++ para Android, basta adicionar dependências cc_library às regras
android_binary ou android_library.
Por exemplo, considerando o seguinte arquivo BUILD para um app Android:
# In <project>/app/src/main/BUILD.bazel
load("@rules_cc//cc:cc_library.bzl", "cc_library")
load("@rules_android//rules:rules.bzl", "android_binary", "android_library")
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",
)
Esse arquivo BUILD resulta no seguinte gráfico de destino:

Figura 1. Crie um gráfico de build do projeto Android com dependências cc_library.
Para criar o app, basta executar:
bazel build //app/src/main:app --android_platforms=<your platform>Se você não especificar --android_platforms, o build vai falhar com erros sobre cabeçalhos JNI ausentes.
O comando bazel build compila os arquivos Java, os arquivos de recursos do Android e as regras cc_library e empacota tudo em um 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.MFO Bazel compila todas as cc_libraries em um único arquivo de objeto compartilhado (.so),
direcionado às arquiteturas especificadas por --android_platforms.
Consulte a seção sobre como configurar a ABI de destino para
mais detalhes.
Exemplo de configuração
Este exemplo está disponível no repositório de exemplos do Bazel.
No arquivo BUILD.bazel, três destinos são definidos com as regras android_binary, android_library e cc_library.
O destino de nível superior android_binary cria o APK.
O destino cc_library contém um único arquivo de origem C++ com uma implementação de função JNI:
#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());
}
O destino android_library especifica as fontes Java, os arquivos de recursos e a
dependência de um destino cc_library. Neste exemplo, MainActivity.java carrega
o arquivo de objeto compartilhado libapp.so e define a assinatura do método para a função
JNI:
public class MainActivity extends AppCompatActivity {
static {
System.loadLibrary("app");
}
@Override
protected void onCreate(Bundle savedInstanceState) {
// ...
}
public native String stringFromJNI();
}
Como configurar a ABI de destino
Para configurar a ABI de destino, use a flag --android_platforms da seguinte maneira:
bazel build //:app --android_platforms=comma-separated list of platformsAssim como a flag --platforms, os valores transmitidos para --android_platforms são os rótulos de destinos platform, usando valores de restrição padrão para descrever seu dispositivo.
Por exemplo, para um dispositivo Android com um processador ARM de 64 bits, você definiria sua plataforma assim:
platform(
name = "android_arm64",
constraint_values = [
"@platforms//os:android",
"@platforms//cpu:arm64",
],
)
Todo platform do Android precisa usar a restrição de SO @platforms//os:android. Para migrar a restrição de CPU, confira este gráfico:
| Valor da CPU | Plataforma |
|---|---|
armeabi-v7a |
@platforms//cpu:armv7 |
arm64-v8a |
@platforms//cpu:arm64 |
x86 |
@platforms//cpu:x86_32 |
x86_64 |
@platforms//cpu:x86_64 |
E, claro, para um APK de várias arquiteturas, você transmite vários rótulos, por exemplo: --android_platforms=//:arm64,//:x86_64 (supondo que você os tenha definido no arquivo BUILD.bazel de nível superior).
O Bazel não consegue selecionar uma plataforma Android padrão. Portanto, é necessário definir e especificar uma com --android_platforms.
Dependendo da revisão do NDK e do nível da API do Android, as seguintes ABIs estão disponíveis:
| Revisão do NDK | Interfaces binárias de aplicativo (ABIs, na sigla em inglês) |
|---|---|
| 16 e versões anteriores | armeabi, armeabi-v7a, arm64-v8a, mips, mips64, x86, x86_64 |
| 17 e mais recentes | armeabi-v7a, arm64-v8a, x86, x86_64 |
Consulte a documentação do NDK para mais informações sobre essas ABIs.
APKs multiarquitetura não são recomendados para builds de lançamento porque aumentam o tamanho do APK, mas podem ser úteis para builds de desenvolvimento e controle de qualidade.
Selecionar um padrão C++
Use as seguintes flags para criar de acordo com um padrão C++:
| Padrão C++ | Sinalização |
|---|---|
| C++98 | Padrão, sem necessidade de flag |
| C++11 | --cxxopt=-std=c++11 |
| C++14 | --cxxopt=-std=c++14 |
| C++17 | --cxxopt=-std=c++17 |
Exemplo:
bazel build //:app --cxxopt=-std=c++11Leia mais sobre como transmitir flags do compilador e do vinculador com --cxxopt, --copt e --linkopt no manual do usuário.
As flags do compilador e do vinculador também podem ser especificadas como atributos em cc_library usando copts e linkopts. Exemplo:
cc_library(
name = "jni_lib",
srcs = ["cpp/native-lib.cpp"],
copts = ["-std=c++11"],
linkopts = ["-ldl"], # link against libdl
)
Como criar um cc_library para Android sem usar o android_binary
Para criar um cc_binary ou cc_library independente para Android sem usar um
android_binary, use a flag --platforms.
Por exemplo, supondo que você tenha definido plataformas Android em
my/platforms/BUILD:
bazel build //my/cc/jni:target \
--platforms=//my/platforms:x86_64Com essa abordagem, toda a árvore de build é afetada.
Essas flags podem ser colocadas em uma configuração bazelrc (uma para cada ABI), em
project/.bazelrc:
common:android_x86 --platforms=//my/platforms:x86
common:android_armeabi-v7a --platforms=//my/platforms:armeabi-v7a
# In general
common:android_<abi> --platforms=//my/platforms:<abi>
Em seguida, para criar um cc_library para x86, por exemplo, execute:
bazel build //my/cc/jni:target --config=android_x86Em geral, use esse método para destinos de baixo nível (como cc_library) ou quando você sabe exatamente o que está criando. Confie nas transições automáticas de configuração de android_binary para destinos de alto nível em que você espera criar muitos destinos que não controla.