Appelez un programme C depuis java avec JNA

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

1
char *hello(char* ch);

helloworld.c

1
2
3
4
5
6
7
8
9
10
11
12
13
#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 :

1
2
$ 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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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 :

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

On exécute :

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

Et voilà.

Commentaires