使用ctypes调用FORTRAN DLL [英] Calling a FORTRAN DLL using ctypes

查看:293
本文介绍了使用ctypes调用FORTRAN DLL的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图学习如何将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屋!

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