Der NDK unterstützt mehrere C++-Laufzeitbibliotheken. In diesem Dokument finden Sie Informationen zu diesen Bibliotheken, den damit verbundenen Nachteilen und ihrer Verwendung.
C++-Laufzeitbibliotheken
Tabelle 1 Laufzeiten und Features von NDK C++.
Name | Funktionen |
---|---|
libc++ | Moderne C++-Unterstützung. |
system | new und delete . (In r18 verworfen.) |
Keine | Keine Header, eingeschränkt in C++. |
libc++ ist sowohl als statische als auch als gemeinsam genutzte Bibliothek verfügbar.
libc++
libc++ von LLVM ist die C++-Standardbibliothek, die seit Lollipop vom Android-Betriebssystem verwendet wird. Seit NDK r18 ist sie die einzige STL-Bibliothek, die im NDK verfügbar ist.
CMake verwendet standardmäßig die Version von C++ Clang, die standardmäßig verwendet wird (derzeit C++14). Legen Sie daher den standardmäßigen CMAKE_CXX_STANDARD
in der Datei CMakeLists.txt
auf den entsprechenden Wert fest, um Funktionen in C++17 oder höher verwenden zu können. Weitere Informationen finden Sie in der CMake-Dokumentation zu CMAKE_CXX_STANDARD
.
„ndk-build“ lässt die Entscheidung standardmäßig auch „clang“. Nutzer von „ndk-build“ sollten also APP_CPPFLAGS
verwenden, um -std=c++17
oder einen beliebigen anderen Wert hinzuzufügen.
Die gemeinsam genutzte Bibliothek für libc++ ist libc++_shared.so
und die statische Bibliothek libc++_static.a
. In der Regel übernimmt und verpackt das Build-System diese Bibliotheken nach Bedarf für den Nutzer. Informationen zu ungewöhnlichen Fällen oder zur Implementierung Ihres eigenen Build-Systems finden Sie im Handbuch für Build-Systemadministratoren oder im Leitfaden zur Verwendung anderer Build-Systeme.
Das LLVM-Projekt unterliegt der Apache-Lizenz v2.0 mit LLVM-Ausnahmen. Weitere Informationen findest du in der Lizenzdatei.
Infotainmentsystem
Die Systemlaufzeit bezieht sich auf /system/lib/libstdc++.so
. Diese Bibliothek ist nicht mit dem voll funktionsfähigen libstdc++ von GNU zu verwechseln. Unter Android ist libstdc++ nur new
und delete
. Verwenden Sie libc++, um eine voll funktionsfähige C++-Standardbibliothek zu erhalten.
Die C++-Systemlaufzeit unterstützt die grundlegende C++-Laufzeit ABI.
Im Wesentlichen stellt diese Bibliothek new
und delete
bereit. Im Gegensatz zu den anderen im NDK verfügbaren Optionen werden die Ausnahmebehandlung oder RTTI nicht unterstützt.
Abgesehen von den C++-Wrappern für die C-Bibliotheksheader wie <cstdio>
wird keine Standardbibliothek unterstützt. Für STL-Dateien sollten Sie eine der anderen Optionen auf dieser Seite verwenden.
Keine
Es ist auch möglich, keine STL festzulegen. Es gibt in diesem Fall keine Verknüpfungs- oder Lizenzierungsanforderungen. Es sind keine C++-Standardheader verfügbar.
C++-Laufzeit auswählen
CMake
Der Standardwert für CMake ist c++_static
.
Sie können c++_shared
, c++_static
, none
oder system
mithilfe der Variable ANDROID_STL
in der Datei build.gradle
auf Modulebene angeben. Weitere Informationen finden Sie in der Dokumentation zu ANDROID_STL in CMake.
NDK-Build
Der Standardwert für „ndk-build“ ist none
.
Sie können c++_shared
, c++_static
, none
oder system
mithilfe der Variable APP_STL
in der Datei Application.mk angeben. Beispiele:
APP_STL := c++_shared
Mit „ndk-build“ können Sie nur eine Laufzeit für Ihre Anwendung auswählen, dies ist nur in Application.mk möglich.
Umgangssprache verwenden
Wenn Sie Clang direkt in Ihrem eigenen Build-System verwenden, verwendet clang++ standardmäßig c++_shared
. Wenn Sie die statische Variante verwenden möchten, fügen Sie den Verknüpfungs-Flags -static-libstdc++
hinzu. Obwohl die Option aus historischen Gründen den Namen "libstdc++" verwendet, gilt dies auch für libc++.
Wichtige Hinweise
Statische Laufzeiten
Wenn sich der gesamte native Code Ihrer Anwendung in einer einzigen gemeinsam genutzten Bibliothek befindet, empfehlen wir die Verwendung der statischen Laufzeit. Auf diese Weise kann die Verknüpfung so viel nicht verwendeten Code wie möglich einbetten und bereinigen, was zu einer optimierten und kleinstmöglichen Anwendung führt. Außerdem werden PackageManager- und Dynamic Linker-Fehler in alten Android-Versionen vermieden, die die Verarbeitung mehrerer gemeinsam genutzter Bibliotheken erschweren und zu Fehlern führen.
In C++ ist es jedoch nicht sicher, mehr als eine Kopie derselben Funktion oder desselben Objekts in einem einzigen Programm zu definieren. Dies ist ein Aspekt der One Definition Rule (One-Definition-Regel), die im C++-Standard vorhanden ist.
Wenn Sie eine statische Laufzeit (und im Allgemeinen statische Bibliotheken) verwenden, kann es leicht passieren, dass diese Regel versehentlich außer Kraft gesetzt wird. Die folgende Anwendung verstößt beispielsweise gegen diese Regel:
# Application.mk
APP_STL := c++_static
# Android.mk
include $(CLEAR_VARS)
LOCAL_MODULE := foo
LOCAL_SRC_FILES := foo.cpp
include $(BUILD_SHARED_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := bar
LOCAL_SRC_FILES := bar.cpp
LOCAL_SHARED_LIBRARIES := foo
include $(BUILD_SHARED_LIBRARY)
In diesem Fall ist der STL einschließlich der globalen Daten und statischen Konstruktoren in beiden Bibliotheken vorhanden. Das Laufzeitverhalten dieser Anwendung ist nicht definiert und in der Praxis kommt es sehr häufig zu Abstürzen. Andere mögliche Probleme sind:
- Arbeitsspeicher, der in einer Bibliothek zugewiesen und in der anderen freigegeben wird, wodurch Speicherlecks oder Heap-Beschädigungen verursacht werden.
- In
libfoo.so
ausgelöste Ausnahmen werden inlibbar.so
nicht erfasst, wodurch Ihre App abstürzt. - Die Zwischenspeicherung von
std::cout
funktioniert nicht richtig.
Abgesehen von den Verhaltensproblemen wird durch die Verknüpfung der statischen Laufzeit mit mehreren Bibliotheken der Code in jeder gemeinsam genutzten Bibliothek dupliziert, was die Größe Ihrer Anwendung erhöht.
Im Allgemeinen können Sie eine statische Variante der C++-Laufzeit nur verwenden, wenn Ihre Anwendung nur eine einzige gemeinsam genutzte Bibliothek enthält.
Gemeinsame Laufzeiten
Wenn Ihre Anwendung mehrere gemeinsam genutzte Bibliotheken enthält, sollten Sie libc++_shared.so
verwenden.
Unter Android ist die vom NDK verwendete libc++ nicht identisch mit der im Betriebssystem. Damit haben NDK-Nutzer auch dann Zugriff auf die neuesten libc++-Funktionen und Fehlerkorrekturen, wenn sie auf ältere Android-Versionen ausgerichtet sind. Der Nachteil: Wenn Sie libc++_shared.so
verwenden, müssen Sie es in Ihre App einbinden. Wenn Sie Ihre Anwendung mit Gradle erstellen, erfolgt dies automatisch.
Ältere Android-Versionen enthielten Fehler im PackageManager und in der dynamischen Verknüpfung, die dazu führten, dass die Installation, Aktualisierung und das Laden nativer Bibliotheken unzuverlässig waren. Wenn Ihre App auf eine ältere Android-Version als Android 4.3 (Android API-Level 18) ausgerichtet ist und Sie libc++_shared.so
verwenden, müssen Sie die gemeinsam genutzte Bibliothek vor jeder anderen abhängigen Bibliothek laden.
Das Projekt ReLinker bietet Behelfslösungen für alle bekannten Probleme beim Laden nativer Bibliotheken und ist normalerweise eine bessere Wahl, als eigene Problemumgehungen zu entwickeln.
Eine STL pro App
In der Vergangenheit hat der NDK neben libc++ auch GNU libstdc++ und STLport unterstützt. Wenn Ihre Anwendung von vordefinierten Bibliotheken abhängig ist, die auf einem anderen NDK als der zum Erstellen der Anwendung verwendeten NDK erstellt wurden, müssen Sie dafür sorgen, dass dies auf kompatible Weise erfolgt.
Eine Anwendung sollte nicht mehr als eine C++-Laufzeit verwenden. Die verschiedenen STLs sind nicht miteinander kompatibel. Beispielsweise unterscheidet sich das Layout von std::string
in libc++ mit dem in gnustl. Code, der für einen STL geschrieben wird, kann keine Objekte verwenden, die gegen eine andere STL geschrieben wurden. Dies ist nur ein Beispiel.
Es gibt zahlreiche Inkompatibilitäten.
Diese Regel geht über Ihren Code hinaus. Alle Abhängigkeiten müssen denselben STL verwenden, den Sie ausgewählt haben. Wenn Sie auf eine Closed-Source-Drittanbieterabhängigkeit angewiesen sind, die den STL verwendet und keine Bibliothek pro STL bereitstellt, haben Sie keine Auswahlmöglichkeit für STL. Sie müssen denselben STL-Prozess wie Ihre Abhängigkeit verwenden.
Es ist möglich, dass Sie von zwei gegenseitig inkompatiblen Bibliotheken abhängig sind. In diesem Fall besteht die einzige Lösung darin, eine der Abhängigkeiten zu löschen oder den Maintainer zu bitten, eine Bibliothek bereitzustellen, die mit dem anderen STL erstellt wurde.
C++-Ausnahmen
C++-Ausnahmen werden von libc++ unterstützt, sind aber in ndk-build standardmäßig deaktiviert. Das liegt daran, dass C++-Ausnahmen in der Vergangenheit im NDK nicht verfügbar waren. Bei CMake- und eigenständigen Toolchains sind C++-Ausnahmen standardmäßig aktiviert.
Wenn Sie Ausnahmen für Ihre gesamte Anwendung in „ndk-build“ aktivieren möchten, fügen Sie der Datei Application.mk die folgende Zeile hinzu:
APP_CPPFLAGS := -fexceptions
Um Ausnahmen für ein einzelnes ndk-build-Modul zu aktivieren, fügen Sie dem jeweiligen Modul in seiner Android.mk die folgende Zeile hinzu:
LOCAL_CPP_FEATURES := exceptions
Alternativ können Sie auch Folgendes verwenden:
LOCAL_CPPFLAGS := -fexceptions
RTT
Wie in Ausnahmefällen wird RTTI von libc++ unterstützt, ist aber in ndk-build standardmäßig deaktiviert. Bei CMake- und eigenständigen Toolchains ist RTTI standardmäßig aktiviert.
Um RTTI für Ihre gesamte Anwendung in ndk-build zu aktivieren, fügen Sie der Datei Application.mk die folgende Zeile hinzu:
APP_CPPFLAGS := -frtti
Um RTTI für ein einzelnes ndk-build-Modul zu aktivieren, fügen Sie dem jeweiligen Modul in Android.mk die folgende Zeile hinzu:
LOCAL_CPP_FEATURES := rtti
Alternativ können Sie auch Folgendes verwenden:
LOCAL_CPPFLAGS := -frtti