Häufige Probleme und Lösungen

In diesem Dokument finden Sie eine Teilliste der häufigsten Probleme, die keine Fehler sind und beim Verwenden des NDK auftreten können, sowie die entsprechenden Lösungen (falls verfügbar).

_FILE_OFFSET_BITS=64 mit älteren API-Levels verwenden

Vor der Einführung einheitlicher Header unterstützte das NDK _FILE_OFFSET_BITS=64 nicht. Wenn Sie es beim Erstellen Ihrer App definiert haben, wurde es stillschweigend ignoriert. Die Option _FILE_OFFSET_BITS=64 wird jetzt mit einheitlichen Headern unterstützt. Bei alten Android-Versionen waren jedoch nur sehr wenige der off_t-APIs als off64_t-Variante verfügbar. Daher stehen bei Verwendung dieses Features mit alten API-Levels weniger Funktionen zur Verfügung.

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

Problem: Bei Ihrem Build werden APIs angefordert, die in Ihrem minSdkVersion nicht vorhanden sind.

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

Nicht deklarierte oder implizite Definition von mmap

In C++ wird möglicherweise der folgende Fehler angezeigt:

error: use of undeclared identifier 'mmap'

oder der folgende Fehler in C:

warning: implicit declaration of function 'mmap' is invalid in C99

Wenn Sie _FILE_OFFSET_BITS=64 verwenden, wird die C-Bibliothek angewiesen, mmap64 anstelle von mmap zu verwenden. mmap64 war erst ab android-21 verfügbar. Wenn Ihr minSdkVersion-Wert niedriger als 21 ist, enthält die C-Bibliothek kein mmap, das mit _FILE_OFFSET_BITS=64 kompatibel ist. Die Funktion ist daher nicht verfügbar.

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

Das API-Level, für das Sie mit dem NDK entwickeln, hat eine ganz andere Bedeutung als compileSdkVersion für Java. Das NDK-API-Level ist das Mindest-API-Level Ihrer App. In ndk-build ist dies die Einstellung APP_PLATFORM. Mit CMake ist dies -DANDROID_PLATFORM.

Da Verweise auf Funktionen in der Regel aufgelöst werden, wenn Bibliotheken geladen werden, und nicht, wenn sie zum ersten Mal aufgerufen werden, können Sie nicht auf APIs verweisen, die nicht immer vorhanden sind, und ihre Verwendung mit API-Level-Prüfungen schützen. Wenn auf sie verwiesen wird, müssen sie vorhanden sein.

Problem: Ihr NDK-API-Level ist höher als das API, das von Ihrem Gerät unterstützt wird.

Lösung: Legen Sie das NDK-API-Level (APP_PLATFORM) auf die Mindestversion von Android fest, die von Ihrer App unterstützt wird.

Build-System 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 Meldung:

UnsatisfiedLinkError: dlopen failed: cannot locate symbol "__aeabi_memcpy"

ist ein Beispiel für mögliche Laufzeitfehler. Diese Fehler werden im Log angezeigt, wenn Sie versuchen, Ihre nativen Bibliotheken zu laden. Das Symbol kann eines der folgenden sein: __aeabi_*; __aeabi_memcpy und __aeabi_memclr sind die häufigsten.

Dieses Problem ist in Problem 126 dokumentiert.

Symbol rand kann nicht gefunden werden

Bei der folgenden Fehlermeldung im Log:

UnsatisfiedLinkError: dlopen failed: cannot locate symbol "rand"

finden Sie hier eine detaillierte Stack Overflow Antwort.

Nicht definierter Verweis auf __atomic_*

Problem: Für einige ABIs ist libatomic erforderlich, um einige Implementierungen für atomare Vorgänge bereitzustellen.

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

Bei der folgenden Fehlermeldung:

error: undefined reference to '__atomic_exchange_4'

kann das tatsächliche Symbol hier alles sein, was mit __atomic_ beginnt.

RTTI/Ausnahmen funktionieren nicht über Bibliotheksgrenzen hinweg

Problem: Ausnahmen werden nicht abgefangen, wenn sie über die Grenzen gemeinsam genutzter Bibliotheken hinweg ausgelöst werden, oder dynamic_cast schlägt fehl.

Lösung: Fügen Sie Ihren Typen eine Schlüsselfunktion hinzu. Eine Schlüsselfunktion ist die erste nicht rein virtuelle Funktion eines Typs, die nicht inline ist. Ein Beispiel finden Sie in der Diskussion zu Problem 533.

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

Wenn ein Typ keine Schlüsselfunktion hat, wird seine typeinfo als schwaches Symbol ausgegeben und übereinstimmende Typinformationen werden beim Laden der Bibliotheken zusammengeführt. Wenn Bibliotheken dynamisch geladen werden, nachdem die ausführbare Datei geladen wurde (d. h. über dlopen oder System.loadLibrary), ist es möglicherweise nicht möglich, Typinformationen für die geladenen Bibliotheken zusammenzuführen. In diesem Fall werden die beiden Typen nicht als gleich betrachtet.

Nicht übereinstimmende vorkompilierte Bibliotheken verwenden

Die Verwendung vorkompilierter Bibliotheken (in der Regel Bibliotheken von Drittanbietern) in Ihrer Anwendung erfordert etwas mehr Sorgfalt. Beachten Sie im Allgemeinen die folgenden Regeln:

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

    Wenn Ihr minSdkVersion 16 ist, Sie aber eine vorkompilierte Bibliothek verwenden, die für 21 erstellt wurde, ist das Mindest-API-Level der resultierenden App 21. Wenn Sie sich nicht daran halten, wird dies zur Build-Zeit sichtbar, wenn die vorkompilierte Bibliothek statisch ist. Bei vorkompilierten gemeinsam genutzten Bibliotheken kann es jedoch erst zur Laufzeit auftreten.

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

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

  • Apps 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 Sie sehr sorgfältig vorgehen. Es ist jedoch besser, das Problem einfach zu vermeiden. Die beste Möglichkeit, dieses Problem zu vermeiden, besteht darin, keine mehreren gemeinsam genutzten Bibliotheken in Ihrer App zu verwenden.