Python / Cython / Fortran模块 - 未定义的符号:_gfortran_runtime_error

时间:2015-07-10 08:01:07

标签: python c fortran cython

我想创建一个使用Cython调用Fortran函数的Python模块。我在全球范围内工作,除了以下示例,当我尝试导入模块时,我从Python收到消息错误:

Python 2.7.5 (default, Feb  8 2014, 08:16:49) 
[GCC 4.4.7 20120313 (Red Hat 4.4.7-3)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import m
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ImportError: ./m.so: undefined symbol: _gfortran_runtime_error

最低工作示例是:

m.pyx

cdef extern from "fortinterface.h":
void f_fortinterface(int* n, float* var, float* resu)

import  numpy as pnp
cimport numpy as cnp

def f(list a):
    cdef cnp.ndarray var  = pnp.array(a,dtype='f',order='F')      #from list to numpy array
    cdef cnp.ndarray resu = pnp.ones(len(a),dtype='f',order='F')

    cdef int n = len(var)
    f_fortinterface(&n, <float*> var.data, <float*> resu.data)

    return resu.tolist()    #back to list from numpy array

fortinterface.f90

module fortinterface

use iso_c_binding
use fortfunction

implicit none

contains

  subroutine f_fortinterface(n,var,resu) bind(c)
  implicit none
  integer(c_int), intent(in)  :: n
  real(c_float),  intent(in)  :: var(n)
  real(c_float),  intent(out) :: resu(n)

  resu(:)  = f_fortfunction(var)

  end subroutine f_fortinterface

end module fortinterface

fortinterface.h

extern void f_fortinterface(int* n, float* var, float* resu);

档案fortfunction.f90

module fortfunction

implicit none

contains

  function f_fortfunction(var)
  implicit none
  real, intent(in)   :: var(:)
  real, allocatable  :: f_fortfunction(:)

  allocate(f_fortfunction(size(var)))
  f_fortfunction(:) = var(:)+1.0

  end function f_fortfunction

end module fortfunction

setup.py

from distutils.core import setup
from distutils.extension import Extension
from Cython.Distutils import build_ext
from numpy import get_include
from os import system

# compile the fortran modules without linking
fortran_mod_comp = 'gfortran fortfunction.f90 -c -o fortfunction.o -fPIC'
print fortran_mod_comp
system(fortran_mod_comp)
shared_obj_comp = 'gfortran fortinterface.f90 -c -o fortinterface.o -fPIC'
print shared_obj_comp
system(shared_obj_comp)

# needed if building with NumPy : this includes the NumPy headers when compiling.
path_includes = [get_include()]

ext_modules =    [Extension('m',                                                      # module name:
                            ['m.pyx'],                                                # source file:
                            extra_link_args=['fortfunction.o', 'fortinterface.o'])]   # other files to link to

setup(name = 'm',
      cmdclass = {'build_ext': build_ext},
      include_dirs = path_includes,
      ext_modules  = ext_modules)

我用

编译所有内容
python setup.py build_ext --inplace

错误消息清楚地表明包含库存在问题(在链接编辑期间,我猜)。我试图为gfortran和gcc(-lm,lgfortran,...)添加几个选项但没有成功。我很困惑,因为错误来自使用可分配数组

f_fortfunction

在文件fortfunction.f90

实际上,如果我用静态数组替换可分配数组,一切正常。然而,对我来说这不是一个可接受的解决方案,因为该函数可能返回不同大小的数组,我真的需要它的动态分配

修改(工作) fortfunction.f90

module fortfunction

implicit none

contains

  function f_fortfunction(var)
  implicit none
  real, intent(in)   :: var(:)
  real               :: f_fortfunction(2)

  f_fortfunction(:) = var(:)+1.0

  end function f_fortfunction

end module fortfunction

在这种情况下,我得到了我想要的东西:

>>> import m
>>> m.f([1,3])
[2.0, 4.0]

2 个答案:

答案 0 :(得分:0)

解决方案是在Fortran中使用自动数组而不是可分配数组。以下是fortfunction.f90有效的示例,

function f_fortfunction(var, n)
implicit none
real, intent(in)   :: var(:)
integer, intent(in)   :: n
real:: f_fortfunction(size(var))

f_fortfunction(:) = var(:)+1.0

end function f_fortfunction

答案 1 :(得分:0)

通过在gfortran的{​​{1}}对象中为Extension的库进行链接,我可以解决此问题,而不必尝试手动链接库。

修改后的setup.py

使用原始的setup.py并给出预期的结果(在Python3上测试)。唯一的变化是在fortfunction.f90中包含了libraries

ext_modules