2010-10-16 145 views
33

我使用的是Ubuntu 10.10如何在linux上爲JNI應用程序編譯動態庫?

這就是我所做的。

Hello.java

class Hello { 
     public native void sayHello(); 

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

     public static void main(String[] args){ 
       Hello h = new Hello(); 
       h.sayHello(); 
     } 
} 

然後我跑了follwing命令:

[email protected]:~/Scrivania/provajni$ javac Hello.java 

[email protected]:~/Scrivania/provajni$ javah -jni Hello 

我獲得Hello.classHello.h

Hello.h

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

#ifndef _Included_Hello 
#define _Included_Hello 
#ifdef __cplusplus 
extern "C" { 
#endif 
/* 
* Class:  Hello 
* Method: sayHello 
* Signature:()V 
*/ 
JNIEXPORT void JNICALL Java_Hello_sayHello 
    (JNIEnv *, jobject); 

#ifdef __cplusplus 
} 
#endif 
#endif 

然後創建HELLO.CPP

#include <jni.h> 
#include "Hello.h" 
#include <iostream> 

using namespace std; 

JNIEXPORT void JNICALL Java_Hello_sayHello (JNIEnv *env, jobject obj) { 
     cout << "Hello World!" << endl; 
     return; 
} 

而現在,我想我搞砸了的部分。我這個guide (Compile the Dynamic or Shared Object Library section)啓發

[email protected]:~/Scrivania/provajni$ gcc -I"/usr/lib/jvm/java-6-sun/include" -I"/usr/lib/jvm/java-6-sun/include/linux" -o hellolib.so -shared -Wl,-soname,hello.so Hello.cpp -static -lc 

生成文件hellolib.so

但是,當我嘗試使用java Hello運行它,我有這樣的錯誤:

Exception in thread "main" java.lang.UnsatisfiedLinkError: no hellolib in java.library.path 
at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1734) 
at java.lang.Runtime.loadLibrary0(Runtime.java:823) 
at java.lang.System.loadLibrary(System.java:1028) 
at Hello.<clinit>(Hello.java:4) 
Could not find the main class: Hello. Program will exit. 

我甚至試過這種:

LD_LIBRARY_PATH=`pwd` 
    export LD_LIBRARY_PATH 

沒有結果。

我知道我在做一些非常愚蠢的事情,但我無法弄清楚它是什麼。動態庫是用-shared選項生成的,不是嗎?

更新#1

我試圖static { System.load("/home/dierre/Scrivania/provajni/hellolib.so"); },看看是否能工作,但現在:

Exception in thread "main" java.lang.UnsatisfiedLinkError: /home/dierre/Scrivania/provajni/hello.so: /home/dierre/Scrivania/provajni/hello.so: undefined symbol: _ZSt4cout 
    at java.lang.ClassLoader$NativeLibrary.load(Native Method) 
    at java.lang.ClassLoader.loadLibrary0(ClassLoader.java:1803) 
    at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1699) 
    at java.lang.Runtime.load0(Runtime.java:770) 
    at java.lang.System.load(System.java:1003) 
    at Hello.<clinit>(Hello.java:4) 

更新#2 好,解決了更新#1問題,我明顯地使用g++ insted gcc。儘管如此,仍然無法使用load方法。我似乎無法告訴它正確的道路。

回答

35

可以使用有效名稱的loadLibrary加載本機庫。例如,lib XXXX .so對於linux系列,您的hellolib.so應該重命名爲libhello.so。 順便說一句,我用jni開發java,我將分離實現和本地接口(.c或.cpp)。

static { 
    System.loadLibrary("hello"); // will load libhello.so 
} 

實施報頭(HelloImpl.h):

#ifndef _HELLO_IMPL_H 
#define _HELLO_IMPL_H 

#ifdef __cplusplus 
     extern "C" { 
#endif 

     void sayHello(); 

#ifdef __cplusplus 
     } 
#endif 

#endif 

HelloImpl.cpp:

#include "HelloImpl.h" 
#include <iostream> 

using namespace std; 

void sayHello() { 
    cout << "Hello World!" << endl; 
    return; 
} 

HELLO.C(我喜歡來編譯C JNI):

#include <jni.h> 
#include "Hello.h" 
#include "HelloImpl.h" 

JNIEXPORT void JNICALL Java_Hello_sayHello (JNIEnv *env, jobject obj) { 
    sayHello(); 
    return; 
} 

最後,我們可以在一些步驟中編譯它們:

  1. 編譯OBJ(生成HelloImpl.o)

