Häufige Probleme und Lösungen

Dieses Dokument enthält eine unvollständige Liste der am häufigsten auftretenden Nichtfehler, die bei der Verwendung des NDK auftreten können, und deren Lösungen (falls verfügbar).

_FILE_OFFSET_BITS=64 mit älteren API-Levels verwenden

Vor einheitlichen Headern unterstützte die NDK kein _FILE_OFFSET_BITS=64. Wenn Sie ihn beim Erstellen der App definiert haben, wurde er ignoriert. Die Option _FILE_OFFSET_BITS=64 wird jetzt mit einheitlichen Headern unterstützt. In älteren Android-Versionen waren jedoch nur wenige der off_t APIs als off64_t-Variante verfügbar. Wenn Sie diese Funktion mit alten API-Ebenen verwenden, sind daher weniger Funktionen verfügbar.

Dieses Problem wird im r16-Blogpost und in der Bionic-Dokumentation ausführlich erläutert.

Problem: Ihr Build fordert APIs an, die in Ihrer minSdkVersion nicht vorhanden sind.

Lösung: Deaktivieren Sie _FILE_OFFSET_BITS=64 oder erhöhen Sie minSdkVersion.

Nicht deklarierte oder implizite Definition von mmap

In C++ kann der folgende Fehler auftreten:

Fehler: Verwendung der nicht deklarierten ID „mmap“

oder den folgenden Fehler in C:

Warnung: Implizite Deklaration der Funktion 'mmap' ist in C99 ungültig.

Mit _FILE_OFFSET_BITS=64 wird die C-Bibliothek angewiesen, mmap64 anstelle von mmap zu verwenden. mmap64 war erst am android-21 verfügbar. Wenn der Wert für minSdkVersion kleiner als 21 ist, enthält die C-Bibliothek kein mit _FILE_OFFSET_BITS=64 kompatibles mmap. Die Funktion ist also nicht verfügbar.

minSdkVersion ist höher als das API-Level des Geräts festgelegt

Das API-Level, für das Sie mit dem NDK erstellen, hat eine ganz andere Bedeutung als compileSdkVersion für Java. Das NDK API-Level ist das mindestens unterstützte API-Level Ihrer App. In „ndk-build“ ist dies Ihre APP_PLATFORM-Einstellung. Bei CMake ist dies -DANDROID_PLATFORM.

Da Verweise auf Funktionen in der Regel beim Laden von Bibliotheken und nicht beim ersten Aufruf aufgelöst werden, können Sie nicht auf APIs verweisen, die nicht immer vorhanden sind, und ihre Verwendung durch API-Prüfungen schützen. Wenn überhaupt, auf die sie verwiesen wird, müssen sie vorhanden sein.

Problem: Dein NDK API-Level ist höher als die von deinem Gerät unterstützte API.

Lösung: Lege als NDK API-Level (APP_PLATFORM) die Mindestversion von Android fest, die von deiner App unterstützt wird.

System entwickeln Einstellung
ndk-build APP_PLATFORM
CMake ANDROID_PLATFORM
externalNativeBuild android.minSdkVersion

Informationen zu anderen Build-Systemen finden Sie unter NDK mit anderen Build-Systemen verwenden.

__aeabi-Symbole können nicht gefunden werden

Die folgende Nachricht:

UnzufriedenerLinkError: dlopen fehlgeschlagen: Symbol "__aeabi_memcpy" kann nicht gefunden werden

ist ein Beispiel für mögliche runtime-Fehler. Diese Fehler werden im Log angezeigt, wenn Sie versuchen, Ihre nativen Bibliotheken zu laden. Das Symbol kann __aeabi_* sein; __aeabi_memcpy und __aeabi_memclr kommen am häufigsten vor.

Dieses Problem ist in Problem 126 dokumentiert.

Symbol rand kann nicht gefunden werden

Für die folgende Fehlerprotokollmeldung:

