вызов функций из общей библиотеки Фортрана в Python - PullRequest
14 голосов
/ 28 апреля 2011

Я хотел бы вызвать некоторые функции из разделяемой библиотеки Fortran в Python.Я нашел некоторые ссылки в сети и прочитал их, и в соответствии с тем, что я нашел, я должен сделать

libadd = cdll.LoadLibrary('./libbin.so') 

, чтобы загрузить общий объект.Однако этот общий объект содержит некоторые символы из другой общей библиотеки.Я прочитал справку по cdll, однако не представляется возможным загрузить несколько общих объектных файлов одновременно.Как я могу вызывать функции из этой библиотеки Fortran, которая, скорее всего, компилируется компилятором Intel Fortran?

Ответы [ 3 ]

17 голосов
/ 28 апреля 2011

Вам необходимо знать сигнатуры функций в общем объекте.У вас есть исходный код или какая-либо ссылка, объясняющая имена функций и типы аргументов?

Например, у меня есть этот исходный код ( mult.f90 ):

integer function multiply(a, b)
    integer, intent(in) :: a, b
    multiply = a * b
end function multiply

.. и чтобы продемонстрировать, как вы можете загружать и использовать несколько общих объектов одновременно, у меня также есть ( add.f90 ):

integer function addtwo(a, b)
    integer, intent(in) :: a, b
    addtwo = a + b
end function addtwo

Компиляция, проверка символов:

% gfortran-4.4 -shared -fPIC -g -o mult.so mult.f90
% gfortran-4.4 -shared -fPIC -g -o add.so add.f90
% nm -ao mult.so | grep multiply
mult.so:00000000000005cc T multiply_

Обратите внимание, что к имени символа в общем объекте добавлено подчеркивание.Поскольку у меня есть источник, я знаю, что подпись multiply_(int *a, int *b), поэтому эту функцию легко вызвать из ctypes:

from ctypes import byref, cdll, c_int

mult = cdll.LoadLibrary('./mult.so')
add = cdll.LoadLibrary('./add.so')
a = c_int(2)
b = c_int(4)
print mult.multiply_(byref(a), byref(b))
print add.addtwo_(byref(a), byref(b))

Вывод:

8
6
5 голосов
/ 25 мая 2011

Я бы добавил к ответу @sameplebias, что можно использовать модуль iso_c_binding, чтобы заставить (любой) компилятор фортрана произвести правильную сигнатуру Си. Пример использования:

module fmesh_wrapper

use iso_c_binding, only: c_double, c_int
use fmesh, only: mesh_exp

implicit none

contains

subroutine c_mesh_exp(r_min, r_max, a, N, mesh) bind(c)
real(c_double), intent(in) :: r_min
real(c_double), intent(in) :: r_max
real(c_double), intent(in) :: a
integer(c_int), intent(in) :: N
real(c_double), intent(out) :: mesh(N)
call mesh_exp(r_min, r_max, a, N, mesh)
end subroutine

! wrap more functions here
! ...

end module

это будет иметь следующую подпись C:

void c_mesh_exp(double *r_min, double *r_max, double *a, int *N,
        double *mesh);

и затем вы можете вызывать его из Python как обычно. Преимущество этого подхода в том, что он работает на всех платформах (без использования каких-либо специальных параметров компилятора).

1 голос
/ 20 мая 2013

Чтобы f2py (из NumPy) работал, позаимствуйте оба примера mult.f90 и add.f90 из @samplebias.Из оболочки скомпилируйте импортируемые разделяемые библиотеки Python:

f2py -c -m mult mult.f90
f2py -c -m add add.f90

Теперь используйте их в Python:

>>> import add
>>> import mult
>>> add.addtwo(4, 5)
9
>>> mult.multiply(4, 5)
20
...