JNI - java.lang.UnsatisfiedLinkError

Bob

Mitglied
Hallo,

ich habe ein kleines Problem mit der Einbindung einer DLL.
Wenn ich versuche Funktionen aus der DLL zu benutzen bekomme ich einen "UnsatisfiedLinkError". Das Einbinden / Laden der DLL scheint zu funktionieren (die Exception kommt nur, wenn ich die Funktion aus der DLL benutze).

Ich habe versucht mich an das Beispiel aus "The Java Native Interface Programmer's Guide and Specification" zu halten.

Hier mal mein Java-Code:

Java:
public class HelloWorld {

	private native void print();

	public static void main(String[] args) {
		new HelloWorld().print();
	}
	
	static {
      System.loadLibrary("HelloWorld");
	}

}

die eintsprechende Header-Datei:
Code:
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class HelloWorld */

#ifndef _Included_HelloWorld
#define _Included_HelloWorld
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     HelloWorld
 * Method:    print
 * Signature: ()V
 */
JNIEXPORT void JNICALL Java_HelloWorld_print
  (JNIEnv *, jobject);

#ifdef __cplusplus
}
#endif
#endif

und die .c-Datei:

Code:
 #include <jni.h>
 #include <stdio.h>
 #include "HelloWorld.h"

 JNIEXPORT void JNICALL
 Java_HelloWorld_print(JNIEnv *env, jobject obj)
 {

     printf("Hello World!\n");
     return;
 }

Ich bekomme zur Laufzeit dann folgende Exception:
Java:
Exception in thread "main" java.lang.UnsatisfiedLinkError: HelloWorld.print()V
	at HelloWorld.print(Native Method)
	at HelloWorld.main(HelloWorld.java:7)


Kann mir jemand sagen wieso ich die Exception bekomme.

Danke & mfG
Bob

Edit: Den ClassPath hab ich natürlich gesetzt: -Djava.library.path=.\bin
 
Zuletzt bearbeitet:
Habs probiert den Pfad absolut anzugeben. Das bringt aber die gleiche Exception.

Wenn bewusst einen falschen Pfad angebe kommt zwar noch die UnsatisfiedLinkError -Exception allerdings ist die Message eine andere:
Java:
java.lang.UnsatisfiedLinkError: no HelloWorld in java.library.path
	at java.lang.ClassLoader.loadLibrary(Unknown Source)
	at java.lang.Runtime.loadLibrary0(Unknown Source)
	at java.lang.System.loadLibrary(Unknown Source)
	at HelloWorld.<clinit>(HelloWorld.java:11)

Ich geh' also davon aus, dass er die dll zumindest findet.
 
Ja, beim ersten hat er sie noch gefunden. Liegt die Klasse in irgendeinem Package? Ansonsten ggf. mal das loadLibrary ganz an den Anfang der Klasse packen (sollte eigentlich keinen Unterschied machen, aber ... )
 
die klasse liegt im default package.
Hab den static-Block auch an den Anfang geschoben ... hat keine Veränderungen gebracht
 
Ja, war auch eher hilflos rum-geraten 😳 Sicher dass nicht irgendeine ältere DLL im Verzeichnis liegt? Beim drüberschauen sehe ich zumindest keinen Fehler, wenn's partout nicht klappt kann ich morgen abend vielleicht mal schauen, was rauskommt, wenn man das compiliert...
Wie hast du das im Moment compiliert? (OS/Compiler...)
 
Da würde eine andere Meldung kommen ("Cannot load an IA64-Library .. " oder so). Die erste Fehlermeldung deutete darauf hin, dass er die DLL findet und laden kann, aber keine passende "print"-Methode darin gefunden wurde ???:L
 
@Marco13:

Nein, nicht unbedingt. Ich hab das mal bei GSTreamer-Java gemerkt. Die Bindings gibt es nich für 64 bit und die Fehlermeldung war dann ähnlich, nämlich, dass er eine Methode nicht finden kann... Ich hab mich auch extremst gewundert, weil es auf einem anderen PC lief... 32 bit!

Auch wenn es vlt in diesem Fall etwas anderes ist, kann ich deine Aussage so nicht stehen lassen 😛
Die in C/C++ kompilierten Dll Dateien deklarieren die Funktionen z. T. mit Hilfe des Präprozessors, sprich ein Code wird nur kompiliert, wenn das System 32bit ist. Bei solchen Sachen können durchaus Fehlermeldungen wie diese auftreten 😉
 
Ah, MinGW und GCC und so... da gibt's ein paar Schwierigkeiten... da muss man AFAIK irgendwie mit dem DLLTool rumpfuschen, weil die Namen der Funktionen bei Windows irgendwie nicht so ein Name@1b42 hinten dran haben oder so (*dunkle Erinnerung*). Ich hatte mir da mal was notiert, werde mal schauen, ob ich das noch finde...
 
Auf jeden Fall erstmal danke für den Hinweis.

Kannst du mir denn einen anderen Compiler empfehlen, der das Problem nicht hat?
 
Ja, hab nochmal geschaut, aber ich glaube das hatte doch nicht direkt damit zu tun (war eine Mail von Anfang 2008... 😳 ) - da gng es darum, dass man eine .lib-Datei nicht mit MinGW verwenden konnte, um eine JNI-DLL draus zu bauen.
Ich verwende üblicherweise Visual Studio (Express Edition ist Kostenlos), aber ich hab's gerade mit einer steinalten IDE (Dev-Cpp) und einem alten MinGW/GCC getestet und das hat wohl funktioniert. Kann gut sein, dass nur irgendwelche Compiler-Flags fehlen, aber welche das beim GCC sein könnten... da bin ich nicht so auf dem Laufenden (Ein Hoch auf den "Compile"-Button moderner IDEs 😀 ).
Welchen Compiler und welche Kommandozeilen verwendest du denn im Moment?
 
Ich habe im Moment leider keine Zeit weiter an diesem Problem zu arbeiten ...

Ich werde mich aber auf jeden Fall bald wieder diesem Problem widmen.
 
Hallo,
wie versprochen muss ich das Probelm jetzt wieder aufwärmen ...

Die gute Nachricht: Inzwischen funktionieren meine erstellten dlls wieder.
Die Schlechte: Ich weiß nicht genau warum.

Ich hatte vor 4 Wochen nach dem Tip bzgl. MinGW und GCC in Verbindung mit JNI (thx Marco13) noch ein bisschen mit den Compiler-Optionen rumgespielt. Allerdings hat es damals trotzdem nicht funktioniert.
Auf jeden Fall funktioniert es jetzt wieder ... mal sehen wie lange noch ;-)

Hier mal vielleicht mal die Kommando-Zeile:

Code:
gcc -IC:\Programme\Java\jdk1.6.0_21\include -IC:\Programme\Java\jdk1.6.0_21\include\win32 -IC:\Dokumente und Einstellungen\Markus\workspace\NativHelloWorld_JavaProject\bin -O0 -g3 -Wall -c -fmessage-length=0 -oHelloWorld.o ..\HelloWorld.c
gcc -Wl,-kill-at -shared -olibNativeHelloWorld_CppProject.dll HelloWorld.o

Vielleicht hilft das ja noch jemandem weiter ...

Grüße und nochmal danke für die Unterstützung

Bob
 
Ich habe inzwischen auch damit gearbeitet und ähnlcihe Probleme gehabt. Du nutzt das hier: gcc -Wl,-kill-at!!

Das war die Lösung bzw. ich habs dann mit MSVC++ gemacht und damit gings dann direkt. Diese Option verbietet dem C COmpiler, dass der an die Funktionen so dumme @12 @8 Annotations macht. Java findet dann die Methodenrümpfe nicht mehr, da die Methoden dann z.B. ()Vprint@8 heißen etc...

Warum es jetzt auf einmal klappt kann ich dir nicht sagen, aber deine Meldung ist ein eindeutiger Hinweis:

