Interopérabilité Java/C++

Programming, Computer Science · lab

Browse all programmation documents

L3 Génie Logiciel – Intéropérabilité Java/C++, Remoting

Appels de fonctions et de méthodes passant la barrière du langage

Vous allez étudier dans ce TP les possibilités d’interopérabilité entre Java et C++, ainsi que

Java RMI.

Communication Java  C++

Création d’un projet C++

Sous Eclipse, créez un projet de type « C/C++Managed Build » ou bien un projet de type

« CMake Project ». Si vous préférez créer le projet depuis un terminal, c’est aussi possible.

Projet CMake

Le projet généré contient déjà un fichier source. Vous allez générer une bibliothèque partagée

(pas un exécutable), donc votre fichier CMakeLists.txt doit être édité pour prendre la forme :

cmake_minimum_required (VERSION 3.1)

project (votreprojet)

set(CMAKE_CXX_STANDARD 11)

add_library(votreprojet SHARED votreprojet.cpp)

set_target_properties(votreprojet PROPERTIES POSITION_INDEPENDENT_CODE ON)

La dernière ligne engendre la passation de l’option –fPIC sur la ligne de commande de

g++/gcc, ce qui est requis. En l’absence de cette ligne, des erreurs ‘ld’ peuvent se produire

provoquant l’échec du build.

Projet Managed Build

Sélectionnez un projet de type « Shared Library », qui sera vide. Ajoutez ensuite un fichier

.cpp avec New > Source File, et donnez un nom de fichier finissant par ‘.cpp’.

Build depuis un terminal

Vous pouvez générer une bibliothèque partagée en faisant :

g++ –fPIC -std=c++11 votrefichier.cpp -shared -o votreprojet.so

Notez que –fPIC est obligatoire avec g++/gcc sinon une erreur ‘ld’ apparaît. De même, ne

surtout pas mettre ‘-c’ sur la ligne de commande, ce qui aurait pour effet de générer un fichier

incorrect.

Build sous Eclipse

Faites le build en cliquant sur le marteau dans la « Launch Bar ».

Ecriture du code C++

Advertisement

Ajoutez le code suivant :

[email protected] - 2019

extern "C" void test_jni(char *mystring)

{

cout << "Hello world";

}

Création d’un projet Java

Créez un projet Java et convertissez ce projet en projet Maven (clic droit sur le nœud du

projet, puis ‘Configure’ puis ‘Convert to Maven project’). Editer ensuite le fichier pom.xml (qui

apparait automatiquement) et après la section <build>, ajouter une section <dependencies>

contenant :

<dependencies>

<dependency>

<groupId>net.java.dev.jna</groupId>

<artifactId>jna</artifactId>

<version>4.3.0</version>

</dependency>

</dependencies>

Sauvez le fichier pom.xml (Ctrl+S).

Ecriture du code Java

Deux classes doivent être créées en Java. La première contient le « proxy JNA » pour le code

natif :

// LibNative.java

import com.sun.jna.Library;

import com.sun.jna.Native;

public interface LibNative extends Library

