CMake 구성

CMake 빌드 스크립트는 CMakeLists.txt로 이름을 지정해야 하는 일반 텍스트 파일이며 CMake가 C/C++ 라이브러리를 빌드하는 데 사용하는 명령어를 포함합니다. 아직 네이티브 소스에 CMake 빌드 스크립트가 없는 경우 빌드 스크립트를 직접 생성하고 적절한 CMake 명령어를 포함해야 합니다. CMake를 설치하는 방법을 알아보려면 NDK 및 CMake 설치 및 구성을 참고하세요.

이 섹션에서는 네이티브 라이브러리를 생성할 때 사용할 소스를 CMake에 알리기 위해 빌드 스크립트에 포함해야 하는 몇 가지 기본 명령어에 관해 설명합니다. 자세한 내용은 CMake 명령어 관련 공식 문서를 참고하세요.

새로운 CMake 빌드 스크립트를 구성한 후에는 Gradle을 구성하여 CMake 프로젝트를 빌드 종속 항목으로 추가해야 Gradle에서 앱의 APK로 네이티브 라이브러리를 빌드하고 패키징할 수 있습니다.

참고: 프로젝트에서 ndk-build를 사용한다면 CMake 빌드 스크립트를 생성할 필요가 없습니다. Android.mk 파일의 경로를 제공하여 기존 네이티브 라이브러리 프로젝트를 포함하도록 간단히 Gradle을 구성할 수 있습니다.

CMake 빌드 스크립트 생성

CMake 빌드 스크립트로 사용할 수 있는 일반 텍스트 파일을 생성하려면 다음 단계를 따르세요.

  1. IDE 왼쪽에서 Project 창을 열고 드롭다운 메뉴에서 Project 뷰를 선택합니다.
  2. your-module의 루트 디렉터리를 마우스 오른쪽 버튼으로 클릭하고 New > File을 선택합니다.

    참고: 원하는 모든 위치에서 빌드 스크립트를 생성할 수 있습니다. 단, 빌드 스크립트를 구성할 때 네이티브 소스 파일 및 라이브러리 경로를 빌드 스크립트의 위치에 상대적인 경로로 지정해야 합니다.

  3. 파일 이름으로 'CMakeLists.txt'를 입력하고 OK를 클릭합니다.

이제 CMake 명령어를 추가하여 빌드 스크립트를 구성할 수 있습니다. CMake가 네이티브 소스 코드에서 네이티브 라이브러리를 생성하도록 지시하려면 다음과 같이 빌드 스크립트에 cmake_minimum_required()add_library() 명령어를 추가합니다.

# Sets the minimum version of CMake required to build your native library.
# This ensures that a certain set of CMake features is available to
# your build.

cmake_minimum_required(VERSION 3.4.1)

# Specifies a library name, specifies whether the library is STATIC or
# SHARED, and provides relative paths to the source code. You can
# define multiple libraries by adding multiple add_library() commands,
# and CMake builds them for you. When you build your app, Gradle
# automatically packages shared libraries with your APK.

add_library( # Specifies the name of the library.
             native-lib

             # Sets the library as a shared library.
             SHARED

             # Provides a relative path to your source file(s).
             src/main/cpp/native-lib.cpp )

도움말: CMake에 소스 파일에서 네이티브 라이브러리를 생성하도록 지시할 수 있는 방법과 마찬가지로 add_executable() 명령어를 사용하여 CMake에 이러한 소스 파일에서 실행 파일을 대신 생성하도록 지시할 수 있습니다. 하지만 네이티브 소스에서 실행 파일을 빌드하는 것은 선택사항이고 네이티브 라이브러리를 빌드하여 APK에 패키징하는 것은 대부분의 프로젝트 요구사항을 충족합니다.

add_library()를 사용하여 CMake 빌드 스크립트에 소스 파일 또는 라이브러리를 추가하면 프로젝트를 동기화한 후 Android 스튜디오의 Project 뷰에 연결된 헤더 파일도 표시됩니다. 그러나, 컴파일 시간 동안 CMake가 헤더 파일을 찾을 수 있도록 다음과 같이 CMake 빌드 스크립트에 include_directories() 명령어를 추가하고 헤더 경로를 지정해야 합니다.

add_library(...)

# Specifies a path to native header files.
include_directories(src/main/cpp/include/)

CMake에서 라이브러리의 파일 이름을 지정하는 데 사용하는 규칙은 다음과 같습니다.

liblibrary-name.so

예를 들어, 빌드 스크립트에서 공유 라이브러리의 이름을 'native-lib'으로 지정하면 CMake에서 libnative-lib.so라는 이름의 파일을 생성합니다. 하지만 자바나 Kotlin 코드에서 이 라이브러리를 로드할 때는 다음과 같이 CMake 빌드 스크립트에 지정한 이름을 사용합니다.

