Rheinwerk Computing < openbook > Rheinwerk Computing - Professionelle Bücher. Auch für Einsteiger.
Professionelle Bücher. Auch für Einsteiger.

Inhaltsverzeichnis
Vorwort
1 Neues in Java 7
2 Threads und nebenläufige Programmierung
3 Datenstrukturen und Algorithmen
4 Raum und Zeit
5 Dateien, Verzeichnisse und Dateizugriffe
6 Datenströme
7 Die eXtensible Markup Language (XML)
8 Dateiformate
9 Grafische Oberflächen mit Swing
10 Grafikprogrammierung
11 Netzwerkprogrammierung
12 Verteilte Programmierung mit RMI
13 RESTful und SOAP Web-Services
14 JavaServer Pages und Servlets
15 Applets
16 Datenbankmanagement mit JDBC
17 Technologien für die Infrastruktur
18 Reflection und Annotationen
19 Dynamische Übersetzung und Skriptsprachen
20 Logging und Monitoring
21 Java Native Interface (JNI)
22 Sicherheitskonzepte
23 Dienstprogramme für die Java-Umgebung
Stichwort

Buch bestellen
Ihre Meinung?

Spacer
Java 7 - Mehr als eine Insel von Christian Ullenboom
Das Handbuch zu den Java SE-Bibliotheken
Buch: Java 7 - Mehr als eine Insel

Java 7 - Mehr als eine Insel
Rheinwerk Computing
1433 S., 2012, geb.
49,90 Euro, ISBN 978-3-8362-1507-7
Pfeil 21 Java Native Interface (JNI)
Pfeil 21.1 Java Native Interface und Invocation-API
Pfeil 21.2 Eine C-Funktion in ein Java-Programm einbinden
Pfeil 21.2.1 Den Java-Code schreiben
Pfeil 21.3 Dynamische Bibliotheken erzeugen
Pfeil 21.3.1 Die Header-Datei erzeugen
Pfeil 21.3.2 Implementierung der Funktion in C
Pfeil 21.3.3 Die C-Programme übersetzen und die dynamische Bibliothek überzeugen
Pfeil 21.4 Nativ die Stringlänge ermitteln
Pfeil 21.5 Erweiterte JNI-Eigenschaften
Pfeil 21.5.1 Klassendefinitionen
Pfeil 21.5.2 Zugriff auf Attribute
Pfeil 21.5.3 Methoden aufrufen
Pfeil 21.5.4 Threads und Synchronisation
Pfeil 21.6 Einfache Anbindung von existierenden Bibliotheken
Pfeil 21.6.1 Generieren von JNI-Wrappern aus C++-Klassen und C-Headern
Pfeil 21.6.2 COM-Schnittstellen anzapfen
Pfeil 21.7 Invocation-API
Pfeil 21.8 Zum Weiterlesen

Rheinwerk Computing - Zum Seitenanfang

21.3 Dynamische Bibliotheken erzeugenZur nächsten Überschrift

Im zweiten Schritt kann der Java-Code übersetzt werden, denn jetzt würde eine Ausführung einen Fehler produzieren. Existiert die dynamische Bibliothek nicht oder ist sie nicht im Pfad eingebunden, folgt ein Fehler wie der folgende:

java.lang.UnsatisfiedLinkError: no strlen 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 com.tutego.jni.StrLen.<clinit>(StrLen.java:7)
Exception in thread "main"

Für die nativen Methoden auf der Java-Seite gibt es auf der C(++)-Seite entsprechende Implementierungen. Da die Implementierung noch nicht erstellt wurde, gibt es logischerweise einen Laufzeitfehler.


Rheinwerk Computing - Zum Seitenanfang

21.3.1 Die Header-Datei erzeugenZur nächsten ÜberschriftZur vorigen Überschrift

Die nativ implementierten Funktionen verfügen über eine bestimmte Signatur, damit die JVM bei einem Aufruf aus der Java-Welt an die native Implementierung weiterleiten kann. Wie die Signatur aussieht, definiert die JNI-Spezifikation. Um es so einfach wie möglich zu machen, generiert ein Hilfsprogramm aus der Java-Klasse mit der nativen Methode eine C(++)-Header-Datei. Eine Header-Datei enthält Makros und Konstanten und definiert sowie dokumentiert oftmals die Funktionen, die dann später in der C(++)-Datei realisiert werden. (Ein bisschen entspricht das den Schnittstellen und den Klassen, die sie implementieren.)

Die Header-Datei gibt die Signatur der Funktionen vor und wird nicht verändert. Anschließend inkludiert das C(++)-Programm die Header-Dateien und implementiert die vorgegebene Funktion. Dann kann das C(++)-Programm übersetzt, in eine dynamische Bibliothek eingepackt und von der JVM ausgelesen werden. Kommen wir zum ersten Schritt:

