본문 바로가기

심오한 세상/mobile

Android NDK r4 OVERVIEW.TXT 문서 번역

※ 먼저 말씀드리지만, 저라는 사람 영어 실력 정말 없는 사람입니다. 외국인에게 "앞으로 가세요"를 "쭉~ go" 이렇게 말합니다;;
감안하시고 보세요.

Android NDK Overview

Introduction:

안드로이드 NDK는 안드로이드 app 개발자에게 c/c++ 소스 파일을 컴파일한 native machine code를 그들의 app package에 추가할 수 있도록 제공하는 tool이다.

IMPORTANT:
  안드로이드 NDK는 단지 Cupcake(a.k.a 1.5)과 그 이상의 버전의 플랫폼이 구동되는 안드로이드 시스템에서 사용할 수 있다.

  1.0과 1.1 시스템은 1.5 release에서 발생된 ABI와 toolchain의 미묘한 변화 때문에 구체적으로 제공하지 않는다.


I. Android NDK Goals:
---------------------

안드로이드 VM은 native code에서 구현되어진 메소드를 호출하기 위한 당신의 app의 소스코드를 JNI를 통해서 허락한다. 간단하게, 이 의미는:

  - 당신의 app 소스 코드는 native code에 구현되어진 함수를 지시하기 위해 'native' 키워드와 함께 method를 정의할 것이다.
    E.g.:

      native byte[]  loadFile(String  filePath);

  - 당신은 함수를 구현을 포함하고 있는 native shared library를 제공하고, 당신의 app의 .apk에 포함될 것이다.
    이 library는 "lib<something>.so"처럼 표준 Unix 규약에 따라 명명되어져야하고, 표준 JNI entry point에 포함되어질 것이다.
    For example:

      libFileLoader.so

  - 당신의 app은 명시적으로 library를 load해야한다. 예를 들어 app의 시작위치에서 그것을 load하기 위해, 간단하게 아래의 소스코드에 따라서 추가해야한다.

static {
System.loadLibrary("FileLoader");
}

    여기에서 'lib' prefix 와 '.so' suffix를 사용하지 않는 것을 유의해야한다.


안드로이드 NDK는 당신을 돕는 안드로이드 SDK 보완물이다:

  - ARM CPU가 구동되고 있는 안드로이드 1.5플랫폼에서 구동할 수 있는 JNI와 호환되는 shared library들을 생성한다.

  - 생성된 shared library를 당신의 app 프로젝트 경로의 적절한 위치에 복사하고, 당신의 마지막 sign된 .apk 에 자동적으로 추가되어 질 것이다.

  - NDK의 마지막 revision에서, 우리는 remote gdb connection과 가능한 많은 소스와 symbol 정보를 통해서 당신의 native code를 디버그하는 것을 돕는 tool을 제공할 것이다.

게다가, 안드로이드 NDK는 제공한다:

  - cross-toolchain(compilers, linkers, etc..) : Linux, OS X와 Windows(with Cygwin)에서 native ARM binary를 생성할 수 있다.

  - system header : 안드로이드 플랫폼에 의해 제공되는 안정된 native API 목록
                    이것은 모든 플랫폼의 최근 release에서 제공되는 위해 보증되어지는 정의를 따른다.
                    이것은 "docs/STABLE-APIS.TXT" 파일에 기록되어져 있다.

    IMPORTANT:
안드로이드 시스템에서 대부분의 native system library는 마지막에 업데이트 되거나 release되는 플랫폼에서 멈추거나, 크게 변하거나, 심지어 지워지지 않는다.

  - 컴파일 되어기 위해 필요한 소스나 컴파일 하는 방법을 기록한 매우 짧은 build 파일을 작성하는 것을 개발자들에게 허용한다.
   build 시스템은 복잡한 toolchain/platform/CPU/ABI의 모든 스펙을 처리한다.
   게다가, NDK의 마지막 업데이트는 개발자의 build 파일에서 요구하는 변경없이 toolchain, playform, system interface를 제공할 수 있다.


II. Android NDK Non-Goals:
--------------------------

NDK는 안드로이드 device에서 구동시키는 generic native code를 쓰기 위한 좋은 방법이 없다.
특히, 당신의 앱은 여전히 자바로서 개발될 것이고, "Application Not Responding"을 피하기 위해 적절히 안드로이드 시스템 이벤트를 handle 하거나 안드로이드 앱 life-cycle을 처리할 것이다.

