我想创建一个使用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]
答案 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