Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

JNI-Problem: DLL gefunden, aber Methode darin nicht

0 views
Skip to first unread message

Markus Pöstinger

unread,
Mar 28, 2006, 6:03:38 AM3/28/06
to
Hallo.

Ich möchte bei mir als Test für ein sehr wichtiges Projekt JNI zum
Laufen bekommen. Dabei klappt eigentlich alles bis zum Punkt des
Einladens der DLL innerhalb Javas. Nur dann findet er die Methode nicht.
Das Ergebnis ist nämlich folgende Exception:

Exception in thread "main" java.lang.UnsatisfiedLinkError: abc
at JniTest.abc(Native Method)
at JniTest.main(JniTest.java:10)

Würde er die DLL selbst nicht finden, dann gäb es das (durch Umbenennung
der DLL gecheckt):

java.lang.UnsatisfiedLinkError: no JniTest in java.library.path
at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1682)
at java.lang.Runtime.loadLibrary0(Runtime.java:822)
at java.lang.System.loadLibrary(System.java:992)
at JniTest.<clinit>(JniTest.java:4)

Der Fehler muss deswegen wohl innerhalb der DLL zu finden sein(?). Ich
möchte im Folgenden mal alle Schritte auflisten, die ich gemacht habe.
Vielleicht kann mir jemand helfen, so daß ich auch etwas kompliziertere
Sachen mit JNI angehen kann. ;)

Innerhalb der Schritte habe ich ggf. den Befehl angegeben (natürlich
eigentlich alles in einer Zeile, hier mit \ manuell umgebrochen), danach
eine etwaige Ausgabe und den Inhalt der produzierten Datei oder den
Dateinamen, falls Binärcode.

Als Compiler verwende ich den gcc aus MinGW.


1) Die Java-Klasse
-------------------

public class JniTest {

static {
System.loadLibrary("JniTest");
}

public static native void abc();

public static void main(String[] args) {
abc();
}

}


2) Die mit javah produzierte Header-Datei für C++
--------------------------------------------------

BEFEHL: "c:\Coding\Tools\Java\JDK1.5\bin\javah -jni -o \
jnitest.h JniTest"

AUSGABE: - keine -

PRODUZIERT:

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class JniTest */

#ifndef _Included_JniTest
#define _Included_JniTest
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: JniTest
* Method: abc
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_JniTest_abc
(JNIEnv *, jclass);

#ifdef __cplusplus
}
#endif
#endif


3) Erstellung des C-Source-Code für die native Methode abc()
-------------------------------------------------------------

#include <jni.h>
#include "JniTest.h"

JNIEXPORT void JNICALL Java_JniTest_abc( JNIEnv *env, jclass clazz ) {

return;

}


4) Kompilierung des C-Code in Objekt-Datei
-------------------------------------------

BEFEHL: "gcc -c -I C:\Coding\Tools\Java\JDK1.5\include \
-I C:\Coding\Tools\Java\JDK1.5\include\win32 \
JniTest.c"

AUSGABE: - keine -

PRODUZIERT: JniTest.o


5) Linking der Objektdatei mit anderen Libraries und Umwandlung in DLL
-----------------------------------------------------------------------

BEFEHL: "ld -shared JniTest.o -o JniTest.dll"

AUSGABE: - keine -

PRODUZIERT: JniTest.dll


6) Kopieren der dll in ein passendes Verzeichnis, damit die JVM sie auch
findet
--------------------------------------------------------------------------------

Mit der Ausgabe des java.library.path habe ich mir angeschaut, wo die
JVM sucht, und die dll dann einfach in das Binär-Verzeichnis meines
MinGW geschoben.


7) Ausführen von JniTest.class
-------------------------------

BEFEHL: "C:\Coding\Tools\Java\JDK1.5\bin\java.exe JniTest"

AUSGABE: Exception in thread "main" java.lang.UnsatisfiedLinkError: abc
at JniTest.abc(Native Method)
at JniTest.main(JniTest.java:10)


Grüße,
Markus