그러나, 적절히 start/stop을 사용한 작은 "application wrapper"와 함께 native code에서 복잡한 앱을 구현하는 것이 가능하다는 것을 기억하라.

이 환경에서 많은 작업은 전형적인 native code에서 필수적으로 흔하지 않는 행동을 개발자로부터 요구되어지기 때문에, JNI의 이해가 높은게 좋습니다.
These include:

  - direct native pointer를 통해서 VM객체의 content에 직접적으로 접근 할 수 없다. 예를 들어 당신은 String 객체의 16-bit 문자 배열에서 loop를 반복하기 위한  pointer를 안전하게 얻을 수 없다.

  - native code가 VM object와 JNI call 사이에서 handles를 유지하기를 원할 때, 명시적인 reference 관리가 요구된다.

NDK는 Android platform에 의해 제공되는 매우 제한된 native API들과 library를 위해 시스템 헤드를 제공한다.
전현적인 android system image는 많은 공유 library를 포함하고 있는데 반하여, 이것은 대폭 업데이트 및 플랫폼의 release 사이에 변경될 수 있는 구현 세부에서 주의해야만 한다.

만약 android system library는 NDK의 header에 의해 명시적으로 제공되어지지 않는 다면, application은 가능한 의존하지 않거나, 다양한 device에서 다음 공지에서 업데이트 하여 리스크를 막아야한다.

선택된 system library는 서서히 안정적인 NDK API를 추가할 것이다.


III. NDK development in practice:
---------------------------------

Android NDK와 함께 native code를 개발할 수 있는 방법에 대한 개략적인 overview 이다:

  1/ native 소스를 "$PROJECT/jni/"에 위치시킨다.

  2/ NDK build 시스템에서 소스를 설명하는 "$PROJECT/jni/Android.mk" 쓴다.
      
LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE := sanangeles

LOCAL_CFLAGS := -DANDROID_NDK \
                            -DDISABLE_IMPORTGL

LOCAL_SRC_FILES := \
    importgl.c \
    demo.c \
    app-android.c \

LOCAL_LDLIBS := -lGLESv1_CM -ldl -llog

include $(BUILD_SHARED_LIBRARY)

  3/ 옵션: build 시스템에서 project에 대해서 더 자세히 기입하기 위해서 "$PROJECT/jni/Application.mk" 를 쓴다.
      비록 시작하지 않아도, 하나 이상의 cpu에 target하거나, compiler/linker flag를 override 할 수 있다
      (자세한 내용은 "docs/APPLICATION-MK.TXT"을 참조하세요).

  4/ 프로젝트 디렉토리나 sub 디렉토리에서 "$NDK/ndk-build" 를 실행함으로써 native code를 build한다.

마지막 단계가 성공적일 경우에,  application의 root project directory에 필요한 stripped 공유 library를 복사할 것이다.
그런 다음 일반적인 수단을 통해서 ".apk"를 생성 해야한다.

이제, 몇 가지 더 자세한 사항을 알아보겠다:


III.1/ Configuring the NDK:
- - - - - - - - - - - - - -

이전 release는 NDK를 configure 하기 위해'build/host-setup.sh' script를 실행했어야했다.
이 단계은 release 4 (a.k.a. NDK r4)에서 제거되었다.


III.2/ Placing C and C++ sources:
- - - - - - - - - - - - - - - - -

native 소스를 "$PROJECT/jni/"에 넣는다.

'$PROJECT'는 android application project의 경로에 해당한다.

'jni'의 content를 구성하는 것은 매우 자유롭다.
디렉토리 이름과 구조는 최종 생성된 application 패키지에 영향을 주지 않을 것이다.
그래서 application 패키지 이름의 경우처럼 'com.<mycompany>.<myproject>'와 같이 mypseudo-unique names를 사용하지 않아도 된다.

C와 C++ 소스는 제공된다. NDK에 의해서 제공되는 기본 C++ 파일의 확장자는 '.cpp'이지만, 다른 확장자도 처리할 수 있다.
(자세한 내용은 'docs/ANDROID-MK.TXT'에서 확인할 수 있다).

'Android.mk' 파일을 적용하는 것은 다른 위치에 있는 소스를 저장하는 것을 가능하게 한다.


III.3/ Writing an Android.mk build script:
- - - - - - - - - - - - - - - - - - - - - -

