如何在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.class
和Hello.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;
}
最后,我们可以在一些步骤中编译它们:
- 编译OBJ(生成HelloImpl.o)
在步骤2g++ -c -I"/opt/java/include" -I"/opt/java/include/linux" HelloImpl.cpp
- 编译的.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!
抱怨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
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
尝试重命名它.... – 2010-10-16 21:29:48
它是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
这对我有用,如果我在上一个编译步骤中省略“-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
它工作。谢谢。你能解释一下这是什么--Djava.library.path =。你好 – 2015-07-06 17:09:24
-Djava.library.path =。指定java应该在哪里查找libXXX.so文件(。表示当前目录) – stanm 2015-10-20 17:49:31