2015-08-21 67 views
0

我在學習如何將FORTRAN代碼編譯成一個DLL,我可以使用ctypes從Python進行調用。即使一個簡單的例子不工作,任何人都可以幫忙嗎?使用ctypes調用FORTRAN DLL

我有一個單一的過程中FORTRAN:

subroutine ex(i) 
    integer i 
    i=i+1 
    return 
    end 

然後我嘗試從Python的

運行此

我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) 

所以雖然功能是存在的,我不能正確調用它。我很難過。

我是一個64位Windows的7臺機器上使用python 2.7.10(32位),我有一個最近MinGW的編譯器版本:

$ 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) 

任何人都可以提供一個解決方案?

謝謝

+0

DLL中的Fortran子例程可能真的在等待一個指針。在Python中而不是'x = c_int(3)'嘗試'x = byref(3)''。如果這有效,我會發布更長的解釋作爲答案。 – Brick

+0

我看到自從我的第一條評論開始,您就編輯了您的問題,並更改了錯誤消息。這很好,因爲有一個問題。現在看起來你已經在不同大小的指針之間產生了一些不兼容的問題。很難從這裏看到究竟是什麼錯誤,但它看起來像是將一個64位指針傳遞到期望32位指針的庫中。 (這是一個4字節的差異 - 確切地說,你的錯誤信息報告。)@Blair – Brick

+0

你的圖書館正在使用[cdecl](https://en.wikipedia.org/wiki/X86_calling_conventions#cdecl)(調用者清理堆棧),不[stdcall](https://en.wikipedia.org/wiki/X86_calling_conventions#stdcall)(被動清理)。加載它爲'dll = CDLL('test')'。 – eryksun

回答

1

Fortran通常是通過引用。當從其他語言如C調用時,這意味着將內存地址傳遞給Fortran子例程。顯然,Python的實現類似。在你編輯之前,你有一個錯誤,如「你在0x000003上非法訪問」,這個值與你想要傳遞的值相同,值爲「3」。你輸入了Fortran子程序就好了,但是當它嘗試添加時,它在內存位置3查找整數,而不是在添加本身中使用值3。

編輯完成後,你傳遞了一個指針(基於我的評論,我認爲)。這給出了一個不同的錯誤。它表明你傳遞了一個額外的參數,因爲它獲得了比預期多4字節的數據。我認爲這可能是一些32位庫和一些64位庫之間的不兼容性,4字節在兩種體系結構中指針之間的長度可能不同。