简体   繁体   English

JNI 中的 UnsatisfiedLinkError

[英]UnsatisfiedLinkError in JNI

I'm working on a project for school using JNI.我正在使用 JNI 为学校开展一个项目。 In a nutshell, I have gotten the first part working using the shared library and JNI, but the second part (which refers to the same library) gives an UnsatisfiedLinkError every time I try to run the code.简而言之,我已经使用共享库和 JNI 使第一部分工作,但第二部分(指的是同一个库)每次我尝试运行代码时都会给出一个 UnsatisfiedLinkError。 My professor and TAs are all unable to figure out this problem and I have been trying to debug it for over a week now.我的教授和助教都无法弄清楚这个问题,我已经尝试调试了一个多星期了。

The first part is a .java program that will be executed independently, given a file of integers and a frequency, it should call native code in C to compute a direct fourier transform and return a value given a frequency.第一部分是一个独立执行的 .java 程序,给定一个整数文件和一个频率,它应该调用 C 中的本机代码来计算直接傅立叶变换并返回给定频率的值。 In java, I stored these ints into an array and passed the array to JNI to compute the DFT in C. This returns a single int value and works like a charm.在 java 中,我将这些 int 存储到一个数组中,并将该数组传递给 JNI 以在 C 中计算 DFT。这将返回一个 int 值,就像一个魅力。

For the second part, we have created a gui interface which loads the JNI library and takes in a .wav file or a file of our own format.对于第二部分,我们创建了一个 gui 接口,用于加载 JNI 库并接收 .wav 文件或我们自己格式的文件。 This gui is required to calculate the frequency of a file when selected from a file chooser.当从文件选择器中选择文件时,需要此 gui 来计算文件的频率。 Since the .wav files (and the other type) have header information as well as binary data, rather than integer numbers as in the first part, my strategy is to pass the filename (as a string) to JNI so that my native code can dissect the int values into an array itself and then calculate the frequency of the file.由于 .wav 文件(和其他类型)具有头信息和二进制数据,而不是第一部分中的整数,我的策略是将文件名(作为字符串)传递给 JNI,以便我的本机代码可以将 int 值分解为数组本身,然后计算文件的频率。 My gui is complete, and the action event of selecting a file from the chooser is supposed to call the JNI code and return the frequency of the file.我的gui完成了,从chooser中选择文件的action事件应该是调用JNI代码并返回文件的频率。 Interestingly, the code compiles in linux and loads the library successfully , but crashes with this link error when the file is chosen and the native code is supposed to be called using the file chooser.有趣的是,代码在Linux中编译并成功加载库,但是在选择文件时使用此链接错误崩溃,并且应该使用文件选择器调用本机代码 I am at a complete and total frustrated defeat.我处于彻底而彻底的挫败感中。 Any ideas?有任何想法吗?

HERE IS THE HEADER FILE GENERATED BY JNI这是 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

HERE IS THE CODE THAT WORKS这是有效的代码

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);
}

HERE IS THE PROBLEM CODE这是问题代码

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

THE FULL ERROR MESSAGE AND STACK完整的错误信息和堆栈

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)

Reading the enormous comment thread of the all omnipresent smart people of SO JNI subculture, i might be missing something, but to me the bug is obvious:阅读 SO JNI 亚文化中所有无所不在的聪明人的大量评论线程,我可能会遗漏一些东西,但对我来说,错误很明显:

You have created your native JNI lib against class dft , hence your native functions are Java_dft_* .您已经针对类dft创建了本机 JNI 库,因此您的本机函数是Java_dft_* It indeed works when being called in scope of dft instance.当在dft实例的范围内被调用时,它确实有效。

Then you create another class TunerPanel .然后创建另一个类TunerPanel Of course you declare the same native method signature, but you don't have any library with Java_TunerPanel_* functions!当然,您声明了相同的本机方法签名,但是您没有任何带有Java_TunerPanel_*函数的库! You are still using the same original library with Java_dft_* .您仍在使用Java_dft_*的相同原始库。

Make dft instance accessible from TunerPanel .使dft实例可从TunerPanel访问。 You can't use the same native library for native methods from two different classes.您不能对来自两个不同类的本机方法使用相同的本机库。 Or make the native methods static.或者使本机方法静态。 As far as my understanding of FFT goes, you don't need to keep any persistent data between runs of compute* .就我对 FFT 的理解而言,您不需要在compute*运行之间保留任何持久数据。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM