Interfacer du Java avec du C (JDK 1.0.2) |
L'operation est possible bien que pas automatique. L'interet d'un tel interfacage apparait si l'on dispose d'un code natif tres performant ou trop gros pour que tout soit recrit. Cependant, dans la version JDK 1.0.2 au moins, un tel interfacage releve de l'acrobatie. L'exemple ci-dessous montre comment envoyer des ordres UNIX en passant par la commande system du C.
Le principe est d'ecrire un fichier qui contient un main appelant une
classe dont l'implementation est en C.
Un fichier distinct du main va decrire cette classe (appelee sur la figure Toto et dans l'exempleci-dessous Interface) qui inclut les fonctions ou procedures C . Dans cette classe, on declarera le profil des fonctions C avec un status native. Puis on chargera la librairie dans un bloc static qui n'est pas une methode. |
![]() |
On verifiera tout d'abord que les fichiers sont accessibles grace aux variables d'environnement :
CLASSPATH et LD_LIBRARY_PATH |
Les fichiers seront compiles separement et un fichier souche special (stub) sera genere pour finir l'interfacage. On ecrit donc directement trois fichiers (deux .java et un .c).
Programme (2 fichiers differents) :
// fichier system.java
public class system { static Interface_c unix ; public static void main(String args[]) { unix = new Interface() ; unix.hello() ; System.out.println("Je demande un <ls>.") ; unix.ls() ; System.out.println("Je demande un <pwd>.") ; unix.pwd(); System.out.println("Une commande plus complexe.") ; unix.passe_parametre() ; // methode java qui va appeler du C } } // fichier Interface.java class Interface { // procedure C public native void hello() ; public native void ls() ; public native void pwd() ; public native void passe_param() ; static { // charge la librairie libma_lib.so System.loadLibrary("ma_lib") ; } // variables utilisees pour l'echange java/c public String java_string ; public int entier ; public float flottant ; public char caractere ; public void passe_parametre() { java_string = new String("Voici une chaine") ; entier = 10 ; flottant = (float) 3.14159 ; caractere = 'q' ; passe_param () ; // fonction C } } |
Il faut ensuite compiler ce programme puis generer un .h par :
javac system.java javac Interface.java javah Interface |
On ecrit ensuite le fichier.c (la lecture du fichier .h genere par javah donne le nom des fonctions) :
/* Fichier InterfaceImp.c dont la compilation va
donner un IntefaceImp.so */
#include <StubPreamble.h> #include <stdio.h> #include "Interface.h" /* voir le fichier Interface.h pour le profile des fonctions C a ecrire */ Interface_hello(struct HInterface * this) { printf("Bonjour le monde\n"); } Interface_ls(struct HInterface * this) { system("ls -l"); return; } Interface_pwd(struct HInterface * this) { system("pwd"); return; } void Interface_passe_param(struct HInterface * this) { printf(" entier : %d\n flottant : %d\n caractere : %d\n", unhand(this)->entier, unhand(this)->flottant, unhand(this)->caractere) ; javaString2CString(unhand(this)->java_string, c_string, sizeof(c_string)) ; printf(" Chaine : %s\n",c _string) ; return ; } |
On notera qu'il faut convertir la chaine java en chaine C pour que cela fonctionne. Par ailleurs, les parametres peuvent bien sur etre modifies dans la procedure C et que pour y acceder, il a fallu passer par une macro appelee unhand.
Il faut ensuite creer un fichier souche qui est ecrit en C (stub file) qui va finir de realiser l'interface entre la classe Java et le programme natif :
javah -stubs Interface |
Le fichier source qui a ete genere s'appelle ici Interface.c.
On dispose maintenant de deux fichiers .c qu'il faut compiler et mettre dans une librairie qui s'appelera ici libma_lib.so (soit en Unix SGI) :
cc -shared -I/opt/java/java-JDK-1.0.2/include -I/opt/java/java-JDK-1.0.2/include/irix Interface.c InterfaceImp.c -o libma_lib.so |
Attention :
En resume :
Fichiers sources a ecrire |
Fichiers generes |
librairie |
system.java Interface.java InterfaceImp.c |
system.class Interface.class Interface.h Interface.c |
libma_lib.so |
Il est a priori possible de passer des parametres plutot que d'utiliser des variables de classe. Cependant, cela complique encore les choses. Enfin, il est egalement a priori possible d'appeler une methode java depuis le C mais nous n'y sommes pas arrive completement (nous attendrons le JDK 1.1 pour resoudre ce probleme).
Ph. RIS 1997