在JNI中链接dll文件

时间:2017-08-27 12:28:34

标签: java c++ makefile java-native-interface

我正在学习使用JNI,但我遇到了一些麻烦...

我正在使用eclipse进行java和c ++,我正在使用makefile来编译c ++文件。

当我尝试在c ++中使用多个类时,所有问题都开始了。

错误代码:

Exception in thread "main" java.lang.UnsatisfiedLinkError: C:\Users\Balinator\workspace\HelloJNI\jni\hello.dll: Can't find dependent libraries
    at java.lang.ClassLoader$NativeLibrary.load(Native Method)
    at java.lang.ClassLoader.loadLibrary0(Unknown Source)
    at java.lang.ClassLoader.loadLibrary(Unknown Source)
    at java.lang.Runtime.loadLibrary0(Unknown Source)
    at java.lang.System.loadLibrary(Unknown Source)
    at HelloJNI.<clinit>(HelloJNI.java:5)

它说“找不到依赖库”,但hello.dll实际存在于路径“C:\ Users \ Balinator \ workspace \ HelloJNI \ jni \ hello.dll”下。 我试图修改makefile,认为存在问题,但没有成功。我对makefile-s不太满意,但我没有在代码本身中发现问题。

我定义了一个VM变量:

-Djava.library.path=jni

这是来源:

Java代码:

HelloJNI.java:

public class HelloJNI {
    static {
        // hello.dll on Windows or libhello.so on Linux
        System.loadLibrary("hello");
    }

    private native int sayHello(int num);

    public native int intMethod(int num);

    public native boolean booleanMethod(boolean booleanb);

    public native String stringMethod(String s);

    public native int intArrayMethod(int[] array);

    private void runSimple() {
        System.out.println("intMethod: " + intMethod(5));
        System.out.println("booleanMethod: " + booleanMethod(true));
        System.out.println("stringMethod: " + stringMethod("str"));
        System.out.println("intArrayMethod: " + intArrayMethod(new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }));
    }

    public native int getAgeC(Employee emp);

    public native Employee createWithAge(int age);

    private void runComplex() {
        Employee emp = new Employee(32);

        System.out.println("Pass employee to C and get age back: " + getAgeC(emp));

        Employee emp2 = createWithAge(23);

        System.out.println("Get employee object from C: " + emp2.getAge());
    }

    public native void speedTest(int num);

    private void speedTest() {
        long time;
        Employee e;

        int num = 1000000;

        System.out.println("Java call!");
        time = System.currentTimeMillis();
        e = new Employee(20);
        for (int i = 0; i < num; ++i) {
            e.getAge();
        }
        System.out.println("Time = " + (System.currentTimeMillis() - time));

        System.out.println("Mixed call!");
        time = System.currentTimeMillis();
        e = createWithAge(20);
        for (int i = 0; i < num; ++i) {
            getAgeC(e);
        }
        System.out.println("Time = " + (System.currentTimeMillis() - time));

        System.out.println("C++ call!");
        time = System.currentTimeMillis();
        speedTest(num);
        System.out.println("Time = " + (System.currentTimeMillis() - time));
    }

    public static void main(String[] args) {
        // invoke the native method

        HelloJNI h = new HelloJNI();
        for (int i = 0; i < 10; ++i) {
            System.out.println("From java = " + h.sayHello(i));
        }

        h.runSimple();
        h.runComplex();

        h.speedTest();
    }
}

Employee.java:

public class Employee {
    private int age;

    public Employee(int age) {
        this.age = age;
    }

    public int getAge() {
        return age;
    }
}

c ++代码:

HelloJNI.h:

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

#ifndef _Included_HelloJNI
#define _Included_HelloJNI
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     HelloJNI
 * Method:    sayHello
 * Signature: (I)I
 */
JNIEXPORT jint JNICALL Java_HelloJNI_sayHello
  (JNIEnv *, jobject, jint);

/*
 * Class:     HelloJNI
 * Method:    intMethod
 * Signature: (I)I
 */
JNIEXPORT jint JNICALL Java_HelloJNI_intMethod
  (JNIEnv *, jobject, jint);

/*
 * Class:     HelloJNI
 * Method:    booleanMethod
 * Signature: (Z)Z
 */
JNIEXPORT jboolean JNICALL Java_HelloJNI_booleanMethod
  (JNIEnv *, jobject, jboolean);

/*
 * Class:     HelloJNI
 * Method:    stringMethod
 * Signature: (Ljava/lang/String;)Ljava/lang/String;
 */
JNIEXPORT jstring JNICALL Java_HelloJNI_stringMethod
  (JNIEnv *, jobject, jstring);

/*
 * Class:     HelloJNI
 * Method:    intArrayMethod
 * Signature: ([I)I
 */
JNIEXPORT jint JNICALL Java_HelloJNI_intArrayMethod
  (JNIEnv *, jobject, jintArray);

/*
 * Class:     HelloJNI
 * Method:    getAgeC
 * Signature: (LEmployee;)I
 */
