使用ctypes调用FORTRAN DLL [英] Calling a FORTRAN DLL using ctypes
问题描述
我试图学习如何将FORTRAN代码编译成一个可以使用ctypes从Python调用的DLL。即使一个简单的例子不工作,任何人都可以帮忙吗?
我有一个FORTRAN过程:
子程序ex(i)
整数
i = i + 1
返回
结束
然后我尝试从Python运行它
我使用MinGW编译器编译它,如下所示
gfortran -c test.f
gfortran -shared -mrtd -o test.dll test.o
查看创建的DLL我看到
Microsoft(R)COFF / PE Dumper版本12.00.30723.0
版权所有(C)Microsoft Corporation。版权所有。
转储文件test.dll
文件类型:DLL
部分包含test.dll的以下导出
00000000特性
0时间日期戳Thu Jan 01 13:00:00 1970
0.00版本
1个序数基数
1个函数数量
1个数字
顺序提示RVA名称
1 0 00001280 ex_
总结
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
打印DLL
print getattr (DLL,'ex_')
打印DLL [1]
打印DLL.ex_
x =指针(c_int(3))
DLL.ex_(x)
输出是
&
< _FuncPtr object at 0x020E88A0>
< _FuncPtr object at 0x020E8918>
< _FuncPtr object at 0x020E88A0>
Traceback(最近一次调用的最后一个):
在< module>文件中,第20行的文件C:\proj_py\test.py
DLL.ex_(x)
ValueError:可能调用的参数太多(超过4个字节)
所以虽然函数在那里,但我没有正确地调用它。我很难过。
我在64位Windows-7机器上使用python 2.7.10(32位),我有最近版本的MinGW编译器:
$ gfortran -v
使用内置规格。
COLLECT_GCC = c:\明智\\ b\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
目标:mingw32
配置:../gcc-4.8.1/configure --prefix = / mingw --host = mingw32 --build = mingw32 --without-pic --enable-shared --e
nable-static --with-gnu-ld --enable -lto --enable-libssp --disable-multilib --enable-languages = c,c ++,fortran,objc,obj-c ++
,ada --disable -sjlj-exceptions --with-dwarf2 --disable -win32-registry --enable-libstdcxx-debug --enable-version-specific
-runtime-libs --with- gmp = / usr / src / pkg / gmp-5.1.2-1-mingw32-src / bld --with-mpc = / usr / src / pkg / mpc-1.0.1-1-mingw32-src / bld -
with -mpfr = --with-system-zlib --with-gnu-as --enable-decimal-float = yes --enable-libgomp --enable-threads --with-libiconv
-prefix = / mingw32 --with-libintl-prefix = / mingw --disable-bootstrap LDFLAGS = -s CFLAGS = -D_USE_32BIT_TIME_T
线程模型:win32
gcc版本4.8.1(GCC)
任何人都可以提供解决方案?
谢谢
Fortran通常是pass-引用。当从其他语言如C调用时,这意味着将内存地址传递给Fortran子例程。显然,Python的实现类似。在你编辑之前,你有一个错误,如你在0x000003上非法访问,这个值与你想要传递的值相同,值为3。你进入Fortran子程序就好了,但是当它试图执行add时,它会在内存位置3查找整数,而不是在加法本身中使用值3.
在你编辑之后,你传递了一个指针(根据我的评论,我认为)。这给出了一个不同的错误。它表明你传递了一个额外的参数,因为它获得了比预期多4字节的数据。我认为这可能是一些32位库和一些64位库之间的不兼容性,4字节在两种体系结构中指针之间的长度可能不同。
I am trying to learn how to complie FORTRAN code into a DLL that I can call from Python using ctypes. Even a simple example is not working, can anyone help?
I have a single procedure in FORTRAN:
subroutine ex(i)
integer i
i=i+1
return
end
Then I try to run this from Python
I compile it with the MinGW complier as follows
gfortran -c test.f
gfortran -shared -mrtd -o test.dll test.o
Looking at the DLL created I see
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
Then I try to access this from 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 )
The output is
<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)
So although the function is there, I'm not calling it correctly. I'm stumped.
I am using python 2.7.10 (32 bit) on a 64-bit Windows-7 machine, I have a recent version of the MinGW compiler:
$ gfortran -v
Using built-in specs.
COLLECT_GCC=c:\mingw\bin\gfortran.exe
COLLECT_LTO_WRAPPER=c:/mingw/bin/../libexec/gcc/mingw32/4.8.1/lto-wrapper.exe
Target: mingw32
Configured with: ../gcc-4.8.1/configure --prefix=/mingw --host=mingw32 --build=mingw32 --without-pic --enable-shared --e
nable-static --with-gnu-ld --enable-lto --enable-libssp --disable-multilib --enable-languages=c,c++,fortran,objc,obj-c++
,ada --disable-sjlj-exceptions --with-dwarf2 --disable-win32-registry --enable-libstdcxx-debug --enable-version-specific
-runtime-libs --with-gmp=/usr/src/pkg/gmp-5.1.2-1-mingw32-src/bld --with-mpc=/usr/src/pkg/mpc-1.0.1-1-mingw32-src/bld --
with-mpfr= --with-system-zlib --with-gnu-as --enable-decimal-float=yes --enable-libgomp --enable-threads --with-libiconv
-prefix=/mingw32 --with-libintl-prefix=/mingw --disable-bootstrap LDFLAGS=-s CFLAGS=-D_USE_32BIT_TIME_T
Thread model: win32
gcc version 4.8.1 (GCC)
Can anyone offer a solution?
Thanks
Fortran is generally pass-by-reference. When calling from other languages like C, that means passing a memory address into the Fortran subroutine. Apparently the Python implementation is similar. Before your edit, you had an error that said something like "Illegal access at 0x000003" which was suspiciously the same value "3" as you were trying to pass as the value. You entered the Fortran subroutine just fine, but when it tried to do the add, it looked for the integer at memory location 3 instead of using the value 3 in the addition itself.
After your edit, you are passing a pointer (based on my comment, I think). That gives a different error. It suggests that you passed an extra argument because it got 4 bytes more data than it expected. I think that's likely an incompatibility between some 32 bit libraries and some 64 bit libraries, with 4 bytes being a likely difference in length between pointers in the two architectures.
这篇关于使用ctypes调用FORTRAN DLL的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!