java - JNI 中的 UnsatisfiedLinkError

标签 java c java-native-interface native

我正在使用 JNI 为学校开发一个项目。简而言之,我已经使用共享库和 JNI 使第一部分工作,但第二部分(引用同一个库)每次尝试运行代码时都会给出 UnsatisfiedLinkError 。我的教授和助教都无法解决这个问题,我已经尝试调试它一个多星期了。

第一部分是一个将独立执行的 .java 程序,给定一个整数文件和一个频率,它应该调用 C 中的 native 代码来计算直接傅立叶变换并返回给定频率的值。在 java 中,我将这些 int 存储到一个数组中,并将该数组传递给 JNI 以计算 C 中的 DFT。这会返回一个 int 值,并且工作起来就像一个魅力。

对于第二部分,我们创建了一个 GUI 界面,它加载 JNI 库并接受 .wav 文件或我们自己格式的文件。当从文件选择器中选择文件时,需要使用此 gui 来计算文件的频率。由于 .wav 文件(和其他类型)具有 header 信息和二进制数据,而不是第一部分中的整数,因此我的策略是将文件名(作为字符串)传递给 JNI,以便我的 native 代码可以将 int 值分解为数组本身,然后计算文件的频率。我的 gui 已完成,从选择器中选择文件的操作事件应该调用 JNI 代码并返回文件的频率。有趣的是,代码在 Linux 中编译并成功加载库,但当选择文件并且应该使用该文件调用 native 代码时,会因此链接错误而崩溃选择器。我彻底彻底失败了。有什么想法吗?

这是 JNI 生成的头文件

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

#ifndef _Included_dft
#define _Included_dft
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     dft
 * Method:    computeDFT
 * Signature: ([III)I
 */
JNIEXPORT jint JNICALL Java_dft_computeDFT
  (JNIEnv *, jobject, jintArray, jint, jint);

/*
 * Class:     dft
 * Method:    computeFileDFT
 * Signature: (Ljava/lang/String;)I
 */
JNIEXPORT jint JNICALL Java_dft_computeFileDFT
  (JNIEnv *, jobject, jstring);

#ifdef __cplusplus
}
#endif
#endif

这是有效的代码

public class dft
{
private native int computeDFT(int[] nums, int count, int freq);
private native int computeFileDFT(String fileName);

static
{
    /* 
     * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
     * SYSTEM LOAD LIBRARY PATH BELOW
     * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
     */
    System.loadLibrary("dft");
}

/**
 * @param args
 * @throws IOException 
 */
public static void main(String[] args) throws IOException
{
    File infile;
    Scanner sc = null;
    dft dft = new dft();
    int count = 0;
    int[] data = new int[4096];

    //code that reads the file and puts the content into an array called 'data'
            //the args[1] below is the specified frequency to be calculated in JNI

    int dftValue = dft.computeDFT(data, count, Integer.parseInt(args[1]));
    System.out.println(dftValue);
}

这是问题代码

private native int computeFileDFT(String fileName);

static
{
    /* 
     * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
     * SYSTEM LOAD LIBRARY PATH BELOW
     * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
     */
    System.loadLibrary("dft");
    System.out.println("loaded successfully");
}

