通过DLL从Fortran调用Ada过程
我在标题中提到的混合语言编程中遇到了问题,更准确地说,就是从Ada到Fortran代码中获取数组。我的Ada过程声明如下所示:通过DLL从Fortran调用Ada过程,dll,fortran,ada,Dll,Fortran,Ada,我在标题中提到的混合语言编程中遇到了问题,更准确地说,就是从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);
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;
双精度数组的声明如下所示
type Double_Precision_Array is (Fortran_Integer range <>) of Double_Precision;
pragma Convention(Fortran, Double_Precision_Array);
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
PROGRAM TEST
IMPLICIT NONE
EXTERNAL initdll
EXTERNAL getdblarray
INTEGER :: LENGTH
DOUBLE PRECISION, DIMENSION(3):: ARR
CALL initdll
CALL getdblarray(ARR, LENGTH)
END PROGRAM TEST
fortran代码使用gfortran编译,并与创建的dll对应的库链接。命令行是
gfortran -o test.exe test.f Ada_Lib.lib
当我在Call语句之前将调试输出插入fortran代码时,我可以看到Get_Double_数组过程被调用,但我得到了异常
raised PROGRAM_ERROR: Name_Of_The_Ada_Body.adb: misaligned address value
此消息中的行号是我声明Array_Length变量的行号。我知道Ada属性的对齐方式,但我不知道在这种情况下如何使用它,因为我已经在使用Fortran兼容的数据类型(至少我这么认为)
当我在Ada端导出C约定,并将C约定用于数组声明,并在Fortran中使用“C,DLLIMPORT,ALIAs”调整cDEC$行时,长度值总是正确的,但数组的内容完全无用
阵列的范围仅在调试时固定。稍后,数组可以是任意长度的,这就是为什么我还需要返回数组的长度
任何有用的提示或解释我做错了什么以及下一步可以尝试什么?问题是Fortran无法以Ada理解的方式将无约束数组传递给Ada(Fortan 90的假定形状数组与Fortan 90有明确的对应关系,但我看不出有任何方法可以告诉Ada方面这就是预期的结果) 我一直在试验这个问题,在MacOSX上使用GCC4.8.0——在我记得在Ada运行时链接之后——它给出了与您得到的相同的异常(顺便问一下,您使用的编译器版本是什么?) 当我尝试将无约束数组传递给过程时
procedure Get_Double_Array
(Double_Array : out Double_Precision_Array;
编辑说
problem.ada:7:07: warning: type of argument "Get_Double_Array.Double_Array" is unconstrained array
problem.ada:7:07: warning: foreign caller must pass bounds explicitly
(我不知道为什么这是一个警告而不是错误!)和运行时的相同异常
我认为您可以做的是声明一个巨大的数组类型(当然,从来没有实际创建过):
(请注意下面的大小写导出名称),带主体
package body Problematic is
procedure Get_Double_Array
(Double_Array : out Double_Precision_Array;
Double_Array_Length : in Fortran_Integer;
Output_Length : out Fortran_Integer)
is
begin
Double_Array(1) := Double_Precision (1.0);
Double_Array(2) := Double_Precision (2.0);
Double_Array(3) := Double_Precision (3.0);
Output_Length := Fortran_Integer (3);
end Get_Double_Array;
end Problematic;
测试程序更改为
PROGRAM TPROG
IMPLICIT NONE
DOUBLE PRECISION, DIMENSION(4) :: XDOT
INTEGER :: LENGTH, J
CALL GET_DOUBLE_ARRAY(XDOT, 4, LENGTH)
PRINT *, 'output length is ', LENGTH
PRINT *, (XDOT(J), J=1,LENGTH)
END PROGRAM TPROG
(编译器无法处理您的接口
部分)
注意!到目前为止,Ada没有调用任何Ada运行时工具。如果是的话,你就得
- 安排在中链接运行时
- 初始化它,并可能完成它
我想那将是另一个问题 经过更多的实验并得到一些同事的帮助,我们发现了一个使用C约定的解决方案
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和gnatdell,我们创建了ADADDLL,并使用windows命令行
lib -machine:IX86 -def:Name_Of_Ada_Package.def -out:Name_Of_Ada_Package.lib > nul
对应的库
type Double_Precision_Array is (Fortran_Integer range <>) of Double_Precision;
pragma Convention(Fortran, Double_Precision_Array);
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
PROGRAM TEST
IMPLICIT NONE
EXTERNAL initdll
EXTERNAL getdblarray
INTEGER :: LENGTH
DOUBLE PRECISION, DIMENSION(3):: ARR
CALL initdll
CALL getdblarray(ARR, LENGTH)
END PROGRAM TEST
根据创建的库编译和链接此程序很好为什么要在Ada和Fortran中导出不同的符号?我将使用Fortran 2003与C的互操作性,而不是pragmas。不是说这是DEC pragma,不是GCC pragma,你确定gfortran明白吗,我想它不明白。另外,您是否确定您的
双精度
在两种语言中都表示相同的实类型,它几乎可以比默认类型大任何值,默认类型可以是任何值。@VladimirF:my lib中的ada函数名为\u name
。有一个GCC pragma DLLIMPORT,但cGCC$DLLIMPORT::_Name不起作用。编译器不接受前导下划线。这就是为什么我建议Fortran 2003bind(C,name=“name”)
并删除所有下划线的原因。@VladimirF:我找到了一些很好的例子,说明如何使用Fortran 2003,但使用2003标准不是我的决定。我应该只使用fortran 77构造。请注意,这些pragma在fortran 77标准的任何地方都没有定义,您正在玩有问题的东西,并为问题做好准备。还要注意,在示例中使用的是假定形状数组。这需要Fortran 90显式接口,根本不适合您。