Функции вызова из общей библиотеки fortran в python

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

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

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

Ответ 1

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

Например, у меня есть этот исходный код (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

Ответ 2

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

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, как обычно. Преимущество этого подхода состоит в том, что он работает на всех платформах (без использования каких-либо специальных параметров компилятора).

Ответ 3

Для работы 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