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):

  1. Den Pfad zum include-Ordner im Installationsverzeichnis ihres JDKs
  2. Den Ordner im include-Ordner mit dem Namen Ihres Betriebssystems (z. B. win32 für Windows oder solaris für Solaris)
  3. 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.

Previous Article
Next Article

One Reply to “19.02 Hello (JNI) World”

  1. Cocojack

    Hallo, es ist vielleicht erwähnenswert, dass man in der Konsole „cd „path zur scr des java Projekts““ machen sollte 😉

    lg coco

Schreibe einen Kommentar

Diese Website verwendet Akismet, um Spam zu reduzieren. Erfahre mehr darüber, wie deine Kommentardaten verarbeitet werden.