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