Ce document représente une liste partielle des non-bugs les plus courants que vous pouvez rencontrer lors de l'utilisation du NDK. Il fournit également des solutions (le cas échéant).
Utiliser _FILE_OFFSET_BITS=64
avec des anciens niveaux d'API
Avant les en-têtes unifiés, le NDK n'acceptait pas _FILE_OFFSET_BITS=64
. Si vous avez défini cette fonction lors de la création de votre application, elle a été ignorée sans notification. L'option _FILE_OFFSET_BITS=64
est désormais compatible avec les en-têtes unifiés, mais sur les anciennes versions d'Android, très peu d'API off_t
étaient disponibles en tant que variante off64_t
. Par conséquent, l'utilisation de cette fonctionnalité avec les anciens niveaux d'API réduit le nombre de fonctions disponibles.
Ce problème est expliqué en détail dans l'article de blog r16 et dans la documentation spécifique à l'implémentation Bionic.
Problème : votre build demande des API qui n'existent pas dans votre minSdkVersion
.
Solution : désactivez _FILE_OFFSET_BITS=64
ou augmentez votre minSdkVersion
.
Définition non déclarée ou implicite de mmap
L'erreur suivante peut s'afficher en C++ :
error: use of undeclared identifier 'mmap' (erreur : utilisation de l'identifiant non déclaré "mmap")
ou l'erreur suivante en C :
warning: implicit declaration of function 'mmap' is invalid in C99 (avertissement : La déclaration implicite de la fonction "mmap" n'est pas valide dans C99)
L'utilisation de _FILE_OFFSET_BITS=64
indique à la bibliothèque C de choisir mmap64
au lieu de mmap
. mmap64
n'était pas disponible avant android-21
. Si la valeur de minSdkVersion
est inférieure à 21, la bibliothèque C ne contient pas de mmap
compatible avec _FILE_OFFSET_BITS=64
. La fonction n'est donc pas disponible.
Niveau de minSdkVersion
supérieur au niveau d'API de l'appareil
Le niveau d'API que vous utilisez pour la compilation avec le NDK a une signification très différente de celle de compileSdkVersion
pour Java. Le niveau d'API du NDK correspond au niveau d'API minimal qui est compatible avec votre application. Dans ndk-build, il s'agit du paramètre APP_PLATFORM
. Avec CMake, il s'agit de -DANDROID_PLATFORM
.
Étant donné que les références aux fonctions sont généralement résolues lors du chargement des bibliothèques plutôt que lors de leur premier appel, vous ne pouvez pas référencer des API qui ne sont pas toujours présentes et protéger leur utilisation avec des vérifications au niveau de l'API. Si elles sont référencées, elles doivent être présentes.
Problème : le niveau d'API du NDK est supérieur à celui de l'API compatible avec votre appareil.
Solution : définissez le niveau d'API du NDK (APP_PLATFORM
) sur la version minimale d'Android compatible avec votre application.
Système de compilation | Paramètre |
---|---|
ndk-build | APP_PLATFORM |
CMake | ANDROID_PLATFORM |
externalNativeBuild | android.minSdkVersion |
Pour les autres systèmes de compilation, consultez Utiliser le NDK avec d'autres systèmes de compilation.
Impossible de localiser les symboles __aeabi
Le message suivant :
UnsatisfiedLinkError: dlopen failed: cannot locate symbol "
__aeabi_memcpy
" (UnlessLinkError : échec de dlopen : impossible de localiser le symbole "__aeabi_memcpy
")
est un exemple d'erreur d'exécution possible. Ces erreurs apparaissent dans le journal lorsque vous tentez de charger vos bibliothèques natives. Le symbole peut être toute variante d'__aeabi_*
. __aeabi_memcpy
et __aeabi_memclr
semblent être les plus courants.
Ce cas de figure est documenté dans le problème 126.
Impossible de localiser le symbole rand
Pour le message de journal d'erreur suivant :
UnsatisfiedLinkError: dlopen failed: cannot locate symbol "
rand
" (UnlessLinkError : échec de dlopen : impossible de localiser le symbole "rand
")
Consultez cette réponse de Stack Overflow.
Référence non définie à __atomic_*
Problème : certaines ABI ont besoin de libatomic
afin de fournir des implémentations pour les opérations atomiques.
Solution : ajoutez -latomic
lors de l'association.
Pour le message d'erreur suivant :
error: undefined reference to '
__atomic_exchange_4
' (erreur : référence non définie à "__atomic_exchange_4
")
Le symbole réel peut être n'importe quel préfixe commençant par __atomic_
.
RTTI et les exceptions ne fonctionnent pas au-delà des limites de la bibliothèque
Problème : les exceptions ne sont pas détectées lorsqu'elles sont générées au-delà des limites de la bibliothèque partagée ou lorsque dynamic_cast
échoue.
Solution : ajoutez une fonction clé à vos types. Une fonction clé est la première fonction virtuelle non pure et non connectée pour un type. Pour consulter un exemple, reportez-vous à la discussion sur le problème 533.
L'ABI C++ indique que deux objets ont le même type si et seulement si leurs pointeurs type_info
sont identiques. Les exceptions ne peuvent être capturées que si type_info
correspond à l'exception générée. La même règle s'applique à dynamic_cast
.
Lorsqu'un type ne comporte pas de fonction clé, son typeinfo
est émis en tant que symbole faible, et les informations sur le type de correspondance sont fusionnées lors du chargement des bibliothèques. Lorsque vous chargez des bibliothèques de manière dynamique après le chargement du fichier exécutable (en d'autres termes, via dlopen
ou System.loadLibrary
), il est possible que le chargeur ne parvienne pas à fusionner les informations sur le type pour les bibliothèques chargées. Dans ce cas, les deux types ne sont pas considérés comme égaux.
Utiliser des bibliothèques prédéfinies non concordantes
L'utilisation de bibliothèques prédéfinies (généralement des bibliothèques tierces) dans votre application demande un peu plus d'attention. En règle générale, tenez compte des règles suivantes :
Le niveau d'API minimal de l'application généré est le maximum de
minSdkVersion
pour toutes les bibliothèques de l'application.Si votre
minSdkVersion
correspond à 16, mais que vous utilisez une bibliothèque prédéfinie créée avec le niveau 21, le niveau d'API minimal de l'application généré sera 21. Le non-respect de cette condition sera visible au moment de la compilation si la bibliothèque prédéfinie est statique. Toutefois, il est possible qu'il n'apparaisse qu'au moment de l'exécution des bibliothèques partagées prédéfinies.Toutes les bibliothèques doivent être générées avec la même version de NDK.
Cette règle est un peu plus flexible que la plupart des cas de figure, car les défaillances sont rares. Cependant, la compatibilité entre les bibliothèques créées avec différentes versions majeures du NDK n'est pas garantie. L'ABI C++ n'est pas stable et a changé par le passé.
Les applications avec plusieurs bibliothèques partagées doivent utiliser une bibliothèque STL partagée.
Comme pour les STL non concordantes, les problèmes causés par cette approche peuvent être évités en prenant le plus grand soin, mais il est préférable de ne prendre aucun risque. Pour ce faire, évitez d'avoir plusieurs bibliothèques partagées dans votre application.