2017-10-26 5 views
-1

Hyのみんな!JNI C++のクラスUnsatisfieldLinkError

は、私はここでJNIについてあまりにも多くのトピックがあります知っているが、私は初心者の聖霊降臨祭JNIいますので、私は新しいものを書くことにしました。

私は、Java層にいくつかのC++クラスにアクセスするためにJNIを記述しようとしていますが、イムは、エラーを取得:

Exception in thread "main" java.lang.UnsatisfiedLinkError: arm.test.lib.FooClass.init(I)V 
    at arm.test.lib.FooClass.init(Native Method) 
    at arm.test.lib.FooClass.<init>(FooClass.java:13) 
    at arm.test.app.Main.main(Main.java:9) 
<end of output> 

私は、次のプロジェクトツリー

source ├── build  ├── CMakeLists.txt ├── foo | ├── src | | ├── foo.cpp | | └── foo.h | ├── include | | └── foo.h -> ../src/foo.h | └── CMakeLists.txt └── java-jni ├── c ├── CMakeLists.txt │   └── jni_wrapper.cpp └── java └── src └── arm └── test ├── app │   └── Main.java └── lib └── FooClass.java

にCMakeListsを持っていますソースフォルダの.txt:

cmake_minimum_required(VERSION 2.8) 
project(java-cpp) 

include_directories(foo) 

option(BUILD_TESTS "Build the test suite (requires foo)" ON) 
if(BUILD_TESTS) 
    enable_testing() 
endif() 

add_subdirectory(foo) 
add_subdirectory(java-jni) 

CMakeLists fooというフォルダから.TXT:

cmake_minimum_required(VERSION 2.8) 
project(foo) 

add_compile_options(-std=c++11) 

set(PROJECT_PATH ${CMAKE_CURRENT_SOURCE_DIR}) 
set(SRCS_PATH  "${PROJECT_PATH}/src") 
set(CPPLIB_INCLUDE_DIR "${PROJECT_PATH}/include" CACHE INTERNAL "foo include directories") 

include_directories(${CPPLIB_INCLUDE_DIR}) 

file(GLOB SRCS "${SRCS_PATH}/*.cpp" "${SRCS_PATH}/*.h") 

add_library(${PROJECT_NAME} SHARED ${SRCS}) 

Fooの単純なクラス、コンストラクタといくつかの機能である...

がfoo.h

#ifndef CLASS_H 
#define CLASS_H 

class Foo { 

private: 
    int m_nb; 

public: 
    Foo(int &n_nb); 
    int getValue() const; 
    void increment(); 

}; 

foo.cpp

#include <iostream> 

#include "foo.h" 


    Foo::Foo(int &n_nb) :m_nb(n_nb) 
    { 
     std::cout << n_nb << std::endl; 
    } 

    int Foo::getValue() const 
    { 
     return this->m_nb; 
    } 

    void Foo::increment() 
    { 
     this->m_nb++; 
    } 

およびJava JNIからCMakeLists.txt

cmake_minimum_required(VERSION 2.8) 

# REQUIRED JAVA 
FIND_PACKAGE(Java COMPONENTS Development) 
INCLUDE(UseJava) 
SET(CMAKE_JAVA_COMPILE_FLAGS "-source" "1.8" "-target" "1.8") 

SET(JAVA_SOURCE_FILES 
arm/test/app/Main.java 
arm/test/lib/FooClass.java) 