    //imagine more code here creating a JPanel object,
    //adding a bunch of stuff to it, etc. 
    //One key item that is added is a button, 
    //which when pressed opens a JFileChooser object, 
    //below you will see my implementation of the 
    //ActionListener which listens to the button and is 
    //supposed to execute the native code when the file is chosen.

private class TunerButtonListener implements ActionListener
{
    //@Override
    public void actionPerformed(ActionEvent event)
    {
        int returnVal = dialog.showOpenDialog(fileButton);
        if(returnVal == JFileChooser.APPROVE_OPTION) 
        {
            currentFileName = dialog.getSelectedFile().getName();
            currentFilePath = dialog.getSelectedFile().getPath();
            message.setText(currentFileName);


            int val = computeFileDFT(currentFilePath);
                    //more code goes here that does more stuff

完整的错误消息和堆栈

Exception in thread "AWT-EventQueue-0" java.lang.UnsatisfiedLinkError: TunerPanel.computeFileDFT(Ljava/lang/String;)I
at TunerPanel.computeFileDFT(Native Method)
at TunerPanel$TunerButtonListener.actionPerformed(TunerPanel.java:167)
at javax.swing.AbstractButton.fireActionPerformed(AbstractButton.java:2012)
at javax.swing.AbstractButton$Handler.actionPerformed(AbstractButton.java:2335)
at javax.swing.DefaultButtonModel.fireActionPerformed(DefaultButtonModel.java:404)
at javax.swing.DefaultButtonModel.setPressed(DefaultButtonModel.java:259)
at javax.swing.plaf.basic.BasicButtonListener.mouseReleased(BasicButtonListener.java:252)
at java.awt.AWTEventMulticaster.mouseReleased(AWTEventMulticaster.java:289)
at java.awt.Component.processMouseEvent(Component.java:6389)
at javax.swing.JComponent.processMouseEvent(JComponent.java:3268)
at java.awt.Component.processEvent(Component.java:6154)
at java.awt.Container.processEvent(Container.java:2045)
at java.awt.Component.dispatchEventImpl(Component.java:4750)
at java.awt.Container.dispatchEventImpl(Container.java:2103)
at java.awt.Component.dispatchEvent(Component.java:4576)
at java.awt.LightweightDispatcher.retargetMouseEvent(Container.java:4633)
at java.awt.LightweightDispatcher.processMouseEvent(Container.java:4297)
at java.awt.LightweightDispatcher.dispatchEvent(Container.java:4227)
at java.awt.Container.dispatchEventImpl(Container.java:2089)
at java.awt.Window.dispatchEventImpl(Window.java:2518)
at java.awt.Component.dispatchEvent(Component.java:4576)
at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:672)
at java.awt.EventQueue.access$400(EventQueue.java:96)
at java.awt.EventQueue$2.run(EventQueue.java:631)
at java.awt.EventQueue$2.run(EventQueue.java:629)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.AccessControlContext$1.doIntersectionPrivilege(AccessControlContext.java:105)
at java.security.AccessControlContext$1.doIntersectionPrivilege(AccessControlContext.java:116)
at java.awt.EventQueue$3.run(EventQueue.java:645)
at java.awt.EventQueue$3.run(EventQueue.java:643)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.AccessControlContext$1.doIntersectionPrivilege(AccessControlContext.java:105)
at java.awt.EventQueue.dispatchEvent(EventQueue.java:642)
at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:275)
at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:200)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:190)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:185)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:177)
at java.awt.EventDispatchThread.run(EventDispatchThread.java:138)

最佳答案

阅读 S.O. 无所不在的聪明人的大量评论。 JNI 亚文化,我可能遗漏了一些东西,但对我来说,这个错误是显而易见的:

您已经针对 dft 类创建了 native JNI 库,因此您的 native 函数是 Java_dft_*。当在 dft 实例范围内调用时,它确实有效。

然后创建另一个类TunerPanel。当然,您声明了相同的 native 方法签名,但您没有任何带有 Java_TunerPanel_* 函数的库!您仍在使用与 Java_dft_* 相同的原始库。

使 dft 实例可从 TunerPanel 访问。您不能对两个不同类的 native 方法使用相同的 native 库。或者将 native 方法设为静态。就我对 FFT 的理解而言,您不需要在 compute* 运行之间保留任何持久数据。

关于java - JNI 中的 UnsatisfiedLinkError,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13283781/

相关文章:

java - 为什么不是所有的 Java 类都有接口(interface)?

java - 如何在 Node JS 中为 ActiveMQ 编写发送方应用程序

c - 我使用过 printf 但当我编译时没有出现任何内容

android - 如何在Android Studio中添加.so、.mk等原生文件?

java - 奇怪的 Java HashMap 行为 - 找不到匹配的对象

java - 使用 ICE PDF 查看器 pdf 在内部框架内不会更改

c - 指向指向文件指针的函数的结构?

c - fread 返回 0 并且无法在 Windows 计算机上打开 db 文件。找不到文件吗?或者是权限?

java - 从继承的 native 部分调用基方法 (Android)

android - 保留通过 native 代码创建的egl上下文