Chaînes d'outils autonomes (obsolètes)

Vous pouvez utiliser les chaînes d'outils fournies avec le NDK Android de manière indépendante ou en tant que plug-ins avec un IDE existant. Cette flexibilité est particulièrement utile si vous disposez déjà de votre propre système de compilation et que vous n'avez besoin que de la capacité d'appeler le compilateur croisé afin qu'il soit compatible avec Android.

Sélectionner votre chaîne d'outils

Avant toute chose, vous devez décider de l'architecture de processeur qui sera ciblée par votre chaîne d'outils autonome. Pour ce faire, utilisez l'indicateur --arch.

Sélectionner le répertoire sysroot

L'étape suivante consiste à définir le sysroot. Un "sysroot" est un répertoire contenant les bibliothèques et les en-têtes système de la cible. Pour définir le répertoire sysroot, vous devez connaître le niveau d'API Android que vous souhaitez cibler pour la compatibilité native. Les API natives disponibles varient selon le niveau d'API Android.

Les bibliothèques des API natives pour les niveaux d'API Android respectifs se trouvent sous $NDK/platforms/. Chaque répertoire au niveau de l'API contient à son tour des sous-répertoires pour les différents processeurs et architectures. Les en-têtes se trouvent dans $NDK/sysroot.

Pour plus d'informations sur les niveaux d'API Android et les API natives compatibles correspondantes, consultez la page API natives.

Créer la chaîne d'outils

Le NDK fournit le script make_standalone_toolchain.py pour vous permettre d'installer une chaîne d'outils personnalisée à partir de la ligne de commande.

Il s'agit d'un nouvel outil qui remplace l'ancien make-standalone-toolchain.sh. Il a été simplifié en Python, ce qui évite aux utilisateurs de Windows d'installer Cygwin ou MSYS pour l'exécuter.

Le script se trouve dans le répertoire $NDK/build/tools/, où $NDK est la racine d'installation du NDK.

Voici un exemple d'utilisation de ce script :

$NDK/build/tools/make_standalone_toolchain.py \
    --arch arm --api 21 --install-dir /tmp/my-android-toolchain

Cette commande crée un répertoire nommé /tmp/my-android-toolchain/, contenant une copie du répertoire sysroot android-21/arch-arm, ainsi que des binaires de la chaîne d'outils pour une cible ARM 32 bits.

Notez que les binaires de la chaîne d'outils ne dépendent pas de chemins spécifiques à l'hôte et qu'ils ne contiennent d'ailleurs pas de chemins spécifiques. En d'autres termes, vous pouvez les installer à l'emplacement de votre choix, voire les déplacer si nécessaire.

L'argument --arch est obligatoire, mais le niveau d'API choisi par défaut est le niveau minimal accepté pour l'architecture donnée (actuellement le niveau 16 pour les architectures 32 bits et 21 pour les architectures 64 bits).

Depuis la version r18, toutes les chaînes d'outils autonomes utilisent Clang et libc++. La bibliothèque partagée libc++ est utilisée par défaut, sauf si vous créez un exécutable statique. Pour forcer l'utilisation de la bibliothèque statique, transmettez -static-libstdc++ lors de l'association. Ce comportement correspond à celui d'une chaîne d'outils hôte normale.

Comme indiqué dans la section Compatibilité avec les bibliothèques C++, vous devrez souvent transmettre -latomic lors de l'association avec libc++.

Notez que si vous omettez l'option --install-dir, l'outil crée un tarball dans le répertoire actuel nommé $TOOLCHAIN_NAME.tar.bz2. Ce tarball peut être placé dans un autre répertoire à l'aide de --package-dir.

Pour plus d'options et d'informations, utilisez --help.

Fonctionnement des binaires Clang

Les binaires Clang sont automatiquement inclus dans les chaînes d'outils autonomes.

Il existe également deux scripts de wrapper, nommés clang et clang++, sous <install-dir>/bin. Ces scripts appellent le binaire clang avec les indicateurs d'architecture cible appropriées. En d'autres termes, ils devraient fonctionner sans nécessiter aucune modification. Pour pouvoir les utiliser dans vos propres compilations, définissez simplement les variables d'environnement CC et CXX pour qu'elles pointent vers elles.

Il existe également des scripts wrapper gcc et g++ qui appellent également Clang. L'objectif est de fournir un certain niveau de compatibilité pour les fichiers de compilation qui font explicitement référence à GCC, même si le NDK ne contient plus GCC. Bien entendu, si un fichier de compilation utilise des options de ligne de commande non compatibles avec Clang, vous devez les supprimer ou les remplacer.

Cibles Clang avec ARM

Lors de la compilation pour ARM, Clang modifie la cible en fonction de la présence des indicateurs de compilation -march=armv7-a et/ou -mthumb :

Tableau 1. Valeurs -march pouvant être spécifiées et cibles obtenues en conséquence

Valeur -march Cible obtenue
-march=armv7-a armv7-none-linux-androideabi
-mthumb thumb-none-linux-androideabi
-march=armv7-a et -mthumb thumbv7-none-linux-androideabi

Si vous le souhaitez, vous pouvez également remplacer la cible par votre propre valeur -target.