Ein Generator erstellt die Header-Datei, der aus der Klassendatei die Methoden-Signatur und Rückgabe ausliest und nach einem festen Schema die Funktionen auf der C(++)-Seite benennt. Zum Aufruf des Generators bietet sich ein Ant-Skript an, und auch das JDK bringt mit javah ein Dienstprogramm mit. Mit Ant erstellt der Task <javah> die entsprechende Header-Datei:

Listing 21.3: build.xml, Ausschnitt

<javah classpath="bin" outputFile="strlen.h" verbose="yes">
<class name="com.tutego.jni.StrLen" />
</javah>

In diesem Beispiel soll für die Klasse StrLen die Header-Datei strlen.h generiert werden.

Hinweis

Soll das Kommandozeilenprogramm javah benutzt werden, so bestimmt der Schalter -o den Namen der Ausgabedatei:

$ javah -jni -o strlen.h com.tutego.jni.StrLen

Die volle Qualifizierung ist wichtig, andernfalls gibt es merkwürdige Fehler wie "error: cannot access StrLen" und "bad class".

An der entstandenen Header-Datei strlen.h sollten keine Änderungen vorgenommen werden. Werfen wir einen Blick hinein, damit wir wissen, welche C-Funktion wir implementieren müssen:

Listing 21.4: strlen.h

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

#ifndef _Included_com_tutego_jni_StrLen
#define _Included_com_tutego_jni_StrLen
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: com_tutego_jni_StrLen
* Method: strlen
* Signature: (Ljava/lang/String;)I
*/
JNIEXPORT jint JNICALL Java_com_tutego_jni_StrLen_strlen
(JNIEnv *, jclass, jstring);

#ifdef __cplusplus
}
#endif
#endif

Die Funktion heißt auf der C-Seite nicht einfach strlen(), weil wegen fehlender Namensräume sonst Verwechslungsgefahren mit anderen nativen Methoden anderer Pakete nicht ausgeschlossen sind. Aus diesem Grund enthält der Funktionsname auf der C-Seite den Paketnamen und den Namen der Java-Klasse. Dementsprechend setzt sich der Funktionsname zusammen aus:

  • einem Präfix Java,
  • dem vollständigen Klassenbezeichner, wobei die einzelnen Glieder im Paket durch »_« und nicht durch ».« getrennt sind, und
  • dem Namen der Methode.

Alle primitiven Java-Typen sind auf spezielle Typen in C abgebildet. So steht jint für ein Integer und jstring für einen Pointer auf eine Zeichenkette.


Rheinwerk Computing - Zum Seitenanfang

21.3.2 Implementierung der Funktion in CZur nächsten ÜberschriftZur vorigen Überschrift

In der automatisch erzeugten Header-Datei lässt sich die Signatur der Funktion ablesen; die Basis für die Implementierung ist:

JNIEXPORT jint JNICALL Java_com_tutego_jni_StrLen_strlen(
JNIEnv *, jclass, jstring );

Wir erzeugen eine neue Datei, strlen.c, mit einer Implementierung für Java_com_tutego_ jni_StrLen_strlen(). Dabei soll zunächst etwas auf dem Bildschirm ausgegeben werden; wir wollen damit testen, ob überhaupt alles zusammen läuft. Anschließend kümmern wir uns um die Zeichenkettenlänge.

Listing 21.5: strlen.c

#include <jni.h>
#include "strlen.h"
#include <stdio.h>
JNIEXPORT jint JNICALL Java_com_tutego_jni_StrLen_strlen(
JNIEnv *env, jclass clazz, jstring s )
{
printf( "Hallo Java-Freunde!\n" );
return 0;
}

Der erste Parameter, env, zeigt auf die JNI-Umgebung, über die alle JNI-Funktionen zur Verfügung stehen. Wir werden sie später nutzen.


Rheinwerk Computing - Zum Seitenanfang

21.3.3 Die C-Programme übersetzen und die dynamische Bibliothek überzeugenZur nächsten ÜberschriftZur vorigen Überschrift

Der C(++)-Compiler muss nun die dynamische Bibliothek übersetzen. Die dynamisch ladbaren Bibliotheken sind unter Windows die .dll-Dateien (dynamic link libraries ) und unter Unix Dateien mit der Endung .so (shared objects). Die .dll- und .so-Dateien erzeugt prinzipiell jeder Compiler, wobei zu beachten ist, dass jeder Compiler andere Aufrufkonventionen befolgt.

Auf dem Markt gibt es eine Reihe guter und freier Compiler, die für die Übersetzung verwendet werden können:

Die GNU Compiler Collection unter Cygwin

Da jeder Compiler andere Aufrufkonventionen hat, führen wir unser Beispiel mit dem GNU Compiler durch. GCC ist klassischerweise ein Unix-Compiler, doch gibt es ihn auch für Windows. Cygwin portiert die unter Unix bekannten Tools für Windows, und ein Teil der Tool-Sammlung ist der C(++)-Compiler.

