Programme Java Machine Virtuelle Methodes Natives Systeme d

Transcription

Programme Java Machine Virtuelle Methodes Natives Systeme d
Introduction au dévellopement de Methodes Natives
Partie I :
appelle de methodes C++ sous windows
Auteur: Frank Sauvage.
1 \ introduction aux methodes natives :
Les methodes natives sont des methodes devellopées dans un autre langage que Java, généralement
C ou C++, mais que pour diverses raisons on souhaite tout de même utiliser dans un programme
écrit en Java.
Le kit de devellopement Java integre en standard une interface appelée JNI pour Java Native
Interface. La documentation de cette Interface est disponible sur le site de java.
Pour la version 1.5 du sdk l'addresse directe est :http://java.sun.com/j2se/1.5.0/docs/guide/jni/
le principal avantage des methodes native reside dans le fait qu'utiliser un langage de plus bas que
Java permet d'eviter les contraintes qu'impose la machine virtuelle. Il devient alors possible d'ecrire
des methodes beaucoup optimisées et rapides, ainsi que d'ecrire des methodes accédant directement
aux fonctions du systeme d'exploitation.
Cependant, le fait d'ecrire une partie d'un programme dans un langage compilé impose de fournir
des bibliothéque pour chacun des systemes où l'on souhaitera voir fonctionner l'application.
Notes :
Dans ce document seul l'ecriture et l'utilisation de methodes en C++ sous windows sera abordé.
L'ecriture de methodes natives sur un autre systeme tel que Linux reste compatible avec ce
document tant que la partie C++ reste conforme à la norme ANSI, et que les bibliothéques utilisées
existe sur la plateforme cible. La compilation de methodes sous Linux sera abordé dans une
prochaine partie de ce document.
Programme Java
Machine
Virtuelle
Methodes
Natives
Systeme d'exploitation
2 \ prérequis :
Dans ce document nous considerons que l'environnement de travail est le suivant :
–
–
SDK java version 1.5 (aussi appelé jdk5.0)
disponible à l'addresse : http://java.sun.com/j2se/1.5.0/download.jsp
Visual C++ Toolkit 2003
http://msdn.microsoft.com/visualc/vctoolkit2003/
le Visual C++ Toolkit (VCT) est une version gratuite et ligne de commande du compilateur C++ de
Windows. Par defaut l'installation propose l'accés en ligne de commande à un environnement en
ligne de commande specifique au compilateur.
Pour fixer les variables d'environnement, cet environnement utilise un fichier batch contenu à la
base du repertoire d'installation nommé VCVARS32.BAT.
Dans notre cas, nous avons besoin de rajouter au chemin des include l'accés vers les fichiers
d'entetes de la JNI. Sous windows, ces fichiers sont contenus dans le repertoire INCLUDE du JDK.
Le sous repertoire WIN32 du repertoire include doit lui aussi etre rajouté.
La ligne suivante represente les ajouts neccessaires :
Set INCLUDE =
c:\program files\java\jdk1.5.0_02\include;c:\program files\java\jdk1.5.0_02\include\win32;C:\Program
Files\Microsoft Visual C++ Toolkit 2003\include;%INCLUDE%
Note : le chemin ici rajouté est celui de notre machine de reference. Il peut etre different sur votre
propre installation.
3 \ création de methodes natives:
Afin d'utiliser du C++ dans un code java, il est neccessaire de créer des fonctions qui serviront de
lien entre les deux langages.
La declaration des fonctions natives est assez delicate en ce qui concerne la partie C++, nous
utiliseront donc un utilitaire fourni dans le JDK : javah.
Javah est un outil qui permet de generer les fichiers d'entetes C++ a partir d'un code compilé java
contenant des methodes declarées en tant que natives.
A partir du fichier java suivant :
package testJNI;
public class FonctionSimple
{
// chargement de la librairie associée
// cette partie sera vue en details plus loin
static {
System.loadLibrary("testJNI_FonctionVoid");
}
//declaration de la fonction native.qui ne rends pas de resultat.
public static native void fonctionVoid();
public static void main(String args[])
{
System.out.println("Appel de la fonction C++ : ");
//appel de la fonction :
FonctionSimple.fonctionVoid();
}
}
on utilise la commande javah pour generer le fichier FonctionSimple.h
la commande javah s'utilise de la meme maniere que la commande javac du compilateur.
javah – classpath repertoiredev\ -d repertoireDev\ testJNI.FonctionSimple
ce qui nous permet d'obtenir le fichier d'entete suivant :
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class testJNI_FonctionSimple */
#ifndef _Included_testJNI_FonctionSimple
#define _Included_testJNI_FonctionSimple
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: testJNI_FonctionSimple
* Method: fonctionVoid
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_testJNI_FonctionSimple_fonctionVoid (JNIEnv *, jclass);
#ifdef __cplusplus
}
#endif
#endif
Comme l'indique l'entete, il est deconseillé d'editer ce fichier mais Les devellopeurs C++ seront
famillier avec la declaration conditionnelle pour le C++ qui nous interresse.
les autres s'interesseront plus particulierement à la ligne suivante :
JNIEXPORT void JNICALL Java_testJNI_FonctionSimple_fonctionVoid (JNIEnv *, jclass);
si on la compare à la declaration java :
public static native void fonctionVoid();
on peut s'appercevoir que pour une fonction void, la version C++ passe en parametre deux
arguments supplementaires : JNIEnv et jclass.
Ces deux parametres seront explicité plus loin, mais sachez qu'il s'agit de variables d'environnement
passées dans chaque fonction native.
L'implementation de la fonction en C++ devient maintenant possible en reprenant le prototype ainsi
obtenu. Dans notre cas, on se contentera d'afficher un message sur la sortie standard pour verifier
que l'appel a bien reussi.
On peut donc ecrire le fichier testJNI_FonctionSimple.cpp suivant :
#include "testJNI_FonctionSimple.h"
#include <iostream>
JNIEXPORT void JNICALL Java_testJNI_FonctionSimple_fonctionVoid (JNIEnv *, jclass)
{
// Un affichage sur la console en C++
printf("l'appel de la fonction a ete effectue avec succes\n");
printf("nous sommes ici en train d'executer du code C++\n");
}
4 \ Java et les Bibliothéques dynamiques
lorsqu'un programme java utilise une classe où des methodes natives sont utilisées, la machine
virtuelle doit charger une bibliothéque dynamique de fonctions.
Ces bibliothéques sont des morceaux de programmes compilés qui peuvent etre chargés et
dechargés à la demande par de larges programmes.
l'avantage en programmation C++ d'utiliser ces bibliothéques reside dans la modularité acquise en
terme d'espace memoire utilisé car ces portions de code peuvent alors etre utilisées par plusieurs
programmes simultanément
cette possibilité est assurée par le systeme d'exploitation qui à la charge de les placer en memoire et
de les rendre accessibles à la demande.
Dans le cas d'ecriture des methodes natives, il est neccessaire d'avoir une bibliothéque par classe, ce
qui peut rapidement devenir difficillement gerable. Cest pourquoi il est preferable de regrouper au
maximum les methodes natives dans des classes de liaisons plutot que de les declarer directement la
où elles sont utilisées.
Revenons donc au code java de notre exemple :
static
{
System.loadLibrary("testJNI_FonctionVoid");
}
comme on peut le voir ici, on demande en fait au systeme de charger pour nous la librairie de notre
classe. Le fichier doit etre accessible par le systeme, soit en etant dans le repertoire de lancement du
programme soit dans le path systeme.
Note :
vous pouvez lister la liste des repertoires du path systeme grace à la méthode java:
System.out.println(System.getProperty("java.library.path"));
5 \ création de la bibliothéque C++ dynamique
pour generer la bibliothéque, il est neccessaire d'utiliser le compilateur C++.
dans le VCT, le compilateur est utilisable grace à la commande cl. A partir du terminal ligne de
commande du VCT, il faut alors se placer dans le repertoire contenant les sources C++ a compiler,
c'est à dire dans notre exemple les fichiers :
testJNI_FonctionSimple.cpp
testJNI_FonctionSimple.h
la commande :
cl /LD testJNI_FonctionSimple.cpp
compilera alors en tant que librairie dynamique les methodes natives de la classe java.
Les fichiers suivant doivent etres generés :
– testJNI_FonctionSimple.exp
– testJNI_FonctionSimple.obj
– testJNI_FonctionSimple.lib
– testJNI_FonctionSimple.dll
les trois premiers sont des fichiers intermediaires utilisés par le compilateur. Le dernier est la DLL
qu'il va falloir fournir avec les programmes utilisant les methodes natives.
Note :
Nous ne nous occuperons pas ici des problemes de link et autres qu'apporte le C++.
nous considerons que toutes les methodes sont implementées dans un seul et unique fichier. Cela
n'inclus pas les utilisation de bibliothéques tierces.
6 \ lancement du programme :
comme nous l'avons vu plus haut, la librairire doit etre accessible dans le path systeme ou presente
dans le repertoire de lancement de l'application.
La commande suivante
java -classpath repertoiredev\ testJNI.FonctionSimple
fait donc apparaître le resultat suivant de notre premier programme utilisant les methodes natives :
Appel de la fonction C++ :
l'appel de la fonction a ete effectue avec succes
nous sommes ici en train d'executer du code C++
Notes
pour eclipse, si l'on desire utiliser les methodes natives, il est neccessaire de les placer à la racine
du de l'arborescence du projet et non dans le repertoire de la classe elle meme.
7 \ Conclusion
ce document introduit au mechanisme de creation et d'utilisation des methodes natives.
Il permet aussi d'apprehender les contraintes liées à leur utilisation et à leur création.
Il est à present neccessaire d'etudier comment passer des données vers et depuis les methodes
natives ainsi que comment invoquer une methode sur un objet java depuis le code C++.