2

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

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

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

这是 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)
4

1 回答 1

2

阅读 SO JNI 亚文化中无所不在的聪明人的巨大评论线程,我可能会遗漏一些东西,但对我来说,错误是显而易见的:

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

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

使dft实例可从TunerPanel. 您不能对来自两个不同类的本地方法使用相同的本地库。或者使本机方法成为静态的。就我对 FFT 的理解而言,您不需要在compute*.

于 2012-11-08T10:00:27.450 回答