jeudi 27 mai 2010

Faire du JNI sous Eclipse

Rappel
Un petit rappel: JNI (Java Native Interface) est une interface de programmation permettant à des classes JAVA d'inclure du code C ou C++. Il peut paraître paradoxal de vouloir ainsi perdre la portabilité du langage. Il y a toutefois de nombreux cas pour lesquels cette interface est très utile. D'une manière générale, elle permet de récupérer des codes éprouvés, difficile voire impossible à porter en JAVA.

JNI c'est bien mais..
La conséquence de l'utilisation de JNI est qu'il faut (re)mettre les mains dans la programmation C.
Il faut aussi se rapeller que la classe JAVA en question devra être accompagnée des librairies pour toutes les plateformes sur lesquelles elle est susceptible de tourner (MAC, Window, Linux, 32/64bits..). On verra dans un prochain post comment s'y prendre.

Je veux pas quitter Eclipse
Comme beaucoup des utilisateurs d'Eclipse ont du mal à revenir au bon vieux couple emacs/gcc, on va voir comment mettre au point un projet JNI dans Eclipe.

1) Installer CDT sur Eclipse
CDT est le plugin C/C++ d'Eclipse.
- Aller dans Help->Install New Software
- Cliquer sur Available Software Sites
- Cliquer sur add et remplir les champs suivants:
    name = CDT
    URL = http://download.eclipse.org/tools/cdt/releases/galileo

- Selectionner CDT dans le combobox Work With
- Continuer l'installation avec Next/Next/Finish

2) La partie Java
- Créer un projet Java dans Eclipse (JSQLITE dans mon cas).
- Déclarer les méthodes natives là ou bon vous semble. Tant que les classes possédant ce genre de méthodes ne sont pas appelées, tout va bien. Autrement, le linker vous gratifie d'un java.lang.UnsatisfiedLinkError signifiant qu'il n'a pas trouvé le code natif.
- Créer dans le projet un répertoire pour les futurs fichiers headers (jni_headers par exemple). Cela se fait par le menu File->New->Directory.

Il faut maintenant créer les fichiers header contenant les prototypes C des méthodes natives. Pour cela, on peut créer un tache d'exécution en cliquant sur le bouton run surmontant une petite valise rouge.
- Clique droit sur Program sélectionner New et remplir les champs de la manière suivante:
    name: javah
    location: /usr/lib/jvm/jdk1.6.0_16/bin/javah
Il s'agit du chemin d'accès à l'utilitaire Java créant les fichiers headers. Il se trouve dans votre JDK.
    Argument -classpath build -d jni_headers wrapper.SQLiteDataImporter. On suppose que wrapper.SQLiteDataImporter est notre classe avec des méthodes natives

L'exécution de cette tâche doit produire les fichiers d'entêtes dans le répertoire jni_header.

3) La partie C
- Créer un projet C de type Shared Library: menu File->New->C Project, puis, Shared Library->Empty Project. Dans note exemple, ce projet s'appelle JSQLITENative.
- Importer les headers JNI: Clique droit sur le projet, puis Properties->C/C++ General->Paths and Symbols.
- Sélectioner le langage GNU C du tab Includes
- Cliquer sur Add->Workspace, puis sélectionner JSQLITE->jni_headers, valider.
- De la même manière ajouter les répertoire JAVA_HOME/include et JAVA_HOME/include/platform afin d'inclure les headers JNI dans les règles de compilation.
- Vos headers JNI doivent apparaitre dans le dossier Includes
- Créer votre source C: menu File->New->Source File
- Ecriver et compiler votre code. Attention, CDT ne pratique pas la compilation à la volée comme en Java. Il vous faut faire un CTRL B pour compiler. En cas d'erreurs persistentes, un peu de nettoyage peut arranger les choses: menu Project->Clean....
- La librairie doit être placée dans le répertoire Binaries.

4) Faire tourner le code Java.
Il faut d'abord indiquer ou se trouve la librairie C.
- Ouvrir la configuration de lancement de votre application Java: Bouton Run puis Run Configuration.
- Sélectionner votre application.
- Ouvrir le tab Argument
- Mettre la ligne suivant dans la zone VM Arguments: -Djava.library.path="${workspace_loc:SQLITENative/Debug}".
Attention le répertoire Debug est le nom du répertoire de votre Workspace ou se trouve la librairie C. Il ne s'agit pas de son avatar figurant dans l'explorateur de projets qui est Binaries.
- N'oublier pas charger la librairie dans le main de votre application: System.loadLibrary("SQLITENative"); pour un libraire dont le nom est libSQLITENative.so.


Voilà, c'est sommaire, mais ca peut aider. N'oublier pas de refaire cette manip sur chacune des plateforme pour lesquelles vous voulez implémenter vos classes JNI.

Aucun commentaire: