Python 使用ctypes调用FORTRAN DLL
我正在尝试学习如何将FORTRAN代码编译成一个DLL,我可以使用ctypes从Python调用该DLL。即使是一个简单的例子也不起作用,有人能帮忙吗 我有一个FORTRAN程序:Python 使用ctypes调用FORTRAN DLL,python,dll,fortran,mingw,ctypes,Python,Dll,Fortran,Mingw,Ctypes,我正在尝试学习如何将FORTRAN代码编译成一个DLL,我可以使用ctypes从Python调用该DLL。即使是一个简单的例子也不起作用,有人能帮忙吗 我有一个FORTRAN程序: subroutine ex(i) integer i i=i+1 return end 然后我试着从Python运行它 from ctypes import * DLL = windll.test print DLL print getattr(DLL,'ex_') print DLL[1
subroutine ex(i)
integer i
i=i+1
return
end
然后我试着从Python运行它
from ctypes import *
DLL = windll.test
print DLL
print getattr(DLL,'ex_')
print DLL[1]
print DLL.ex_
x = pointer( c_int(3) )
DLL.ex_( x )
我使用MinGW编译器编译它,如下所示
gfortran -c test.f
gfortran -shared -mrtd -o test.dll test.o
查看创建的DLL,我看到
Microsoft (R) COFF/PE Dumper Version 12.00.30723.0
Copyright (C) Microsoft Corporation. All rights reserved.
Dump of file test.dll
File Type: DLL
Section contains the following exports for test.dll
00000000 characteristics
0 time date stamp Thu Jan 01 13:00:00 1970
0.00 version
1 ordinal base
1 number of functions
1 number of names
ordinal hint RVA name
1 0 00001280 ex_
Summary
1000 .CRT
1000 .bss
1000 .data
1000 .edata
1000 .eh_fram
1000 .idata
1000 .rdata
1000 .reloc
1000 .text
1000 .tls
然后我尝试从Python访问它
from ctypes import *
DLL = windll.test
print DLL
print getattr(DLL,'ex_')
print DLL[1]
print DLL.ex_
x = pointer( c_int(3) )
DLL.ex_( x )
输出是
<WinDLL 'test', handle 6bec0000 at 2143850>
<_FuncPtr object at 0x020E88A0>
<_FuncPtr object at 0x020E8918>
<_FuncPtr object at 0x020E88A0>
Traceback (most recent call last):
File "C:\proj_py\test.py", line 20, in <module>
DLL.ex_( x )
ValueError: Procedure probably called with too many arguments (4 bytes in excess)
有人能提供解决方案吗
谢谢Fortran通常是通过引用传递的。当从其他语言(如C)调用时,这意味着将内存地址传递给Fortran子例程。显然,Python实现是类似的。在编辑之前,您出现了一个错误,该错误表示“0x000003处的非法访问”,该值可能与您尝试传递的值“3”相同。您很好地输入了Fortran子例程,但当它尝试进行加法时,它在内存位置3查找整数,而不是在加法本身中使用值3
编辑之后,您正在传递一个指针(我想是根据我的评论)。这给出了一个不同的错误。它表明您传递了一个额外的参数,因为它得到的数据比预期的多4字节。我认为这可能是一些32位库和一些64位库之间的不兼容,两种体系结构中指针的长度可能相差4个字节。DLL中的Fortran子程序可能真的需要指针。在Python中尝试
x=byref(3)
,而不是x=c_int(3)
。如果行得通,我会发布一个较长的解释作为答案。我看到你在我第一次发表评论后编辑了你的问题,错误消息也发生了变化。这很好,因为一个问题解决了。现在看来,不同大小的指针之间存在一些不兼容。从这里很难看出到底是什么错误,但看起来您正在将64位指针传递到一个库中,而该库需要32位指针。(这是一个4字节的差异-正是您的错误消息报告的内容。)@blair您的库正在使用(调用者清理堆栈),而不是(调用者清理)。将其加载为dll=CDLL('test')
。似乎@eryksun已经给出了答案。谢谢:-)当链接调用stdcall时,我想使用选项-mrtd。那个选项在做什么?对不起,我错过了-mrtd
是一个编译选项,而不是链接选项。如果需要stdcall,请使用gfortran-c-mrtd test.f
。在这种情况下,使用DLL=windl('test')
加载DLL。