Erste Schritte in JNI

Status
Nicht offen für weitere Antworten.

The_S

Top Contributor
Hi,

ich versuche mich gerade ein bisschen an JNI und habe dazu das Tutorial in den JAQ durchgearbeitet. Leider will das nicht so klappen bei mir. Ich bin wie folgt vorgegangen:

HelloWorld.java geschrieben:

Code:
class HelloWorld {
	public native void displayHelloWorld();

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

Die dazugehörige Header-Datei erstellt:

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:    displayHelloWorld
 * Signature: ()V
 */
JNIEXPORT void JNICALL Java_HelloWorld_displayHelloWorld
  (JNIEnv *, jobject);

#ifdef __cplusplus
}
#endif
#endif

Dann habe ich unter meiner Eclipse C/C++ IDE ein neues Shared Library Projekt angelegt (JNIDLLs). Dort habe ich ein Source-Verzeichnis für die Header-Datei erstellt und diese dort eingefügt. Außerdem habe ich ein weiteres Source-Verzeichnis für meine C-Datei angelegt. Die C-Datei sieht wie folgt aus:

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

JNIEXPORT void JNICALL
Java_HelloWorld_displayHelloWorld(JNIEnv *env, jobject obj)
{
    printf("Hello world!\n");
    return;
}

Außerdem habe ich noch die Settings des Projekts unter GCC C Compiler/Directories dahingehend angepasst, dass auf die Header-Datei im Workspace und auf das include und include/win32 Verzeichnis des JDKs verwiesen wird.

Das Ganze habe ich dann builden lassen und die daraus resultierende dll (libJNIDLLs.dll) in C:\winnt\system32 kopiert (dahin verweist u. a. auch der java.library.path). Wenn ich mein Java-Programm jetzt aber ausführen möchte, bekomme ich folgende Fehlermeldung:

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

weiß jemand woran das liegt und was ich dagegen machen kann? Danke!
 

The_S

Top Contributor
Sorry, bin nicht so C/C++ bewandert und hab von den Compilern/Linkern nicht so viel Ahnung :oops: . Eclipse zeigt mir als Parameter für den Compiler folgendes an:

-I"C:\Programme\Java\jdk1.5.0\include\win32" -I"C:\Programme\Java\jdk1.5.0\include" -I"C:\Eclipse Cpp\workspace\JNIDLLs\header" -O2 -Wall -c -fmessage-length=0

und als Parameter für den Linker


[edit] OK, ich hab den Linker jetzt um folgende Parameter erweitert:

-mno-cygwin -Wl,--add-stdcall-alias

jetzt funktionierts. Danke @thE_29 :)
 

thE_29

Top Contributor
Hehe ;)
Kein Problem!
Ich weiß halt selbst das der GCC Compiler ziemlich viele Probleme verursacht!
Dafür "frißt" er auch mehr als der VC++ Compiler von MS.
 

The_S

Top Contributor
So, ich muss leider dieses alte Thema nochmal aufgreifen, da ich blöderweise meine (endlich funktionierende) Entwicklungsumgebung auf tragische Weise verloren habe ;) .

Ich versuche das Ganze jetzt auch ohne IDE aufzuziehen. Dazu habe ich mir ein Verzeichnis angelegt, welches ein Verzeichnis "java" hat und ein Verzeichnis "c".

Im Verzeichnis Java befindet sich unter de/stkiese/jni folgende Klasse:

Code:
package de.stkiese.jni;

public class HelloJNIWorld {

	static {
		System.load("C:/Blank_JNI/java/helloworld.dll");
	}

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

	public static native void printHelloWorld();
}

Unter "c" befindet sich die Datei helloworld.c:

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

JNIEXPORT void JNICALL Java_helloworld_printHelloWorld(JNIEnv *env, jobject obj)   {
   printf("HelloWorld\n");
   return;
}

Als C-Compiler/Linker verwende ich Cygwin. Installiert mit den Standardeinstellungen und zusätzlich installiertem gcc-core, gcc-g++, gdb und make.

