2012-02-20 48 views
6

Tôi đang cố gắng sử dụng JNI và nhận được java.lang.UnsatisfiedLinkError. Không giống như hàng triệu câu hỏi khác được hỏi về điều này, tôi có lib trên đường dẫn của tôi, và thậm chí còn thấy sự thay đổi ngoại lệ khi tôi gỡ bỏ nó. Tôi chắc chắn rằng một cái gì đó là sai với dll tôi đã tạo ra, nhưng tôi không chắc chắn những gì.JNI: Thư viện được tìm thấy trên đường dẫn, nhưng phương pháp không phải là (java.lang.UnsatisfiedLinkError)

Đây là mã lớp java của tôi:

package com; 

public class Tune { 
    static { 
     System.loadLibrary("lala"); 
    } 
    public static void main(String[] args) { 
     Tune j = new Tune(); 
     System.out.println("2+6="+j.add(2, 6)); 
    } 
    native public int add(int x,int y); 
} 

Dưới đây là phần rút gọn của javah sản xuất tập tin tiêu đề của tôi:

/* 
* Class:  com_Tune 
* Method: add 
* Signature: (II)I 
*/ 
JNIEXPORT jint JNICALL Java_com_Tune_add 
    (JNIEnv *, jobject, jint, jint); 

Đây là c của tôi ++ mã:

#include <jni.h> 
#include <com_Tune.h> 

JNIEXPORT jint JNICALL Java_com_Tune_add 
    (JNIEnv * env, jobject obj, jint x, jint y) { 
    return x+y; 
    } 

Dưới đây là ngoại lệ thời gian chạy tôi nhận được từ nhật thực:

Exception in thread "main" java.lang.UnsatisfiedLinkError: com.Tune.add(II)I 
    at com.Tune.add(Native Method) 
    at com.Tune.main(Tune.java:9) 

Tôi đọc rằng ngoại lệ trên có nghĩa là DID tìm thư viện "lala", nhưng phương thức "thêm" vẫn chưa được xác định. Điều duy nhất tôi nhìn thấy khác nhau giữa dự án của tôi và hướng dẫn là:

  • Mine sử dụng một gói, thay vì gói mặc định (không nên hướng dẫn thực sự làm được điều này thôi nào chúng ta hãy chuyên nghiệp?!?!)
    • Mỏ có giá trị trả lại.
    • tôi chuyển dll của tôi sau khi nó đã được tạo ra (tôi không nghĩ rằng điều này sẽ phá vỡ nó kể từ khi con đường của tôi được cấu hình.)

Làm thế nào có thể như vậy?

Thông tin khác:

Hệ điều hành: Windows 7
JDK: 1.6.0_31 (cho x86, 32 bit JVM)
C++ IDE: Code :: Blocks (dll được biên soạn tự động bởi Bộ luật :: Blocks IDE)
C++: MinGW32-g ++ (GNU C++)

tôi có jni.h và com_Tune.h trong C: \ _ \ include
tôi có lala.dll trong C: \ _ \ lib

Biến môi trường:
PATH: C: \ Program Files (x86) \ Tập đoàn NVIDIA \ PhysX \ Common;% CommonProgramFiles% \ Microsoft chia sẻ \ Windows Live; C: \ Program Files (x86) \ AMD APP \ bin \ x86_64; C : \ Program Files (x86) \ AMD APP \ bin \ x86;% SystemRoot% \ system32;% SystemRoot%;% SystemRoot% \ System32 \ Wbem;% SYSTEMROOT% \ System32 \ WindowsPowerShell \ v1.0 \; C: \ Chương trình Tệp (x86) \ ATI Công nghệ \ ATI.ACE \ Lõi-Tĩnh; C: \ Ứng dụng;% JAVA_HOME% \ bin; C: \ Program Files \ MySQL \ MySQL Máy chủ 5.5 \ bin;% MAVEN_HOME% \ bin;% HADOOP_INSTALL% \ bin; c: \ Program Files (x86) \ Microsoft SQL Server \ 100 \ Công cụ \ Binn \; c: \ Program Files \ Microsoft SQL Server \ 100 \ Công cụ \ Binn \; c: \ Program Files \ Microsoft SQL Server \ 100 \ DTS \ Binn \; C: \ MinGW \ bin; C: \ Program Files (x86) \ GnuWin32 \ bin; C: _ \ path; C: \ _ \ lib; C: \ Program Files (x86) \ Microsoft Visual Studio 10.0 \ VC \ bin; C: \ _ \ include

+0

mã này dường như đúng. Bạn có thể kiểm tra bảng xuất DLL (tức là với Dependency Walker) và đảm bảo rằng chức năng của bạn có mặt trong xuất khẩu không? – Mersenne

Trả lời

1

Chỉ cần đoán ... là dll của bạn phụ thuộc vào một dll đó không phải là trên con đường? Các mô-đun MinGW thường phụ thuộc vào thư viện thời gian chạy C cụ thể.

+0

