테스트 환경은 JDK1.6.20, Eclipse 3.5, Android SDK 2.2, Android NDK r4-windows 이구요.
음.. http://micropilot.tisory.com/1522 보고 그대로 따라했는데, 런타임에 UnsatisfiedLinkError가 발생합니다.
구현파일에서 함수 이름도 제대로 했다고 생각하구요a
- NdkHello.c
#include "NdkHello.h"
#include <string.h>
jstring Java_android_ndk_test_hello_NdkHello_getMsgFromJni(JNIEnv* env, jobject thiz)
{
return (*env)->NewStringUTF(env, "This message is from Native module");
}
음.. javah로 헤더도 만들었고, ndk-build로 so 파일도 잘 만들어졌어요.
근데,
package android.ndk.test.hello;
import android.app.Activity;
import android.os.Bundle;
import android.widget.TextView;
public class NdkHelloActivity extends Activity {
/** Called when the activity is first created. */
NdkHello ndkHello;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
ndkHello = new NdkHello();
TextView tv = (TextView)findViewById(R.id.textView);
tv.setText(ndkHello.getMsgFromJni());
}
}
마지막줄에 ndkHello.getMsgFromJni() 실행할 때 에러가 나네요. ㅠ
로그캣 보면
09-02 07:44:33.428: DEBUG/dalvikvm(528): No JNI_OnLoad found in /data/data/android.ndk.test.hello/lib/libHelloLibrary.so 0x43e380d0, skipping init
09-02 07:44:35.780: WARN/dalvikvm(528): No implementation found for native Landroid/ndk/test/hello/NdkHello;.getMsgFromJni ()Ljava/lang/String;
09-02 07:44:36.842: DEBUG/AndroidRuntime(528): Shutting down VM
09-02 07:44:36.842: WARN/dalvikvm(528): threadid=1: thread exiting with uncaught exception (group=0x4001d800)
09-02 07:44:36.960: ERROR/AndroidRuntime(528): FATAL EXCEPTION: main
09-02 07:44:36.960: ERROR/AndroidRuntime(528): java.lang.UnsatisfiedLinkError: getMsgFromJni
09-02 07:44:36.960: ERROR/AndroidRuntime(528): at android.ndk.test.hello.NdkHello.getMsgFromJni(Native Method)
09-02 07:44:36.960: ERROR/AndroidRuntime(528): at android.ndk.test.hello.NdkHelloActivity.onCreate(NdkHelloActivity.java:18)
09-02 07:44:36.960: ERROR/AndroidRuntime(528): at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1047)
09-02 07:44:36.960: ERROR/AndroidRuntime(528): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2627)
09-02 07:44:36.960: ERROR/AndroidRuntime(528): at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2679)
09-02 07:44:36.960: ERROR/AndroidRuntime(528): at android.app.ActivityThread.access$2300(ActivityThread.java:125)
09-02 07:44:36.960: ERROR/AndroidRuntime(528): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2033)
09-02 07:44:36.960: ERROR/AndroidRuntime(528): at android.os.Handler.dispatchMessage(Handler.java:99)
09-02 07:44:36.960: ERROR/AndroidRuntime(528): at android.os.Looper.loop(Looper.java:123)
09-02 07:44:36.960: ERROR/AndroidRuntime(528): at android.app.ActivityThread.main(ActivityThread.java:4627)
09-02 07:44:36.960: ERROR/AndroidRuntime(528): at java.lang.reflect.Method.invokeNative(Native Method)
09-02 07:44:36.960: ERROR/AndroidRuntime(528): at java.lang.reflect.Method.invoke(Method.java:521)
09-02 07:44:36.960: ERROR/AndroidRuntime(528): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:868)
09-02 07:44:36.960: ERROR/AndroidRuntime(528): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:626)
09-02 07:44:36.960: ERROR/AndroidRuntime(528): at dalvik.system.NativeStart.main(Native Method)
이런식으로 UnsatisfiedLinkError 가 뜨네요.. ㅠ
구글링했더니 ClassPath 를 어떻게 지정해 줘야한다는 말도 있던데 그건 잘 몰라서;;;
고수님들 도와주세요. ㅠ
- 공지사항 보고 수정 및 추가합니다.
다시 이리저리 하다보니까 .c file은 잘 동작하네요.
그런데 제가 영상처리를 해야해서.. C++ 언어로 구현한 파일을 돌렸으면 하는데요,
- NdkHello.cpp
#include "NdkHello.h"
#include <string.h>
jstring Java_android_ndk_test_hello_NdkHello_getMsgFromJni(JNIEnv* env, jobject thiz)
{
return env->NewStringUTF("This message is from Native module");
}
이렇게 만든 Cpp 파일을 가지고 Android.mk 파일을 아래와 같이 수정하고,
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := HelloLibrary
LOCAL_SRC_FILES := NdkHello.cpp
include $(BUILD_SHARED_LIBRARY)
다시 ndk-build clean 후에 다시 ndk-build 해서 so 파일을 만들어서 실행했는데요,
Cpp 파일로 했을때만 에러가 나네요. ㅠㅠ
C에서 CPP 함수를 호출하는 형식으로 짜세요.
JAVA - NDK C - CPP 이런식으로 말이죠.
실제로 왜 CPP가 다이렉트로 안불려지는가에 대해서 설명을 조금 드리면...
CPP는 빌드 옵션을 특별히 주지 않으면 함수들의 심볼을 변형해서 처리합니다. (맹글링이라고 한다던데요...)
gdb 같은걸로 리스트 때려보면 금방 알수 있지요...
반면에 C는 맹글링을 하지 않습니다. 따라서 같은 이름이라도 호출 할수 없게 되는겁니다.