--
Markus Pöstinger, cand.inf. Tempus bestia est, quae nos sequitur
My private homepage ......................... [ http://rgh.datamoon.de ]
You like Trek and writing stories? .............. [ http://www.sfg.org ]

Thomas Söhne

unread,
Mar 28, 2006, 6:33:28 AM3/28/06
to
Hallo,

Markus Pöstinger schrieb:


>
>
> 1) Die Java-Klasse
> -------------------
>
> public class JniTest {
>
> static {
> System.loadLibrary("JniTest");
> }
>
> public static native void abc();
>
> public static void main(String[] args) {
> abc();
> }
>
> }
>

ok

>
> 2) Die mit javah produzierte Header-Datei für C++
> --------------------------------------------------
>
> BEFEHL: "c:\Coding\Tools\Java\JDK1.5\bin\javah -jni -o \
> jnitest.h JniTest"
>
> AUSGABE: - keine -
>
> PRODUZIERT:
>
> /* DO NOT EDIT THIS FILE - it is machine generated */
> #include <jni.h>
> /* Header for class JniTest */
>
> #ifndef _Included_JniTest
> #define _Included_JniTest
> #ifdef __cplusplus
> extern "C" {
> #endif
> /*
> * Class: JniTest
> * Method: abc
> * Signature: ()V
> */
> JNIEXPORT void JNICALL Java_JniTest_abc
> (JNIEnv *, jclass);
>
> #ifdef __cplusplus
> }
> #endif
> #endif
>

scheint ok

>
> 3) Erstellung des C-Source-Code für die native Methode abc()
> -------------------------------------------------------------
>
> #include <jni.h>
> #include "JniTest.h"
>
> JNIEXPORT void JNICALL Java_JniTest_abc( JNIEnv *env, jclass clazz ) {
>
> return;
>
> }
>

scheint ok

>
> 4) Kompilierung des C-Code in Objekt-Datei
> -------------------------------------------
>
> BEFEHL: "gcc -c -I C:\Coding\Tools\Java\JDK1.5\include \
> -I C:\Coding\Tools\Java\JDK1.5\include\win32 \
> JniTest.c"
>
> AUSGABE: - keine -
>
> PRODUZIERT: JniTest.o
>
>
> 5) Linking der Objektdatei mit anderen Libraries und Umwandlung in DLL
> -----------------------------------------------------------------------
>
> BEFEHL: "ld -shared JniTest.o -o JniTest.dll"
>
> AUSGABE: - keine -
>
> PRODUZIERT: JniTest.dll
>

kannste auch in einem schritt, wenn du die Option -Wl nachschlägst
siehst Du das.

Aber füge mal die Option --kill-at ein, ich glaube wenn ich die weglasse
laufen meine DLL's auch nicht.

>
> 6) Kopieren der dll in ein passendes Verzeichnis, damit die JVM sie auch
> findet
> --------------------------------------------------------------------------------
>
> Mit der Ausgabe des java.library.path habe ich mir angeschaut, wo die
> JVM sucht, und die dll dann einfach in das Binär-Verzeichnis meines
> MinGW geschoben.
>

kopier die dll mal in %SYSTEM32%, dann sollte das gehen.

>
> 7) Ausführen von JniTest.class
> -------------------------------
>
> BEFEHL: "C:\Coding\Tools\Java\JDK1.5\bin\java.exe JniTest"
>
> AUSGABE: Exception in thread "main" java.lang.UnsatisfiedLinkError: abc
> at JniTest.abc(Native Method)
> at JniTest.main(JniTest.java:10)
>
>
> Grüße,
> Markus
>

Vermutlich liegt es am linken, die Funktionen müssen halt korrekt
gelinkt werden, damit sie von allen Programmen von aussen gefunden
werden könnnen.

Grüße,
Thomas

ps.: Heute war schon ein JNI Thread, da hab ich ein paar links gepostet.

Markus Pöstinger

unread,
Mar 28, 2006, 6:37:21 AM3/28/06
to
Hallo.

Am Tue, 28 Mar 2006 13:03:38 +0200 schrieb Markus Pöstinger:

> 4) Kompilierung des C-Code in Objekt-Datei
> -------------------------------------------
>
> BEFEHL: "gcc -c -I C:\Coding\Tools\Java\JDK1.5\include \
> -I C:\Coding\Tools\Java\JDK1.5\include\win32 \
> JniTest.c"
> AUSGABE: - keine -
> PRODUZIERT: JniTest.o
>
> 5) Linking der Objektdatei mit anderen Libraries und Umwandlung in DLL
> -----------------------------------------------------------------------
>
> BEFEHL: "ld -shared JniTest.o -o JniTest.dll"
> AUSGABE: - keine -
> PRODUZIERT: JniTest.dll

