19.02 Hello (JNI) World
Nachdem Sie nun wissen, was JNI ist und für was Sie es alles einsetzen können, programmieren Sie heute ein erstes HelloWorld-Programm mit JNI. Dabei ruft Ihr Java-Programm eine selbst geschriebene C-Bibliothek auf, welche ein einfaches Hello World
auf der Konsole ausgibt.
Installation einer C/C++ Umgebung
Damit Sie aus Ihrem C/C++-Code eine Programmbibliothek (z. B. unter Windows *.dll oder bei Solaris *.so) erstellen können, benötigen Sie zuerst eine entsprechende Umgebung (ähnlich dem JDK). Hierfür bietet sich gcc an. Für die Windows-Plattform könnten Sie auf Cygwin oder MinGW zurückgreifen. Bei der Installation müssen Sie lediglich darauf achten, dass Sie gcc-core, gcc-g++, gdb und make mit installieren.
Nachdem die Installation erfolgreich abgeschlossen wurde, sollten Sie noch das bin-Verzeichnis, welches den gcc enthält, in die Umgebungsvariable PATH
mit aufnehmen.
Natürlich können Sie auch eine andere Umgebung zur Entwicklung Ihrer nativen Schnittstellen verwenden. Dieses Kapitel bezieht sich allerdings auf den gcc.
Wenn Sie alles richtig gemacht haben, können Sie jetzt über Ihre Konsole folgendes Kommando ohne Fehlermeldung ausführen:
gcc --version
Das Java-Programm
Erstellen Sie eine neue Klasse mit dem Namen HelloJNIWorld
und dem Inhalt
package de.jbb.jni; public class HelloJNIWorld { static { System.loadLibrary("helloworld"); } public static void main(String[] args) { printHelloWorld(); } public static native void printHelloWorld(); }
im Package de.jbb.jni
. Wie Sie bereits aus dem Kapitel über weitere Modifizierer wissen, verweist die Methode printHelloWorld
dank des native
-Modifizierers auf eine native Implementierung dieser Methode. Der statische Initialisierer sorgt dafür, dass die native Bibliothek beim Start geladen wird. Hierzu wird die Methode loadLibrary
der Klasse System
verwendet. Wir gehen davon aus, dass sich die Library im selben Verzeichnis wie das Programm befindet (oder zumindest im library.path), weshalb es genügt, den Namen der Bibliothek ohne Dateiendung zu nennen (die Dateiendung wird – je nach Plattform – automatisch hinzugefügt).
Der library.path ist der Ort, an dem Java nach Bibliotheken sucht. Sie können sich diesen Pfad über
System.out.println(System.getPropertie("java.library.path"));
anzeigen lassen.
Es ist ebenfalls möglich zum Laden der Bibliothek einen absoluten Pfad, wie z. B. C:\java\dlls\helloworld.dll zu verwenden. Diesen laden Sie dann aber nicht über System.loadLibrary
sondern über System.load
.
Die Klasse kann nun ganz normal kompiliert werden.
Die Header-Datei
So wie Java-Programme imports von Klassen zur Funktionserweiterung benötigen, benötigen C-Programme includes von Header-Dateien.
Eine Header-Datei enthält u. a. Deklarationen für den eigentlichen Quellcode und bilden in einer gewissen Form die Schnittstellen zwischen den unterschiedlichen Programmelementen.
Damit Sie eine Schnittstelle zwischen Java und C/C++ aufbauen können, wird zwingend eine solche Header-Datei benötigt. Um diese Datei zu erstellen, bietet Java das Tool javah an. Hiermit lassen sich automatisiert solche Header-Dateien für eine Klasse mit einem nativen Aufruf erzeugen. Dieses Programm finden Sie im bin-Verzeichnis Ihrer JDK-Installation. Da sich dieses Verzeichnis ohnehin in der PATH
-Variable befinden sollte, können Sie das Tool ohne Probleme von überall aus auf der Konsole starten. Der Aufruf schaut genauso wie ein normaler java-Aufruf aus – nur eben mit javah
anstelle von java
:
javah de.jbb.jni.HelloJNIWorld
Auf der selben Ebene wie ihr de-Ordner befindet sich nun die Header-Datei mit dem Namen de_jbb_jni_HelloJNIWorld.h. Es ist wichtig, dass Sie diese Datei niemals verändern oder anpassen, sie sollte dann in etwa so aussehen:
/* DO NOT EDIT THIS FILE - it is machine generated */ #include <jni.h> /* Header for class de_jbb_jni_HelloJNIWorld */ #ifndef _Included_de_jbb_jni_HelloJNIWorld #define _Included_de_jbb_jni_HelloJNIWorld #ifdef __cplusplus extern "C" { #endif /* * Class: de_jbb_jni_HelloJNIWorld * Method: printHelloWorld * Signature: ()V */ JNIEXPORT void JNICALL Java_de_jbb_jni_HelloJNIWorld_printHelloWorld (JNIEnv *, jclass); #ifdef __cplusplus } #endif #endif
Das C-Programm
Nun ist es an der Zeit die dazugehörige Library zu erstellen. Entweder verwenden Sie ein C/C++ Plugin für Ihre IDE (z. B. CDT für Eclipse), oder Sie legen von Hand eine neue Textdatei an, und benennen diese in helloworld.c um. Diese Datei öffnen Sie dann mit einem beliebigen Texteditor und fügen folgenden Code ein:
#include <jni.h> #include <stdio.h> #include "de_jbb_jni_HelloJNIWorld.h" JNIEXPORT void JNICALL Java_de_jbb_jni_HelloJNIWorld_printHelloWorld(JNIEnv *env, jclass cls) { printf("Hello World\n"); return; }
Beachten Sie, dass eine Leerzeile am Ende der Datei stehen muss!
Wie Sie bereits wissen, entsprechen die include
-Zeilen in etwa den import
-Anweisungen aus Java. Es werden also folgende Header-Dateien importiert:
- jni.h – für die Standard-JNI-Funktionen
- stdio.h – für die Funktionen zur Ausgabe von Text auf der Konsole
- de_jbb_jni_HelloJNIWorld.h – der eben generierte Header als Schnittstelle zu unserem Java-Programm
Jetzt folgt auch schon die Implementation Ihrer nativen Methode. Solche Methoden beginnen immer mit JNIEXPORT
gefolgt vom Rückgabetyp (in unserem Fall void
) und dem Macro JNICALL
. Anschließend folgt der Name der Methode. Er beginnt immer mit Java, gefolgt vom Package der Klasse mit den nativen Methoden und letztendlich der Klasse selbst und dem Namen der nativen Methode. Die einzelnen Elemente sind dabei jeweils durch Unterstriche getrennt Java_de_jbb_jni_HelloJNIWorld_pintHelloWorld
. Als Parameter werden der Methode standardmäßig die JNI-Umgebung (JNIEnv *env
) und die aufrufende Klasse (jclass cls
) bei statischen Methoden, bzw. das aufrufende Objekt (jobject obj
) bei Objektmethoden übergeben. Sollte die Methode an sich noch Parameter erwarten, folgen diese im Anschluss.
Die JNI Environment stellt Ihre Schnittstelle zur Java-Welt dar. Diese werden Sie nach und nach in den nächsten Kapiteln kennenlernen. Eine detaillierte Übersicht, welche Funktionen Ihnen die
JNIEnv
bietet, finden Sie auf der Seite JNI Functions von sun.
Die Zeile printf("Hello World\n");
gibt erwartungsgemäß den Text „Hello World“ aus und das abschließende return;
beendet die Methode.
In den nachfolgenden Kapiteln werden grundlegende C-Kenntnisse vorausgesetzt. Sollten Sie diese nicht besitzen oder auffrischen wollen, empfehle ich Ihnen die Online-Version des Buches C von A bis Z.
Kompilierung des C-Codes
Nun müssen Sie Ihren C-Quellcode noch in eine Bibliothek umwandeln. Wenn Sie – wie oben empfohlen – gcc verwenden, sieht der dazugehörige Aufruf im Verzeichnis Ihrer C-Datei auf der Konsole wie folgt aus:
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
Sie müssen jetzt noch die Pfade der -I
-Aufrufe anpassen. Dabei werden folgende Verzeichnisse übergeben (relativ oder absolut):
- Den Pfad zum include-Ordner im Installationsverzeichnis ihres JDKs
- Den Ordner im include-Ordner mit dem Namen Ihres Betriebssystems (z. B. win32 für Windows oder solaris für Solaris)
- Den Pfad zum Verzeichnis, wo sich Ihre erzeugte Header-Datei (de_jbb_jni_HelloJNIWorld.h) befindet
Die letzten beiden Parameter spezifizieren den Namen der Programmbibliothek (ändern Sie hier bitte die Dateiendung .sfx in die Dateiendung der Programmbibliotheken Ihres Betriebssystems – z. B. .dll für Windows oder .so für Solaris ab) und der Source-Datei.
Nach Absenden dieses Befehls wird eine native Bibliothek im aktuellen Verzeichnis erstellt. Kopieren Sie die erstellte Datei nun auf die selbe Ebene, in der sich auch der de-Ordner Ihres Java-Programms befindet (bzw. falls Sie load
anstelle von loadLibrary
verwendet haben, an die Stelle, die Sie angegeben haben).
Jetzt können Sie Ihr Java-Programm ganz normal ausführen und sollten die Konsolenausgabe Hello World
erhalten.
Hiermit haben Sie Ihr erstes JNI-Programm erstellt.
Hallo, es ist vielleicht erwähnenswert, dass man in der Konsole „cd „path zur scr des java Projekts““ machen sollte 😉
lg coco