zoukankan      html  css  js  c++  java
  • 转载JNI(Windows) 规格严格

    Windows平台上使用MinGW GCC编译JNI动态链接库会在Java加载的时候出错,本文简单介绍其中的原因和应对策略。这里只是简单示范如何用MinGW GCC去编译JNI程序

    第一步:编写java程序

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    
    //Test.java
    public class Test {
    	public static native void print();
    	static {
    		System.loadLibrary("hello");
    	}
     
    	public static void main(String[] args) {
    		//打印Java加载DLL文件路径,应该包括当前目录,也就是"."
    		//System.out.
    		//println(System.getProperty("java.library.path"));
    		Test.print();
    	}
    }

    注意其中的代码:public static native void print();

    意思是声明print()这个方法是本地方法而且是静态方法哦,需要在jni中实现。

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

    意思是载入库文件,意味着我们下面的jni程序最终需要打包成hello.dll

    第二步:编译java程序

    javac Test.java

    第三步:生成头文件

    javah -classpath .\bin -d src Test

    -classpath .\bin是指定Test.class文件在当前目录的子目录bin里面

    -d src 是指把生产的Test.h文件放到当前目录下的src子目录下面

    第四步:编写本地实现代码

    我们打开第三步生成的Test.h这个文件,找到其中的方法声明:

    JNIEXPORT void JNICALL Java_Test_print(JNIEnv *, jobject);

    这是jni的命名规范,具体可以参考java tutorial。这里只是方法声明,现在我们来实现它。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    
    /* Test.cpp */
    #include "Test.h"
    #include <iostream>
    using namespace std;
     
    JNIEXPORT void JNICALL Java_Test_print(JNIEnv *, jclass)
    {
    	cout<<"Cpp,Java and JNI~"<<endl;
    }

    第五步:创建库文件

    前面第一步里面提到过hello.dll,这里利用以前提到的制作动态库的命令来生成它:

    g++ -I%JAVA_HOME%\include -I%JAVA_HOME%\include\win32 -shared -o hello.dll Test.cpp

    运行:java Test

    不好,出错了:

    Exception in thread "main" java.lang.UnsatisfiedLinkError: print

    at Test.print(Native Method)

    at Test.main(HelloWorld.java:11)

    意思是库文件已经成功载入了,但是没有找到相匹配的print这个方法。可是我们明明实现了这个方法的呀?原来程序在调用动态库的时候,没有我们想象中的那么简单,而且不同的编译器做法不一样,windows版java中调用jni遵从的是vc的调用方式,和我们用的MinGW GCC默认格式不一致。我们需要调整一下参数,(注意其中的–kill-at):

    g++ -I%JAVA_HOME%\include -I%JAVA_HOME%\include\win32 -shared -Wl,--kill-at -o hello.dll Test.cpp

    如果你在程序里面没有使用了C++的函数库,那么把g++换成gcc就可以了。另外,也可以把jni.h jni_md.h两个文件拷贝到源文件目录下面,这样的话就可以不用指定-I参数了,编译也更方便一些。例如,我把Test.h,Test.cpp和jni.h jni_md.h放在一起,然后可以使用命令:

    g++ -shared -Wl,--kill-at -o hello.dll Test.cpp

    运行:java Test

    显示:Cpp,Java and JNI~

    运行成功!

  • 相关阅读:
    dotnet 控制台读写 Sqlite 提示 no such table 找不到文件
    dotnet 控制台读写 Sqlite 提示 no such table 找不到文件
    dotnet 控制台 Hangfire 后台定时任务
    dotnet 控制台 Hangfire 后台定时任务
    dotnet 获取指定进程的输入命令行
    dotnet 获取指定进程的输入命令行
    PHP sqrt() 函数
    PHP sinh() 函数
    PHP sin() 函数
    PHP round() 函数
  • 原文地址:https://www.cnblogs.com/diyunpeng/p/1689715.html
Copyright © 2011-2022 走看看