代码之家  ›  专栏  ›  技术社区  ›  dierre

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

  •  36
  • dierre  · 技术社区  · 15 年前

    我在用 Ubuntu 10.10版

    程序过程 :

    class Hello {
            public native void sayHello();
    
            static { System.loadLibrary("hellolib"); }
    
            public static void main(String[] args){
                    Hello h = new Hello();
                    h.sayHello();
            }
    }
    

    然后我执行以下命令:

    dierre@cox:~/Scrivania/provajni$ javac Hello.java
    
    dierre@cox:~/Scrivania/provajni$ javah -jni Hello 
    

    我得到了 Hello.class Hello.h

    你好,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
    

    你好,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) :

    dierre@cox:~/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++ 仪表 gcc load 但是方法。我好像不能告诉它正确的道路。

    3 回复  |  直到 15 年前
        1
  •  40
  •   qrtt1    15 年前

    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
    

    #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

    1. 用.o编译jni

    g++-I“/opt/java/include” -Wl,-soname,hello.so hello.c HelloImpl.o-static-lc

    在步骤2中,我们使用g++来编译它。这很重要。你能看见 How to mix C and C++

    编译完成后,可以用nm检查函数命名:

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

    $ java -Djava.library.path=. Hello
    Hello World!
    
        2
  •  31
  •   Matthieu    12 年前

    最后我的代码起作用了。 我是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 
    

    $ 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
    
        3
  •  5
  •   Gordon Thompson    15 年前

    这抱怨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
    
    推荐文章