Se non utilizzi CMake o ndk-build, ma desideri l'integrazione completa della build del plug-in C/C++ per Android Gradle (AGP) e di Android Studio, puoi creare un sistema di build C/C++ personalizzato creando uno script shell che scriva informazioni sulla build nel formato file di build Ninja.
Ad Android Studio e AGP è stato aggiunto il supporto sperimentale per i sistemi di build C/C++ personalizzati. Questa funzionalità è disponibile a partire da Android Studio Dolphin | 2021.3.1 Canary 4.
Panoramica
Uno schema comune per i progetti C/C++, in particolare quelli che hanno come target più piattaforme, è generare progetti per ciascuna di queste piattaforme da una rappresentazione sottostante.
Un esempio significativo di questo pattern è CMake. CMake può generare progetti per Android, iOS e altre piattaforme da un'unica rappresentazione sottostante, salvata nel file CMakeLists.txt
.
Sebbene CMake sia supportato direttamente da AGP, sono disponibili altri generatori di progetti che non sono direttamente supportati:
Generatori di progetti personalizzati e privati
Questi tipi di generatori di progetti supportano i Ninja come rappresentazione di backend della build C/C++ oppure possono essere adattati per generare Ninja come rappresentazione di backend.
Se configurato correttamente, un progetto AGP con un generatore di sistema integrato per progetti C/C++ consente agli utenti di:
Crea dalla riga di comando e da Android Studio.
Modifica le fonti con il supporto completo dei servizi linguistici (ad esempio, la definizione di riferimento) in Android Studio.
Utilizzare i debugger di Android Studio per eseguire il debug di processi nativi e misti.
Come modificare la build per utilizzare uno script di configurazione della build C/C++ personalizzato
Questa sezione illustra i passaggi per utilizzare uno script di configurazione della build C/C++ personalizzato da AGP.
Passaggio 1: modifica il file build.gradle
a livello di modulo per fare riferimento a uno script di configurazione
Per attivare il supporto Ninja in AGP, configura experimentalProperties
nel file build.gradle
a livello di modulo:
android {
defaultConfig {
externalNativeBuild {
experimentalProperties["ninja.abiFilters"] = [ "x86", "arm64-v8a" ]
experimentalProperties["ninja.path"] = "source-file-list.txt"
experimentalProperties["ninja.configure"] = "configure-ninja"
experimentalProperties["ninja.arguments"] = [
"\${ndk.moduleMakeFile}",
"--variant=\${ndk.variantName}",
"--abi=Android-\${ndk.abi}",
"--configuration-dir=\${ndk.configurationDir}",
"--ndk-version=\${ndk.moduleNdkVersion}",
"--min-sdk-version=\${ndk.minSdkVersion}"
]
}
}
Le proprietà sono interpretate da AGP come segue:
ninja.abiFilters
è un elenco di ABI da creare. I valori validi sono:x86
,x86-64
,armeabi-v7a
earm64-v8a
.ninja.path
è il percorso di un file di progetto C/C++. Il formato di questo file può essere qualsiasi cosa tu voglia. Le modifiche a questo file attiveranno una richiesta di sincronizzazione Gradle in Android Studio.ninja.configure
è un percorso di un file di script che verrà eseguito da Gradle quando sarà necessario configurare il progetto C/C++. Un progetto viene configurato nella prima build, durante una sincronizzazione Gradle in Android Studio o quando cambia uno degli input dello script di configurazione.ninja.arguments
è un elenco di argomenti che verranno passati allo script definito da ninja.configure. Gli elementi di questo elenco possono fare riferimento a un insieme di macro i cui valori dipendono dal contesto di configurazione corrente in AGP:${ndk.moduleMakeFile}
è il percorso completo del fileninja.configure
. Nell'esempio sarebbeC:\path\to\configure-ninja.bat
.${ndk.variantName}
è il nome dell'attuale variante AGP in fase di creazione. Ad esempio, esegui il debug o la release.${ndk.abi}
è il nome dell'attuale ABI ABI in fase di creazione. Ad esempio,x86
oarm64-v8a
.
${ndk.buildRoot}
è il nome di una cartella, generata da AGP, in cui lo script scrive l'output. I dettagli saranno spiegati nel Passaggio 2: crea lo script di configurazione.${ndk.ndkVersion}
è la versione dell'NDK da utilizzare. Di solito si tratta del valore trasmesso ad android.ndkVersion nel filebuild.gradle
oppure di un valore predefinito se non è presente.${ndk.minPlatform}
è la piattaforma Android target minima richiesta da AGP.
ninja.targets
è un elenco di target ninja specifici da creare.
Passaggio 2: crea lo script di configurazione
La responsabilità minima dello script di configurazione (configure-ninja.bat
nell'esempio precedente) è generare un file build.ninja
che, se creato con Ninja, compilerà e collegherà tutti gli output nativi del progetto. Di solito si tratta di file .o
(oggetto), .a
(archivio) e .so
(oggetto condiviso).
Lo script di configurazione può scrivere il file build.ninja
in due posizioni diverse, a seconda delle tue esigenze.
Se AGP può scegliere una località, lo script di configurazione scrive
build.ninja
nella località impostata nella macro${ndk.buildRoot}
.Se lo script di configurazione deve scegliere la posizione del file
build.ninja
, scrive anche un file denominatobuild.ninja.txt
nella posizione impostata nella macro${ndk.buildRoot}
. Questo file contiene il percorso completo del filebuild.ninja
scritto dallo script di configurazione.
Struttura del file build.ninja
In genere, la maggior parte delle strutture che rappresentano in modo accurato una build Android C/C++ è valida. Gli elementi chiave richiesti da AGP e Android Studio sono:
L'elenco dei file sorgente C/C++ insieme ai flag necessari a Clang per compilarli.
L'elenco delle librerie di output. In genere si tratta di file
.so
(oggetto condiviso), ma anche.a
(archivio) o eseguibili (nessuna estensione).
Se hai bisogno di esempi su come generare un file build.ninja
, puoi esaminare l'output di CMake quando viene utilizzato il generatore build.ninja
.
Ecco un esempio di modello build.ninja
minimo.
rule COMPILE
command = /path/to/ndk/clang -c $in -o $out {other flags}
rule LINK
command = /path/to/ndk/clang $in -o $out {other flags}
build source.o : COMPILE source.cpp
build lib.so : LINK source.o
Best practice
Oltre ai requisiti (elenco di file di origine e librerie di output), di seguito sono riportate alcune best practice consigliate.
Dichiara gli output con nome con phony
regole
Se possibile, è consigliabile che la struttura build.ninja
utilizzi le regole phony
per assegnare nomi leggibili agli output della build. Ad esempio, se hai un output denominato c:/path/to/lib.so
, puoi assegnargli un nome leggibile come segue.
build curl: phony /path/to/lib.so
Il vantaggio di questa operazione è che potrai specificare questo nome come destinazione nel file build.gradle
. Ad esempio,
android {
defaultConfig {
externalNativeBuild {
...
experimentalProperties["ninja.targets"] = [ "curl" ]
Specifica un target completo
Quando specifichi un target all
, questo sarà l'insieme predefinito di librerie create da AGP quando nessun target è specificato esplicitamente nel file build.gradle
.
rule COMPILE
command = /path/to/ndk/clang $in -o $out {other flags}
rule LINK
command = /path/to/ndk/clang $in -o $out {other flags}
build foo.o : COMPILE foo.cpp
build bar.o : COMPILE bar.cpp
build libfoo.so : LINK foo.o
build libbar.so : LINK bar.o
build all: phony libfoo.so libbar.so
(Facoltativo) Specifica un metodo di compilazione alternativo
Un caso d'uso più avanzato è quello di includere un sistema di build esistente non basato su Ninja. In questo caso, devi comunque rappresentare tutte le origini con i relativi flag, oltre alle librerie di output, in modo che Android Studio possa presentare le funzionalità dei servizi linguistici corrette, come il completamento automatico e la definizione go-to. Tuttavia, vuoi che AGP si riferisca al sistema di build sottostante durante la build effettiva.
A questo scopo, puoi utilizzare un output di build Ninja con un'estensione specifica .passthrough
.
Come esempio più concreto, supponiamo che tu voglia eseguire un MSBuild. Lo script di configurazione genererà il build.ninja
come di consueto, ma aggiungerebbe anche una destinazione passthrough che definisce il modo in cui AGP richiama MSBuild.
rule COMPILE
command = /path/to/ndk/clang $in -o $out {other flags}
rule LINK
command = /path/to/ndk/clang $in -o $out {other flags}
rule MBSUILD_CURL
command = /path/to/msbuild {flags to build curl with MSBuild}
build source.o : COMPILE source.cpp
build lib.so : LINK source.o
build curl : phony lib.so
build curl.passthrough : MBSUILD_CURL
Fornisci feedback
Questa funzionalità è sperimentale, quindi il tuo feedback è molto importante. Puoi inviare feedback tramite i seguenti canali:
Per un feedback generale, aggiungi un commento a questo bug.
Per segnalare un bug, apri Android Studio e fai clic su Guida > Invia feedback. Assicurati di fare riferimento a "Sistemi di build C/C++ personalizzati" per indirizzare il bug.
Per segnalare un bug se non hai installato Android Studio, segnalalo utilizzando questo modello.