# Build Java classes 
FILE(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/java/bin") 
SET(class_files) 
FOREACH(_java_file ${JAVA_SOURCE_FILES}) 
    # _java_file: relative file name 
    # _class_file: relative class name 
    STRING(REGEX REPLACE "\\.java$" 
     ".class" _class_file 
      "${_java_file}") 
    ADD_CUSTOM_COMMAND(
     OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/java/bin/${_class_file}" 
     COMMAND 
      ${Java_JAVAC_EXECUTABLE} 
      ${CMAKE_JAVA_COMPILE_FLAGS} 
      -sourcepath "${CMAKE_CURRENT_SOURCE_DIR}/java/src" 
      -d "${CMAKE_CURRENT_BINARY_DIR}/java/bin" 
      "${CMAKE_CURRENT_SOURCE_DIR}/java/src/${_java_file}" 
     DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/java/src/${_java_file}") 
    LIST(APPEND class_files "java/bin/${_class_file}") 
ENDFOREACH() 

ADD_CUSTOM_TARGET(JavaJNIClasses ALL DEPENDS ${class_files}) 

# Make the JNI header file 
ADD_CUSTOM_COMMAND(
    OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/include/FooClass_jni.h" 
    COMMAND 
     ${Java_JAVAH_EXECUTABLE} 
     -o "${CMAKE_CURRENT_BINARY_DIR}/include/FooClass_jni.h" 
     -classpath "${CMAKE_CURRENT_BINARY_DIR}/java/bin" 
     arm.test.lib.FooClass 
    DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/java/bin/arm/test/lib/FooClass.class") 
ADD_CUSTOM_TARGET(JavaJNIHeaders ALL DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/include/FooClass_jni.h") 

# Require JNI 
FIND_PACKAGE(JNI REQUIRED) 

# Builds the JNI wrapper 
INCLUDE_DIRECTORIES("${CPPLIB_INCLUDE_DIR}" 
        "${CMAKE_CURRENT_BINARY_DIR}/include" 
        ${JNI_INCLUDE_DIRS} 
) 

ADD_LIBRARY(foo_jni SHARED c/jni_wrapper.cpp) 

link_directories("${CMAKE_BINARY_DIR}/foo") 

SET_TARGET_PROPERTIES(
    foo_jni PROPERTIES 
    LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}" 
    LIBRARY_OUTPUT_DIRECTORY_DEBUG "${CMAKE_CURRENT_BINARY_DIR}" 
    LIBRARY_OUTPUT_DIRECTORY_RELEASE "${CMAKE_CURRENT_BINARY_DIR}" 
    RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}" 
    RUNTIME_OUTPUT_DIRECTORY_DEBUG "${CMAKE_CURRENT_BINARY_DIR}" 
    RUNTIME_OUTPUT_DIRECTORY_RELEASE "${CMAKE_CURRENT_BINARY_DIR}") 

TARGET_LINK_LIBRARIES(foo_jni foo) 

ADD_DEPENDENCIES(foo_jni JavaJNIHeaders) 

# Testing 
IF(BUILD_TESTS) 
    FIND_PACKAGE(Java COMPONENTS Runtime) 
    ADD_TEST(
     NAME run-jni 
     COMMAND 
      "${Java_JAVA_EXECUTABLE}" 
      -cp java-jni/java/bin 
      -Djava.library.path=${CMAKE_CURRENT_BINARY_DIR} 
      arm.test.app.Main 
     WORKING_DIRECTORY "${CMAKE_BINARY_DIR}") 
ENDIF() 

内部のCパスは、JavaのラッパーCです。私は私のこのファイルに生成するJava-jniのjavahは内部cmakeのファイルを実行した

#include "foo.h" 

#include "FooClass_jni.h" 

static jfieldID _get_self_id(JNIEnv *env, jobject thisObj) 
{ 
    static int init = 0; 
    static jfieldID fidSelfPtr; 
    if(!init) 
    { 
     jclass thisClass = env->GetObjectClass(thisObj); 
     fidSelfPtr = env->GetFieldID(thisClass, "self_ptr", "J"); 
    } 
    return fidSelfPtr; 
} 
static Foo *_get_self(JNIEnv *env, jobject thisObj) 
{ 
    jlong selfPtr = env->GetLongField(thisObj, _get_self_id(env, thisObj)); 
    return *(Foo**)&selfPtr; 
} 

static void _set_self(JNIEnv *env, jobject thisObj, Foo *self) 
{ 
    jlong selfPtr = *(jlong*)&self; 
    env->SetLongField(thisObj, _get_self_id(env, thisObj), selfPtr); 
} 


extern "C" JNIEXPORT void JNICALL Java_arm_test_lib_Foo_init(JNIEnv *env, jobject thisObj, jint nb) 
{ 
    Foo *self = new Foo(nb); 
    _set_self(env, thisObj, self); 
} 

extern "C" JNIEXPORT jint JNICALL Java_arm_test_lib_Foo_getValue(JNIEnv *env, jobject thisObj) 
{ 
    Foo *self = _get_self(env, thisObj); 
    return self->getValue(); 
} 

extern "C" JNIEXPORT void JNICALL Java_arm_test_lib_Foo_increment(JNIEnv *env, jobject thisObj) 
{ 
    Foo *self = _get_self(env, thisObj); 
    self->increment(); 
} 

extern "C" JNIEXPORT void JNICALL Java_arm_test_lib_Foo_finalize(JNIEnv *env, jobject thisObj) 
{ 
    Foo *self = _get_self(env, thisObj); 
    if(self != NULL) 
    { 
     delete self; 
     _set_self(env, thisObj, NULL); 
    } 
} 

/* DO NOT EDIT THIS FILE - it is machine generated */ 
#include <jni.h> 
/* Header for class arm_test_lib_FooClass */ 

#ifndef _Included_arm_test_lib_FooClass 
#define _Included_arm_test_lib_FooClass 
#ifdef __cplusplus 
extern "C" { 
#endif 
/* 
* Class:  arm_test_lib_FooClass 
* Method: init 
* Signature: (I)V 
*/ 
JNIEXPORT void JNICALL Java_arm_test_lib_FooClass_init 
    (JNIEnv *, jobject, jint); 

/* 
* Class:  arm_test_lib_FooClass 
* Method: getValue 
* Signature:()I 
*/ 
JNIEXPORT jint JNICALL Java_arm_test_lib_FooClass_getValue 
    (JNIEnv *, jobject); 

/* 
* Class:  arm_test_lib_FooClass 
* Method: increment 
* Signature:()V 
*/ 
JNIEXPORT void JNICALL Java_arm_test_lib_FooClass_increment 
    (JNIEnv *, jobject); 

/* 
* Class:  arm_test_lib_FooClass 
* Method: finalize 
* Signature:()V 
*/ 
JNIEXPORT void JNICALL Java_arm_test_lib_FooClass_finalize 
    (JNIEnv *, jobject); 

#ifdef __cplusplus 
} 
#endif 
#endif 

finaly私はFooClass.java

package arm.test.lib; 

public class FooClass{ 

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

    private long self_ptr; 

    public FooClass(int nb) 
    { 
     init(nb); 
    } 

    private native void init(int nb); 

    public native int getValue(); 

    public native void increment(); 

    protected native void finalize(); 

} 

コードが利用可能である得た:

https://github.com/eduardoaugustojulio/java-cpp-study

よろしく。

+0

コードはここに*利用可能でなければなりません。* – EJP

答えて

0

あなたjni_wrapper.cppは、JavaクラスFooののために書かれていますが、クラスFooClassからそれを使用しようとしています。

+0

うん!あなたは正しいです、ありがとう!私は、関数 'Java_arm_test_lib_Foo'を' Java_arm_test_lib_FooClass'にリネームして作業しました。 – gorn

+0

あなたが答えを受け入れるならば、JNIはもっとうまくいくでしょう;) –

関連する問題