Kotlin

companion object {
    init {
        System.loadLibrary("native-lib");
    }
}

자바

static {
    System.loadLibrary("native-lib");
}

참고: CMake 빌드 스크립트에서 라이브러리 이름을 변경하거나 라이브러리를 삭제한다면 Gradle에서 변경사항을 적용하거나 APK에서 이전 버전의 라이브러리를 삭제하기 전에 프로젝트를 정리해야 합니다. 프로젝트를 정리하려면 메뉴 바에서 Build > Clean Project를 선택합니다.

Android 스튜디오는 소스 파일과 헤더를 Project 창의 cpp 그룹에 자동으로 추가합니다. add_library() 명령어를 여러 번 사용하여 CMake가 다른 소스 파일에서 빌드할 추가 라이브러리를 정의할 수 있습니다.

NDK API 추가

Android NDK에서는 유용할 수 있는 일련의 네이티브 API 및 라이브러리를 제공합니다. 프로젝트의 CMakeLists.txt 스크립트 파일에 NDK 라이브러리를 포함하여 이러한 API를 사용할 수 있습니다.

미리 빌드된 NDK 라이브러리가 이미 Android 플랫폼에 존재하므로 빌드하거나 APK에 패키징하지 않아도 됩니다. NDK 라이브러리는 이미 CMake의 검색 경로에 포함되어 있기 때문에 로컬 NDK 설치에서 라이브러리 위치를 지정할 필요가 없습니다. 즉, 사용하려는 라이브러리 이름을 CMake에 제공하고 자체 네이티브 라이브러리에 연결하기만 하면 됩니다.

CMake 빌드 스크립트에 find_library() 명령어를 추가하여 NDK 라이브러리를 찾고 라이브러리 경로를 변수로 저장합니다. 이 변수를 사용하여 빌드 스크립트의 다른 부분에서 NDK 라이브러리를 참고할 수 있습니다. 다음 샘플은 Android 관련 로그 지원 라이브러리를 찾고 log-lib에 라이브러리 경로를 저장합니다.

find_library( # Defines the name of the path variable that stores the
              # location of the NDK library.
              log-lib

              # Specifies the name of the NDK library that
              # CMake needs to locate.
              log )

네이티브 라이브러리에서 log 라이브러리의 함수를 호출하려면 다음과 같이 CMake 빌드 스크립트에서 target_link_libraries() 명령어를 사용하여 라이브러리를 연결해야 합니다.

find_library(...)

# Links your native library against one or more other native libraries.
target_link_libraries( # Specifies the target library.
                       native-lib

                       # Links the log library to the target library.
                       ${log-lib} )

또한, NDK에는 빌드하여 네이티브 라이브러리에 연결해야 하는 몇 가지 라이브러리가 소스 코드로 포함되어 있습니다. CMake 빌드 스크립트에서 add_library() 명령어를 사용하여 소스 코드를 네이티브 라이브러리로 컴파일할 수 있습니다. 로컬 NDK 라이브러리 경로를 제공하려면 Android 스튜디오에서 자동으로 정의하는 ANDROID_NDK 경로 변수를 사용하면 됩니다.

다음 명령어는 CMake에 NativeActivity 수명 주기 이벤트와 터치 입력을 관리하는 android_native_app_glue.c를 정적 라이브러리로 빌드하라고 지시하며 라이브러리를 native-lib에 연결합니다.

add_library( app-glue
             STATIC
             ${ANDROID_NDK}/sources/android/native_app_glue/android_native_app_glue.c )

# You need to link static libraries against your shared native library.
target_link_libraries( native-lib app-glue ${log-lib} )

미리 빌드된 다른 라이브러리 추가

미리 빌드된 라이브러리를 추가하는 작업은 CMake에서 빌드할 다른 네이티브 라이브러리를 지정하는 작업과 유사합니다. 하지만, 라이브러리가 이미 빌드되어 있으므로 IMPORTED 플래그를 사용하여 라이브러리를 프로젝트로 가져오는 것만 원한다는 사실을 CMake에 알려야 합니다.

add_library( imported-lib
             SHARED
             IMPORTED )

그런 다음 아래와 같이 set_target_properties() 명령어를 사용하여 라이브러리의 경로를 지정해야 합니다.

일부 라이브러리에서는 특정 CPU 구조를 위한 별도의 패키지, 즉 Application Binary Interface(ABI)를 제공한 후 별도의 디렉터리로 구성합니다. 이 접근 방식은 개발자가 원하는 라이브러리 버전만 사용하도록 허용하는 동시에 라이브러리가 특정 CPU 아키텍처를 활용하는 데 도움이 됩니다. 라이브러리 버전별로 여러 명령어를 작성할 필요 없이 여러 ABI 버전의 라이브러리를 CMake 빌드 스크립트에 추가하려면 ANDROID_ABI 경로 변수를 사용하면 됩니다. 이 변수는 NDK에서 지원하는 기본 ABI 목록 또는 Gradle에서 사용하도록 수동으로 구성하는 ABI의 필터링된 목록을 사용합니다. 예:

