Android:NDK:Sample
Windows에서 cygwin의 bash를 사용한 컴파일 방법
컴파일을 위하여 우선, 아래의 환경변수가 설정되어 있어야 한다.
- CYGWIN_HOME: cygwin이 설치된 디렉터리.
- NDK_HOME: NDK가 설치된 디렉터리. (반드시 PATH 변수에 추가해야 한다.)
Android.mk의 기본 구조
Makefile에서 읽는 Android.mk의 기본형은 아래와 같다.
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
# 여기 이후에 추가 설정 정보를 입력해야 한다.
# LOCAL_DEFAULT_CPP_EXTENSION := cpp
LOCAL_MODULE := [LIBRARY_NAME]
LOCAL_SRC_FILES := [SRC_FILES]
# 여기 이전에 추가 설정 정보 입력을 완료해야 한다.
include $(BUILD_SHARED_LIBRARY)
-
$(LOCAL_MODULE)
: 출력되는 라이브러리 파일의 명칭.
(파일이름은 접두사로 lib, 접미사로 .so가 붙는다.) -
$(LOCAL_SRC_FILES)
: 컴파일 해야 하는 소스파일 리스트.
Android.mk Macro List
Makefile에서 읽는 Android.mk에 미리 지정되어있는 매크로는 아래와 같다.
-
$(NDK_PROJECT_PATH)
: ndk 프로젝트 경로. -
$(NDK_APP_APPLICATION_MK)
: ndk-build가 읽을*.mk
파일을 지정한다.
Android.mk에 C/C++사용여부 추가
아래와 같이 CPP 파일 확장자를 추가해야 한다. 주의할 점은 include $(CLEAR_VARS)
이후에 삽입해야 한다. (Cygwin에서 직접 컴파일 할 경우 c는 gcc, cpp는 g++로 컴파일한다.)
Java class에 JNI Library를 연결하는 방법
JNI 라이브러리를 연결하고자 하는 클래스에 아래와 같이 System.loadLibrary()를 사용하여 라이브러리를 불러온다. (주의할 점은 라이브러리 이름은 전두사 lib
와 접미사 .so
를 제거한, Android.mk의 $(LOCAL_MODULE)
과 동일한 이름을 줘야 한다.)
package com.example;
public class TestNdkActivity extends Activity {
static {
System.loadLibrary("libraryname");
}
}
메서드(Method) 연결방법
Java에서 JNI의 C함수를 사용할 때, 아래와 같이 native
키워드를 추가해야 한다.
주의할점은 네이티브(Native)코드 즉, C언어측에서 함수명을 정확히 적어야 하는데, 아래와 같은 조건으로 함수명을 적어야 한다.
- C++를 사용할 경우
extern "C"
를 사용하여 C언어로 만들어야 한다. - C++를 사용할 경우 반환형 앞에
JNIEXPORT
를 추가해야 한다. - C++를 사용할 경우 반환형과 함수명 사이에
JNICALL
를 추가해야 한다. - 함수명은 아래와 같은 순서로 입력한다.
- 접두사로
Java_
를 입력한다. - 패키지명을 차례대로 입력하되, 온점(.)은 밑줄()로 변환한다. (패키지명에 밑줄()또는 붙임표(hyphen; -)를 사용하면 안된다.)
- 사용할 클래스명을 입력한다. (패키지명과 구분하기 위해 앞에 밑줄(_)을 붙인다.)
- 사용할 메서드(Method)명을 입력한다. (패키지명과 구분하기 위해 앞에 밑줄(_)을 붙인다.)
- 접두사로
- 첫 번째 파라미터는
JNIEnv* env
로 고정한다. - 두 번째 파라미터는
jobject thiz
로 고정한다. - 세 번째 파라미터 이후는, Java에서 넘겨줄 파라미터 순서로 사용한다.
Example
이해를 돕기 위하여 한 가지 예를 들어, 아래의 조건을 만족하는 함수를 만들어보겠다.
Language(C++), Package(com.example), class(TestNdkActivity) Method(private native String getJniTestString):
#include <jni.h>
#ifdef __cplusplus
extern "C" {
#endif
JNIEXPORT jstring JNICALL
Java_com_example_TestNdkActivity_getJniTestString(JNIEnv* env, jobject thiz) {
return env->NewStringUTF("Hello, NDK!");
}
#ifdef __cplusplus
}
#endif
C와 C++ 구현부 차이점
NDK를 사용할 경우 C와 C++의 사용방법에 차이점이 있다.
C 구현부:
#include <string.h>
#include <jni.h>
jstring
Java_com_example_hellojni_HelloJni_stringFromJNI( JNIEnv* env, jobject thiz ) {
return (*env)->NewStringUTF(env, "Hello from JNI !");
}
C++ 구현부:
#include <string.h>
#include <jni.h>
JNIEXPORT jstring JNICALL Java_com_example_hellojni_HelloJni_stringFromJNI( JNIEnv* env, jobject thiz ) {
return env->NewStringUTF("Hello, NDK!");
}
Android NDK Samples 소개
- http://developer.android.com/tools/sdk/ndk/overview.html
- http://blog.naver.com/PostView.nhn?blogId=bluekms21&logNo=10141500106
NDK설치시 함께 포함되는 샘플 프로젝트에 대한 설명:
- hello-jni: 네이티브 메서드가 구현된 공유 라이브러리에서 문자열을 불러와 어플리케이션 UI로 띄우는 예제
- two-libs: 동적으로 공유 라이브러리를 로드하고 제공하는 네이티브 메서드를 부르는 예제. 이때 네이티브 메서드는 정적 라이브러리에 구현되어 있고, 공유 라이브러리에 임포트 되어있다.
- san-angeles: 네이티브 OpenGL ES의 API를 써서 3D 그래픽을 렌더링하는 예제. 렌더링 중에는 엑티비티 라이프사이클이 GLSurfaceView Object에 의해 관리된다.
- hello-gl2: OpenGL ES 2.0의 버택스 & 프레그먼트 셰이더를 이용해 삼각형을 렌더링하는 예제.
- hello-neon: cpufeature 라이브러리로 런타임중에 CPU capabilities를 체크하는 예제 (단, CPU가 NEON intrinsics를 지원할 경우) 특별히 이 예제는 C버전(tiny benchmark for a FIR filter loop)과 NEON 최적화 버전 두가지로 구현되어 있다.
- bitmap-plasma: 네이티브에서 어떻게 Android Bitmap Object의 픽셀버퍼를 접근하는지 보여주는 예제.
- native-activity: native-app-glue 정적 라이브러리로 어떻게 네이티브 엑티비티를 만드는지 보여주는 예제.
- native-plasma: 네이티브 엑티비티로 구현된 bitmap-plasma 예제.