JNI中的UnsatisfiedLinkError

时间:2012-11-08 06:36:40

标签: java c java-native-interface native

我正在使用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)

1 个答案:

答案 0 :(得分:2)

阅读S.O.所有无所不在的聪明人的巨大评论主题。 JNI亚文化,我可能会遗漏一些东西,但对我来说这个bug很明显:

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

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

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