Exception in thread "main" java.lang.UnsatisfiedLinkError: HelloWorld.print()V
at HelloWorld.print(Native Method)
at HelloWorld.main(HelloWorld.java:7)

Das heißt, dass die DLL schon gefunden wurde aber die Methode eben nciht 😉

Gruß,

Chris
 
Ich habe inzwischen auch damit gearbeitet und ähnlcihe Probleme gehabt. Du nutzt das hier: gcc -Wl,-kill-at!!

Das war die Lösung bzw. ich habs dann mit MSVC++ gemacht und damit gings dann direkt. Diese Option verbietet dem C COmpiler, dass der an die Funktionen so dumme @12 @8 Annotations macht. Java findet dann die Methodenrümpfe nicht mehr, da die Methoden dann z.B. ()Vprint@8 heißen etc...

Hmgrlmpf ... :autsch: genau DArum ging es in der alten Mail, die ich da erwähnt hatte - aber da ging es darum, dass ich die dann mit DLLTool, Texteditor, DEF-Dateil-Export und anderen Krämpfen so zurechgestümpert habe, dass sie funktioniert haben ... dabei hätte es ein einfaches Compile-Flag schon getan... gut zu wissen :rtfm:
 
Wenn du den MSVC++ Compiler nutzt, dann brauchst du das Flag komischerweise nicht, ich weiß nicht warum. Liegt nach mehreren Aussagen wohl am MinGW...
 
Ja, ich hatte mich da nur reingefräst, weil jemand eine Bibliothek mit minGW compilieren wollte, und das nicht ging wegen dieser fehlenden @41-Dinger. Aber ... beim zweiten Nachdenken glaube ich, dass das Problem auftrat, weil diese Dinger nicht in seiner eigenen Bibliothek gefehlt haben, sondern in einer, die er nur verwenden wollte (und die vielleicht mit MSVC compiliert war), d.h. vielleicht war der K(r)ampf mit dem DLLTool und den DEF-Dateien gar nicht sooo überflüssig...
 
ist zwar schon lange her, aber vllt hilft es ja noch jemandem...

Ich habe das obige Beispiel auf nem win7 x64 Rechner getestet und bin zu dem Ergebnis gekommen, dass es nicht am MinGW liegt, sondern an der verwendeten JDK bzw JRE

Mit Version 7.03 läuft alles ohne Probleme
Mit Version 7.07 bekomme ich den LinkError

Compileraufruf
Code:
"C:\Program Files\Java\jdk1.7.0_03\bin\javac.exe" -classpath "D:\Workspace\test" -d "C:\Users\XXX\XXX\BDllGen\temp" "D:\Workspace\test\src\HelloWorld.java"

Code:
"C:\Program Files\Java\jdk1.7.0_03\bin\javah.exe" -jni -o "D:\Workspace\test_c\src\HelloWorld.h" -classpath "C:\Users\XXX\XXX\BDllGen\temp" "HelloWorld"

Code:
"C:\Program Files (x86)\MinGW\bin\gcc.exe" -I "C:\Program Files\Java\jdk1.7.0_03\include" -I "C:\Program Files\Java\jdk1.7.0_03\include\win32" -shared -Wl,--add-stdcall-alias -o "D:\Workspace\test\src\HelloWorld_x86.dll" "D:\Workspace\test_c\src\test_c.c"

Code:
"C:\Program Files\MinGW\bin\x86_64-w64-mingw32-gcc.exe" -I "C:\Program Files\Java\jdk1.7.0_03\include" -I "C:\Program Files\Java\jdk1.7.0_03\include\win32" -shared -Wl,--add-stdcall-alias -o "D:\Workspace\test\src\HelloWorld_x64.dll" "D:\Workspace\test_c\src\test_c.c"


Das würde auch erklären, warum sich das Problem bei BOB irgendwann von alleine löste.

Gruß,
Die_ELFE
 

Zurück
Oben