gpt4 book ai didi

java - 无法让最简单的 JNI 示例在 Windows 10 上运行

转载 作者:搜寻专家 更新时间:2023-10-31 02:05:44 25 4
gpt4 key购买 nike

对于我正在做的项目,我很快将不得不使用 Java Native 接口(interface)。我试图通过阅读开始使用它 this tutorial在 IBM DeveloperWorks 网站上。

基本上,它告诉我写这个类:

public class Sample1 {
public native int intMethod( int n );
public native boolean booleanMethod( boolean bool );
public native String stringMethod( String text );
public native int intArrayMethod( int[] intArray );

public static void main( String[] args ){
try{
System.loadLibrary( "Sample132" );
} catch( UnsatisfiedLinkError e ){
System.out.println( "Linking failed with message\n" + e.getMessage() );
}

Sample1 sample = new Sample1();
int square = 0, sum = 0;
boolean bool = false;
String text = "";

try{
square = sample.intMethod( 5 );
bool = sample.booleanMethod( true );
text = sample.stringMethod( "JAVA" );
sum =
sample.intArrayMethod(
new int[]{ 1, 1, 2, 3, 5, 8, 13 } );
} catch( UnsatisfiedLinkError e ){
System.out.println( "Calling native method failed with\n" + e.getMessage() );
System.exit( 1 );
}

System.out.println( "intMethod: " + square );
System.out.println( "booleanMethod: " + bool );
System.out.println( "stringMethod: " + text );
System.out.println( "intArrayMethod: " + sum );
}
}

这个类只包含一些简单的本地方法。在其主要方法中,它尝试加载包含这些实现的 DLL。我用 javah 为类生成了适当的头文件 (Sample1.h)。我的包含实现的 C++ 文件如下所示:

#include "Sample1.h"

#include <string.h>

extern "C" {
JNIEXPORT jint JNICALL Java_Sample1_intMethod
( JNIEnv * env,
jobject obj,
jint num ){
return( num * num );
}

JNIEXPORT jboolean JNICALL Java_Sample1_booleanMethod
( JNIEnv * env,
jobject obj,
jboolean boolean ){
return( ! boolean );
}

JNIEXPORT jstring JNICALL Java_Sample1_stringMethod
( JNIEnv * env,
jobject obj,
jstring string ){
const char * str = env->GetStringUTFChars( string, 0 );
char cap[ 128 ];
strcpy( cap, str );
env->ReleaseStringUTFChars( string, 0 );
return( env->NewStringUTF( strupr( cap ) ) );
}

JNIEXPORT jint JNICALL Java_Sample1_intArrayMethod
( JNIEnv * env,
jobject obj,
jintArray array ){
int i, sum = 0;
jsize len = env->GetArrayLength( array );
jint * body = env->GetIntArrayElements( array, 0 );
for( i=0; i < len; i++ ){
sum += body[ i ];
}
env->ReleaseIntArrayElements(array, body, 0);
return( sum );
}
}

我现在遇到的问题是,一旦 Sample1 类的主方法调用了其实例上的 native intMethod,它就会崩溃并出现 UnsatisfiedLinkError 运行时异常。现在,DLL 与类位于同一目录中,我已验证主函数实际上已成功加载库:它不会在 System.loadLibrary() 调用中抛出 UnsatisfiedLinkError 异常。但是为了完整起见,我想知道我用 MinGW 的 G++ 编译 DLL 的方式是否与调用失败有关:

g++ -I"C:\Program Files (x86)\Java\jdk1.8.0_172\include"-I"C:\Program Files (x86)\Java\jdk1.8.0_172\include\win32"-fPIC --shared -m32 -o Sample132.dll Sample1.cpp

我还应该注意,我在 32 位 JVM 中运行该类,它是一个 32 位 DLL!

最后,使用 MS VS 的 dumpbin 工具,我得到了这个输出:

Dump of file Sample132.dll

File Type: DLL

Section contains the following exports for Sample132.dll

00000000 characteristics
5B4F79B4 time date stamp Wed Jul 18 19:32:36 2018
0.00 version
1 ordinal base
4 number of functions
4 number of names

ordinal hint RVA name

1 0 000012DE Java_Sample1_booleanMethod@12
2 1 00001368 Java_Sample1_intArrayMethod@12
3 2 000012D0 Java_Sample1_intMethod@12
4 3 000012F5 Java_Sample1_stringMethod@12

Summary

1000 .CRT
1000 .bss
1000 .data
1000 .debug_abbrev
1000 .debug_aranges
2000 .debug_info
1000 .debug_line
1000 .edata
1000 .eh_frame
1000 .idata
1000 .rdata
1000 .reloc
1000 .text
1000 .tls

所以看起来符号并没有被破坏,因此 JVM 无法在加载的 DLL 中找到正确的符号。

有谁知道为什么我的程序在调用 native 方法时会失败并出现 UnsatisfieLinkError?一些帮助将不胜感激!

提前致谢,约书亚

编辑:这是仍然无法编译的 C++ 文件

#include "Sample1.h"

#include <string.h>

JNIEXPORT jint JNICALL Java_Sample1_intMethod
( JNIEnv * env,
jobject obj,
jint num ){
return( num * num );
}

JNIEXPORT jboolean JNICALL Java_Sample1_booleanMethod
( JNIEnv * env,
jobject obj,
jboolean boolean ){
return( ! boolean );
}

JNIEXPORT jstring JNICALL Java_Sample1_stringMethod
( JNIEnv * env,
jobject obj,
jstring string ){
const char * str = env->GetStringUTFChars( string, 0 );
char cap[ 128 ];
strcpy( cap, str );
env->ReleaseStringUTFChars( string, 0 );
return( env->NewStringUTF( strupr( cap ) ) );
}

JNIEXPORT jint JNICALL Java_Sample1_intArrayMethod
( JNIEnv * env,
jobject obj,
jintArray array ){
int i, sum = 0;
jsize len = env->GetArrayLength( array );
jint * body = env->GetIntArrayElements( array, 0 );
for( i=0; i < len; i++ ){
sum += body[ i ];
}
env->ReleaseIntArrayElements(array, body, 0);
return( sum );
}

void main(){}

最佳答案

好的,我解决了我的问题。问题在于我构建 DLL 的方式。

首先,您应该将选项kill-at 传递给MinGW 链接器(ld)。当你不传递这个选项时,尽管有 extern "C" 声明,你的符号仍然会以一种微妙的方式被破坏:在函数名的末尾,编译器将附加 @<函数参数占用的字节数>。这看起来像是一个小细节,但您想要这个。 Java(或者至少是标准的 Oracle JVM)需要这个后缀!

其次,g++ 实际上允许您定义 _JNI_IMPLEMENTATION。这个内置标识符将向编译器发出信号,表明它将要构建的共享库用于 JNI 并相应地配置自身。

因此,最后,要编译 DLL 属性,您不要必须对原始 javah 生成的头文件进行任何更改。只需执行此命令:

g++ -I"C:\Program Files (x86)\Java\jdk1.8.0_172\include" -I"C:\Program Files (x86)\Java\jdk1.8.0_172\include\win32" -D_JNI_IMPLEMENTATION -Wl,--kill-at --shared -o Sample132.dll Sample1.cpp

(当然,将包含路径更改为您的 Java SDK 安装的包含路径)

This page包含许多有关使用 MinGW 构建 JNI 兼容 DLL 的有趣信息

我希望这对将来的人也有帮助。非常感谢您的帮助,Alerra! :)

关于java - 无法让最简单的 JNI 示例在 Windows 10 上运行,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51408117/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com