[NDK] 빌드 환경에 관한 정리

NDK (Native Development Kit Environment) 입니다. 구글은 Java 환경의 SDK 만 가지고 모든 것이 가능할 것이라고 주장했었으나, 몇 버젼 지나지 않아 자신들의 주장을 철회하고 Native C/C++ 프로그램이 가능한 NDK 를 공개했습니다. 

 왜 NDK 를 사용하는가에 관해서는 몇가지 이유가 있겠지만 

 - 빠른 연산을 위해서 (아무래도 C/C++ 이 자바 보다 속도가 빠른것은 주지의 사실입니다) 
 - 수많은 Open Source 들이 아직도 C/C++ 로 되어 있기 때문에


일단 이 두개를 크게 들 수가 있겠습니다. 그렇다고 해서 윈도우 다루는 부분까지 전부 NDK 로 하는 것을 추천하지는 않습니다. 속도가 필요한 부분이나 위에서 언급된 오픈 소스로 만들어진 라이브러리를 응용하는 부분에 사용할 것을 추천합니다. 

 NDK 를 컴파일 하기 위해서 알아야 할 구글에서 만들어둔 Makefile 입니다. Makefile 의 문법을 쓰고 있지만 세세하게 다 작성할 필요 없이 형태에만 맞춰주면 나머지는 빌드스크립트가 알아서 처리를 해 줍니다. 물론 이 방법 말고 OpenSource 를 컴파일하기 위해서는 방법이 따로 필요하지만 그 건 다른 포스트에서 다루기로 하겠습니다. 

 실제로 예제를 따라 만들어 보면 쉽게 이해가 될 것 같습니다. 
 

 NDK 를 개발하기 위한 준비 과정입니다. SDK 와 NDK 를 받아서 적당한 곳에 풀고 SDK 에 관련된 명령을 어디서든 실행할 수 있게 PATH 에 걸어주고, NDK 또한 어디서건 실행이 가능하게 PATH 에 걸어줍니다. 

안드로이드 프로젝트를 만들어줍니다. Eclipse (ADT) 에서도 만들어 줄 수 있지만 저는 기본적으로 Command Line 을 선호하므로 Terminal 에서 만들어 줍니다. 

필수로 입력해야할 내용들입니다. -n 은 프로젝트의 이름 (위에서는 HelloNDK) -t 은 현재 자신의 개발 머신에 설치되어 있는 SDK 버젼의 id 입니다. -k 는 패키지 명입니다. (위에서는 com.comjuck) -a 는 Activity 의 이름입니다. 

 디자인 부분을 손봐줍니다. 그냥 간단하게 TextView 하나 생성해 줍니다. 

 MainActivity 에서 Layout 에서 만들어준 TextView 에 NativeCode 에서 리턴한 문자열을 출력하는 예제를 만들 예정입니다. 따라서 위와 같이 작성해주면 됩니다. 

 실제로 Android 프로젝트를 빌드하는 과정입니다. 그냥 위 명령 그대로 입력하면 컴파일 될 것입니다. 

EDIT: ubuntu 에서 javah 사용시 classpath 를 명시해 줘야 하더군요. 

javah -classpath <android-sdk-path>/platforms/android-20/android.jar:$PROJECT_PATH/bin/classes com.comjuck.MainActivity 


Android 부분이 에러 없이 컴파일 된다고 해도 실제로 Native Code 부분이 없기 때문에 실행하면 에러가 발생합니다. 따라서 Native 부분을 작성해 주는 과정입니다.  javah 명령을 이용해서 header 를 자동으로 생성해 주기로 합니다. javah 는 native 키워드가 붙은 부분에 대해서 자동으로 선언을 만들어 줍니다. (JNI 가 기본으로 제공해 주는 기능입니다) 

그래서 생성된 파일(이름에 주목하면 package 명 + Class 명이 합쳐진 형태)을 $PROJECT_PATH/jni 디렉토리로 복사해줍니다. 

Native 코드들이 위치하는 곳은 $PROJECT_PATH/jni 입니다. 

 Native Code 가 위치해야 하는 $PROJECT_ROOT/jni 에 javah 를 이용해서 생성해준 com_comjuck_MainActivity.h 에 대응하는 Body 를 만들어줍니다. 여기서는 HelloNDK.c 로 만들어 주고 위와 같은 코드를 채워줍니다. 

AndroidManifest.xml 파일을 열어서 이제부터 NDK 를 사용할 것이라는 것을 지정해줘야 합니다. 딱히 해줄것은 없고 minSDKVersion 정보를 최소 14로 맞춰주는 것입니다. 

Native Code를 컴파일 하기 위해서 필요한 Android 용 Makefile 입니다. 현재 지금 있는 것을 컴파일 하기 위해서는 단지 위와 같이 작성해주면 됩니다. 

Android.mk 의 예제입니다. 

LOCAL_PATH 는 ndk-build 가 실행될 때의 위치에 따라서 정보가 다르게 저장되긴 하지만 기본적으로 $PROJECT_ROOT/jni 을 지정하게 되어 있습니다. 

include $(CLEAR_VARS) 는 LOCAL_PATH 를 제외한 모든 LOCAL_ 로 시작되는 변수들이 초기화 됩니다. 왜 필요한가 의문을 가질 수 있지만 여러개의 프로젝트를 컴파일할 때 꼭 필요한 명령입니다. 

LOCAL_CFLAGS 는 추가해줄 컴파일 옵션에 관한 세팅입니다. 

LOCAL_MODULE 은 만들고자 하는 모듈의 이름입니다. 

LOCAL_LDLIBS 는 연결하고자 하는 링크옵션입니다. 

LOCAL_SRC_FILES 는 컴파일 될 대상인 소스파일들의 리스트입니다. 여기에 나열만 해주는 것으로 알아서 처리가 됩니다. 

include $(BUILD_SHARED_LIBRARY) 는 shared object (so 파일) 을 생성하기 위한 명령입니다. BUILD_STATIC_LIBRARY 는 static object (a 파일)을 만들어주기 위한 명령입니다. 

$PROJECT_ROOT 나 jni 디렉토리에서 ndk-build 만 입력하면 컴파일 됩니다. 그리고 다시 $PROJECT_ROOT 에 가서 ant -e debug 를 입력하셔서 다시 컴파일 해주시면 됩니다. 

여러가지 방법이 있겠지만 Command Line 을 이용하자면 

$ ant -e installd


를 이용하면 Device 에 인스톨 됩니다.