Jeśli nie używasz CMake ani ndk-build, ale potrzebujesz pełnej integracji kompilacji C/C++ Androida (AGP) i Android Studio, możesz stworzyć niestandardowy system kompilacji C/C++, tworząc skrypt powłoki zapisujący informacje o kompilacji w formacie pliku kompilacji Ninja.
W Android Studio i AGP dodaliśmy eksperymentalną obsługę niestandardowych systemów kompilacji w języku C/C++. Ta funkcja jest dostępna od Androida Studio Dolphin | 2021.3.1. wersja Canary 4.
Omówienie
Typowym wzorcem w przypadku projektów C/C++, zwłaszcza tych kierowanych na wiele platform, jest generowanie projektów dla każdej z nich na podstawie własnej reprezentacji.
Doskonałym przykładem tego wzorca jest CMake. CMake może generować projekty na Androida, iOS i inne platformy na podstawie jednej bazowej reprezentacji zapisanej w pliku CMakeLists.txt
.
Chociaż CMake jest bezpośrednio obsługiwane przez AGP, istnieją też inne generatory projektów, które nie są bezpośrednio obsługiwane:
Prywatne, niestandardowe generatory projektów
Tego typu generatory projektów obsługują język Ninja jako reprezentację backendu kompilacji w języku C/C++ lub można je dostosować, tak aby generował Ninja jako reprezentację backendu.
Prawidłowo skonfigurowany projekt AGP ze zintegrowanym generatorem systemu projektów C/C++ umożliwia użytkownikom:
Kompiluj z poziomu wiersza poleceń i Android Studio.
Edytuj źródła z pełną obsługą usług językowych (np. definicja go-to) w Android Studio.
Do debugowania procesów natywnych i różnych możesz używać debugerów Android Studio.
Jak zmodyfikować kompilację, aby użyć niestandardowego skryptu konfiguracji kompilacji w C/C++
W tej sekcji omawiamy czynności, jakie należy wykonać, aby użyć niestandardowego skryptu konfiguracji kompilacji C/C++ z pakietu AGP.
Krok 1. Zmodyfikuj plik build.gradle
na poziomie modułu, aby zawierał informacje o skrypcie konfiguracji
Aby włączyć obsługę ninja w AGP, skonfiguruj experimentalProperties
w pliku build.gradle
na poziomie modułu:
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}"
]
}
}
Właściwości są interpretowane przez interfejs AGP w następujący sposób:
ninja.abiFilters
to lista interfejsów ABI do utworzenia. Prawidłowe wartości tox86
,x86-64
,armeabi-v7a
iarm64-v8a
.ninja.path
to ścieżka do pliku projektu w C/C++. Plik może mieć dowolny format. Zmiany wprowadzone w tym pliku będą aktywować prośbę o synchronizację Gradle w Android Studio.ninja.configure
to ścieżka do pliku skryptu, która będzie wykonywana przez Gradle, gdy będzie konieczne skonfigurowanie projektu C/C++. Projekt jest konfigurowany przy pierwszej kompilacji, podczas synchronizacji Gradle w Android Studio lub gdy zmieni się któreś z danych wejściowych konfigurowanego skryptu.ninja.arguments
to lista argumentów, które zostaną przekazane do skryptu zdefiniowanego przez ninja.configure. Elementy z tej listy mogą odwoływać się do zestawu makr, których wartości zależą od bieżącego kontekstu konfiguracji w AGP:${ndk.moduleMakeFile}
to pełna ścieżka do plikuninja.configure
. W tym przykładzie będzie toC:\path\to\configure-ninja.bat
.${ndk.variantName}
to nazwa obecnie tworzonego wariantu AGP. Na przykład debuguj lub zwalniaj.${ndk.abi}
to nazwa obecnie tworzonego interfejsu AGP ABI. na przykładx86
lubarm64-v8a
.
${ndk.buildRoot}
to nazwa folderu wygenerowana przez AGP, w którym skrypt zapisuje dane wyjściowe. Szczegółowe informacje na ten temat znajdziesz w sekcji Krok 2. Utwórz skrypt konfiguracji.${ndk.ndkVersion}
to wersja NDK, która ma zostać użyta. Zwykle jest to wartość przekazywana do android.ndkVersion w plikubuild.gradle
lub wartość domyślna, jeśli nie ma żadnej wartości.${ndk.minPlatform}
to minimalna docelowa platforma Androida, której żąda AGP.
ninja.targets
zawiera listę konkretnych celów ninja, które należy utworzyć.
Krok 2. Utwórz skrypt konfiguracji
Minimalną odpowiedzialność skryptu konfiguracyjnego (configure-ninja.bat
w poprzednim przykładzie) jest wygenerowanie pliku build.ninja
, który po utworzeniu w programie Ninja skompiluje i połączy wszystkie natywne dane wyjściowe projektu. Zwykle są to pliki .o
(Object), .a
(Archive) i .so
(Shared Object).
W zależności od potrzeb skrypt konfiguracji może zapisać plik build.ninja
w 2 różnych miejscach.
Jeśli AGP może wybrać lokalizację, skrypt konfiguracji zapisze wartość
build.ninja
w lokalizacji ustawionej w makrze${ndk.buildRoot}
.Jeśli skrypt konfiguracji musi wybrać lokalizację pliku
build.ninja
, w lokalizacji określonej w makrze${ndk.buildRoot}
zapisuje też plik o nazwiebuild.ninja.txt
. Ten plik zawiera pełną ścieżkę do plikubuild.ninja
napisanego przez skrypt konfiguracji.
Struktura pliku build.ninja
Zasadniczo sprawdzi się większość struktury, które dokładnie reprezentują kompilację Androida w języku C/C++. Najważniejsze elementy wymagane przez AGP i Android Studio:
Lista plików źródłowych C/C++ wraz z flagami potrzebnymi Clang do ich skompilowania.
Lista bibliotek wyjściowych. Zwykle są to pliki
.so
(obiekty współużytkowane), ale mogą też być typu.a
(archiwalne) lub wykonywalne (bez rozszerzenia).
Jeśli potrzebujesz przykładów, jak wygenerować plik build.ninja
, możesz przejrzeć dane wyjściowe narzędzia CMake, gdy używany jest generator build.ninja
.
Oto przykład minimalnego szablonu build.ninja
.
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
Sprawdzone metody
Oprócz wymagań (listy plików źródłowych i bibliotek wyjściowych) warto też zapoznać się z zalecanymi sprawdzonymi metodami.
Deklarowanie nazwanych danych wyjściowych za pomocą phony
reguł
Zalecamy, aby w miarę możliwości struktura build.ninja
używała reguł phony
, aby nadawać wynikom kompilacji zrozumiałe dla człowieka nazwy. Jeśli np. masz dane wyjściowe o nazwie c:/path/to/lib.so
, możesz nadać im czytelną nazwę w podany niżej sposób.
build curl: phony /path/to/lib.so
Zaletą takiego rozwiązania jest możliwość określenia tej nazwy jako celu kompilacji w pliku build.gradle
. Na przykład
android {
defaultConfig {
externalNativeBuild {
...
experimentalProperties["ninja.targets"] = [ "curl" ]
Określ wartość „Wszystkie” cel
Jeśli określisz środowisko docelowe all
, będzie to domyślny zbiór bibliotek utworzony przez AGP, jeśli w pliku build.gradle
nie określono żadnych środowisk docelowych.
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
Określ alternatywną metodę kompilacji (opcjonalnie)
Bardziej zaawansowanym przypadkiem użycia jest opakowanie istniejącego systemu kompilacji, który nie jest oparty na technologii Ninja. W takim przypadku nadal musisz reprezentować wszystkie źródła za pomocą ich flag wraz z bibliotekami wyjściowymi, aby Android Studio mógł prezentować prawidłowe funkcje usługi językowej, takie jak autouzupełnianie i definicja. Chcesz jednak, aby podczas rzeczywistego tworzenia gry pakiet AGP pozostawał przy użyciu bazowego systemu kompilacji.
Aby to zrobić, możesz użyć danych wyjściowych kompilacji Ninja z określonym rozszerzeniem .passthrough
.
Bardziej konkretny przykład: załóżmy, że chcesz pakować instancję MSBuild. Twój skrypt konfiguracji wygenerowałby zasób build.ninja
w zwykły sposób, ale dodałby również środowisko docelowe określające sposób, w jaki AGP będzie wywoływał 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
Prześlij opinię
Ta funkcja jest eksperymentalna, dlatego Twoja opinia jest dla nas bardzo ważna. Opinie możesz przesyłać, korzystając z tych kanałów:
Żeby przesłać ogólną opinię, dodaj komentarz do tego błędu.
Aby zgłosić błąd, otwórz Android Studio i kliknij Pomoc > Prześlij opinię. Pamiętaj, aby dodać odwołanie do artykułu „Custom C/C++ Build Systems” (Niestandardowe systemy kompilacji C/C++). by pomóc w kierowaniu błędem.
Aby zgłosić błąd, jeśli nie masz zainstalowanego Android Studio, zgłoś błąd, korzystając z tego szablonu.