Compiler pour les architectures 32 bits et 64 bits

Le système de compilation permet de créer des binaires pour deux architectures de processeur cibles, 32 bits et 64 bits, dans la même compilation. Cette compilation à deux cibles est appelée compilation multilib.

Pour les bibliothèques statiques intégrées et les bibliothèques partagées, le système de compilation configure des règles pour créer des binaires pour les deux architectures. La configuration du produit (PRODUCT_PACKAGES), ainsi que le graphique des dépendances, déterminent les binaires qui sont compilés et installés dans l'image système.

Pour les exécutables et les applications, le système de compilation ne crée que la version 64 bits par défaut, mais vous pouvez remplacer ce paramètre par une variable BoardConfig.mk globale ou une variable de portée de module.

Identifier une deuxième architecture de processeur et une deuxième ABI

BoardConfig.mk inclut les variables suivantes pour configurer la deuxième architecture de processeur et l'interface binaire d'application (ABI):

  • TARGET_2ND_ARCH
  • TARGET_2ND_ARCH_VARIANT
  • TARGET_2ND_CPU_VARIANT
  • TARGET_2ND_CPU_ABI
  • TARGET_2ND_CPU_ABI2

Pour obtenir un exemple de fichier make qui utilise ces variables, consultez build/make/target/board/generic_arm64/BoardConfig.mk.

Dans une compilation multilib, les noms de module dans PRODUCT_PACKAGES couvrent à la fois les binaires 32 bits et 64 bits, à condition qu'ils soient définis par le système de compilation. Pour les bibliothèques incluses par une dépendance, une bibliothèque 32 bits ou 64 bits n'est installée que si elle est requise par une autre bibliothèque ou un autre exécutable 32 bits ou 64 bits.

Toutefois, les noms de module sur la ligne de commande make ne couvrent que la version 64 bits. Par exemple, après l'exécution de lunch aosp_arm64-eng, make libc ne compile que la libc 64 bits. Pour compiler la libc 32 bits, vous devez exécuter make libc_32.

Définir l'architecture des modules dans le fichier Android.mk

Vous pouvez utiliser la variable LOCAL_MULTILIB pour configurer votre compilation pour 32 bits et 64 bits, et remplacer la variable TARGET_PREFER_32_BIT globale.

Pour remplacer TARGET_PREFER_32_BIT, définissez LOCAL_MULTILIB sur l'une des valeurs suivantes:

  • both génère des builds 32 bits et 64 bits.
  • 32 ne compile que des builds 32 bits.
  • 64 ne crée que des versions 64 bits.
  • first ne compile que pour la première architecture (32 bits sur les appareils 32 bits et 64 bits sur les appareils 64 bits).

Par défaut, LOCAL_MULTILIB n'est pas défini, et le système de compilation décide de l'architecture à compiler en fonction de la classe de module et d'autres variables LOCAL_*, telles que LOCAL_MODULE_TARGET_ARCH et LOCAL_32_BIT_ONLY.

Si vous souhaitez compiler votre module pour des architectures spécifiques, utilisez les variables suivantes:

  • LOCAL_MODULE_TARGET_ARCH : définissez cette variable sur une liste d'architectures, comme arm x86 arm64. Si l'architecture en cours de compilation figure dans cette liste, le module actuel est inclus par le système de compilation.

  • LOCAL_MODULE_UNSUPPORTED_TARGET_ARCH : cette variable est l'opposé de LOCAL_MODULE_TARGET_ARCH. Si l'architecture en cours de compilation est not dans cette liste, le module actuel est inclus par le système de compilation.

Il existe des variantes mineures de ces deux variables:

  • LOCAL_MODULE_TARGET_ARCH_WARN
  • LOCAL_MODULE_UNSUPPORTED_TARGET_ARCH_WARN

Le système de compilation émet un avertissement si le module actuel est ignoré en raison des architectures listées.

