2015-08-21 3 views
0

Я пытаюсь узнать, как выполнить код FORTRAN в DLL, которую я могу вызвать из Python с использованием ctypes. Даже простой пример не работает, может ли кто-нибудь помочь?Вызов библиотеки FORTRAN с использованием ctypes

У меня есть одну процедуру в 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) 

Так что, хотя эта функция есть, я не называю это правильно. Я в тупике.

Я использую питона 2.7.10 (32 бит) на 64-разрядной ОС Windows-7 машине, у меня есть последняя версия компилятора 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) 

Может кто-нибудь предложить решение?

Thanks

+0

Подпрограмма Fortran в DLL, вероятно, действительно ожидает указателя. Попробуйте 'x = byref (3)' в вашем Python вместо 'x = c_int (3)'. Если это сработает, я отправлю более длинное объяснение в качестве ответа. – Brick

+0

Я вижу, что вы отредактировали свой вопрос с моего первого комментария, и сообщение об ошибке изменилось. Это хорошо, потому что одна проблема. Теперь похоже, что вы получаете некоторую несовместимость между указателями разных размеров. Трудно видеть, что именно не так, но похоже, что вы передаете 64-битный указатель в библиотеку, ожидающую 32-битного указателя. (Это разница в 4 байта.). @Blair – Brick

+0

В вашей библиотеке используется [cdecl] (https://en.wikipedia.org/wiki/X86_calling_conventions#cdecl) (вызывающий очищает стек), not [stdcall] (https://en.wikipedia.org/wiki/X86_calling_conventions#stdcall) (очистка вызываемого абонента). Загрузите его как 'dll = CDLL ('test')'. – eryksun

ответ

1

Фортран, как правило, передается по ссылке. При вызове с других языков, таких как C, это означает передачу адреса памяти в подпрограмму Fortran. По-видимому, реализация Python аналогична. Перед редактированием у вас была ошибка, в которой говорилось что-то вроде «Недопустимый доступ в 0x000003», который был подозрительно тем же значением «3», что и вы пытались передать как значение. Вы вошли в подпрограмму Fortran просто отлично, но когда он попытался сделать добавление, он искал целое число в ячейке памяти 3 вместо того, чтобы использовать значение 3 в самом добавлении.

После вашего редактирования вы передаете указатель (на мой комментарий, я думаю). Это дает другую ошибку. Это предполагает, что вы передали дополнительный аргумент, потому что он получил 4 байта больше данных, чем ожидалось. Я думаю, что это, вероятно, несовместимость между некоторыми 32-битными библиотеками и некоторыми 64-битными библиотеками, причем 4 байта являются вероятной разницей в длине между указателями в двух архитектурах.

Смежные вопросы