【问题标题】:JNI error while calling a C subroutine调用 C 子例程时出现 JNI 错误
【发布时间】:2019-11-18 19:11:25
【问题描述】:

我想从 Java 中调用一个 C 子例程。我正在使用 JNI。我创建了 .java、.c 和 .h 文件,并编译了一个 DLL。所有文件都在同一个文件夹中。但是当我运行程序时,它会显示一个unsatisfiedlinkError。我哪里错了……?

在学习 JNI 时,我使用的源代码来自:http://www.ibm.com/developerworks/java/tutorials/j-jni/section2.html 以及我已经尝试过的东西:

  • 使用 Code::Blocks(ide) 和 GCC 作为编译器创建一个 dll
  • 使用 GCC 从命令行创建 dll (Ref. http://sig9.com/node/35)
  • 我使用的是Win7 32位,我猜上面所有的方法都会生成32位的DLL
  • 我找到的所有用于创建 DLL(共享库)的解决方案都适用于 MS VC/VCPP,而我的机器上现在没有。

问题出在哪里?正在生成 DLL 文件,没有任何异常,但是当我运行 Java 代码时,它会抛出异常。


PS:如果有任何解释 JNI 工作原理和实际作用的理论示例,请分享链接...

被抛出的消息或异常:

    c:\myjava1>java Sample1
    Exception in thread "main" java.lang.UnsatisfiedLinkError: Sample1.intMethod(I)I
      at Sample1.intMethod(Native Method)
      at Sample1.main(Sample1.java:11)

在创建 dll 文件很多次之后,我很确定它可能没有问题,路径有问题...我已经更改了 loadlibrary 加载方法的方法,但仍然没有运气,.....


根据 MOD 的建议: 我一直在帖子上讨论这个问题:调用C子程序时出现JNI错误,我在这里发布所有代码,因为cmets的字符有限...... Sample1.c

#include "jni.h"
#include"Sample_Sample1.h"
JNIEXPORT jint JNICALL Java_Sample_Sample1_test(JNIEnv *env, jobject obj){
return(1);
}
void main(){}

Sample1.java

package Sample;

public class Sample1
{
public native int test();
static{ 
System.loadLibrary("Sample1");
}
public static void main(String[] args)
{
 Sample1 sample = new Sample1();
 System.out.println(sample.test());
 }
}

Sample_Sample1.h(使用 javah -jni 命令生成)

/* DO NOT EDIT THIS FILE - it is machine generated */
#include "jni.h"
/* Header for class Sample_Sample1 */

#ifndef _Included_Sample_Sample1
#define _Included_Sample_Sample1
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     Sample_Sample1
 * Method:    test
 * Signature: ()I
 */
JNIEXPORT jint JNICALL Java_Sample_Sample1_test
  (JNIEnv *, jobject);

#ifdef __cplusplus
}
#endif
#endif

谁能指导我问题出在哪里?在之前的帖子中,我提到我使用的代码是教程中的代码,但是为了简化我已经更改代码的事情......在使用 **java Sample.Sample1 “我得到了:

c:\myjava1>java Sample.Sample1 线程“主”java.lang.UnsatisfiedLinkError 中的异常:Sample.Sample1.test()I 在 Sample.Sample1.test(本机方法) 在 Sample.Sample1.main(Sample1.java:12)

【问题讨论】:

  • 所有代码(.c和.java)均取自帖子中提到的链接,仍在重复:ibm.com/developerworks/java/tutorials/j-jni/section2.html>
  • 错误是什么?是 Java 找不到你的库(loadLibrary 调用失败),还是 Java 找不到你的方法?请检查您的 DLL 是否导出了正确的名称,例如使用依赖walker dependencywalker.com.
  • 抛出 what 异常?用什么讯息?这里没有足够的信息。
  • 是的,导入的名称与 .c 文件中提到的名称相同(并在 .java 中调用)
  • 您必须发布框架代码:至少 Java 包语句、loadLibrary() 调用和本地方法声明,以及生成的 .h 和 .c 文件。

标签: java c java-native-interface


【解决方案1】:

你需要have your library explicitly set on your path

您使用的标志可能不太正确。试试这个:

gcc -Wall -D_JNI_IMPLEMENTATION_ -Wl,--kill-at \
    -I[Java_HOME]/include -I[Java_HOME]/include/win32 \
    -shared -o Sample1.dll Sample1.c

来自MinGW GCC site

【讨论】:

  • @buch11,.dll 的完整路径是什么?当您尝试执行程序时,路径环境变量的值是多少?请记住,这是您的路径,而不是您的类路径。
  • .dll 的路径 = "C:\Program Files\Java\jdk1.6.0_20\bin\Sample1.dll" 和路径变量="%SystemRoot%\system32;%SystemRoot%;%SystemRoot %\System32\Wbem;%SYSTEMROOT%\System32\WindowsPowerShell\v1.0\;c:\program files\java\jdk1.6.0_20\bin;C:\Program Files\QuickTime\QTSystem\;c:\PHP; "
  • @buch11,我明白了。也许这不是路径问题,而是 .dll 构建过程本身之一。构建 .dll 时使用的 gcc 标志是什么?
  • 我在 gcc 中使用的命令是:::gcc -shared -o path/Sample1.dll path/Sample1.o:::我已经按照建议使用工具依赖walker检查了dll,并且也表现出正常行为...
  • @buch11 您在那里使用的标志可能不太正确。试试这个:gcc -Wall -D_JNI_IMPLEMENTATION_ -Wl,--kill-at -I[Java_HOME]/include -I[Java_HOME]/include/win32 -shared -o Sample1.dll Sample1.cMinGW-GCC site
【解决方案2】:

您是否通过从存根 C++ 应用程序调用来检查您的 DLL?请特别注意您调用的方法的确切名称(包括大小写)。

UnsatisfiedLinkError 的 Javadoc 说“如果 Java 虚拟机找不到声明为本地的方法的适当本地语言定义,则抛出此错误。”这可能意味着名称拼写错误,或者您的 DLL 不在 JVM 期望的位置。

【讨论】:

  • JVM 会在哪里期待它?我已经设置了类路径
【解决方案3】:

最后使用 System.load() 方法解决了问题, System.loadLibrary() 仍然对我不起作用...它继续给出相同的异常,我认为问题出在 .dll 谢谢致所有支持和回应的人......

【讨论】:

    【解决方案4】:

    花费 2 小时分析代码后。问题在于 .dll/.so 编译。下面的命令对我有用:

    g++ -dynamiclib HelloJni.cpp -I /usr/include/ -I /usr/lib/jvm/java-1.8.0-openjdk-amd64/include/ -I /usr/lib /jvm/java-1.8.0-openjdk-amd64/include/linux/ -shared -o libHelloJni.so

    g++ -dynamiclib HelloJni.cpp -I /usr/include/ -I $JAVA_HOME/include/ -I $JAVA_HOME/include/linux/ -shared -o libHelloJni.so

    以上命令适用于 linux。如果是Windows,请更改

    [Java_HOME]/include/linux/ ---> [Java_HOME]/include/win/

    苹果机:

    $Java_HOME/include/linux/  --->  $Java_HOME/include/darwin/
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-01-02
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多