2

タイトルで述べたように、混合言語プログラミング、より正確には Ada から Fortran コードへの配列の取得に問題があります。私のAdaプロシージャ宣言は次のようになります。

    procedure Get_Double_Array
      (Double_Array    : in System.Address;
       Length_of_Array : in System.Address);
    pragma Export(Fortran, Get_Double_Array, "Get_Double_Array_");

私のプロシージャの対応する本体は

    procedure Get_Double_Array
      (Double_Array : in System.Address;
       Length_Of_Array : in System.Address)
    is
        use Interfaces.Fortran;

        Array_Length : Fortran_Integer;
        for Array_Length'Address use Length_Of_Array;

        Result_Array : Double_Precision_Array(1..3);
        for Result_Array'Address use Double_Array;
    begin
        Result_Array(1) := Double_Precision(1.0);
        Result_Array(2) := Double_Precision(2.0);
        Result_Array(3) := Double_Precision(3.0);

        Array_Length := Fortran_Integer(Result_Array'Last);
    end Get_Double_Array;

Double_Precision_Array の宣言は次のようになります

    type Double_Precision_Array is (Fortran_Integer range <>) of Double_Precision;
    pragma Convention(Fortran, Double_Precision_Array);

この手順を DLL で使用できるようにすることは、既に機能しています。作成された dll の dumpbin /exports は、期待どおりに Get_Double_Array_ を示します。

Fortran プログラムは次のようになります。

    PROGRAM TPROG
    IMPLICIT NONE

    INTERFACE
    SUBROUTINE GETARR(DPARR, LENGTH)
    cDEC$ ATTRIBUTES DLLIMPORT, ALIAS : '_Get_Double_Array_' :: GETARR
    DOUBLE PRECISION, DIMENSION (:) :: DPARR
    INTEGER :: LENGTH
    END SUBROUTINE
    END INTERFACE

    DOUBLE PRECISION, DIMENSION(3) :: XDOT
    INTEGER :: LENGTH
    CALL GETARR(XDOT, LENGTH)
    END PROGRAM TPROG

fortran コードは gfortran でコンパイルされ、作成された dll に対応する lib とリンクされます。コマンドラインは

    gfortran -o test.exe test.f Ada_Lib.lib

Fortran コードの Call ステートメントの前にデバッグ出力を挿入すると、Get_Double_Array プロシージャが呼び出されていることがわかりますが、例外が発生します。

    raised PROGRAM_ERROR: Name_Of_The_Ada_Body.adb: misaligned address value

このメッセージの行番号は、Array_Length 変数を宣言する場所です。Ada Attribute 'Alignment については知っていますが、Fortran 互換のデータ型を既に使用しているため (少なくとも私はそう思います)、この状況での使用方法がわかりません。

Ada 側で C 規則をエクスポートし、配列宣言にも C 規則を使用し、Fortran の cDEC$ 行を 'C, DLLIMPORT, ALIAs' に適合させると、長さの値は常に正しくなりますが、配列の内容は完全に役に立たない。

配列の範囲は、デバッグ用にのみ固定されています。後で、Array は任意の長さにすることができるため、配列の長さも返す必要があります。

私が間違っていること、次に何を試すことができるかについて、役立つヒントや説明はありますか?

4

2 に答える 2

0

もう少し実験し、何人かの同僚の助けを借りた後、C の規則を使用するソリューションを見つけました。

  1. AdaInit と AdaFinal の手順を忘れていました。これらの関数は、dll の作成中にバインダーによって作成されます。機能を使用する前に、AdaInit 関数を呼び出す必要があります。これに対する私たちのアプローチは、次のような関数をエクスポートすることです

    procedure Init_Dll;
    pragma Export(C, Init_Dll, "initdll_");
    

宣言のプライベート部分に追加しました

    procedure AdaInit;
    pragma Import(C, AdaInit);

    procedure AdaFinal;
    pragma Export(C, AdaFinal);

Init_Dll の本体は単純です

    procedure Init_Dll
    is
    begin
        AdaInit;
    end Init_Dll;

次に、gnatmake と gnatdll を使用して Ada dll を作成し、Windows コマンドラインで

    lib -machine:IX86 -def:Name_Of_Ada_Package.def -out:Name_Of_Ada_Package.lib > nul

対応するライブラリ

  1. Fortran 側では、インターフェイスの代わりに外部コマンドを使用したため、プログラムは次のようになります。

    PROGRAM TEST
    IMPLICIT NONE
    EXTERNAL initdll
    EXTERNAL getdblarray
    INTEGER :: LENGTH
    DOUBLE PRECISION, DIMENSION(3):: ARR
    CALL initdll
    CALL getdblarray(ARR, LENGTH)
    END PROGRAM TEST
    

作成されたライブラリに対してこのプログラムをコンパイルおよびリンクすると、問題なく動作します

于 2013-06-19T08:10:02.640 に答える