JNIEXPORT jint JNICALL Java_HelloJNI_getAgeC
  (JNIEnv *, jobject, jobject);

/*
 * Class:     HelloJNI
 * Method:    createWithAge
 * Signature: (I)LEmployee;
 */
JNIEXPORT jobject JNICALL Java_HelloJNI_createWithAge
  (JNIEnv *, jobject, jint);

/*
 * Class:     HelloJNI
 * Method:    speedTest
 * Signature: (I)V
 */
JNIEXPORT void JNICALL Java_HelloJNI_speedTest
  (JNIEnv *, jobject, jint);

#ifdef __cplusplus
}
#endif
#endif

HelloJNI.cpp:

/*
 * HelloJNI.cpp
 *
 *  Created on: 2017. aug. 26.
 *      Author: Balinator
 */

#include <jni.h>
#include <cstdio>

#include <string.h>

#include "HelloJNI.h"
#include "Employee.h"

JNIEXPORT jint JNICALL Java_HelloJNI_sayHello(JNIEnv *env, jobject thisObj,
        jint num) {
    printf("Hello World! %d\n", num);
    return num;
}

JNIEXPORT jint JNICALL Java_HelloJNI_intMethod(JNIEnv *env, jobject obj,
        jint num) {
    return num * num;
}

JNIEXPORT jboolean JNICALL Java_HelloJNI_booleanMethod(JNIEnv *env, jobject obj,
        jboolean boolean) {
    return !boolean;
}

JNIEXPORT jstring JNICALL Java_HelloJNI_stringMethod(JNIEnv *env, jobject obj,
        jstring string) {
    const char *str = env->GetStringUTFChars(string, 0);
    char cap[128];
    strcpy(cap, str);
    env->ReleaseStringUTFChars(string, str);
    return env->NewStringUTF(strupr(cap));
}

JNIEXPORT jint JNICALL Java_HelloJNI_intArrayMethod(JNIEnv *env, jobject obj,
        jintArray array) {
    int i, sum = 0;
    jsize len = env->GetArrayLength(array);
    jint *body = env->GetIntArrayElements(array, 0);
    for (i = 0; i < len; i++) {
        sum += body[i];
    }
    env->ReleaseIntArrayElements(array, body, 0);
    return sum;
}

JNIEXPORT jint JNICALL Java_HelloJNI_getAgeC(JNIEnv *env, jobject callingObject,
        jobject employeeObject) {
    jclass employeeClass = env->GetObjectClass(employeeObject);
    jmethodID midGetAge = env->GetMethodID(employeeClass, "getAge", "()I");
    int age = env->CallIntMethod(employeeObject, midGetAge);
    return age;
}

JNIEXPORT jobject JNICALL Java_HelloJNI_createWithAge(JNIEnv *env,
        jobject callingObject, jint age) {
    jclass employeeClass = env->FindClass("LEmployee;");
    jmethodID midConstructor = env->GetMethodID(employeeClass, "<init>",
            "(I)V");
    jobject employeeObject = env->NewObject(employeeClass, midConstructor, age);
    return employeeObject;
}

JNIEXPORT void JNICALL Java_HelloJNI_SpeedTest(JNIEnv *env,
        jobject callingObject, jint num) {
    Employee e(20);
    for(int i = 0; i < num; ++i){
        e.getAge();
    }
}

Employee.h:

/*
 * Employee.h
 *
 *  Created on: 2017. aug. 27.
 *      Author: Balinator
 */

#ifndef JNI_EMPLOYEE_H_
#define JNI_EMPLOYEE_H_

class Employee {
private:
    int age;
public:
    Employee(int age);
    virtual ~Employee();
    int getAge();
};

#endif /* JNI_EMPLOYEE_H_ */

Employee.cpp:

/*
 * Employee.cpp
 *
 *  Created on: 2017. aug. 27.
 *      Author: Balinator
 */

#include "Employee.h"

Employee::Employee(int age):age(age) {}
Employee::~Employee() {}

int Employee::getAge(){
    return age;
}

生成文件:

# Define a variable for classpath
CLASS_PATH = ../bin

# Define a virtual path for .class in the bin directory
vpath %.class $(CLASS_PATH)

cleanbuild: clean all

all : hello.dll

# $@ matches the target, $^ matches all dependancys
hello.dll : HelloJNI.o Employee.o
    g++ -m64 -fpic -shared -o $@ $^

# $@ matches the target, $< matches the first dependancy
HelloJNI.o : HelloJNI.cpp HelloJNI.h
    g++ -m64 -I"C:\Program Files\Java\jdk1.8.0_121\include" -c $< -o $@

# $* matches the target filename without the extension
HelloJNI.h : HelloJNI.class
    javah -classpath $(CLASS_PATH) $*

Employee.o: Employee.cpp Employee.h
    g++ -m64 -c $< -o $@

clean :
    rm HelloJNI.h HelloJNI.o hello.dll Employee.o

0 个答案:

没有答案