g++ -c -I"/opt/java/include" -I"/opt/java/include/linux" HelloImpl.cpp

在步驟2
  • 編譯的.o
  • g++ -I"/opt/java/include" -I"/opt/java/include/linux" -o libhello.so -shared -Wl,-soname,hello.so Hello.c HelloImpl.o -static -lc

    JNI,我們使用g ++來編譯它。這個非常重要。侑可以看到How to mix C and C++

    編譯後,可以檢查函數納米命名:

    $ nm libhello.so |grep say 
    00000708 T Java_Hello_sayHello 
    00000784 t _GLOBAL__I_sayHello 
    00000718 T sayHello 
    

    有一個Java_Hello_sayHello標記T.它不應該您準確等於你的本地方法的名稱。如果一切正常。你可以運行它:

    $ java -Djava.library.path=. Hello 
    Hello World! 
    
    +4

    這對我有用,如果我在上一個編譯步驟中省略「-static」選項。如果我沒有,我得到這個錯誤: /usr/bin/ld:/usr/lib/gcc/x86_64-linux-gnu/4.6.1/crtbeginT.o:重定位R_X86_64_32對着__DTOR_END__不能在製作共享對象時使用;用-fPIC重新編譯 我在這個SO問題中找到了解決方案:http://stackoverflow.com/questions/6634387/c-statically-linked-shared-library – 2012-08-29 20:17:47

    +0

    它工作。謝謝。你能解釋一下這是什麼--Djava.library.path =。你好 – 2015-07-06 17:09:24

    +0

    -Djava.library.path =。指定java應該在哪裏查找libXXX.so文件(。表示當前目錄) – stanm 2015-10-20 17:49:31

    4

    抱怨C++符號不可用。我似乎記得,當我用來做JNI的東西,所有的時候,有問題鏈接在C++庫中,我們總是堅持普通的老C如果你改變你的代碼,以便它的標準C(並重命名文件):

    #include <jni.h> 
    #include "Hello.h" 
    #include <stdio.h> 
    
    JNIEXPORT void JNICALL Java_Hello_sayHello (JNIEnv *env, jobject obj) { 
         printf("Hello World"); 
         return; 
    } 
    

    並編譯

    gcc -I/usr/lib/jvm/java-6-openjdk/include -o libhellolib.so -shared Hello.c 
    

    它的工作原理

    java -Djava.library.path=`pwd` Hello 
    Hello World 
    
    +0

    dierre @ COX:〜/ Scrivania/provajni $ LDD hello.so \t Linux的gate.so.1 =>(0x00b46000) \t libc.so.6的= > /lib/libc.so.6(0x0018d000) \t /lib/ld-linux.so.2(0x00b16000) – dierre 2010-10-16 20:48:48

    +0

    嘗試重命名它.... – 2010-10-16 21:29:48

    +2

    它是gcc而不是g ++。但是我仍然不能使用'loadLibrary',只有'load' – dierre 2010-10-17 11:25:47

    25

    最後我的代碼工作。 這是hello.java

    public class hello { 
        public native void sayHello(int length) ; 
        public static void main (String args[]) { 
        String str = "I am a good boy" ; 
        hello h = new hello() ; 
        h.sayHello (str.length()) ; 
        } 
        static { 
        System.loadLibrary ("hello") ; 
        } 
    } 
    

    你應該編譯爲:

    $ javac hello.java 
    

    創建。h文件,你應該用這個命令:

    $ javah -jni hello 
    

    這是hello.h

    JNIEXPORT void JNICALL Java_hello_sayHello 
    (JNIEnv *, jobject, jint); 
    

    這裏是hello.c

    #include<stdio.h> 
    #include<jni.h> 
    #include "hello.h" 
    
    JNIEXPORT void JNICALL Java_hello_sayHello 
        (JNIEnv *env, jobject object, jint len) { 
        printf ("\nLength is %d", len); } 
    

    要編譯這一點,並創造我們要運行一個共享庫此命令:

    $ gcc -I/usr/lib/jvm/java-6-openjdk/include -o libhello.so -shared hello.c 
    

    然後終於運行此之一:

    $ java -Djava.library.path=. hello 
    
    +1

    當我編譯時,它的工作原理是:'gcc -I/usr/local/jdk1.8.0_91/include/usr/local/jdk1。 8.0_91/include/linux -o libhello.so -shared -fPIC hello.c' – tidy 2016-05-31 06:37:06

    +0

    @tidy您的命令行適用於我,否則Sandipan的示例非常好。 – drlolly 2017-04-24 15:44:40

    相關問題