在Python中调用共享Fortran库的函数

16 投票
3 回答
7268 浏览
提问于 2025-04-16 16:33

我想在Python中调用一些来自Fortran共享库的函数。我在网上找到了一些相关的链接并阅读了它们,根据我了解到的,我应该这样做:

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

来加载这个共享对象。不过,这个共享对象还包含了另一个共享库中的一些符号。我查看了cdll的帮助文档,但似乎不可能同时加载多个共享对象文件。我该如何调用这个Fortran库中的函数呢?这个库很可能是用Intel Fortran编译器编译的。

3 个回答

1

要让f2py(来自NumPy)正常工作,可以借用@samplebias提供的两个例子:mult.f90add.f90。在命令行中,编译这些可以在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
5

我想补充一下@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中调用它。这个方法的好处是它在所有平台上都能工作(不需要使用任何特殊的编译器选项)。

22

你需要知道共享对象中函数的签名。你有源代码吗?或者有一些可以解释函数名称和参数类型的参考资料吗?

比如,我有这个源代码(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

撰写回答