Interface Bibliothèque dynamic Ada avec Java à l’aide des packages JNA et Interface.C d’Ada

Je dois écrire une DLL est censé fournir un service simple qui prend:

  • EN une chaîne de caractères ou un tableau d’octets (équivalent de char *)
  • IN entier expliquant la taille du caractère in *
  • IN équivalent à char * buffer utilisé par la bibliothèque pour écrire des données dans
  • Taille IN du tampon char * disponible pour l’écriture
  • Taille écrite effective dans la mémoire tampon out *

En utilisant un sharepoint vue C, la signature devrait ressembler à:

void myService (char* inBuffer, // as in ssortingng int anInteger, // as in param char* outBuffer, // used as out buffer, but initalized by calling code int outBufferSize, // the initaliaed size int usedBufferSize // used as out param, the actually used size ); 

La bibliothèque est choisie pour être codée dans Ada pour plusieurs raisons (plusieurs packages Ada réutilisés que nous ne voulons plus coder ni redéfinir (hérités)). La bibliothèque est supposée être utilisée dans un projet Java (et nous ne voulons pas recoder à partir de Java les services fournis par lib). (La raison principale en est que la bibliothèque masque la conversion complexe des types Ada en JSON + une bibliothèque de protocoles.)

La bibliothèque devra également être interfacée avec C ou C ++ à l’avenir, donc l’idée principale est de s’appuyer sur des types de base.

Comment faire l’interface avec C et Java en même temps?

(J’ai trouvé une solution, alors je voulais partager les détails ci-dessous; voir ma propre réponse. Impossible de le faire en utilisant la case à cocher car l’ancien navigateur Web était très bogué … )

Voici comment j’ai réussi à interfacer Java avec une bibliothèque Ada à l’aide des packages JNA et Interface.C d’Ada.

La dll est assez simple, et les codes Ada et Java fournis ici montrent au moins 2 utilisations de char* tant que parameters in ou out.

On peut lire les documents suivants: la documentation de la JNA , ce wiki Ada, le doc standard Ada et quelques autres doc standard Ada .

NB: Notez que le code Java suivant fonctionnera avec n’importe quelle déclaration d’interface C correspondante. Voir le fichier .h proposé à la fin du post. Bien sûr, le résultat de la console Java dépend de l’implémentation de la DLL.

Contrôles préliminaires

Vous devez inclure dans votre projet Java le JNA.jar et le JNA.jar JNA-Platform.jar . voir JNA GitHub pour les téléchargements.

Veillez à utiliser une architecture Java et Ada lib cohérente: à la fois 32 bits ou 64 bits. Sinon, JNA / Java ne pourra pas charger la bibliothèque.

N’oubliez pas également d’utiliser l’option de machine virtuelle suivante -Djna.debug_load=true pour afficher le journal de connexion de la JNA dans la console!

Votre dossier projet / bin Java doit contenir les éléments suivants:

  • la DLL Ada produite (avec le code donné, ce sera libadalib.dll )
  • votre libgnat-version.dll
  • votre libgcc_s_seh-1.dll

Tout d’abord, la partie Ada:

Veuillez noter que vous aurez peut-être besoin de placer des DLL de moustiques près de votre propre DLL. Je n’ai pas encore réussi à tout emballer dans ma propre DLL.

Il se peut donc que vous deviez avoir les éléments suivants dans le même dossier de la dll produite (le répertoire /bin votre projet Java):

  • votre libgnat-version.dll
  • votre libgcc_s_seh-1.dll

Utilisez DependancyWalker si nécessaire pour résoudre ce problème. (voir http://www.dependencywalker.com/ )

Il existe une option GPR pour activer / désactiver l’élaboration automatique de DLL, mais je ne l’ai pas encore testée.


Code Ada

Projet de bibliothèque Ada:

 project adalib is for Languages use ("Ada"); for Source_Dirs use (project'Project_Dir & "./src"); for Library_Kind use "dynamic"; -- for DLL for Library_Name use project'Name; -- will produce "libadalib.dll" for Library_Interface use ("ada_interface"); for Library_Dir use project'Project_Dir & "./dll"; for Library_Src_Dir use project'Project_Dir & "./dll"; -- include other DLL / .a here if needed -- for Library_Options use ("-L" & path_to_lib, -- "-l" & path_to_lib -- ); -- define your favorite comstackr, builder, binder, linker options end adalib; 

fichiers ./src ada

ada_interface.ads

 pragma Ada_2012; with Interfaces.C; with Interfaces.C.Ssortingngs; package ada_interface is procedure myService ( inBuffer : in Interfaces.C.Ssortingngs.chars_ptr; -- as in anInteger : in Interfaces.C.int; outBuffer : in Interfaces.C.Ssortingngs.chars_ptr; -- as out buffer outBufferSize : in Interfaces.C.int; -- max out buffer size usedBufferSize : out Interfaces.C.int ); pragma Export (Convention => C, Entity => myService, External_Name => "Renamed_myService"); end ada_interface; 

ada_interface.adb

 pragma Ada_2012; with Ada.Text_IO; with Interfaces.C.Ssortingngs; package body ada_interface is procedure myService ( inBuffer : in Interfaces.C.Ssortingngs.chars_ptr; -- as in anInteger : in Interfaces.C.int; outBuffer : in Interfaces.C.Ssortingngs.chars_ptr; -- as out buffer outBufferSize : in Interfaces.C.int; -- max out buffer size usedBufferSize : out Interfaces.C.int ) is -- if elaboration needs to be explicitly called procedure ada_elaboration; pragma import (C, ada_elaboration, "adalibinit"); -- "init". May not be needed with proper options in GPR Required_Length : Natural := Natural (outBufferSize); mySsortingng : Ssortingng := "This is a sample ssortingng"; use type Interfaces.C.size_t; begin ada_elaboration; -- Ada.Text_IO.Put_Line ("======= inside myService"); -- print the ssortingng given by char* Ada.Text_IO.Put_Line (Interfaces.C.Ssortingngs.Value (inBuffer)); -- the int Ada.Text_IO.Put_Line (Natural'Image (Natural (anInteger))); -- current value of the char* to be used as OUT buffer Ada.Text_IO.Put_Line (Interfaces.C.Ssortingngs.Value (outBuffer)); -- use the char* to be used as out Interfaces.C.Ssortingngs.Update (Item => outBuffer, Offset => 0, Str => mySsortingng & Interfaces.C.To_Ada (Interfaces.C.nul), -- "& Interfaces.C.To_Ada(Interfaces.C.nul)" is equivalent to "& Character'Val(0)" Check => false); usedBufferSize := Interfaces.C.int (Interfaces.C.Ssortingngs.Strlen (outBuffer) - 1); -- see later java code and traces end myService; end ada_interface; 

Maintenant le code Java:

Classe pour charger et mapper des services à la bibliothèque:

 package tst; import com.sun.jna.Library; import com.sun.jna.Native; import com.sun.jna.Pointer; import com.sun.jna.ptr.IntByReference; public class Ada_Lib { public interface My_Ada_Lib extends Library { My_Ada_Lib instance = (My_Ada_Lib) Native.loadLibrary("libadalib", My_Ada_Lib.class); My_Ada_Lib synchronizedInstance = (My_Ada_Lib) Native.synchronizedLibrary(instance); void Renamed_myService ( Pointer inBuffer, int anInteger, byte[] outBuffer, int outBufferSize, IntByReference usedBufferSize ); } } 

Classe pour appeler la bibliothèque

 package tst; import com.sun.jna.Memory; import com.sun.jna.Native; import com.sun.jna.Pointer; import com.sun.jna.ptr.IntByReference; import tst.Ada_Lib.My_Ada_Lib; public class TestMyLib { private static My_Ada_Lib theLib = Ada_Lib.My_Ada_Lib.synchronizedInstance; public static void main(Ssortingng[] args) { Ssortingng lorem = "Sin autem ad adulescentiam perduxissent, dirimi tamen interdum contentione vel uxoriae condicionis vel commodi alicuius, quod idem adipisci uterque non posset. Quod si qui longius in amicitia provecti essent, tamen saepe labefactari, si in honoris contentionem incidissent; pestem enim nullam maiorem esse amicitiis quam in plerisque pecuniae cupiditatem, in optimis quibusque honoris certamen et gloriae; ex quo inimicitias maximas saepe inter amicissimos exstitisse." + "\n" + "Quanta autem vis amicitiae sit, ex hoc intellegi maxime potest, quod ex infinita societate generis humani, quam conciliavit ipsa natura, ita contracta res est et adducta in angustum ut omnis caritas aut inter duos aut inter paucos iungeretur." + "\n" + "Haec subinde Constantius audiens et quaedam referente Thalassio doctus, quem eum odisse iam conpererat lege communi, scribens ad Caesarem blandius adiumenta paulatim illi subtraxit, sollicitari se simulans ne, uti est militare otium fere tumultuosum, in eius perniciem conspiraret, solisque scholis iussit esse contentum palatinis et protectorum cum Scutariis et Gentilibus, et mandabat Domitiano, ex comite largitionum, praefecto ut cum in Syriam venerit, Gallum, quem crebro acciverat, ad Italiam properare blande hortaretur et verecunde.\n"; // in params int inputInt = 25; Pointer p_Lorem = new Memory(lorem.length()+1); // +1 for C's \0 p_Lorem.setSsortingng(0, lorem); // offset 0, no need to start at another offset // in param but to used for out buffer Ssortingng stubOut = "Hello World ! 0123456789\0"; int maxBufferSize = (stubOut.length()); byte[] buffer = new byte[maxBufferSize]; buffer = stubOut.getBytes(); IntByReference usedBufferSize = new IntByReference(0); // any value works, since it is used as out param System.out.println("-------------------- Call to Lib ----------------------------"); // call the lib ! theLib.Renamed_myService(p_Lorem, inputInt, buffer, maxBufferSize, usedBufferSize); System.out.println("--------------------- Back to java --------------------------"); System.out.println("In Java: used buffer size = " + usedBufferSize.getValue()); System.out.println("In Java: read outBuffer as Ssortingng = " + Native.toSsortingng(buffer)); System.out.println("In Java: read outBuffer as Ssortingng with returned used buffer size = " + new Ssortingng(buffer,0,usedBufferSize.getValue())); } } 

Sortie d’une console java (avec le débogage JNA à true)

 Looking in classpath from sun.misc.Launcher$AppClassLoader@4e0e2f2a for /com/sun/jna/win32-x86-64/jnidispatch.dll Found library resource at jar:file:/ [...] Looking for library 'libadalib' Adding paths from jna.library.path: null Trying libadalib.dll Adding system paths: [] Trying libadalib.dll Looking for lib- prefix Trying liblibadalib.dll Looking in classpath from sun.misc.Launcher$AppClassLoader@4e0e2f2a for libadalib Found library resource at file://TestMyLib/bin/libadalib.dll Looking in \TestMyLib\bin\libadalib.dll Found library 'libadalib' at \TestMyLib\bin\libadalib.dll -------------------- Call to Lib ---------------------------- ======= inside myService Sin autem ad adulescentiam perduxissent, dirimi tamen interdum contentione vel uxoriae condicionis vel commodi alicuius, quod idem adipisci uterque non posset. Quod si qui longius in amicitia provecti essent, tamen saepe labefactari, si in honoris contentionem incidissent; pestem enim nullam maiorem esse amicitiis quam in plerisque pecuniae cupiditatem, in optimis quibusque honoris certamen et gloriae; ex quo inimicitias maximas saepe inter amicissimos exstitisse. Quanta autem vis amicitiae sit, ex hoc intellegi maxime potest, quod ex infinita societate generis humani, quam conciliavit ipsa natura, ita contracta res est et adducta in angustum ut omnis caritas aut inter duos aut inter paucos iungeretur. Haec subinde Constantius audiens et quaedam referente Thalassio doctus, quem eum odisse iam conpererat lege communi, scribens ad Caesarem blandius adiumenta paulatim illi subtraxit, sollicitari se simulans ne, uti est militare otium fere tumultuosum, in eius perniciem conspiraret, solisque scholis iussit esse contentum palatinis et protectorum cum Scutariis et Gentilibus, et mandabat Domitiano, ex comite largitionum, praefecto ut cum in Syriam venerit, Gallum, quem crebro acciverat, ad Italiam properare blande hortaretur et verecunde. 25 Hello World ! 0123456789 --------------------- Back to java -------------------------- In Java: used buffer size = 22 In Java: read outBuffer as Ssortingng = This is a sample ssortingng // reads the full buffer In Java: read outBuffer as Ssortingng with returned used buffer size = This is a sample ssortingn // reads a length of 22 (so the 'g' is missing) 

Maintenant, la bibliothèque Ada peut également être facilement interfacée avec C ou C ++, en utilisant un fichier .h correspondant:

 void myService (char* inBuffer, // as in ssortingng int anInteger, // as in param char* outBuffer, // used as out buffer, but initalized by calling code int outBufferSize, // the initaliaed size int usedBufferSize // used as out param, the actually used size ); 

Comment déboguer la lib en appelant depuis Eclipse?

En utilisant Gnat Pro Studio (GPS), vous pouvez accéder à l’affichage du débogueur et associer gdb au PID (pour Windows) de votre processus d’application Java. Cependant, sans l’astuce suivante, vous ne pourrez pas définir de points d’arrêt.

L’astuce consiste à avoir une boucle infinie à l’intérieur de la DLL (à des fins de développement).

corps:

 while flag loop null; end loop; 

fichier d’annonces:

 flag : boolean := true; -- in private part 

Une fois que la firebase database gdb parvient à se connecter au code de la DLL en cours d’exécution (boucle infinie), elle se brise.

Mettez un point d’arrêt dans votre boucle et tapez gdb c . Ça va casser dans votre boucle.

Mettez un autre point d’arrêt ailleurs dans le code, puis tapez l’indicateur follwong set flag := false , puis c .

Maintenant, la gdb devrait continuer jusqu’au prochain point d’arrêt.

(Ou utilisez l’instruction “n” (suivante) de gdb pour déboguer à votre guise.)