2017-02-19 9 views
2

Я пытаюсь передать аргументы в подпрограмму Fortran в общей библиотеке с использованием ctypes. Теперь вот мой простой Фортран код:Передача строк python в подпрограмму Fortran с использованием ctypes

MODULE test_module 
INCLUDES 
SUBROUTINE fstr_test(file_or_extension, ierr, iopen) 
    IMPLICIT NONE 
    INTEGER, INTENT(out) :: ierr 
    INTEGER, OPTIONAL :: iopen 
    CHARACTER(LEN=*), INTENT(in) :: file_or_extension 
    WRITE(6,*) file_or_extension,ierr,iopen 
    RETURN 
END SUBROUTINE fstr_test 
END MODULE test_module 

компилировать это с

gcc -shared -fPIC -o libtest.o fstr_test.f90 

Это, кажется, работает хорошо, я на самом деле может загрузить динамическую библиотеку в Python 3. Вот, не разбивая код:

from ctypes import * 
libtest = cdll.LoadLibrary("libtest.so") 
f = libtest.test_module_MOD__fstr_test 
file = b'wout_li383.nc' 
ierr = c_int(0) 
iopen = c_int(0) 
cfile=c_char_p(b"test_str") 
f(cfile,byref(ierr),byref(iopen)) 

Однако я не могу передать строку правильно. В форме выше строка пуста, и два целых числа корректно печатаются на консоли. В основном единственный прогресс, который я сделал, - это заставить Python рухнуть. Я попробовал решение здесь:

Passing string to Fortran DLL using ctypes and Python

но это, кажется, не работает для меня, может быть, потому что это говорит о Python 2?

Например

f.argtype = [c_char_p,c_int_c_int] 
c = c_char_p(b"test.txt") 
f(c,byref(ierr),byref(iopen)) 

Не врезаться ядро, но строка пуста. Изменение к сокращению:

f.argtype = [c_char_p,c_int_c_int] 
c = c_char_p(b"test.txt") 
f(byref(c),byref(ierr),byref(iopen)) 

такой же эффект. Теперь, если я попытаюсь передать длину, добавив аргумент length и передав его, я получаю сообщение «Dead Kernel», и я должен перезапустить ядро. Нет сообщения об ошибке.

f.argtype = [c_char_p,c_int,c_int_c_int] 
file = b'text.txt' 
c = c_char_p(file) 
c_len = c_int(len(file)) 
f(c,byref(c_len),byref(ierr),byref(iopen)) 

Надеюсь, это разъяснит. Я не получаю сообщение об ошибке, ядро ​​просто умирает.

+0

Ответ на связанный вопрос рассказывает о передаче «скрытого» аргумента для длины строки (общий подход, когда не используются C-совместимые переменные символов). Вы этого не делаете? – francescalus

+0

Почему он не работает? Сообщение об ошибке? Неверные результаты? Показать им. –

+0

Если я укажу длину строки как скрытую переменную, ядро ​​разбивается. – Lazer

ответ

2

Итак, несколько вопросов, одна скрытая длина (по крайней мере, с gfortran неизвестна, что делают другие компиляторы) должна идти в конце списка аргументов. Вам не нужно ByRef на него либо и не обернуть байт-строку в c_char_p

Изменение IERR переменной в подпрограмме

SUBROUTINE fstr_test(file_or_extension, ierr, iopen) 
    IMPLICIT NONE 
    INTEGER, INTENT(out) :: ierr 
    INTEGER, OPTIONAL :: iopen 
    CHARACTER(LEN=*), INTENT(in) :: file_or_extension 
    WRITE(6,*) file_or_extension,ierr,iopen 
    ierr=1 
    RETURN 
    END SUBROUTINE fstr_test 

и

gfortran -shared -fPIC -o libtest.so fstr_test.f90 

Затем питона код должен быть таким:

import ctypes 

lib=ctypes.CDLL("./libtest.so") 
f=getattr(lib,'__test_module_MOD_fstr_test') 

f.argtypes=[ctypes.c_char_p,ctypes.c_int,ctypes.c_int,ctypes.c_int] 
f.restype=None 

x=b'abcdef' 
ierr=ctypes.c_int(0) 
iopen=0 
f(x,ctypes.byref(ierr),iopen,len(x)) 
print(ierr.value) 

Хотя у меня нет дополнительного аргумента, работающего let, поэтому я добавил пустой int, это должно все же передать строку и получить ierr.

+0

Должно ли это быть 'argparse' или' argtypes' в вашем примере? BTW- Спасибо, что это работает очень хорошо. – Lazer

+0

Хороший улов, это должны быть аргипы – Rob

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