为什么我在Windows上调用MinGW编译的函数(不加载库)时,会出现UnsatisfiedLinkError?

 2023-01-20    325  

问题描述

我正在使用Windows上的Eclipse制作一个简单的JNI测试应用程序.我的C ++编译器是MingW 4.6.2.当我尝试在测试DLL中调用功能时,Java将抛出UnsatisfiedLinkError(dll本身无问题加载).我已经验证了我的DLL导出一个” C”函数,其名称与javah实用程序生成的函数相同.

如何尝试 该功能可能会产生链接错误?(另外,是否有任何方法可以获取有关找不到哪些符号的详细信息”秃头”的秃头声明UnsatisfiedLinkError旁边是无用的.)

为什么我在Windows上调用MinGW编译的函数(不加载库)时,会出现UnsatisfiedLinkError?

这是定义本机函数的Java:

package com.xyz.jsdi_test;

import java.io.File;

public class JSDI
{
    public static native void func(
        String str,
        int i,
        Integer ii,
        long j /* 64 bits */,
        Long jj,
        byte[] b
    );
    public static void dummy()
    {
        System.out.println("JSDI.dummy()");
    }
    static
    {
        File f = new File("..\\jsdi\\bin\\jsdi.dll");
        System.out.println("Preparing to load: " + f);
        System.load(f.getAbsolutePath());
        System.out.println("Successfully loaded: " + f);
    }

这是javah的相应输出:

...
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     com_xyz_jsdi_test_JSDI
 * Method:    func
 * Signature: (Ljava/lang/String;ILjava/lang/Integer;JLjava/lang/Long;[B)V
 */
JNIEXPORT void JNICALL Java_com_xyz_jsdi_1test_JSDI_func
  (JNIEnv *, jclass, jstring, jint, jobject, jlong, jobject, jbyteArray);

#ifdef __cplusplus
}
#endif

…以及我如何实现功能…

extern "C"
{

JNIEXPORT void JNICALL Java_com_xyz_jsdi_1test_JSDI_func(
    JNIEnv * env,
    jclass _class,
    jstring str,
    jint i,
    jobject ii,
    jlong j,
    jobject jj,
    jbyteArray b
)
{
    // don't do anything...let's just try to get called successfully...
}

} // extern "C"

这是我尝试调用它的方式.

...

public static void main(String[] args)
{
    JSDI.dummy(); // cause class to load, which should cause System.load() to run.
    JSDI.func("hello", 0, 0, 0L, 0L, (byte[])null);
}

最后,这是输出:

Preparing to load: ..\jsdi\bin\jsdi.dll
Successfully loaded: ..\jsdi\bin\jsdi.dll
JSDI.dummy()
java.lang.UnsatisfiedLinkError: com.xyz.jsdi_test.JSDI.func(Ljava/lang/String;ILjava/lang/Integer;JLjava/lang/Long;[B)V
   at com.xyz.jsdi_test.JSDI.func(Native Method)
   at com.xyz.jsdi_test.SimpleTest.main(SimpleTest.java:24)

推荐答案

解决了 – wooo!

事实证明,MSVC对__stdcall函数的名称进行了强调.明格没有. Windows JVM显然期望” _”前缀.一旦我将’_’列入函数名称并使用mingw进行了重建,一切都奏效了.

eg :

JNIEXPORT void JNICALL Java_com_xyz_jsdi_1test_JSDI_func ==> _Java_com_xyz_jsdi_1test_JSDI_func

编辑:
MINGW包含的dlltool实用程序的–add-stdcall-underscore功能可以为您透明地解决此问题.将其设置在您的makefile中,您不必担心拥有不同编译器的实际源代码的不同版本.请参阅在此链接.

其他推荐答案

发布一个工作示例,在同一目录中的三个文件中复制内容(修改JDK的路径),然后调用build.cmd

/* File: HelloWorld.java */
public class HelloWorld {
    private static native void writeHelloWorldToStdout();

    public static void main(String[] args) {
        System.loadLibrary("HelloWorld");
        writeHelloWorldToStdout();
    }
}

/* File: HelloWorld.c */
#include <stdio.h>
#include "HelloWorld.h"
JNIEXPORT void JNICALL Java_HelloWorld_writeHelloWorldToStdout(JNIEnv *env, jclass c)
{
    printf("Hello World!");
}

rem File: build.cmd 

%echo off
echo delete generated binaries
del HelloWorld.class
del HelloWorld.dll
del HelloWorld.h
del HelloWorld.def

echo Compile the Java Class
javac HelloWorld.java

echo Generate the Header file
javah -classpath . -o HelloWorld.h HelloWorld

echo Build the DLL 
gcc -I"C:\Program Files (x86)\Java\jdk1.7.0_25\include" -I"C:\Program Files (x86)\Java\jdk1.7.0_25\include\win32" -Wl,--add-stdcall-alias -Wl,--output-def,HelloWorld.def -shared  -o HelloWorld.dll HelloWorld.c

echo run the program 
java HelloWorld

其他推荐答案

例外中的签名没有” int”参数.因此,您的Java代码不同意您的本机代码.

以上所述是小编给大家介绍的为什么我在Windows上调用MinGW编译的函数(不加载库)时,会出现UnsatisfiedLinkError?,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对77isp云服务器技术网的支持!

原文链接:https://77isp.com/post/25980.html

=========================================

https://77isp.com/ 为 “云服务器技术网” 唯一官方服务平台,请勿相信其他任何渠道。