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 8 und Java 7
2 Fortgeschrittene String-Verarbeitung
3 Threads und nebenläufige Programmierung
4 Datenstrukturen und Algorithmen
5 Raum und Zeit
6 Dateien, Verzeichnisse und Dateizugriffe
7 Datenströme
8 Die eXtensible Markup Language (XML)
9 Dateiformate
10 Grafische Oberflächen mit Swing
11 Grafikprogrammierung
12 JavaFX
13 Netzwerkprogrammierung
14 Verteilte Programmierung mit RMI
15 RESTful und SOAP-Web-Services
16 Technologien für die Infrastruktur
17 Typen, Reflection und Annotationen
18 Dynamische Übersetzung und Skriptsprachen
19 Logging und Monitoring
20 Sicherheitskonzepte
21 Datenbankmanagement mit JDBC
22 Java Native Interface (JNI)
23 Dienstprogramme für die Java-Umgebung
Stichwortverzeichnis

Jetzt Buch bestellen
Ihre Meinung?

Spacer
<< zurück
Java SE 8 Standard-Bibliothek von Christian Ullenboom
Das Handbuch für Java-Entwickler
Buch: Java SE 8 Standard-Bibliothek

Java SE 8 Standard-Bibliothek
Pfeil 22 Java Native Interface (JNI)
Pfeil 22.1 Java Native Interface und Invocation-API
Pfeil 22.2 Eine C-Funktion in ein Java-Programm einbinden
Pfeil 22.2.1 Den Java-Code schreiben
Pfeil 22.3 Dynamische Bibliotheken erzeugen
Pfeil 22.3.1 Die Header-Datei erzeugen
Pfeil 22.3.2 Implementierung der Funktion in C
Pfeil 22.3.3 Die C-Programme übersetzen und die dynamische Bibliothek erzeugen
Pfeil 22.4 Nativ die String-Länge ermitteln
Pfeil 22.5 Erweiterte JNI-Eigenschaften
Pfeil 22.5.1 Klassendefinitionen
Pfeil 22.5.2 Zugriff auf Attribute
Pfeil 22.5.3 Methoden aufrufen
Pfeil 22.5.4 Threads und Synchronisation
Pfeil 22.5.5 @Native Markierungen *
Pfeil 22.6 Einfache Anbindung von existierenden Bibliotheken
Pfeil 22.6.1 JNA (Java Native Access)
Pfeil 22.6.2 BridJ
Pfeil 22.6.3 Generieren von JNI-Wrappern aus C++-Klassen und C-Headern
Pfeil 22.6.4 COM-Schnittstellen anzapfen
Pfeil 22.7 Invocation-API
Pfeil 22.8 Zum Weiterlesen
 
Zum Seitenanfang

22.3Dynamische Bibliotheken erzeugen Zur vorigen ÜberschriftZur 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.

 
Zum Seitenanfang

22.3.1Die Header-Datei erzeugen Zur vorigen ÜberschriftZur nächsten Ü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 Methodensignatur 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 22.3build.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-Dateistrlen.h sollten keine Änderungen vorgenommen werden. Werfen wir einen Blick hinein, damit wir wissen, welche C-Funktion wir implementieren müssen:

Listing 22.4strlen.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 Verwechslungen 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.

 
Zum Seitenanfang

22.3.2Implementierung der Funktion in C Zur vorigen ÜberschriftZur nächsten Ü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 22.5strlen.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.

 
Zum Seitenanfang

22.3.3Die C-Programme übersetzen und die dynamische Bibliothek erzeugen Zur vorigen ÜberschriftZur nächsten Ü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 Standarddistribution 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 22.6build.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.8.0\include" />
<arg value="-I" />
<arg value="C:\Program Files\Java\jdk1.8.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.

 


Ihre Meinung

Wie hat Ihnen das Openbook gefallen? Wir freuen uns immer über Ihre Rückmeldung. Schreiben Sie uns gerne Ihr Feedback als E-Mail an kommunikation@rheinwerk-verlag.de.

<< zurück
 Zum Rheinwerk-Shop
Zum Rheinwerk-Shop: Java SE 8 Standard-Bibliothek Java SE 8 Standard-Bibliothek
Jetzt Buch bestellen

 Buchempfehlungen
Zum Rheinwerk-Shop: Java ist auch eine Insel
Java ist auch eine Insel


Zum Rheinwerk-Shop: Professionell entwickeln mit Java EE 8
Professionell entwickeln mit Java EE 8


Zum Rheinwerk-Shop: Besser coden
Besser coden


Zum Rheinwerk-Shop: Entwurfsmuster
Entwurfsmuster


Zum Rheinwerk-Shop: IT-Projektmanagement
IT-Projektmanagement


 Lieferung
Versandkostenfrei bestellen in Deutschland, Österreich und der Schweiz
InfoInfo

 
 


Copyright © Rheinwerk Verlag GmbH 2018
Für Ihren privaten Gebrauch dürfen Sie die Online-Version natürlich ausdrucken. Ansonsten unterliegt das Openbook 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

Cookie-Einstellungen ändern