UnzufriedenerLinkError: dlopen fehlgeschlagen: Symbol "rand" kann nicht gefunden werden

Hier finden Sie eine ausführliche Stack Overflow-Antwort.

Nicht definierter Verweis auf __atomic_*

Problem: Einige ABIs benötigen libatomic, um einige Implementierungen für atomare Vorgänge bereitzustellen.

Lösung: Fügen Sie beim Verknüpfen -latomic hinzu.

Die folgende Fehlermeldung wird angezeigt:

Fehler: nicht definierter Verweis auf '__atomic_exchange_4'

Das eigentliche Symbol kann hier jedoch etwas mit dem Präfix __atomic_ sein.

RTTI/Ausnahmen funktionieren nicht über Bibliotheksgrenzen hinweg

Problem: Ausnahmen werden nicht abgefangen, wenn sie über die Grenzen der gemeinsam genutzten Bibliothek hinaus ausgelöst werden oder dynamic_cast schlägt fehl.

Lösung: Fügen Sie den Typen eine Schlüsselfunktion hinzu. Eine Schlüsselfunktion ist die erste nicht-reine, Out-of-Line-Funktion für einen Typ. Ein Beispiel finden Sie in der Diskussion zu Problem 533.

Das C++ ABI besagt, dass zwei Objekte denselben Typ haben, wenn ihre type_info-Zeiger identisch sind. Ausnahmen können nur dann abgefangen werden, wenn der type_info für den Catch mit der ausgelösten Ausnahme übereinstimmt. Dieselbe Regel gilt für dynamic_cast.

Wenn ein Typ keine Schlüsselfunktion hat, wird sein typeinfo als schwaches Symbol ausgegeben und übereinstimmende Typinformationen werden beim Laden von Bibliotheken zusammengeführt. Wenn Bibliotheken nach dem Laden der ausführbaren Datei dynamisch geladen werden, also über dlopen oder System.loadLibrary, kann es sein, dass das Ladeprogramm die Typinformationen für die geladenen Bibliotheken nicht zusammenführt. In diesem Fall gelten die beiden Typen nicht als gleich.

Nicht übereinstimmende vordefinierte Bibliotheken verwenden

Wenn Sie vordefinierte Bibliotheken – in der Regel Drittanbieterbibliotheken – in Ihrer Anwendung verwenden, ist besondere Sorgfalt erforderlich. Im Allgemeinen sind die folgenden Regeln zu beachten:

  • Das minimale API-Level der resultierenden App ist das Maximum der minSdkVersions aller Bibliotheken der App.

    Wenn minSdkVersion 16 ist, Sie aber eine vordefinierte Bibliothek verwenden, die mit 21 erstellt wurde, ist das Mindest-API-Level der resultierenden App 21. Andernfalls wird sie beim Build angezeigt, wenn die vordefinierte Bibliothek statisch ist. Für vordefinierte gemeinsam genutzte Bibliotheken kann dies jedoch erst bei der Laufzeit angezeigt werden.

  • Alle Bibliotheken sollten mit derselben NDK-Version generiert werden.

    Diese Regel ist etwas flexibler als die meisten anderen, da Ausfälle selten sind. Die Kompatibilität zwischen Bibliotheken, die mit verschiedenen Hauptversionen des NDK erstellt wurden, ist jedoch nicht garantiert. Das C++ ABI ist nicht stabil und hat sich in der Vergangenheit geändert.

  • Anwendungen mit mehreren gemeinsam genutzten Bibliotheken müssen eine gemeinsam genutzte STL verwenden.

    Wie bei nicht übereinstimmenden STLs können die dadurch verursachten Probleme vermieden werden, wenn man viel Vorsicht walten lässt. Es ist jedoch besser, das Problem einfach zu vermeiden. Dieses Problem lässt sich am besten vermeiden, wenn Sie in Ihrer App nicht mehrere gemeinsam genutzte Bibliotheken verwenden.