Questo documento è un elenco parziale dei problemi più comuni che potresti riscontrare quando utilizzi l'NDK e delle relative soluzioni (se disponibili).
Utilizzare _FILE_OFFSET_BITS=64 con livelli API precedenti
Prima delle intestazioni unificate, l'NDK non supportava _FILE_OFFSET_BITS=64. Se lo hai definito durante la creazione dell'app, è stato ignorato. L'opzione _FILE_OFFSET_BITS=64 è ora supportata con le intestazioni unificate, ma nelle versioni precedenti di Android erano disponibili pochissime API off_t come variante off64_t. Di conseguenza, l'utilizzo di questa funzionalità con i livelli API precedenti comporta la disponibilità di un numero inferiore di funzioni.
Questo problema è spiegato in dettaglio nel post del blog r16 e nella documentazione di Bionic.
Problema: la build richiede API che non esistono in
minSdkVersion.
Soluzione: disattiva _FILE_OFFSET_BITS=64 o aumenta minSdkVersion.
Definizione implicita o non dichiarata di mmap
Potresti visualizzare il seguente errore in C++:
error: use of undeclared identifier 'mmap'
o il seguente errore in C:
warning: implicit declaration of function 'mmap' is invalid in C99
L'utilizzo di _FILE_OFFSET_BITS=64 indica alla libreria C di utilizzare mmap64 anziché
mmap. mmap64 non era disponibile fino ad android-21. Se il valore di minSdkVersion è inferiore a 21, la libreria C non contiene un mmap compatibile con _FILE_OFFSET_BITS=64, quindi la funzione non è disponibile.
minSdkVersion impostato su un valore superiore al livello API del dispositivo
Il livello API su cui esegui la build con l'NDK ha un significato molto diverso da compileSdkVersion per Java. Il livello API dell'NDK è il livello API minimo supportato dall'app. In ndk-build, questa è l'impostazione APP_PLATFORM. Con CMake, è -DANDROID_PLATFORM.
Poiché i riferimenti alle funzioni vengono in genere risolti quando le librerie vengono caricate anziché quando vengono chiamate per la prima volta, non puoi fare riferimento alle API che non sono sempre presenti e proteggere il loro utilizzo con i controlli del livello API. Se vengono chiamate, devono essere presenti.
Problema: il livello API dell'NDK è superiore all'API supportata dal dispositivo.
Soluzione: imposta il livello API dell'NDK (APP_PLATFORM) sulla versione minima
di Android supportata dall'app.
| Sistema di compilazione | Impostazione |
|---|---|
| ndk-build | APP_PLATFORM |
| CMake | ANDROID_PLATFORM |
| externalNativeBuild | android.minSdkVersion |
Per altri sistemi di compilazione, vedi Utilizzare l'NDK con altri sistemi di compilazione.
Impossibile individuare i simboli __aeabi
Il seguente messaggio:
UnsatisfiedLinkError: dlopen failed: cannot locate symbol "
__aeabi_memcpy"
è un esempio di possibili errori di runtime. Questi errori vengono visualizzati nel log quando tenti di caricare le librerie native. Il simbolo può essere uno qualsiasi di __aeabi_*; __aeabi_memcpy e __aeabi_memclr sembrano essere i più comuni.
Questo problema è documentato in Problema 126
Impossibile individuare il simbolo rand
Per il seguente messaggio di log degli errori:
UnsatisfiedLinkError: dlopen failed: cannot locate symbol "
rand"
Consulta questa risposta dettagliata di Stack Overflow answer.
Riferimento non definito a __atomic_*
Problema: alcune ABI richiedono libatomic per fornire alcune implementazioni per
operazioni atomiche.
Soluzione: aggiungi -latomic durante il collegamento.
Per il seguente messaggio di errore:
error: undefined reference to '
__atomic_exchange_4'
Il simbolo effettivo qui potrebbe essere qualsiasi elemento con il prefisso __atomic_.
RTTI/eccezioni non funzionanti tra i limiti delle librerie
Problema: le eccezioni non vengono rilevate quando vengono generate tra i limiti delle librerie condivise
o dynamic_cast non riesce.
Soluzione: aggiungi una funzione chiave ai tuoi tipi. Una funzione chiave è la prima funzione virtuale non pura e out-of-line per un tipo. Per un esempio, consulta la discussione sul problema 533.
L'ABI C++ indica che due oggetti hanno lo stesso tipo se e
solo se i relativi puntatori type_info sono identici. Le eccezioni possono essere rilevate solo se type_info per il catch corrisponde all'eccezione generata. La stessa regola si applica a dynamic_cast.
Quando un tipo non ha una funzione chiave, il relativo typeinfo viene emesso come simbolo debole e le informazioni sul tipo corrispondenti vengono unite quando le librerie vengono caricate. Quando le librerie vengono caricate dinamicamente dopo il caricamento dell'eseguibile (in altre parole, tramite dlopen o System.loadLibrary), potrebbe non essere possibile per il caricatore unire le informazioni sul tipo per le librerie caricate. In questo caso, i due tipi non vengono considerati uguali.
Utilizzare librerie predefinite non corrispondenti
L'utilizzo di librerie predefinite, in genere librerie di terze parti, nella tua applicazione richiede un po' di attenzione in più. In generale, tieni presente le seguenti regole:
Il livello API minimo dell'app risultante è il massimo dei valori
minSdkVersiondi tutte le librerie dell'app.Se
minSdkVersionè 16, ma utilizzi una libreria predefinita creata per 21, il livello API minimo dell'app risultante è 21. Il mancato rispetto di questa regola sarà visibile in fase di tempo di compilazione se la libreria predefinita è statica, ma potrebbe non essere visualizzata fino al runtime per le librerie condivise predefinite.Tutte le librerie devono essere generate con la stessa versione dell'NDK.
Questa regola è un po' più flessibile della maggior parte, 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 una shared STL.
Come per le STL non corrispondenti, i problemi causati da questa situazione possono essere evitati se si presta molta attenzione, ma è meglio evitare il problema. Il modo migliore per evitare questo problema è evitare di avere più librerie condivise nell'app.