Cómo compilar para arquitecturas de 32 y 64 bits

El sistema de compilación permite compilar objetos binarios para dos arquitecturas de la CPU de destino (32 bits y 64 bits) en la misma compilación. Esta compilación de dos objetivos se conoce como compilación multilib.

En el caso de las bibliotecas estáticas y las bibliotecas compartidas integradas, el sistema de compilación configura reglas de compilación de objetos binarios para ambas arquitecturas. La configuración del producto (PRODUCT_PACKAGES), junto con el gráfico de dependencia, determina qué objetos binarios se compilan y se instalan en la imagen del sistema.

En el caso de los ejecutables y las apps, el sistema de compilación solo compila la versión de 64 bits de forma predeterminada. Sin embargo, puedes anular esta configuración con una variable BoardConfig.mk global o una variable específica del módulo.

Cómo identificar la segunda arquitectura de CPU y ABI

BoardConfig.mk incluye las siguientes variables para configurar la segunda arquitectura de la CPU y la interfaz binaria de la aplicación (ABI):

  • TARGET_2ND_ARCH
  • TARGET_2ND_ARCH_VARIANT
  • TARGET_2ND_CPU_VARIANT
  • TARGET_2ND_CPU_ABI
  • TARGET_2ND_CPU_ABI2

Para ver un ejemplo de un archivo Make que usa estas variables, consulta build/make/target/board/generic_arm64/BoardConfig.mk.

En una compilación multilib, los nombres de módulos en PRODUCT_PACKAGES abarcan los objetos binarios para 32 y 64 bits, siempre y cuando los defina el sistema de compilación. Para las bibliotecas incluidas por dependencia, una biblioteca de 32 o 64 bits se instala solo si lo requiere otra biblioteca de 32 o 64 bits o un ejecutable.

No obstante, solo se aplican los nombres de módulo en la línea de comandos make a la versión de 64 bits. Por ejemplo, luego de ejecutar lunch aosp_arm64-eng, make libc solo compila la libc de 64 bits. Si quieres compilar la de 32 bits, debes ejecutar make libc_32.

Cómo definir la arquitectura de módulo en Android.mk

Puedes usar la variable LOCAL_MULTILIB para configurar tu compilación para 32 o 64 bits y anular la variable TARGET_PREFER_32_BIT global.

Para anular TARGET_PREFER_32_BIT, establece LOCAL_MULTILIB en una de las siguientes opciones:

  • both compila 32 bits y 64 bits.
  • 32 solo compila 32 bits.
  • 64 solo compila 64 bits.
  • first solo compila para la primera arquitectura (32 bits en dispositivos de 32 bits y 64 bits en dispositivos de 64 bits).

De forma predeterminada, LOCAL_MULTILIB no está establecido y el sistema de compilación decide la arquitectura que debe compilar según la clase de módulo y otras variables LOCAL_*, como LOCAL_MODULE_TARGET_ARCH y LOCAL_32_BIT_ONLY.

Si deseas compilar tu módulo para arquitecturas específicas, usa las siguientes variables:

  • LOCAL_MODULE_TARGET_ARCH: Establece esta variable como una lista de arquitecturas. Por ejemplo, arm x86 arm64. Si la arquitectura que se compila está en esa lista, el sistema de compilación incluirá el módulo actual.

  • LOCAL_MODULE_UNSUPPORTED_TARGET_ARCH: Esta variable es opuesta a LOCAL_MODULE_TARGET_ARCH. Si la arquitectura que se compila not está en esa lista, el sistema de compilación incluirá el módulo actual.

Hay variantes menores de estas dos variables:

  • LOCAL_MODULE_TARGET_ARCH_WARN
  • LOCAL_MODULE_UNSUPPORTED_TARGET_ARCH_WARN

El sistema de compilación muestra una advertencia si se omite el módulo actual debido a las arquitecturas de la lista.

Si quieres configurar marcas de compilación para una arquitectura en particular, usa las variables LOCAL_* específicas de la arquitectura donde * es un sufijo específico de la arquitectura. Por ejemplo:

  • LOCAL_SRC_FILES_arm, LOCAL_SRC_FILES_x86,
  • LOCAL_CFLAGS_arm, LOCAL_CFLAGS_arm64,
  • LOCAL_LDFLAGS_arm, LOCAL_LDFLAGS_arm64,

Solo se aplican estas variables si se está compilando un objeto binario para esa arquitectura.

En ocasiones, es más sencillo configurar marcas en función de si el objeto binario se compila para 32 o 64 bits. Usa la variable LOCAL_* con un sufijo _32 o _64, por ejemplo:

  • LOCAL_SRC_FILES_32, LOCAL_SRC_FILES_64,
  • LOCAL_CFLAGS_32, LOCAL_CFLAGS_64,
  • LOCAL_LDFLAGS_32, LOCAL_LDFLAGS_64,

Cómo establecer la ruta de instalación de la biblioteca

Para una compilación que no sea multilib, puedes usar LOCAL_MODULE_PATH para instalar una biblioteca en una ubicación que no sea la predeterminada. Por ejemplo, LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw.

Sin embargo, en una compilación multilib, usa LOCAL_MODULE_RELATIVE_PATH en su lugar:

LOCAL_MODULE_RELATIVE_PATH := hw

Con este formato, tanto las bibliotecas de 64 bits como las de 32 bits se instalan en la ubicación correcta.

Si compilas un archivo ejecutable para 32 bits y 64 bits, usa una de las siguientes variables para distinguir la ruta de acceso de instalación:

  • LOCAL_MODULE_STEM_32, LOCAL_MODULE_STEM_64: Especifica el nombre del archivo instalado.
  • LOCAL_MODULE_PATH_32, LOCAL_MODULE_PATH_64: Especifica la ruta de acceso de instalación.

Cómo obtener el directorio intermedio para los archivos de fuente

En una compilación multilib, si generas archivos de origen en $(local-intermediates-dir) (o $(intermediates-dir-for) con variables explícitas), el funcionamiento no es confiable, ya que tanto la compilación de 32 bits como la de 64 bits requieren los archivos de origen intermedios generados, pero $(local-intermediates-dir) solo apunta a uno de los dos directorios intermedios.

El sistema de compilación proporciona un directorio intermedio dedicado que es compatible con multilib para generar fuentes. Para recuperar la ruta de acceso del directorio intermedio, usa el macro $(local-generated-sources-dir) o $(generated-sources-dir-for). El uso de estos macros es similar a $(local-intermediates-dir) y $(intermediates-dir-for).

Si se genera un archivo de origen en este directorio dedicado y LOCAL_GENERATED_SOURCES lo recoge, se compila para 32 y 64 bits en una compilación multilib.

Cómo indicar la arquitectura del sistema de objetivos binarios compilados previamente

En una compilación multilib, no puedes usar TARGET_ARCH (ni TARGET_ARCH combinado con TARGET_2ND_ARCH) para indicar la arquitectura del sistema de objetivos binarios compilados previamente. En su lugar, usa las variables LOCAL_* LOCAL_MODULE_TARGET_ARCH o LOCAL_MODULE_UNSUPPORTED_TARGET_ARCH.

Con esas variables, el sistema de compilación puede elegir el objeto binario de 32 bits precompilado correspondiente, incluso aunque funcione en una compilación multilib de 64 bits.

Si deseas usar la arquitectura elegida para calcular la ruta de acceso de origen del objeto binario precompilado, llama a $(get-prebuilt-src-arch).

Cómo asegurar la generación del archivo ODEX de 32 y 64 bits

En el caso de dispositivos de 64 bits, de forma predeterminada, generamos archivos ODEX de 32 y 64 bits para la imagen de arranque y cualquier biblioteca Java. Para los APKs, Google genera ODEX de forma predeterminada solo para la arquitectura de 64 bits principal. Si se iniciará una app en procesos de 32 y 64 bits, usa LOCAL_MULTILIB := both para garantizar que se generen archivos ODEX para ambas arquitecturas. Si la app tiene bibliotecas JNI de 32 o 64 bits, esa marca también le indica al sistema de compilación que las incluya.