Problemi comuni e soluzioni

Questo documento è un elenco parziale dei non bug più comunemente riscontrati durante l'utilizzo dell'NDK e delle relative soluzioni (se disponibili).

Utilizzo di _FILE_OFFSET_BITS=64 con livelli API precedenti

Prima delle intestazioni unificate, l'NDK non supportava il formato _FILE_OFFSET_BITS=64. Se lo hai definito durante la creazione dell'app, è stato ignorato automaticamente. L'opzione _FILE_OFFSET_BITS=64 è ora supportata con intestazioni unificate, ma nelle vecchie versioni di Android erano disponibili poche API off_t come variante off64_t. Pertanto, l'utilizzo di questa funzionalità con livelli API precedenti comporta un minor numero di funzioni disponibili.

Questo problema è spiegato in dettaglio nel post del blog r16 e nella documentazione bionica.

Problema: la tua build richiede API che non esistono in minSdkVersion.

Soluzione: disattiva _FILE_OFFSET_BITS=64 o aumenta minSdkVersion.

Definizione implicita o non dichiarata di mmap

In C++ potresti visualizzare il seguente errore:

errore: utilizzo dell'identificatore non dichiarato "mmap"

o il seguente errore in C:

avviso: la dichiarazione implicita della funzione "mmap" non è valida in C99

L'uso di _FILE_OFFSET_BITS=64 indica alla libreria C di utilizzare mmap64 anziché mmap. mmap64 non era disponibile fino al giorno android-21. Se il valore minSdkVersion è inferiore a 21, la libreria C non contiene un valore mmap compatibile con _FILE_OFFSET_BITS=64, pertanto la funzione non è disponibile.

Valore minSdkVersion impostato su un livello superiore a quello API del dispositivo

Il livello API su cui crei con l'NDK ha un significato molto diverso rispetto a compileSdkVersion per Java. Il livello API NDK è il livello API minimo supportato della tua app. In ndk-build, questa è l'impostazione di APP_PLATFORM. Con CMake, è -DANDROID_PLATFORM.

Poiché i riferimenti alle funzioni in genere vengono risolti quando le librerie vengono caricate, anziché quando vengono chiamate la prima volta, non è possibile fare riferimento alle API che non sono sempre presenti e ne proteggono l'utilizzo con i controlli a livello di API. Se vi si fa riferimento, devono essere presenti.

Problema: il livello dell'API NDK è superiore all'API supportata dal tuo dispositivo.

Soluzione: imposta il livello API NDK (APP_PLATFORM) sulla versione minima di Android supportata dalla tua app.

Sistema di build Impostazione
build-ndk APP_PLATFORM
CMake ANDROID_PLATFORM
externalNativeBuild android.minSdkVersion

Per altri sistemi di build, consulta l'articolo su come utilizzare l'NDK con altri sistemi di build.

Impossibile individuare i simboli __aeabi

Il seguente messaggio:

UnSoddisfattoLinkError: dlopen non riuscito: impossibile individuare il simbolo "__aeabi_memcpy"

è un esempio di possibili errori di runtime. Questi errori vengono visualizzati nel log quando provi a caricare le librerie native. Il simbolo potrebbe essere uno tra __aeabi_*; __aeabi_memcpy e __aeabi_memclr sembrano essere i più comuni.

Questo problema è documentato nel Problema 126

Impossibile individuare il simbolo rand

Per il seguente messaggio del log di errore:

UnSoddisfattoLinkError: dlopen non riuscito: impossibile individuare il simbolo "rand"

Consulta questa risposta dettagliata di Stack Overflow.

Riferimento a __atomic_* non definito

Problema: alcune ABI hanno bisogno di libatomic per fornire alcune implementazioni per le operazioni atomiche.

Soluzione: aggiungi -latomic durante il collegamento.

Per il seguente messaggio di errore:

errore: riferimento non definito a "__atomic_exchange_4"

il simbolo effettivo qui potrebbe essere qualsiasi cosa con prefisso __atomic_.

RTTI/eccezioni non oltre i confini della biblioteca

Problema: le eccezioni non vengono rilevate quando vengono lanciate oltre i confini della libreria condivisa oppure quando dynamic_cast presenta un errore.

Soluzione: aggiungi una funzione chiave ai tipi. Una funzione chiave è la prima funzione virtuale fuori linea non pura di un tipo. Per un esempio, vedi la discussione sul Problema 533.

L'ABI C++ indica che due oggetti hanno lo stesso tipo se e solo se i puntatori type_info sono identici. Le eccezioni possono essere rilevate solo se il type_info per l'individuazione corrisponde all'eccezione generata. La stessa regola si applica per dynamic_cast.

Quando un tipo non ha una funzione chiave, il relativo typeinfo viene emesso come simbolo debole e le informazioni sul tipo corrispondente vengono unite quando vengono caricate le librerie. Quando si caricano le librerie in modo dinamico dopo che l'eseguibile è stato caricato (in altre parole, tramite dlopen o System.loadLibrary), il caricatore potrebbe non riuscire a unire le informazioni sul tipo per le librerie caricate. In questi casi, i due tipi non sono considerati uguali.

Utilizzo di librerie predefinite che non corrispondono

L'utilizzo di librerie predefinite (in genere librerie di terze parti) nell'applicazione richiede un po' di attenzione in più. In generale, tieni presente le seguenti regole:

  • Il livello API minimo dell'app risultante è il numero massimo di minSdkVersion tra tutte le librerie dell'app.

    Se minSdkVersion è 16, ma utilizzi una libreria predefinita basata su 21, il livello API minimo dell'app risultante è 21. La mancata osservanza di questo requisito sarà visibile al momento della creazione se la libreria predefinita è statica, ma potrebbe non essere visualizzata fino al momento dell'esecuzione per le librerie condivise predefinite.

  • Tutte le librerie devono essere generate con la stessa versione NDK.

    Questa regola è un po' più flessibile della maggior parte degli altri poiché le interruzioni sono rare, ma la compatibilità tra le librerie create con versioni principali diverse dell'NDK non è garantita. L'ABI C++ non è stabile ed è cambiata in passato.

  • Le app con più librerie condivise devono utilizzare un tipo STL condiviso.

    Come per gli STL non corrispondenti, i problemi causati da questa situazione possono essere evitati se si presta molta attenzione, ma è sempre meglio evitare il problema. Il modo migliore per evitare questo problema è evitare di avere più librerie condivise nella tua app.