hyeon.s
개발로그
hyeon.s
전체 방문자
오늘
어제
  • 분류 전체보기 (150)
    • Web 및 인프라 (1)
      • Web (1)
      • Terraform (2)
      • Docker (1)
    • Android (1)
      • 공부 (28)
      • 트러블슈팅 (12)
      • 프로젝트 개발 (10)
      • Compose (2)
      • 우테코 프리코스 (0)
    • Server (5)
      • 공부 (1)
      • Spring (4)
    • 알고리즘 (68)
      • 문제풀이 (C++,Kotlin) (54)
      • 공부 (13)
    • 디자인 (3)
      • UI (3)
    • Language (5)
      • Kotlin (5)
      • JAVA (0)
    • IT 동아리 (8)
      • UMC 3기 (Android) (7)
      • Sopt 32기 (Android) (1)

Github

글쓰기 / 관리자
hELLO · Designed By 정상우.
hyeon.s

개발로그

[Android/공부] NDK(네이티브 개발 키트) 사용과 ABI 빌드 환경 톺아보기
Android/공부

[Android/공부] NDK(네이티브 개발 키트) 사용과 ABI 빌드 환경 톺아보기

2024. 11. 14. 11:30
728x90

들어가기 전
가상화 솔루션은 x86 환경에 안드로이드 앱을 올린다. 이 때 안드로이드 앱에서 사용한 네이티브로 작성된 라이브러리(.so)가 x86 환경에서는 실행되지 않는 경우가 있었다.

왜 이런 상황이 발생하는지, 어떻게 NDK를 사용 및 빌드해야 해결할 수 있는지를 알아보고자 이 포스팅을 작성하게 되었다.

NDK란?

네이티브 개발 키트(NDK)는 Android에서 C및 C++코드를 사용할 수 있게 해주는 일련의 도구 모음이다.

NDK의 호환 가능한 아키텍처

ARM

  • armeabi-v7a : 32비트 ARM 아키텍처
  • arm64-v8a : 64비트 ARM 아키텍처

x86

  • x86 : 32비트 Intel 아키텍처
  • x86_64 : 64비트 Intel 아키텍처

NDK는 다양한 아키텍처에 대한 지원을 제공하며, 각 아키텍처는 ABI를 통해 정의 된다.
각 ABI는 특정 명령 세트를 지원하며, 이를 통해 개발자는 다양한 기기에서 애플리케이션을 실행할 수 있다.

NDK 통한 라이브러리 빌드 방법

NDK로 C/C++ 코드를 빌드하는 방법은 크게 2가지가 있다.

Make 기반 ndk-build

ndk-build 스크립트를 활용하여 C/C++ 프로젝트를 빌드할 수 있다.

ndk-build 주요 기능

  • 프로젝트 빌드 : Android 애플리케이션에 네이티브 코드 (C/C++ 코드)를 컴파일 하고 링크하여 공유 라이브러리 .so 파일을 생성한다.
  • 구성파일 : 빌드를 위해서 Android.mk, Application.mk 2가지의 구성 파일이 필요하다.

Android.mk : 소스파일, 라이브러리 및 모듈 정보 정의

Application.mk : 빌드 설정 (ex. ABI : 어떤 ABI를 사용할 것인지, 릴리즈/디버그 모드 지정)

ndk-build로 네이티브 코드 빌드 예시

CMake

Gradle과 함께 작동하여 네이티브 라이브러리를 빌드할 수 있다.
Android Gradle 플러그인의 ExternalNativeBuild를 통해서 CMake를 직접 호출하여 사용한다.

→ 다양한 플랫폼 (Android, Linux, Windows, iOS) 지원, 안드로이드 스튜디오 기본 툴인 점에서 ndk-build 보다 CMake를 더 많이 사용한다. 실제로 ndk-build는 레거시 프로젝트로 분류된다.

NDK 사용 위한 CMake 기본 사항

1. NDK, CMake 설치


  • Tools > SDK Manager > SDK Tools 클릭
  • NDK (Side by side) 및 CMake 체크박스 선택 후 설치

2. CMake 빌드 스크립트 작성

  • CMake 빌드 스크립트는 CMakeLists.txt라는 이름으로 지정해야 하는 일반 텍스트 파일이다.
  • CMake가 C/C++ 라이브러리를 빌드하는 데 사용하는 명령어를 포함한다.

CMakeLists.txt 내용

C/C++ 라이브러리를 사용하는 방법에 따라서 내용이 달라진다.
아래 3가지의 케이스에 대해서 어떻게 컴파일 및 빌드를 진행하는지 알아보자.

[ 직접 작성한 소스코드를 라이브러리로 사용 ]

*참고사항 : security library를 만들 때 사용했던 방법

