CMake

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를 호출할 때 명령줄에 제공됩니다. 지원되는 인수 목록은 도구 모음 인수 섹션을 참고하세요.

사용

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별로 다른 빌드 디렉터리를 사용하여 빌드 간의 충돌을 피하는 것이 좋습니다.

Notes
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_ARM_NEON

armeabi-v7a에 NEON을 사용 설정하거나 사용 중지합니다. 다른 ABI의 경우 영향이 없습니다. 기본값은 API 수준(minSdkVersion 또는 ANDROID_PLATFORM) 23 이상의 경우 true이고 그렇지 않으면 false입니다. 자세한 내용은 Neon 지원 문서를 참고하세요.

메모
TRUE API 수준 23 이상의 경우 기본값입니다.
FALSE API 수준 22 이하의 경우 기본값입니다.

ANDROID_LD

사용할 링커를 선택합니다. lld는 현재 NDK용 실험 단계이며 이 인수로 사용 설정할 수 있습니다.

Notes
lld lld를 사용 설정합니다.
기본값 주어진 ABI에 기본 링커를 사용합니다.

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이 사용됩니다.

Notes
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에서 다음과 같이 변경합니다.

  1. 값을 ASM_NASM으로 설정하여 enable_language를 호출합니다.
  2. 빌드 중인 것이 공유 라이브러리 또는 실행 바이너리 중 무엇인지에 따라 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 버그를 신고하세요.