Supporto della libreria C++

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 in libbar.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