Tutoriel pour exécuter du code natif à partir de Java avec JNA, en 5 minutes

Ce tutoriel s'intéresse à présenter l'utilisation de la bibliothèque JNA pour adresser du code natif dans du code Java. Alors que le précédent tutoriel (http://mbaron.developpez.com/tutoriels/java/executer-code-natif-avec-jni-jna/) se focalisait sur les différences entre JNA et JNI, ce nouveau tutoriel se propose de montrer via un exemple complet comment utiliser exclusivement JNA en 5 minutes.

Les expérimentations se feront à partir de Mac OS X. Bien entendu, tout système supportant la plateforme Java peut être utilisé pour reproduire cette expérimentation.

Si vous souhaitez donner votre avis sur le contenu de cet article, exprimez votre opinion, profitez de cette discussion 4 commentaires Donner une note à l'article (5) 

Article lu   fois.

L'auteur

Profil ProSite personnel

Liens sociaux

Viadeo Twitter Facebook Share on Google+   

I. Présentation de JNA

Avant de présenter JNA, focalisons-nous rapidement sur JNI qui est historiquement le premier moyen d'adresser du code natif avec la plateforme Java. JNI (Java Native Interface) est une couche de programmation qui permet à du code Java d'appeler ou d'être appelé par du code natif. Il n'existe pas réellement de bibliothèque à télécharger pour faire du JNI puisque cette couche de programmation est fournie par défaut dans le JDK. Toutefois, au moment de la création de projets JNI, des fichiers header C (identification de la JVM par exemple) devront être liés lors de la phase de liaison. Ces fichiers header sont disponibles à la racine du répertoire JDK dans le répertoire %JAVA_HOME%\include. En fonction du système d'exploitation vous trouverez un sous-répertoire proposant des fichiers header spécifiques. Par exemple pour Windows %JAVA_HOME%\include\win32 ou pour Mac OS %JAVA_HOME%\include\darwin.

JNA (Java Native Access) est une API permettant d'accéder à du code natif sans faire appel explicitement à la couche de programmation JNI. Le développement nécessite une interface Java pour décrire le prototype, les fonctions et les structures contenus dans le code natif à appeler.

Contrairement à JNI, l'utilisation de JNA nécessite le téléchargement d'une bibliothèque spécifique. Vous trouverez donc sur le site de JNA la bibliothèque à télécharger, puis de nombreux exemples mettant en œuvre cette bibliothèque.

II. Développer une bibliothèque native via le langage C

Nous allons réaliser un programme C minimaliste qui affiche un texte sur la console.

  • Commencer par créer et éditer le fichier helloworld.h.
 
Sélectionnez
1.
void display(char* ch);
  • Créer la partie implémentation en éditant ce fichier helloworld.c.
 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
#include "helloworld.h"
#include <stdlib.h>
#include <stdio.h>

void display(char* ch) {
    printf("%s", ch);
}
  • Depuis la ligne de commande, compiler l'exemple
 
Sélectionnez
1.
$ gcc -c helloworld.c
  • Puis fabriquer la bibliothèque
 
Sélectionnez
1.
$ gcc -dynamiclib helloworld.o -o helloworld.dylib

À la fin de cette section vous devriez avoir un fichier helloworld.dylib. Si bien entendu vous êtes sur un autre système que Mac OS X vous devriez avoir un fichier helloworld.so pour Linux, et helloworld.dll pour Windows.

III. Développer un programme Java qui appelle la bibliothèque native

Nous allons maintenant créer un projet Java, ajouter la dépendance Maven, et faire le lien avec la bibliothèque :

  • Créer un projet Maven à partir de votre environnement de développement préféré.
  • Ajouter la dépendance vers la bibliothèque JNA.
 
Sélectionnez
1.
2.
3.
4.
5.
<dependency>
  <groupId>net.java.dev.jna</groupId>
  <artifactId>jna</artifactId>
  <version>4.3.0</version>
</dependency>
  • Créer une interface qui permettra de faire le lien entre les fonctions définies dans le C et les méthodes Java.
 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
public interface CHelloWorld extends Library {
  CHelloWorld INSTANCE = (CHelloWorld) Native.loadLibrary("helloworld",    CHelloWorld.class);

  void display(String g);

  int printf(String format, Object... args); // From stdio
}

La première instruction permet de charger en mémoire la bibliothèque native et d'associer les fonctions présentes dans le fichier .h avec les méthodes Java de l'interface CHelloWorld. Deux méthodes ont été définies : La première permet de se mapper sur la fonction hello(char* ch). La seconde se mappe sur une fonction non définie par nos soins mais définie dans la bibliothèque stdlib. Le fichier helloworld.dylib que nous avons créé dans la section précédente doit être à la racine du classpath du projet.

  • Créer un programme principal qui appelle les fonctions natives
 
Sélectionnez
1.
2.
3.
4.
5.
6.
public class Launcher {
  public static void main(String[] args) {
    CHelloWorld.INSTANCE.display("Bonjour tout le monde\n");
    CHelloWorld.INSTANCE.printf("J'ai %d chats", 2);
  }
}
  • Exécuter le programme principal. Vous devriez obtenir ce résultat
 
Sélectionnez
1.
2.
Bonjour tout le monde
J'ai 2 chats

IV. Conclusion et remerciements

Nous venons de réaliser une première expérimentation avec JNA. Cette solution est plus simple que celle de JNI car elle n'impose pas de compiler des dépendances de JNI dans son projet C. Par ailleurs, l'utilisation de JNA est pratique si vous avez déjà une bibliothèque native existante. Malheureusement il y aura un coût en terme de performance. Une réponse à cela a été apportée ici : https://github.com/java-native-access/jna/blob/master/www/FrequentlyAskedQuestions.md#how-does-jna-performance-compare-to-custom-jni. Le choix entre JNA ou JNI devra se poser quand la bibliothèque que vous souhaitez réaliser nécessite de hautes performances. Clairement dans notre exemple jouet, cela n'aura pas un grand impact d'utiliser JNI.

Bien entendu nous avons rapidement survolé la bibliothèque JNA. Il reste encore beaucoup de choses à étudier comme la conversion de type entre le langage Java et le langage C. Nous invitons les lecteurs à se rendre sur la page officielle de JNA pour plus de détails : github.com/java-native-access/jna.

Nous tenons à remercier fearyourself pour la relecture technique et Maxy35 pour la correction orthographique.

Vous avez aimé ce tutoriel ? Alors partagez-le en cliquant sur les boutons suivants : Viadeo Twitter Facebook Share on Google+   

  

Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par les droits d'auteur. Copyright © 2016 Mickael BARON. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.