clang et clang++ se substituent à gcc et g++ dans un fichier makefile. En cas de doute, utilisez les options suivantes lorsque vous appelez le compilateur pour vérifier qu'elles fonctionnent correctement :

  • -v pour vider les commandes associées aux problèmes de pilote de compilation
  • -### pour vider les options de ligne de commande, y compris les options implicitement prédéfinies
  • -x c < /dev/null -dM -E pour vider les définitions de préprocesseur prédéfinies
  • -save-temps pour comparer les fichiers prétraités *.i ou *.ii

Compatibilité avec les ABI

Par défaut, une chaîne d'outils autonome ARM Clang cible l'ABI armeabi-v7a. Pour modifier ce comportement, transmettez l'option -march ou -target appropriée.

Nous vous recommandons d'utiliser l'indicateur de compilation -mthumb pour forcer la génération d'instructions Thumb-2 16 bits. Dans le cas contraire, la chaîne d'outils émettra des instructions ARM 32 bits.

Pour utiliser les instructions NEON, vous devez choisir l'indicateur de compilation -mfpu : -mfpu=neon.

Notez que ce paramètre force l'utilisation de VFPv3-D32, conformément à la spécification ARM.

Veillez également à fournir les deux indicateurs suivants à l'outil d'association : -march=armv7-a -Wl,--fix-cortex-a8.

Le premier indicateur demande à l'outil d'association de choisir des bibliothèques de chaînes d'outils personnalisées pour armv7-a. Le deuxième indicateur est nécessaire pour contourner un bug du processeur dans certaines implémentations de Cortex-A8.

Vous n'avez pas besoin d'utiliser un indicateur de compilation spécifique lorsque vous ciblez les autres ABI.

Pour en savoir plus sur la compatibilité avec les ABI, consultez la section ABI Android.

Avertissements et limites

Compatibilité Windows

Les binaires Windows ne dépendent pas de Cygwin. Ce manque de dépendance les rend plus rapides. En revanche, ils ne comprennent pas les spécifications des chemins d'accès à Cygwin, comme cygdrive/c/foo/bar, par opposition à C:/foo/bar.

Exceptions, RTTI et STL

Les binaires de la chaîne d'outils sont compatibles avec les exceptions C++ et RTTI par défaut. Pour désactiver les exceptions C++ et RTTI lors de la création des sources (pour générer un code machine plus léger, par exemple), utilisez -fno-exceptions et -fno-rtti.

Compatibilité de l'implémentation STL C++

La chaîne d'outils autonome inclut une implémentation STL (Standard Template Library) C++.

  • Utilisez -static-libstdc++ pour obtenir la version statique de la bibliothèque libc++. De cette façon, vous vous assurez que tout le code STL C++ requis sera inclus dans le binaire final. Cette méthode est idéale si vous ne générez qu'une seule bibliothèque partagée ou un seul fichier exécutable, ce que nous recommandons.

  • La version libc++ de la bibliothèque partagée est utilisée par défaut. Aucun indicateur supplémentaire n'est nécessaire pour l'association avec la bibliothèque partagée. Vous devez empaqueter libc++_shared.so dans votre application pour que votre code se charge.

    Le tableau 2 indique l'emplacement de ce fichier pour chaque architecture.

    Tableau 2. Valeurs -march pouvant être spécifiées et cibles obtenues en conséquence

    Chaîne d'outils Localisation
    arm $TOOLCHAIN/arm-linux-androideabi/lib/
    arm64 $TOOLCHAIN/aarch64-linux-android/lib/
    x86 $TOOLCHAIN/i686-linux-android/lib/
    x86_64 $TOOLCHAIN/x86_64-linux-android/lib/

Créer des projets Open Source à l'aide de chaînes d'outils autonomes

Avec cet exemple de chaîne d'outils :

# Create an arm64 API 26 libc++ toolchain.
$NDK/build/tools/make_standalone_toolchain.py \
  --arch arm64 \
  --api 26 \
  --install-dir=my-toolchain

Voici comment configurer votre environnement pour l'utiliser afin de créer un projet Open Source traditionnel :

# Add the standalone toolchain to the search path.
export PATH=$PATH:`pwd`/my-toolchain/bin

# Tell configure what tools to use.
target_host=aarch64-linux-android
export AR=$target_host-ar
export AS=$target_host-clang
export CC=$target_host-clang
export CXX=$target_host-clang++
export LD=$target_host-ld
export STRIP=$target_host-strip

# Tell configure what flags Android requires.
export CFLAGS="-fPIE -fPIC"
export LDFLAGS="-pie"

Projets avec des systèmes de compilation personnalisés

Voici un exemple de création d'une boîte à outils après avoir suivi les étapes précédentes :

git clone https://github.com/landley/toybox.git
cd toybox
make defconfig && make

Projets avec autoconf

Alternativement, un projet basé sur autoconf ressemblerait davantage à ceci :

tar zxvf make-4.2.tar.gz
cd make-4.2
./configure --host=$target_host && make

Notez que la possibilité d'effectuer la compilation croisée entre les projets basés sur autoconf est très variable. Notez également que si vous exécutez la commande git clone au niveau d'un projet autoconf, il est peu probable qu'un script configure soit enregistré. Vous devrez donc suivre la documentation de ce projet pour découvrir comment procéder à l'amorçage.