ok, tôi đang cố gắng lời khuyên của bạn để sử dụng Dependency walker. Tôi không may mới với C++, và đây là lần đầu tiên tôi nghe nói về walker phụ thuộc. Bạn không chắc chắn cách sử dụng nó để phát hiện các phụ thuộc bị thiếu. Tôi đã mở "lala.dll" với nó, và chọn nút gốc trong cây. Bảng "Pi" trống. Bảng "E" có một mục nhập cho một hàm. Chức năng: Java_com_Tune_add @ 16. Thứ tự: 1 (0x0 0 0 1). Gợi ý: 0 (0x0 0 0 0). Entry Point: 0x0 0 0 0 1 2 5 4. Bạn có thể vui lòng cho tôi biết tôi cần tìm gì không? – msknapp

+0

Ngoài ra, cột "E" có một khối với chữ "C" trong đó, không phải "C++". Có thể đó là vấn đề? – msknapp

+0

Vâng, đúng vậy. Chức năng của bạn được xuất. Dấu "C" là bình thường, "C++" đánh dấu các phương thức của các lớp C++, như tôi biết. Nhìn vào trẻ em trực tiếp của nút gốc. Đó là thư viện được nhập. Chính xác là gì? Đối với trường hợp "đơn giản-phương thức-thư viện" của bạn, phải có ít mục nhập. I E. trong dll thử nghiệm của tôi (cũng với một phương pháp đơn giản) chỉ có hai thư viện. – Mersenne

2

Một nguồn có thể có của prob lem có thể là bạn đã biên dịch mã bằng trình biên dịch C++, sử dụng [quy ước gọi điện] khác với C.Nếu thats trường hợp thì giải pháp sẽ được quấn mã cho phương pháp này trong một khối extern "C" như thế này:

#ifdef __cplusplus 
extern "C" { 
#endif 

JNIEXPORT jint JNICALL Java_com_Tune_add 
... 

#ifdef __cplusplus 
} 
#endif 
+0

cảm ơn vì đã cố giúp đỡ, nhưng tiếc là điều đó không khắc phục được. – msknapp

+0

Tôi nghĩ msknapp đã bỏ qua các chỉ thị tiền xử lý trong câu hỏi của mình. 'javah', công cụ tạo tiêu đề cho JNI, tự động thêm những thứ cần thiết. – Mersenne

+0

Giống như tôi đã nói trong câu hỏi, đầu ra javah được rút ngắn để giữ cho câu hỏi ngắn gọn. Tôi không thay đổi bất cứ thứ gì được sản xuất bởi javah. Nếu bạn thực sự muốn nhìn thấy tất cả của nó, here you go:/* KHÔNG CHỈNH SỬA FILE NÀY - đó là máy tạo */#include /* Tiêu đề cho lớp com_Tune */ #ifndef _Included_com_Tune #define _Included_com_Tune #ifdef __cplusplus extern "C" { #endif /* * class: com_Tune * Phương pháp: thêm * Chữ ký: (II) tôi */ JNIEXPORT jint JNICALL Java_com_Tune_add (JNIEnv *, jobject, jint , jint); #ifdef __cplusplus } #endif #endif – msknapp

4

Vấn đề là với trình biên dịch tên đã tạo: [email protected]

Sử dụng một trong hai

gcc -Wl,-kill-at

Hoặc

gcc -Wl,--add-stdcall-alias

này sẽ đảm bảo hệ của Java_com_Tune_add

Và sau đó cuộc gọi phương thức của bạn sẽ thành công.

+0

Để lưu ý thêm, câu trả lời này là câu trả lời đúng và điều này khắc phục được sự cố của tôi. Tôi nghĩ đây là câu trả lời nên được chấp nhận. Thay vào đó, những người khác đào sâu vào chủ đề này sẽ bị đánh lừa. –

0

Tôi đã gặp vấn đề tương tự và cờ -Wl, -kill-at đã làm việc cho tôi.

0

Hãy thử với theo gương cho Windows: (hãy nhớ rằng tên lớp Java phải giống nhau mà tương ứng với tên file)

Bước 1. Tạo file sau Java (P.java):

class P 
{ 
    static 
    { 
    // "P" is the name of DLL without ".dll" 
    System.loadLibrary ("P"); 
    } 

    public static native void f(int i); 

    public static void main(String[] args) 
    { 
    f(1); 
    } 
} 

Bước 2. javac P.java

Bước 3. javah P

Sau đó, "javah" tạo ra các tập tin tiêu đề "Ph"

Bước 4. Tạo file "sức phòng thủ vật" bao gồm hai dòng sau đây (file này định nghĩa những biểu tượng xuất khẩu, trong trường hợp này tên của chức năng C):

EXPORTS 
Java_P_f 

Bước 5. Tạo của bạn tập tin C (Pc):

#include "P.h" 

JNIEXPORT void JNICALL Java_P_f(JNIEnv *env, jclass c, jint i) 
{ 
    printf("%i\n",i); 
} 

Bước 6. trong thời hạn thị giác lệnh Studio promt, xác định các biến sau:

bộ JAVA_HOME = con đường của JDK

.210

bộ include =% bao gồm%;% JAVA_HOME% \ include;% JAVA_HOME% \ include \ win32

Bước 7. Tạo DLL:

cl/LD Pc sức phòng thủ vật

Bước 8 . Chạy chương trình Java:

java P

(Lưu ý: P.dll và P.class đều nằm trong cùng thư mục)

Các vấn đề liên quan