NDK supporta più librerie di runtime C++. Questo documento fornisce informazioni su queste librerie, sui compromessi necessari e su come utilizzarle.
Librerie di runtime C++
Tabella 1. Runtime e funzionalità di NDK C++.
Nome | Funzionalità |
---|---|
libc++ | Supporto moderno di C++. |
Pixel | new e delete . (deprecato nella versione r18.) |
nessuno | Nessuna intestazione, C++ limitato. |
libc++ è disponibile sia come libreria statica che come libreria condivisa.
libc++
libc++ di LLVM è lo standard C++ utilizzata dal sistema operativo Android da Lollipop e a partire da NDK r18 è l'unico STL disponibile nell'NDK.
CMake esegue l'impostazione predefinita di qualsiasi versione del clang C++ (attualmente C++14),
quindi devi impostare il valore standard per CMAKE_CXX_STANDARD
nel file CMakeLists.txt
per utilizzare le funzionalità di C++17 o versioni successive. Visualizza CMake
documentazione per CMAKE_CXX_STANDARD
per ulteriori informazioni.
ndk-build lascia inoltre la decisione di usare clang per impostazione predefinita, quindi gli utenti di ndk-build
dovrebbero utilizzare APP_CPPFLAGS
per aggiungere -std=c++17
o qualsiasi altro metodo.
La libreria condivisa per libc++ è libc++_shared.so
e il file statico
libreria è libc++_static.a
. Nei casi tipici, il sistema di compilazione
utilizzando e pacchettizzando queste librerie in base alle esigenze dell'utente. Per casi atipici
o quando implementi il tuo sistema di compilazione, consulta la sezione Build System Retainer
Guida o la guida per l'utilizzo di altri sistemi di build.
Il progetto LLVM è coperto dalla licenza Apache v2.0 con eccezioni LLVM. Per ulteriori informazioni informazioni, consulta il file di licenza.
di infotainment
Il runtime del sistema si riferisce a /system/lib/libstdc++.so
. Questa libreria non deve
potrebbe essere confusa con la libstdc++, dotata di tutte le funzioni, di GNU. Su Android, libstdc++ è solo
new
e delete
. Utilizza libc++ per una libreria standard C++ completa.
Il runtime C++ del sistema fornisce supporto per l'ABI del runtime C++ di base.
Essenzialmente, questa libreria fornisce new
e delete
. A differenza dell'altro
disponibili in NDK, non è previsto alcun supporto per la gestione delle eccezioni
RTTI
Non esiste un supporto standard per la libreria a parte i wrapper C++ per il file
come <cstdio>
. Se vuoi un STL, devi utilizzare uno di
le altre opzioni presentate in questa pagina.
nessuno
È disponibile anche l'opzione per evitare di impostare STL. Non ci sono collegamenti o licenze in questo caso. Non sono disponibili intestazioni standard C++.
Selezione di un runtime C++
Marca
Il valore predefinito per CMake è c++_static
.
Puoi specificare c++_shared
, c++_static
, none
o system
utilizzando il
ANDROID_STL
nel file build.gradle
a livello di modulo. Per saperne di più,
consulta la documentazione per ANDROID_STL in
CMake.
build-ndk
Il valore predefinito per ndk-build è none
.
Puoi specificare c++_shared
, c++_static
, none
o system
utilizzando il
APP_STL
nel file Application.mk. Ad esempio:
APP_STL := c++_shared
ndk-build ti consente di selezionare un solo runtime per la tua app e può farlo solo Application.mk.
Usa direttamente clang
Se utilizzi clang direttamente nel tuo sistema di compilazione, clang++ utilizzerà
c++_shared
per impostazione predefinita. Per utilizzare la variante statica, aggiungi -static-libstdc++
a
dalle segnalazioni del linker. Tieni presente che, sebbene l'opzione utilizzi il nome "libstdc++" della
motivi storici, questo è corretto anche per libc++.
Considerazioni importanti
Runtime statici
Se tutto il codice nativo della tua applicazione è contenuto in un unico ambiente , consigliamo di utilizzare il runtime statico. In questo modo il linker in linea e svuotare il più possibile il codice inutilizzato, ottenendo e la più piccola applicazione possibile. Evita inoltre PackageManager e Dynamic bug linker nelle vecchie versioni di Android che rendono la gestione di più librerie difficili e soggette a errori.
Detto questo, in C++ non è sicuro definire più di una copia dello stesso una funzione o un oggetto in un singolo programma. Questo è un aspetto della Una regola di definizione presente nello standard C++.
Quando utilizzi un runtime statico (e in generale le librerie statiche), è facile per involontariamente questa regola. Ad esempio, la seguente applicazione interrompe questo regola:
# 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 questa situazione, l'STL, inclusi i dati globali e i costruttori statici, saranno presenti in entrambe le librerie. Il comportamento di runtime di questa applicazione è indefinita e, nella pratica, gli arresti anomali sono molto comuni. Altri possibili problemi include:
- Memoria allocata in una libreria e liberata nell'altra, causando memoria o il danneggiamento dell'heap.
- Le eccezioni sollevate in
libfoo.so
non vengono rilevate inlibbar.so
, causando il quale la tua l'arresto anomalo dell'app. - Il buffering di
std::cout
non funziona correttamente.
Oltre ai problemi comportamentali coinvolti, il collegamento del runtime statico in più librerie duplica il codice in ogni libreria condivisa, aumentando la dimensione la tua applicazione.
In generale, puoi utilizzare una variante statica del runtime C++ solo se ne hai una e una sola libreria condivisa nella tua applicazione.
Runtime condivisi
Se la tua applicazione include più librerie condivise, devi usare
libc++_shared.so
.
Su Android, il valore libc++ utilizzato dall'NDK non corrisponde a quello che fa parte
del sistema operativo. In questo modo gli utenti di NDK possono accedere alle funzionalità e ai bug più recenti di libc++
correzioni anche per il targeting di versioni precedenti di Android. Lo svantaggio è che se
usare libc++_shared.so
, devi includerlo nella tua app. Se stai creando il tuo
dell'applicazione con Gradle viene gestita automaticamente.
Le vecchie versioni di Android presentavano bug in PackageManager e nel Linker dinamico
che ha causato l'installazione, l'aggiornamento e il caricamento delle librerie native
inaffidabili. In particolare, se la tua app ha come target una versione di Android precedente
rispetto ad Android 4.3 (livello API Android 18) e utilizzi libc++_shared.so
,
Deve caricare la libreria condivisa prima di qualsiasi altra libreria che ne dipende.
Il progetto ReLinker offre soluzioni alternative per tutti i problemi di caricamento delle librerie native note e di solito è è una scelta migliore che scrivere personalmente le soluzioni alternative.
Un STL per app
Storicamente, l'NDK supportava GNU libstdc++ e STLport oltre a libc++. Se la tua applicazione dipende da librerie predefinite create sulla base di un NDK diversa da quella usata per creare l'applicazione, dovrai assicurarti in modo compatibile.
Un'applicazione non deve utilizzare più di un runtime C++. I vari STL sono
non compatibili tra loro. Ad esempio, il layout di std::string
in libc++ non è come in gnustl. Il codice scritto in base a un STL
non sarà in grado di utilizzare oggetti scritti su un altro. Questo è solo un esempio.
le incompatibilità sono numerose.
Questa regola va oltre il tuo codice. Tutte le dipendenze devono usare lo stesso STL selezionato. Se dipendi da una terza parte chiusa che utilizza l'STL e non fornisce una libreria per ogni STL, non puoi scegliere il formato STL. Devi utilizzare lo stesso STL della dipendenza.
È possibile che dipenderai da due librerie reciprocamente incompatibili. Nella questa situazione le uniche soluzioni sono quella di abbandonare una delle dipendenze o chiedere per fornire una libreria basata sull'altro STL.
Eccezioni C++
Le eccezioni C++ sono supportate da libc++, ma sono disabilitate per impostazione predefinita in ndk-build. Questo accade perché storicamente le eccezioni C++ non erano disponibili nella NDK CMake e toolchain autonome hanno le eccezioni C++ abilitate per impostazione predefinita.
Per abilitare le eccezioni per l'intera applicazione in ndk-build, aggiungi il metodo seguente riga al tuo file Application.mk:
APP_CPPFLAGS := -fexceptions
Per abilitare le eccezioni per un singolo modulo ndk-build, aggiungi la riga seguente a il modulo specificato nel relativo file Android.mk:
LOCAL_CPP_FEATURES := exceptions
In alternativa, puoi utilizzare:
LOCAL_CPPFLAGS := -fexceptions
RTTI
Come con le eccezioni, RTTI è supportato da libc++, ma è disabilitato per impostazione predefinita in ndk-build. CMake e toolchain autonome hanno RTTI abilitato per impostazione predefinita.
Per abilitare RTTI nell'intera applicazione in ndk-build, aggiungi quanto segue al file Application.mk:
APP_CPPFLAGS := -frtti
Per abilitare RTTI per un singolo modulo ndk-build, aggiungi la seguente riga al un determinato modulo nel relativo file Android.mk:
LOCAL_CPP_FEATURES := rtti
In alternativa, puoi utilizzare:
LOCAL_CPPFLAGS := -frtti