使用JNA和Ada的Interface.C包将Ada动态库与Java接口 [英] Interface Ada dynamic Library with Java using JNA and Ada's Interface.C packages

查看:270
本文介绍了使用JNA和Ada的Interface.C包将Ada动态库与Java接口的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我必须写一个DLL应该提供一个简单的服务:

I have to write a DLL is supposed to provide a simple service that takes:


  • IN字符串或字节数组(相当于char *)

  • IN整数表示in char *的大小

  • IN等效于库*用于写入数据的char *缓冲区

  • 用于写入的可用char *缓冲区的大小

  • 将有效写入的大小写入out char * buffer

  • IN a string or byte array (equivalent of char*)
  • IN integer expliciting the size of the in char*
  • IN equivalent of char* buffer used by library to write data in
  • IN size of the available char* buffer for writing
  • OUT effetive written size into the out char* buffer

使用C观点,签名应如下所示:

Using a C point of view, the signature should look like:

void myService (char* inBuffer,  // as in string
                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
);

由于多种原因选择在Ada中编码库(多个Ada包重用,我们不会想再次编码或重新设计(遗留))。
该库应该用在Java项目中(我们不希望从Java端重新编写lib提供的服务)。
(主要原因是该库隐藏了复杂的Ada类型转换为JSON +协议库。)

The library is chosen to be coded in Ada for several reasons (several Ada packages reuse that we do no want to code again nor redesign (legacy)). The library is supposed to be used in a Java project (and we do not want to recode from Java side the services provided by lib). (The main reason for this is that the library hides complex Ada types conversion to JSON + a protocol library.)

该库还应与C接口或者将来使用C ++,所以主要的想法是依赖基本类型。

The library shall also be interfaced with C or C++ in the future, so the main idea is to rely on basic types.

如何同时连接到C和Java?

