Wenn Sie CMake oder ndk-build nicht verwenden, aber eine vollständige Integration des C/C++-Builds des Android-Gradle-Plug-ins (AGP) und von Android Studio wünschen, können Sie ein benutzerdefiniertes C/C++-Build-System erstellen. Dazu erstellen Sie ein Shell-Script, das Build-Informationen im Ninja-Build-Dateiformat schreibt.
Android Studio und AGP bieten jetzt experimentelle Unterstützung für benutzerdefinierte C/C++-Build-Systeme. Diese Funktion ist ab Android Studio Dolphin | 2021.3.1 Canary 4 verfügbar.
Übersicht
Ein gängiges Muster für C/C++-Projekte, insbesondere für solche, die auf mehrere Plattformen abzielen, besteht darin, Projekte für jede dieser Plattformen aus einer zugrunde liegenden Darstellung zu generieren. Ein bekanntes Beispiel für dieses Muster ist CMake. CMake kann Projekte für Android, iOS und andere Plattformen aus einer einzigen zugrunde liegenden Darstellung generieren, die in der Datei CMakeLists.txt gespeichert ist.
CMake wird zwar direkt vom AGP unterstützt, es gibt jedoch auch andere Projektgeneratoren, die nicht direkt unterstützt werden:
Diese Arten von Projektgeneratoren unterstützen entweder Ninja als Backend-Darstellung des C/C++-Builds oder können so angepasst werden, dass Ninja als Backend-Darstellung generiert wird.
Bei korrekter Konfiguration ermöglicht ein AGP-Projekt mit einem integrierten C/C++-Projektsystemgenerator Nutzern Folgendes:
Build über die Befehlszeile und Android Studio erstellen
Quellen mit vollständiger Unterstützung für Sprachdienstfunktionen (z. B. „Gehe zu Definition“) in Android Studio bearbeiten
Verwenden Sie Android Studio-Debugger, um native und gemischte Prozesse zu debuggen.
Build so ändern, dass ein benutzerdefiniertes C/C++-Build-Konfigurationsskript verwendet wird
In diesem Abschnitt werden die Schritte zur Verwendung eines benutzerdefinierten C/C++-Build-Konfigurationsskripts aus dem AGP beschrieben.
Schritt 1: Datei build.gradle auf Modulebene so ändern, dass sie auf ein Konfigurationsskript verweist
Wenn Sie die Ninja-Unterstützung im AGP aktivieren möchten, konfigurieren Sie experimentalProperties in der Datei build.gradle auf Modulebene:
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}"
]
}
}
Die Eigenschaften werden vom AGP so interpretiert:
ninja.abiFiltersist eine Liste der zu erstellenden ABIs. Gültige Werte sind:x86,x86-64,armeabi-v7aundarm64-v8a.ninja.pathist der Pfad zu einer C/C++-Projektdatei. Das Format dieser Datei kann beliebig sein. Änderungen an dieser Datei lösen in Android Studio eine Aufforderung zur Gradle-Synchronisierung aus.ninja.configureist ein Pfad zu einer Skriptdatei, die von Gradle ausgeführt wird, wenn das C/C++-Projekt konfiguriert werden muss. Ein Projekt wird beim ersten Build, während einer Gradle-Synchronisierung in Android Studio oder wenn sich eine der Eingaben des Konfigurationsskripts ändert, konfiguriert.ninja.argumentsist eine Liste von Argumenten, die an das durch ninja.configure definierte Script übergeben werden. Elemente in dieser Liste können auf eine Reihe von Makros verweisen, deren Werte vom aktuellen Konfigurationskontext im AGP abhängen:${ndk.moduleMakeFile}ist der vollständige Pfad zur Dateininja.configure. In diesem Beispiel wäre dasC:\path\to\configure-ninja.bat.${ndk.variantName}ist der Name der aktuellen AGP-Variante, die erstellt wird. Beispiel: Debug oder Release.${ndk.abi}ist der Name der aktuellen AGP-ABI, die erstellt wird. Zum Beispielx86oderarm64-v8a.
${ndk.buildRoot}ist der Name eines vom AGP generierten Ordners, in den das Script seine Ausgabe schreibt. Details dazu werden in Schritt 2: Konfigurationsskript erstellen erläutert.${ndk.ndkVersion}ist die zu verwendende NDK-Version. Dies ist in der Regel der Wert, der in der Dateibuild.gradlean android.ndkVersion übergeben wird, oder ein Standardwert, falls kein Wert vorhanden ist.${ndk.minPlatform}ist die von AGP angeforderte Mindest-Android-Zielplattform.
ninja.targetsist eine Liste der spezifischen Ninja-Ziele, die erstellt werden sollen.
Schritt 2: Konfigurationsskript erstellen
Die Mindestaufgabe des Konfigurationsskripts (configure-ninja.bat im vorherigen Beispiel) besteht darin, eine build.ninja-Datei zu generieren, die beim Erstellen mit Ninja alle nativen Ausgaben des Projekts kompiliert und verknüpft. In der Regel sind dies .o- (Objekt), .a- (Archiv) und .so-Dateien (freigegebenes Objekt).
Das Konfigurationsskript kann die Datei build.ninja je nach Bedarf an zwei verschiedenen Orten schreiben.
Wenn es in Ordnung ist, dass das AGP einen Speicherort auswählt, schreibt das Konfigurationsskript
build.ninjaan den im Makro${ndk.buildRoot}festgelegten Speicherort.Wenn das Konfigurationsskript den Speicherort der Datei
build.ninjaauswählen muss, wird auch eine Datei mit dem Namenbuild.ninja.txtan den im Makro${ndk.buildRoot}festgelegten Speicherort geschrieben. Diese Datei enthält den vollständigen Pfad zur Dateibuild.ninja, die vom Konfigurationsskript geschrieben wurde.
Struktur der Datei build.ninja
Im Allgemeinen funktionieren die meisten Strukturen, die einen Android-C/C++-Build korrekt darstellen. Die wichtigsten Elemente, die für das AGP und Android Studio erforderlich sind, sind:
Die Liste der C/C++-Quelldateien zusammen mit den Flags, die von Clang zum Kompilieren benötigt werden.
Die Liste der Ausgabebibliotheken. In der Regel sind dies
.so-Dateien (Shared Object), es können aber auch.a-Dateien (Archiv) oder ausführbare Dateien (ohne Erweiterung) sein.
Wenn Sie Beispiele für die Erstellung einer build.ninja-Datei benötigen, können Sie sich die Ausgabe von CMake ansehen, wenn der build.ninja-Generator verwendet wird.
Hier ist ein Beispiel für eine minimale build.ninja-Vorlage.
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
Empfehlungen
Zusätzlich zu den Anforderungen (Liste der Quelldateien und Ausgabebibliotheken) finden Sie hier einige Empfehlungen.
Benannte Ausgaben mit phony-Regeln deklarieren
Wenn möglich, sollte die build.ninja-Struktur phony-Regeln verwenden, um Build-Ausgaben menschenlesbare Namen zu geben. Wenn Sie beispielsweise eine Ausgabe mit dem Namen c:/path/to/lib.so haben, können Sie ihr so einen menschenlesbaren Namen geben.
build curl: phony /path/to/lib.so
Der Vorteil besteht darin, dass Sie diesen Namen dann als Build-Ziel in der Datei build.gradle angeben können. Beispiel:
android {
defaultConfig {
externalNativeBuild {
...
experimentalProperties["ninja.targets"] = [ "curl" ]
Ziel „all“ angeben
Wenn Sie ein all-Ziel angeben, ist dies der Standardsatz von Bibliotheken, die von AGP erstellt werden, wenn in der Datei build.gradle keine Ziele explizit angegeben sind.
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
Alternative Build-Methode angeben (optional)
Ein erweiterter Anwendungsfall ist das Wrapping eines vorhandenen Build-Systems, das nicht auf Ninja basiert. In diesem Fall müssen Sie weiterhin alle Quellen mit ihren Flags zusammen mit den Ausgabebibliotheken darstellen, damit Android Studio die richtigen Sprachdienstfunktionen wie die automatische Vervollständigung und die Definition „Gehe zu“ anzeigen kann. Sie möchten jedoch, dass das AGP während des eigentlichen Builds auf das zugrunde liegende Build-System zurückgreift.
Dazu können Sie eine Ninja-Build-Ausgabe mit der spezifischen Erweiterung .passthrough verwenden.
Ein konkreteres Beispiel: Wenn Sie ein MSBuild-Skript einbinden möchten, generiert Ihr Konfigurationsskript wie gewohnt die build.ninja, fügt aber auch ein Passthrough-Ziel hinzu, das definiert, wie das AGP MSBuild aufruft.
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
Feedback geben
Diese Funktion befindet sich noch in der Testphase. Wir freuen uns daher über Feedback. Sie können Feedback über die folgenden Kanäle geben:
Wenn Sie allgemeines Feedback geben möchten, fügen Sie dem entsprechenden Fehler einen Kommentar hinzu.
Wenn Sie einen Fehler melden möchten, öffnen Sie Android Studio und klicken Sie auf Hilfe > Feedback geben. Verweisen Sie auf „Benutzerdefinierte C/C++-Build-Systeme“, um den Fehler zu melden.
Wenn Sie Android Studio nicht installiert haben, können Sie einen Fehler über die Fehlervorlage melden.