Android.mk 파일은 NDK build system에서 소스를 설명하기 위해 사용하는 작은 build script이다.
문법은 'docs/ANDROID-MK.TXT' 파일에 자세히 설명되어 있다.

분명하게 말하면, NDK는 각각의 모듈을 다음 중 하나가 될 수 있는 곳으로 소스를 그룹화시킨다:

  - a static library
  - a shared library

하나의 'Android.mk' 안에 여러가지 모듈을 정의할 수 잇고, 각각 정의된 하나의 모듈에 여러가지 'Android.mk' 파일을 쓸 수 있다.

'Android.mk' 파일은 build system에 의해 여러번 parse된다. 따라서 안에 정의되지 않는 특정 변수는 할당되지 않는다.
기본적으로, NDK는 build 다음 script를 찾습니다:

   $PROJECT/jni/Android.mk

만약 서브 디렉토리에 'Android.mk'를 정의하기를 원한다면, 최상위 'Android.mk'에서 명시적으로 서브 디렉토리에서 정의한 것을 포함하고 있어야한다. 이것을 사용하기 위해서 helper 함수가 있다. 즉, include $(call all-subdir-makefiles)를 사용한다.

이 파일은 현재 build 파일 경로의 서브 디렉토리에서 모든 'Android.mk' 파일을 포함하고 있을 것이다.


III.4/ Writing an Application.mk build file (optional):
- - - - - - - - - - - - - - - - - - - - - - - - - - - -

'Android.mk' 파일이 build system에서 모듈을 정의하고 있는 반면에, 'Application.mk' 파일은 application 자체를 표현하고 있다.
이 파일이 무엇인지 이해하기 위해서는 'docs/APPLICATION-MK.TXT' 문서를 확인하면 된다.
이것은 다른 것을 포함하고 있다:

   - application에서 용구되어 지는 정확한 모듈 목록

   - machine code를 생성하기 위한 CPU architecture(s)

  - release나 debug 빌드에 대한 옵션 처럼, 모든 모듈을 build하기 위한 적용하는 명확한 C나 C++ compiler flag와 기타 옵션 정보

이 파일은 선택 사항입니다: 기본적으로 NDK는 'Android.mk'에 있는 모든 모듈(포함된 모든 makefile과 함께)을 build하고 기본 CPU ABI(armeabi) 타겟팅하는 것을 제공할 것이다.

'Application.mk' 를 사용하는 두 가지 방법이 있다:

  - '$PROJECT/jni/' 아래에 놓으면, 'ndk-build' script에 의해 자동적으로 pick up될 것이다.

  -'$NDK/apps/<name>/' 아래에 놓으면된다. 여기서 $NDK는 NDK 설치 경로를 나타낸다. 이후에 NDK 디렉토리로부터 "make APP=<name>"를 실행시키면 된다.

    이 방법은 Android NDK r4 이전에 사용되던 방법이다.
    이것은 호환성의 이유로 아직까지 제공되고 있다.
    하지만 대신에 첫번째 방법을 사용하는 것을 권고한다.
    왜냐하면 그것이 더 간단하고ㅡ NDK 설치 트리의 변경이나 수정이 필요하지 않기 때문이다.

다시 말하면, 이것의 완벽한 설명은 'docs/APPLICATION-MK.TXT'를 확인하면된다.


III.5/ Invoke the NDK build system:
- - - - - - - - - - - - - - - - - -

NDK와 함께 machine code를 build하는 선호되는 방법은 Andoid NDK r4와 함께 소개되어진 'ndk-build'를 사용하는 것이다.
또한 '$NDK/apps' 서브 디렉토리를 만드는 전통적인 두번째 방법을 사용할 수 있다.