네이티브 코드 (C/C++) 파일을 작성

// 헤더 중략

#define LOG_TAG "AntiDebug"
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)

// 실제 사용 c언어 파일

jboolean detectDebugger() {
 // 중략
}

CMakeLists.txt 내용

  • 소스코드를 라이브러리로 빌드하기 위해서 아래와 같이 작성한다.
cmake_minimum_required(VERSION 3.10.2) // 필요한 최소 CMake 버전 지정

add_library(
        antidebug // 생성 할 라이브러리 이름
        SHARED // SHARED 라이브러리로 지정
        antidebug.c) // 라이브러리로 생성 할 c 코드 파일 

find_library(
        log-lib // 불러올 라이브러리의 경로를 저장할 변수
        log ) // 불러올 라이브러리의 이름

target_link_libraries( // 라이브러리들 연결
        antidebug 
        ${log-lib} )

add_library

  • 빌드 할 라이브러리를 정의한다.
  • 만든 소스코드를 빌드 할 라이브러리 이름을 지정하고, SHARED 라이브러리로 생성한다.
  • 라이브러리로 생성 할 소스 파일을 추가한다.
  • 따라서 antidebug.c 를 → antidebug.so 이름의 공유 라이브러리로 생성한다.

find_library

  • 외부 NDK 라이브러리를 사용하기 위해 라이브러리를 찾아온다.
  • 네이티브 (C/C++)코드에서 log를 사용하기 위해 log 라이브러리를 가져온다.
  • 위 소스코드에서는 log 라이브러리를 가져와 해당 경로를 log-lib에 저장한다.

target_link_libraries

  • 생성된 라이브러리에 다른 라이브러리를 링크한다.
  • antidebug 라이브러리에 사용된 log 라이브러리를 연결하기 위해서 사용된다.
  • antidebug ${log-lib} 로 작성한다. *${log-lib}는 위에서 가져온 log 라이브러리의 경로이다.

라이브러리의 ABI 지정

라이브러리로 컴파일 및 빌드하는 방법에서 abiFilters를 통해 ABI를 지정할 수 있다.
예를 들어 64비트 ABI만 빌드하려면 abiFilters 'arm64-v8a', 'x86_64' 이렇게 지정할 수 있다.

build.gradle

android {
    defaultConfig {
        ndk {
            abiFilters 'arm64-v8a', 'armeabi-v7a', 'x86', 'x86_64'
        }
    }

    externalNativeBuild {
        cmake {
            path "src/main/cpp/CMakeLists.txt"
        }
    }
}
  • 위 예시는 arm64, areabi, x86, x86_64 를 모두 지원하는 라이브러리를 생성하겠다는 뜻이다.
  • ndk abiFilters에서 원하는 ABI를 지정할 수 있다.
  • 이 후 externalNativeBuild 를 통해 작성한 CMakeLists를 연결하면 된다.

→ CMakeLists.txt 에 작성한 빌드 방법으로 abiFilters에 지정한 ABI에 대해 각각 빌드를 수행한다.

  • 이 프로젝트를 apk로 만들면 4개의 ABI에 지원하는 fat APK가 된다.
    • fat APK는 단일 ABI용 바이너리만 포함한 APK 보다 훨씬 크다.
    • 따라서 호환성의 폭은 넓지만 APK가 커진다는 단점이 있다.
  • 생성된 APK 는 abiFilters에 지정된 모든 ABI를 지원하는 기기에서 실행 가능하다.
  • APK가 설치될 때, 시스템은 기기의 주 ABI에 맞는 네이티브 라이브러리를 선택하여 사용한다.

[ NDK API (이미 컴파일 된 NDK 라이브러리) 사용 ]

Android NDK에서는 일련의 네이티브 API 및 라이브러리를 제공한다. 이미 컴파일 되어있기 때문에, 사용하려는 라이브러리의 이름을 CMake에 제공하고, 자체 네이티브 라이브러리와 연결하기만 하면 된다.

https://developer.android.com/ndk/guides/stable_apis?hl=ko 

CMakeLists.txt 내용

예시 : 작성한 네이티브 프로젝트에서 OpenGRL ES (NDK라이브러리 중 하나)를 사용

add_library(
        openGRLexample // 생성 할 라이브러리 이름
        SHARED // SHARED 라이브러리로 지정
        openGRLexample.c) // 라이브러리로 생성 할 작성한 c 코드 파일 

find_library(
    GLESv2-lib // GLES 라이브러리 경로를 해당 변수에 저장한다.
    GLESv2 // GLES 라이브러리를 가져온다.
)

target_link_libraries( //연결 할 라이브러리 작성
    openGRLexample // 생성 할 나의 라이브러리
    ${GLESv2-lib} // GLES 라이브러리 연결
)