Das bin-Verzeichnis vom cygwin ist natürlich im Path aufgenommen. Zum Testen habe ich mir jetzt folgendes Skript geschrieben:

Code:
cd java
erase helloworld.dll
javac de\stkiese\jni\HelloJNIWorld.java
javah -jni de.stkiese.jni.HelloJNIWorld
cd ..
cd c
gcc -mno-cygwin -I"C:\Programme\Java\jdk1.6.0_07\include\win32" -I"C:\Programme\Java\jdk1.6.0_07\include" -I"..\java" -Wl,--add-stdcall-alias -shared -o ..\java\helloworld.dll helloworld.c
cd ..
cd java
java de.stkiese.jni.HelloJNIWorld
pause

Welches im selben Verzeichnis liegt, wo sich auch die Ordner "java" und "c" befinden. Wenn ich dieses Skript ausführe, bekomme ich keine Fehlermeldungen (dll wird auch schön generiert), nur beim letzten Schritt - ausführen der Java-Klasse. Und zwar handelt es sich dabei um den selben Fehler, den ich auch schon weiter oben in diesem Thread hatte -

Code:
C:\Blank_JNI\java>java de.stkiese.jni.HelloJNIWorld
Exception in thread "main" java.lang.UnsatisfiedLinkError: de.stkiese.jni.HelloJ
NIWorld.printHelloWorld()V
        at de.stkiese.jni.HelloJNIWorld.printHelloWorld(Native Method)
        at de.stkiese.jni.HelloJNIWorld.main(HelloJNIWorld.java:10)

Was kann ich da machen?

Danke!
 

tfa

Top Contributor
>System.load("C:/Blank_JNI/java/helloworld.dll");

Der Pfad zur Lib gehört in den java.library.path (beim Start der VM als Parameter angeben). Die Endung ".dll" gehört hier auch nicht hin, das wäre ja plattformspezifisch. Ein System.load("helloworld"); sollte reichen.
 

The_S

Top Contributor
Na, was du meinst ist System.loadLibrary ;) . Bei System.load gibt man den kompletten Pfad an (absicht, nicht dass die dll nicht im library.path ist).
 

tfa

Top Contributor
Ups, hab ich überlesen. Ich hab immer loadLibrary genommen. Damit hat's geklappt :)
 

The_S

Top Contributor
Kommt aber aufs selbe drauf zam, wenn ich loadLibrary verwende. Und die Library wird ja auch gefunden, sonst hätte ich eine andere Fehlermeldung :( .

Trotzdem danke!
 

thE_29

Top Contributor
JNIEXPORT void JNICALL Java_helloworld_printHelloWorld(JNIEnv *env, jobject obj)

Das ist definitiv falsch!

Hierzu auch: http://www.java-forum.org/de/viewtopic.php?p=218268#218268
Zeile 3!

Wenn du aus einer Klasse mit dem package de.stkiese.jni dir via javah -jni eine h Datei erstellen lässt, müsste die Funktion so lauten

JNIEXPORT TYP Java_dein_package_wie_im_java_KLASSEN-NAME-WO-NATIVE-IST_nativeFunktionsName

Und das trifft bei dir eindeutig nicht zu!
Ihr dürft nicht hergehen und diese Funktionsnamen abändern, nur weil sie euch net gefallen! Der benötigt diese für den Einstiegspunkt.
Ergo findet er diese Funktion nicht, weil dein Header nicht zur Java Datei passt ;)
 

The_S