양쪽다, 성공적인 build는 application에서 요구하는 최종 stripped binary 모듈(i.e. 공유 library)을 application의 project 경로에 복사할 것이다(unstripped 버전은 디버깅 목적으로 보관하고, device에서는 unstripped binary를 복사할 필요가 없다).


  1: Using the 'ndk-build' command:
  ---------------------------------

  NDK 설치 경로의 최상위에 위치한 'ndk-build' script는 application project 디렉토리('AndroidManifest.xml'위치되어 있는
  곳)나 서브디렉토리로 부터 직접적으로 작동시킨다.
  For example:

    cd $PROJECT
    $NDK/ndk-build

   이것은 NDK build script를 실행시킬 것이고, 자동적으로 build해야할 development system과 application project file을
   결정하기위해 조사할 것이다.

  For example:

    ndk-build
    ndk-build  clean    --> 생성된 binary를 clean
    ndk-build  -B V=1   --> command를 보여주면서 완전하게 다시 build함.

   기본적으로, $PROJECT/jni/Application.mk 아래의 옵션 파일과 요구된 $PROJECT/jni/Application.mk를 기대하고 있다.

   성공하면, project tree에서 적절한 위치로 생성된 binary 모듈(i.e. shared libraries)을 복사할 것이다.
   나중에 안드로이드 application package를 'ant'나 ADT Eclipse 플러그인을 통해서 전부 다시 빌드할 수 있다.

   이 스크립트가 무엇을 하며, 추가적인 옵션이 무엇을 하는지에 대한 자세한 설명은 'docs/NDK-BUILD.TXT'을 살펴보면 된다.


  2: Using the $NDK/apps/<name>/Application.mk:
  ---------------------------------------------

   이 빌드 방법은 Android NDK r4 이전에 단 하나의 방법이었고, 단지 호환성의 이유로 제공되어졌었다.
   최종 NDK 릴리즈에서 legacy지원을 제거할 것이기 때문에, 가능하면 'ndk-build' 명령어를 사용하는 것을 강력하게 추천한다.

   이것은 다음과 같이 요구되어진다:

    1. NDK 설치 디렉토리(project 경로가 아님) 아래에 '$NDK/apps/<name>/' 이름으로 서브 디렉토리 만들기

       '<name>'은 NDK 빌드 시스템에서 application을 나타내기 위한 임의의 이름이다(공백허용 안함).

    2. application 프로젝트 디렉토리를 지시하는 'APP_PROJECT_PATH' 정의가 요구하는  '$NDK/apps/<name>/Application.mk' 쓰기

    3. NDK 설치 경로로 이동하여 최상위 GNUMakefile 실행, as in:

         cd $NDK
         make APP=<name>

   중간에 생성된 파일이 '$NDK/out/apps/<name>/' 아래에 위치하는 것을 제외하고, 첫 번째 방법과 동일한 결과가 될 것이다.

IV. Rebuild your application package:
- - - - - - - - - - - - - - - - - - -

NDK에 의해서 바이너리가 생성된 이후에, 'ant' 명령어를 사용하거나 ADT Eclipse plugin을 이용하여 안드로이드 application package files(.apk)을 다시 빌드해야한다.

안드로이드 SDK 문서를 더 자세히 보길 바란다. 새로운 .apk는 공유 라이브러리를 포함하고 있을 것이고, target device에 package를 설치할 때, 시스템에 의한 설치 시간에 자동으로 풀릴 것이다.


V. Debugging support:
- - - - - - - - - - -

NDK는 'ndk-gdb'라는 helper script를 제공한다. 이것은 application의 native 디버깅 세션에서 쉽게 실행할 수 있다.

Native 디버깅은 단지 안드로이드 2.2나 그 이상이 구동되고 있는 생산 기계에서 수행할 수 있다. 그리고 root 같은 특정 접근을 요구되지 않는다.

더 많은 정보는 'docs/NDK-GDB.TXT' 파일을 살펴보길 바란다.  간단하게 말해서, native 디버깅은 간단한 방법을 따른다:

   1. application을 디버깅할 수 있도록 한다.(e.g. 'AndroidManifest.xml'에서 android:debuggable을 "true"로 설정한다.)

   2. 'ndk-build'와 함께 application을 빌드하고, 'device/emulator'에 설치한다.

   3. application을 실행한다.

   4. application 프로젝트 디렉토리로 부터 'ndk-gdb'를 실행한다.

gdb prompt를 나타난다. 유용한 명령어 목록은 GDB User 메뉴얼을 살펴본다.


이상 Android NDK r4의 OVERVIEW에 대한 번역입니다.
이 문서를 번역하는 중간에 회사에서 안드로이드 개발이 다른분께 가게되어서 더이상 이 내용을 번역할 필요는 없었지만,
기왕 시작한거 마무리 짓고 싶었습니다.
행여 나중에라도 이 내용이 저에게 필요하게 될지도 모르기에..

이 번역에서 도와준 서동영군... 정말 고맙습니다.