Android NDK는 CMake를 사용하여 애플리케이션의 C 및 C++ 코드를 컴파일하도록 지원합니다. 이 페이지에서는 Android Gradle 플러그인의 ExternalNativeBuild
를 통해서 또는 CMake를 직접 호출할 때 NDK와 함께 CMake를 사용하는 방법을 설명합니다.
CMake 도구 모음 파일
NDK는 도구 모음 파일을 통해 CMake를 지원합니다. 도구 모음 파일은 크로스 컴파일을 위해 도구 모음의 동작을 맞춤설정하는 CMake 파일입니다. NDK에 사용되는 도구 모음 파일은 NDK의 <NDK>/build/cmake/android.toolchain.cmake
에 있습니다.
ABI, minSdkVersion
등과 같은 빌드 매개변수는 cmake
를 호출할 때 명령줄에 제공됩니다. 지원되는 인수 목록은 도구 모음 인수 섹션을 참고하세요.
'새로운' 툴체인 파일
이전 NDK에서는 툴체인 파일의 새로운 구현을 실험했습니다. NDK의 툴체인 파일 사용과 할 수 있습니다. 이로 인해 상당한 양의 행동을 개선하지는 못했지만, 더 이상 이 목표를 추구하지 않습니다.
'새로운' 도구 모음 파일에 '레거시' 파일에 비해 동작 회귀가 있음
툴체인 파일에 포함됩니다. 기본 동작은 권장되는 워크플로입니다. 만약
-DANDROID_USE_LEGACY_TOOLCHAIN_FILE=OFF
를 사용하는 경우 해당 플래그를 삭제하는 것이 좋습니다.
삭제할 수 있습니다 새 툴체인 파일이 레거시와 패리티에 도달하지 못함
툴체인 파일을 포함하므로 동작 회귀가 있을 수 있습니다.
새 툴체인 파일의 사용은 권장하지 않지만 NDK에서 삭제할 계획입니다. 그렇게 하면 새 도구 모음 파일과 기존 도구 모음 파일 간의 동작 차이 안타깝게도 '기존'임을 분명히 하도록 옵션 이름을 실제로는 을 사용하는 것이 좋습니다. Google Meet을 사용해 새 툴체인 파일을 교체하느라 새 툴체인 파일을 교체할 수는 있지만, 문제가 수정되지 않을 수 있으며 대신 마이그레이션해야 합니다
사용
Gradle
externalNativeBuild
를 사용할 때는 CMake 도구 모음 파일이 자동으로 사용됩니다. 자세한 내용은 Android 스튜디오의 C 및 C++ 코드를 프로젝트에 추가 가이드를 참고하세요.
명령줄
Gradle 외부에서 CMake로 빌드할 때는 도구 모음 파일 자체 및 인수를 CMake에 전달해야 합니다. 예:
$ cmake \
-DCMAKE_TOOLCHAIN_FILE=$NDK/build/cmake/android.toolchain.cmake \
-DANDROID_ABI=$ABI \
-DANDROID_PLATFORM=android-$MINSDKVERSION \
$OTHER_ARGS
도구 모음 인수
CMake 도구 모음 파일에 다음 인수를 전달할 수 있습니다. Gradle로 빌드하는 경우 ExternalNativeBuild 문서의 설명대로 android.defaultConfig.externalNativeBuild.cmake.arguments
에 인수를 추가합니다. 명령줄에서 빌드하는 경우 -D
를 사용해 CMake에 인수를 전달합니다. 예를 들어 armeabi-v7a가 Neon으로 빌드되지 않도록 할 수 있습니다.
-DANDROID_ARM_NEON=FALSE
를 전달합니다.
ANDROID_ABI
타겟 ABI입니다. 지원되는 ABI에 관한 자세한 내용은 Android ABI를 참고하세요.
Gradle
Gradle은 이 인수를 자동으로 제공합니다. 이 인수를 build.gradle
파일에서 명시적으로 설정하지 마세요. ABI Gradle의 타겟을 제어하려면 Android ABI의 설명대로 abiFilters
를 사용하세요.
명령줄
CMake는 빌드별 하나의 타겟을 기준으로 빌드합니다. Android ABI 두 개 이상을 타겟팅하려면 ABI별로 한 번씩 빌드해야 합니다. ABI별로 다른 빌드 디렉터리를 사용하여 빌드 간의 충돌을 피하는 것이 좋습니다.
값 | 메모 |
---|---|
armeabi-v7a |
|
armeabi-v7a with NEON |
armeabi-v7a 과 동일합니다. |
arm64-v8a |
|
x86 |
|
x86_64 |
ANDROID_ARM_MODE
armeabi-v7a용 arm 명령을 생성할지 아니면 thumb 명령을 생성할지 지정합니다. 다른 ABI의 경우 영향이 없습니다. 자세한 내용은 Android ABI 문서를 참고하세요.
값 | 메모 |
---|---|
arm | |
thumb | 기본 동작입니다. |
ANDROID_NATIVE_API_LEVEL
ANDROID_PLATFORM의 별칭입니다.
ANDROID_PLATFORM
애플리케이션 또는 라이브러리에서 지원하는 최소 API 수준을 지정합니다. 이 값은 애플리케이션의 minSdkVersion
에 해당합니다.
Gradle
Android Gradle 플러그인을 사용하는 경우 이 값은 애플리케이션의 minSdkVersion
과 일치하는 값으로 자동 설정되며 수동으로 설정해서는 안 됩니다.
명령줄
CMake를 직접 호출하는 경우 사용 중인 NDK가 지원하는 API 수준 중 가장 낮은 수준이 기본값으로 설정됩니다. 예를 들어 NDK r20의 경우 이 값은 API 수준 16으로 기본 설정됩니다.
이 매개변수에는 여러 형식이 허용됩니다.
android-$API_LEVEL
$API_LEVEL
android-$API_LETTER
$API_LETTER
형식을 사용하면 출시와 관련된 번호를 확인하지 않고도 android-N
을 지정할 수 있습니다. 일부 출시에서는 문자 증가 없이 API가 증가했습니다. 이러한 API는 -MR1
접미사를 추가하여 지정할 수 있습니다. 예를 들어 API 수준 25는 android-N-MR1
입니다.
ANDROID_STL
이 애플리케이션에 사용할 STL을 지정합니다. 자세한 내용은 C++ 라이브러리 지원을 참고하세요. 기본적으로 c++_static
이 사용됩니다.
값 | 메모 |
---|---|
c++_shared | libc++의 공유 라이브러리 변형입니다. |
c++_static | libc++의 정적 라이브러리 변형입니다. |
none | C++ 표준 라이브러리 지원이 없습니다. |
system | 시스템 STL입니다. |
CMake 빌드 명령어 이해
CMake 빌드 문제를 디버깅할 때 Android용 크로스 컴파일 시 Gradle에서 사용하는 특정 빌드 인수를 알고 있으면 유용합니다.
Android Gradle 플러그인은 각 ABI-빌드 유형 쌍의 CMake 빌드를 실행하는 데 사용하는 빌드 인수를 build_command.txt
에 저장합니다. 이러한 파일은 다음 디렉터리에 있습니다.
<project-root>/<module-root>/.cxx/cmake/<build-type>/<ABI>/
다음 스니펫은 armeabi-v7a
아키텍처를 타겟팅하는 hello-jni
샘플의 디버깅 가능한 출시를 빌드하는 CMake 인수의 예를 보여줍니다.
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
미리 빌드된 라이브러리 사용
가져와야 하는 미리 빌드된 라이브러리가 AAR로 배포된 경우 스튜디오의 종속 항목 문서를 따라 라이브러리를 가져오고 사용하세요. AGP를 사용하지 않는 경우 https://google.github.io/prefab/example-workflow.html을 따르면 되지만, AGP로 이전하는 것이 훨씬 쉬울 수 있습니다.
AAR로 배포되지 않는 라이브러리의 경우 CMake로 미리 빌드된 라이브러리를 사용하는 방법은 CMake 매뉴얼에서 IMPORTED
타겟에 관한 add_library
문서를 참고하세요.
서드 파티 코드 빌드
CMake 프로젝트의 일부로 서드 파티 코드를 빌드하는 방법에는 여러 가지가 있으며 가장 효과적인 옵션은 상황에 따라 다릅니다. 가장 좋은 방법은 CMake 프로젝트에서 서드 파티 코드를 빌드하지 않는 것입니다. 대신 라이브러리의 AAR을 빌드하여 애플리케이션에서 사용합니다. 이 AAR을 게시할 필요는 없습니다. Gradle 프로젝트 내부에 있으면 됩니다.
이런 방법을 사용할 수 없는 경우 다음 단계를 따르세요.
- 서드 파티 소스를 저장소에 복사하고 add_subdirectory를 사용하여 빌드합니다. 이는 다른 라이브러리도 CMake로 빌드된 경우에만 작동합니다.
- ExternalProject를 정의합니다.
- 라이브러리를 프로젝트와 별개로 빌드하고 미리 빌드된 라이브러리 사용에 따라 미리 빌드된 라이브러리로 가져옵니다.
CMake에서 YASM 지원
NDK는 YASM으로 작성된 어셈블리 코드를 x86 및 x86-64 아키텍처에서 실행하도록 빌드할 수 있게 CMake 지원을 제공합니다. YASM은 x86 및 x86-64 아키텍처용 오픈소스 어셈블러로, NASM 어셈블러에 기반합니다.
CMake로 어셈블리 코드를 빌드하려면 프로젝트의 CMakeLists.txt
에서 다음과 같이 변경합니다.
- 값을
ASM_NASM
으로 설정하여enable_language
를 호출합니다. - 빌드 중인 것이 공유 라이브러리 또는 실행 바이너리 중 무엇인지에 따라
add_library
또는add_executable
을 호출합니다. 인수에서.asm
파일(YASM의 어셈블리 프로그램용) 및.c
파일(연결된 C 라이브러리 또는 함수용)로 이루어진 소스 파일 목록을 전달합니다.
다음 스니펫은 YASM 프로그램을 공유 라이브러리로 빌드하도록 CMakeLists.txt
를 구성하는 방법을 보여줍니다.
cmake_minimum_required(VERSION 3.6.0)
enable_language(ASM_NASM)
add_library(test-yasm SHARED jni/test-yasm.c jni/print_hello.asm)
YASM 프로그램을 실행 파일로 빌드하는 방법의 예는 NDK git 저장소의 yasm 테스트를 참고하세요.
문제 신고
NDK 또는 CMake 도구 모음 파일에 문제가 발생하면 GitHub의 android-ndk/ndk Issue tracker를 통해 보고하세요. Gradle 또는 Android Gradle 플러그인 문제의 경우 대신 Studio 버그를 신고하세요.