add_library(...)
set_target_properties( # Specifies the target library.
                       imported-lib

                       # Specifies the parameter you want to define.
                       PROPERTIES IMPORTED_LOCATION

                       # Provides the path to the library you want to import.
                       imported-lib/src/${ANDROID_ABI}/libimported-lib.so )

컴파일 시간에 CMake가 헤더 파일을 찾을 수 있도록 하려면 다음과 같이 include_directories() 명령어를 사용하여 헤더 파일 경로를 포함해야 합니다.

include_directories( imported-lib/include/ )

참고: 예를 들어, imported-lib의 종속 항목인 미리 빌드된 라이브러리를 추가하는 것과 같이 빌드 시간에 종속되지 않는 미리 빌드된 라이브러리를 패키징하려면 다음 안내에 따라 라이브러리를 연결할 필요가 없습니다.

미리 빌드된 라이브러리를 자체 네이티브 라이브러리에 연결하려면 다음과 같이 CMake 빌드 스크립트의 target_link_libraries() 명령어에 추가합니다.

target_link_libraries( native-lib imported-lib app-glue ${log-lib} )

미리 빌드된 라이브러리를 APK에 패키징하려면 sourceSets 블록으로 Gradle을 수동으로 구성하여 .so 파일 경로를 포함해야 합니다. APK를 빌드한 후 APK Analyzer를 사용하여 Gradle이 APK로 패키징한 라이브러리가 무엇인지 확인할 수 있습니다.

다른 CMake 프로젝트 포함

여러 CMake 프로젝트를 빌드하고 Android 프로젝트에 출력을 포함하려면 하나의 CMakeLists.txt 파일을 최상위 CMake 빌드 스크립트(Gradle에 연결한 빌드 스크립트)로 사용하고 CMake 프로젝트를 빌드 스크립트의 종속 항목으로 추가하면 됩니다. 다음 최상위 CMake 빌드 스크립트는 add_subdirectory() 명령어를 사용하여 다른 CMakeLists.txt 파일을 빌드 종속 항목으로 지정한 다음 다른 미리 빌드된 라이브러리에서 한 것과 마찬가지로 출력에 연결합니다.

# Sets lib_src_DIR to the path of the target CMake project.
set( lib_src_DIR ../gmath )

# Sets lib_build_DIR to the path of the desired output directory.
set( lib_build_DIR ../gmath/outputs )
file(MAKE_DIRECTORY ${lib_build_DIR})

# Adds the CMakeLists.txt file located in the specified directory
# as a build dependency.
add_subdirectory( # Specifies the directory of the CMakeLists.txt file.
                  ${lib_src_DIR}

                  # Specifies the directory for the build outputs.
                  ${lib_build_DIR} )

# Adds the output of the additional CMake build as a prebuilt static
# library and names it lib_gmath.
add_library( lib_gmath STATIC IMPORTED )
set_target_properties( lib_gmath PROPERTIES IMPORTED_LOCATION
                       ${lib_build_DIR}/${ANDROID_ABI}/lib_gmath.a )
include_directories( ${lib_src_DIR}/include )

# Links the top-level CMake build output against lib_gmath.
target_link_libraries( native-lib ... lib_gmath )

명령줄에서 CMake 호출

다음 명령어로 CMake를 호출하여 Android 스튜디오 외부에서 닌자 프로젝트를 생성합니다.

cmake
-Hpath/to/cmakelists/folder
-Bpath/to/generated/ninja/project/debug/ABI
-DANDROID_ABI=ABI                               // For example, arm64-v8a
-DANDROID_PLATFORM=platform-version-string      // For example, android-16
-DANDROID_NDK=android-sdk/ndk/ndk-version
-DCMAKE_TOOLCHAIN_FILE=android-sdk/ndk/ndk-version/build/cmake/android.toolchain.cmake
-G Ninja

이 명령어는 Android 실행 라이브러리(.so 파일)를 만드는 데 실행할 수 있는 닌자 프로젝트를 생성합니다. NDK의 CMake 지원을 사용하려면 CMAKE_TOOLCHAIN_FILE이 필요합니다. CMake 3.21 이상에서는 CMake에 내장된 NDK 지원을 대신 사용할 수 있지만, CMake의 Android용 크로스 컴파일 문서에 설명된 대로 다른 변수 그룹을 사용해야 합니다.