Hm, wenn ich den Microsoft Compiler aus Visual C++ 2003 verwende und
diese beiden Schritte zu diesem zusammenfüge:

"cl -I C:\Coding\Tools\Java\JDK1.5\include \


-I C:\Coding\Tools\Java\JDK1.5\include\win32 \

-LD JniTest.c -FeJniTest.dll"

Dann klappt's. :)

Allerdings ist auch die resultierende Datei um ein Vielfaches größer (40
KB für Null Operationen?!) anstelle der 3-4 KB, die gcc produziert.
Offensichtlich schmeißt Microsofts Compiler einfach automatisch ne Menge
Kram dazu, dann passt's schon irgendwie. ;)

Hat jemand einen Tip, wie es auch mit gcc klappen könnte?

Markus Pöstinger

unread,
Mar 28, 2006, 6:55:05 AM3/28/06
to
Hallo Thomas.

Am Tue, 28 Mar 2006 13:33:28 +0200 schrieb Thomas Söhne:

> Aber füge mal die Option --kill-at ein, ich glaube wenn ich die weglasse
> laufen meine DLL's auch nicht.

Huch. Jetzt klappt's. :)) Hab extra alle alten DLLs getilgt, und die
neue mit --kill-at kompilierte verwendet (die ist jetzt auch wieder nur
4KB groß ;)).

Danke Dir. :)

> kannste auch in einem schritt, wenn du die Option -Wl nachschlägst
> siehst Du das.

Da bekomme ich allerdings:

gcc -c -I C:\Coding\Tools\Java\JDK1.5\include \
-I C:\Coding\Tools\Java\JDK1.5\include\win32 \

JniTest.c -Wl,-shared,JniTest.o,-o,JniTest.dll

gcc: -shared: linker input file unused because linking not done
gcc: JniTest.o: linker input file unused because linking not done
gcc: -o: linker input file unused because linking not done
gcc: JniTest.dll: linker input file unused because linking not done

Verwende ich den falsch?

> kopier die dll mal in %SYSTEM32%, dann sollte das gehen.

Jo, geht auch.

> ps.: Heute war schon ein JNI Thread, da hab ich ein paar links gepostet.

Jau, schon gesehen und begutachtet.

Thomas Söhne

unread,
Mar 28, 2006, 7:07:57 AM3/28/06
to
Hallo,

Markus Pöstinger schrieb:


> gcc -c -I C:\Coding\Tools\Java\JDK1.5\include \
> -I C:\Coding\Tools\Java\JDK1.5\include\win32 \
> JniTest.c -Wl,-shared,JniTest.o,-o,JniTest.dll
>
> gcc: -shared: linker input file unused because linking not done
> gcc: JniTest.o: linker input file unused because linking not done
> gcc: -o: linker input file unused because linking not done
> gcc: JniTest.dll: linker input file unused because linking not done
>
> Verwende ich den falsch?

gcc -I -I C:\Coding\Tools\Java\JDK1.5\include \


-I C:\Coding\Tools\Java\JDK1.5\include\win32 \

-shared -Wl,--kill-at -o JniTest.dll JniTest.c

sollte es tun.

Grüße,
Thomas

Jochen Theodorou

unread,
Mar 28, 2006, 7:21:08 AM3/28/06
to
Markus Pöstinger schrieb:
[...]

> gcc -c -I C:\Coding\Tools\Java\JDK1.5\include \
> -I C:\Coding\Tools\Java\JDK1.5\include\win32 \
> JniTest.c -Wl,-shared,JniTest.o,-o,JniTest.dll

gcc -I C:\Coding\Tools\Java\JDK1.5\include \


-I C:\Coding\Tools\Java\JDK1.5\include\win32 \

-Wl,--kill-at -shared
JniTest.c -o JniTest.dll

-c beduetet kein linken, also bringt es auch ncihts dem linker irgendwas
zu geben


gcc -Wall -D_JNI_IMPLEMENTATION -Wl,--kill-at -shared foo.c -o foo.dll

das ist womit ich immer compiliere, das Makro brauchst du ja vielleicht
nicht unbedingt, die includes sind bei mir automatisch drin, aber der
Rest entspricht dann dem was ich oben geschrieben habe

Gruss theo

0 new messages