Top Contributor
Oh man, wie dämlich :oops: . Das kommt davon, wenn man sich auf Copy&Paste verlässt. Danke nochmal, dämlicher Anfängerfehler :(
 

Schampanja

Mitglied
Hi,
ich glaube ich habe ein ähnliches Problem. Leider habe ich das Problem auch mit den Antworten nicht gelöst bekommen. Aber evtl. bekomme ich ja hier einen wertvollen Tip. :D

Mein Java Code (HelloWorld.java):
Code:
class HelloWorld {
	
	private native void callnative();

	public static void main(String[] args){
		new HelloWorld().callnative();
	}

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

Mein C Code (hello.c):
Code:
#include <jni.h>
#include <stdio.h>
#include "helloworld.h"

JNIEXPORT void JNICALL Java_helloworld_callnative(JNIEnv *env,
jobject obj){
	printf("Helloworld\n");
	return;
}

Zunächst habe ich ganz normal mein Java File compiled,
javac HelloWorld.java
und dann die HelloWorld.h datei erzeugt mittels:
javah -jni HelloWorld

Alles Wunderbar und ohne Fehler!!!!!


Dann habe ich mein C Programm compiled:
gcc -shared -I"C:\Programme\Java\jdk1.6.0_11\include" -I"C:\Programme\Java\jdk1.6.0_11\include\win32" hello.c -o hello.dll

Funktioniert auch ohne Probleme und ich bekomme meine hello.dll

Wenn ich jetzt aber mein Java Programm ausführen will, bekomme ich folgenden Fehler:
C:\jnitest>java HelloWorld
Exception in thread "main" java.lang.UnsatisfiedLinkError: HelloWorld.callnative()V
at HelloWorld.callnative(Native Method)
at HelloWorld.main(HelloWorld.java:7)

Woran kann das liegen?

Vielen dank für alle Antworten!

LG

David[/list]
 

Schampanja

Mitglied
Hi, danke schonmal.
Ich verwende kein Cygwin, deswegen kann ich es nicht zu 100% so machen.
Mein Befehl sieht jetzt so aus:
gcc -shared -Wl,--add-stdcall-alias -I"C:\Programme\Java\jdk1.6.0_11\include" -I"C:\Programme\Java\jdk1.6.0_11\include\win32" hello.c -o hello.dll

Ändert aber leider nichts. Nur dass ich zusätzlich zu dem dll File noch die Datei a.exe erhalte.

Gruß,
David
 

The_S

Top Contributor
Versuchs mal so

gcc -mno-cygwin -I"pfad\zum\jdk\include\os" -I"pfad\zum\jdk\include" -I"pfad\zum\verzeichnis\von\de_jbb_jni_HelloJNIWorld" -Wl,--add-stdcall-alias -shared -o helloworld.sfx helloworld.c

Hab ich jetzt einfach mal aus einem Kapitel von http://java-blog-buch.de kopiert, das noch nicht veröffentlicht ist ;) . Muss also noch ein bisschen angepasst werden.
 

Schampanja

Mitglied
Hey!
Sorry, leider klappt es immer noch nicht.
Ich habe jetzt mal einen anderen Compiler verwendet und zwar den von Microsoft.
So bin ich vorgegangen:

C:\jnitest>cl -IC:\Programme\Java\jdk1.5.0_17\include -IC:\Programme\Java\jdk1.5.0_17\include\win32 -MD -LD hello.c -Fehello.dll

Das Ergebnis ist eine Fehlermeldung, dass er die MSVCR80.dll nicht kennt, sowie folgende Ausgabe:

C:\jnitest>java HelloWorld
Exception in thread "main" java.lang.UnsatisfiedLinkError: C:\jnitest\hello.dll:
Can't find dependent libraries
at java.lang.ClassLoader$NativeLibrary.load(Native Method)
at java.lang.ClassLoader.loadLibrary0(ClassLoader.java:1751)
at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1676)
at java.lang.Runtime.loadLibrary0(Runtime.java:822)
at java.lang.System.loadLibrary(System.java:993)
at HelloWorld.<clinit>(HelloWorld.java:11)

Was mache ich bloß falsch?

Vielen dank nochmal!!

LG

David
 

Schampanja

Mitglied
So,
das funktioniert jetzt! :) Endlich!!
Aber mein "Hello World" leider noch nicht :(

Ich bekomme jetzt den Fehler:

Runtime Error!
Program: C:\Programme\......\java.exe

R6034
An application has made anattempt to load the C runtime library incorrectly.
Please contact the application's support team for more information.

Ist das auf den Java oder den C Compiler zurück zu führen?

Danke!

Gruß

David
 
Status
Nicht offen für weitere Antworten.

Ähnliche Java Themen

Neue Themen


Oben