我想在Python中调用来自Fortran共享库的某些函数。我在网上找到了一些链接并阅读了它们,根据我所发现的,我应该这样做:
libadd = cdll.LoadLibrary('./libbin.so')
需要加载共享对象。然而,这个共享对象包含另一个共享库中的一些符号。我读了cdll的帮助文档,但似乎不可能同时加载多个共享对象文件。我该如何调用这个Fortran库中的函数,这个库很可能是由Intel Fortran编译器编译的?
我想在Python中调用来自Fortran共享库的某些函数。我在网上找到了一些链接并阅读了它们,根据我所发现的,我应该这样做:
libadd = cdll.LoadLibrary('./libbin.so')
需要加载共享对象。然而,这个共享对象包含另一个共享库中的一些符号。我读了cdll的帮助文档,但似乎不可能同时加载多个共享对象文件。我该如何调用这个Fortran库中的函数,这个库很可能是由Intel Fortran编译器编译的?
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
nm mult.so
)时,它显示为_multiply_
而不是multiply_
,尽管后者在C和Python中仍然有效。您知道这是为什么吗? - marshall.ward我想补充一下@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一样调用它。这种方法的优点是它适用于所有平台(无需使用任何特殊的编译器选项)。
mult.f90
和add.f90
示例。从shell中编译Python可导入共享库:f2py -c -m mult mult.f90
f2py -c -m add add.f90
>>> import add
>>> import mult
>>> add.addtwo(4, 5)
9
>>> mult.multiply(4, 5)
20