вызывать функции из общей библиотеки фортрана в python

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

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

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


person Umut Tabak    schedule 27.04.2011    source источник
comment
Вы также можете посмотреть на f2py. Он является частью NumPy.   -  person lafras    schedule 28.04.2011


Ответы (3)


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

Например, у меня есть этот исходный код (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
person samplebias    schedule 28.04.2011
comment
Спасибо за прекрасный ответ. У меня есть быстрый дополнительный вопрос. Когда я просматриваю список имен библиотек (nm mult.so), он показывает _multiply_, а не multiply_, хотя последний по-прежнему работает в C и python. Вы знаете, почему это так? - person marshall.ward; 29.04.2011
comment
Пожалуйста. Различные компиляторы могут добавлять символы подчеркивания в начале/добавлении к именам символов. Я знаю, что в случае с gfortran вы можете указать -fno-underscoring, чтобы отключить это; в результате символ multiply для этой функции. Ваш компилятор+платформа может иметь эту опцию. Я обновлю ответ другим возможным решением, если вы имеете дело с общим объектом неизвестного происхождения. - person samplebias; 29.04.2011
comment
На самом деле, я воздержусь от дальнейших комментариев, которые я слышу по поводу опции компилятора, поскольку это может решить проблему для вас. Суть в том, что вам нужно знать сигнатуру функции, которую вы вызываете, поэтому вы хотите свести к минимуму догадки, исправляя вещи вверх по течению. - person samplebias; 29.04.2011
comment
@samplebias Я должен был упомянуть, что использовал OS X. Знаки подчеркивания в начале не появляются в библиотеках Linux, так что, вероятно, это проблема OS X (или BSD). Поскольку это выходит за рамки вопроса, я, вероятно, должен на этом остановиться. Спасибо за внимание. - person marshall.ward; 29.04.2011
comment
@samplebias: есть некоторые символы, на которые есть ссылки в одном из общих объектных файлов, которые все еще не определены. И тезисы находятся в другом объектном файле, однако попытка загрузить этот общий объект дает ошибку, что объектный файл не распознан, есть идеи? - person Umut Tabak; 29.04.2011
comment
@Umut Хм, похоже, что он может быть неправильно скомпилирован для вашей платформы, например. не используются -shared и -fPIC, возможно, неправильная архитектура процессора для вашей платформы и т. д. Отсюда трудно сказать. Еще одна проблема, с которой вы можете столкнуться в будущем: когда вы загружаете общий объект из локального каталога, и этот .so связан с другими общими объектами, вам нужно установить LD_LIBRARY_PATH, чтобы загрузчик мог найти все необходимые библиотеки и связать их. в исполняемый файл. - person samplebias; 05.05.2011

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

person Ondřej Čertík    schedule 25.05.2011

Чтобы 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
person Mike T    schedule 20.05.2013