find_library

  • 외부 NDK 라이브러리를 사용하기 위해 라이브러리를 찾아온다.
  • 네이티브 (C/C++)코드에서 GLESv2를 사용하기 위해 GLESv2라이브러리를 가져온다.
  • 위 소스코드에서는 GLESv2 라이브러리를 가져와 해당 경로를 GLESv2-lib에 저장한다.

target_link_libraries

  • 생성된 라이브러리에 다른 라이브러리를 링크한다.
  • openGRLexample (예시) 라이브러리에 사용된 GLESv2 라이브러리를 연결하기 위해서 사용된다.

이미 컴파일된 시스템 라이브러리이므로 add_library에서는 GLESv2를 넣지 않아도 된다.

[ 이미 빌드된 라이브러리 사용 ]

이미 미리 컴파일된 서드파티 라이브러리를 추가하는 방법이다.

  • 해당 서드파티 라이브러리가 빌드되었을 때 지정한 ABI에 대해서만 지원한다.
    → 즉 서드파티 라이브러리가 x86 ABI를 지정하여 빌드했다면, 해당 ABI에서만 실행 가능하다.

CMakeLists.txt 내용

add_library(example-lib SHARED **IMPORTED**)
set_target_properties(example-lib PROPERTIES IMPORTED_LOCATION
    ${CMAKE_SOURCE_DIR}/../jniLibs/${ANDROID_ABI}/libexample.so)
  • 라이브러리 파일 app/src/main/jniLibs/[ABI]/ 디렉토리에 위치
  • libexample.so 파일을 프로젝트에 추가하기 위해 CMakeLists.txt를 작성해야 한다.

add_library

  • 추가하고자 하는 라이브러리의 이름을 작성한다.
  • example-lib SHARED
  • 이미 빌드된 서드파티 라이브러리 이므로 IMPORTED를 지정한다.

set_target_properties

  • 추가하고자 하는 라이브러리의 이름과 .so 파일의 위치를 작성한다.
  • ${CMAKE_SOURCE_DIR}/../jniLibs/${ANDROID_ABI}/libexample.so
  • 해당 프로젝트를 실행하면 ANDROID_ABI 에 빌드 당시에 지정한 ABI가 들어가는 곳이다.
  • 실행시키는 환경에서 ANDROID_ABI 디렉토리에 파일이 없을 경우 빌드되지 않는다.
  • 서드파티 라이브러리를 안드로이드에서 사용하는 방법 또한 JNI를 통해서 사용하면 된다.
  • Java/Kotlin에서 네이티브 메서드 선언한 후 일반 메소드 처럼 호출하면 된다.

 

참고 레퍼런스

 

CMake  |  Android NDK  |  Android Developers

이 페이지는 Cloud Translation API를 통해 번역되었습니다. CMake 컬렉션을 사용해 정리하기 내 환경설정을 기준으로 콘텐츠를 저장하고 분류하세요. Android NDK는 CMake를 사용하여 애플리케이션의 C 및 C

developer.android.com


 

Android ABI  |  Android NDK  |  Android Developers

이 페이지는 Cloud Translation API를 통해 번역되었습니다. Android ABI 컬렉션을 사용해 정리하기 내 환경설정을 기준으로 콘텐츠를 저장하고 분류하세요. 다양한 Android 기기는 각기 다른 CPU를 사용하

developer.android.com

 

Android ABI  |  Android NDK  |  Android Developers

이 페이지는 Cloud Translation API를 통해 번역되었습니다. Android ABI 컬렉션을 사용해 정리하기 내 환경설정을 기준으로 콘텐츠를 저장하고 분류하세요. 다양한 Android 기기는 각기 다른 CPU를 사용하

developer.android.com

728x90
저작자표시 (새창열림)

'Android > 공부' 카테고리의 다른 글

[Android/공부] Compose로 UI 적용기 -1  (0) 2024.10.14
[Android] MockWebServer란? : okhttp mockwebserver  (0) 2024.09.25
[Android] MockWebServer로 Mock API 활용하기  (2) 2024.09.25
[Android] XML 과 Compose 렌더링 방식의 차이  (0) 2024.09.23
[Android/공부] 안드로이드 라이브러리 / AAR 만들기  (0) 2024.07.17
'Android/공부' 카테고리의 다른 글
  • [Android/공부] Compose로 UI 적용기 -1
  • [Android] MockWebServer란? : okhttp mockwebserver
  • [Android] MockWebServer로 Mock API 활용하기
  • [Android] XML 과 Compose 렌더링 방식의 차이
hyeon.s
hyeon.s
이유있는 코드를 짜자

티스토리툴바