(我找到了一个解决方案,所以我想分享下面的详细信息;请参阅我自己的答案。无法使用复选框执行此操作由于旧的工作场所webbrowser非常错误...

(I found one solution, so I wanted to share the details below ; see my own answer. Couldn't do it using the checkbox due to old workplace webbrowser being very buggy ...)

推荐答案

以下是我如何设法与Java接口使用JNA和Ada的 Interface.C 包的Ada库。

Here is how I managed to interface Java with an Ada Library using the JNA and Ada's Interface.C packages.

dll相当简单,而且Ada这里提供的Java代码显示至少2个 char * 的用法作为in或out参数。

The dll is rather simple, and the Ada and Java code provided here show at least 2 usages of char* as in or out parameters.

可以阅读以下文档: JNA文档此Ada wiki ,< a href =http://www.adaic.org/resources/add_content/standards/05rm/html/RM-B-3.html\"rel =nofollow noreferrer> Ada标准文档和其他一些Ada标准文档

One can read the following docs : JNA documentation, this Ada wiki, Ada standard doc and some other Ada standard doc.

注意:请注意,以下Java代码适用于任何匹配的C接口声明。在帖子结尾处查看建议的 .h 文件。当然Java控制台结果将取决于DLL实现。

N.B.: Note that the following Java code would work with any matching C interface declaration. See the proposed .h file at end of post. Of course Java console result would depend on DLL implementation.

您需要包括你的java项目是 JNA.jar jar和 JNA-Platform.jar
请参阅 JNA GitHub 进行下载。

You'll need to include in your java project the JNA.jar jar and the JNA-Platform.jar. see JNA GitHub for downloads.

确保使用一致的Java和Ada lib体系结构:即32位或64位。否则,JNA / Java将无法加载库。

Be sure to use a consistent Java and Ada lib architecture : i.e. both 32 bits or both 64 bits. Otherwise, JNA/Java won't be able to load the library.

不要忘记使用以下VM选项 -Djna。 debug_load = true 查看JNA登录控制台!

Don't also forget to use the following VM option -Djna.debug_load=true to see the JNA's log in console !

您的Java项目/ bin文件夹应包含以下内容:

Your Java's project /bin folder shall contain the following:


  • 生成的Ada DLL(使用给定的代码,它将是 libadalib.dll

  • 您的 libgnat-version.dll

  • 您的 libgcc_s_seh-1.dll

  • the Ada DLL produced (with the given code, it will be libadalib.dll)
  • your libgnat-version.dll
  • your libgcc_s_seh-1.dll

请注意,您可能需要在您自己的DLL附近放置一些gnat DLL。我目前还没有设法将所有内容打包在我自己的DLL中。

Please note that you may need to put some gnat DLLs near your own one. I currently have not yet managed to pack everything in my own DLL.

所以你可能需要在生成的同一个文件夹中包含以下内容dll(即你的Java项目的 / bin 目录):

So you may need to have the following in same folder of the produced dll (I.e. your Java project's /bin directory):


  • 你的libgnat-version .dll

  • 你的libgcc_s_seh-1.dll

如果需要,可以使用DependancyWalker来解决这个问题。 (参见 http://www.dependencywalker.com/

Use DependancyWalker if needed to figure this out. (see http://www.dependencywalker.com/)

有一个GPR选项来激活/停用自动DLL详细说明,但我还没有测试过。

There is a GPR option to activate / deactivate automatic DLL elaboration, but I do not have tested it yet.

Ada代码

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 compiler, builder, binder, linker options
end adalib;






./ src ada files


./src ada files

ada_interface.ads

ada_interface.ads

pragma Ada_2012;

with Interfaces.C;
with Interfaces.C.Strings;


package ada_interface is

    procedure myService (
                         inBuffer       : in     Interfaces.C.Strings.chars_ptr; -- as in
                         anInteger      : in     Interfaces.C.int;
                         outBuffer      : in     Interfaces.C.Strings.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

ada_interface.adb

pragma Ada_2012;


with Ada.Text_IO;

with Interfaces.C.Strings;

package body ada_interface is

    procedure myService (
                         inBuffer       : in     Interfaces.C.Strings.chars_ptr; -- as in
                         anInteger      : in     Interfaces.C.int;
                         outBuffer      : in     Interfaces.C.Strings.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"); -- "<name of lib>init". May not be needed with proper options in GPR

       Required_Length : Natural := Natural (outBufferSize);
       myString : String := "This is a sample string";
       use type Interfaces.C.size_t;
    begin

       ada_elaboration;

       --
       Ada.Text_IO.Put_Line ("======= inside myService");

       -- print the string given by char*
       Ada.Text_IO.Put_Line (Interfaces.C.Strings.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.Strings.Value (outBuffer));

       -- use the char* to be used as out
       Interfaces.C.Strings.Update
         (Item   => outBuffer,
          Offset => 0,
          Str    => myString & 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.Strings.Strlen (outBuffer) - 1); -- see later java code and traces

    end myService;

end ada_interface;






现在Java代码:



加载和映射服务到库的类:


Now the Java code:

Class to load and map services to the library:

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
                       );
    }
}

调用库的类

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(String[] args) {

        String 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.setString(0, lorem); // offset 0, no need to start at another offset

        // in param but to used for out buffer
        String 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 String = " + Native.toString(buffer));
        System.out.println("In Java: read outBuffer as String with returned used buffer size = " + new String(buffer,0,usedBufferSize.getValue()));

    }

}






从java控制台输出(JNA调试为true)


Output from a java console (with JNA debug to 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:/<path>/TestMyLib/bin/libadalib.dll
Looking in <path>\TestMyLib\bin\libadalib.dll
Found library 'libadalib' at <path>\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 String = This is a sample string // reads the full buffer
In Java: read outBuffer as String with returned used buffer size = This is a sample strin // reads a length of 22 (so the 'g' is missing)






现在,使用匹配的.h文件,Ada库也可以轻松地与C或C ++接口:


Now the Ada library can also be easily interfaced with C or C++, using a matching .h file:

void myService (char* inBuffer,  // as in string
                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
);






如何在从Eclipse调用时调试lib?


How to debug the lib while called from Eclipse ?

使用Gnat Pro Studio(GPS),您可以进入调试器视图并将gdb附加到Java应用程序进程的PID(用于Windows)。
但是,如果没有以下技巧,你将无法设置断点。

Using Gnat Pro Studio (GPS), you can go in the debugger view and attach gdb to the PID (for windows) of your java application process. However, without the following trick, you won't be able to set breakpoints.

诀窍是在DLL内部有一个无限循环(对于dev目的)。

The trick is to have an infinite loop inside the DLL (for dev purposes).

正文:

while flag loop
    null;
end loop;

广告文件:

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

一旦gdb设法附加到正在运行的DLL代码(无限循环), gdb将中断。

Once the gdb manages to attach to the running DLL code (infinite loop), the gdb will break.

在循环中放置断点,gdb中的类型 c
它将在你的循环中断。

Put a breakpoint in your loop, and the type in gdb c. It will break in your loop.

在代码中的其他地方放置另一个断点,然后键入follwong set flag:= false ,然后 c

Put another breakpoint elsewhere in code, then type the follwong set flag := false, and then c.

现在gdb应该继续下一个断点。

Now the gdb should continue to next breakpoint.

(或者使用n(下一个)gdb指令自行调试。)

(Or use the "n" (next) gdb instruction to debug at your own will.)

这篇关于使用JNA和Ada的Interface.C包将Ada动态库与Java接口的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