Für die Installation wird zunächst unter http://www.cygwin.com/ das kleine Programm set-up.exe geladen und ausgeführt (es steckt hinter dem Link Install or update Cygwin now).

  1. Nach dem Start überspringe das Willkommensfenster mit Weiter >.
  2. Wähle den Eintrag Install from Internet aus, um aus dem Internet alle nötigen Pakete geladen zu bekommen. Wähle dann Weiter >.
  3. Gib bei Root Directory zum Beispiel c:\cygwin ein, und wähle Weiter >.
  4. Cygwin speichert die geladenen Teile erst zwischen und möchte dazu ein Verzeichnis bekommen – das Verzeichnis kann nach der Installation gelöscht werden. Vorgewählt ist der Desktop. Der Eintrag wird geändert oder so belassen. Dann Weiter >.
  5. Im Folgenden lassen sich Verbindungsdaten einstellen, damit das Setup-Programm die Programme aus dem Internet laden kann. Die Voreinstellung Direct Connection passt im Regelfall. Dann Weiter >.
  6. Wähle aus der Liste einen Server aus, von dem die Dateien geladen werden. Dann aktiviere Weiter >. Falls jetzt ein Setup Alert kommt, kann dieser mit OK geschlossen werden.
  7. Wähle aus dem Zweig Devel den Eintrag gcc-core (bzw. gcc-g++). (Den gdb können wir angeben, wenn C-Programme debuggt werden sollen.) Dann Weiter >. Die Wahl selektiert automatisch ein paar weitere abgeleitete Pakete und zeigt sie an. Dann Weiter >. Der tatsächliche Download beginnt.
  8. Es lassen sich Icons setzen. Sie sind nicht nötig und können abgewählt werden. Weiter > schließt die Installation ab.

Übersetzen mit Ant

Das Build-Tool Ant bringt in der Standard-Distribution keinen Task mit, der einen C-Compiler anstößt. Nichtsdestotrotz lassen sich mit <exec> externe Programme aufrufen. Somit sieht das ganze Build-Skript folgendermaßen aus:

Listing 21.6: build.xml

<project default="cc" basedir=".">

<target name="javah">
<javah classpath="bin" outputFile="strlen.h" verbose="yes">
<class name="com.tutego.jni.StrLen" />
</javah>
</target>

<target name="cc" depends="javah">

<exec dir="c:\cygwin\bin\" executable="c:\cygwin\bin\gcc-3">
<arg value="-mno-cygwin" />
<arg value="-I" />
<arg value="C:\Program Files\Java\jdk1.7.0\include" />
<arg value="-I" />
<arg value="C:\Program Files\Java\jdk1.7.0\include\win32" />
<arg value="-shared" />
<arg value="-Wl,--add-stdcall-alias" />
<arg value="-o" />
<arg value="${basedir}\strlen.dll" />
<arg value="${basedir}\strlen.c" />
</exec>

</target>

</project>
Hinweis

Die dynamische Bibliothek muss unter Windows die Endung .dll und unter Unix-Systemen die Endung .so haben. In der Unix-Welt beginnen die dynamischen Bibliotheken mit dem Präfix lib, sodass sich daraus für eine Datei die Namensgebung libName.so ergibt.

Wer den <exec>-Task nicht verwenden mag, der kann auch die externen CC-Tasks unter http://ant-contrib.sourceforge.net/ nutzen.



Ihr Kommentar

Wie hat Ihnen das <openbook> gefallen? Wir freuen uns immer über Ihre freundlichen und kritischen Rückmeldungen.

>> Zum Feedback-Formular
<< zurück
  Zum Katalog
Neuauflage: Java SE 8 Standard-Bibliothek
Neuauflage: Java SE 8 Standard-Bibliothek
Jetzt bestellen


 Ihre Meinung?
Wie hat Ihnen das <openbook> gefallen?
Ihre Meinung

 Buchempfehlungen
Zum Katalog: Professionell entwickeln mit Java EE 7






 Professionell
 entwickeln mit
 Java EE 7


Zum Katalog: Java ist auch eine Insel






 Java ist auch
 eine Insel


Zum Katalog: Einstieg in Eclipse






 Einstieg in Eclipse


Zum Katalog: Einstieg in Java






 Einstieg in Java


 Shopping
Versandkostenfrei bestellen in Deutschland und Österreich
InfoInfo




Copyright © Rheinwerk Verlag GmbH 2012
Für Ihren privaten Gebrauch dürfen Sie die Online-Version natürlich ausdrucken. Ansonsten unterliegt das denselben Bestimmungen, wie die gebundene Ausgabe: Das Werk einschließlich aller seiner Teile ist urheberrechtlich geschützt. Alle Rechte vorbehalten einschließlich der Vervielfältigung, Übersetzung, Mikroverfilmung sowie Einspeicherung und Verarbeitung in elektronischen Systemen.


Nutzungsbestimmungen | Datenschutz | Impressum

Rheinwerk Verlag GmbH, Rheinwerkallee 4, 53227 Bonn, Tel.: 0228.42150.0, Fax 0228.42150.77, service@rheinwerk-verlag.de