{

LibNative INSTANCE = (LibNative)Native.loadLibrary(

"..\\fc.Application.JNAJNI.Native\\build\\"

"cmake.debug.win32.x86_64\\"

libfc.Application.JNAJNI.Native.dll", LibNative.class);

Advertisement

void test_jni(String message);

}

Attention, le chemin de fichier est relatif, et doit refléter votre environnement (environnement

Windows+MinGW en mode Debug pour la ligne du dessus qu’il vous faudra changer).

La seconde classe, dans un autre fichier, contient le programme principal :

package fc.Application.JNAJNI;

public class Main

{

public static void main(String[] args)

{

System.out.println("Hello from Java");

LibNative.INSTANCE.test_jni("Hello from C++");

}

}

Lancement du programme

[email protected] - 2019

Lancez maintenant le programme Java depuis Eclipse. Si votre programme fonctionne, vous

verrez deux lignes s’afficher dans la Console d’Eclipse.

Si vous avez mal paramétré le chemin d’accès à votre bibliothèque partagée C++, vous aurez

une exception de type « UnsatisfiedLinkException ».

Examen de la pile des appels

Relancez le programme, mais en mode déboguage cette fois. Examinez ce qu’il se passe lorsque

vous faites un « step into » avec le débogueur sur la ligne contenant l’appel JNI :

Pour aller plus loin

Déclarez en Java le « miroir » d’une classe C++. Pour ce faire, déclarez en Java une classe

ayant des méthodes « native » qui appellent du code C++. Dans la classe Java, déclarez un

champ de type jlong qui vous permettra de sauver le pointeur ‘this’ de votre objet C++.

[email protected] - 2019

Communication C++  Java

Hosting de la JVM

Le principe est cette fois de créer un projet exécutable en C++ qui instancie une machine

Advertisement

virtuelle Java. On charge dans cette machine virtuelle du code Java ayant déjà été compilé. Le

code Java compilé est ensuite appelé depuis C++.

Création d’un projet C++

Créez à nouveau un projet C++, un exécutable cette fois, de préférence avec CMake car vous

allez devoir intégrer les dépendances JNI, qui sont simples à récupérer avec CMake.

cmake_minimum_required (VERSION 3.1)

project (fc.Application.JVMHost)

set(CMAKE_CXX_STANDARD 11)

find_package(JNI REQUIRED)

INCLUDE_DIRECTORIES(${JNI_INCLUDE_DIRS})

add_executable(fc.Application.JVMHost fc.Application.JVMHost)

target_link_libraries(fc.Application.JVMHost ${JNI_LIBRARIES})

Votre code dans le main va contenir la création d’une JVM :

https://pastebin.com/PrbWpXcE

Attention, ce code doit être modifié pour que la chaine java.class.path reflète votre

environnement. Cette variable passée sous forme de chaîne de caractères à la JVM indique

l’emplacement des fichiers compilés (extension .class) du projet Java que vous allez créer dans

la prochaine section (ci-après). La valeur de cette variable doit être définie de sorte que chaque

fichier .class se trouve dans des sous-dossiers correspondant à son espace de nom.

Création d’un projet Java qui va être appelé par C++

Créez un projet Java et ajouter une classe ayant pour espace de nom

fc.Application.JVMHost.Java et ayant pour nom TestJni. Cette classe ne doit exposer qu’une

seule méthode publique statique, nommée greet, et acceptant un argument de type String.

Affichez le nom reçu en paramètre dans la console.

Exécution du code C++

Lancez le programme C++ : la communication avec Java doit être assurée.

Diversification des types des arguments passés entre Java et C++

Pour aller plus loin dans la communication Java  C++, passez des types autre que String,

et retournez des valeurs autre que void. Vous pouvez tester les tableaux également. Veillez à

bien libérer les données créées avec les fonctions appropriées, à bien respecter les types (jint au

lieu de int, jstring au lieu de string etc.) et à être rigoureux.

Advertisement

[email protected] - 2019

Exports de classes plus complexes

Le kit JDK installé en salles machines contient un compilateur qui permet de lire un fichier

.class et d’en générer un fichier header .H, utilisable en C/C++.

Introduction à Java RMI

Dans cette partie vous allez vous familiariser avec Java RMI, Java Remote Method Invocation.

Reprenez le code qui a été vu en cours/TD, en faisant 3 projets Eclipse distincts.

Code partagé entre le client et le serveur :

l’interface RMI doit dériver de java.rmi.Remote

la signature de la méthode distante doit comporter « throws RemoteException » à la

fin de la déclaration

Code serveur :

implémentation de l’interface, dérivant de UnicastRemoteObject

fonction main, permettant de réceptionner les appels des clients

Code client :

fonction main effectuant un lookup de l’instance distante avec Naming.lookup

 appel de la méthode distante

Le code serveur doit être du type :

https://pastebin.com/cHyg5ChE

La fonction main() du serveur :

https://pastebin.com/nk4PhyAf

Une fois tout mis en place, vous testerez également comment passer une référence d’objet

distant vers le client, en ajoutant une méthode sur l’interface, renvoyant une référence d’objet

en retour. Ajoutez ce type dans le projet contenant le code partagé client/serveur.

[email protected] - 2019