Pakiet Android NDK na Androida obsługuje użycie narzędzia CMake do kompilowania kodu C i C++ aplikacji. Na tej stronie opisujemy, jak korzystać z CMake z narzędziem NDK za pomocą ExternalNativeBuild
wtyczki Androida do obsługi Gradle lub podczas bezpośredniego wywoływania CMake.
plik łańcucha narzędzi CMake;
NDK obsługuje CMake za pomocą plikutoolchain. Pliki narzędzi to pliki CMake, które dostosowują działanie łańcucha narzędzi na potrzeby kompilacji krzyżowej. Plik narzędzia NDK znajduje się w folderze NDK pod adresem <NDK>/build/cmake/android.toolchain.cmake
.
Parametry kompilacji, takie jak ABI, minSdkVersion
itp., są podawane w wierszu poleceń podczas wywoływania cmake
. Listę obsługiwanych argumentów znajdziesz w sekcji Argumenty łańcucha narzędzi.
Nowy plik łańcucha narzędzi
Wcześniejsze wersje NDK eksperymentowały z nową implementacją pliku łańcucha narzędzi, która miała zmniejszyć różnice w zachowaniu między użyciem pliku łańcucha narzędzi NDK a użyciem wbudowanego wsparcia CMake. Okazało się, że wymaga to znacznej ilości pracy (która nie została ukończona), ale nie poprawia to działania, więc nie będziemy już tego robić.
W „nowym” pliku narzędzia wystąpiły regresje zachowania w porównaniu z „starym” plikiem narzędzia. Działanie domyślne to zalecany proces. Jeśli używasz flagi -DANDROID_USE_LEGACY_TOOLCHAIN_FILE=OFF
, zalecamy jej usunięcie z kompilacji. Nowy plik łańcucha narzędzi nigdy nie był zgodny ze starszym plikiem, więc prawdopodobnie mogą wystąpić regresje w działaniu.
Nie zalecamy używania nowego pliku narzędzi, ale nie planujemy go obecnie usuwać z NDK. Spowoduje to przerwanie kompilacji, które opierają się na różnicach w zachowaniu między nowymi a starszymi plikami narzędzi. Niestety zmiana nazwy opcji w celu wskazania, że zalecana jest wersja starsza, również spowoduje przerwanie pracy użytkowników tej opcji. Jeśli korzystasz z nowego pliku łańcucha narzędzi, nie musisz go przenosić, ale wiesz, że wszelkie błędy wynikające z działania plików w nowym łańcuchu narzędzi prawdopodobnie nie zostaną naprawione i trzeba będzie przeprowadzić migrację.
Wykorzystanie
Gradle
Korzystanie z pliku łańcucha narzędzi CMake jest automatyczne, gdy używasz opcji externalNativeBuild
. Więcej informacji znajdziesz w przewodniku Dodawanie kodu C i C++ do projektu w Android Studio.
Wiersz poleceń
Podczas kompilowania za pomocą CMake poza Gradle należy przekazać do CMake plik toolchain i jego argumenty. Na przykład:
$ cmake \
-DCMAKE_TOOLCHAIN_FILE=$NDK/build/cmake/android.toolchain.cmake \
-DANDROID_ABI=$ABI \
-DANDROID_PLATFORM=android-$MINSDKVERSION \
$OTHER_ARGS
Argumenty łańcucha narzędzi
Do pliku łańcucha narzędzi CMake można przekazać te argumenty. Jeśli kompilujesz za pomocą Gradle, dodaj argumenty do android.defaultConfig.externalNativeBuild.cmake.arguments
zgodnie z opisem w dokumentacji ExternalNativeBuild. Jeśli kompilujesz z poziomu wiersza poleceń, przekaż argumenty do CMake za pomocą -D
. Aby na przykład wymusić kompilację bez obsługi Neona na platformie armeabi-v7a, prześlij wartość -DANDROID_ARM_NEON=FALSE
.
ANDROID_ABI
docelowy interfejs ABI; Informacje o obsługiwanych interfejsach ABI znajdziesz w artykule Interfejsy ABI Androida.
Gradle
Gradle udostępnia ten argument automatycznie. Nie ustawiaj tego argumentu w pliku build.gradle
. Aby kontrolować, na jakie interfejsy ABI Gradle ma być kierowany, użyj abiFilters
zgodnie z opisem w artykule Interfejsy ABI Androida.
Wiersz poleceń
CMake kompiluje pojedynczy cel na kompilację. Aby kierować reklamy na więcej niż 1 interfejs ABI Androida, musisz utworzyć po 1 wersji na każdy interfejs ABI. Zalecamy używanie różnych katalogów kompilacji dla każdego ABI, aby uniknąć kolizji między kompilacjami.
Wartość | Uwagi |
---|---|
armeabi-v7a |
|
armeabi-v7a with NEON |
Taka sama cena jak w usłudze armeabi-v7a . |
arm64-v8a |
|
x86 |
|
x86_64 |
ANDROID_ARM_MODE
Określa, czy dla armeabi-v7a należy wygenerować instrukcje arm czy thumb. Nie ma to wpływu na inne interfejsy ABI. Więcej informacji znajdziesz w dokumentacji dotyczącej interfejsów ABI Androida.
Wartość | Uwagi |
---|---|
ręka | |
kciuk | Domyślne zachowanie. |
ANDROID_NATIVE_API_LEVEL
Alias dla ANDROID_PLATFORM.
ANDROID_PLATFORM
Określa minimalny poziom interfejsu API obsługiwany przez aplikację lub bibliotekę. Ta wartość odpowiada minSdkVersion
aplikacji.
Gradle
Jeśli używasz wtyczki Gradle na Androida, ta wartość jest automatycznie ustawiana tak, aby pasowała do wartości minSdkVersion
aplikacji. Nie należy jej ustawiać ręcznie.
Wiersz poleceń
Gdy wywołujesz CMake bezpośrednio, ta wartość domyślnie przyjmuje najniższy poziom interfejsu API obsługiwany przez używany NDK. Na przykład w NDK r20 ta wartość jest domyślnie ustawiona na poziom API 16.
W przypadku tego parametru akceptowane są różne formaty:
android-$API_LEVEL
$API_LEVEL
android-$API_LETTER
Format $API_LETTER
umożliwia określenie android-N
bez konieczności określania numeru powiązanego z danym wydaniem. Pamiętaj, że niektóre wersje otrzymały nowe interfejsy API bez zmiany numeru wersji. Te interfejsy API można określić, dodając sufiks -MR1
. Na przykład poziom interfejsu API 25 to android-N-MR1
.
ANDROID_STL
Określa, którego STL użyć w przypadku tej aplikacji. Więcej informacji znajdziesz w artykule na temat obsługi biblioteki C++. Domyślnie używana jest wartość c++_static
.
Wartość | Uwagi |
---|---|
c++_shared | Wersja biblioteki współdzielonej libc++. |
c++_static | Wersja statycznej biblioteki libc++. |
brak | Brak obsługi standardowej biblioteki C++. |
system | System STL |
Zarządzanie flagami kompilatora
Jeśli chcesz przekazać kompilatorowi lub linkerowi określone flagi w ramach kompilacji, zapoznaj się z dokumentacją CMake dotyczącą opcji set_target_compile_options i powiązanej grupy opcji. Sekcja „Zobacz też” na dole tej strony zawiera przydatne wskazówki.
Zwykle sprawdzoną metodą jest stosowanie flag kompilatora w najwęźszym dostępnym zakresie. Flagi, które chcesz zastosować do wszystkich docelowych wartości (np. -Werror
), trudno powtarzać w każdym module, ale i tak nie należy ich stosować globalnie (CMAKE_CXX_FLAGS
), ponieważ może to mieć niepożądany wpływ na zależności zewnętrzne w Twoim projekcie. W takich przypadkach flagi można zastosować w zakresie katalogu (add_compile_options
).
W przypadku wąskiego podzbioru flag kompilatora można również ustawić w pliku build.gradle za pomocą właściwości cppFlags
lub podobnych. Nie rób tego. Flagi przekazywane do CMake z Gradle będą miały zaskakujące zachowania priorytetów, w niektórych przypadkach zastępując flagi przekazywane domyślnie przez implementację, które są wymagane do kompilowania kodu na Androida. Zawsze preferuj obsługę zachowania CMake bezpośrednio w CMake. Jeśli chcesz kontrolować flagi kompilatora w ramach AGP buildType
, zapoznaj się z artykułem Praca z typami kompilacji AGP w CMake.
Praca z typami kompilacji AGP w CMake
Jeśli chcesz dostosować działanie CMake do niestandardowego Gradle buildType
, użyj tego typu kompilacji, aby przekazać dodatkowy parametr CMake (a nie parametr kompilatora), który mogą odczytać skrypty kompilacji CMake. Jeśli na przykład masz warianty kompilacji „free” i „premium”, które są kontrolowane przez plik build.gradle.kts i musisz przekazać te dane do CMake:
android {
buildTypes {
free {
externalNativeBuild {
cmake {
arguments.add("-DPRODUCT_VARIANT_PREMIUM=OFF")
}
}
}
premium {
externalNativeBuild {
cmake {
arguments.add("-DPRODUCT_VARIANT_PREMIUM=ON")
}
}
}
}
}
Następnie w pliku CMakeLists.txt:
if (DPRODUCT_VARIANT_PREMIUM)
# Do stuff for the premium build.
else()
# Do stuff for the free build.
endif()
Nazwa zmiennej zależy od Ciebie, ale pamiętaj, aby nie używać prefiksów ANDROID_
, APP_
ani CMAKE_
, aby uniknąć konfliktów lub pomyłek z dotychczasowymi flagami.
Przykładem może być plikacja Sanitizers NDK.
Poznawanie polecenia kompilacji CMake
Przy debugowaniu problemów z kompilacją CMake warto znać konkretne argumenty kompilacji, które Gradle używa do kompilacji w przypadku Androida.
Wtyczka Android Gradle zapisuje w build_command.txt
argumenty kompilacji, których używa do wykonywania kompilacji CMake dla każdej pary ABI i typu kompilacji. Znajdziesz je w tym katalogu:
<project-root>/<module-root>/.cxx/cmake/<build-type>/<ABI>/
Ten fragment kodu zawiera przykładowe argumenty CMake pozwalające utworzyć możliwą do debugowania wersję przykładowej wersji hello-jni
kierowanej na architekturę armeabi-v7a
.
Executable : ${HOME}/Android/Sdk/cmake/3.10.2.4988404/bin/cmake
arguments :
-H${HOME}/Dev/github-projects/googlesamples/ndk-samples/hello-jni/app/src/main/cpp
-DCMAKE_FIND_ROOT_PATH=${HOME}/Dev/github-projects/googlesamples/ndk-samples/hello-jni/app/.cxx/cmake/universalDebug/prefab/armeabi-v7a/prefab
-DCMAKE_BUILD_TYPE=Debug
-DCMAKE_TOOLCHAIN_FILE=${HOME}/Android/Sdk/ndk/22.1.7171670/build/cmake/android.toolchain.cmake
-DANDROID_ABI=armeabi-v7a
-DANDROID_NDK=${HOME}/Android/Sdk/ndk/22.1.7171670
-DANDROID_PLATFORM=android-23
-DCMAKE_ANDROID_ARCH_ABI=armeabi-v7a
-DCMAKE_ANDROID_NDK=${HOME}/Android/Sdk/ndk/22.1.7171670
-DCMAKE_EXPORT_COMPILE_COMMANDS=ON
-DCMAKE_LIBRARY_OUTPUT_DIRECTORY=${HOME}/Dev/github-projects/googlesamples/ndk-samples/hello-jni/app/build/intermediates/cmake/universalDebug/obj/armeabi-v7a
-DCMAKE_RUNTIME_OUTPUT_DIRECTORY=${HOME}/Dev/github-projects/googlesamples/ndk-samples/hello-jni/app/build/intermediates/cmake/universalDebug/obj/armeabi-v7a
-DCMAKE_MAKE_PROGRAM=${HOME}/Android/Sdk/cmake/3.10.2.4988404/bin/ninja
-DCMAKE_SYSTEM_NAME=Android
-DCMAKE_SYSTEM_VERSION=23
-B${HOME}/Dev/github-projects/googlesamples/ndk-samples/hello-jni/app/.cxx/cmake/universalDebug/armeabi-v7a
-GNinja
jvmArgs :
Build command args: []
Version: 1
Korzystanie z gotowych bibliotek
Jeśli gotowa biblioteka, którą chcesz zaimportować, jest rozpowszechniana jako plik AAR, zaimportuj ją i użyj, postępując zgodnie z dokumentacją Studio na temat zależności. Jeśli nie używasz AGP, możesz śledzić stronę https://google.github.io/prefab/example-workflow.html, ale przejście na AGP jest prawdopodobnie znacznie łatwiejsze.
Instrukcje dotyczące korzystania z wstępnie skompilowanych bibliotek za pomocą CMake znajdziesz w dokumentacji add_library
dotyczącej celów IMPORTED
w podręczniku CMake.
Tworzenie kodu zewnętrznego
Istnieją różne sposoby kompilowania kodu zewnętrznego w ramach projektu CMake. Wybór najlepszej opcji zależy od sytuacji. Często najlepszym rozwiązaniem jest unikanie tego. Zamiast tego utwórz AAR dla biblioteki i użyj go w swojej aplikacji. Nie musisz publikować tego pliku AAR. Może być wewnętrzny w Twoim projekcie Gradle.
Jeśli nie ma takiej możliwości:
- Dostawca kopiuje źródło zewnętrzne do repozytorium i używa polecenia add_subdirectory, aby je skompilować. Działa to tylko wtedy, gdy druga biblioteka jest utworzona w CMake.
- Zdefiniuj ExternalProject.
- Utwórz bibliotekę osobno od projektu i zaimportuj ją jako gotową, postępując zgodnie z instrukcjami podanymi w artykule Używanie gotowych bibliotek.
Obsługa YASM w CMake
NDK zapewnia obsługę CMake do kompilowania kodu w języku asemblistycznym napisanego w YASM, aby można było go uruchomić na architekturach x86 i x86-64. YASM to kompilator typu open source dla architektur x86 i x86-64 oparty na kompilatorze NASM.
Aby skompilować kod asemblera za pomocą CMake, wprowadź następujące zmiany w pliku CMakeLists.txt
projektu:
- Wywołaj metodę
enable_language
z wartościąASM_NASM
. - W zależności od tego, czy kompilujesz bibliotekę współdzieloną, czy plik wykonywalny (binarny), wywołaj
add_library
lubadd_executable
. W argumentach podaj listę plików źródłowych zawierających pliki.asm
dla programu asemblera w YASM oraz pliki.c
dla powiązanych bibliotek lub funkcji C.
Ten fragment kodu pokazuje, jak skonfigurować CMakeLists.txt
, aby tworzyć program YASM jako udostępnioną bibliotekę.
cmake_minimum_required(VERSION 3.6.0)
enable_language(ASM_NASM)
add_library(test-yasm SHARED jni/test-yasm.c jni/print_hello.asm)
Przykładowy sposób kompilowania programu YASM jako pliku wykonywalnego znajdziesz w pliku yasmtest w repozytorium git NDK.
Zgłaszanie problemów
Jeśli napotkasz jakiekolwiek problemy z NDK lub jego narzędziem łańcucha narzędzi CMake, zgłoś je za pomocą narzędzia do śledzenia błędów android-ndk/ndk na GitHub. W przypadku problemów z Gradle lub wtyczką Androida do obsługi Gradle zgłoś błąd w Studio.