如何在linux上为JNI应用程序编译动态库?

问题描述:

我使用的是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方法。我似乎无法告诉它正确的道路。

可以使用有效名称的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
  1. 编译的.o
  2. 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

抱怨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

最后我的代码工作。 这是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