Appelez un programme C depuis java avec JNA

Et oui, on peut appeler nativement une lib C, C++ Rust ou Go directement en Java grâce à JNA.

En fait c’est facile.

D’abord, il faut une lib en C. Par exemple en voici une :

helloworld.h

char *hello(char* ch);

helloworld.c

#include "helloworld.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

char* hello(char* ch) {
    char prefix[] = "Hello ";
    char *res;
    res = malloc(strlen(prefix) + strlen(ch));
    strcpy(res, prefix);
    strcat(res,ch);
    return res;
}

Hey, mais, il y a un malloc sans free, ça craint. Bon, pas de soucis, on verra plus loi comment faire un free après l’appel.

Ok, maintenant, on compile :

$ gcc -c helloworld.c 
$ gcc -shared -dynamiclib helloworld.o -o ./helloworld.so

Maintenant, la partie Java. Il faut avoir la lib JNA dans son classpath, bien évidement.

CHelloWorld.java

package io.warp10.ext.test;

import com.sun.jna.Library;
import com.sun.jna.Native;
import com.sun.jna.Pointer;

public interface CHelloWorld extends Library {
  // On charge la lib
  CHelloWorld INSTANCE = Native.load("helloworld.so", CHelloWorld.class);
  // on décrit l'interface utilisée
  Pointer hello(String g);
  // Youpi, on pourra appeler free
  void free(Pointer p);  // JNA le fournit (et pas que ça)
}

Test.java

public class Test {
  public static void main(String[] args) {
    Pointer ptr = null;
    try {
      // on appelle notre fonction C
      ptr = CHelloWorld.INSTANCE.hello(args[0]);
      // on parse le résultat
      System.out.println(ptr.getString(0));
    } catch (Exception e) {
      throw e;
    } finally {
      // On libère la mémoire
      if (null != ptr) {
        CHelloWorld.INSTANCE.free(ptr); 
      }
    }
  }
}

On compile :

$ javac -cp ./jna-5.10.0.jar ./*.java

On exécute :

$ java -cp /opt/jna-5.10.0.jar:./* mon.package.Test Kitty
Hello Kitty

Et voilà.

Partager c'est la vie