Pour configurer des indicateurs de compilation pour une architecture particulière, utilisez les variables LOCAL_* spécifiques à l'architecture, où * est un suffixe spécifique à l'architecture, par exemple:

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

Ces variables ne s'appliquent que si un binaire est créé pour cette architecture.

Il est parfois plus simple de configurer des indicateurs en fonction de la version binaire créée (32 bits ou 64 bits). Utilisez la variable LOCAL_* avec un suffixe _32 ou _64, par exemple:

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

Définir le chemin d'installation de la bibliothèque

Pour une compilation non multilib, vous pouvez utiliser LOCAL_MODULE_PATH pour installer une bibliothèque à un autre emplacement que l'emplacement par défaut. Par exemple, LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw.

Toutefois, dans une compilation multilib, utilisez plutôt LOCAL_MODULE_RELATIVE_PATH:

LOCAL_MODULE_RELATIVE_PATH := hw

Avec ce format, les bibliothèques 64 bits et 32 bits sont installées au bon endroit.

Si vous créez un exécutable en 32 bits et en 64 bits, utilisez l'une des variables suivantes pour distinguer le chemin d'installation:

  • LOCAL_MODULE_STEM_32, LOCAL_MODULE_STEM_64 : spécifie le nom de fichier installé.
  • LOCAL_MODULE_PATH_32, LOCAL_MODULE_PATH_64 : spécifie le chemin d'installation.

Obtenir le répertoire intermédiaire pour les fichiers sources

Dans une compilation multilib, si vous générez des fichiers sources pour $(local-intermediates-dir) (ou $(intermediates-dir-for) avec des variables explicites), cela ne fonctionne pas de manière fiable. En effet, les sources générées intermédiaires sont requises à la fois pour les builds 32 bits et 64 bits, mais $(local-intermediates-dir) ne pointe que sur l'un des deux répertoires intermédiaires.

Le système de compilation fournit un répertoire intermédiaire dédié, compatible avec les multilibs, pour générer des sources. Pour récupérer le chemin d'accès au répertoire intermédiaire, utilisez la macro $(local-generated-sources-dir) ou $(generated-sources-dir-for). L'utilisation de ces macros est semblable à celle de $(local-intermediates-dir) et $(intermediates-dir-for).

Si un fichier source est généré dans ce répertoire dédié et récupéré par LOCAL_GENERATED_SOURCES, il est compilé pour les architectures 32 bits et 64 bits dans une compilation multilib.

Indiquer l'architecture système des cibles binaires précompilées

Dans une compilation multilib, vous ne pouvez pas utiliser TARGET_ARCH, ni TARGET_ARCH combiné à TARGET_2ND_ARCH, pour indiquer l'architecture système des cibles binaires précompilées. Utilisez plutôt les variables LOCAL_* LOCAL_MODULE_TARGET_ARCH ou LOCAL_MODULE_UNSUPPORTED_TARGET_ARCH.

Avec ces variables, le système de compilation peut choisir le binaire précompilé 32 bits correspondant, même s'il travaille sur une version multilib 64 bits.

Si vous souhaitez utiliser l'architecture choisie pour calculer le chemin d'accès source du binaire précompilé, appelez $(get-prebuilt-src-arch).

Assurer la génération de fichiers ODEX 32 et 64 bits

Pour les appareils 64 bits, Google génère par défaut des fichiers ODEX 32 bits et 64 bits pour l'image de démarrage et toutes les bibliothèques Java. Pour les APK, Google ne génère par défaut des fichiers ODEX que pour l'architecture 64 bits principale. Si une application est lancée à la fois dans des processus 32 bits et 64 bits, utilisez LOCAL_MULTILIB := both pour vous assurer que les fichiers ODEX 32 bits et 64 bits sont générés. Si l'application contient des bibliothèques JNI 32 ou 64 bits, cet indicateur indique également au système de compilation de les inclure.